0N/A/*
2362N/A * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/Apackage sun.security.pkcs;
0N/A
0N/Aimport java.io.ByteArrayOutputStream;
0N/Aimport java.io.PrintStream;
0N/Aimport java.io.IOException;
0N/Aimport java.math.BigInteger;
0N/A
0N/Aimport java.security.cert.CertificateException;
0N/Aimport java.security.NoSuchAlgorithmException;
0N/Aimport java.security.InvalidKeyException;
0N/Aimport java.security.Signature;
0N/Aimport java.security.SignatureException;
0N/Aimport java.security.PublicKey;
0N/A
0N/Aimport sun.misc.BASE64Encoder;
0N/A
0N/Aimport sun.security.util.*;
0N/Aimport sun.security.x509.AlgorithmId;
0N/Aimport sun.security.x509.X509Key;
0N/Aimport sun.security.x509.X500Name;
0N/A
0N/A/**
0N/A * A PKCS #10 certificate request is created and sent to a Certificate
0N/A * Authority, which then creates an X.509 certificate and returns it to
0N/A * the entity that requested it. A certificate request basically consists
0N/A * of the subject's X.500 name, public key, and optionally some attributes,
0N/A * signed using the corresponding private key.
0N/A *
0N/A * The ASN.1 syntax for a Certification Request is:
0N/A * <pre>
0N/A * CertificationRequest ::= SEQUENCE {
0N/A * certificationRequestInfo CertificationRequestInfo,
0N/A * signatureAlgorithm SignatureAlgorithmIdentifier,
0N/A * signature Signature
0N/A * }
0N/A *
0N/A * SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
0N/A * Signature ::= BIT STRING
0N/A *
0N/A * CertificationRequestInfo ::= SEQUENCE {
0N/A * version Version,
0N/A * subject Name,
0N/A * subjectPublicKeyInfo SubjectPublicKeyInfo,
0N/A * attributes [0] IMPLICIT Attributes
0N/A * }
0N/A * Attributes ::= SET OF Attribute
0N/A * </pre>
0N/A *
0N/A * @author David Brownell
0N/A * @author Amit Kapoor
0N/A * @author Hemma Prafullchandra
0N/A */
0N/Apublic class PKCS10 {
0N/A /**
0N/A * Constructs an unsigned PKCS #10 certificate request. Before this
0N/A * request may be used, it must be encoded and signed. Then it
0N/A * must be retrieved in some conventional format (e.g. string).
0N/A *
0N/A * @param publicKey the public key that should be placed
0N/A * into the certificate generated by the CA.
0N/A */
0N/A public PKCS10(PublicKey publicKey) {
0N/A subjectPublicKeyInfo = publicKey;
0N/A attributeSet = new PKCS10Attributes();
0N/A }
0N/A
0N/A /**
0N/A * Constructs an unsigned PKCS #10 certificate request. Before this
0N/A * request may be used, it must be encoded and signed. Then it
0N/A * must be retrieved in some conventional format (e.g. string).
0N/A *
0N/A * @param publicKey the public key that should be placed
0N/A * into the certificate generated by the CA.
0N/A * @param attributes additonal set of PKCS10 attributes requested
0N/A * for in the certificate.
0N/A */
0N/A public PKCS10(PublicKey publicKey, PKCS10Attributes attributes) {
0N/A subjectPublicKeyInfo = publicKey;
0N/A attributeSet = attributes;
0N/A }
0N/A
0N/A /**
0N/A * Parses an encoded, signed PKCS #10 certificate request, verifying
0N/A * the request's signature as it does so. This constructor would
0N/A * typically be used by a Certificate Authority, from which a new
0N/A * certificate would then be constructed.
0N/A *
0N/A * @param data the DER-encoded PKCS #10 request.
0N/A * @exception IOException for low level errors reading the data
0N/A * @exception SignatureException when the signature is invalid
0N/A * @exception NoSuchAlgorithmException when the signature
0N/A * algorithm is not supported in this environment
0N/A */
0N/A public PKCS10(byte[] data)
0N/A throws IOException, SignatureException, NoSuchAlgorithmException {
0N/A DerInputStream in;
0N/A DerValue[] seq;
0N/A AlgorithmId id;
0N/A byte[] sigData;
0N/A Signature sig;
0N/A
0N/A encoded = data;
0N/A
0N/A //
0N/A // Outer sequence: request, signature algorithm, signature.
0N/A // Parse, and prepare to verify later.
0N/A //
0N/A in = new DerInputStream(data);
0N/A seq = in.getSequence(3);
0N/A
0N/A if (seq.length != 3)
0N/A throw new IllegalArgumentException("not a PKCS #10 request");
0N/A
0N/A data = seq[0].toByteArray(); // reusing this variable
0N/A id = AlgorithmId.parse(seq[1]);
0N/A sigData = seq[2].getBitString();
0N/A
0N/A //
0N/A // Inner sequence: version, name, key, attributes
0N/A //
0N/A BigInteger serial;
0N/A DerValue val;
0N/A
0N/A serial = seq[0].data.getBigInteger();
0N/A if (!serial.equals(BigInteger.ZERO))
0N/A throw new IllegalArgumentException("not PKCS #10 v1");
0N/A
0N/A subject = new X500Name(seq[0].data);
0N/A subjectPublicKeyInfo = X509Key.parse(seq[0].data.getDerValue());
0N/A
0N/A // Cope with a somewhat common illegal PKCS #10 format
0N/A if (seq[0].data.available() != 0)
0N/A attributeSet = new PKCS10Attributes(seq[0].data);
0N/A else
0N/A attributeSet = new PKCS10Attributes();
0N/A
0N/A if (seq[0].data.available() != 0)
0N/A throw new IllegalArgumentException("illegal PKCS #10 data");
0N/A
0N/A //
0N/A // OK, we parsed it all ... validate the signature using the
0N/A // key and signature algorithm we found.
0N/A //
0N/A try {
0N/A sig = Signature.getInstance(id.getName());
0N/A sig.initVerify(subjectPublicKeyInfo);
0N/A sig.update(data);
0N/A if (!sig.verify(sigData))
0N/A throw new SignatureException("Invalid PKCS #10 signature");
0N/A } catch (InvalidKeyException e) {
0N/A throw new SignatureException("invalid key");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Create the signed certificate request. This will later be
0N/A * retrieved in either string or binary format.
0N/A *
1955N/A * @param subject identifies the signer (by X.500 name).
1955N/A * @param signature private key and signing algorithm to use.
0N/A * @exception IOException on errors.
0N/A * @exception CertificateException on certificate handling errors.
0N/A * @exception SignatureException on signature handling errors.
0N/A */
1955N/A public void encodeAndSign(X500Name subject, Signature signature)
0N/A throws CertificateException, IOException, SignatureException {
0N/A DerOutputStream out, scratch;
0N/A byte[] certificateRequestInfo;
0N/A byte[] sig;
0N/A
0N/A if (encoded != null)
0N/A throw new SignatureException("request is already signed");
0N/A
1955N/A this.subject = subject;
0N/A
0N/A /*
0N/A * Encode cert request info, wrap in a sequence for signing
0N/A */
0N/A scratch = new DerOutputStream();
0N/A scratch.putInteger(BigInteger.ZERO); // PKCS #10 v1.0
0N/A subject.encode(scratch); // X.500 name
0N/A scratch.write(subjectPublicKeyInfo.getEncoded()); // public key
0N/A attributeSet.encode(scratch);
0N/A
0N/A out = new DerOutputStream();
0N/A out.write(DerValue.tag_Sequence, scratch); // wrap it!
0N/A certificateRequestInfo = out.toByteArray();
0N/A scratch = out;
0N/A
0N/A /*
0N/A * Sign it ...
0N/A */
1955N/A signature.update(certificateRequestInfo, 0,
0N/A certificateRequestInfo.length);
1955N/A sig = signature.sign();
0N/A
0N/A /*
0N/A * Build guts of SIGNED macro
0N/A */
1955N/A AlgorithmId algId = null;
1955N/A try {
1955N/A algId = AlgorithmId.getAlgorithmId(signature.getAlgorithm());
1955N/A } catch (NoSuchAlgorithmException nsae) {
1955N/A throw new SignatureException(nsae);
1955N/A }
1955N/A algId.encode(scratch); // sig algorithm
0N/A scratch.putBitString(sig); // sig
0N/A
0N/A /*
0N/A * Wrap those guts in a sequence
0N/A */
0N/A out = new DerOutputStream();
0N/A out.write(DerValue.tag_Sequence, scratch);
0N/A encoded = out.toByteArray();
0N/A }
0N/A
0N/A /**
0N/A * Returns the subject's name.
0N/A */
0N/A public X500Name getSubjectName() { return subject; }
0N/A
0N/A /**
0N/A * Returns the subject's public key.
0N/A */
0N/A public PublicKey getSubjectPublicKeyInfo()
0N/A { return subjectPublicKeyInfo; }
0N/A
0N/A /**
0N/A * Returns the additional attributes requested.
0N/A */
0N/A public PKCS10Attributes getAttributes()
0N/A { return attributeSet; }
0N/A
0N/A /**
0N/A * Returns the encoded and signed certificate request as a
0N/A * DER-encoded byte array.
0N/A *
0N/A * @return the certificate request, or null if encodeAndSign()
0N/A * has not yet been called.
0N/A */
0N/A public byte[] getEncoded() {
0N/A if (encoded != null)
0N/A return encoded.clone();
0N/A else
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Prints an E-Mailable version of the certificate request on the print
0N/A * stream passed. The format is a common base64 encoded one, supported
0N/A * by most Certificate Authorities because Netscape web servers have
0N/A * used this for some time. Some certificate authorities expect some
0N/A * more information, in particular contact information for the web
0N/A * server administrator.
0N/A *
0N/A * @param out the print stream where the certificate request
0N/A * will be printed.
0N/A * @exception IOException when an output operation failed
0N/A * @exception SignatureException when the certificate request was
0N/A * not yet signed.
0N/A */
0N/A public void print(PrintStream out)
0N/A throws IOException, SignatureException {
0N/A if (encoded == null)
0N/A throw new SignatureException("Cert request was not signed");
0N/A
0N/A BASE64Encoder encoder = new BASE64Encoder();
0N/A
0N/A out.println("-----BEGIN NEW CERTIFICATE REQUEST-----");
0N/A encoder.encodeBuffer(encoded, out);
0N/A out.println("-----END NEW CERTIFICATE REQUEST-----");
0N/A }
0N/A
0N/A /**
0N/A * Provides a short description of this request.
0N/A */
0N/A public String toString() {
0N/A return "[PKCS #10 certificate request:\n"
0N/A + subjectPublicKeyInfo.toString()
0N/A + " subject: <" + subject + ">" + "\n"
0N/A + " attributes: " + attributeSet.toString()
0N/A + "\n]";
0N/A }
0N/A
0N/A /**
0N/A * Compares this object for equality with the specified
0N/A * object. If the <code>other</code> object is an
0N/A * <code>instanceof</code> <code>PKCS10</code>, then
0N/A * its encoded form is retrieved and compared with the
0N/A * encoded form of this certificate request.
0N/A *
0N/A * @param other the object to test for equality with this object.
0N/A * @return true iff the encoded forms of the two certificate
0N/A * requests match, false otherwise.
0N/A */
0N/A public boolean equals(Object other) {
0N/A if (this == other)
0N/A return true;
0N/A if (!(other instanceof PKCS10))
0N/A return false;
0N/A if (encoded == null) // not signed yet
0N/A return false;
0N/A byte[] otherEncoded = ((PKCS10)other).getEncoded();
0N/A if (otherEncoded == null)
0N/A return false;
0N/A
0N/A return java.util.Arrays.equals(encoded, otherEncoded);
0N/A }
0N/A
0N/A /**
0N/A * Returns a hashcode value for this certificate request from its
0N/A * encoded form.
0N/A *
0N/A * @return the hashcode value.
0N/A */
0N/A public int hashCode() {
0N/A int retval = 0;
0N/A if (encoded != null)
0N/A for (int i = 1; i < encoded.length; i++)
0N/A retval += encoded[i] * i;
0N/A return(retval);
0N/A }
0N/A
0N/A private X500Name subject;
0N/A private PublicKey subjectPublicKeyInfo;
0N/A private PKCS10Attributes attributeSet;
0N/A private byte[] encoded; // signed
0N/A}