Friday, October 30, 2009

Writing a Simple Certificate Authority
















































Writing a Simple Certificate Authority



Now
you will look at taking a certification request and using it and an
existing root certificate to generate a new certificate. As you can see
from Figure 6-2, this is essentially what a certificate authority does in its most basic form.






Figure 6-2

Creating a certificate with a signature that can be
verified by another certificate creates a relationship between the two
certificates that is normally expressed in terms of a certificate path
or a certificate chain, and the validation of these certificate paths
is one of the things that various profiles concern themselves with. In
Java terms the simplest way to think of a certificate path is as an
array of certificates, with the first certificate in the array being
the end entity certificate, whose signature can be verified by the next
certificate in the array, and the last certificate in the array is the
root certificate, which is normally self-signed and has to be accepted
on trust.


In X.509 terms there are a couple of steps to finding
out which certificate has signed which. First you would expect if one
certificate can be used to verify another one, that same certificate
will have a subject that is equal to the issuer on the certificate
being verified. Second, you would obviously expect that, given that the
subject of any certificate is the issuer of another, the key on the
first certificate will validate the signature on the second. Of course,
an issuer may have issued several certificates, so another two
extensions are provided with X.509 version 3, which can be used to make
it easier to work out, given an unordered set of certificates, what
order the certificates are meant to be in. The extensions are the AuthorityKeyIdentifier and the SubjectKeyIdentifier.


The OID and value of the AuthorityKeyIdentifier extension are defined as follows:



id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 }

AuthorityKeyIdentifier ::= SEQUENCE {
keyIdentifier [0] KeyIdentifier OPTIONAL,
authorityCertIssuer [1] GeneralNames OPTIONAL,
authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }

KeyIdentifier ::= OCTET STRING



As you can see, the kind of information contained in the AuthorityKeyIdentifier is what you would imagine would be associated with the issuer of the certificate it is attached to. For example, setting the authorityCertIssuer and authorityCertSerialNumber
to the issuer and serial number of the verifying certificate is usually
enough to identify the issuer's certificate uniquely. The keyIdentifier field allows the issuer's certificate to be identified in another way as well—by associating an OCTET STRING
with the key that is in the verifying certificate. You can make use of
this information to find the issuer's certificate if the issuer's
certificate includes the SubjectKeyIdentifier extension.


The OID and value of the SubjectKeyIdentifier extension are defined as follows:



id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 }

SubjectKeyIdentifier ::= KeyIdentifier


This value can be anything, but two currently recommended approaches are as follows:





  • q Calculate the 160-bit SHA-1 hash of the value of the BIT STRING field subjectPublicKey, excluding the tag value, length, and number of pad bits.





  • q Perform the same operation as
    previously; however, use only the least significant 60 bits of the
    SHA-1 value and prepend the bit string “0100” to the start of it, giving a 64-bit number.




People also use other ways of generating the bytes,
such as a sequence of monotonically increasing integers; it doesn't
really matter. The important thing is that a clash is highly unlikely,
and if the keyIdentifier field in an AuthorityKeyIdentifier is used, it is taken from the value of the SubjectKeyIdentifier of the issuer certificate corresponding to the AuthorityKeyIdentifier.


The PKIX profile, described in RFC 3280, specifies that
while neither of these extensions should be marked as critical, they
should be included in any certificate generated. As you can see, used
properly, the two extensions provide essentially the same facility as
pointers, but in an X.509 landscape, and make building certificate
chains on the fly a lot easier.




Try It Out: Creating a Certificate from a Certification Request






This example takes the process one step farther
and creates a certificate. In it two key pairs get created: one that is
used to create a certification request using the same method as the
last example; the other that is used to create a root certificate using
use a method defined in an earlier example ("Try It Out: Creating a
Self-Signed Version 1 Certificate"). The certificate that gets created
from the certification request is a version 3 certificate containing
the extensions used in the version 3 creation Try It Out ("Creating a
Self-Signed Version 3 Certificate") plus two more. The extra extensions
are the AuthorityKeyIdentifier and the SubjectKeyIdentifier, which, as you have read, are required for RFC 3280 compliance.


package chapter6;

import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;

import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DERObjectIdentifier;

import org.bouncycastle.asn1.pkcs.Attribute;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;

/**
* An example of a basic CA.
*/
public class PKCS10CertCreateExample
{
public static X509Certificate[] buildChain() throws Exception
{
// create the certification request
KeyPair pair = Utils.generateRSAKeyPair();
PKCS10CertificationRequest request =
PKCS10ExtensionExample.generateRequest(pair);

// create a root certificate
KeyPair rootPair = Utils.generateRSAKeyPair();
X509Certificate rootCert =
X509V1CreateExample.generateV1Certificate(rootPair);

// validate the certification request
if (!request.verify("BC"))
{
System.out.println("request failed to verify!");
System.exit(1);
}

// create the certificate using the information in the request
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();

certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setIssuerDN(rootCert.getSubjectX500Principal());
certGen.setNotBefore(new Date(System.currentTimeMillis()));
certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000));
certGen.setSubjectDN(request.getCertificationRequestInfo().getSubject());
certGen.setPublicKey(request.getPublicKey("BC"));
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");

certGen.addExtension(X509Extensions.AuthorityKeyIdentifier,
false, new AuthorityKeyIdentifierStructure(rootCert));

certGen.addExtension(X509Extensions.SubjectKeyIdentifier,

false, new SubjectKeyIdentifierStructure(request.getPublicKey("BC")));

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));

// extract the extension request attribute
ASN1Set attributes = request.getCertificationRequestInfo().getAttributes();

for (int i = 0; i != attributes.size(); i++)
{
Attribute attr = Attribute.getInstance(attributes.getObjectAt(i));

// process extension request
if (attr.getAttrType().equals(
PKCSObjectIdentifiers.pkcs_9_at_extensionRequest))
{
X509Extensions extensions = X509Extensions.getInstance(
attr.getAttrValues().getObjectAt(0));

Enumeration e = extensions.oids();
while (e.hasMoreElements())
{
DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
X509Extension ext = extensions.getExtension(oid);

certGen.addExtension(oid, ext.isCritical(),
ext.getValue().getOctets());
}
}
}
X509Certificate issuedCert = certGen.generateX509Certificate(
rootPair.getPrivate());

return new X509Certificate[] { issuedCert, rootCert };
}
public static void main(String[] args) throws Exception
{
X509Certificate[] chain = buildChain();

PEMWriter pemWrt = new PEMWriter(
new OutputStreamWriter(System.out));

pemWrt.writeObject(chain[0]);
pemWrt.writeObject(chain[1]);

pemWrt.close();
}
}


Run
this and you should see the program print out the two PEM-encoded
certificates. The first one will be much larger, being the issued
certificate and carrying the necessary extensions to indicate its usage
and origins. The second one will appear a lot smaller, as it is a
version 1 certificate with no extensions attached.

















How It Works


The example proceeds through a number of steps. The createChain() method starts out pretending it is a client and then starts to behave as a CA instead.


First, in "client mode," a certification request is created; then, in "CA mode," a root certificate is created.


Next, still in CA mode, the certification request is
validated and then the client certificate is created. This step
introduces a couple of new classes as well: AuthorityKeyIdentifierStructure and SubjectKeyIdentifier structure, both of which are defined in the org.bouncycastle.x509. extension package.


The AuthorityKeyIdentifierStructure class is a helper class that allows you to create the necessary structure for the value field in an AuthorityKeyIdentifier extension. Like the other extension objects you looked at previously, it generates an ASN1Encodable object, which is then encoded as an OCTET STRING internally and added to the certificate. The SubjectKeyIdentifierStructure object is also a helper class and calculates a KeyIdentifier for the passed in public key using the SHA-1 method and returns it wrapped in an OCTET STRING suitable for re-encoding into a SubjectKeyIdentifier extension value. You add the AuthorityKeyIdentifier extension so you have a link with the certificate that can be used to verify you. The SubjectKeyIdentifier gets added in case anyone needs to create a link back to your certificate in the future.


Once the AuthorityKeyIdentifier, SubjectKeyIdentifier,
and other extensions have been added, the example then extracts the
attributes from the certification request and looks for an extensionRequest attribute. If it finds one, it then creates an X509Extensions object by extracting the value from the attribute set and iterates through it, retrieving each extension as an org.bouncycastle.asn1. x509.X509Extension object and adding it to the certificate generator using the addExtension() method that takes a DER-encoded byte array. Too easy!


Well, in some ways it is too easy. In real life you
would probably want to do a bit more. To start with, the CA code isn't
checking that it is overwriting one of its own extensions when it adds
one from the user. Nor is any validation being done on the contents of
the extension being added. As mentioned earlier with extensions that
contain identifying information on the owner of the certificate, it is
worth making sure the identifying information is for the person you
think it is and that the information inserted is only what is
acceptable. For example, you might allow your local users to add their
e-mail addresses to their certificates if they want to. So the first
form of validation you would want to do on the SubjectAltName extension is make sure the only value in it is an rfc822Name,
and then you would want to check that it is an e-mail address that
makes sense. If you are running a business, you probably don't want to
issue certificates to your staff that tell people that the staff
member's private business e-mail address is evil@evil_competitor.com, do you?


After the extensions are parsed and added in the
certification request, the resulting certificate chain, consisting of
the root certificate and the client certificate, is printed out. In the
normal course of events this is what would be sent by the CA to the
client; the only difference is that in the real world, clients would
never need
to expose their private keys. The CA would also normally use the same
private key and root certificate for signing a number of certificates
and may have a number of intermediate certificates resulting in a
certificate path, or chain, similar to the one seen in Figure 6-3.






Figure 6-3







































No comments:

Post a Comment