/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wildfly.security.asn1;
import org.junit.Test;
import org.wildfly.security.util.CodePointIterator;
import java.util.ArrayList;
import static org.junit.Assert.*;
import static org.wildfly.security.asn1.ASN1.*;
import static org.wildfly.security.pem.Pem.extractDerContent;
/**
* Tests for DER decoding.
*
* @author <a href="mailto:fjuma@redhat.com">Farah Juma</a>
*/
public class DERDecoderTest {
@Test
public void testDecodeEmptyOctetString() throws Exception {
// As byte array
DERDecoder decoder = new DERDecoder(new byte[] {4, 0});
assertArrayEquals(new byte[0], decoder.decodeOctetString());
// As string
decoder = new DERDecoder(new byte[] {4, 0});
assertEquals("", decoder.decodeOctetStringAsString());
}
@Test
public void testDecodeOctetString() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {4, 13, 97, 98, 99, 100, 33, 35, 69, 70, 71, 72, 32, 94, 94});
assertArrayEquals(new byte[] {97, 98, 99, 100, 33, 35, 69, 70, 71, 72, 32, 94, 94}, decoder.decodeOctetString());
}
@Test
public void testDecodeOctetStringAsString() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {4, 20, -61, -124, -61, -92, -61, -117, -61, -85, -61, -113, -61, -81, -61, -106, -61, -74, -61, -100, -61, -68});
assertEquals("ÄäËëÏïÖöÜü", decoder.decodeOctetStringAsString());
decoder = new DERDecoder(new byte[] { 4, 10, -60, -28, -53, -21, -49, -17, -42, -10, -36, -4 });
assertEquals("ÄäËëÏïÖöÜü", decoder.decodeOctetStringAsString("ISO-8859-1"));
}
@Test
public void testDecodeEmptyIA5String() throws Exception {
// As string
DERDecoder decoder = new DERDecoder(new byte[] {22, 0});
assertEquals("", decoder.decodeIA5String());
// As byte array
decoder = new DERDecoder(new byte[] {22, 0});
assertArrayEquals(new byte[0], decoder.decodeIA5StringAsBytes());
}
@Test
public void testDecodeIA5String() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109});
assertEquals("test1@rsa.com", decoder.decodeIA5String());
decoder = new DERDecoder(new byte[] {22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109});
assertArrayEquals(new byte[] {116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109}, decoder.decodeIA5StringAsBytes());
}
@Test
public void testDecodeEmptyBitString() throws Exception {
// Decode as a byte array
DERDecoder decoder = new DERDecoder(new byte[] {3, 1, 0});
assertArrayEquals(new byte[] {}, decoder.decodeBitString());
// Decode as a binary string
decoder = new DERDecoder(new byte[] {3, 1, 0});
assertEquals("", decoder.decodeBitStringAsString());
}
@Test
public void testDecodeBitString() throws Exception {
// With unused bits present
DERDecoder decoder = new DERDecoder(new byte[] {3, 4, 6, 110, 93, -64});
byte[] expected = new byte[] {1, -71, 119};
assertArrayEquals(expected, decoder.decodeBitString());
// Without unused bits
decoder = new DERDecoder(new byte[] {3, 4, 0, 110, 93, -64});
expected = new byte[] {110, 93, -64};
assertArrayEquals(expected, decoder.decodeBitString());
}
@Test
public void testDecodeBitStringAsString() throws Exception {
// With unused bits present
DERDecoder decoder = new DERDecoder(new byte[] {3, 4, 6, 110, 93, -64});
assertEquals("011011100101110111", decoder.decodeBitStringAsString());
// Without unused bits
decoder = new DERDecoder(new byte[] {3, 4, 0, 110, 93, -64});
assertEquals("011011100101110111000000", decoder.decodeBitStringAsString());
}
@Test(expected=ASN1Exception.class)
public void testDecodeInvalidBitString() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {3, 4, 8, 110, 93, -64});
decoder.decodeBitStringAsString();
}
@Test
public void testDecodeObjectIdentifier() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {6, 21, 105, -126, -89, -33, -76, -24, -97, -72, -72, -57, -75, -94, -46, -64, -128, -86, -82, -41, -118, 27, 1});
assertEquals("2.25.196556539987194312349856245628873852187.1", decoder.decodeObjectIdentifier());
}
@Test
public void testDecodeNull() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {5, 0});
assertTrue(decoder.hasNextElement());
decoder.decodeNull();
assertFalse(decoder.hasNextElement());
}
@Test(expected=ASN1Exception.class)
public void testDecodeInvalidNull() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {5, 12});
decoder.decodeNull();
}
@Test(expected=IllegalStateException.class)
public void testDecodeEndSequenceBeforeStart() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {48, 41, 22, 14, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 116, 101, 115, 116, 4, 8, 1, 35, 69, 103, -119, -85, -51, -17, 22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109});
decoder.endSequence();
}
@Test(expected=IllegalStateException.class)
public void testDecodeEndSetBeforeStart() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {49, 28, 4, 8, 1, 35, 69, 103, -119, -85, -51, -17, 4, 3, 1, 35, 69, 5, 0, 6, 9, 42, -126, -28, 116, -108, -91, -31, -90, 38});
decoder.endSet();
}
@Test(expected=IllegalStateException.class)
public void testDecodeEndExplicitBeforeStart() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {-94, 43, 48, 41, 22, 14, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 116, 101, 115, 116, 4, 8, 1, 35, 69, 103, -119, -85, -51, -17, 22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109});
decoder.endExplicit();
}
@Test
public void testDecodeSimpleSequence() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {48, 41, 22, 14, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 116, 101, 115, 116, 4, 8, 1, 35, 69, 103, -119, -85, -51, -17, 22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109});
assertTrue(decoder.hasNextElement());
decoder.startSequence();
assertTrue(decoder.hasNextElement());
assertEquals("this is a test", decoder.decodeIA5String());
assertTrue(decoder.hasNextElement());
assertArrayEquals(new byte[] {1, 35, 69, 103, -119, -85, -51, -17}, decoder.decodeOctetString());
assertTrue(decoder.hasNextElement());
assertEquals("test1@rsa.com", decoder.decodeIA5String());
assertFalse(decoder.hasNextElement());
decoder.endSequence();
assertFalse(decoder.hasNextElement());
}
@Test
public void testDecodeComplexSequence() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {48, 93, 22, 11, 116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103, 4, 8, 1, 35, 69, 103, -119, -85, -51, -17, 48, 59, 22, 14, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 116, 101, 115, 116, 4, 8, 1, 35, 69, 103, -119, -85, -51, -17, 48, 16, 22, 7, 116, 101, 115, 116, 105, 110, 103, 22, 5, 97, 103, 97, 105, 110, 22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109, 22, 7, 116, 104, 101, 32, 101, 110, 100});
decoder.startSequence();
assertEquals("test string", decoder.decodeIA5String());
assertArrayEquals(new byte[]{1, 35, 69, 103, -119, -85, -51, -17}, decoder.decodeOctetString());
decoder.startSequence();
assertEquals("this is a test", decoder.decodeIA5String());
assertArrayEquals(new byte[] {1, 35, 69, 103, -119, -85, -51, -17}, decoder.decodeOctetString());
decoder.startSequence();
// Skip over the two elements in this sequence
decoder.endSequence();
assertEquals("test1@rsa.com", decoder.decodeIA5String());
decoder.endSequence();
assertEquals("the end", decoder.decodeIA5String());
decoder.endSequence();
}
@Test
public void testDecodeSimpleSet() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {49, 28, 4, 8, 1, 35, 69, 103, -119, -85, -51, -17, 4, 3, 1, 35, 69, 5, 0, 6, 9, 42, -126, -28, 116, -108, -91, -31, -90, 38});
assertEquals(SET_TYPE, decoder.peekType());
decoder.startSet();
assertEquals(OCTET_STRING_TYPE, decoder.peekType());
assertArrayEquals(new byte[] {1, 35, 69, 103, -119, -85, -51, -17}, decoder.decodeOctetString());
assertEquals(OCTET_STRING_TYPE, decoder.peekType());
assertArrayEquals(new byte[] {1, 35, 69}, decoder.decodeOctetString());
assertEquals(NULL_TYPE, decoder.peekType());
decoder.decodeNull();
assertEquals(OBJECT_IDENTIFIER_TYPE, decoder.peekType());
assertEquals("1.2.45684.5447897894", decoder.decodeObjectIdentifier());
decoder.endSet();
}
@Test
public void testDecodeComplexSet() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {49, 67, 4, 8, 1, 35, 69, 103, -119, -85, -51, -17, 6, 4, 42, 123, -119, 82, 49, 34, 4, 3, 1, 35, 69, 5, 0, 6, 5, 81, 58, -86, 80, 36, 49, 18, 5, 0, 22, 14, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 116, 101, 115, 116, 22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109});
assertEquals(SET_TYPE, decoder.peekType());
decoder.startSet();
assertEquals(OCTET_STRING_TYPE, decoder.peekType());
decoder.skipElement();
assertEquals(OBJECT_IDENTIFIER_TYPE, decoder.peekType());
decoder.skipElement();
assertEquals(SET_TYPE, decoder.peekType());
decoder.startSet();
assertEquals(OCTET_STRING_TYPE, decoder.peekType());
decoder.skipElement();
assertEquals(NULL_TYPE, decoder.peekType());
decoder.skipElement();
assertEquals(OBJECT_IDENTIFIER_TYPE, decoder.peekType());
decoder.skipElement();
assertEquals(SET_TYPE, decoder.peekType());
decoder.skipElement();
decoder.endSet();
assertEquals(IA5_STRING_TYPE, decoder.peekType());
decoder.skipElement();
}
@Test
public void testDecodeSimpleSetOf() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {49, 25, 6, 4, 42, 123, -119, 82, 6, 7, 81, 58, -86, 80, 36, -125, 72, 6, 8, 42, -125, 75, -15, 123, -115, -31, 58});
assertEquals(SET_TYPE, decoder.peekType());
ArrayList<String> oidList = new ArrayList<String>();
decoder.startSetOf();
while (decoder.hasNextElement()) {
assertEquals(OBJECT_IDENTIFIER_TYPE, decoder.peekType());
oidList.add(decoder.decodeObjectIdentifier());
}
decoder.endSetOf();
assertFalse(decoder.hasNextElement());
assertEquals(3, oidList.size());
assertEquals("1.2.123.1234", oidList.get(0));
assertEquals("2.1.58.5456.36.456", oidList.get(1));
assertEquals("1.2.459.14587.225466", oidList.get(2));
}
@Test
public void testDecodeComplexSetOf() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {49, 82, 49, 28, 22, 11, 97, 98, 99, 64, 114, 115, 97, 46, 99, 111, 109, 22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109, 49, 50, 22, 16, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 116, 114, 105, 110, 103, 22, 30, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 116, 114, 105, 110, 103, 32, 116, 104, 97, 116, 39, 115, 32, 108, 111, 110, 103, 101, 114});
assertEquals(SET_TYPE, decoder.peekType());
ArrayList<String> strList = new ArrayList<String>();
boolean firstSetSeen = false;
decoder.startSetOf();
while (decoder.hasNextElement()) {
assertEquals(SET_TYPE, decoder.peekType());
decoder.startSetOf();
while (decoder.hasNextElement()) {
assertEquals(IA5_STRING_TYPE, decoder.peekType());
strList.add(decoder.decodeIA5String());
}
if (! firstSetSeen) {
assertEquals(2, strList.size());
firstSetSeen = true;
}
decoder.endSetOf();
}
decoder.endSetOf();
assertFalse(decoder.hasNextElement());
assertEquals(4, strList.size());
assertEquals("abc@rsa.com", strList.get(0));
assertEquals("test1@rsa.com", strList.get(1));
assertEquals("this is a string", strList.get(2));
assertEquals("this is a string that's longer", strList.get(3));
}
@Test
public void testDecodeExplicitTag() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {-94, 43, 48, 41, 22, 14, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 116, 101, 115, 116, 4, 8, 1, 35, 69, 103, -119, -85, -51, -17, 22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109});
assertTrue(decoder.isNextType(CONTEXT_SPECIFIC_MASK, 2, true));
decoder.startExplicit(2);
assertTrue(decoder.hasNextElement());
decoder.startSequence();
assertTrue(decoder.hasNextElement());
assertEquals("this is a test", decoder.decodeIA5String());
assertArrayEquals(new byte[] {1, 35, 69, 103, -119, -85, -51, -17}, decoder.decodeOctetString());
assertEquals("test1@rsa.com", decoder.decodeIA5String());
assertFalse(decoder.hasNextElement());
decoder.endSequence();
assertFalse(decoder.hasNextElement());
decoder.endExplicit();
assertFalse(decoder.hasNextElement());
}
@Test
public void testDecodeImplicitTag() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {-126, 19, 115, 101, 114, 118, 101, 114, 49, 46, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109});
assertFalse(decoder.isNextType(CONTEXT_SPECIFIC_MASK, 0, false));
assertFalse(decoder.isNextType(CONTEXT_SPECIFIC_MASK, 1, true));
assertTrue(decoder.isNextType(CONTEXT_SPECIFIC_MASK, 2, false));
decoder.decodeImplicit(2);
assertEquals("server1.example.com", decoder.decodeIA5String());
}
@Test(expected=ASN1Exception.class)
public void testDecodeWrongType() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {5, 12});
decoder.decodeIA5String();
}
@Test
public void testDecodeRecoverAfterWrongType() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {22, 13, 116, 101, 115, 116, 49, 64, 114, 115, 97, 46, 99, 111, 109});
try {
decoder.decodeOctetString();
} catch (ASN1Exception e) {
assertTrue(decoder.hasNextElement());
assertEquals(IA5_STRING_TYPE, decoder.peekType());
assertEquals("test1@rsa.com", decoder.decodeIA5String());
}
}
@Test
public void testDecodeDrainElementValue() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {49, 25, 6, 4, 42, 123, -119, 82, 6, 7, 81, 58, -86, 80, 36, -125, 72, 6, 8, 42, -125, 75, -15, 123, -115, -31, 58});
assertEquals(SET_TYPE, decoder.peekType());
assertTrue(decoder.hasNextElement());
byte[] expected = new byte[] {6, 4, 42, 123, -119, 82, 6, 7, 81, 58, -86, 80, 36, -125, 72, 6, 8, 42, -125, 75, -15, 123, -115, -31, 58};
assertArrayEquals(expected, decoder.drainElementValue());
assertFalse(decoder.hasNextElement());
}
@Test
public void testDecodeDrainElement() throws Exception {
DERDecoder decoder = new DERDecoder(new byte[] {48, 26, -126, 19, 115, 101, 114, 118, 101, 114, 49, 46, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, -124, 3, 42, 3, 4});
decoder.startSequence();
byte[] expected = new byte[] {-126, 19, 115, 101, 114, 118, 101, 114, 49, 46, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109};
assertArrayEquals(expected, decoder.drainElement());
expected = new byte[] {-124, 3, 42, 3, 4};
assertArrayEquals(expected, decoder.drainElement());
decoder.endSequence();
assertFalse(decoder.hasNextElement());
}
@Test
public void testFormatDSAPublicKeyAsn1() throws Exception {
String dsaPublicKey = "-----BEGIN PUBLIC KEY-----\n" +
"MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E\n" +
"AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f\n" +
"6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv\n" +
"8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtc\n" +
"NrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwky\n" +
"jMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/h\n" +
"WuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAM5NVUxljeI2jZ9tQYhyyAZ9vy5c\n" +
"gfvl2R1x+IbLWR84StLSQ07+Fu4Dj7Rr5Mh1DNVLuUtjRUyy1Mq5EkiIzuuAsv5a\n" +
"9PCztH7rqV3Fgc0Yd48waOrcBDC9KjoI4bwH/Q1CcPynE6UOWxnaNNynIqQXYDfV\n" +
"qnnkzohcaWf0mHnt\n" +
"-----END PUBLIC KEY-----\n";
byte[] der = extractDerContent(CodePointIterator.ofString(dsaPublicKey));
String formatted = ASN1.formatAsn1(new DERDecoder(der));
assertEquals("[sequence:[sequence:[oid:1.2.840.10040.4.1][sequence:[int:178011905478542266528237562450159990145232156369120674273274450314442865788737020770612695252123463079567156784778466449970650770920727857050009668388144034129745221171818506047231150039301079959358067395348717066319802262019714966524135060945913707594956514672855690606794135837542707371727429551343320695239][int:864205495604807476120572616017955259175325408501][int:174068207532402095185811980123523436538604490794561350978495831040599953488455823147851597408940950725307797094915759492368300574252438761037084473467180148876118103083043754985190983472601550494691329488083395492313850000361646482644608492304078721818959999056496097769368017749273708962006689187956744210730]]][bits:000000101000000110000001000000001100111001001101010101010100110001100101100011011110001000110110100011011001111101101101010000011000100001110010110010000000011001111101101111110010111001011100100000011111101111100101110110010001110101110001111110001000011011001011010110010001111100111000010010101101001011010010010000110100111011111110000101101110111000000011100011111011010001101011111001001100100001110101000011001101010101001011101110010100101101100011010001010100110010110010110101001100101010111001000100100100100010001000110011101110101110000000101100101111111001011010111101001111000010110011101101000111111011101011101010010101110111000101100000011100110100011000011101111000111100110000011010001110101011011100000001000011000010111101001010100011101000001000111000011011110000000111111111010000110101000010011100001111110010100111000100111010010100001110010110110001100111011010001101001101110010100111001000101010010000010111011000000011011111010101101010100111100111100100110011101000100001011100011010010110011111110100100110000111100111101101]]", formatted);
}
@Test
public void testFormatRSAPublicKeyAsn1() throws Exception {
String dsaPublicKey = "-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJwvNh9/9zLIb1V0mI1VlbOml6\n" +
"lopNYWwV1dl4F03rg2lXVMRbsRm+rQSyZeF5pUOWRe4O6U+2IZF1JJ4T1QZwpejJ\n" +
"6AnBYnAI78HZwX7FCI8DWR81Wqk5aUpxaIWF88ciicOLJt5XW77IAeYDET8wh+gz\n" +
"SQl9rF89HNQhZ0NyGwIDAQAB\n" +
"-----END PUBLIC KEY-----\n";
byte[] der = extractDerContent(CodePointIterator.ofString(dsaPublicKey));
String formatted = ASN1.formatAsn1(new DERDecoder(der));
assertEquals("[sequence:[sequence:[oid:1.2.840.113549.1.1.1][null]][bits:0011000010000001100010010000001010000001100000010000000010001001110000101111001101100001111101111111111101110011001011001000011011110101010101110100100110001000110101010101100101011011001110100110100101111010100101101000101001001101011000010110110000010101110101011101100101111000000101110100110111101011100000110110100101010111010101001100010001011011101100010001100110111110101011010000010010110010011001011110000101111001101001010100001110010110010001011110111000001110111010010100111110110110001000011001000101110101001001001001111000010011110101010000011001110000101001011110100011001001111010000000100111000001011000100111000000001000111011111100000111011001110000010111111011000101000010001000111100000011010110010001111100110101010110101010100100111001011010010100101001110001011010001000010110000101111100111100011100100010100010011100001110001011001001101101111001010111010110111011111011001000000000011110011000000011000100010011111100110000100001111110100000110011010010010000100101111101101011000101111100111101000111001101010000100001011001110100001101110010000110110000001000000011000000010000000000000001]]", formatted);
}
@Test
public void testFormatECPublicKeyAsn1() throws Exception {
String dsaPublicKey = "-----BEGIN PUBLIC KEY-----\n" +
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4r0DR0jxgNK4RGCpXrpS8qXot2/3\n" +
"YtoGAW5fLU7+93mHRBNyW16JWUYH9RDa7igYb29MpIzX6w82cgt494xn/g==\n" +
"-----END PUBLIC KEY-----\n";
byte[] der = extractDerContent(CodePointIterator.ofString(dsaPublicKey));
String formatted = ASN1.formatAsn1(new DERDecoder(der));
assertEquals("[sequence:[sequence:[oid:1.2.840.10045.2.1][oid:1.2.840.10045.3.1.7]][bits:0000010011100010101111010000001101000111010010001111000110000000110100101011100001000100011000001010100101011110101110100101001011110010101001011110100010110111011011111111011101100010110110100000011000000001011011100101111100101101010011101111111011110111011110011000011101000100000100110111001001011011010111101000100101011001010001100000011111110101000100001101101011101110001010000001100001101111011011110100110010100100100011001101011111101011000011110011011001110010000010110111100011110111100011000110011111111110]]", formatted);
}
}