Path: blob/master/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java
41159 views
/*1* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526package sun.security.pkcs10;2728import java.io.PrintStream;29import java.io.IOException;30import java.math.BigInteger;3132import java.security.*;3334import java.util.Base64;3536import sun.security.util.*;37import sun.security.x509.AlgorithmId;38import sun.security.x509.X509Key;39import sun.security.x509.X500Name;40import sun.security.util.SignatureUtil;414243/**44* A PKCS #10 certificate request is created and sent to a Certificate45* Authority, which then creates an X.509 certificate and returns it to46* the entity that requested it. A certificate request basically consists47* of the subject's X.500 name, public key, and optionally some attributes,48* signed using the corresponding private key.49*50* The ASN.1 syntax for a Certification Request is:51* <pre>52* CertificationRequest ::= SEQUENCE {53* certificationRequestInfo CertificationRequestInfo,54* signatureAlgorithm SignatureAlgorithmIdentifier,55* signature Signature56* }57*58* SignatureAlgorithmIdentifier ::= AlgorithmIdentifier59* Signature ::= BIT STRING60*61* CertificationRequestInfo ::= SEQUENCE {62* version Version,63* subject Name,64* subjectPublicKeyInfo SubjectPublicKeyInfo,65* attributes [0] IMPLICIT Attributes66* }67* Attributes ::= SET OF Attribute68* </pre>69*70* @author David Brownell71* @author Amit Kapoor72* @author Hemma Prafullchandra73*/74public class PKCS10 {75/**76* Constructs an unsigned PKCS #10 certificate request. Before this77* request may be used, it must be encoded and signed. Then it78* must be retrieved in some conventional format (e.g. string).79*80* @param publicKey the public key that should be placed81* into the certificate generated by the CA.82*/83public PKCS10(PublicKey publicKey) {84subjectPublicKeyInfo = publicKey;85attributeSet = new PKCS10Attributes();86}8788/**89* Constructs an unsigned PKCS #10 certificate request. Before this90* request may be used, it must be encoded and signed. Then it91* must be retrieved in some conventional format (e.g. string).92*93* @param publicKey the public key that should be placed94* into the certificate generated by the CA.95* @param attributes additonal set of PKCS10 attributes requested96* for in the certificate.97*/98public PKCS10(PublicKey publicKey, PKCS10Attributes attributes) {99subjectPublicKeyInfo = publicKey;100attributeSet = attributes;101}102103/**104* Parses an encoded, signed PKCS #10 certificate request, verifying105* the request's signature as it does so. This constructor would106* typically be used by a Certificate Authority, from which a new107* certificate would then be constructed.108*109* @param data the DER-encoded PKCS #10 request.110* @exception IOException for low level errors reading the data111* @exception SignatureException when the signature is invalid112* @exception NoSuchAlgorithmException when the signature113* algorithm is not supported in this environment114*/115public PKCS10(byte[] data)116throws IOException, SignatureException, NoSuchAlgorithmException {117DerInputStream in;118DerValue[] seq;119AlgorithmId id;120byte[] sigData;121Signature sig;122123encoded = data;124125//126// Outer sequence: request, signature algorithm, signature.127// Parse, and prepare to verify later.128//129in = new DerInputStream(data);130seq = in.getSequence(3);131132if (seq.length != 3)133throw new IllegalArgumentException("not a PKCS #10 request");134135data = seq[0].toByteArray(); // reusing this variable136id = AlgorithmId.parse(seq[1]);137sigData = seq[2].getBitString();138139//140// Inner sequence: version, name, key, attributes141//142BigInteger serial;143DerValue val;144145serial = seq[0].data.getBigInteger();146if (!serial.equals(BigInteger.ZERO))147throw new IllegalArgumentException("not PKCS #10 v1");148149subject = new X500Name(seq[0].data);150subjectPublicKeyInfo = X509Key.parse(seq[0].data.getDerValue());151152// Cope with a somewhat common illegal PKCS #10 format153if (seq[0].data.available() != 0)154attributeSet = new PKCS10Attributes(seq[0].data);155else156attributeSet = new PKCS10Attributes();157158if (seq[0].data.available() != 0)159throw new IllegalArgumentException("illegal PKCS #10 data");160161//162// OK, we parsed it all ... validate the signature using the163// key and signature algorithm we found.164//165try {166sigAlg = id.getName();167sig = Signature.getInstance(sigAlg);168SignatureUtil.initVerifyWithParam(sig, subjectPublicKeyInfo,169SignatureUtil.getParamSpec(sigAlg, id.getParameters()));170171sig.update(data);172if (!sig.verify(sigData)) {173throw new SignatureException("Invalid PKCS #10 signature");174}175} catch (InvalidKeyException e) {176throw new SignatureException("Invalid key");177} catch (InvalidAlgorithmParameterException e) {178throw new SignatureException("Invalid signature parameters", e);179} catch (ProviderException e) {180throw new SignatureException("Error parsing signature parameters",181e.getCause());182}183}184185/**186* Create the signed certificate request. This will later be187* retrieved in either string or binary format.188*189* @param subject identifies the signer (by X.500 name).190* @param key private key to use.191* @param algorithm signing algorithm to use.192* @exception IOException on errors.193* @exception SignatureException on signature handling errors.194* @exception NoSuchAlgorithmException algorithm is not recognized195* @exception InvalidKeyException key has a problem196*/197public void encodeAndSign(X500Name subject, PrivateKey key, String algorithm)198throws IOException, SignatureException,199NoSuchAlgorithmException, InvalidKeyException {200201DerOutputStream out, scratch;202byte[] certificateRequestInfo;203byte[] sig;204205if (encoded != null) {206throw new SignatureException("request is already signed");207}208209Signature signature = SignatureUtil.fromKey(210algorithm, key, (Provider)null);211212this.subject = subject;213214/*215* Encode cert request info, wrap in a sequence for signing216*/217scratch = new DerOutputStream();218scratch.putInteger(BigInteger.ZERO); // PKCS #10 v1.0219subject.encode(scratch); // X.500 name220scratch.write(subjectPublicKeyInfo.getEncoded()); // public key221attributeSet.encode(scratch);222223out = new DerOutputStream();224out.write(DerValue.tag_Sequence, scratch); // wrap it!225certificateRequestInfo = out.toByteArray();226scratch = out;227228/*229* Sign it ...230*/231signature.update(certificateRequestInfo, 0,232certificateRequestInfo.length);233sig = signature.sign();234sigAlg = signature.getAlgorithm();235236/*237* Build guts of SIGNED macro238*/239AlgorithmId algId = SignatureUtil.fromSignature(signature, key);240241algId.encode(scratch); // sig algorithm242scratch.putBitString(sig); // sig243244/*245* Wrap those guts in a sequence246*/247out = new DerOutputStream();248out.write(DerValue.tag_Sequence, scratch);249encoded = out.toByteArray();250}251252/**253* Returns the subject's name.254*/255public X500Name getSubjectName() { return subject; }256257/**258* Returns the subject's public key.259*/260public PublicKey getSubjectPublicKeyInfo()261{ return subjectPublicKeyInfo; }262263/**264* Returns the signature algorithm.265*/266public String getSigAlg() { return sigAlg; }267268/**269* Returns the additional attributes requested.270*/271public PKCS10Attributes getAttributes()272{ return attributeSet; }273274/**275* Returns the encoded and signed certificate request as a276* DER-encoded byte array.277*278* @return the certificate request, or null if encodeAndSign()279* has not yet been called.280*/281public byte[] getEncoded() {282if (encoded != null)283return encoded.clone();284else285return null;286}287288/**289* Prints an E-Mailable version of the certificate request on the print290* stream passed. The format is a common base64 encoded one, supported291* by most Certificate Authorities because Netscape web servers have292* used this for some time. Some certificate authorities expect some293* more information, in particular contact information for the web294* server administrator.295*296* @param out the print stream where the certificate request297* will be printed.298* @exception IOException when an output operation failed299* @exception SignatureException when the certificate request was300* not yet signed.301*/302public void print(PrintStream out)303throws IOException, SignatureException {304if (encoded == null)305throw new SignatureException("Cert request was not signed");306307308byte[] CRLF = new byte[] {'\r', '\n'};309out.println("-----BEGIN NEW CERTIFICATE REQUEST-----");310out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(encoded));311out.println("-----END NEW CERTIFICATE REQUEST-----");312}313314/**315* Provides a short description of this request.316*/317public String toString() {318return "[PKCS #10 certificate request:\n"319+ subjectPublicKeyInfo.toString()320+ " subject: <" + subject + ">" + "\n"321+ " attributes: " + attributeSet.toString()322+ "\n]";323}324325/**326* Compares this object for equality with the specified327* object. If the <code>other</code> object is an328* <code>instanceof</code> <code>PKCS10</code>, then329* its encoded form is retrieved and compared with the330* encoded form of this certificate request.331*332* @param other the object to test for equality with this object.333* @return true iff the encoded forms of the two certificate334* requests match, false otherwise.335*/336public boolean equals(Object other) {337if (this == other)338return true;339if (!(other instanceof PKCS10))340return false;341if (encoded == null) // not signed yet342return false;343byte[] otherEncoded = ((PKCS10)other).getEncoded();344if (otherEncoded == null)345return false;346347return java.util.Arrays.equals(encoded, otherEncoded);348}349350/**351* Returns a hashcode value for this certificate request from its352* encoded form.353*354* @return the hashcode value.355*/356public int hashCode() {357int retval = 0;358if (encoded != null)359for (int i = 1; i < encoded.length; i++)360retval += encoded[i] * i;361return(retval);362}363364private X500Name subject;365private PublicKey subjectPublicKeyInfo;366private String sigAlg;367private PKCS10Attributes attributeSet;368private byte[] encoded; // signed369}370371372