/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import static java.lang.System.out; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Base64; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import sun.security.util.BitArray; import sun.security.util.ObjectIdentifier; import sun.security.x509.*; /** * @test * @bug 8049237 * @modules java.base/sun.security.x509 * java.base/sun.security.util * @summary This test generates V3 certificate with all the supported * extensions. Writes back the generated certificate in to a file and checks for * equality with the original certificate. */ public class V3Certificate { public static final String V3_FILE = "certV3"; public static final String V3_B64_FILE = "certV3.b64"; public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeyException, CertificateException, NoSuchProviderException, SignatureException { boolean success = true; success &= test("RSA", "SHA256withRSA", 2048); success &= test("DSA", "SHA256withDSA", 2048); success &= test("EC", "SHA256withECDSA", 384); if (!success) { throw new RuntimeException("At least one test case failed"); } } public static boolean test(String algorithm, String sigAlg, int keyLength) throws IOException, NoSuchAlgorithmException, InvalidKeyException, CertificateException, NoSuchProviderException, SignatureException { byte[] issuerId = {1, 2, 3, 4, 5}; byte[] subjectId = {6, 7, 8, 9, 10}; boolean testResult = true; // Subject and Issuer X500Name subject = new X500Name("test", "Oracle", "Santa Clara", "US"); X500Name issuer = subject; // Generate keys and sign KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm); keyGen.initialize(keyLength); KeyPair pair = keyGen.generateKeyPair(); PublicKey publicKey = pair.getPublic(); PrivateKey privateKey = pair.getPrivate(); MessageDigest md = MessageDigest.getInstance("SHA"); byte[] keyId = md.digest(publicKey.getEncoded()); Signature signature = Signature.getInstance(sigAlg); signature.initSign(privateKey); // Validity interval Date firstDate = new Date(); Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("PST")); cal.set(2014, 03, 10, 12, 30, 30); Date lastDate = cal.getTime(); CertificateValidity interval = new CertificateValidity(firstDate, lastDate); // Certificate Info X509CertInfo cert = new X509CertInfo(); cert.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); cert.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber((int) (firstDate.getTime() / 1000))); cert.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(AlgorithmId.get(sigAlg))); cert.set(X509CertInfo.SUBJECT, subject); cert.set(X509CertInfo.KEY, new CertificateX509Key(publicKey)); cert.set(X509CertInfo.VALIDITY, interval); cert.set(X509CertInfo.ISSUER, issuer); cert.set(X509CertInfo.ISSUER_ID, new UniqueIdentity( new BitArray(issuerId.length * 8 - 2, issuerId))); cert.set(X509CertInfo.SUBJECT_ID, new UniqueIdentity(subjectId)); // Create Extensions CertificateExtensions exts = new CertificateExtensions(); GeneralNameInterface mailInf = new RFC822Name("test@Oracle.com"); GeneralName mail = new GeneralName(mailInf); GeneralNameInterface dnsInf = new DNSName("Oracle.com"); GeneralName dns = new GeneralName(dnsInf); GeneralNameInterface uriInf = new URIName("http://www.Oracle.com"); GeneralName uri = new GeneralName(uriInf); // localhost byte[] address = new byte[]{127, 0, 0, 1}; GeneralNameInterface ipInf = new IPAddressName(address); GeneralName ip = new GeneralName(ipInf); int[] oidData = new int[]{1, 2, 3, 4}; GeneralNameInterface oidInf = new OIDName(new ObjectIdentifier(oidData)); GeneralName oid = new GeneralName(oidInf); SubjectAlternativeNameExtension subjectName = new SubjectAlternativeNameExtension(); IssuerAlternativeNameExtension issuerName = new IssuerAlternativeNameExtension(); GeneralNames subjectNames = (GeneralNames) subjectName. get(SubjectAlternativeNameExtension.SUBJECT_NAME); GeneralNames issuerNames = (GeneralNames) issuerName. get(IssuerAlternativeNameExtension.ISSUER_NAME); subjectNames.add(mail); subjectNames.add(dns); subjectNames.add(uri); issuerNames.add(ip); issuerNames.add(oid); cal.set(2000, 11, 15, 12, 30, 30); lastDate = cal.getTime(); PrivateKeyUsageExtension pkusage = new PrivateKeyUsageExtension(firstDate, lastDate); KeyUsageExtension usage = new KeyUsageExtension(); usage.set(KeyUsageExtension.CRL_SIGN, true); usage.set(KeyUsageExtension.DIGITAL_SIGNATURE, true); usage.set(KeyUsageExtension.NON_REPUDIATION, true); KeyIdentifier kid = new KeyIdentifier(keyId); SerialNumber sn = new SerialNumber(42); AuthorityKeyIdentifierExtension aki = new AuthorityKeyIdentifierExtension(kid, subjectNames, sn); SubjectKeyIdentifierExtension ski = new SubjectKeyIdentifierExtension(keyId); BasicConstraintsExtension cons = new BasicConstraintsExtension(true, 10); PolicyConstraintsExtension pce = new PolicyConstraintsExtension(2, 4); exts.set(SubjectAlternativeNameExtension.NAME, subjectName); exts.set(IssuerAlternativeNameExtension.NAME, issuerName); exts.set(PrivateKeyUsageExtension.NAME, pkusage); exts.set(KeyUsageExtension.NAME, usage); exts.set(AuthorityKeyIdentifierExtension.NAME, aki); exts.set(SubjectKeyIdentifierExtension.NAME, ski); exts.set(BasicConstraintsExtension.NAME, cons); exts.set(PolicyConstraintsExtension.NAME, pce); cert.set(X509CertInfo.EXTENSIONS, exts); // Generate and sign X509CertImpl X509CertImpl crt = new X509CertImpl(cert); crt.sign(privateKey, sigAlg); crt.verify(publicKey); try (FileOutputStream fos = new FileOutputStream(new File(V3_FILE)); FileOutputStream fos_b64 = new FileOutputStream(new File(V3_B64_FILE)); PrintWriter pw = new PrintWriter(fos_b64)) { crt.encode((OutputStream) fos); fos.flush(); // Certificate boundaries/ pw.println("-----BEGIN CERTIFICATE-----"); pw.flush(); fos_b64.write(Base64.getMimeEncoder().encode(crt.getEncoded())); fos_b64.flush(); pw.println("-----END CERTIFICATE-----"); } out.println("*** Certificate ***"); out.println(crt); out.println("*** End Certificate ***"); X509Certificate x2 = generateCertificate(V3_FILE); if (!x2.equals(crt)) { out.println("*** Certificate mismatch ***"); testResult = false; } X509Certificate x3 = generateCertificate(V3_B64_FILE); if (!x3.equals(crt)) { out.println("*** Certificate mismatch ***"); testResult = false; } return testResult; } static X509Certificate generateCertificate(String certFile) { try (InputStream inStrm = new FileInputStream(certFile)) { CertificateFactory cf = CertificateFactory.getInstance("X509"); X509Certificate x2 = (X509Certificate) cf.generateCertificate(inStrm); return x2; } catch (CertificateException | IOException e) { throw new RuntimeException("Exception while " + "genrating certificate for " + certFile, e); } } }