Search code examples
c#itextdigital-signaturebouncycastlesigning

BouncyCastle Error "Unable to cast object of type 'Org.BouncyCastle.Asn1.DerSequence' to type 'Org.BouncyCastle.Asn1.DerOctetString'


Woking with BouncyCastle and trying to casting Asn1Object to DerOctetString

DerOctetString dosCrlDP = (DerOctetString)derObjCrlDP;

Getting the casting error: "Unable to cast object of type 'Org.BouncyCastle.Asn1.DerSequence' to type 'Org.BouncyCastle.Asn1.DerOctetString'."

The full code is given below

public List<string> getCrlDistributionPoints(Org.BouncyCastle.X509.X509Certificate cert)
{
    byte[] crldpExt = cert.GetExtensionValue(X509Extensions.CrlDistributionPoints.Id).GetOctets();
    if ((crldpExt == null))
    {
        List<string> emptyList;
        return emptyList;
    }

    Asn1InputStream oAsnInStream = null/* TODO Change to default(_) if this is not a reference type */;
    Asn1InputStream oAsnInStream2 = null/* TODO Change to default(_) if this is not a reference type */;
    List<string> crlUrls;
    try
    {
        oAsnInStream = new Asn1InputStream(new MemoryStream(crldpExt));
        Asn1Object derObjCrlDP = oAsnInStream.ReadObject;
        //Getting the casting error.
        DerOctetString dosCrlDP = (DerOctetString)derObjCrlDP;
        byte[] crldpExtOctets = dosCrlDP.GetOctets;
        oAsnInStream2 = new Asn1InputStream(new MemoryStream(crldpExtOctets));
        Asn1Object derObj2 = oAsnInStream2.ReadObject;
        CrlDistPoint distPoint = CrlDistPoint.GetInstance(derObj2);
        foreach (DistributionPoint dp in distPoint.GetDistributionPoints)
        {
            DistributionPointName dpn = dp.DistributionPointName;
            // Look for URIs in fullName
            if ((!(dpn) == null))
            {
                if (dpn.GetType.Name == DistributionPointName.FullName)
                {
                    GeneralName[] genNames = GeneralNames.GetInstance(dpn.Name).GetNames;
                    // Look for an URI
                    int j = 0;
                    while ((j < genNames.Length))
                    {
                        if ((genNames[j].TagNo == GeneralName.UniformResourceIdentifier))
                        {
                            string url = DerIA5String.GetInstance(genNames[j].Name).GetString;
                            crlUrls.Add(url);
                        }

                        j = (j + 1);
                    }
                }
            }
        }
    }
    catch (IOException e)
    {
        throw new Exception(e.Message, e);
    }

    return crlUrls;
}

I have no idea how to deal with it.

Please share ideas, suggestions, and working code. or any alternatives.

Thanks in advance.


Solution

  • In a comment you say

    Check this link and see how casting works in this java code: https://stackoverflow.com/a/46330079/18803035

    The difference between that code and yours is that in the Java code there is

    final byte[] crldpExt = cert.getExtensionValue(X509Extension.cRLDistributionPoints.getId());
    

    while in your C# code you have

    byte[] crldpExt = cert.GetExtensionValue(X509Extensions.CrlDistributionPoints.Id).GetOctets();
    

    Apparently, the Java cert.getExtensionValue returns a byte[] while the C# cert.GetExtensionValue returns something with a GetOctets() method. Looking into the (open source!!) code of .NET BouncyCastle one sees that the C# version actually returns an Asn1OctetString object of which you call that GetOctets() method.

    Thus, while the Java code first has to put the retrieved byte[] into an ASN1InputStream and call readObject() to get an ...OctetString object, the C# code already has that ...OctetString object. Furthermore, your call of GetOctets() retrieves the content contained in the octet string, not an encoding of that full octet string object anymore.

    In the code lines quoted above, therefore, the C# code already is one step ahead of the Java code in the process of unwrapping the information. So you have to remove the extra code required for that step in Java.

    In other words, as a quick fix replace

    oAsnInStream = new Asn1InputStream(new MemoryStream(crldpExt));
    Asn1Object derObjCrlDP = oAsnInStream.ReadObject;
    //Getting the casting error.
    DerOctetString dosCrlDP = (DerOctetString)derObjCrlDP;
    byte[] crldpExtOctets = dosCrlDP.GetOctets;
    

    by

    byte[] crldpExtOctets = crldpExt;
    

    Beware, I did not check whether there are similar differences in the following code, too, where you'd have to consider what you actually do.


    As a side note, there not only are certain differences between the Java and the .NET version of BouncyCastle; actually there are certain breaking changes between arbitrary BouncyCastle versions even though the version numbers may differ only in the minor position. Thus, whenever re-using BouncyCastle code you find somewhere, be prepared to have to look up and compare the BouncyCastle APIs used by your source and by you unless you're using the exactly identical version.