'How to parse the ASN.1 object and get the data using bouncycastle in java
I have an ASN.1 data which contain some URL info and certificates data. Now I am trying to parse the data. I am using the dump method which is shown below.
private static void dump(ASN1Object obj, StringBuffer buf, int depth) throws Exception
{
indent(buf, depth);
if (obj == null)
{
buf.append("Null").append(NL);
}
else if (obj instanceof DERBitString)
{
try {
DERBitString dbr = (DERBitString)obj;
Log.e("Testing", "DERBitString length:"+dbr.getBytes().length);
} catch (Exception e) {
// TODO: handle exception
Log.e("Testing", "Exception :"+e);
}
// buf.append("DERBitString : ").append(((DERBitString)obj).getBytes().length * 8).append(" bits").append(NL);
buf.append("DERBitString content111 : ").append(new String(((DERBitString)obj).getBytes())).append(NL);
cert.write(obj.getEncoded());
}
else if (obj instanceof ASN1String)
{
Log.i("Testing", "Hashcode:"+obj.hashCode());
buf.append("ASN1String : ").append(((ASN1String)obj).getString()).append(NL);
if(numOctString == 1 && sURL == null )
{
sURL = ((ASN1String)obj).getString();
}
else
{
cert.write(obj.getEncoded());
}
}
else if (obj instanceof ASN1UTCTime)
{
buf.append("ASN1UTCTime : ").append(((ASN1UTCTime)obj).getTime()).append(NL);
cert.write(obj.getEncoded());
}
else if (obj instanceof ASN1GeneralizedTime)
{
buf.append("ASN1GeneralizedTime : ").append(((ASN1GeneralizedTime)obj).getTime()).append(NL);
cert.write(obj.getEncoded());
}
else if (obj instanceof ASN1ObjectIdentifier)
{
buf.append("ASN1ObjectIdentifier : ").append((ASN1ObjectIdentifier)obj).append(NL);
ASN1ObjectIdentifier identifier = (ASN1ObjectIdentifier)obj;
cert.write(obj.getEncoded());
//buf.append("ASN1ObjectIdentifier : ").append(OidMap.get(((ASN1ObjectIdentifier)obj).getId())).append(NL);
}
else if (obj instanceof ASN1Integer)
{
buf.append("ASN1Integer : ").append(((ASN1Integer)obj).getValue().toString()).append(NL);
cert.write(obj.getEncoded());
}
else if (obj instanceof ASN1Boolean)
{
buf.append("ASN1Boolean : ").append(((ASN1Boolean)obj).isTrue() ? "true" : "false").append(NL);
cert.write(obj.getEncoded());
}
else if (obj instanceof ASN1OctetString)
{
numOctString ++;
buf.append("ASN1OctetString").append(NL);
ASN1OctetString octObj = (ASN1OctetString)obj;
try
{
ASN1InputStream aIn = new ASN1InputStream(octObj.getOctetStream());
ASN1Primitive dobj = aIn.readObject();
dump(dobj, buf, depth + 1);
}
catch(Exception e)
{
indent(buf, depth + 1);
//buf.append(ByteArrayUtil.toHexString(octObj.getOctets(), ":")).append(NL);
}
}
else if (obj instanceof ASN1TaggedObject)
{
buf.append("ASN1TaggedObject").append(NL);
dump(((ASN1TaggedObject)obj).getObject(), buf, depth + 1);
}
else if (obj instanceof ASN1Sequence)
{
buf.append("ASN1Sequence").append(NL);
Enumeration objs = ((ASN1Sequence)obj).getObjects();
while (objs.hasMoreElements())
{
Object o = objs.nextElement();
if (o == null || o instanceof DERNull)
{
indent(buf, depth + 1);
//ASN1VectorImpl impl= new ASN1VectorImpl((ASN1Sequence)obj);
buf.append("DERNull").append(NL);
}
else if (o instanceof ASN1Primitive)
{
dump((ASN1Primitive)o, buf, depth + 1);
}
else
{
dump(((ASN1Encodable)o).toASN1Primitive(), buf, depth + 1);
}
}
}
else if (obj instanceof ASN1Set)
{
buf.append("ASN1Set").append(NL);
Enumeration objs = ((ASN1Set)obj).getObjects();
while (objs.hasMoreElements())
{
Object o = objs.nextElement();
if (o == null || o instanceof DERNull)
{
indent(buf, depth + 1);
buf.append(NL);
}
else if (o instanceof ASN1Primitive)
{
dump((ASN1Primitive)o, buf, depth + 1);
}
else
{
dump(((ASN1Encodable)o).toASN1Primitive(), buf, depth + 1);
}
}
}
else
{
Log.e("Testing", "==================Else case=============");
Log.e("Testing", "==================obj============="+obj.getEncoded().length);
buf.append(obj.getClass().getName()).append(NL);
}
}
When I print the StringBuffer i am getting the output as below.
ASN1Sequence
ASN1Sequence
ASN1String : 1
ASN1OctetString
ASN1Sequence
ASN1String : https://website url(Some StringDta )
ASN1String : StringDta
ASN1Sequence
ASN1OctetString
ASN1Sequence
ASN1Sequence
ASN1TaggedObject
ASN1Integer : 2
ASN1Integer : 288799720653653968683086
ASN1Sequence
ASN1ObjectIdentifier : 1.2.840.113549.1.1.5
DERNull
ASN1Sequence
ASN1Set
ASN1Sequence
ASN1ObjectIdentifier : 2.5.4.3
ASN1String : StringDta
ASN1Sequence
ASN1UTCTime : 130417071944GMT+00:00
ASN1UTCTime : 140417072944GMT+00:00
ASN1Sequence
ASN1Set
ASN1Sequence
ASN1ObjectIdentifier : 2.5.4.10
ASN1String : StringDta
ASN1Set
ASN1Sequence
ASN1ObjectIdentifier : 2.5.4.3
ASN1String : StringDta
ASN1Set
ASN1Sequence
ASN1ObjectIdentifier : 1.2.840.113549.1.9.1
ASN1String : StringDta
ASN1Sequence
ASN1Sequence
ASN1ObjectIdentifier : 1.2.840.113549.1.1.1
DERNull
DERBitString content111 : 0?
?
Now how can parse the above data to get the required data like URL and certificates data?
How can we identify the URL and certificates data from above output? Can some one help on this?
Solution 1:[1]
The ASN.1 encoded object only contains the structured data but not the meaning of every field. An ASN.1 module is required in order to decode meaningful data from the object. The module is a data specification, its purpose is to name a set of types and (optionally) values definitions.
For instance this is the ASN.1 module for X.509 certificates: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1
Now, assuming that your ASN.1 module defines this structure
MyData ::= SEQUENCE {
websiteURL UTF8String (SIZE (1..MAX)),
certificate Certificate,
}
You can decode this object with this small code snippet:
public void decode(byte[] encoding) throws Exception
{
ASN1Sequence seq = ASN1Sequence.getInstance(encoding);
String url = DERUTF8String.getInstance(seq.getObjectAt(0)).getString();
CertificateFactory factory = CertificateFactory.getInstance("X.509");
byte[] certEnc = seq.getObjectAt(1).toASN1Primitive().getEncoded();
Certificate cert = factory.generateCertificate(new ByteArrayInputStream(certEnc));
}
UPDATE Dec, 7th
According to the ASN.1 decoding tree you gave I think that the certificate is contained in the second Octet String Object:
ASN1Sequence
ASN1Sequence
ASN1String : 1
ASN1OctetString
ASN1Sequence
ASN1String : https://website url(Some StringDta )
ASN1String : StringDta
ASN1Sequence
ASN1OctetString
ASN1Sequence <-- IMHO the certificate starts here
ASN1Sequence
ASN1TaggedObject
ASN1Integer : 2
ASN1Integer : 288799720653653968683086
...
You need to get the ASN1OctetString
object from the sequence, get the byte[] it wraps and decode the certificate.
ASN1Sequence seq = ...
ASN1OctetString ostr = ASN1OctetString.getInstance(seq.getObjectAt(0));
byte[] encodedCertificate = ostr.getOctets();
Certificate cert = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(encodedCertificate));
You can also use openssl ans1parse command to print more details on the ASN.1 objects
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Community |