Friday, October 30, 2009

X.509 Certificates


















































X.509 Certificates


X.509 certificates, covered here, have their
origins in the same OSI standards that produced X.500 and in a lot of
ways follow the demise of the original X.500 directory concept.
Originally with version 1, introduced in 1988, it was assumed that you
could use the Issuer DN of a given certificate to build the certificate
chain going back to the root; so given a collection of certificates,
you would be able to easily sort them into a chain starting at a root
and going to the end entity. This turned out to be too restrictive, and
in 1993, version 2 introduced the concepts of unique identifiers
for both the issuer and the subject to allow for reuse of DNs but still
maintained the directory structure. Finally, the whole "enterprise"
collapsed, and the concept of certificate extensions was introduced in
version 3 in 1996. This introduced concepts like key usage and
completely removed the restriction that a certificate chain had to
follow the directory structure, allowing for both a hierarchical
approach and a web of trust approach where there is no clear hierarchy, but a lot of cross dependencies.



Of
the three different types, you will probably not see any version 2
certificates, or certificates using the unique identifiers that were
added in version 2, as the use of the unique identifiers added in
version 2 was discourage with the release of version 3. There are still
a lot of X.509 version 1 certificates in use, especially for
self-signed root certificates. You will find version 3 certificates for
virtually all other applications.


Back in the Java world, support for X.509 certificates was explicitly added with the introduction of the java.security.cert package in JDK 1.2. The fundamental classes are the X509Certificate class and the X509Extension interface that's implemented by the X509Certificate class. The X509Extension interface supports the use of version 3 extensions. You'll look at the X509Certificate class first and then move onto the X509Extension interface and the methods on X509Certificate that derive from it.




The X509Certificate Class


The java.security.cert.X509Certificate
class provides the basic support for X.509 certificates. The design of
the class and the interfaces it implements is based on the following
ASN.1 structures published in X.509:


Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }

As you can see, an X.509 certificate is simply a
sequence with three fields in it. As you have probably also guessed,
most of the detail is in the tbsCertificate field, which contains the data that was used to generate the signature represented in the signatureValue field using the algorithm given by the details contained in the AlgorithmIdentifier in the signatureAlgorithm field. As you will see in a minute, the TBSCertificate
structure contains the details of the issuer of the certificate as well
as information on who it was issued for(the subject. The AlgorithmIdentifier structure is the same one you saw in Chapter 5.


I will start by detailing the TBSCertificate structure and going through the relevant methods on the X509Certificate
class so that you can see how the ASN.1 structures relate to the class.
Apart from giving you extra insight into the way the certificate class
works, referring to the ASN.1 structure will also help explain some of
the strange problems you may encounter when dealing with X.509
certificates.




X509Certificate.get TBSCertificate()


The getTBSCertificate() method returns the bytes making up the ASN.1 encoding of the TBSCertificate
structure. These are the bytes that are used as the input data for
calculating the signature the certificate carries, so if you wanted to
verify a certificate signature using the Signature class, you could do
so using the public key of the certificate issuer and the bytes
returned by getTBSCertificate(). The actual structure contained in the ASN.1 encoding that getTBSCertificate() returns is defined in X.509 as follows:



TBSCertificate ::=  SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,

validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version shall be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version shall be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version shall be v3 }

Name ::= CHOICE { RDNSequence }


and most of the get() methods that follow provide access to fields in this structure. I will ignore the extensions field for the moment, as I will cover it when in the discussion of the X509Extension interface.





X509Certificate.get Version()


The getVersion() method returns the version of the TBSCertificate structure that was used to create the certificate. The ASN.1 definition of Version is defined as follows:


Version ::= INTEGER { v1(0), v2(1), v3(2) }

Ideally, X.509 certificates will always be encoded so that if extensions is present, the version will be v3; if issuerUniqueID and subjectUniqueID are present and extensions is not the version will be v2; and if none of extensions, issuerUniqueID, and subjectUniqueID
are present, the version will be v1. However, if you are importing
certificates from a variety of possibly unknown sources, the truth is
that you cannot rely on the fact that


boolean v3 = (x509Cert .getVersion() == 3);

setting v3 to true means the extensions
field is present, as some organizations have issued certificates that
purport to be version 3 but could really be accommodated using version
1.


The getVersion() method diverts from what is in the encoded certificate in that it returns 3 if the certificate is type v3, 2 if it is of type v2, and 1 if it is of type v1. This is different from the actual version number stored in the TBSCertificate structure, since, as you can see from the ASN.1, the numbering starts with 0. In fact, as the TBSCertificate
structure is generally DER encoded, in the case of a version 1
certificate, the actual version number will not be present. Therefore,
if you need to process the contents of a TBSCertificate structure by hand, be prepared to deal with the version field being missing.





X509Certificate.get SerialNumber()


The getSerialNumber() returns a BigInteger representing the value of the serialNumber field in the TBSCertificate structure. You can see from the definition of TBSCertificate that this is of the type CertificateSerialNumber, which is defined as follows:


CertificateSerialNumber ::= INTEGER

It is very rare for these values to be represented as anything other than a BigInteger, so don't assume you can represent them as an int or a long.



Something
else that's also rare, but is possible, is that the serial number will
be negative. While the definition allows for it, it seems a bit odd
that this happens. The likelihood is that some CAs are written
forgetting that an ASN.1 INTEGER is a signed number and the
certificate generation code does not allow for a leading zero in the
case where the encoding of their internal, probably unsigned,
representation has its top bit set. Avoid using negative serial
numbers, because there are some applications out there that assume
serial numbers are always positive; likewise, avoid assuming the serial
number will always be positive. The issuer information, which you will
look at next, and the serial number serve to uniquely identify the
certificate, but any search based on this will most likely fail or
return the wrong certificate if the serial number is negative and you
have changed its sign.





X509Certificate.get IssuerX500Principal()


As you saw in the definition of the TBSCertificate structure, the issuer is simply a Name structure, so you use getIssuerX500Principal()
to retrieve the DN of the issuer of the certificate. Combined with the
serial number, the principal representing the issuer should uniquely
identify the certificate.


You have already looked at DNs and the Name structure at the start of the chapter; however, I will make one further comment. Originally, prior to JDK 1.4, there was only X509Certificate.getIssuerDN(),
which returned an object representing the X.500 name associated with
the issuer of the certificate. The major problem was that it meant the
only obvious provider-independent way to get access to the DN was via
the Object.toString() method(something you have already seen that is, at best, quite hazardous. Now you can use getIssuerX500Principal(), which returns a X500Principal object, a DN, which has a precise defined behavior, and better yet, a getEncoded() method, so that for the most part, you can avoid converting the DN into a String whenever possible.


If you are using JDK 1.3 or earlier, the Bouncy Castle API also provides a helper class in the org.bouncycastle.jce package called PrincipalUtil, which returns a Bouncy Castle-specific object, X509Principal, an equivalent to the X500Principal class. You can use the PrincipalUtil.getIssuerX509Principal()
to extract the issuer from a certificate, and the object you get back
will allow you to avoid having to convert the issuer principal into a String in order to do processing on it.





X509Certificate.getNotBefore() and X509Certificate.getNotAfter()


The getNotBefore() and getNotAfter() methods are derived from the validity field in the TBSCertificate structure. The validity field has a type Validity, which is defined as follows:


Validity ::= SEQUENCE {
notBefore Time,
notAfter Time }
Time ::= CHOICE {
utcTime UTCTime,
generalTime GeneralizedTime }

The notBefore field represents the time at which the certificate starts to be valid, and the getNotBefore() method returns it as a Date object. The notAfter field represents the last time at which the certificate will be valid, and the getNotAfter() method returns it as a Date object.


Note that the Time type can be a UTCTime, which has a two-digit year. You are unlikely to run into a new certificate carrying UTCTime
these days. However, if you expect to be using certificates, say, from
a legacy application, make sure the provider you are using for loading
the certificates is handling the conversion from a two-to a four-digit
year correctly. Otherwise, you may find certificates expiring before
their time, or staying valid much longer than they should be.





X509Certificate.check Validity()



There are two versions of the checkValidity() method.


Called without parameters, the method checks the certificate's notBefore and notAfter times against the current time and throws an exception if the certificate is not yet valid or has expired.


Called with a single date parameter, the method checks the notBefore and notAfter
times against the time represented by the date passed in and throws an
exception if the certificate was not yet valid at that date or the
certificate had already expired at that date.


The exceptions that will be thrown by checkValidity() if there is a problem with the time checking can be one of two. CertificateNotYetValidException is thrown if the time being checked is prior to the notBefore time, and CertificateExpiredException is thrown if the time being checked is after the notAfter date.





X509Certificate.get SubjectX500 Principal()


The subject field, representing the owner of the public key in the certificate, is also defined in the TBSCertificate structure as a Name, and the getSubjectX500Principal() method returns the DN for the key owner as a X500Principal. In a similar manner to getIssuerX500Principal(), originally this was often done using X509Certificate.getSubjectDN() with the same resultant problems. Whenever possible, avoid the use of getSubjectDN(). If you are using JDK 1.3 or earlier, you can use the Bouncy Castle helper class PrincipalUtil to retrieve the subject principal instead. After the same fashion as the issuer principal, you can call PrincipalUtil.getSubjectX509Principal() to return an object, which will give you more options with processing of the certificate's subject principal.





X509Certificate.get IssuerUniqueID()


You saw earlier that the issuerUniqueID field was defined as:


issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,

The ASN.1 definition of UniqueIdentifier is defined as:


UniqueIdentifier ::= BIT STRING

In the case of Java, the easiest match for an arbitrary bit string is an array of booleans, so the getissuerUniqueID() method returns a boolean array matching the BIT STRING that was in the issuerUniqueID field if it is present—a very rare occurrence; you will normally only see one in a version 2 certificate.





X509Certificate.get SubjectUniqueID()


Like the issuerUniqueID, the subjectUniqueID is defined as:


subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,

and the getSubjectUniqueID() returns an array of booleans representing the BIT STRING value that was present in the subjectUniqueID field, if the field is present. Once again, you would only expect to see this value set in version 2 certificates.





X509Certificate.get Signature()



The getSignature() method returns the bytes making up the signature stored in the BIT STRING contained in the signatureValue field. These bytes are suitable for verification with a java.security.Signature class.





X509Certificate.getSigAlgOID() and X509Certificate.getSigAlgParams()


The getSigAlgOID() method returns the value of the OBJECT IDENTIFIER in the algorithm field of the AlgorithmIdentifier structure in the signatureAlgorithm field in the Certificate structure. The getSigAlgParams() returns a byte array that represents the DER encoding of the parameters field in the AlgorithmIdentifier structure in the signatureAlgorithm field.


You would have noticed there is a signature field in the TBSCertificate structure that's also of the type AlgorithmIdentifier. The purpose of this is to provide a cross-check against the unsigned signatureAlgorithm field in the Certificate structure. The contents of the signatureAlgorithm field and the signature field will always be equal in a valid certificate.





X509Certificate.get SigAlgName()


The getSigAlgName() method will return a more
(hopefully) human-friendly version of the name that is associated with
the signature algorithm used(for example, SHA1withDSA rather than the 1.2.840.10040.4.3 that getSigAlgOID() would return.




Try It Out: Creating a Self-Signed Version 1 Certificate






This actually gives you enough to look at the
process of creating a version 1 X.509 certificate. There is not any
support for doing certificate creation directly in the JCA; however,
the Bouncy Castle APIs have X.509 certificate generators in the org.bouncycastle.x509 package. Look at the following example using the org.bouncycastle.x509. X509V1CertificateGenerator:


package chapter6;

import java.math.BigInteger;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.x509.X509V1CertificateGenerator;
/**
* Basic X.509 V1 Certificate creation.
*/
public class X509V1CreateExample
{
public static X509Certificate generateV1Certificate(KeyPair pair)
throws InvalidKeyException, NoSuchProviderException, SignatureException
{
// generate the certificate


X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();

certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setIssuerDN(new X500Principal("CN=Test Certificate"));
certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000));
certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000));
certGen.setSubjectDN(new X500Principal("CN=Test Certificate"));
certGen.setPublicKey(pair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");

return certGen.generateX509Certificate(pair.getPrivate(), "BC");
}

public static void main(String[] args) throws Exception
{
// create the keys
KeyPair pair = Utils.generateRSAKeyPair();

// generate the certificate
X509Certificate cert = generateV1Certificate(pair);

// show some basic validation
cert.checkValidity(new Date());

cert.verify(cert.getPublicKey());

System.out.println("valid certificate generated");
}
}

Running the example should produce the line


valid certificate generated

on standard output.


















How It Works


The heart of the example is the generator method(generateV1Certificate(). Going through the setting up of the X509V1CertificateGenerator object, you can see that the set() methods called correspond to the setting of the fields you have just looked at in the TBSCertficate structure and are closely equivalent to the names used in the get() methods implemented by the X509Certificate class. There are a few things worth noting, so I will go through the use of the generator class step-by-step.


First off, the serial number for the certificate is set on the following line:



certGen1.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));


The best way to create serial numbers is largely up to
the environment you are working in. The main thing is they need to be
positive and unique for a given issuer value. Keep in mind that,
because it is a BigInteger, you have a few bits you can work
with, so it should always be possible to come up with an algorithm that
will make sure the numbers are unique.



The
next thing that is done is that the issuer of the certificate is
assigned. As you would expect, this is simply an X.500 name, so I used
an X500Principal to do this.



certGen1.setIssuerDN(new X500Principal("CN=Test Certificate"));


After the issuer, the notBefore and notAfter fields are set.



certGen1.setNotBefore(new Date(System.currentTimeMillis() - 50000));
certGen1.setNotAfter(new Date(System.currentTimeMillis() + 50000));


The generator object uses a GeneralizedTime to represent these dates, so the certificate you are producing will have a four-digit year on it. You can see from the Date
objects being used that while the certificate will be valid when the
program finishes, it has a total lifetime of only 100 seconds, 50 of
which have already gone when it is created.


After setting the dates, you set the subject. Like the issuer this is also an X500Principal and, because the certificate is self-signed, has the same value as the issuer.



certGen1.setSubjectDN(new X500Principal("CN=Test Certificate"));


In the normal case, where the subject, or owner of the
public key, is a different entity from the entity issuing the
certificate, you would expect the X500Principal passed to the setSubjectDN() method to be different from that passed to setIssuerDN().


Next, the example sets the public key that will be carried in the certificate:


certGen1.setPublicKey(pair.getPublic());

After this, you specify the signature algorithm that
will be used to sign the certificate. In this case you are using
SHA-256 with RSA with the signature format, as outlined in PKCS #1
version 1.5.


certGen1.setSignatureAlgorithm("SHA256WithRSAEncryption");

Finally, you generate the certificate, providing a private key to sign it with and the name of the provider you want to use:



return certGen1.generateX509Certificate(pair.getPrivate(), "BC");


Because this certificate is self-signed, it just
uses the private key that corresponds to the public key on the
certificate. As you will see a bit later when you read about
certification requests, you would normally be using a completely
different private key to sign a certificate with(the private key you
would use would be the one corresponding to the public key on the CA
certificate that you issued for yourself so that people could check
that certificates claiming to be issued by you really were.






X.509 Extensions


The extensions field in the TBSCertificate structure was added with the release of X.509 version 3. As you can see from the original definition of TBSCertificate, it is optional, explicitly tagged, and of the type Extensions. The ASN.1 definition of Extensions is as follows:



Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension

Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING }


MAX, of course, is implementation-dependent, but will normally
always be big enough for the purposes of accommodating any certificates
you have to deal with.


You can see that the actual Extension type is a three-member sequence. First, there is the extnID field, which identifies what extension is contained in an Extension structure and how to interpret the bytes in the extnValue field. Next, there is the critical
field, which determines whether or not an implementation trying to
process a X.509 certificate must be able to understand the extension if
it is to process the certificate correctly. Finally, there is the extnValue field, which contains a DER encoding of the type associated with an extension associated with the identifier stored in the extnID field.


X.509 does not cover all the possibilities for extensions. Getting coverage on this is dependent on what profile
the certificate is being created for. The signature on a certificate
being valid is one thing, but you also need to know that the
certificate is being valid for the use it is being presented to you
for, and this is where the profile comes in. In the case of
certificates, a profile tells you which extensions should be critical,
what the allowed values of some of the certificates extensions might
be, what extensions might have to be present, and which criteria must
be met for a certificate chain to be recognized as valid. For example,
I may trust an individual enough to sign a certificate for you to allow
you to send signed e-mail, but it is another thing completely to trust
someone to the level where I would expect another party to accept an
executable signed with a certificate I had issued and think I had
verified that the executable was not going to cause mischief. Aprofile
provides the guidelines that allow someone that has been presented with
a certificate to decide not only whether a particular CA signed the
certificate, but also whether the certificate is being presented for a
use that the CA issued it for.


There are now quite a few profiles, the most prevalent
one probably being the Internet profile, also known as PKIX, which is
covered in RFC 3280. Most providers will endeavor to conform to the
PKIX profile, but which profile you should be using will also depend a
lot on what environment you are working in, as many national standards
bodies now have their own idea of what constitutes a good profile, and
not all of them are in agreement.


That completes the background information on the
outside world's view of extensions. Now you will have a look at the
Java support for extensions.





The X509Extension Interface


The X509Extension interface provides some basic
methods for investigating the extensions that are present in an X.509
certificate. It allows you to find out which extensions are critical
and which are not, to get the value for a particular extension, and,
finally, to check if there are any extensions that are unsupported by
the profile the extension was created in.




X509Extension.get CriticalExtensionsOIDs()



The getCriticalExtensionsOIDs() method returns a possibly empty set of String
objects representing the object identifiers related to the extensions
marked as critical—that is, with the critical field set to TRUE—in the implementing certificate. If there are no extensions present in the implementing certificate, the method returns null.





X509Extension.get ExtensionValue()


The getExtensionValue() method takes a string
representing the object identifier of the extension you are interested
in getting the value for. The method returns a byte array containing
the DER-encoded OCTET STRING that is present in the extnValue field in the Extension structure associated with the passed in OID, or null if an extension related to that OID is not present.


Note the words "the method returns the OCTET STRING stored in the extnValue
field." If you need to do further examinations on the structure
associated with the extension, you will need to do something like the
following to convert the byte array you get back from the method into
the type that is indicated by the extension's OID:



ASN1InputStream aIn = new ASN1InputStream(
x509Cert .getExtensionValue(extensionOID));
ASN1OctetString extnValue = (ASN1OctetString)aIn.readObject();

aIn = new ASN1InputStream(extnValue.getOctets());

DERObject extensionType = aIn.readObject();


The value extensionType will then contain
the ASN.1 predefined types making up the structure that is associated
with the object identifier indicated by extensionOID.





X509Extension.get NonCriticalExtensionOIDs()


The getCriticalExtensoinsOIDs() method returns a possibly empty set of String
objects representing the object identifiers related to the extensions
not marked as critical—that is, with the critical field set to the
default value of FALSE—in the implementing certificate. If there are no extensions present in the implementing certificate, the method returns null.





X509Extension.has UnsupportedCriticalExtension()


The hasUnsupportedCriticalExtension() method returns true
if the certificate contains an extension that is marked as critical but
that is not expected as a critical extension by the profile the
certificate was created for; otherwise, the method returns false.


It's actually hard to see what real use this
method has now, since from JDK 1.4, an API for doing certificate path
validation was introduced. In general, if you are using it, you will
probably find it conforms to the PKIX profile; however, if you are
serious about checking your certificates, you should use the CertPath
API, which is discussed in Chapter 7.






Extensions Supported Directly by X509Certificate



Some of the more common extensions are supported directly by the X509Certificate
class. You'll have a look at them here. The directly supported
extensions help give you some idea of how the path validation APIs get
the information they need to do their job, as well as how usage
restrictions can be placed on version 3 certificates.


The common extensions are defined as part of X.500,
which has the object identifier "2.5", being off the joint ISO/ITU-T
branch. X.500 then assigned arc 29 to certificate extensions, giving it
the name id-ce. You will also find these extensions among those documented in RFC 3280.




X509Certificate.get KeyUsage()


The KeyUsage extension is simply a BIT STRING and is associated with the object identifier id-ce-keyUsage, which has the value "2.5.29.15". The extension's ASN.1 definition looks as follows:


KeyUsage ::= BIT STRING {
digitalSignature (0),
nonRepudiation (1),
keyEncipherment (2),
dataEncipherment (3),
keyAgreement (4),
keyCertSign (5),
cRLSign (6),
encipherOnly (7),
decipherOnly (8) }

The getKeyUsage() method returns these as an array of booleans. In the event that not all bits are set in the BIT STRING, the array of booleans is always padded out to eight elements, with the missing elements being set to false.


The presence of a particular bit indicates what roles
the issuer of the certificate had in mind when the certificate was
generated. The name of the bits and their meanings are as follows:





  • q digitalSignature—The key can be used with signature mechanisms other than those involving certificate signing.





  • q nonRepudiation—The key can be used for verifying signatures used to provide a nonrepudiation service.





  • q keyEncipherment—The key can be used to encrypt other keys.





  • q dataEncipherment—The key can be used to encrypt data other than cryptographic keys.





  • q keyAgreement—The key can be used for key agreement.





  • q keyCertSign—The key may be used for verifying other certificates.





  • q cRLSign—The key can be used to verify a signature on a CRL, or certificate revocation list. You will have closer look at CRLs in Chapter 7.





  • q encipherOnly—This bit is only meaningful if the KeyAgreement bit is set. If both it and the KeyAgreement bit are set, key agreement can be carried out only for the purpose of encrypting data.





  • q decipherOnly—This bit is only meaningful if the KeyAgreement bit is set. If both it and the KeyAgreement bit are set, key agreement can be carried out only for the purpose of decrypting data.







X509Certificate.get SubjectAlternativeNames()


In addition to the details of the subject name provided by the getSubjectX500Principal(),
a certificate can also carry other names that the owner of the public
key in the certificate can be known by. This is done using the SubjectAltName
extension, which allows a range of alternatives to be included for
identifying the subject. If you want to include the e-mail of a subject
in a certificate, this is really the place to do it, rather than use
the older PKCS #9 e-mail address field in the DN.


The SubjectAltName extension is indicated by the presence of the OID "2.5.29.17" (id-ce-subjectAltName). The value of the extension is a GeneralNames structure, which is defined as follows and has the following ASN.1 definition:



SubjectAltName ::= GeneralNames

GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName

GeneralName ::= CHOICE {
otherName [0] AnotherName,
rfc822Name [1] IA5String,
dNSName [2] IA5String,
x400Address [3] ORAddress,
directoryName [4] Name,
ediPartyName [5] EDIPartyName,
uniformResourceIdentifier [6] IA5String,
iPAddress [7] OCTET STRING,
registeredID [8] OBJECT IDENTIFIER }

AnotherName ::= SEQUENCE {
type-id OBJECT IDENTIFIER,
value [0] EXPLICIT ANY DEFINED BY type-id }

EDIPartyName ::= SEQUENCE {
nameAssigner [0] DirectoryString OPTIONAL,
partyName [1] DirectoryString }

DirectoryString ::= CHOICE {
teletexString TeletexString,
printableString PrintableString,
bmpString BMPString,
universalString UniversalString,
uTF8String UTF8String }


I'll show you how to construct a SubjectAltName extension in the example a bit later. Meanwhile, when it comes to reading one using the getSubjectAlternativeNames() method, the method returns null if the extension is not present, or if it is present, it returns an immutable collection representing the GeneralNames structure.


The mechanism for constructing the collection is as follows. Each entry in the GeneralNames structure is turned into a two-element list, the first element being an integer representing the tag associated with that GeneralName, and the second element being an object representing the value of the GeneralName. The various values are returned either as Java String objects or as byte arrays that contain the DER encoding of the name value. The tags returned as String objects are those for rfc822Name, dNSName, uniformResourceIdentifier, iPAddress, directoryName, and registeredID. IP addresses are converted into strings using dotted quad notation in the case of IPv4 and for IPv6 in the form "a1:a2:
:a8", where a1 to a8 each represent one part of the eight 16-bit pieces
making up the address. Directory name objects are converted into String
objects using RFC 2253 string format. In the case of the others, the
DER-encoded value of the choice item is returned in a byte array.


Note, the conversion of directory names to RFC
2253 strings may not always have the desired result. If you need to
process directory names in the SubjectAltName extension, you may need to unpack the extension by hand instead using X509Extension.getExtensionValue().





X509Certificate.get IssuerAlternativeNames()


The IssuerAltName extension is indicated by the presence of the OID "2.5.29.18" (id-ce-issuerAltName). It is defined in the same way as the SubjectAltName extension, as a GeneralNames structure, and consequently also returns a collection that has been formatted according to the rules outlined for getSubjectAlternativeNames().





X509Certificate.get BasicConstraints()


The BasicConstraints extension is indicated by the presence of the OID "2.5.29.19" (id-ce-basicConstraints). The getBasicConstraints() method returns an int value, and to understand why, you need to look at the ASN.1 definition of the BasicConstraints structure that is as follows:


BasicConstraints ::= SEQUENCE {
cA BOOLEAN DEFAULT FALSE,
pathLenConstraint INTEGER (0..MAX) OPTIONAL }

The return value of the method is derived from the value of the pathLenConstraint, which is meaningful only if the cA field is set to TRUE, meaning that the subject of the certificate is a certificate authority. If the cA field is FALSE, then the extension indicates that the certificate is an end entity certificate and should not be used to sign another one.


When pathLenConstraint is meaningful it
indicates how many certificates can follow the one that contains the
extension. For example, if the value is 0, then any certificate
verifiable by the certificate containing the extension must be an end
entity certificate. If pathLenConstraint is left out and the cA field is TRUE, then any number of CA certificates can follow the certificate containing the extension.


So in respect of the getBasicConstraints() method: If the cA field is TRUE and the pathLenConstraint has been set, then the value returned is the int representing the value in pathLenconstraint; if pathLenConstraint is not present, then Integer.MAX_VALUE is returned instead. If the cA field is FALSE, then getBasicConstraints() returns 1, indicating the certificate containing the extension can only come at the end of the chain.





X509Certificate.get ExtendedKeyUsage()


The ExtendedKeyUsage extension was created when it turned out a more flexible arrangement than the one offered by the KeyUsage extension was required. It is associated with the object identifier "2.5.29.37" (id-ce-extKeyUsage) and its ASN.1 definition is as follows:



ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId

KeyPurposeId ::= OBJECT IDENTIFIER

As you can see, the type encoded in the extnValue field is just a sequence of OIDs, so unlike the KeyUsage extension, the ExtendedKeyUsage
allows the certificate issuer to use object identifiers to determine
what the public key in the certificate can be used for. The greater
customization this extension allows in certificate purpose has resulted
in it becoming increasingly popular, with a number of organizations and
companies publishing lists of object identifiers that can be used as a KeyPurposeId.


The PKIX profile described in RFC 3280 describes a
number of these, which are for supporting some of the more standard
uses a certificate key can be put to. The current list includes the
following:





  • q anyExtendedKeyUsage, OID "2.5.29.37.0", key can be used for any purpose.





  • q id-kp-serverAuth, OID "1.3.6.1.5.5.7.3.1", key can be used for SSL/TLS server authentication.





  • q id-kp-clientAuth, OID "1.3.6.1.5.5.7.3.2", key can be used for SSL/TLS client authentication.





  • q id-kp-codeSigning, OID "1.3.6.1.5.5.7.3.3", key can be used for signing executable code.





  • q id-kp-emailProtection, OID "1.3.6.1.5.5.7.3.4", key can be used for e-mail encryption/signing.





  • q id-kp-timeStamping, OID "1.3.6.1.5.5.7.3.8", key can be used for creating timestamps.





  • q id-kp-OCSPSigning, OID "1.3.6.1.5.5.7.3.9", key can be used for signing OCSP (RFC 2560) messages.




As you may have guessed from the "1.3.6.1.5.5.7.3", also known as id-kp, is an object identifier that marks an arc reserved for PKIX extended key purpose object identifiers.


Both KeyUsage and ExtendedKeyUsage
extensions can appear in the same certificate, so it is acceptable to
include both if you are creating a certificate that contains both, or
evaluating one that contains both, just make sure they are consistent
with each other. For example, it does not make sense to have a KeyUsage extension with only the dataEncipherment bit set and have an ExtendedKeyUsage extension with the id-kp-codeSigning OID present.




Try It Out: Creating a Self-Signed Version 3 Certificate






Creation of a version 3 certificate is very
similar to a version 1 certificate—the only difference is the presence
of extensions. This section creates a version 3 certificate with a
couple of the extensions covered in the last section.


Choice of extensions is largely dictated by the purpose the certificate is for, although you will also see in Chapter 7
that extensions exist that serve to provide references to how to verify
the certificate is still valid, what other certificate can be used to
verify it, and extra information on the public key contained in the
certificate. In the example here I'll generate a self-signed
certificate marked for use with SSL using the ExtendedKeyUsage extension, as well as set the appropriate bits in the KeyUsage extension. The certificate will also be marked as unsuitable for use as a CA cert by using the BasicConstraints extension, and finally I'll include an e-mail address for the certificate's subject using the SubjectAltName extension.


package chapter6;

import java.math.BigInteger;

import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.x509.X509V3CertificateGenerator;


/**
* Basic X.509 V3 Certificate creation with TLS flagging.
*/
public class X509V3CreateExample
{
public static X509Certificate generateV3Certificate(KeyPair pair)
throws InvalidKeyException, NoSuchProviderException, SignatureException
{
// generate the certificate
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();

certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setIssuerDN(new X500Principal("CN=Test Certificate"));
certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000));
certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000));
certGen.setSubjectDN(new X500Principal("CN=Test Certificate"));
certGen.setPublicKey(pair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");

certGen.addExtension(X509Extensions.BasicConstraints, true,
new BasicConstraints(false));
certGen.addExtension(X509Extensions.KeyUsage, true,
new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
certGen.addExtension(X509Extensions.ExtendedKeyUsage, true,
new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth));

certGen.addExtension(X509Extensions.SubjectAlternativeName, false,
new GeneralNames(
new GeneralName(GeneralName.rfc822Name, "test@test.test")));


return certGen.generateX509Certificate(pair.getPrivate(), "BC");
}
public static void main(String[] args) throws Exception
{
// create the keys
KeyPair pair = Utils.generateRSAKeyPair();

// generate the certificate

X509Certificate cert = generateV3Certificate(pair);

// show some basic validation
cert.checkValidity(new Date());

cert.verify(cert.getPublicKey());

System.out.println("valid certificate generated");
}
}

















How It Works


As you can see, this is example is very similar
to the last one, so the basics of the certificate construction are
essentially what was described earlier. The difference in this case is
the use of the X509V3CertificateGenerator class and that you are now adding some extensions to the certificate.


Looking at the example, note that each call to the X509V3CertificateGenerator.addExtension()
method takes three parameters reflecting the three fields required in
an extension that you saw in the ASN.1 definition earlier:


Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING }

The first and second parameters, representing extnID and critical, are self-explanatory. The last parameter, which is used to fill in the extnValue field, needs a bit more examination, though. For example, take the adding of a KeyUsage extension, which is done on the following lines:



certGen.addExtension(X509Extensions.KeyUsage, true,
new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));


The last parameter is an ASN1Encodable object
representing the value of the extension. What happens internally to the
generator is that the value is encoded as a DER-encoded byte array,
which is then used to create an OCTET STRING. It is this OCTET STRING that is then assigned as the value of the extnValue field. Likewise, if you were to add



byte[] usageExt = cert.getExtensionValue(X509Extensions.KeyUsage.getId());


the byte array usageExt would represent the DER encoding of the OCTET STRING, and the octets contained in the OCTET STRING would represent the DER encoding of KeyUsage.


One further point of interest about the example is
the choice of whether or not to make a particular extension critical by
passing true as the value for the critical field. As
mentioned earlier, this largely depends on the profile that the
certificate is being created for. In the case of the example, the
choices have been based on the PKIX profile detailed in RFC 3280. If
you look up RFC 3280, you will see that BasicConstraints in an end entity certificate may be marked as critical; in the example I have taken the option of doing so. KeyUsage, on the other hand, should be marked as critical, so it is. ExtendedKeyUsage
may also be critical; however, if it is, the key can be used only for
the purpose allowed by the extension, and the purpose given in the
extension must also correspond with the purposes allowed by the KeyUsage extension if it is present. In my case, I wanted to assert the purpose of the certificate key strongly, so I have marked ExtendedKeyUsage as critical. Finally, I added the SubjectAltName extension, which in this case has a purely informational role and so is marked as noncritical.











































1 comment:

  1. Amazing ! You have covered almost everything about this type of certificate. I am feeling so excited that I found this detail. I will do share it with my friends too.
    digital signature certificate

    ReplyDelete