Search code examples
javacertificatebouncycastlex509certificate

Using DEROctetString vs pure Extension


I am using bouncy castle librarires to add extensions to my X509V3Certificate certificate.Let's say that I want to add ExtendedKeyUsage extension to my certificate.I am using X509V3CertificateBuilder class and addExtension() method so I do this.

   X509V3CertificateBuilder cf=...;
   ExtendedKeyUsage eku = new ExtendedKeyUsage(KeyPurposeId.anyExtendedKeyUsage);
cf.addExtension(Extension.ExtendedKeyUsage, false , eku);

But what I am seeing in some examples all over the web , people are doing next thing

cf.addExtension(Extension.ExtendedKeyUsage, false, new DEROctetString(eku));

I don't get any warnings from compiler when I use first method(without DEROctetString) but I don't know what is the difference, which way is better, and are they both correct?


Solution

  • TLDR: your (first) method is correct

    For background, the actual extensions field in (the body=TBSCertificate of) an X.509 certificate represents/encodes the value of each extension as an OCTET STRING 'wrapping' the DER encoding of the actual value.

    But in Bouncy when calling the older overloads of X509v3CertificateBuilder.addExtension whose third paramater is either ASN1Encodable (the value object) or byte[] (its encoding) you don't need to do the OCTET STRING yourself; the ExtensionsGenerator used internally by the builder does it for you. In fact, creating DEROctetString yourself here actually creates (a cert containing) an extension whose value is 'double wrapped' -- an OCTET STRING containing the DER of another OCTET STRING containing the DER of the actual value, which is wrong.

    However, recent versions (1.53 up) contain another overload which instead of separate OID, boolean, value takes a single org.bouncycastle.asn1.x509.Extension object which contains those three -- and creating that object is different: its constructors take either the encoding (and wrap it) or a DEROctetString object you create yourself, and whose constructors in turn take either the encoding or the encodable. (It's actually declared as the superclass ASN1OctetString but you want to use the DER subclass because cert bodies need to be entirely DER.) Thus (any of) the following are also correct:

    certbuilder.addExtension(new Extension(Extension.extendedKeyUsage, false, eku.getEncoded()))
    certbuilder.addExtension(new Extension(Extension.extendedKeyUsage, false, new DEROctetString(eku)))
    certbuilder.addExtension(new Extension(Extension.extendedKeyUsage, false, new DEROctetString(eku.getEncoded())))
    

    Are you sure it is not one of the latter two that you saw elsewhere?