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.
   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  * @modules java.base/sun.security.x509
  57  *          java.base/sun.security.util
  58  *          java.base/sun.misc
  59  * @summary This test generates V3 certificate with all the supported
  60  * extensions. Writes back the generated certificate in to a file and checks for
  61  * equality with the original certificate.
  62  */
  63 public class V3Certificate {
  64 
  65     public static final String V3_FILE = "certV3";
  66     public static final String V3_B64_FILE = "certV3.b64";
  67 
  68     public static void main(String[] args) throws IOException,
  69             NoSuchAlgorithmException, InvalidKeyException, CertificateException,
  70             NoSuchProviderException, SignatureException {
  71 
  72         boolean success = true;
  73 
  74         success &= test("RSA", "SHA256withRSA", 2048);
  75         success &= test("DSA", "SHA256withDSA", 2048);
  76         success &= test("EC", "SHA256withECDSA", 384);
  77 
  78         if (!success) {
  79             throw new RuntimeException("At least one test case failed");
  80         }
  81     }
  82 
  83     public static boolean test(String algorithm, String sigAlg, int keyLength)
  84             throws IOException,
  85             NoSuchAlgorithmException,
  86             InvalidKeyException,
  87             CertificateException,
  88             NoSuchProviderException,
  89             SignatureException {
  90 
  91         byte[] issuerId = {1, 2, 3, 4, 5};
  92         byte[] subjectId = {6, 7, 8, 9, 10};
  93         boolean testResult = true;
  94 
  95         // Subject and Issuer
  96         X500Name subject = new X500Name("test", "Oracle", "Santa Clara",
  97                 "US");
  98         X500Name issuer = subject;
  99 
 100         // Generate keys and sign
 101         KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
 102         keyGen.initialize(keyLength);
 103         KeyPair pair = keyGen.generateKeyPair();
 104         PublicKey publicKey = pair.getPublic();
 105         PrivateKey privateKey = pair.getPrivate();
 106         MessageDigest md = MessageDigest.getInstance("SHA");
 107         byte[] keyId = md.digest(publicKey.getEncoded());
 108 
 109         Signature signature = Signature.getInstance(sigAlg);
 110         signature.initSign(privateKey);
 111 
 112         // Validity interval
 113         Date firstDate = new Date();
 114         Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("PST"));
 115         cal.set(2014, 03, 10, 12, 30, 30);
 116         Date lastDate = cal.getTime();
 117         CertificateValidity interval = new CertificateValidity(firstDate,
 118                 lastDate);
 119 
 120         // Certificate Info
 121         X509CertInfo cert = new X509CertInfo();
 122 
 123         cert.set(X509CertInfo.VERSION,
 124                 new CertificateVersion(CertificateVersion.V3));
 125         cert.set(X509CertInfo.SERIAL_NUMBER,
 126                 new CertificateSerialNumber((int) (firstDate.getTime() / 1000)));
 127         cert.set(X509CertInfo.ALGORITHM_ID,
 128                 new CertificateAlgorithmId(AlgorithmId.get(sigAlg)));
 129         cert.set(X509CertInfo.SUBJECT, subject);
 130         cert.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
 131         cert.set(X509CertInfo.VALIDITY, interval);
 132         cert.set(X509CertInfo.ISSUER, issuer);
 133 
 134         cert.set(X509CertInfo.ISSUER_ID,
 135                 new UniqueIdentity(
 136                         new BitArray(issuerId.length * 8 - 2, issuerId)));
 137         cert.set(X509CertInfo.SUBJECT_ID, new UniqueIdentity(subjectId));
 138 
 139         // Create Extensions
 140         CertificateExtensions exts = new CertificateExtensions();
 141 
 142         GeneralNameInterface mailInf = new RFC822Name("test@Oracle.com");
 143         GeneralName mail = new GeneralName(mailInf);
 144         GeneralNameInterface dnsInf = new DNSName("Oracle.com");
 145         GeneralName dns = new GeneralName(dnsInf);
 146         GeneralNameInterface uriInf = new URIName("http://www.Oracle.com");
 147         GeneralName uri = new GeneralName(uriInf);
 148 
 149         // localhost
 150         byte[] address = new byte[]{127, 0, 0, 1};
 151 
 152         GeneralNameInterface ipInf = new IPAddressName(address);
 153         GeneralName ip = new GeneralName(ipInf);
 154         int[] oidData = new int[]{1, 2, 3, 4};
 155 
 156         GeneralNameInterface oidInf = new OIDName(new ObjectIdentifier(oidData));
 157         GeneralName oid = new GeneralName(oidInf);
 158 
 159         SubjectAlternativeNameExtension subjectName
 160                 = new SubjectAlternativeNameExtension();
 161         IssuerAlternativeNameExtension issuerName
 162                 = new IssuerAlternativeNameExtension();
 163 
 164         GeneralNames subjectNames
 165                 = (GeneralNames) subjectName.
 166                 get(SubjectAlternativeNameExtension.SUBJECT_NAME);
 167 
 168         GeneralNames issuerNames
 169                 = (GeneralNames) issuerName.
 170                 get(IssuerAlternativeNameExtension.ISSUER_NAME);
 171 
 172         subjectNames.add(mail);
 173         subjectNames.add(dns);
 174         subjectNames.add(uri);
 175 
 176         issuerNames.add(ip);
 177         issuerNames.add(oid);
 178 
 179         cal.set(2000, 11, 15, 12, 30, 30);
 180         lastDate = cal.getTime();
 181         PrivateKeyUsageExtension pkusage
 182                 = new PrivateKeyUsageExtension(firstDate, lastDate);
 183 
 184         KeyUsageExtension usage = new KeyUsageExtension();
 185         usage.set(KeyUsageExtension.CRL_SIGN, true);
 186         usage.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
 187         usage.set(KeyUsageExtension.NON_REPUDIATION, true);
 188 
 189         KeyIdentifier kid = new KeyIdentifier(keyId);
 190         SerialNumber sn = new SerialNumber(42);
 191         AuthorityKeyIdentifierExtension aki
 192                 = new AuthorityKeyIdentifierExtension(kid, subjectNames, sn);
 193 
 194         SubjectKeyIdentifierExtension ski
 195                 = new SubjectKeyIdentifierExtension(keyId);
 196 
 197         BasicConstraintsExtension cons
 198                 = new BasicConstraintsExtension(true, 10);
 199 
 200         PolicyConstraintsExtension pce = new PolicyConstraintsExtension(2, 4);
 201 
 202         exts.set(SubjectAlternativeNameExtension.NAME, subjectName);
 203         exts.set(IssuerAlternativeNameExtension.NAME, issuerName);
 204         exts.set(PrivateKeyUsageExtension.NAME, pkusage);
 205         exts.set(KeyUsageExtension.NAME, usage);
 206         exts.set(AuthorityKeyIdentifierExtension.NAME, aki);
 207         exts.set(SubjectKeyIdentifierExtension.NAME, ski);
 208         exts.set(BasicConstraintsExtension.NAME, cons);
 209         exts.set(PolicyConstraintsExtension.NAME, pce);
 210         cert.set(X509CertInfo.EXTENSIONS, exts);
 211 
 212         // Generate and sign X509CertImpl
 213         X509CertImpl crt = new X509CertImpl(cert);
 214         crt.sign(privateKey, sigAlg);
 215         crt.verify(publicKey);
 216 
 217         try (FileOutputStream fos = new FileOutputStream(new File(V3_FILE));
 218                 FileOutputStream fos_b64
 219                 = new FileOutputStream(new File(V3_B64_FILE));
 220                 PrintWriter pw = new PrintWriter(fos_b64)) {
 221             crt.encode((OutputStream) fos);
 222             fos.flush();
 223 
 224             // Certificate boundaries/
 225             pw.println("-----BEGIN CERTIFICATE-----");
 226             pw.flush();
 227             new BASE64Encoder().encodeBuffer(crt.getEncoded(), fos_b64);
 228             fos_b64.flush();
 229             pw.println("-----END CERTIFICATE-----");
 230         }
 231 
 232         out.println("*** Certificate ***");
 233         out.println(crt);
 234         out.println("*** End Certificate ***");
 235 
 236         X509Certificate x2 = generateCertificate(V3_FILE);
 237         if (!x2.equals(crt)) {
 238             out.println("*** Certificate mismatch ***");
 239             testResult = false;
 240         }
 241 
 242         X509Certificate x3 = generateCertificate(V3_B64_FILE);
 243         if (!x3.equals(crt)) {
 244             out.println("*** Certificate mismatch ***");
 245             testResult = false;
 246         }
 247 
 248         return testResult;
 249     }
 250 
 251     static X509Certificate generateCertificate(String certFile) {
 252         try (InputStream inStrm = new FileInputStream(certFile)) {
 253             CertificateFactory cf = CertificateFactory.getInstance("X509");
 254             X509Certificate x2
 255                     = (X509Certificate) cf.generateCertificate(inStrm);
 256             return x2;
 257         } catch (CertificateException | IOException e) {
 258             throw new RuntimeException("Exception while "
 259                     + "genrating certificate for " + certFile, e);
 260         }
 261     }
 262 }
--- EOF ---