Home | History | Annotate | Download | only in ssl
      1 package com.google.polo.ssl;
      2 
      3 import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
      4 import org.bouncycastle.asn1.x509.BasicConstraints;
      5 import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
      6 import org.bouncycastle.asn1.x509.GeneralName;
      7 import org.bouncycastle.asn1.x509.GeneralNames;
      8 import org.bouncycastle.asn1.x509.KeyPurposeId;
      9 import org.bouncycastle.asn1.x509.KeyUsage;
     10 import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
     11 import org.bouncycastle.asn1.x509.X509Extensions;
     12 import org.bouncycastle.asn1.x509.X509Name;
     13 import org.bouncycastle.x509.X509V3CertificateGenerator;
     14 import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
     15 
     16 import java.math.BigInteger;
     17 import java.security.GeneralSecurityException;
     18 import java.security.KeyPair;
     19 import java.security.PublicKey;
     20 import java.security.cert.X509Certificate;
     21 import java.util.Calendar;
     22 import java.util.Date;
     23 
     24 /**
     25  * Utility class to generate X509 Root Certificates and Issue X509 Certificates signed by a root
     26  * Certificate.
     27  */
     28 public class CsrUtil {
     29     private static final String SIGNATURE_ALGORITHM = "SHA256WithRSAEncryption";
     30     private static final String EMAIL = "android-tv-remote-support (at) google.com";
     31     private static final int NOT_BEFORE_NUMBER_OF_DAYS = -30;
     32     private static final int NOT_AFTER_NUMBER_OF_DAYS = 10 * 365;
     33 
     34     /**
     35      * Generate a X509 Certificate that should be used as an authority/root certificate only.
     36      *
     37      * This certificate shouldn't be used for communications, only as an authority as it won't have
     38      * the correct flags.
     39      *
     40      * @param rootName Common Name used in certificate.
     41      * @param rootPair Key Pair used to signed the certificate
     42      * @return
     43      * @throws GeneralSecurityException
     44      */
     45     public static X509Certificate generateX509V3AuthorityCertificate(String rootName,
     46             KeyPair rootPair)
     47             throws GeneralSecurityException {
     48         Calendar calendar = Calendar.getInstance();
     49         calendar.add(Calendar.DAY_OF_YEAR, NOT_BEFORE_NUMBER_OF_DAYS);
     50         Date notBefore  = new Date(calendar.getTimeInMillis());
     51         calendar.add(Calendar.DAY_OF_YEAR, NOT_AFTER_NUMBER_OF_DAYS);
     52         Date notAfter = new Date(calendar.getTimeInMillis());
     53 
     54         BigInteger serialNumber = BigInteger.valueOf(Math.abs(System.currentTimeMillis()));
     55 
     56         return generateX509V3AuthorityCertificate(rootName, rootPair, notBefore, notAfter, serialNumber);
     57     }
     58 
     59 
     60     @SuppressWarnings("deprecation")
     61     static X509Certificate generateX509V3AuthorityCertificate(String rootName,
     62             KeyPair rootPair, Date notBefore, Date notAfter, BigInteger serialNumber)
     63             throws GeneralSecurityException {
     64         X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
     65         X509Name dnName = new X509Name(rootName);
     66 
     67         certGen.setSerialNumber(serialNumber);
     68         certGen.setIssuerDN(dnName);
     69         certGen.setSubjectDN(dnName);
     70         certGen.setNotBefore(notBefore);
     71         certGen.setNotAfter(notAfter);
     72         certGen.setPublicKey(rootPair.getPublic());
     73         certGen.setSignatureAlgorithm(SIGNATURE_ALGORITHM);
     74 
     75         certGen.addExtension(X509Extensions.BasicConstraints, true,
     76                 new BasicConstraints(0));
     77 
     78         certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.digitalSignature
     79                 | KeyUsage.keyEncipherment | KeyUsage.keyCertSign));
     80 
     81         AuthorityKeyIdentifier authIdentifier = SslUtil.createAuthorityKeyIdentifier(
     82                 rootPair.getPublic(), dnName, serialNumber);
     83 
     84         certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, true, authIdentifier);
     85         certGen.addExtension(X509Extensions.SubjectKeyIdentifier, true,
     86                 SubjectKeyIdentifier.getInstance(rootPair.getPublic().getEncoded()));
     87 
     88         certGen.addExtension(X509Extensions.SubjectAlternativeName, false, new GeneralNames(
     89                 new GeneralName(GeneralName.rfc822Name, EMAIL)));
     90 
     91         X509Certificate cert = certGen.generate(rootPair.getPrivate());
     92         return cert;
     93     }
     94 
     95 
     96     /**
     97      * Given a public key and an authority certificate and key pair, issue an X509 Certificate
     98      * chain signed by the provided authority certificate.
     99      *
    100      * @param name Common name used in the issued certificate.
    101      * @param publicKey Public key to use in issued certificate.
    102      * @param rootCert Root certificate used to issue the new certificate.
    103      * @param rootPair Root key pair used to issue the new certificate.
    104      * @return Array containing the issued certificate and the provided root certificate.
    105      * @throws GeneralSecurityException
    106      */
    107     public static X509Certificate[] issueX509V3Certificate(String name, PublicKey publicKey,
    108             X509Certificate rootCert, KeyPair rootPair) throws GeneralSecurityException {
    109         Calendar calendar = Calendar.getInstance();
    110         calendar.add(Calendar.DAY_OF_YEAR, NOT_BEFORE_NUMBER_OF_DAYS);
    111         Date notBefore  = new Date(calendar.getTimeInMillis());
    112         calendar.add(Calendar.DAY_OF_YEAR, NOT_AFTER_NUMBER_OF_DAYS);
    113         Date notAfter = new Date(calendar.getTimeInMillis());
    114 
    115         BigInteger serialNumber = BigInteger.valueOf(Math.abs(System.currentTimeMillis()));
    116 
    117         return issueX509V3Certificate(name, publicKey, rootCert, rootPair, notBefore, notAfter, serialNumber);
    118     }
    119 
    120     @SuppressWarnings("deprecation")
    121     static X509Certificate[] issueX509V3Certificate(String name, PublicKey publicKey,
    122             X509Certificate rootCert, KeyPair rootPair, Date notBefore, Date notAfter,
    123             BigInteger serialNumber) throws GeneralSecurityException {
    124 
    125         X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
    126 
    127         X509Name dnName = new X509Name(name);
    128 
    129         certGen.setSerialNumber(serialNumber);
    130         certGen.setIssuerDN(rootCert.getSubjectX500Principal());
    131         certGen.setNotBefore(notBefore);
    132         certGen.setNotAfter(notAfter);
    133         certGen.setSubjectDN(dnName);
    134         certGen.setPublicKey(publicKey);
    135         certGen.setSignatureAlgorithm(SIGNATURE_ALGORITHM);
    136 
    137         // Use Root Certificate as the authority
    138         certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
    139                 new AuthorityKeyIdentifierStructure(rootCert));
    140         // Use provided public key for the subject
    141         certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
    142                 SubjectKeyIdentifier.getInstance(publicKey.getEncoded()));
    143         // This is not a CA certificate, do not allow
    144         certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
    145         // This can be used for signature and encryption
    146         certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.digitalSignature
    147                 | KeyUsage.keyEncipherment));
    148         // This is used for server authentication
    149         certGen.addExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(
    150                 KeyPurposeId.id_kp_serverAuth));
    151 
    152         X509Certificate issuedCert = certGen.generate(rootPair.getPrivate());
    153 
    154         return new X509Certificate[] { issuedCert, rootCert };
    155     }
    156 }
    157