1 /* |
|
2 * Copyright 1997-2008 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 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 } |
|