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 // set parameters before Signature.initSign/initVerify call, 173 // so key can be checked when it's set 174 SignatureUtil.specialSetParameter(sig, id.getParameters()); 175 176 sig.initVerify(subjectPublicKeyInfo); 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 algId = AlgorithmId.get(signature.getAlgorithm()); 240 } catch (NoSuchAlgorithmException nsae) { 241 throw new SignatureException(nsae); 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 }