J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 1997-2004 Sun Microsystems, Inc. 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. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any questions. |
| 24 | */ |
| 25 | |
| 26 | package sun.security.x509; |
| 27 | |
| 28 | import java.io.IOException; |
| 29 | import java.io.InputStream; |
| 30 | import java.io.OutputStream; |
| 31 | import java.io.ObjectInputStream; |
| 32 | import java.io.ObjectOutputStream; |
| 33 | import java.io.Serializable; |
| 34 | import java.math.BigInteger; |
| 35 | import java.security.*; |
| 36 | import java.util.Date; |
| 37 | import java.util.Enumeration; |
| 38 | |
| 39 | import sun.security.util.*; // DER |
| 40 | |
| 41 | /** |
| 42 | * @author David Brownell |
| 43 | * |
| 44 | * @see CertAndKeyGen |
| 45 | * @deprecated Use the new X509Certificate class. |
| 46 | * This class is only restored for backwards compatibility. |
| 47 | */ |
| 48 | @Deprecated |
| 49 | public class X509Cert implements Certificate, Serializable { |
| 50 | |
| 51 | static final long serialVersionUID = -52595524744692374L; |
| 52 | |
| 53 | /* |
| 54 | * NOTE: All fields are marked transient, because we do not want them to |
| 55 | * be included in the class description when we serialize an object of |
| 56 | * this class. We override "writeObject" and "readObject" to use the |
| 57 | * ASN.1 encoding of a certificate as the serialized form, instead of |
| 58 | * calling the default routines which would operate on the field values. |
| 59 | * |
| 60 | * MAKE SURE TO MARK ANY FIELDS THAT ARE ADDED IN THE FUTURE AS TRANSIENT. |
| 61 | */ |
| 62 | |
| 63 | /* The algorithm id */ |
| 64 | transient protected AlgorithmId algid; |
| 65 | |
| 66 | /* |
| 67 | * Certificate data, and its envelope |
| 68 | */ |
| 69 | transient private byte rawCert []; |
| 70 | transient private byte signature []; |
| 71 | transient private byte signedCert []; |
| 72 | |
| 73 | /* |
| 74 | * X509.v1 data (parsed) |
| 75 | */ |
| 76 | transient private X500Name subject; // from subject |
| 77 | transient private PublicKey pubkey; |
| 78 | |
| 79 | transient private Date notafter; // from CA (constructor) |
| 80 | transient private Date notbefore; |
| 81 | |
| 82 | transient private int version; // from CA (signAndEncode) |
| 83 | transient private BigInteger serialnum; |
| 84 | transient private X500Name issuer; |
| 85 | transient private AlgorithmId issuerSigAlg; |
| 86 | |
| 87 | /* |
| 88 | * flag to indicate whether or not this certificate has already been parsed |
| 89 | * (through a call to one of the constructors or the "decode" or |
| 90 | * "readObject" methods). This is to ensure that certificates are |
| 91 | * immutable. |
| 92 | */ |
| 93 | transient private boolean parsed=false; |
| 94 | |
| 95 | /* |
| 96 | * X509.v2 extensions |
| 97 | */ |
| 98 | |
| 99 | /* |
| 100 | * X509.v3 extensions |
| 101 | */ |
| 102 | |
| 103 | /* |
| 104 | * Other extensions ... Netscape, Verisign, SET, etc |
| 105 | */ |
| 106 | |
| 107 | |
| 108 | /** |
| 109 | * Construct a uninitialized X509 Cert on which <a href="#decode"> |
| 110 | * decode</a> must later be called (or which may be deserialized). |
| 111 | */ |
| 112 | // XXX deprecated, delete this |
| 113 | public X509Cert() { } |
| 114 | |
| 115 | |
| 116 | /** |
| 117 | * Unmarshals a certificate from its encoded form, parsing the |
| 118 | * encoded bytes. This form of constructor is used by agents which |
| 119 | * need to examine and use certificate contents. That is, this is |
| 120 | * one of the more commonly used constructors. Note that the buffer |
| 121 | * must include only a certificate, and no "garbage" may be left at |
| 122 | * the end. If you need to ignore data at the end of a certificate, |
| 123 | * use another constructor. |
| 124 | * |
| 125 | * @param cert the encoded bytes, with no terminatu (CONSUMED) |
| 126 | * @exception IOException when the certificate is improperly encoded. |
| 127 | */ |
| 128 | public X509Cert(byte cert []) throws IOException |
| 129 | { |
| 130 | DerValue in = new DerValue (cert); |
| 131 | parse (in); |
| 132 | if (in.data.available () != 0) |
| 133 | throw new CertParseError ("garbage at end"); |
| 134 | signedCert = cert; |
| 135 | } |
| 136 | |
| 137 | |
| 138 | /** |
| 139 | * Unmarshals a certificate from its encoded form, parsing the |
| 140 | * encoded bytes. This form of constructor is used by agents which |
| 141 | * need to examine and use certificate contents. That is, this is |
| 142 | * one of the most commonly used constructors. |
| 143 | * |
| 144 | * @param buf the buffer holding the encoded bytes |
| 145 | * @param offset the offset in the buffer where the bytes begin |
| 146 | * @param len how many bytes of certificate exist |
| 147 | * |
| 148 | * @exception IOException when the certificate is improperly encoded. |
| 149 | */ |
| 150 | public X509Cert(byte buf [], int offset, int len) throws IOException |
| 151 | { |
| 152 | DerValue in = new DerValue (buf, offset, len); |
| 153 | |
| 154 | parse (in); |
| 155 | if (in.data.available () != 0) |
| 156 | throw new CertParseError ("garbage at end"); |
| 157 | signedCert = new byte [len]; |
| 158 | System.arraycopy (buf, offset, signedCert, 0, len); |
| 159 | } |
| 160 | |
| 161 | |
| 162 | /** |
| 163 | * Unmarshal a certificate from its encoded form, parsing a DER value. |
| 164 | * This form of constructor is used by agents which need to examine |
| 165 | * and use certificate contents. |
| 166 | * |
| 167 | * @param derVal the der value containing the encoded cert. |
| 168 | * @exception IOException when the certificate is improperly encoded. |
| 169 | */ |
| 170 | public X509Cert(DerValue derVal) throws IOException |
| 171 | { |
| 172 | parse (derVal); |
| 173 | if (derVal.data.available () != 0) |
| 174 | throw new CertParseError ("garbage at end"); |
| 175 | signedCert = derVal.toByteArray (); |
| 176 | } |
| 177 | |
| 178 | |
| 179 | /** |
| 180 | * Partially constructs a certificate from descriptive parameters. |
| 181 | * This constructor may be used by Certificate Authority (CA) code, |
| 182 | * which later <a href="#signAndEncode">signs and encodes</a> the |
| 183 | * certificate. Also, self-signed certificates serve as CA certificates, |
| 184 | * and are sometimes used as certificate requests. |
| 185 | * |
| 186 | * <P>Until the certificate has been signed and encoded, some of |
| 187 | * the mandatory fields in the certificate will not be available |
| 188 | * via accessor functions: the serial number, issuer name and signing |
| 189 | * algorithm, and of course the signed certificate. The fields passed |
| 190 | * to this constructor are available, and must be non-null. |
| 191 | * |
| 192 | * <P>Note that the public key being signed is generally independent of |
| 193 | * the signature algorithm being used. So for example Diffie-Hellman |
| 194 | * keys (which do not support signatures) can be placed in X.509 |
| 195 | * certificates when some other signature algorithm (e.g. DSS/DSA, |
| 196 | * or one of the RSA based algorithms) is used. |
| 197 | * |
| 198 | * @see CertAndKeyGen |
| 199 | * |
| 200 | * @param subjectName the X.500 distinguished name being certified |
| 201 | * @param subjectPublicKey the public key being certified. This |
| 202 | * must be an "X509Key" implementing the "PublicKey" interface. |
| 203 | * @param notBefore the first time the certificate is valid |
| 204 | * @param notAfter the last time the certificate is valid |
| 205 | * |
| 206 | * @exception CertException if the public key is inappropriate |
| 207 | */ |
| 208 | public X509Cert(X500Name subjectName, X509Key subjectPublicKey, |
| 209 | Date notBefore, Date notAfter) throws CertException |
| 210 | { |
| 211 | subject = subjectName; |
| 212 | |
| 213 | if (!(subjectPublicKey instanceof PublicKey)) |
| 214 | throw new CertException (CertException.err_INVALID_PUBLIC_KEY, |
| 215 | "Doesn't implement PublicKey interface"); |
| 216 | |
| 217 | // The X509 cert API requires X509 keys, else things break. |
| 218 | pubkey = subjectPublicKey; |
| 219 | notbefore = notBefore; |
| 220 | notafter = notAfter; |
| 221 | version = 0; |
| 222 | } |
| 223 | |
| 224 | |
| 225 | /** |
| 226 | * Decode an X.509 certificate from an input stream. |
| 227 | * |
| 228 | * @param in an input stream holding at least one certificate |
| 229 | * @exception IOException when the certificate is improperly encoded, or |
| 230 | * if it has already been parsed. |
| 231 | */ |
| 232 | public void decode(InputStream in) throws IOException |
| 233 | { |
| 234 | DerValue val = new DerValue(in); |
| 235 | parse(val); |
| 236 | signedCert = val.toByteArray(); |
| 237 | } |
| 238 | |
| 239 | |
| 240 | /** |
| 241 | * Appends the certificate to an output stream. |
| 242 | * |
| 243 | * @param out an input stream to which the certificate is appended. |
| 244 | * @exception IOException when appending fails. |
| 245 | */ |
| 246 | public void encode (OutputStream out) throws IOException |
| 247 | { out.write (getSignedCert ()); } |
| 248 | |
| 249 | |
| 250 | /** |
| 251 | * Compares two certificates. This is false if the |
| 252 | * certificates are not both X.509 certs, otherwise it |
| 253 | * compares them as binary data. |
| 254 | * |
| 255 | * @param other the object being compared with this one |
| 256 | * @return true iff the certificates are equivalent |
| 257 | */ |
| 258 | public boolean equals (Object other) |
| 259 | { |
| 260 | if (other instanceof X509Cert) |
| 261 | return equals ((X509Cert) other); |
| 262 | else |
| 263 | return false; |
| 264 | } |
| 265 | |
| 266 | |
| 267 | /** |
| 268 | * Compares two certificates, returning false if any data |
| 269 | * differs between the two. |
| 270 | * |
| 271 | * @param other the object being compared with this one |
| 272 | * @return true iff the certificates are equivalent |
| 273 | */ |
| 274 | public boolean equals (X509Cert src) |
| 275 | { |
| 276 | if (this == src) |
| 277 | return true; |
| 278 | if (signedCert == null || src.signedCert == null) |
| 279 | return false; |
| 280 | if (signedCert.length != src.signedCert.length) |
| 281 | return false; |
| 282 | for (int i = 0; i < signedCert.length; i++) |
| 283 | if (signedCert [i] != src.signedCert [i]) |
| 284 | return false; |
| 285 | return true; |
| 286 | } |
| 287 | |
| 288 | |
| 289 | /** Returns the "X.509" format identifier. */ |
| 290 | public String getFormat () // for Certificate |
| 291 | { return "X.509"; } |
| 292 | |
| 293 | |
| 294 | /** Returns <a href="#getIssuerName">getIssuerName</a> */ |
| 295 | public Principal getGuarantor () // for Certificate |
| 296 | { return getIssuerName (); } |
| 297 | |
| 298 | |
| 299 | /** Returns <a href="#getSubjectName">getSubjectName</a> */ |
| 300 | public Principal getPrincipal () |
| 301 | { return getSubjectName (); } |
| 302 | |
| 303 | |
| 304 | /** |
| 305 | * Throws an exception if the certificate is invalid because it is |
| 306 | * now outside of the certificate's validity period, or because it |
| 307 | * was not signed using the verification key provided. Successfully |
| 308 | * verifying a certificate does <em>not</em> indicate that one should |
| 309 | * trust the entity which it represents. |
| 310 | * |
| 311 | * <P><em>Note that since this class represents only a single X.509 |
| 312 | * certificate, it cannot know anything about the certificate chain |
| 313 | * which is used to provide the verification key and to establish trust. |
| 314 | * Other code must manage and use those cert chains. |
| 315 | * |
| 316 | * <P>For now, you must walk the cert chain being used to verify any |
| 317 | * given cert. Start at the root, which is a self-signed certificate; |
| 318 | * verify it using the key inside the certificate. Then use that to |
| 319 | * verify the next certificate in the chain, issued by that CA. In |
| 320 | * this manner, verify each certificate until you reach the particular |
| 321 | * certificate you wish to verify. You should not use a certificate |
| 322 | * if any of the verification operations for its certificate chain |
| 323 | * were unsuccessful. |
| 324 | * </em> |
| 325 | * |
| 326 | * @param issuerPublicKey the public key of the issuing CA |
| 327 | * @exception CertException when the certificate is not valid. |
| 328 | */ |
| 329 | public void verify (PublicKey issuerPublicKey) |
| 330 | throws CertException |
| 331 | { |
| 332 | Date now = new Date (); |
| 333 | |
| 334 | if (now.before (notbefore)) |
| 335 | throw new CertException (CertException.verf_INVALID_NOTBEFORE); |
| 336 | if (now.after (notafter)) |
| 337 | throw new CertException (CertException.verf_INVALID_EXPIRED); |
| 338 | if (signedCert == null) |
| 339 | throw new CertException (CertException.verf_INVALID_SIG, |
| 340 | "?? certificate is not signed yet ??"); |
| 341 | |
| 342 | // |
| 343 | // Verify the signature ... |
| 344 | // |
| 345 | String algName = null; |
| 346 | |
| 347 | try { |
| 348 | Signature sigVerf = null; |
| 349 | |
| 350 | algName = issuerSigAlg.getName(); |
| 351 | sigVerf = Signature.getInstance(algName); |
| 352 | sigVerf.initVerify (issuerPublicKey); |
| 353 | sigVerf.update (rawCert, 0, rawCert.length); |
| 354 | |
| 355 | if (!sigVerf.verify (signature)) { |
| 356 | throw new CertException (CertException.verf_INVALID_SIG, |
| 357 | "Signature ... by <" + issuer + "> for <" + subject + ">"); |
| 358 | } |
| 359 | |
| 360 | // Gag -- too many catch clauses, let most through. |
| 361 | |
| 362 | } catch (NoSuchAlgorithmException e) { |
| 363 | throw new CertException (CertException.verf_INVALID_SIG, |
| 364 | "Unsupported signature algorithm (" + algName + ")"); |
| 365 | |
| 366 | } catch (InvalidKeyException e) { |
| 367 | // e.printStackTrace(); |
| 368 | throw new CertException (CertException.err_INVALID_PUBLIC_KEY, |
| 369 | "Algorithm (" + algName + ") rejected public key"); |
| 370 | |
| 371 | } catch (SignatureException e) { |
| 372 | throw new CertException (CertException.verf_INVALID_SIG, |
| 373 | "Signature by <" + issuer + "> for <" + subject + ">"); |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | |
| 378 | /** |
| 379 | * Creates an X.509 certificate, and signs it using the issuer |
| 380 | * passed (associating a signature algorithm and an X.500 name). |
| 381 | * This operation is used to implement the certificate generation |
| 382 | * functionality of a certificate authority. |
| 383 | * |
| 384 | * @see #getSignedCert |
| 385 | * @see #getSigner |
| 386 | * @see CertAndKeyGen |
| 387 | * |
| 388 | * @param serial the serial number of the certificate (non-null) |
| 389 | * @param issuer the certificate issuer (CA) (non-null) |
| 390 | * @return the signed certificate, as returned by getSignedCert |
| 391 | * |
| 392 | * @exception IOException if any of the data could not be encoded, |
| 393 | * or when any mandatory data was omitted |
| 394 | * @exception SignatureException on signing failures |
| 395 | */ |
| 396 | public byte [] |
| 397 | encodeAndSign ( |
| 398 | BigInteger serial, |
| 399 | X500Signer issuer |
| 400 | ) throws IOException, SignatureException |
| 401 | { |
| 402 | rawCert = null; |
| 403 | |
| 404 | /* |
| 405 | * Get the remaining cert parameters, and make sure we have enough. |
| 406 | * |
| 407 | * We deduce version based on what attribute data are available |
| 408 | * For now, we have no attributes, so we always deduce X.509v1 ! |
| 409 | */ |
| 410 | version = 0; |
| 411 | serialnum = serial; |
| 412 | this.issuer = issuer.getSigner (); |
| 413 | issuerSigAlg = issuer.getAlgorithmId (); |
| 414 | |
| 415 | if (subject == null || pubkey == null |
| 416 | || notbefore == null || notafter == null) |
| 417 | throw new IOException ("not enough cert parameters"); |
| 418 | |
| 419 | /* |
| 420 | * Encode the raw cert, create its signature and put it |
| 421 | * into the envelope. |
| 422 | */ |
| 423 | rawCert = DERencode (); |
| 424 | signedCert = sign (issuer, rawCert); |
| 425 | return signedCert; |
| 426 | } |
| 427 | |
| 428 | |
| 429 | /** |
| 430 | * Returns an X500Signer that may be used to create signatures. Those |
| 431 | * signature may in turn be verified using this certificate (or a |
| 432 | * copy of it). |
| 433 | * |
| 434 | * <P><em><b>NOTE:</b> If the private key is by itself capable of |
| 435 | * creating signatures, this fact may not be recognized at this time. |
| 436 | * Specifically, the case of DSS/DSA keys which get their algorithm |
| 437 | * parameters from higher in the certificate chain is not supportable |
| 438 | * without using an X509CertChain API, and there is no current support |
| 439 | * for other sources of algorithm parameters.</em> |
| 440 | * |
| 441 | * @param algorithm the signature algorithm to be used. Note that a |
| 442 | * given public/private key pair may support several such algorithms. |
| 443 | * @param privateKey the private key used to create the signature, |
| 444 | * which must correspond to the public key in this certificate |
| 445 | * @return the Signer object |
| 446 | * |
| 447 | * @exception NoSuchAlgorithmException if the signature |
| 448 | * algorithm is not supported |
| 449 | * @exception InvalidKeyException if either the key in the certificate, |
| 450 | * or the private key parameter, does not support the requested |
| 451 | * signature algorithm |
| 452 | */ |
| 453 | public X500Signer getSigner (AlgorithmId algorithmId, |
| 454 | PrivateKey privateKey) |
| 455 | throws NoSuchAlgorithmException, InvalidKeyException |
| 456 | { |
| 457 | String algorithm; |
| 458 | Signature sig; |
| 459 | |
| 460 | if (privateKey instanceof Key) { |
| 461 | Key key = (Key)privateKey; |
| 462 | algorithm = key.getAlgorithm(); |
| 463 | } else { |
| 464 | throw new InvalidKeyException("private key not a key!"); |
| 465 | } |
| 466 | |
| 467 | sig = Signature.getInstance(algorithmId.getName()); |
| 468 | |
| 469 | if (!pubkey.getAlgorithm ().equals (algorithm)) { |
| 470 | |
| 471 | throw new InvalidKeyException( "Private key algorithm " + |
| 472 | algorithm + |
| 473 | " incompatible with certificate " + |
| 474 | pubkey.getAlgorithm()); |
| 475 | } |
| 476 | sig.initSign (privateKey); |
| 477 | return new X500Signer (sig, subject); |
| 478 | } |
| 479 | |
| 480 | |
| 481 | /** |
| 482 | * Returns a signature object that may be used to verify signatures |
| 483 | * created using a specified signature algorithm and the public key |
| 484 | * contained in this certificate. |
| 485 | * |
| 486 | * <P><em><b>NOTE:</b> If the public key in this certificate is not by |
| 487 | * itself capable of verifying signatures, this may not be recognized |
| 488 | * at this time. Specifically, the case of DSS/DSA keys which get |
| 489 | * their algorithm parameters from higher in the certificate chain |
| 490 | * is not supportable without using an X509CertChain API, and there |
| 491 | * is no current support for other sources of algorithm parameters.</em> |
| 492 | * |
| 493 | * @param algorithm the algorithm of the signature to be verified |
| 494 | * @return the Signature object |
| 495 | * @exception NoSuchAlgorithmException if the signature |
| 496 | * algorithm is not supported |
| 497 | * @exception InvalidKeyException if the key in the certificate |
| 498 | * does not support the requested signature algorithm |
| 499 | */ |
| 500 | public Signature getVerifier(String algorithm) |
| 501 | throws NoSuchAlgorithmException, InvalidKeyException |
| 502 | { |
| 503 | String algName; |
| 504 | Signature sig; |
| 505 | |
| 506 | sig = Signature.getInstance(algorithm); |
| 507 | sig.initVerify (pubkey); |
| 508 | return sig; |
| 509 | } |
| 510 | |
| 511 | |
| 512 | |
| 513 | /** |
| 514 | * Return the signed X.509 certificate as a byte array. |
| 515 | * The bytes are in standard DER marshaled form. |
| 516 | * Null is returned in the case of a partially constructed cert. |
| 517 | */ |
| 518 | public byte [] getSignedCert () |
| 519 | { return (byte[])signedCert.clone(); } |
| 520 | |
| 521 | |
| 522 | /** |
| 523 | * Returns the certificate's serial number. |
| 524 | * Null is returned in the case of a partially constructed cert. |
| 525 | */ |
| 526 | public BigInteger getSerialNumber () |
| 527 | { return serialnum; } |
| 528 | |
| 529 | |
| 530 | /** |
| 531 | * Returns the subject's X.500 distinguished name. |
| 532 | */ |
| 533 | public X500Name getSubjectName () |
| 534 | { return subject; } |
| 535 | |
| 536 | |
| 537 | /** |
| 538 | * Returns the certificate issuer's X.500 distinguished name. |
| 539 | * Null is returned in the case of a partially constructed cert. |
| 540 | */ |
| 541 | public X500Name getIssuerName () |
| 542 | { return issuer; } |
| 543 | |
| 544 | |
| 545 | /** |
| 546 | * Returns the algorithm used by the issuer to sign the certificate. |
| 547 | * Null is returned in the case of a partially constructed cert. |
| 548 | */ |
| 549 | public AlgorithmId getIssuerAlgorithmId () |
| 550 | { return issuerSigAlg; } |
| 551 | |
| 552 | |
| 553 | /** |
| 554 | * Returns the first time the certificate is valid. |
| 555 | */ |
| 556 | public Date getNotBefore () |
| 557 | { return new Date(notbefore.getTime()); } |
| 558 | |
| 559 | |
| 560 | /** |
| 561 | * Returns the last time the certificate is valid. |
| 562 | */ |
| 563 | public Date getNotAfter () |
| 564 | { return new Date(notafter.getTime()); } |
| 565 | |
| 566 | |
| 567 | /** |
| 568 | * Returns the subject's public key. Note that some public key |
| 569 | * algorithms support an optional certificate generation policy |
| 570 | * where the keys in the certificates are not in themselves sufficient |
| 571 | * to perform a public key operation. Those keys need to be augmented |
| 572 | * by algorithm parameters, which the certificate generation policy |
| 573 | * chose not to place in the certificate. |
| 574 | * |
| 575 | * <P>Two such public key algorithms are: DSS/DSA, where algorithm |
| 576 | * parameters could be acquired from a CA certificate in the chain |
| 577 | * of issuers; and Diffie-Hellman, with a similar solution although |
| 578 | * the CA then needs both a Diffie-Hellman certificate and a signature |
| 579 | * capable certificate. |
| 580 | */ |
| 581 | public PublicKey getPublicKey () |
| 582 | { return pubkey; } |
| 583 | |
| 584 | |
| 585 | /** |
| 586 | * Returns the X.509 version number of this certificate, zero based. |
| 587 | * That is, "2" indicates an X.509 version 3 (1993) certificate, |
| 588 | * and "0" indicates X.509v1 (1988). |
| 589 | * Zero is returned in the case of a partially constructed cert. |
| 590 | */ |
| 591 | public int getVersion () |
| 592 | { return version; } |
| 593 | |
| 594 | |
| 595 | /** |
| 596 | * Calculates a hash code value for the object. Objects |
| 597 | * which are equal will also have the same hashcode. |
| 598 | */ |
| 599 | public int hashCode () |
| 600 | { |
| 601 | int retval = 0; |
| 602 | |
| 603 | for (int i = 0; i < signedCert.length; i++) |
| 604 | retval += signedCert [i] * i; |
| 605 | return retval; |
| 606 | } |
| 607 | |
| 608 | |
| 609 | /** |
| 610 | * Returns a printable representation of the certificate. This does not |
| 611 | * contain all the information available to distinguish this from any |
| 612 | * other certificate. The certificate must be fully constructed |
| 613 | * before this function may be called; in particular, if you are |
| 614 | * creating certificates you must call encodeAndSign() before calling |
| 615 | * this function. |
| 616 | */ |
| 617 | public String toString () |
| 618 | { |
| 619 | String s; |
| 620 | |
| 621 | if (subject == null || pubkey == null |
| 622 | || notbefore == null || notafter == null |
| 623 | || issuer == null || issuerSigAlg == null |
| 624 | || serialnum == null) |
| 625 | throw new NullPointerException ("X.509 cert is incomplete"); |
| 626 | |
| 627 | s = " X.509v" + (version + 1) + " certificate,\n"; |
| 628 | s += " Subject is " + subject + "\n"; |
| 629 | s += " Key: " + pubkey; |
| 630 | s += " Validity <" + notbefore + "> until <" + notafter + ">\n"; |
| 631 | s += " Issuer is " + issuer + "\n"; |
| 632 | s += " Issuer signature used " + issuerSigAlg.toString () + "\n"; |
| 633 | s += " Serial number = " + Debug.toHexString(serialnum) + "\n"; |
| 634 | |
| 635 | // optional v2, v3 extras |
| 636 | |
| 637 | return "[\n" + s + "]"; |
| 638 | } |
| 639 | |
| 640 | |
| 641 | /** |
| 642 | * Returns a printable representation of the certificate. |
| 643 | * |
| 644 | * @param detailed true iff lots of detail is requested |
| 645 | */ |
| 646 | public String toString (boolean detailed) |
| 647 | { return toString (); } |
| 648 | |
| 649 | |
| 650 | /************************************************************/ |
| 651 | |
| 652 | /* |
| 653 | * Cert is a SIGNED ASN.1 macro, a three elment sequence: |
| 654 | * |
| 655 | * - Data to be signed (ToBeSigned) -- the "raw" cert |
| 656 | * - Signature algorithm (SigAlgId) |
| 657 | * - The signature bits |
| 658 | * |
| 659 | * This routine unmarshals the certificate, saving the signature |
| 660 | * parts away for later verification. |
| 661 | */ |
| 662 | private void parse (DerValue val) throws IOException |
| 663 | { |
| 664 | if (parsed == true) { |
| 665 | throw new IOException("Certificate already parsed"); |
| 666 | } |
| 667 | |
| 668 | DerValue seq [] = new DerValue [3]; |
| 669 | |
| 670 | seq [0] = val.data.getDerValue (); |
| 671 | seq [1] = val.data.getDerValue (); |
| 672 | seq [2] = val.data.getDerValue (); |
| 673 | |
| 674 | if (val.data.available () != 0) |
| 675 | throw new CertParseError ("signed overrun, bytes = " |
| 676 | + val.data.available ()); |
| 677 | if (seq [0].tag != DerValue.tag_Sequence) |
| 678 | throw new CertParseError ("signed fields invalid"); |
| 679 | |
| 680 | rawCert = seq [0].toByteArray (); // XXX slow; fixme! |
| 681 | |
| 682 | |
| 683 | issuerSigAlg = AlgorithmId.parse (seq [1]); |
| 684 | signature = seq [2].getBitString (); |
| 685 | |
| 686 | if (seq [1].data.available () != 0) { |
| 687 | // XXX why was this error check commented out? |
| 688 | // It was originally part of the next check. |
| 689 | throw new CertParseError ("algid field overrun"); |
| 690 | } |
| 691 | |
| 692 | if (seq [2].data.available () != 0) |
| 693 | throw new CertParseError ("signed fields overrun"); |
| 694 | |
| 695 | /* |
| 696 | * Let's have fun parsing the cert itself. |
| 697 | */ |
| 698 | DerInputStream in; |
| 699 | DerValue tmp; |
| 700 | |
| 701 | in = seq [0].data; |
| 702 | |
| 703 | /* |
| 704 | * Version -- this is optional (default zero). If it's there it's |
| 705 | * the first field and is specially tagged. |
| 706 | * |
| 707 | * Both branches leave "tmp" holding a value for the serial |
| 708 | * number that comes next. |
| 709 | */ |
| 710 | version = 0; |
| 711 | tmp = in.getDerValue (); |
| 712 | if (tmp.isConstructed () && tmp.isContextSpecific ()) { |
| 713 | version = tmp.data.getInteger(); |
| 714 | if (tmp.data.available () != 0) |
| 715 | throw new IOException ("X.509 version, bad format"); |
| 716 | tmp = in.getDerValue (); |
| 717 | } |
| 718 | |
| 719 | /* |
| 720 | * serial number ... an integer |
| 721 | */ |
| 722 | serialnum = tmp.getBigInteger (); |
| 723 | |
| 724 | /* |
| 725 | * algorithm type for CA's signature ... needs to match the |
| 726 | * one on the envelope, and that's about it! different IDs |
| 727 | * may represent a signature attack. In general we want to |
| 728 | * inherit parameters. |
| 729 | */ |
| 730 | tmp = in.getDerValue (); |
| 731 | { |
| 732 | AlgorithmId algid; |
| 733 | |
| 734 | |
| 735 | algid = AlgorithmId.parse(tmp); |
| 736 | |
| 737 | if (!algid.equals (issuerSigAlg)) |
| 738 | throw new CertParseError ("CA Algorithm mismatch!"); |
| 739 | |
| 740 | this.algid = algid; |
| 741 | } |
| 742 | |
| 743 | /* |
| 744 | * issuer name |
| 745 | */ |
| 746 | issuer = new X500Name (in); |
| 747 | |
| 748 | /* |
| 749 | * validity: SEQUENCE { start date, end date } |
| 750 | */ |
| 751 | tmp = in.getDerValue (); |
| 752 | if (tmp.tag != DerValue.tag_Sequence) |
| 753 | throw new CertParseError ("corrupt validity field"); |
| 754 | |
| 755 | notbefore = tmp.data.getUTCTime (); |
| 756 | notafter = tmp.data.getUTCTime (); |
| 757 | if (tmp.data.available () != 0) |
| 758 | throw new CertParseError ("excess validity data"); |
| 759 | |
| 760 | /* |
| 761 | * subject name and public key |
| 762 | */ |
| 763 | subject = new X500Name (in); |
| 764 | |
| 765 | tmp = in.getDerValue (); |
| 766 | pubkey = X509Key.parse (tmp); |
| 767 | |
| 768 | /* |
| 769 | * XXX for v2 and later, a bunch of tagged options follow |
| 770 | */ |
| 771 | |
| 772 | if (in.available () != 0) { |
| 773 | /* |
| 774 | * Until we parse V2/V3 data ... ignore it. |
| 775 | * |
| 776 | // throw new CertParseError ("excess cert data"); |
| 777 | System.out.println ( |
| 778 | "@end'o'cert, optional V2/V3 data unparsed: " |
| 779 | + in.available () |
| 780 | + " bytes" |
| 781 | ); |
| 782 | */ |
| 783 | } |
| 784 | |
| 785 | parsed = true; |
| 786 | } |
| 787 | |
| 788 | |
| 789 | /* |
| 790 | * Encode only the parts that will later be signed. |
| 791 | */ |
| 792 | private byte [] DERencode () throws IOException |
| 793 | { |
| 794 | DerOutputStream raw = new DerOutputStream (); |
| 795 | |
| 796 | encode (raw); |
| 797 | return raw.toByteArray (); |
| 798 | } |
| 799 | |
| 800 | |
| 801 | /* |
| 802 | * Marshal the contents of a "raw" certificate into a DER sequence. |
| 803 | */ |
| 804 | private void encode (DerOutputStream out) throws IOException |
| 805 | { |
| 806 | DerOutputStream tmp = new DerOutputStream (); |
| 807 | |
| 808 | /* |
| 809 | * encode serial number, issuer signing algorithm, |
| 810 | * and issuer name into the data we'll return |
| 811 | */ |
| 812 | tmp.putInteger (serialnum); |
| 813 | issuerSigAlg.encode (tmp); |
| 814 | issuer.encode (tmp); |
| 815 | |
| 816 | /* |
| 817 | * Validity is a two element sequence ... encode the |
| 818 | * elements, then wrap them into the data we'll return |
| 819 | */ |
| 820 | { |
| 821 | DerOutputStream seq = new DerOutputStream (); |
| 822 | |
| 823 | seq.putUTCTime (notbefore); |
| 824 | seq.putUTCTime (notafter); |
| 825 | tmp.write (DerValue.tag_Sequence, seq); |
| 826 | } |
| 827 | |
| 828 | /* |
| 829 | * Encode subject (principal) and associated key |
| 830 | */ |
| 831 | subject.encode (tmp); |
| 832 | tmp.write(pubkey.getEncoded()); |
| 833 | |
| 834 | /* |
| 835 | * Wrap the data; encoding of the "raw" cert is now complete. |
| 836 | */ |
| 837 | out.write (DerValue.tag_Sequence, tmp); |
| 838 | } |
| 839 | |
| 840 | |
| 841 | /* |
| 842 | * Calculate the signature of the "raw" certificate, |
| 843 | * and marshal the cert with the signature and a |
| 844 | * description of the signing algorithm. |
| 845 | */ |
| 846 | private byte [] sign (X500Signer issuer, byte data []) |
| 847 | throws IOException, SignatureException |
| 848 | { |
| 849 | /* |
| 850 | * Encode the to-be-signed data, then the algorithm used |
| 851 | * to create the signature. |
| 852 | */ |
| 853 | DerOutputStream out = new DerOutputStream (); |
| 854 | DerOutputStream tmp = new DerOutputStream (); |
| 855 | |
| 856 | tmp.write (data); |
| 857 | issuer.getAlgorithmId ().encode(tmp); |
| 858 | |
| 859 | |
| 860 | /* |
| 861 | * Create and encode the signature itself. |
| 862 | */ |
| 863 | issuer.update (data, 0, data.length); |
| 864 | signature = issuer.sign (); |
| 865 | tmp.putBitString (signature); |
| 866 | |
| 867 | /* |
| 868 | * Wrap the signed data in a SEQUENCE { data, algorithm, sig } |
| 869 | */ |
| 870 | out.write (DerValue.tag_Sequence, tmp); |
| 871 | return out.toByteArray (); |
| 872 | } |
| 873 | |
| 874 | |
| 875 | /** |
| 876 | * Serialization write ... X.509 certificates serialize as |
| 877 | * themselves, and they're parsed when they get read back. |
| 878 | * (Actually they serialize as some type data from the |
| 879 | * serialization subsystem, then the cert data.) |
| 880 | */ |
| 881 | private void writeObject (java.io.ObjectOutputStream stream) |
| 882 | throws IOException |
| 883 | { encode(stream); } |
| 884 | |
| 885 | /** |
| 886 | * Serialization read ... X.509 certificates serialize as |
| 887 | * themselves, and they're parsed when they get read back. |
| 888 | */ |
| 889 | private void readObject (ObjectInputStream stream) |
| 890 | throws IOException |
| 891 | { decode(stream); } |
| 892 | } |