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