/*
 * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package sun.security.pkcs10;

import java.io.PrintStream;
import java.io.IOException;
import java.math.BigInteger;

import java.security.*;

import java.util.Base64;

import sun.security.util.*;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X509Key;
import sun.security.x509.X500Name;
import sun.security.util.SignatureUtil;


A PKCS #10 certificate request is created and sent to a Certificate Authority, which then creates an X.509 certificate and returns it to the entity that requested it. A certificate request basically consists of the subject's X.500 name, public key, and optionally some attributes, signed using the corresponding private key. The ASN.1 syntax for a Certification Request is:
CertificationRequest ::= SEQUENCE {
   certificationRequestInfo CertificationRequestInfo,
   signatureAlgorithm       SignatureAlgorithmIdentifier,
   signature                Signature
 }
SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
Signature ::= BIT STRING
CertificationRequestInfo ::= SEQUENCE {
   version                 Version,
   subject                 Name,
   subjectPublicKeyInfo    SubjectPublicKeyInfo,
   attributes [0] IMPLICIT Attributes
}
Attributes ::= SET OF Attribute
Author:David Brownell, Amit Kapoor, Hemma Prafullchandra
/** * A PKCS #10 certificate request is created and sent to a Certificate * Authority, which then creates an X.509 certificate and returns it to * the entity that requested it. A certificate request basically consists * of the subject's X.500 name, public key, and optionally some attributes, * signed using the corresponding private key. * * The ASN.1 syntax for a Certification Request is: * <pre> * CertificationRequest ::= SEQUENCE { * certificationRequestInfo CertificationRequestInfo, * signatureAlgorithm SignatureAlgorithmIdentifier, * signature Signature * } * * SignatureAlgorithmIdentifier ::= AlgorithmIdentifier * Signature ::= BIT STRING * * CertificationRequestInfo ::= SEQUENCE { * version Version, * subject Name, * subjectPublicKeyInfo SubjectPublicKeyInfo, * attributes [0] IMPLICIT Attributes * } * Attributes ::= SET OF Attribute * </pre> * * @author David Brownell * @author Amit Kapoor * @author Hemma Prafullchandra */
public class PKCS10 {
Constructs an unsigned PKCS #10 certificate request. Before this request may be used, it must be encoded and signed. Then it must be retrieved in some conventional format (e.g. string).
Params:
  • publicKey – the public key that should be placed into the certificate generated by the CA.
/** * Constructs an unsigned PKCS #10 certificate request. Before this * request may be used, it must be encoded and signed. Then it * must be retrieved in some conventional format (e.g. string). * * @param publicKey the public key that should be placed * into the certificate generated by the CA. */
public PKCS10(PublicKey publicKey) { subjectPublicKeyInfo = publicKey; attributeSet = new PKCS10Attributes(); }
Constructs an unsigned PKCS #10 certificate request. Before this request may be used, it must be encoded and signed. Then it must be retrieved in some conventional format (e.g. string).
Params:
  • publicKey – the public key that should be placed into the certificate generated by the CA.
  • attributes – additonal set of PKCS10 attributes requested for in the certificate.
/** * Constructs an unsigned PKCS #10 certificate request. Before this * request may be used, it must be encoded and signed. Then it * must be retrieved in some conventional format (e.g. string). * * @param publicKey the public key that should be placed * into the certificate generated by the CA. * @param attributes additonal set of PKCS10 attributes requested * for in the certificate. */
public PKCS10(PublicKey publicKey, PKCS10Attributes attributes) { subjectPublicKeyInfo = publicKey; attributeSet = attributes; }
Parses an encoded, signed PKCS #10 certificate request, verifying the request's signature as it does so. This constructor would typically be used by a Certificate Authority, from which a new certificate would then be constructed.
Params:
  • data – the DER-encoded PKCS #10 request.
Throws:
/** * Parses an encoded, signed PKCS #10 certificate request, verifying * the request's signature as it does so. This constructor would * typically be used by a Certificate Authority, from which a new * certificate would then be constructed. * * @param data the DER-encoded PKCS #10 request. * @exception IOException for low level errors reading the data * @exception SignatureException when the signature is invalid * @exception NoSuchAlgorithmException when the signature * algorithm is not supported in this environment */
public PKCS10(byte[] data) throws IOException, SignatureException, NoSuchAlgorithmException { DerInputStream in; DerValue[] seq; AlgorithmId id; byte[] sigData; Signature sig; encoded = data; // // Outer sequence: request, signature algorithm, signature. // Parse, and prepare to verify later. // in = new DerInputStream(data); seq = in.getSequence(3); if (seq.length != 3) throw new IllegalArgumentException("not a PKCS #10 request"); data = seq[0].toByteArray(); // reusing this variable id = AlgorithmId.parse(seq[1]); sigData = seq[2].getBitString(); // // Inner sequence: version, name, key, attributes // BigInteger serial; DerValue val; serial = seq[0].data.getBigInteger(); if (!serial.equals(BigInteger.ZERO)) throw new IllegalArgumentException("not PKCS #10 v1"); subject = new X500Name(seq[0].data); subjectPublicKeyInfo = X509Key.parse(seq[0].data.getDerValue()); // Cope with a somewhat common illegal PKCS #10 format if (seq[0].data.available() != 0) attributeSet = new PKCS10Attributes(seq[0].data); else attributeSet = new PKCS10Attributes(); if (seq[0].data.available() != 0) throw new IllegalArgumentException("illegal PKCS #10 data"); // // OK, we parsed it all ... validate the signature using the // key and signature algorithm we found. // try { sigAlg = id.getName(); sig = Signature.getInstance(sigAlg); SignatureUtil.initVerifyWithParam(sig, subjectPublicKeyInfo, SignatureUtil.getParamSpec(sigAlg, id.getParameters())); sig.update(data); if (!sig.verify(sigData)) { throw new SignatureException("Invalid PKCS #10 signature"); } } catch (InvalidKeyException e) { throw new SignatureException("Invalid key"); } catch (InvalidAlgorithmParameterException e) { throw new SignatureException("Invalid signature parameters", e); } catch (ProviderException e) { throw new SignatureException("Error parsing signature parameters", e.getCause()); } }
Create the signed certificate request. This will later be retrieved in either string or binary format.
Params:
  • subject – identifies the signer (by X.500 name).
  • key – private key to use.
  • algorithm – signing algorithm to use.
Throws:
/** * Create the signed certificate request. This will later be * retrieved in either string or binary format. * * @param subject identifies the signer (by X.500 name). * @param key private key to use. * @param algorithm signing algorithm to use. * @exception IOException on errors. * @exception SignatureException on signature handling errors. * @exception NoSuchAlgorithmException algorithm is not recognized * @exception InvalidKeyException key has a problem */
public void encodeAndSign(X500Name subject, PrivateKey key, String algorithm) throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException { DerOutputStream out, scratch; byte[] certificateRequestInfo; byte[] sig; if (encoded != null) { throw new SignatureException("request is already signed"); } Signature signature = SignatureUtil.fromKey( algorithm, key, (Provider)null); this.subject = subject; /* * Encode cert request info, wrap in a sequence for signing */ scratch = new DerOutputStream(); scratch.putInteger(BigInteger.ZERO); // PKCS #10 v1.0 subject.encode(scratch); // X.500 name scratch.write(subjectPublicKeyInfo.getEncoded()); // public key attributeSet.encode(scratch); out = new DerOutputStream(); out.write(DerValue.tag_Sequence, scratch); // wrap it! certificateRequestInfo = out.toByteArray(); scratch = out; /* * Sign it ... */ signature.update(certificateRequestInfo, 0, certificateRequestInfo.length); sig = signature.sign(); sigAlg = signature.getAlgorithm(); /* * Build guts of SIGNED macro */ AlgorithmId algId = SignatureUtil.fromSignature(signature, key); algId.encode(scratch); // sig algorithm scratch.putBitString(sig); // sig /* * Wrap those guts in a sequence */ out = new DerOutputStream(); out.write(DerValue.tag_Sequence, scratch); encoded = out.toByteArray(); }
Returns the subject's name.
/** * Returns the subject's name. */
public X500Name getSubjectName() { return subject; }
Returns the subject's public key.
/** * Returns the subject's public key. */
public PublicKey getSubjectPublicKeyInfo() { return subjectPublicKeyInfo; }
Returns the signature algorithm.
/** * Returns the signature algorithm. */
public String getSigAlg() { return sigAlg; }
Returns the additional attributes requested.
/** * Returns the additional attributes requested. */
public PKCS10Attributes getAttributes() { return attributeSet; }
Returns the encoded and signed certificate request as a DER-encoded byte array.
Returns:the certificate request, or null if encodeAndSign() has not yet been called.
/** * Returns the encoded and signed certificate request as a * DER-encoded byte array. * * @return the certificate request, or null if encodeAndSign() * has not yet been called. */
public byte[] getEncoded() { if (encoded != null) return encoded.clone(); else return null; }
Prints an E-Mailable version of the certificate request on the print stream passed. The format is a common base64 encoded one, supported by most Certificate Authorities because Netscape web servers have used this for some time. Some certificate authorities expect some more information, in particular contact information for the web server administrator.
Params:
  • out – the print stream where the certificate request will be printed.
Throws:
/** * Prints an E-Mailable version of the certificate request on the print * stream passed. The format is a common base64 encoded one, supported * by most Certificate Authorities because Netscape web servers have * used this for some time. Some certificate authorities expect some * more information, in particular contact information for the web * server administrator. * * @param out the print stream where the certificate request * will be printed. * @exception IOException when an output operation failed * @exception SignatureException when the certificate request was * not yet signed. */
public void print(PrintStream out) throws IOException, SignatureException { if (encoded == null) throw new SignatureException("Cert request was not signed"); byte[] CRLF = new byte[] {'\r', '\n'}; out.println("-----BEGIN NEW CERTIFICATE REQUEST-----"); out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(encoded)); out.println("-----END NEW CERTIFICATE REQUEST-----"); }
Provides a short description of this request.
/** * Provides a short description of this request. */
public String toString() { return "[PKCS #10 certificate request:\n" + subjectPublicKeyInfo.toString() + " subject: <" + subject + ">" + "\n" + " attributes: " + attributeSet.toString() + "\n]"; }
Compares this object for equality with the specified object. If the other object is an instanceof PKCS10, then its encoded form is retrieved and compared with the encoded form of this certificate request.
Params:
  • other – the object to test for equality with this object.
Returns:true iff the encoded forms of the two certificate requests match, false otherwise.
/** * Compares this object for equality with the specified * object. If the <code>other</code> object is an * <code>instanceof</code> <code>PKCS10</code>, then * its encoded form is retrieved and compared with the * encoded form of this certificate request. * * @param other the object to test for equality with this object. * @return true iff the encoded forms of the two certificate * requests match, false otherwise. */
public boolean equals(Object other) { if (this == other) return true; if (!(other instanceof PKCS10)) return false; if (encoded == null) // not signed yet return false; byte[] otherEncoded = ((PKCS10)other).getEncoded(); if (otherEncoded == null) return false; return java.util.Arrays.equals(encoded, otherEncoded); }
Returns a hashcode value for this certificate request from its encoded form.
Returns:the hashcode value.
/** * Returns a hashcode value for this certificate request from its * encoded form. * * @return the hashcode value. */
public int hashCode() { int retval = 0; if (encoded != null) for (int i = 1; i < encoded.length; i++) retval += encoded[i] * i; return(retval); } private X500Name subject; private PublicKey subjectPublicKeyInfo; private String sigAlg; private PKCS10Attributes attributeSet; private byte[] encoded; // signed }