'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