1 /*
   2  * Copyright (c) 2006, 2017, 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 /*
  25  * @test
  26  * @bug 6405536 6414980 8051972
  27  * @summary Make sure that we can parse certificates using various named curves
  28  *   and verify their signatures
  29  * @author Andreas Sterbenz
  30  * @library ..
  31  * @library ../../../../java/security/testlibrary
  32  * @modules jdk.crypto.cryptoki
  33  * @run main/othervm ReadCertificates
  34  * @run main/othervm ReadCertificates sm policy
  35  */
  36 
  37 import java.io.File;
  38 import java.io.FileInputStream;
  39 import java.io.InputStream;
  40 import java.security.InvalidKeyException;
  41 import java.security.NoSuchAlgorithmException;
  42 import java.security.NoSuchProviderException;
  43 import java.security.Provider;
  44 import java.security.PublicKey;
  45 import java.security.SecureRandom;
  46 import java.security.SignatureException;
  47 import java.security.cert.CertificateException;
  48 import java.security.cert.CertificateFactory;
  49 import java.security.cert.X509Certificate;
  50 import java.security.interfaces.ECPublicKey;
  51 import java.security.spec.ECParameterSpec;
  52 import java.util.ArrayList;
  53 import java.util.Arrays;
  54 import java.util.Collection;
  55 import java.util.LinkedHashMap;
  56 import java.util.List;
  57 import java.util.Map;
  58 import javax.security.auth.x500.X500Principal;
  59 
  60 public class ReadCertificates extends PKCS11Test {
  61 
  62     private static CertificateFactory factory;
  63 
  64     private static SecureRandom random;
  65 
  66     private static Collection<X509Certificate> readCertificates(File file) throws Exception {
  67         System.out.println("Loading " + file.getName() + "...");
  68         Collection<X509Certificate> certs;
  69         try (InputStream in = new FileInputStream(file)) {
  70             certs = (Collection<X509Certificate>)factory.generateCertificates(in);
  71         }
  72         return certs;
  73     }
  74 
  75     public static void main(String[] args) throws Exception {
  76         main(new ReadCertificates(), args);
  77     }
  78 
  79     @Override
  80     public void main(Provider p) throws Exception {
  81         if (p.getService("Signature", "SHA1withECDSA") == null) {
  82             System.out.println("Provider does not support ECDSA, skipping...");
  83             return;
  84         }
  85 
  86         /*
  87          * PKCS11Test.main will remove this provider if needed
  88          */
  89         Providers.setAt(p, 1);
  90 
  91         random = new SecureRandom();
  92         factory = CertificateFactory.getInstance("X.509");
  93         try {
  94             // clear certificate cache in from a previous run with a different
  95             // provider (undocumented hack for the Sun provider)
  96             factory.generateCertificate(null);
  97         } catch (CertificateException e) {
  98             // ignore
  99         }
 100         Map<X500Principal,X509Certificate> certs = new LinkedHashMap<>();
 101 
 102         File dir = new File(BASE, "certs");
 103         File closedDir = new File(CLOSED_BASE, "certs");
 104         File[] files = concat(dir.listFiles(), closedDir.listFiles());
 105         Arrays.sort(files);
 106         for (File file : files) {
 107             if (file.isFile() == false) {
 108                 continue;
 109             }
 110             Collection<X509Certificate> certList = readCertificates(file);
 111             for (X509Certificate cert : certList) {
 112                 X509Certificate old = certs.put(cert.getSubjectX500Principal(), cert);
 113                 if (old != null) {
 114                     System.out.println("Duplicate subject:");
 115                     System.out.println("Old Certificate: " + old);
 116                     System.out.println("New Certificate: " + cert);
 117                     throw new Exception(file.getPath());
 118                 }
 119             }
 120         }
 121         System.out.println("OK: " + certs.size() + " certificates.");
 122 
 123         // Get supported curves
 124         List<ECParameterSpec> supportedEC = getKnownCurves(p);
 125 
 126         System.out.println("Test Certs:\n");
 127         for (X509Certificate cert : certs.values()) {
 128             X509Certificate issuer = certs.get(cert.getIssuerX500Principal());
 129             System.out.print("Verifying " + cert.getSubjectX500Principal() +
 130                     "...  ");
 131             PublicKey key = issuer.getPublicKey();
 132             // Check if curve is supported
 133             if (issuer.getPublicKey() instanceof ECPublicKey) {
 134                 if (!checkSupport(supportedEC,
 135                         ((ECPublicKey)key).getParams())) {
 136                     System.out.println("Curve not found. Skipped.");
 137                     continue;
 138                 }
 139             }
 140 
 141            try {
 142                cert.verify(key, p.getName());
 143                System.out.println("Pass.");
 144            } catch (NoSuchAlgorithmException e) {
 145                System.out.println("Warning: " + e.getMessage() +
 146                    ". Trying another provider...");
 147                cert.verify(key);
 148            } catch (CertificateException | InvalidKeyException |
 149                     NoSuchProviderException | SignatureException e) {
 150                System.out.println(e.getMessage());
 151                if (key instanceof ECPublicKey) {
 152                    System.out.println("Failed.\n\tCurve: " +
 153                            ((ECPublicKey)key).getParams() +
 154                            "\n\tSignature Alg: " + cert.getSigAlgName());
 155                } else {
 156                    System.out.println("Key: "+key.toString());
 157                }
 158 
 159                System.err.println("Verifying " + cert.getSubjectX500Principal());
 160                e.printStackTrace();
 161            }
 162         }
 163 
 164         // try some random invalid signatures to make sure we get the correct
 165         // error
 166         System.out.println("Checking incorrect signatures...");
 167         List<X509Certificate> certList = new ArrayList<>(certs.values());
 168         for (int i = 0; i < 20; i++) {
 169             X509Certificate cert, signer;
 170             do {
 171                 cert = getRandomCert(certList);
 172                 signer = getRandomCert(certList);
 173             } while (cert.getIssuerX500Principal().equals(signer.getSubjectX500Principal()));
 174             try {
 175                 PublicKey signerPublicKey = signer.getPublicKey();
 176                 cert.verify(signerPublicKey);
 177                 // Ignore false positives
 178                 if (cert.getPublicKey().equals(signerPublicKey)) {
 179                     System.out.println("OK: self-signed certificate detected");
 180                 } else {
 181                     throw new Exception("Verified invalid signature");
 182                 }
 183             } catch (SignatureException | InvalidKeyException e) {
 184                 System.out.println("OK: " + e);
 185             }
 186         }
 187 
 188         System.out.println("OK");
 189     }
 190 
 191     private static X509Certificate getRandomCert(List<X509Certificate> certs) {
 192         int n = random.nextInt(certs.size());
 193         return certs.get(n);
 194     }
 195 
 196 }