1 /*
   2  * Copyright (c) 1996, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package sun.security.pkcs10;
  28 
  29 import java.io.PrintStream;
  30 import java.io.IOException;
  31 import java.math.BigInteger;
  32 
  33 import java.security.cert.CertificateException;
  34 import java.security.*;
  35 import java.security.spec.AlgorithmParameterSpec;
  36 
  37 import java.util.Base64;
  38 
  39 import sun.security.util.*;
  40 import sun.security.x509.AlgorithmId;
  41 import sun.security.x509.X509Key;
  42 import sun.security.x509.X500Name;
  43 import sun.security.util.SignatureUtil;
  44 
  45 
  46 /**
  47  * A PKCS #10 certificate request is created and sent to a Certificate
  48  * Authority, which then creates an X.509 certificate and returns it to
  49  * the entity that requested it. A certificate request basically consists
  50  * of the subject's X.500 name, public key, and optionally some attributes,
  51  * signed using the corresponding private key.
  52  *
  53  * The ASN.1 syntax for a Certification Request is:
  54  * <pre>
  55  * CertificationRequest ::= SEQUENCE {
  56  *    certificationRequestInfo CertificationRequestInfo,
  57  *    signatureAlgorithm       SignatureAlgorithmIdentifier,
  58  *    signature                Signature
  59  *  }
  60  *
  61  * SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
  62  * Signature ::= BIT STRING
  63  *
  64  * CertificationRequestInfo ::= SEQUENCE {
  65  *    version                 Version,
  66  *    subject                 Name,
  67  *    subjectPublicKeyInfo    SubjectPublicKeyInfo,
  68  *    attributes [0] IMPLICIT Attributes
  69  * }
  70  * Attributes ::= SET OF Attribute
  71  * </pre>
  72  *
  73  * @author David Brownell
  74  * @author Amit Kapoor
  75  * @author Hemma Prafullchandra
  76  */
  77 public class PKCS10 {
  78     /**
  79      * Constructs an unsigned PKCS #10 certificate request.  Before this
  80      * request may be used, it must be encoded and signed.  Then it
  81      * must be retrieved in some conventional format (e.g. string).
  82      *
  83      * @param publicKey the public key that should be placed
  84      *          into the certificate generated by the CA.
  85      */
  86     public PKCS10(PublicKey publicKey) {
  87         subjectPublicKeyInfo = publicKey;
  88         attributeSet = new PKCS10Attributes();
  89     }
  90 
  91     /**
  92      * Constructs an unsigned PKCS #10 certificate request.  Before this
  93      * request may be used, it must be encoded and signed.  Then it
  94      * must be retrieved in some conventional format (e.g. string).
  95      *
  96      * @param publicKey the public key that should be placed
  97      *          into the certificate generated by the CA.
  98      * @param attributes additonal set of PKCS10 attributes requested
  99      *          for in the certificate.
 100      */
 101     public PKCS10(PublicKey publicKey, PKCS10Attributes attributes) {
 102         subjectPublicKeyInfo = publicKey;
 103         attributeSet = attributes;
 104     }
 105 
 106     /**
 107      * Parses an encoded, signed PKCS #10 certificate request, verifying
 108      * the request's signature as it does so.  This constructor would
 109      * typically be used by a Certificate Authority, from which a new
 110      * certificate would then be constructed.
 111      *
 112      * @param data the DER-encoded PKCS #10 request.
 113      * @exception IOException for low level errors reading the data
 114      * @exception SignatureException when the signature is invalid
 115      * @exception NoSuchAlgorithmException when the signature
 116      *  algorithm is not supported in this environment
 117      */
 118     public PKCS10(byte[] data)
 119     throws IOException, SignatureException, NoSuchAlgorithmException {
 120         DerInputStream  in;
 121         DerValue[]      seq;
 122         AlgorithmId     id;
 123         byte[]          sigData;
 124         Signature       sig;
 125 
 126         encoded = data;
 127 
 128         //
 129         // Outer sequence:  request, signature algorithm, signature.
 130         // Parse, and prepare to verify later.
 131         //
 132         in = new DerInputStream(data);
 133         seq = in.getSequence(3);
 134 
 135         if (seq.length != 3)
 136             throw new IllegalArgumentException("not a PKCS #10 request");
 137 
 138         data = seq[0].toByteArray();            // reusing this variable
 139         id = AlgorithmId.parse(seq[1]);
 140         sigData = seq[2].getBitString();
 141 
 142         //
 143         // Inner sequence:  version, name, key, attributes
 144         //
 145         BigInteger      serial;
 146         DerValue        val;
 147 
 148         serial = seq[0].data.getBigInteger();
 149         if (!serial.equals(BigInteger.ZERO))
 150             throw new IllegalArgumentException("not PKCS #10 v1");
 151 
 152         subject = new X500Name(seq[0].data);
 153         subjectPublicKeyInfo = X509Key.parse(seq[0].data.getDerValue());
 154 
 155         // Cope with a somewhat common illegal PKCS #10 format
 156         if (seq[0].data.available() != 0)
 157             attributeSet = new PKCS10Attributes(seq[0].data);
 158         else
 159             attributeSet = new PKCS10Attributes();
 160 
 161         if (seq[0].data.available() != 0)
 162             throw new IllegalArgumentException("illegal PKCS #10 data");
 163 
 164         //
 165         // OK, we parsed it all ... validate the signature using the
 166         // key and signature algorithm we found.
 167         //
 168         try {
 169             sigAlg = id.getName();
 170             sig = Signature.getInstance(sigAlg);
 171 
 172             sig.initVerify(subjectPublicKeyInfo);
 173 
 174             // set parameters after Signature.initSign/initVerify call,
 175             // so the deferred provider selections occur when key is set
 176             SignatureUtil.specialSetParameter(sig, id.getParameters());
 177 
 178             sig.update(data);
 179             if (!sig.verify(sigData)) {
 180                 throw new SignatureException("Invalid PKCS #10 signature");
 181             }
 182         } catch (InvalidKeyException e) {
 183             throw new SignatureException("Invalid key");
 184         } catch (InvalidAlgorithmParameterException e) {
 185             throw new SignatureException("Invalid signature parameters", e);
 186         } catch (ProviderException e) {
 187             throw new SignatureException("Error parsing signature parameters",
 188                 e.getCause());
 189         }
 190     }
 191 
 192     /**
 193      * Create the signed certificate request.  This will later be
 194      * retrieved in either string or binary format.
 195      *
 196      * @param subject identifies the signer (by X.500 name).
 197      * @param signature private key and signing algorithm to use.
 198      * @exception IOException on errors.
 199      * @exception CertificateException on certificate handling errors.
 200      * @exception SignatureException on signature handling errors.
 201      */
 202     public void encodeAndSign(X500Name subject, Signature signature)
 203     throws CertificateException, IOException, SignatureException {
 204         DerOutputStream out, scratch;
 205         byte[]          certificateRequestInfo;
 206         byte[]          sig;
 207 
 208         if (encoded != null)
 209             throw new SignatureException("request is already signed");
 210 
 211         this.subject = subject;
 212 
 213         /*
 214          * Encode cert request info, wrap in a sequence for signing
 215          */
 216         scratch = new DerOutputStream();
 217         scratch.putInteger(BigInteger.ZERO);            // PKCS #10 v1.0
 218         subject.encode(scratch);                        // X.500 name
 219         scratch.write(subjectPublicKeyInfo.getEncoded()); // public key
 220         attributeSet.encode(scratch);
 221 
 222         out = new DerOutputStream();
 223         out.write(DerValue.tag_Sequence, scratch);      // wrap it!
 224         certificateRequestInfo = out.toByteArray();
 225         scratch = out;
 226 
 227         /*
 228          * Sign it ...
 229          */
 230         signature.update(certificateRequestInfo, 0,
 231                 certificateRequestInfo.length);
 232         sig = signature.sign();
 233         sigAlg = signature.getAlgorithm();
 234 
 235         /*
 236          * Build guts of SIGNED macro
 237          */
 238         AlgorithmId algId = null;
 239         try {
 240             algId = AlgorithmId.get(signature.getAlgorithm());
 241         } catch (NoSuchAlgorithmException nsae) {
 242             throw new SignatureException(nsae);
 243         }
 244         algId.encode(scratch);     // sig algorithm
 245         scratch.putBitString(sig);                      // sig
 246 
 247         /*
 248          * Wrap those guts in a sequence
 249          */
 250         out = new DerOutputStream();
 251         out.write(DerValue.tag_Sequence, scratch);
 252         encoded = out.toByteArray();
 253     }
 254 
 255     /**
 256      * Returns the subject's name.
 257      */
 258     public X500Name getSubjectName() { return subject; }
 259 
 260     /**
 261      * Returns the subject's public key.
 262      */
 263     public PublicKey getSubjectPublicKeyInfo()
 264         { return subjectPublicKeyInfo; }
 265 
 266     /**
 267      * Returns the signature algorithm.
 268      */
 269     public String getSigAlg() { return sigAlg; }
 270 
 271     /**
 272      * Returns the additional attributes requested.
 273      */
 274     public PKCS10Attributes getAttributes()
 275         { return attributeSet; }
 276 
 277     /**
 278      * Returns the encoded and signed certificate request as a
 279      * DER-encoded byte array.
 280      *
 281      * @return the certificate request, or null if encodeAndSign()
 282      *          has not yet been called.
 283      */
 284     public byte[] getEncoded() {
 285         if (encoded != null)
 286             return encoded.clone();
 287         else
 288             return null;
 289     }
 290 
 291     /**
 292      * Prints an E-Mailable version of the certificate request on the print
 293      * stream passed.  The format is a common base64 encoded one, supported
 294      * by most Certificate Authorities because Netscape web servers have
 295      * used this for some time.  Some certificate authorities expect some
 296      * more information, in particular contact information for the web
 297      * server administrator.
 298      *
 299      * @param out the print stream where the certificate request
 300      *  will be printed.
 301      * @exception IOException when an output operation failed
 302      * @exception SignatureException when the certificate request was
 303      *  not yet signed.
 304      */
 305     public void print(PrintStream out)
 306     throws IOException, SignatureException {
 307         if (encoded == null)
 308             throw new SignatureException("Cert request was not signed");
 309 
 310 
 311         byte[] CRLF = new byte[] {'\r', '\n'};
 312         out.println("-----BEGIN NEW CERTIFICATE REQUEST-----");
 313         out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(encoded));
 314         out.println("-----END NEW CERTIFICATE REQUEST-----");
 315     }
 316 
 317     /**
 318      * Provides a short description of this request.
 319      */
 320     public String toString() {
 321         return "[PKCS #10 certificate request:\n"
 322             + subjectPublicKeyInfo.toString()
 323             + " subject: <" + subject + ">" + "\n"
 324             + " attributes: " + attributeSet.toString()
 325             + "\n]";
 326     }
 327 
 328     /**
 329      * Compares this object for equality with the specified
 330      * object. If the <code>other</code> object is an
 331      * <code>instanceof</code> <code>PKCS10</code>, then
 332      * its encoded form is retrieved and compared with the
 333      * encoded form of this certificate request.
 334      *
 335      * @param other the object to test for equality with this object.
 336      * @return true iff the encoded forms of the two certificate
 337      * requests match, false otherwise.
 338      */
 339     public boolean equals(Object other) {
 340         if (this == other)
 341             return true;
 342         if (!(other instanceof PKCS10))
 343             return false;
 344         if (encoded == null) // not signed yet
 345             return false;
 346         byte[] otherEncoded = ((PKCS10)other).getEncoded();
 347         if (otherEncoded == null)
 348             return false;
 349 
 350         return java.util.Arrays.equals(encoded, otherEncoded);
 351     }
 352 
 353     /**
 354      * Returns a hashcode value for this certificate request from its
 355      * encoded form.
 356      *
 357      * @return the hashcode value.
 358      */
 359     public int hashCode() {
 360         int     retval = 0;
 361         if (encoded != null)
 362             for (int i = 1; i < encoded.length; i++)
 363              retval += encoded[i] * i;
 364         return(retval);
 365     }
 366 
 367     private X500Name            subject;
 368     private PublicKey           subjectPublicKeyInfo;
 369     private String              sigAlg;
 370     private PKCS10Attributes    attributeSet;
 371     private byte[]              encoded;        // signed
 372 }