1 /*
2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.testlibrary;
27 
28 import java.io.*;
29 import java.util.*;
30 import java.security.*;
31 import java.security.cert.X509Certificate;
32 import java.security.cert.CertificateException;
33 import java.security.cert.CertificateFactory;
34 import java.security.cert.Extension;
35 import javax.security.auth.x500.X500Principal;
36 import java.math.BigInteger;
37 
38 import sun.security.util.DerOutputStream;
39 import sun.security.util.DerValue;
40 import sun.security.util.ObjectIdentifier;
41 import sun.security.x509.AccessDescription;
42 import sun.security.x509.AlgorithmId;
43 import sun.security.x509.AuthorityInfoAccessExtension;
44 import sun.security.x509.AuthorityKeyIdentifierExtension;
45 import sun.security.x509.SubjectKeyIdentifierExtension;
46 import sun.security.x509.BasicConstraintsExtension;
47 import sun.security.x509.ExtendedKeyUsageExtension;
48 import sun.security.x509.DNSName;
49 import sun.security.x509.GeneralName;
50 import sun.security.x509.GeneralNames;
51 import sun.security.x509.KeyUsageExtension;
52 import sun.security.x509.SerialNumber;
53 import sun.security.x509.SubjectAlternativeNameExtension;
54 import sun.security.x509.URIName;
55 import sun.security.x509.KeyIdentifier;
56 
57 /**
58  * Helper class that builds and signs X.509 certificates.
59  *
60  * A CertificateBuilder is created with a default constructor, and then
61  * uses additional public methods to set the public key, desired validity
62  * dates, serial number and extensions.  It is expected that the caller will
63  * have generated the necessary key pairs prior to using a CertificateBuilder
64  * to generate certificates.
65  *
66  * The following methods are mandatory before calling build():
67  * <UL>
68  * <LI>{@link #setSubjectName(java.lang.String)}
69  * <LI>{@link #setPublicKey(java.security.PublicKey)}
70  * <LI>{@link #setNotBefore(java.util.Date)} and
71  * {@link #setNotAfter(java.util.Date)}, or
72  * {@link #setValidity(java.util.Date, java.util.Date)}
73  * <LI>{@link #setSerialNumber(java.math.BigInteger)}
74  * </UL><BR>
75  *
76  * Additionally, the caller can either provide a {@link List} of
77  * {@link Extension} objects, or use the helper classes to add specific
78  * extension types.
79  *
80  * When all required and desired parameters are set, the
81  * {@link #build(java.security.cert.X509Certificate, java.security.PrivateKey,
82  * java.lang.String)} method can be used to create the {@link X509Certificate}
83  * object.
84  *
85  * Multiple certificates may be cut from the same settings using subsequent
86  * calls to the build method.  Settings may be cleared using the
87  * {@link #reset()} method.
88  */
89 public class CertificateBuilder {
90     private final CertificateFactory factory;
91 
92     private X500Principal subjectName = null;
93     private BigInteger serialNumber = null;
94     private PublicKey publicKey = null;
95     private Date notBefore = null;
96     private Date notAfter = null;
97     private final Map<String, Extension> extensions = new HashMap<>();
98     private byte[] tbsCertBytes;
99     private byte[] signatureBytes;
100 
101     /**
102      * Default constructor for a {@code CertificateBuilder} object.
103      *
104      * @throws CertificateException if the underlying {@link CertificateFactory}
105      * cannot be instantiated.
106      */
CertificateBuilder()107     public CertificateBuilder() throws CertificateException {
108         factory = CertificateFactory.getInstance("X.509");
109     }
110 
111     /**
112      * Set the subject name for the certificate.
113      *
114      * @param name An {@link X500Principal} to be used as the subject name
115      * on this certificate.
116      */
setSubjectName(X500Principal name)117     public void setSubjectName(X500Principal name) {
118         subjectName = name;
119     }
120 
121     /**
122      * Set the subject name for the certificate.
123      *
124      * @param name The subject name in RFC 2253 format
125      */
setSubjectName(String name)126     public void setSubjectName(String name) {
127         subjectName = new X500Principal(name);
128     }
129 
130     /**
131      * Set the public key for this certificate.
132      *
133      * @param pubKey The {@link PublicKey} to be used on this certificate.
134      */
setPublicKey(PublicKey pubKey)135     public void setPublicKey(PublicKey pubKey) {
136         publicKey = Objects.requireNonNull(pubKey, "Caught null public key");
137     }
138 
139     /**
140      * Set the NotBefore date on the certificate.
141      *
142      * @param nbDate A {@link Date} object specifying the start of the
143      * certificate validity period.
144      */
setNotBefore(Date nbDate)145     public void setNotBefore(Date nbDate) {
146         Objects.requireNonNull(nbDate, "Caught null notBefore date");
147         notBefore = (Date)nbDate.clone();
148     }
149 
150     /**
151      * Set the NotAfter date on the certificate.
152      *
153      * @param naDate A {@link Date} object specifying the end of the
154      * certificate validity period.
155      */
setNotAfter(Date naDate)156     public void setNotAfter(Date naDate) {
157         Objects.requireNonNull(naDate, "Caught null notAfter date");
158         notAfter = (Date)naDate.clone();
159     }
160 
161     /**
162      * Set the validity period for the certificate
163      *
164      * @param nbDate A {@link Date} object specifying the start of the
165      * certificate validity period.
166      * @param naDate A {@link Date} object specifying the end of the
167      * certificate validity period.
168      */
setValidity(Date nbDate, Date naDate)169     public void setValidity(Date nbDate, Date naDate) {
170         setNotBefore(nbDate);
171         setNotAfter(naDate);
172     }
173 
174     /**
175      * Set the serial number on the certificate.
176      *
177      * @param serial A serial number in {@link BigInteger} form.
178      */
setSerialNumber(BigInteger serial)179     public void setSerialNumber(BigInteger serial) {
180         Objects.requireNonNull(serial, "Caught null serial number");
181         serialNumber = serial;
182     }
183 
184 
185     /**
186      * Add a single extension to the certificate.
187      *
188      * @param ext The extension to be added.
189      */
addExtension(Extension ext)190     public void addExtension(Extension ext) {
191         Objects.requireNonNull(ext, "Caught null extension");
192         extensions.put(ext.getId(), ext);
193     }
194 
195     /**
196      * Add multiple extensions contained in a {@code List}.
197      *
198      * @param extList The {@link List} of extensions to be added to
199      * the certificate.
200      */
addExtensions(List<Extension> extList)201     public void addExtensions(List<Extension> extList) {
202         Objects.requireNonNull(extList, "Caught null extension list");
203         for (Extension ext : extList) {
204             extensions.put(ext.getId(), ext);
205         }
206     }
207 
208     /**
209      * Helper method to add DNSName types for the SAN extension
210      *
211      * @param dnsNames A {@code List} of names to add as DNSName types
212      *
213      * @throws IOException if an encoding error occurs.
214      */
addSubjectAltNameDNSExt(List<String> dnsNames)215     public void addSubjectAltNameDNSExt(List<String> dnsNames) throws IOException {
216         if (!dnsNames.isEmpty()) {
217             GeneralNames gNames = new GeneralNames();
218             for (String name : dnsNames) {
219                 gNames.add(new GeneralName(new DNSName(name)));
220             }
221             addExtension(new SubjectAlternativeNameExtension(false,
222                     gNames));
223         }
224     }
225 
226     /**
227      * Helper method to add one or more OCSP URIs to the Authority Info Access
228      * certificate extension.
229      *
230      * @param locations A list of one or more OCSP responder URIs as strings
231      *
232      * @throws IOException if an encoding error occurs.
233      */
addAIAExt(List<String> locations)234     public void addAIAExt(List<String> locations)
235             throws IOException {
236         if (!locations.isEmpty()) {
237             List<AccessDescription> acDescList = new ArrayList<>();
238             for (String ocspUri : locations) {
239                 acDescList.add(new AccessDescription(
240                         AccessDescription.Ad_OCSP_Id,
241                         new GeneralName(new URIName(ocspUri))));
242             }
243             addExtension(new AuthorityInfoAccessExtension(acDescList));
244         }
245     }
246 
247     /**
248      * Set a Key Usage extension for the certificate.  The extension will
249      * be marked critical.
250      *
251      * @param bitSettings Boolean array for all nine bit settings in the order
252      * documented in RFC 5280 section 4.2.1.3.
253      *
254      * @throws IOException if an encoding error occurs.
255      */
addKeyUsageExt(boolean[] bitSettings)256     public void addKeyUsageExt(boolean[] bitSettings) throws IOException {
257         addExtension(new KeyUsageExtension(bitSettings));
258     }
259 
260     /**
261      * Set the Basic Constraints Extension for a certificate.
262      *
263      * @param crit {@code true} if critical, {@code false} otherwise
264      * @param isCA {@code true} if the extension will be on a CA certificate,
265      * {@code false} otherwise
266      * @param maxPathLen The maximum path length issued by this CA.  Values
267      * less than zero will omit this field from the resulting extension and
268      * no path length constraint will be asserted.
269      *
270      * @throws IOException if an encoding error occurs.
271      */
addBasicConstraintsExt(boolean crit, boolean isCA, int maxPathLen)272     public void addBasicConstraintsExt(boolean crit, boolean isCA,
273             int maxPathLen) throws IOException {
274         addExtension(new BasicConstraintsExtension(crit, isCA, maxPathLen));
275     }
276 
277     /**
278      * Add the Authority Key Identifier extension.
279      *
280      * @param authorityCert The certificate of the issuing authority.
281      *
282      * @throws IOException if an encoding error occurs.
283      */
addAuthorityKeyIdExt(X509Certificate authorityCert)284     public void addAuthorityKeyIdExt(X509Certificate authorityCert)
285             throws IOException {
286         addAuthorityKeyIdExt(authorityCert.getPublicKey());
287     }
288 
289     /**
290      * Add the Authority Key Identifier extension.
291      *
292      * @param authorityKey The public key of the issuing authority.
293      *
294      * @throws IOException if an encoding error occurs.
295      */
addAuthorityKeyIdExt(PublicKey authorityKey)296     public void addAuthorityKeyIdExt(PublicKey authorityKey) throws IOException {
297         KeyIdentifier kid = new KeyIdentifier(authorityKey);
298         addExtension(new AuthorityKeyIdentifierExtension(kid, null, null));
299     }
300 
301     /**
302      * Add the Subject Key Identifier extension.
303      *
304      * @param subjectKey The public key to be used in the resulting certificate
305      *
306      * @throws IOException if an encoding error occurs.
307      */
addSubjectKeyIdExt(PublicKey subjectKey)308     public void addSubjectKeyIdExt(PublicKey subjectKey) throws IOException {
309         byte[] keyIdBytes = new KeyIdentifier(subjectKey).getIdentifier();
310         addExtension(new SubjectKeyIdentifierExtension(keyIdBytes));
311     }
312 
313     /**
314      * Add the Extended Key Usage extension.
315      *
316      * @param ekuOids A {@link List} of object identifiers in string form.
317      *
318      * @throws IOException if an encoding error occurs.
319      */
addExtendedKeyUsageExt(List<String> ekuOids)320     public void addExtendedKeyUsageExt(List<String> ekuOids)
321             throws IOException {
322         if (!ekuOids.isEmpty()) {
323             Vector<ObjectIdentifier> oidVector = new Vector<>();
324             for (String oid : ekuOids) {
325                 oidVector.add(new ObjectIdentifier(oid));
326             }
327             addExtension(new ExtendedKeyUsageExtension(oidVector));
328         }
329     }
330 
331     /**
332      * Clear all settings and return the {@code CertificateBuilder} to
333      * its default state.
334      */
reset()335     public void reset() {
336         extensions.clear();
337         subjectName = null;
338         notBefore = null;
339         notAfter = null;
340         serialNumber = null;
341         publicKey = null;
342         signatureBytes = null;
343         tbsCertBytes = null;
344     }
345 
346     /**
347      * Build the certificate.
348      *
349      * @param issuerCert The certificate of the issuing authority, or
350      * {@code null} if the resulting certificate is self-signed.
351      * @param issuerKey The private key of the issuing authority
352      * @param algName The signature algorithm name
353      *
354      * @return The resulting {@link X509Certificate}
355      *
356      * @throws IOException if an encoding error occurs.
357      * @throws CertificateException If the certificate cannot be generated
358      * by the underlying {@link CertificateFactory}
359      * @throws NoSuchAlgorithmException If an invalid signature algorithm
360      * is provided.
361      */
build(X509Certificate issuerCert, PrivateKey issuerKey, String algName)362     public X509Certificate build(X509Certificate issuerCert,
363             PrivateKey issuerKey, String algName)
364             throws IOException, CertificateException, NoSuchAlgorithmException {
365         // TODO: add some basic checks (key usage, basic constraints maybe)
366 
367         AlgorithmId signAlg = AlgorithmId.get(algName);
368         byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, signAlg);
369         ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert);
370         return (X509Certificate)factory.generateCertificate(bais);
371     }
372 
373     /**
374      * Encode the contents of the outer-most ASN.1 SEQUENCE:
375      *
376      * <PRE>
377      *  Certificate  ::=  SEQUENCE  {
378      *      tbsCertificate       TBSCertificate,
379      *      signatureAlgorithm   AlgorithmIdentifier,
380      *      signatureValue       BIT STRING  }
381      * </PRE>
382      *
383      * @param issuerCert The certificate of the issuing authority, or
384      * {@code null} if the resulting certificate is self-signed.
385      * @param issuerKey The private key of the issuing authority
386      * @param signAlg The signature algorithm object
387      *
388      * @return The DER-encoded X.509 certificate
389      *
390      * @throws CertificateException If an error occurs during the
391      * signing process.
392      * @throws IOException if an encoding error occurs.
393      */
encodeTopLevel(X509Certificate issuerCert, PrivateKey issuerKey, AlgorithmId signAlg)394     private byte[] encodeTopLevel(X509Certificate issuerCert,
395             PrivateKey issuerKey, AlgorithmId signAlg)
396             throws CertificateException, IOException {
397         DerOutputStream outerSeq = new DerOutputStream();
398         DerOutputStream topLevelItems = new DerOutputStream();
399 
400         tbsCertBytes = encodeTbsCert(issuerCert, signAlg);
401         topLevelItems.write(tbsCertBytes);
402         try {
403             signatureBytes = signCert(issuerKey, signAlg);
404         } catch (GeneralSecurityException ge) {
405             throw new CertificateException(ge);
406         }
407         signAlg.derEncode(topLevelItems);
408         topLevelItems.putBitString(signatureBytes);
409         outerSeq.write(DerValue.tag_Sequence, topLevelItems);
410 
411         return outerSeq.toByteArray();
412     }
413 
414     /**
415      * Encode the bytes for the TBSCertificate structure:
416      * <PRE>
417      *  TBSCertificate  ::=  SEQUENCE  {
418      *      version         [0]  EXPLICIT Version DEFAULT v1,
419      *      serialNumber         CertificateSerialNumber,
420      *      signature            AlgorithmIdentifier,
421      *      issuer               Name,
422      *      validity             Validity,
423      *      subject              Name,
424      *      subjectPublicKeyInfo SubjectPublicKeyInfo,
425      *      issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
426      *                        -- If present, version MUST be v2 or v3
427      *      subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
428      *                        -- If present, version MUST be v2 or v3
429      *      extensions      [3]  EXPLICIT Extensions OPTIONAL
430      *                        -- If present, version MUST be v3
431      *      }
432      *
433      * @param issuerCert The certificate of the issuing authority, or
434      * {@code null} if the resulting certificate is self-signed.
435      * @param signAlg The signature algorithm object
436      *
437      * @return The DER-encoded bytes for the TBSCertificate structure
438      *
439      * @throws IOException if an encoding error occurs.
440      */
encodeTbsCert(X509Certificate issuerCert, AlgorithmId signAlg)441     private byte[] encodeTbsCert(X509Certificate issuerCert,
442             AlgorithmId signAlg) throws IOException {
443         DerOutputStream tbsCertSeq = new DerOutputStream();
444         DerOutputStream tbsCertItems = new DerOutputStream();
445 
446         // Hardcode to V3
447         byte[] v3int = {0x02, 0x01, 0x02};
448         tbsCertItems.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
449                 (byte)0), v3int);
450 
451         // Serial Number
452         SerialNumber sn = new SerialNumber(serialNumber);
453         sn.encode(tbsCertItems);
454 
455         // Algorithm ID
456         signAlg.derEncode(tbsCertItems);
457 
458         // Issuer Name
459         if (issuerCert != null) {
460             tbsCertItems.write(
461                     issuerCert.getSubjectX500Principal().getEncoded());
462         } else {
463             // Self-signed
464             tbsCertItems.write(subjectName.getEncoded());
465         }
466 
467         // Validity period (set as UTCTime)
468         DerOutputStream valSeq = new DerOutputStream();
469         valSeq.putUTCTime(notBefore);
470         valSeq.putUTCTime(notAfter);
471         tbsCertItems.write(DerValue.tag_Sequence, valSeq);
472 
473         // Subject Name
474         tbsCertItems.write(subjectName.getEncoded());
475 
476         // SubjectPublicKeyInfo
477         tbsCertItems.write(publicKey.getEncoded());
478 
479         // TODO: Extensions!
480         encodeExtensions(tbsCertItems);
481 
482         // Wrap it all up in a SEQUENCE and return the bytes
483         tbsCertSeq.write(DerValue.tag_Sequence, tbsCertItems);
484         return tbsCertSeq.toByteArray();
485     }
486 
487     /**
488      * Encode the extensions segment for an X.509 Certificate:
489      *
490      * <PRE>
491      *  Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
492      *
493      *  Extension  ::=  SEQUENCE  {
494      *      extnID      OBJECT IDENTIFIER,
495      *      critical    BOOLEAN DEFAULT FALSE,
496      *      extnValue   OCTET STRING
497      *                  -- contains the DER encoding of an ASN.1 value
498      *                  -- corresponding to the extension type identified
499      *                  -- by extnID
500      *      }
501      * </PRE>
502      *
503      * @param tbsStream The {@code DerOutputStream} that holds the
504      * TBSCertificate contents.
505      *
506      * @throws IOException if an encoding error occurs.
507      */
encodeExtensions(DerOutputStream tbsStream)508     private void encodeExtensions(DerOutputStream tbsStream)
509             throws IOException {
510         DerOutputStream extSequence = new DerOutputStream();
511         DerOutputStream extItems = new DerOutputStream();
512 
513         for (Extension ext : extensions.values()) {
514             ext.encode(extItems);
515         }
516         extSequence.write(DerValue.tag_Sequence, extItems);
517         tbsStream.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
518                 (byte)3), extSequence);
519     }
520 
521     /**
522      * Digitally sign the X.509 certificate.
523      *
524      * @param issuerKey The private key of the issuing authority
525      * @param signAlg The signature algorithm object
526      *
527      * @return The digital signature bytes.
528      *
529      * @throws GeneralSecurityException If any errors occur during the
530      * digital signature process.
531      */
signCert(PrivateKey issuerKey, AlgorithmId signAlg)532     private byte[] signCert(PrivateKey issuerKey, AlgorithmId signAlg)
533             throws GeneralSecurityException {
534         Signature sig = Signature.getInstance(signAlg.getName());
535         sig.initSign(issuerKey);
536         sig.update(tbsCertBytes);
537         return sig.sign();
538     }
539  }
540