1 /*
2  * Copyright (c) 2006, 2018, 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 /test/lib ..
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 
readCertificates(File file)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 
main(String[] args)75     public static void main(String[] args) throws Exception {
76         main(new ReadCertificates(), args);
77     }
78 
79     @Override
main(Provider p)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 
getRandomCert(List<X509Certificate> certs)191     private static X509Certificate getRandomCert(List<X509Certificate> certs) {
192         int n = random.nextInt(certs.size());
193         return certs.get(n);
194     }
195 
196 }
197