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