{"id":407,"date":"2008-10-27T21:01:07","date_gmt":"2008-10-28T02:01:07","guid":{"rendered":"http:\/\/unitstep.net\/?p=407"},"modified":"2008-11-06T18:39:48","modified_gmt":"2008-11-06T23:39:48","slug":"extracting-x509-extensions-from-a-csr-using-the-bouncy-castle-apis","status":"publish","type":"post","link":"https:\/\/unitstep.net\/blog\/2008\/10\/27\/extracting-x509-extensions-from-a-csr-using-the-bouncy-castle-apis\/","title":{"rendered":"Extracting X509 Extensions from a CSR using the Bouncy Castle APIs"},"content":{"rendered":"
The Bouncy Castle Cryptography Java APIs<\/a> are an excellent set of APIs that act as a provider for JCE and JCA. Additionally, they take care of the mundane and tedious (some would say overly complicated) details involved in reading and creating the data structures associated with the X.500 and PKCS standards. (The APIs are also available in C#, for .NET developers out there)<\/p>\n One thing they handle well is the concept of certificate extensions. X.509 v3 certificates introduced the concept of these extensions, which are basically additional (potentially optional) fields containing information not contained in the older original X.509 specifications. Each extension is specified by an OID (Object Identifier); a good list of these extensions<\/a> is available.<\/p>\n While it’s easy to read these extensions from an existing X.509 v3 certificate using the Bouncy Castle APIs it is a bit more involved to read these extensions from a Certificate Signing Request<\/a>, or CSR; this is the data structure that is sent to a CA to request a certificate. The CA then reads the data from this and creates a signed certificate issued to the requester. In this guide I’ll present a brief way to extract X.509 extensions request<\/a> from a CSR so that they may be included in the resulting issued certificate.<\/p>\n <\/p>\n Assuming you have added the Bouncy Castle JARs to your classpath, you should have access to the classes used here. <\/p>\n You must first have the CSR in the format of a Bouncy Castle data object, namely the We first decode the PEM (Base64) CSR into We then grab the first entry in the list, checking if it is a CSR. We can now convert this into the proper data structure by supplying the raw bytes (i.e. the DER-encoded format) to the constructor of The method to extract the Basically, we get the certificate request info from the CSR structure and then extract attributes from it. Then, we loop through to find the attribute with the “Extension Request” OID<\/a>.<\/p>\n After that, I make an assumption that the actual extensions are contained in the first value of the place of the ASN.1 Set that makes up the “Extensions Request” structure – not a big assumption, and in my testing I haven’t encountered a situation where this wasn’t the case. It’s worthwhile to keep in mind that ASN.1 often prescribes Set or multi-value structures in places where the underlying data can only be single-valued. <\/p>\n After running through that code, we’ll have either found the extensions, and be returning them in a Once you have the Note that a CA is not required<\/em> to use any of the extension requests present in a CSR – hence the name “requests”. It is entirely up to the CA to decide what extensions are appropriate, along with their values, for the certificates that it issues. <\/p>\n The code is a little complicated and could probably benefit from some refactoring. However, a lot of the complexity derives from the fact that the X.509 and associated standards are quite complex themselves. This is a reflection on the vision that the designers of X.509 had for the future of the standard. However, the complexity of X.509<\/a> is another topic for another article. <\/p>\nCode: The good stuff<\/h3>\n
PKCS10CertificationRequest<\/code><\/a>. If all you have is the PEM-format of the CSR (i.e. Base64-encoded contents delimited by headers like
----- BEGIN CERTIFICATE REQUEST -----<\/code> and
----- END CERTIFICATE REQUEST -----<\/code>) then you will need to convert this to the proper data structure using something like
\nPEMUtil<\/a> from Commons-SSL like I have done below. (BC has a PEMUtil<\/a> class as well, but it appears to be only for internal use)<\/p>\n\/\/ NOTE: Commons-SSL doesn't support generics.\r\nfinal List pemItems = PEMUtil.decode( csrContent.getBytes() );\r\n\r\n\/\/ Verify list isn't empty - uses Apache Commons Lang.\r\nValidate.isTrue( !pemItems.isEmpty() );\r\n\r\n\/\/ No support for generics, so have to cast. (Could have cast the entire List)\r\nfinal PEMItem csrPemFormat = (PEMItem) pemItems.get( 0 );\r\n\r\n\/\/ Verify the type.\r\nValidate.isTrue( csrPemFormat.pemType.equals( \"CERTIFICATE REQUEST\" ), \r\n \"This is not a CSR\" );\r\n\r\nfinal PKCS10CertificationRequest csr = new PKCS10CertificationRequest( \r\n csrPemFormat.getDerBytes() );<\/code><\/pre>\n
List<\/code> of
PEMItem<\/code><\/a>s. Note that Commons-SSL doesn’t support generics<\/a>, so you are going to get a cast warning somewhere in the code, no matter what. When calling
getBytes()<\/code> on the CSR string, you may want to specify the
US-ASCII<\/code> character set, since the no-arg method uses the platform default character set, which might give inconsistent results across different systems when converting from characters to bytes. <\/p>\n
PKCS10CertificationRequest<\/code>.<\/p>\n
X509Extensions<\/code><\/a> structure from the
PKCS10CertificationRequest<\/code> is shown below.<\/p>\n
\/**\r\n * Gets the X509 Extensions contained in a CSR (Certificate Signing Request).\r\n *\r\n * @param certificateSigningRequest the CSR.\r\n * @return the X509 Extensions in the request.\r\n * @throws CertificateException if the extensions could not be found.\r\n *\/\r\n X509Extensions getX509ExtensionsFromCsr(\r\n final PKCS10CertificationRequest certificateSigningRequest ) throws CertificateException\r\n {\r\n final CertificationRequestInfo certificationRequestInfo = certificateSigningRequest\r\n .getCertificationRequestInfo();\r\n\r\n final ASN1Set attributesAsn1Set = certificationRequestInfo.getAttributes();\r\n\r\n \/\/ The `Extension Request` attribute is contained within an ASN.1 Set,\r\n \/\/ usually as the first element.\r\n X509Extensions certificateRequestExtensions = null;\r\n for (int i = 0; i < attributesAsn1Set.size(); ++i)\r\n {\r\n \/\/ There should be only only one attribute in the set. (that is, only\r\n \/\/ the `Extension Request`, but loop through to find it properly)\r\n final DEREncodable derEncodable = attributesAsn1Set.getObjectAt( i );\r\n if (derEncodable instanceof DERSequence)\r\n {\r\n final Attribute attribute = new Attribute( (DERSequence) attributesAsn1Set\r\n .getObjectAt( i ) );\r\n\r\n if (attribute.getAttrType().equals( PKCSObjectIdentifiers.pkcs_9_at_extensionRequest ))\r\n {\r\n \/\/ The `Extension Request` attribute is present.\r\n final ASN1Set attributeValues = attribute.getAttrValues();\r\n\r\n \/\/ The X509Extensions are contained as a value of the ASN.1 Set.\r\n \/\/ Assume that it is the first value of the set.\r\n if (attributeValues.size() >= 1)\r\n {\r\n certificateRequestExtensions = new X509Extensions( (ASN1Sequence) attributeValues\r\n .getObjectAt( 0 ) );\r\n\r\n \/\/ No need to search any more.\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (null == certificateRequestExtensions)\r\n {\r\n throw new CertificateException( \"Could not obtain X509 Extensions from the CSR\" );\r\n }\r\n\r\n return certificateRequestExtensions;\r\n }<\/code><\/pre>\n
X509Extensions<\/code><\/a> structure, or an exception will be thrown. You could modify the code to return
null<\/code> if that suits your style or purpose better.<\/p>\n
A few more notes<\/h3>\n
X509Extensions<\/code> structure you can use the extensions contained within to create\/issue a certificate with them. Check out the Bouncy Castle Guide on Certificate Generation<\/a> for more details.<\/p>\n
Code Review<\/h3>\n