1 /*
   2  * Copyright (c) 2003, 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  *
  26  * @author Sean Mullan
  27  * @author Steve Hanna
  28  *
  29  */
  30 import java.io.ByteArrayInputStream;
  31 import java.io.ByteArrayOutputStream;
  32 import java.io.File;
  33 import java.io.FileInputStream;
  34 import java.io.InputStream;
  35 import java.io.IOException;
  36 import java.security.cert.CertificateException;
  37 import java.security.cert.CertificateFactory;
  38 import java.security.cert.CertPath;
  39 import java.security.cert.CertPathBuilder;
  40 import java.security.cert.CertPathValidator;
  41 import java.security.cert.CertStore;
  42 import java.security.cert.CollectionCertStoreParameters;
  43 import java.security.cert.CRLException;
  44 import java.security.cert.PKIXBuilderParameters;
  45 import java.security.cert.PKIXCertPathBuilderResult;
  46 import java.security.cert.PKIXCertPathValidatorResult;
  47 import java.security.cert.PKIXParameters;
  48 import java.security.cert.X509Certificate;
  49 import java.security.cert.X509CRL;
  50 import java.util.ArrayList;
  51 import java.util.HashSet;
  52 import java.util.List;
  53 import java.util.Set;
  54 
  55 /**
  56  * Static utility methods useful for testing certificate/certpath APIs.
  57  */
  58 public class CertUtils {
  59 
  60     private CertUtils() {}
  61 
  62     /**
  63      * Get a DER-encoded X.509 certificate from a file.
  64      *
  65      * @param certFilePath path to file containing DER-encoded certificate
  66      * @return the X509Certificate
  67      * @throws CertificateException if the certificate type is not supported
  68      *                              or cannot be parsed
  69      * @throws IOException if the file cannot be opened
  70      */
  71     public static X509Certificate getCertFromFile(String certFilePath)
  72         throws CertificateException, IOException {
  73         File certFile = new File(System.getProperty("test.src", "."),
  74                                  certFilePath);
  75         try (FileInputStream fis = new FileInputStream(certFile)) {
  76             return (X509Certificate)
  77                 CertificateFactory.getInstance("X.509")
  78                                   .generateCertificate(fis);
  79         }
  80     }
  81 
  82     /**
  83      * Get a PEM-encoded X.509 certificate from a string.
  84      *
  85      * @param cert string containing the PEM-encoded certificate
  86      * @return the X509Certificate
  87      * @throws CertificateException if the certificate type is not supported
  88      *                              or cannot be parsed
  89      */
  90     public static X509Certificate getCertFromString(String cert)
  91         throws CertificateException {
  92         byte[] certBytes = cert.getBytes();
  93         ByteArrayInputStream bais = new ByteArrayInputStream(certBytes);
  94         return (X509Certificate)
  95             CertificateFactory.getInstance("X.509").generateCertificate(bais);
  96     }
  97 
  98     /**
  99      * Get a DER-encoded X.509 CRL from a file.
 100      *
 101      * @param crlFilePath path to file containing DER-encoded CRL
 102      * @return the X509CRL
 103      * @throws CertificateException if the crl type is not supported
 104      * @throws CRLException if the crl cannot be parsed
 105      * @throws IOException if the file cannot be opened
 106      */
 107     public static X509CRL getCRLFromFile(String crlFilePath)
 108         throws CertificateException, CRLException, IOException {
 109         File crlFile = new File(System.getProperty("test.src", "."),
 110                                 crlFilePath);
 111         try (FileInputStream fis = new FileInputStream(crlFile)) {
 112             return (X509CRL)
 113                 CertificateFactory.getInstance("X.509").generateCRL(fis);
 114         }
 115     }
 116 
 117     /**
 118      * Get a PEM-encoded X.509 crl from a string.
 119      *
 120      * @param crl string containing the PEM-encoded crl
 121      * @return the X509CRL
 122      * @throws CertificateException if the crl type is not supported
 123      * @throws CRLException if the crl cannot be parsed
 124      */
 125     public static X509CRL getCRLFromString(String crl)
 126         throws CertificateException, CRLException {
 127         byte[] crlBytes = crl.getBytes();
 128         ByteArrayInputStream bais = new ByteArrayInputStream(crlBytes);
 129         return (X509CRL)
 130             CertificateFactory.getInstance("X.509").generateCRL(bais);
 131     }
 132 
 133     /**
 134      * Read a bunch of certs from files and create a CertPath from them.
 135      *
 136      * @param fileNames an array of <code>String</code>s that are file names
 137      * @throws Exception on error
 138      */
 139     public static CertPath buildPath(String [] fileNames) throws Exception {
 140         return buildPath("", fileNames);
 141     }
 142 
 143     /**
 144      * Read a bunch of certs from files and create a CertPath from them.
 145      *
 146      * @param relPath relative path containing certs (must end in
 147      *    file.separator)
 148      * @param fileNames an array of <code>String</code>s that are file names
 149      * @throws Exception on error
 150      */
 151     public static CertPath buildPath(String relPath, String [] fileNames)
 152         throws Exception {
 153         List<X509Certificate> list = new ArrayList<X509Certificate>();
 154         for (int i = 0; i < fileNames.length; i++) {
 155             list.add(0, getCertFromFile(relPath + fileNames[i]));
 156         }
 157         CertificateFactory cf = CertificateFactory.getInstance("X509");
 158         return(cf.generateCertPath(list));
 159     }
 160 
 161 
 162     /**
 163      * Read a bunch of certs from files and create a CertStore from them.
 164      *
 165      * @param fileNames an array of <code>String</code>s that are file names
 166      * @return the <code>CertStore</code> created
 167      * @throws Exception on error
 168      */
 169     public static CertStore createStore(String [] fileNames) throws Exception {
 170         return createStore("", fileNames);
 171     }
 172 
 173     /**
 174      * Read a bunch of certs from files and create a CertStore from them.
 175      *
 176      * @param relPath relative path containing certs (must end in
 177      *    file.separator)
 178      * @param fileNames an array of <code>String</code>s that are file names
 179      * @return the <code>CertStore</code> created
 180      * @throws Exception on error
 181      */
 182     public static CertStore createStore(String relPath, String [] fileNames)
 183         throws Exception {
 184         Set<X509Certificate> certs = new HashSet<X509Certificate>();
 185         for (int i = 0; i < fileNames.length; i++) {
 186             certs.add(getCertFromFile(relPath + fileNames[i]));
 187         }
 188         return CertStore.getInstance("Collection",
 189             new CollectionCertStoreParameters(certs));
 190     }
 191 
 192     /**
 193      * Read a bunch of CRLs from files and create a CertStore from them.
 194      *
 195      * @param fileNames an array of <code>String</code>s that are file names
 196      * @return the <code>CertStore</code> created
 197      * @throws Exception on error
 198      */
 199     public static CertStore createCRLStore(String [] fileNames)
 200         throws Exception {
 201         return createCRLStore("", fileNames);
 202     }
 203 
 204     /**
 205      * Read a bunch of CRLs from files and create a CertStore from them.
 206      *
 207      * @param relPath relative path containing CRLs (must end in file.separator)
 208      * @param fileNames an array of <code>String</code>s that are file names
 209      * @return the <code>CertStore</code> created
 210      * @throws Exception on error
 211      */
 212     public static CertStore createCRLStore(String relPath, String [] fileNames)
 213         throws Exception {
 214         Set<X509CRL> crls = new HashSet<X509CRL>();
 215         for (int i = 0; i < fileNames.length; i++) {
 216             crls.add(getCRLFromFile(relPath + fileNames[i]));
 217         }
 218         return CertStore.getInstance("Collection",
 219             new CollectionCertStoreParameters(crls));
 220     }
 221 
 222     /**
 223      * Perform a PKIX path build. On failure, throw an exception.
 224      *
 225      * @param params PKIXBuilderParameters to use in validation
 226      * @throws Exception on error
 227      */
 228     public static PKIXCertPathBuilderResult build(PKIXBuilderParameters params)
 229         throws Exception {
 230         CertPathBuilder builder =
 231             CertPathBuilder.getInstance("PKIX");
 232         return (PKIXCertPathBuilderResult) builder.build(params);
 233     }
 234 
 235     /**
 236      * Perform a PKIX validation. On failure, throw an exception.
 237      *
 238      * @param path CertPath to validate
 239      * @param params PKIXParameters to use in validation
 240      * @throws Exception on error
 241      */
 242     public static PKIXCertPathValidatorResult validate
 243         (CertPath path, PKIXParameters params) throws Exception {
 244         CertPathValidator validator =
 245             CertPathValidator.getInstance("PKIX");
 246         return (PKIXCertPathValidatorResult) validator.validate(path, params);
 247     }
 248 
 249     /*
 250      * Reads the entire input stream into a byte array.
 251      */
 252     private static byte[] getTotalBytes(InputStream is) throws IOException {
 253            byte[] buffer = new byte[8192];
 254         ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
 255         int n;
 256         baos.reset();
 257         while ((n = is.read(buffer, 0, buffer.length)) != -1) {
 258             baos.write(buffer, 0, n);
 259         }
 260         return baos.toByteArray();
 261     }
 262 }