Search code examples
javabouncycastledeprecated

Java BouncyCastle getObject() in ASN1TaggedObject has been deprecated how to replace?


When upgrading to version 1.71 of BouncyCastle we get following warning when compiling:

warning: [deprecation] getObject() in ASN1TaggedObject has been deprecated ASN1OctetString url = (ASN1OctetString) location.getObject();

I can see from:

https://javadoc.io/doc/org.bouncycastle/bcprov-jdk15on/latest/org/bouncycastle/asn1/ASN1TaggedObject.html#getTagClass--

following description:

getObject() Deprecated. Tagged objects now include the tag class. This method will raise an exception if it is not BERTags.CONTEXT_SPECIFIC. Use getBaseUniversal(boolean, int) only after confirming the expected tag class.

I have no clue how to rewrite the getObject()

    protected static void getAuthorityInfoExtensionValue(byte[] extensionValue,
        CertSignatureInformation certInfo) throws IOException
{
    ASN1Sequence asn1Seq = (ASN1Sequence) JcaX509ExtensionUtils.parseExtensionValue(extensionValue);
    Enumeration<?> objects = asn1Seq.getObjects();
    while (objects.hasMoreElements())
    {
        // AccessDescription
        ASN1Sequence obj = (ASN1Sequence) objects.nextElement();
        ASN1Encodable oid = obj.getObjectAt(0);
        // accessLocation
        ASN1TaggedObject location = (ASN1TaggedObject) obj.getObjectAt(1);

        if (X509ObjectIdentifiers.id_ad_ocsp.equals(oid)
                && location.getTagNo() == GeneralName.uniformResourceIdentifier)
        {
            ASN1OctetString url = (ASN1OctetString) location.getObject();
            certInfo.setOcspUrl(new String(url.getOctets()));  
        }
        else if (X509ObjectIdentifiers.id_ad_caIssuers.equals(oid))
        {
            ASN1OctetString uri = (ASN1OctetString) location.getObject();
            certInfo.setIssuerUrl(new String(uri.getOctets()));
        }
    }
}

or this

    /**
 * Gets the first CRL URL from given extension value. Structure has to be
 * built as in 4.2.1.14 CRL Distribution Points of RFC 2459.
 *
 * @param extensionValue to get the extension value from
 * @return first CRL- URL or null
 * @throws IOException when there is a problem with the extensionValue
 */
protected static String getCrlUrlFromExtensionValue(byte[] extensionValue) throws IOException
{
    ASN1Sequence asn1Seq = (ASN1Sequence) JcaX509ExtensionUtils.parseExtensionValue(extensionValue);
    Enumeration<?> objects = asn1Seq.getObjects();

    while (objects.hasMoreElements())
    {
        Object obj = objects.nextElement();
        if (obj instanceof ASN1Sequence)
        {
            String url = extractCrlUrlFromSequence((ASN1Sequence) obj);
            if (url != null)
            {
                return url;
            }
        }
    }
    return null;
}

private static String extractCrlUrlFromSequence(ASN1Sequence sequence)
{
    ASN1TaggedObject taggedObject = (ASN1TaggedObject) sequence.getObjectAt(0);
    taggedObject = (ASN1TaggedObject) taggedObject.getObject();
    if (taggedObject.getObject() instanceof ASN1TaggedObject)
    {
        taggedObject = (ASN1TaggedObject) taggedObject.getObject();
    }
    else if (taggedObject.getObject() instanceof ASN1Sequence)
    {
        // multiple URLs (we take the first)
        ASN1Sequence seq = (ASN1Sequence) taggedObject.getObject();
        if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
        {
            taggedObject = (ASN1TaggedObject) seq.getObjectAt(0);
        }
        else
        {
            return null;
        }
    }
    else
    {
        return null;
    }
    if (taggedObject.getObject() instanceof ASN1OctetString)
    {
        ASN1OctetString uri = (ASN1OctetString) taggedObject.getObject();
        String url = new String(uri.getOctets());

        // return first http(s)-Url for crl
        if (url.startsWith("http"))
        {
            return url;
        }
    }
    // else happens with http://blogs.adobe.com/security/SampleSignedPDFDocument.pdf
    return null;
}

so this warning disappears.

Any help much appreciated.


Solution

  • When asking for how to parse some ASN.1 structure, you would ideally give the ASN.1 definitions involved. In this case it's especially important since correctly parsing a tagged object requires knowing the tag definition (as well as whether implicit tagging is enabled in the relevant ASN.1 module).

    The old getObject assumed you had already checked the tag number (getTagNo) and it also only worked for CONTEXT_SPECIFIC tags using explicit tagging.

    A reasonable guess at a replacement would be:

    ASN1Util.getContextBaseUniversal(location, tagNo, true, BERTags.OCTET_STRING)
    

    where 'tagNo' is the tag number, which ought to be known at the call site, and 'true' indicates the field is using explicit tagging.


    From your example code we can see that the overall extension being parsed here is an Authority Information Access (read about the extension here); technically the ASN.1 type is AuthorityInfoAccessSyntax. It's worth reading that section to understand in particular that the 'accessLocation' (being a GeneralName) can take several forms (though I assume it's OK to only process the URI one if you can't make use of the others).

    BouncyCastle already has a class for parsing these:

    org.bouncycastle.asn1.x509.AuthorityInformationAccess
    

    So you could rewrite your method something like this:

    protected static void getAuthorityInfoExtensionValue(byte[] extensionValue,
        CertSignatureInformation certInfo) throws IOException
    {
        AuthorityInformationAccess authInfo = AuthorityInformationAccess.getInstance(
            JcaX509ExtensionUtils.parseExtensionValue(extensionValue));
    
        for (AccessDescription accessDescription : authInfo.getAccessDescriptions())
        {
            ASN1ObjectIdentifier accessMethod = accessDescription.getAccessMethod();
            GeneralName accessLocation = accessDescription.getAccessLocation();
    
            if (X509ObjectIdentifiers.id_ad_ocsp.equals(accessMethod))
            {
                if (GeneralName.uniformResourceIdentifier == accessLocation.getTagNo())
                {
                    ASN1IA5String uri = ASN1IA5String.getInstance(accessLocation.getName());
                    certInfo.setOcspUrl(uri.getString());
                }
            }
            else if (X509ObjectIdentifiers.id_ad_caIssuers.equals(accessMethod))
            {
                if (GeneralName.uniformResourceIdentifier == accessLocation.getTagNo())
                {
                    ASN1IA5String uri = ASN1IA5String.getInstance(accessLocation.getName());
                    certInfo.setIssuerUrl(uri.getString());
                }
            }
        }
    }
    

    You should probably also deal with the possibility of there being multiple access descriptions for a given access method (so potentially multiple URIs).


    For your second example (getCrlUrlFromExtensionValue), BC has this ASN.1 type (refer also to RFC 5280 4.2.1.13):

    org.bouncycastle.asn1.x509.CRLDistPoint
    

    Example code:

        CRLDistPoint crlDistPoint = CRLDistPoint.getInstance(
            JcaX509ExtensionUtils.parseExtensionValue(extensionValue));
        for (DistributionPoint distPoint : crlDistPoint.getDistributionPoints())
        {
            GeneralNames crlIssuer = distPoint.getCRLIssuer();
            if (crlIssuer != null)
            {
                for (GeneralName name : crlIssuer.getNames())
                {
                    // Look for URI as in first example
                }
            }
        }