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