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