1 /*
2  * Copyright (c) 2015, 2016, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.io.PrintWriter;
31 import static java.lang.System.out;
32 import java.security.InvalidKeyException;
33 import java.security.KeyPair;
34 import java.security.KeyPairGenerator;
35 import java.security.MessageDigest;
36 import java.security.NoSuchAlgorithmException;
37 import java.security.NoSuchProviderException;
38 import java.security.PrivateKey;
39 import java.security.PublicKey;
40 import java.security.Signature;
41 import java.security.SignatureException;
42 import java.security.cert.CertificateException;
43 import java.security.cert.CertificateFactory;
44 import java.security.cert.X509Certificate;
45 import java.util.Calendar;
46 import java.util.Date;
47 import java.util.TimeZone;
48 import sun.misc.BASE64Encoder;
49 import sun.security.util.BitArray;
50 import sun.security.util.ObjectIdentifier;
51 import sun.security.x509.*;
52 
53 /**
54  * @test
55  * @bug 8049237
56  * @summary This test generates V3 certificate with all the supported
57  * extensions. Writes back the generated certificate in to a file and checks for
58  * equality with the original certificate.
59  */
60 public class V3Certificate {
61 
62     public static final String V3_FILE = "certV3";
63     public static final String V3_B64_FILE = "certV3.b64";
64 
main(String[] args)65     public static void main(String[] args) throws IOException,
66             NoSuchAlgorithmException, InvalidKeyException, CertificateException,
67             NoSuchProviderException, SignatureException {
68 
69         boolean success = true;
70 
71         success &= test("RSA", "SHA256withRSA", 2048);
72         success &= test("DSA", "SHA256withDSA", 2048);
73         success &= test("EC", "SHA256withECDSA", 384);
74 
75         if (!success) {
76             throw new RuntimeException("At least one test case failed");
77         }
78     }
79 
test(String algorithm, String sigAlg, int keyLength)80     public static boolean test(String algorithm, String sigAlg, int keyLength)
81             throws IOException,
82             NoSuchAlgorithmException,
83             InvalidKeyException,
84             CertificateException,
85             NoSuchProviderException,
86             SignatureException {
87 
88         byte[] issuerId = {1, 2, 3, 4, 5};
89         byte[] subjectId = {6, 7, 8, 9, 10};
90         boolean testResult = true;
91 
92         // Subject and Issuer
93         X500Name subject = new X500Name("test", "Oracle", "Santa Clara",
94                 "US");
95         X500Name issuer = subject;
96 
97         // Generate keys and sign
98         KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
99         keyGen.initialize(keyLength);
100         KeyPair pair = keyGen.generateKeyPair();
101         PublicKey publicKey = pair.getPublic();
102         PrivateKey privateKey = pair.getPrivate();
103         MessageDigest md = MessageDigest.getInstance("SHA");
104         byte[] keyId = md.digest(publicKey.getEncoded());
105 
106         Signature signature = Signature.getInstance(sigAlg);
107         signature.initSign(privateKey);
108 
109         // Validity interval
110         Date firstDate = new Date();
111         Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("PST"));
112         cal.set(2014, 03, 10, 12, 30, 30);
113         Date lastDate = cal.getTime();
114         CertificateValidity interval = new CertificateValidity(firstDate,
115                 lastDate);
116 
117         // Certificate Info
118         X509CertInfo cert = new X509CertInfo();
119 
120         cert.set(X509CertInfo.VERSION,
121                 new CertificateVersion(CertificateVersion.V3));
122         cert.set(X509CertInfo.SERIAL_NUMBER,
123                 new CertificateSerialNumber((int) (firstDate.getTime() / 1000)));
124         cert.set(X509CertInfo.ALGORITHM_ID,
125                 new CertificateAlgorithmId(AlgorithmId.get(sigAlg)));
126         cert.set(X509CertInfo.SUBJECT, subject);
127         cert.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
128         cert.set(X509CertInfo.VALIDITY, interval);
129         cert.set(X509CertInfo.ISSUER, issuer);
130 
131         cert.set(X509CertInfo.ISSUER_ID,
132                 new UniqueIdentity(
133                         new BitArray(issuerId.length * 8 - 2, issuerId)));
134         cert.set(X509CertInfo.SUBJECT_ID, new UniqueIdentity(subjectId));
135 
136         // Create Extensions
137         CertificateExtensions exts = new CertificateExtensions();
138 
139         GeneralNameInterface mailInf = new RFC822Name("test@Oracle.com");
140         GeneralName mail = new GeneralName(mailInf);
141         GeneralNameInterface dnsInf = new DNSName("Oracle.com");
142         GeneralName dns = new GeneralName(dnsInf);
143         GeneralNameInterface uriInf = new URIName("http://www.Oracle.com");
144         GeneralName uri = new GeneralName(uriInf);
145 
146         // localhost
147         byte[] address = new byte[]{127, 0, 0, 1};
148 
149         GeneralNameInterface ipInf = new IPAddressName(address);
150         GeneralName ip = new GeneralName(ipInf);
151         int[] oidData = new int[]{1, 2, 3, 4};
152 
153         GeneralNameInterface oidInf = new OIDName(new ObjectIdentifier(oidData));
154         GeneralName oid = new GeneralName(oidInf);
155 
156         SubjectAlternativeNameExtension subjectName
157                 = new SubjectAlternativeNameExtension();
158         IssuerAlternativeNameExtension issuerName
159                 = new IssuerAlternativeNameExtension();
160 
161         GeneralNames subjectNames
162                 = (GeneralNames) subjectName.
163                 get(SubjectAlternativeNameExtension.SUBJECT_NAME);
164 
165         GeneralNames issuerNames
166                 = (GeneralNames) issuerName.
167                 get(IssuerAlternativeNameExtension.ISSUER_NAME);
168 
169         subjectNames.add(mail);
170         subjectNames.add(dns);
171         subjectNames.add(uri);
172 
173         issuerNames.add(ip);
174         issuerNames.add(oid);
175 
176         cal.set(2000, 11, 15, 12, 30, 30);
177         lastDate = cal.getTime();
178         PrivateKeyUsageExtension pkusage
179                 = new PrivateKeyUsageExtension(firstDate, lastDate);
180 
181         KeyUsageExtension usage = new KeyUsageExtension();
182         usage.set(KeyUsageExtension.CRL_SIGN, true);
183         usage.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
184         usage.set(KeyUsageExtension.NON_REPUDIATION, true);
185 
186         KeyIdentifier kid = new KeyIdentifier(keyId);
187         SerialNumber sn = new SerialNumber(42);
188         AuthorityKeyIdentifierExtension aki
189                 = new AuthorityKeyIdentifierExtension(kid, subjectNames, sn);
190 
191         SubjectKeyIdentifierExtension ski
192                 = new SubjectKeyIdentifierExtension(keyId);
193 
194         BasicConstraintsExtension cons
195                 = new BasicConstraintsExtension(true, 10);
196 
197         PolicyConstraintsExtension pce = new PolicyConstraintsExtension(2, 4);
198 
199         exts.set(SubjectAlternativeNameExtension.NAME, subjectName);
200         exts.set(IssuerAlternativeNameExtension.NAME, issuerName);
201         exts.set(PrivateKeyUsageExtension.NAME, pkusage);
202         exts.set(KeyUsageExtension.NAME, usage);
203         exts.set(AuthorityKeyIdentifierExtension.NAME, aki);
204         exts.set(SubjectKeyIdentifierExtension.NAME, ski);
205         exts.set(BasicConstraintsExtension.NAME, cons);
206         exts.set(PolicyConstraintsExtension.NAME, pce);
207         cert.set(X509CertInfo.EXTENSIONS, exts);
208 
209         // Generate and sign X509CertImpl
210         X509CertImpl crt = new X509CertImpl(cert);
211         crt.sign(privateKey, sigAlg);
212         crt.verify(publicKey);
213 
214         try (FileOutputStream fos = new FileOutputStream(new File(V3_FILE));
215                 FileOutputStream fos_b64
216                 = new FileOutputStream(new File(V3_B64_FILE));
217                 PrintWriter pw = new PrintWriter(fos_b64)) {
218             crt.encode((OutputStream) fos);
219             fos.flush();
220 
221             // Certificate boundaries/
222             pw.println("-----BEGIN CERTIFICATE-----");
223             pw.flush();
224             new BASE64Encoder().encodeBuffer(crt.getEncoded(), fos_b64);
225             fos_b64.flush();
226             pw.println("-----END CERTIFICATE-----");
227         }
228 
229         out.println("*** Certificate ***");
230         out.println(crt);
231         out.println("*** End Certificate ***");
232 
233         X509Certificate x2 = generateCertificate(V3_FILE);
234         if (!x2.equals(crt)) {
235             out.println("*** Certificate mismatch ***");
236             testResult = false;
237         }
238 
239         X509Certificate x3 = generateCertificate(V3_B64_FILE);
240         if (!x3.equals(crt)) {
241             out.println("*** Certificate mismatch ***");
242             testResult = false;
243         }
244 
245         return testResult;
246     }
247 
generateCertificate(String certFile)248     static X509Certificate generateCertificate(String certFile) {
249         try (InputStream inStrm = new FileInputStream(certFile)) {
250             CertificateFactory cf = CertificateFactory.getInstance("X509");
251             X509Certificate x2
252                     = (X509Certificate) cf.generateCertificate(inStrm);
253             return x2;
254         } catch (CertificateException | IOException e) {
255             throw new RuntimeException("Exception while "
256                     + "genrating certificate for " + certFile, e);
257         }
258     }
259 }
260