Java tutorial
/* * $Id: CertificateExtensionFactory.java,v 1.3 2007/08/22 10:38:47 vtschopp Exp $ * * Created on Sep 12, 2006 by Valery Tschopp <tschopp@switch.ch> * * Copyright (c) Members of the EGEE Collaboration. 2004. * See http://eu-egee.org/partners/ for details on the copyright holders. * For license conditions see the license file or http://eu-egee.org/license.html */ package org.glite.slcs.pki; import java.util.Enumeration; import java.util.StringTokenizer; import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; 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.PolicyInformation; import org.bouncycastle.asn1.x509.X509Extension; import org.bouncycastle.asn1.x509.X509Extensions; /** * X.509 certificate extensions factory * * @author Valery Tschopp <tschopp@switch.ch> * @version $Revision: 1.3 $ */ public class CertificateExtensionFactory { /** Logging */ private static Log LOG = LogFactory.getLog(CertificateExtensionFactory.class); /** * Creates a CertificateExtension. The id can be the OID or the name as * defined below. The values is a comma separated list of value(s) * <p> * Valid names and values: * <ul> * <li>KeyUsage * <ul> * <li>DigitalSignature * <li>NonRepudiation * <li>KeyEncipherment * <li>DataEncipherment * <li>KeyAgreement * <li>KeyCertSign * <li>CRLSign * <li>EncipherOnly * <li>DecipherOnly * </ul> * <li>ExtendedKeyUsage * <ul> * <li>AnyExtendedKeyUsage * <li>ServerAuth * <li>ClientAuth * <li>CodeSigning * <li>EmailProtection * <li>IPSecEndSystem * <li>IPSecTunnel * <li>IPSecUser * <li>OCSPSigning * <li>Smartcardlogon * </ul> * <li>CertificatePolicies * <ul> * <li>The policy OID(s) * </ul> * <li>SubjectAltName * <ul> * <li>email:EMAIL_ADDRESS * <li>dns:HOSTNAME * </ul> * </ul> * <p> * Example: * <pre> * CertificateExtension keyUsageExtension = * CertificateExtensionFactory.createCertificateExtension("KeyUsage", "DigitalSignature,KeyEncipherment"); * CertificateExtension subjectAltNameExtension = * CertificateExtensionFactory.createCertificateExtension("SubjectAltName", "email:john.doe@example.com,dns:www.exmaple.com"); * </pre> * * @param id * The name or the OID of the extension. * @param values * A comma separated list of extension value(s). * @return The corresponding CertificateExtension or <code>null</code> if * the id (name or oid) is not supported. */ static public CertificateExtension createCertificateExtension(String id, String values) { if (LOG.isDebugEnabled()) { LOG.debug("id:" + id + " value(s):" + values); } if (id.equals(X509Extensions.KeyUsage.getId()) || id.equalsIgnoreCase("KeyUsage")) { // parse the comma separated list of key usage int usage = 0; StringTokenizer st = new StringTokenizer(values, ","); while (st.hasMoreElements()) { String keyUsage = (String) st.nextElement(); keyUsage = keyUsage.trim(); if (keyUsage.equalsIgnoreCase("DigitalSignature")) { usage += KeyUsage.digitalSignature; } else if (keyUsage.equalsIgnoreCase("NonRepudiation")) { usage += KeyUsage.nonRepudiation; } else if (keyUsage.equalsIgnoreCase("KeyEncipherment")) { usage += KeyUsage.keyEncipherment; } else if (keyUsage.equalsIgnoreCase("DataEncipherment")) { usage += KeyUsage.dataEncipherment; } else if (keyUsage.equalsIgnoreCase("KeyAgreement")) { usage += KeyUsage.keyAgreement; } else if (keyUsage.equalsIgnoreCase("KeyCertSign")) { usage += KeyUsage.keyCertSign; } else if (keyUsage.equalsIgnoreCase("CRLSign")) { usage += KeyUsage.cRLSign; } else if (keyUsage.equalsIgnoreCase("EncipherOnly")) { usage += KeyUsage.encipherOnly; } else if (keyUsage.equalsIgnoreCase("DecipherOnly")) { usage += KeyUsage.decipherOnly; } else { LOG.error("Unknown KeyUsage: " + keyUsage); } } return createKeyUsageExtension(usage, values); } else if (id.equals(X509Extensions.ExtendedKeyUsage.getId()) || id.equalsIgnoreCase("ExtendedKeyUsage")) { // value is a comma separated list of keyPurpose Vector keyPurposeIds = new Vector(); StringTokenizer st = new StringTokenizer(values, ","); while (st.hasMoreElements()) { String keyPurpose = (String) st.nextElement(); keyPurpose = keyPurpose.trim(); if (keyPurpose.equalsIgnoreCase("AnyExtendedKeyUsage")) { keyPurposeIds.add(KeyPurposeId.anyExtendedKeyUsage); } else if (keyPurpose.equalsIgnoreCase("ServerAuth")) { keyPurposeIds.add(KeyPurposeId.id_kp_serverAuth); } else if (keyPurpose.equalsIgnoreCase("ClientAuth")) { keyPurposeIds.add(KeyPurposeId.id_kp_clientAuth); } else if (keyPurpose.equalsIgnoreCase("CodeSigning")) { keyPurposeIds.add(KeyPurposeId.id_kp_codeSigning); } else if (keyPurpose.equalsIgnoreCase("EmailProtection")) { keyPurposeIds.add(KeyPurposeId.id_kp_emailProtection); } else if (keyPurpose.equalsIgnoreCase("IPSecEndSystem")) { keyPurposeIds.add(KeyPurposeId.id_kp_ipsecEndSystem); } else if (keyPurpose.equalsIgnoreCase("IPSecTunnel")) { keyPurposeIds.add(KeyPurposeId.id_kp_ipsecTunnel); } else if (keyPurpose.equalsIgnoreCase("IPSecUser")) { keyPurposeIds.add(KeyPurposeId.id_kp_ipsecUser); } else if (keyPurpose.equalsIgnoreCase("TimeStamping")) { keyPurposeIds.add(KeyPurposeId.id_kp_timeStamping); } else if (keyPurpose.equalsIgnoreCase("OCSPSigning")) { keyPurposeIds.add(KeyPurposeId.id_kp_OCSPSigning); } else if (keyPurpose.equalsIgnoreCase("Smartcardlogon")) { keyPurposeIds.add(KeyPurposeId.id_kp_smartcardlogon); } else { LOG.error("Unknown ExtendedKeyUsage: " + keyPurpose); } } return createExtendedKeyUsageExtension(keyPurposeIds, values); } else if (id.equals(X509Extensions.CertificatePolicies.getId()) || id.equalsIgnoreCase("CertificatePolicies")) { // values is a comma separated list of policyOIDs Vector policyOIDs = new Vector(); StringTokenizer st = new StringTokenizer(values, ","); while (st.hasMoreElements()) { String policyOID = (String) st.nextElement(); policyOID = policyOID.trim(); policyOIDs.add(policyOID); } return createCertificatePoliciesExtension(policyOIDs, values); } else if (id.equals(X509Extensions.SubjectAlternativeName.getId()) || id.equalsIgnoreCase("SubjectAltName")) { // values is a comma separated list of altername names prefixed with // the type (email: or dns:) Vector typedSubjectAltNames = new Vector(); StringTokenizer st = new StringTokenizer(values, ","); while (st.hasMoreElements()) { String typedAltName = (String) st.nextElement(); typedAltName = typedAltName.trim(); typedSubjectAltNames.add(typedAltName); } return createSubjectAltNameExtension(typedSubjectAltNames, values); } LOG.error("Unsupported CertificateExtension: " + id); return null; } /** * * @param keyPurposeIds * @param keyPurposeNames * @return */ static protected CertificateExtension createExtendedKeyUsageExtension(Vector keyPurposeIds, String keyPurposeNames) { ExtendedKeyUsage extendedKeyUsage = new ExtendedKeyUsage(keyPurposeIds); X509Extension extendedKeyUsageExtension = new X509Extension(false, new DEROctetString(extendedKeyUsage)); return new CertificateExtension(X509Extensions.ExtendedKeyUsage, "ExtendedKeyUsage", extendedKeyUsageExtension, keyPurposeNames); } /** * * @param keyPurposeId * @param keyPurposeName * @return */ static protected CertificateExtension createExtendedKeyUsageExtension(KeyPurposeId keyPurposeId, String keyPurposeName) { DERSequence keyPurposeIds = new DERSequence(keyPurposeId); ExtendedKeyUsage extendedKeyUsage = new ExtendedKeyUsage(keyPurposeIds); X509Extension extendedKeyUsageExtension = new X509Extension(false, new DEROctetString(extendedKeyUsage)); return new CertificateExtension(X509Extensions.ExtendedKeyUsage, "ExtendedKeyUsage", extendedKeyUsageExtension, keyPurposeName); } /** * Creates a RFC882 Subject Alternative Name: email:johndoe@example.com * extension. * * @param emailAddress * The email address to be included as alternative name. * @return The subject alternative name CertificateExtension. */ static protected CertificateExtension createSubjectAltNameExtension(String emailAddress) { GeneralName subjectAltName = new GeneralName(GeneralName.rfc822Name, emailAddress); GeneralNames subjectAltNames = new GeneralNames(subjectAltName); X509Extension subjectAltNameExtension = new X509Extension(false, new DEROctetString(subjectAltNames)); return new CertificateExtension(X509Extensions.SubjectAlternativeName, "SubjectAltName", subjectAltNameExtension, emailAddress); } /** * * @param prefixedAltNames * @param values * @return */ static protected CertificateExtension createSubjectAltNameExtension(Vector prefixedAltNames, String values) { ASN1EncodableVector altNames = new ASN1EncodableVector(); Enumeration typeAndNames = prefixedAltNames.elements(); while (typeAndNames.hasMoreElements()) { String typeAndName = (String) typeAndNames.nextElement(); typeAndName = typeAndName.trim(); if (typeAndName.startsWith("email:")) { String emailAddress = typeAndName.substring("email:".length()); GeneralName altName = new GeneralName(GeneralName.rfc822Name, emailAddress); altNames.add(altName); } else if (typeAndName.startsWith("dns:")) { String hostname = typeAndName.substring("dns:".length()); GeneralName altName = new GeneralName(GeneralName.dNSName, hostname); altNames.add(altName); } else { LOG.error("Unsupported subjectAltName: " + typeAndName); } } DERSequence subjectAltNames = new DERSequence(altNames); GeneralNames generalNames = new GeneralNames(subjectAltNames); X509Extension subjectAltNameExtension = new X509Extension(false, new DEROctetString(generalNames)); return new CertificateExtension(X509Extensions.SubjectAlternativeName, "SubjectAltName", subjectAltNameExtension, values); } /** * Creates a Cerificate Policies: policyOID extension with the given policy * OID. * * @param policyOID * The policy OID (2.16.756.1.2.*) * @return The certificate policies CertificateExtension. */ static protected CertificateExtension createCertificatePoliciesExtension(String policyOID) { DERObjectIdentifier policyIdentifier = new DERObjectIdentifier(policyOID); PolicyInformation policyInformation = new PolicyInformation(policyIdentifier); DERSequence certificatePolicies = new DERSequence(policyInformation); X509Extension certificatePoliciesExtension = new X509Extension(false, new DEROctetString(certificatePolicies)); return new CertificateExtension(X509Extensions.CertificatePolicies, "CertificatePolicies", certificatePoliciesExtension, policyOID); } /** * * @param policyOIDs * @param values * @return */ static protected CertificateExtension createCertificatePoliciesExtension(Vector policyOIDs, String values) { ASN1EncodableVector policyInformations = new ASN1EncodableVector(); Enumeration pOids = policyOIDs.elements(); while (pOids.hasMoreElements()) { String policyOid = (String) pOids.nextElement(); DERObjectIdentifier policyIdentifier = new DERObjectIdentifier(policyOid); PolicyInformation policyInformation = new PolicyInformation(policyIdentifier); policyInformations.add(policyInformation); } DERSequence certificatePolicies = new DERSequence(policyInformations); X509Extension certificatePoliciesExtension = new X509Extension(false, new DEROctetString(certificatePolicies)); return new CertificateExtension(X509Extensions.CertificatePolicies, "CertificatePolicies", certificatePoliciesExtension, values); } /** * Creates a Key Usage extension for the given usage. This extension is * critical. * * @param usage * The usage is the sum of all KeyUsage values. * @param value * The formal value of the usage. Example: * KeyEncipherment,DigitalSignature * @return The KeyUsage certificate extension. * @see org.bouncycastle.asn1.x509.KeyUsage */ static protected CertificateExtension createKeyUsageExtension(int usage, String value) { KeyUsage keyUsage = new KeyUsage(usage); // KeyUsage is critical X509Extension keyUsageExtension = new X509Extension(true, new DEROctetString(keyUsage)); return new CertificateExtension(X509Extensions.KeyUsage, "KeyUsage", keyUsageExtension, value, true); } /** * Do not allow instantiation of the factory. */ private CertificateExtensionFactory() { } }