• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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      */
generateX509V3AuthorityCertificate(String rootName, KeyPair rootPair)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")
generateX509V3AuthorityCertificate(String rootName, KeyPair rootPair, Date notBefore, Date notAfter, BigInteger serialNumber)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      */
issueX509V3Certificate(String name, PublicKey publicKey, X509Certificate rootCert, KeyPair rootPair)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")
issueX509V3Certificate(String name, PublicKey publicKey, X509Certificate rootCert, KeyPair rootPair, Date notBefore, Date notAfter, BigInteger serialNumber)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