jdk/src/share/classes/sun/security/pkcs/PKCS10.java
changeset 10822 0294e016d9b1
parent 10821 5ec6698ec5a9
parent 10808 882388c78d4e
child 10823 86db042b3385
equal deleted inserted replaced
10821:5ec6698ec5a9 10822:0294e016d9b1
     1 /*
       
     2  * Copyright (c) 1996, 2011, 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.pkcs;
       
    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 sun.misc.BASE64Encoder;
       
    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             sig = Signature.getInstance(id.getName());
       
   171             sig.initVerify(subjectPublicKeyInfo);
       
   172             sig.update(data);
       
   173             if (!sig.verify(sigData))
       
   174                 throw new SignatureException("Invalid PKCS #10 signature");
       
   175         } catch (InvalidKeyException e) {
       
   176             throw new SignatureException("invalid key");
       
   177         }
       
   178     }
       
   179 
       
   180     /**
       
   181      * Create the signed certificate request.  This will later be
       
   182      * retrieved in either string or binary format.
       
   183      *
       
   184      * @param subject identifies the signer (by X.500 name).
       
   185      * @param signature private key and signing algorithm to use.
       
   186      * @exception IOException on errors.
       
   187      * @exception CertificateException on certificate handling errors.
       
   188      * @exception SignatureException on signature handling errors.
       
   189      */
       
   190     public void encodeAndSign(X500Name subject, Signature signature)
       
   191     throws CertificateException, IOException, SignatureException {
       
   192         DerOutputStream out, scratch;
       
   193         byte[]          certificateRequestInfo;
       
   194         byte[]          sig;
       
   195 
       
   196         if (encoded != null)
       
   197             throw new SignatureException("request is already signed");
       
   198 
       
   199         this.subject = subject;
       
   200 
       
   201         /*
       
   202          * Encode cert request info, wrap in a sequence for signing
       
   203          */
       
   204         scratch = new DerOutputStream();
       
   205         scratch.putInteger(BigInteger.ZERO);            // PKCS #10 v1.0
       
   206         subject.encode(scratch);                        // X.500 name
       
   207         scratch.write(subjectPublicKeyInfo.getEncoded()); // public key
       
   208         attributeSet.encode(scratch);
       
   209 
       
   210         out = new DerOutputStream();
       
   211         out.write(DerValue.tag_Sequence, scratch);      // wrap it!
       
   212         certificateRequestInfo = out.toByteArray();
       
   213         scratch = out;
       
   214 
       
   215         /*
       
   216          * Sign it ...
       
   217          */
       
   218         signature.update(certificateRequestInfo, 0,
       
   219                 certificateRequestInfo.length);
       
   220         sig = signature.sign();
       
   221 
       
   222         /*
       
   223          * Build guts of SIGNED macro
       
   224          */
       
   225         AlgorithmId algId = null;
       
   226         try {
       
   227             algId = AlgorithmId.get(signature.getAlgorithm());
       
   228         } catch (NoSuchAlgorithmException nsae) {
       
   229             throw new SignatureException(nsae);
       
   230         }
       
   231         algId.encode(scratch);     // sig algorithm
       
   232         scratch.putBitString(sig);                      // sig
       
   233 
       
   234         /*
       
   235          * Wrap those guts in a sequence
       
   236          */
       
   237         out = new DerOutputStream();
       
   238         out.write(DerValue.tag_Sequence, scratch);
       
   239         encoded = out.toByteArray();
       
   240     }
       
   241 
       
   242     /**
       
   243      * Returns the subject's name.
       
   244      */
       
   245     public X500Name getSubjectName() { return subject; }
       
   246 
       
   247     /**
       
   248      * Returns the subject's public key.
       
   249      */
       
   250     public PublicKey getSubjectPublicKeyInfo()
       
   251         { return subjectPublicKeyInfo; }
       
   252 
       
   253     /**
       
   254      * Returns the additional attributes requested.
       
   255      */
       
   256     public PKCS10Attributes getAttributes()
       
   257         { return attributeSet; }
       
   258 
       
   259     /**
       
   260      * Returns the encoded and signed certificate request as a
       
   261      * DER-encoded byte array.
       
   262      *
       
   263      * @return the certificate request, or null if encodeAndSign()
       
   264      *          has not yet been called.
       
   265      */
       
   266     public byte[] getEncoded() {
       
   267         if (encoded != null)
       
   268             return encoded.clone();
       
   269         else
       
   270             return null;
       
   271     }
       
   272 
       
   273     /**
       
   274      * Prints an E-Mailable version of the certificate request on the print
       
   275      * stream passed.  The format is a common base64 encoded one, supported
       
   276      * by most Certificate Authorities because Netscape web servers have
       
   277      * used this for some time.  Some certificate authorities expect some
       
   278      * more information, in particular contact information for the web
       
   279      * server administrator.
       
   280      *
       
   281      * @param out the print stream where the certificate request
       
   282      *  will be printed.
       
   283      * @exception IOException when an output operation failed
       
   284      * @exception SignatureException when the certificate request was
       
   285      *  not yet signed.
       
   286      */
       
   287     public void print(PrintStream out)
       
   288     throws IOException, SignatureException {
       
   289         if (encoded == null)
       
   290             throw new SignatureException("Cert request was not signed");
       
   291 
       
   292         BASE64Encoder   encoder = new BASE64Encoder();
       
   293 
       
   294         out.println("-----BEGIN NEW CERTIFICATE REQUEST-----");
       
   295         encoder.encodeBuffer(encoded, out);
       
   296         out.println("-----END NEW CERTIFICATE REQUEST-----");
       
   297     }
       
   298 
       
   299     /**
       
   300      * Provides a short description of this request.
       
   301      */
       
   302     public String toString() {
       
   303         return "[PKCS #10 certificate request:\n"
       
   304             + subjectPublicKeyInfo.toString()
       
   305             + " subject: <" + subject + ">" + "\n"
       
   306             + " attributes: " + attributeSet.toString()
       
   307             + "\n]";
       
   308     }
       
   309 
       
   310     /**
       
   311      * Compares this object for equality with the specified
       
   312      * object. If the <code>other</code> object is an
       
   313      * <code>instanceof</code> <code>PKCS10</code>, then
       
   314      * its encoded form is retrieved and compared with the
       
   315      * encoded form of this certificate request.
       
   316      *
       
   317      * @param other the object to test for equality with this object.
       
   318      * @return true iff the encoded forms of the two certificate
       
   319      * requests match, false otherwise.
       
   320      */
       
   321     public boolean equals(Object other) {
       
   322         if (this == other)
       
   323             return true;
       
   324         if (!(other instanceof PKCS10))
       
   325             return false;
       
   326         if (encoded == null) // not signed yet
       
   327             return false;
       
   328         byte[] otherEncoded = ((PKCS10)other).getEncoded();
       
   329         if (otherEncoded == null)
       
   330             return false;
       
   331 
       
   332         return java.util.Arrays.equals(encoded, otherEncoded);
       
   333     }
       
   334 
       
   335     /**
       
   336      * Returns a hashcode value for this certificate request from its
       
   337      * encoded form.
       
   338      *
       
   339      * @return the hashcode value.
       
   340      */
       
   341     public int hashCode() {
       
   342         int     retval = 0;
       
   343         if (encoded != null)
       
   344             for (int i = 1; i < encoded.length; i++)
       
   345              retval += encoded[i] * i;
       
   346         return(retval);
       
   347     }
       
   348 
       
   349     private X500Name            subject;
       
   350     private PublicKey           subjectPublicKeyInfo;
       
   351     private PKCS10Attributes    attributeSet;
       
   352     private byte[]              encoded;        // signed
       
   353 }