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 171 sig.initVerify(subjectPublicKeyInfo); 172 173 // set parameters after Signature.initSign/initVerify call, 174 // so the deferred provider selections occur when key is set 175 SignatureUtil.specialSetParameter(sig, id.getParameters()); 176 177 sig.update(data); 178 if (!sig.verify(sigData)) { 179 throw new SignatureException("Invalid PKCS #10 signature"); 180 } 181 } catch (InvalidKeyException e) { 182 throw new SignatureException("Invalid key"); 183 } catch (InvalidAlgorithmParameterException e) { 184 throw new SignatureException("Invalid signature parameters", e); 185 } catch (ProviderException e) { 186 throw new SignatureException("Error parsing signature parameters", 187 e.getCause()); 188 } 189 } 190 191 /** 192 * Create the signed certificate request. This will later be 193 * retrieved in either string or binary format. 194 * 195 * @param subject identifies the signer (by X.500 name). 196 * @param signature private key and signing algorithm to use. 197 * @exception IOException on errors. 198 * @exception CertificateException on certificate handling errors. 199 * @exception SignatureException on signature handling errors. 200 */ 201 public void encodeAndSign(X500Name subject, Signature signature) 202 throws CertificateException, IOException, SignatureException { 203 DerOutputStream out, scratch; 204 byte[] certificateRequestInfo; 205 byte[] sig; 206 207 if (encoded != null) 208 throw new SignatureException("request is already signed"); 209 210 this.subject = subject; 211 212 /* 213 * Encode cert request info, wrap in a sequence for signing 214 */ 215 scratch = new DerOutputStream(); 216 scratch.putInteger(BigInteger.ZERO); // PKCS #10 v1.0 217 subject.encode(scratch); // X.500 name 218 scratch.write(subjectPublicKeyInfo.getEncoded()); // public key 219 attributeSet.encode(scratch); 220 221 out = new DerOutputStream(); 222 out.write(DerValue.tag_Sequence, scratch); // wrap it! 223 certificateRequestInfo = out.toByteArray(); 224 scratch = out; 225 226 /* 227 * Sign it ... 228 */ 229 signature.update(certificateRequestInfo, 0, 230 certificateRequestInfo.length); 231 sig = signature.sign(); 232 sigAlg = signature.getAlgorithm(); 233 234 /* 235 * Build guts of SIGNED macro 236 */ 237 AlgorithmId algId = null; 238 try { 239 AlgorithmParameters params = signature.getParameters(); 240 algId = params == null 241 ? AlgorithmId.get(signature.getAlgorithm()) 242 : AlgorithmId.get(params); 243 } catch (NoSuchAlgorithmException nsae) { 244 throw new SignatureException(nsae); 245 } 246 247 algId.encode(scratch); // sig algorithm 248 scratch.putBitString(sig); // sig 249 250 /* 251 * Wrap those guts in a sequence 252 */ 253 out = new DerOutputStream(); 254 out.write(DerValue.tag_Sequence, scratch); 255 encoded = out.toByteArray(); 256 } 257 258 /** 259 * Returns the subject's name. 260 */ 261 public X500Name getSubjectName() { return subject; } 262 263 /** 264 * Returns the subject's public key. 265 */ 266 public PublicKey getSubjectPublicKeyInfo() 267 { return subjectPublicKeyInfo; } 268 269 /** 270 * Returns the signature algorithm. 271 */ 272 public String getSigAlg() { return sigAlg; } 273 274 /** 275 * Returns the additional attributes requested. 276 */ 277 public PKCS10Attributes getAttributes() 278 { return attributeSet; } 279 280 /** 281 * Returns the encoded and signed certificate request as a 282 * DER-encoded byte array. 283 * 284 * @return the certificate request, or null if encodeAndSign() 285 * has not yet been called. 286 */ 287 public byte[] getEncoded() { 288 if (encoded != null) 289 return encoded.clone(); 290 else 291 return null; 292 } 293 294 /** 295 * Prints an E-Mailable version of the certificate request on the print 296 * stream passed. The format is a common base64 encoded one, supported 297 * by most Certificate Authorities because Netscape web servers have 298 * used this for some time. Some certificate authorities expect some 299 * more information, in particular contact information for the web 300 * server administrator. 301 * 302 * @param out the print stream where the certificate request 303 * will be printed. 304 * @exception IOException when an output operation failed 305 * @exception SignatureException when the certificate request was 306 * not yet signed. 307 */ 308 public void print(PrintStream out) 309 throws IOException, SignatureException { 310 if (encoded == null) 311 throw new SignatureException("Cert request was not signed"); 312 313 314 byte[] CRLF = new byte[] {'\r', '\n'}; 315 out.println("-----BEGIN NEW CERTIFICATE REQUEST-----"); 316 out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(encoded)); 317 out.println("-----END NEW CERTIFICATE REQUEST-----"); 318 } 319 320 /** 321 * Provides a short description of this request. 322 */ 323 public String toString() { 324 return "[PKCS #10 certificate request:\n" 325 + subjectPublicKeyInfo.toString() 326 + " subject: <" + subject + ">" + "\n" 327 + " attributes: " + attributeSet.toString() 328 + "\n]"; 329 } 330 331 /** 332 * Compares this object for equality with the specified 333 * object. If the <code>other</code> object is an 334 * <code>instanceof</code> <code>PKCS10</code>, then 335 * its encoded form is retrieved and compared with the 336 * encoded form of this certificate request. 337 * 338 * @param other the object to test for equality with this object. 339 * @return true iff the encoded forms of the two certificate 340 * requests match, false otherwise. 341 */ 342 public boolean equals(Object other) { 343 if (this == other) 344 return true; 345 if (!(other instanceof PKCS10)) 346 return false; 347 if (encoded == null) // not signed yet 348 return false; 349 byte[] otherEncoded = ((PKCS10)other).getEncoded(); 350 if (otherEncoded == null) 351 return false; 352 353 return java.util.Arrays.equals(encoded, otherEncoded); 354 } 355 356 /** 357 * Returns a hashcode value for this certificate request from its 358 * encoded form. 359 * 360 * @return the hashcode value. 361 */ 362 public int hashCode() { 363 int retval = 0; 364 if (encoded != null) 365 for (int i = 1; i < encoded.length; i++) 366 retval += encoded[i] * i; 367 return(retval); 368 } 369 370 private X500Name subject; 371 private PublicKey subjectPublicKeyInfo; 372 private String sigAlg; 373 private PKCS10Attributes attributeSet; 374 private byte[] encoded; // signed 375 }