blob: b1157799663930047d6a976931d1d7d19a6a61c5 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2007 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
26package sun.security.x509;
27
28import java.io.InputStream;
29import java.io.OutputStream;
30import java.io.IOException;
31import java.math.BigInteger;
32import java.security.Principal;
33import java.security.PublicKey;
34import java.security.PrivateKey;
35import java.security.Security;
36import java.security.Signature;
37import java.security.NoSuchAlgorithmException;
38import java.security.InvalidKeyException;
39import java.security.NoSuchProviderException;
40import java.security.SignatureException;
41import java.security.cert.Certificate;
42import java.security.cert.X509CRL;
43import java.security.cert.X509Certificate;
44import java.security.cert.X509CRLEntry;
45import java.security.cert.CRLException;
46import java.util.*;
47
48import javax.security.auth.x500.X500Principal;
49
50import sun.security.provider.X509Factory;
51import sun.security.util.*;
52import sun.misc.HexDumpEncoder;
53
54/**
55 * <p>
56 * An implmentation for X509 CRL (Certificate Revocation List).
57 * <p>
58 * The X.509 v2 CRL format is described below in ASN.1:
59 * <pre>
60 * CertificateList ::= SEQUENCE {
61 * tbsCertList TBSCertList,
62 * signatureAlgorithm AlgorithmIdentifier,
63 * signature BIT STRING }
64 * </pre>
65 * More information can be found in
66 * <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
67 * Public Key Infrastructure Certificate and CRL Profile</a>.
68 * <p>
69 * The ASN.1 definition of <code>tbsCertList</code> is:
70 * <pre>
71 * TBSCertList ::= SEQUENCE {
72 * version Version OPTIONAL,
73 * -- if present, must be v2
74 * signature AlgorithmIdentifier,
75 * issuer Name,
76 * thisUpdate ChoiceOfTime,
77 * nextUpdate ChoiceOfTime OPTIONAL,
78 * revokedCertificates SEQUENCE OF SEQUENCE {
79 * userCertificate CertificateSerialNumber,
80 * revocationDate ChoiceOfTime,
81 * crlEntryExtensions Extensions OPTIONAL
82 * -- if present, must be v2
83 * } OPTIONAL,
84 * crlExtensions [0] EXPLICIT Extensions OPTIONAL
85 * -- if present, must be v2
86 * }
87 * </pre>
88 *
89 * @author Hemma Prafullchandra
90 * @see X509CRL
91 */
92public class X509CRLImpl extends X509CRL {
93
94 // CRL data, and its envelope
95 private byte[] signedCRL = null; // DER encoded crl
96 private byte[] signature = null; // raw signature bits
97 private byte[] tbsCertList = null; // DER encoded "to-be-signed" CRL
98 private AlgorithmId sigAlgId = null; // sig alg in CRL
99
100 // crl information
101 private int version;
102 private AlgorithmId infoSigAlgId; // sig alg in "to-be-signed" crl
103 private X500Name issuer = null;
104 private X500Principal issuerPrincipal = null;
105 private Date thisUpdate = null;
106 private Date nextUpdate = null;
107 private Map<X509IssuerSerial,X509CRLEntry> revokedCerts = new LinkedHashMap<X509IssuerSerial,X509CRLEntry>();
108 private CRLExtensions extensions = null;
109 private final static boolean isExplicit = true;
110 private static final long YR_2050 = 2524636800000L;
111
112 private boolean readOnly = false;
113
114 /**
115 * PublicKey that has previously been used to successfully verify
116 * the signature of this CRL. Null if the CRL has not
117 * yet been verified (successfully).
118 */
119 private PublicKey verifiedPublicKey;
120 /**
121 * If verifiedPublicKey is not null, name of the provider used to
122 * successfully verify the signature of this CRL, or the
123 * empty String if no provider was explicitly specified.
124 */
125 private String verifiedProvider;
126
127 /**
128 * Not to be used. As it would lead to cases of uninitialized
129 * CRL objects.
130 */
131 private X509CRLImpl() { }
132
133 /**
134 * Unmarshals an X.509 CRL from its encoded form, parsing the encoded
135 * bytes. This form of constructor is used by agents which
136 * need to examine and use CRL contents. Note that the buffer
137 * must include only one CRL, and no "garbage" may be left at
138 * the end.
139 *
140 * @param crlData the encoded bytes, with no trailing padding.
141 * @exception CRLException on parsing errors.
142 */
143 public X509CRLImpl(byte[] crlData) throws CRLException {
144 try {
145 parse(new DerValue(crlData));
146 } catch (IOException e) {
147 signedCRL = null;
148 throw new CRLException("Parsing error: " + e.getMessage());
149 }
150 }
151
152 /**
153 * Unmarshals an X.509 CRL from an DER value.
154 *
155 * @param val a DER value holding at least one CRL
156 * @exception CRLException on parsing errors.
157 */
158 public X509CRLImpl(DerValue val) throws CRLException {
159 try {
160 parse(val);
161 } catch (IOException e) {
162 signedCRL = null;
163 throw new CRLException("Parsing error: " + e.getMessage());
164 }
165 }
166
167 /**
168 * Unmarshals an X.509 CRL from an input stream. Only one CRL
169 * is expected at the end of the input stream.
170 *
171 * @param inStrm an input stream holding at least one CRL
172 * @exception CRLException on parsing errors.
173 */
174 public X509CRLImpl(InputStream inStrm) throws CRLException {
175 try {
176 parse(new DerValue(inStrm));
177 } catch (IOException e) {
178 signedCRL = null;
179 throw new CRLException("Parsing error: " + e.getMessage());
180 }
181 }
182
183 /**
184 * Initial CRL constructor, no revoked certs, and no extensions.
185 *
186 * @param issuer the name of the CA issuing this CRL.
187 * @param thisUpdate the Date of this issue.
188 * @param nextUpdate the Date of the next CRL.
189 */
190 public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate) {
191 this.issuer = issuer;
192 this.thisUpdate = thisDate;
193 this.nextUpdate = nextDate;
194 }
195
196 /**
197 * CRL constructor, revoked certs, no extensions.
198 *
199 * @param issuer the name of the CA issuing this CRL.
200 * @param thisUpdate the Date of this issue.
201 * @param nextUpdate the Date of the next CRL.
202 * @param badCerts the array of CRL entries.
203 *
204 * @exception CRLException on parsing/construction errors.
205 */
206 public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
207 X509CRLEntry[] badCerts)
208 throws CRLException
209 {
210 this.issuer = issuer;
211 this.thisUpdate = thisDate;
212 this.nextUpdate = nextDate;
213 if (badCerts != null) {
214 X500Principal crlIssuer = getIssuerX500Principal();
215 X500Principal badCertIssuer = crlIssuer;
216 for (int i = 0; i < badCerts.length; i++) {
217 X509CRLEntryImpl badCert = (X509CRLEntryImpl)badCerts[i];
218 try {
219 badCertIssuer = getCertIssuer(badCert, badCertIssuer);
220 } catch (IOException ioe) {
221 throw new CRLException(ioe);
222 }
223 badCert.setCertificateIssuer(crlIssuer, badCertIssuer);
224 X509IssuerSerial issuerSerial = new X509IssuerSerial
225 (badCertIssuer, badCert.getSerialNumber());
226 this.revokedCerts.put(issuerSerial, badCert);
227 if (badCert.hasExtensions()) {
228 this.version = 1;
229 }
230 }
231 }
232 }
233
234 /**
235 * CRL constructor, revoked certs and extensions.
236 *
237 * @param issuer the name of the CA issuing this CRL.
238 * @param thisUpdate the Date of this issue.
239 * @param nextUpdate the Date of the next CRL.
240 * @param badCerts the array of CRL entries.
241 * @param crlExts the CRL extensions.
242 *
243 * @exception CRLException on parsing/construction errors.
244 */
245 public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
246 X509CRLEntry[] badCerts, CRLExtensions crlExts)
247 throws CRLException
248 {
249 this(issuer, thisDate, nextDate, badCerts);
250 if (crlExts != null) {
251 this.extensions = crlExts;
252 this.version = 1;
253 }
254 }
255
256 /**
257 * Returned the encoding as an uncloned byte array. Callers must
258 * guarantee that they neither modify it nor expose it to untrusted
259 * code.
260 */
261 public byte[] getEncodedInternal() throws CRLException {
262 if (signedCRL == null) {
263 throw new CRLException("Null CRL to encode");
264 }
265 return signedCRL;
266 }
267
268 /**
269 * Returns the ASN.1 DER encoded form of this CRL.
270 *
271 * @exception CRLException if an encoding error occurs.
272 */
273 public byte[] getEncoded() throws CRLException {
274 return getEncodedInternal().clone();
275 }
276
277 /**
278 * Encodes the "to-be-signed" CRL to the OutputStream.
279 *
280 * @param out the OutputStream to write to.
281 * @exception CRLException on encoding errors.
282 */
283 public void encodeInfo(OutputStream out) throws CRLException {
284 try {
285 DerOutputStream tmp = new DerOutputStream();
286 DerOutputStream rCerts = new DerOutputStream();
287 DerOutputStream seq = new DerOutputStream();
288
289 if (version != 0) // v2 crl encode version
290 tmp.putInteger(version);
291 infoSigAlgId.encode(tmp);
292 if ((version == 0) && (issuer.toString() == null))
293 throw new CRLException("Null Issuer DN not allowed in v1 CRL");
294 issuer.encode(tmp);
295
296 if (thisUpdate.getTime() < YR_2050)
297 tmp.putUTCTime(thisUpdate);
298 else
299 tmp.putGeneralizedTime(thisUpdate);
300
301 if (nextUpdate != null) {
302 if (nextUpdate.getTime() < YR_2050)
303 tmp.putUTCTime(nextUpdate);
304 else
305 tmp.putGeneralizedTime(nextUpdate);
306 }
307
308 if (!revokedCerts.isEmpty()) {
309 for (X509CRLEntry entry : revokedCerts.values()) {
310 ((X509CRLEntryImpl)entry).encode(rCerts);
311 }
312 tmp.write(DerValue.tag_Sequence, rCerts);
313 }
314
315 if (extensions != null)
316 extensions.encode(tmp, isExplicit);
317
318 seq.write(DerValue.tag_Sequence, tmp);
319
320 tbsCertList = seq.toByteArray();
321 out.write(tbsCertList);
322 } catch (IOException e) {
323 throw new CRLException("Encoding error: " + e.getMessage());
324 }
325 }
326
327 /**
328 * Verifies that this CRL was signed using the
329 * private key that corresponds to the given public key.
330 *
331 * @param key the PublicKey used to carry out the verification.
332 *
333 * @exception NoSuchAlgorithmException on unsupported signature
334 * algorithms.
335 * @exception InvalidKeyException on incorrect key.
336 * @exception NoSuchProviderException if there's no default provider.
337 * @exception SignatureException on signature errors.
338 * @exception CRLException on encoding errors.
339 */
340 public void verify(PublicKey key)
341 throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
342 NoSuchProviderException, SignatureException {
343 verify(key, "");
344 }
345
346 /**
347 * Verifies that this CRL was signed using the
348 * private key that corresponds to the given public key,
349 * and that the signature verification was computed by
350 * the given provider.
351 *
352 * @param key the PublicKey used to carry out the verification.
353 * @param sigProvider the name of the signature provider.
354 *
355 * @exception NoSuchAlgorithmException on unsupported signature
356 * algorithms.
357 * @exception InvalidKeyException on incorrect key.
358 * @exception NoSuchProviderException on incorrect provider.
359 * @exception SignatureException on signature errors.
360 * @exception CRLException on encoding errors.
361 */
362 public synchronized void verify(PublicKey key, String sigProvider)
363 throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
364 NoSuchProviderException, SignatureException {
365
366 if (sigProvider == null) {
367 sigProvider = "";
368 }
369 if ((verifiedPublicKey != null) && verifiedPublicKey.equals(key)) {
370 // this CRL has already been successfully verified using
371 // this public key. Make sure providers match, too.
372 if (sigProvider.equals(verifiedProvider)) {
373 return;
374 }
375 }
376 if (signedCRL == null) {
377 throw new CRLException("Uninitialized CRL");
378 }
379 Signature sigVerf = null;
380 if (sigProvider.length() == 0) {
381 sigVerf = Signature.getInstance(sigAlgId.getName());
382 } else {
383 sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider);
384 }
385 sigVerf.initVerify(key);
386
387 if (tbsCertList == null) {
388 throw new CRLException("Uninitialized CRL");
389 }
390
391 sigVerf.update(tbsCertList, 0, tbsCertList.length);
392
393 if (!sigVerf.verify(signature)) {
394 throw new SignatureException("Signature does not match.");
395 }
396 verifiedPublicKey = key;
397 verifiedProvider = sigProvider;
398 }
399
400 /**
401 * Encodes an X.509 CRL, and signs it using the given key.
402 *
403 * @param key the private key used for signing.
404 * @param algorithm the name of the signature algorithm used.
405 *
406 * @exception NoSuchAlgorithmException on unsupported signature
407 * algorithms.
408 * @exception InvalidKeyException on incorrect key.
409 * @exception NoSuchProviderException on incorrect provider.
410 * @exception SignatureException on signature errors.
411 * @exception CRLException if any mandatory data was omitted.
412 */
413 public void sign(PrivateKey key, String algorithm)
414 throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
415 NoSuchProviderException, SignatureException {
416 sign(key, algorithm, null);
417 }
418
419 /**
420 * Encodes an X.509 CRL, and signs it using the given key.
421 *
422 * @param key the private key used for signing.
423 * @param algorithm the name of the signature algorithm used.
424 * @param provider the name of the provider.
425 *
426 * @exception NoSuchAlgorithmException on unsupported signature
427 * algorithms.
428 * @exception InvalidKeyException on incorrect key.
429 * @exception NoSuchProviderException on incorrect provider.
430 * @exception SignatureException on signature errors.
431 * @exception CRLException if any mandatory data was omitted.
432 */
433 public void sign(PrivateKey key, String algorithm, String provider)
434 throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
435 NoSuchProviderException, SignatureException {
436 try {
437 if (readOnly)
438 throw new CRLException("cannot over-write existing CRL");
439 Signature sigEngine = null;
440 if ((provider == null) || (provider.length() == 0))
441 sigEngine = Signature.getInstance(algorithm);
442 else
443 sigEngine = Signature.getInstance(algorithm, provider);
444
445 sigEngine.initSign(key);
446
447 // in case the name is reset
448 sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm());
449 infoSigAlgId = sigAlgId;
450
451 DerOutputStream out = new DerOutputStream();
452 DerOutputStream tmp = new DerOutputStream();
453
454 // encode crl info
455 encodeInfo(tmp);
456
457 // encode algorithm identifier
458 sigAlgId.encode(tmp);
459
460 // Create and encode the signature itself.
461 sigEngine.update(tbsCertList, 0, tbsCertList.length);
462 signature = sigEngine.sign();
463 tmp.putBitString(signature);
464
465 // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
466 out.write(DerValue.tag_Sequence, tmp);
467 signedCRL = out.toByteArray();
468 readOnly = true;
469
470 } catch (IOException e) {
471 throw new CRLException("Error while encoding data: " +
472 e.getMessage());
473 }
474 }
475
476 /**
477 * Returns a printable string of this CRL.
478 *
479 * @return value of this CRL in a printable form.
480 */
481 public String toString() {
482 StringBuffer sb = new StringBuffer();
483 sb.append("X.509 CRL v" + (version+1) + "\n");
484 if (sigAlgId != null)
485 sb.append("Signature Algorithm: " + sigAlgId.toString() +
486 ", OID=" + (sigAlgId.getOID()).toString() + "\n");
487 if (issuer != null)
488 sb.append("Issuer: " + issuer.toString() + "\n");
489 if (thisUpdate != null)
490 sb.append("\nThis Update: " + thisUpdate.toString() + "\n");
491 if (nextUpdate != null)
492 sb.append("Next Update: " + nextUpdate.toString() + "\n");
493 if (revokedCerts.isEmpty())
494 sb.append("\nNO certificates have been revoked\n");
495 else {
496 sb.append("\nRevoked Certificates: " + revokedCerts.size());
497 int i = 1;
498 for (Iterator<X509CRLEntry> iter = revokedCerts.values().iterator();
499 iter.hasNext(); i++)
500 sb.append("\n[" + i + "] " + iter.next().toString());
501 }
502 if (extensions != null) {
503 Collection<Extension> allExts = extensions.getAllExtensions();
504 Object[] objs = allExts.toArray();
505 sb.append("\nCRL Extensions: " + objs.length);
506 for (int i = 0; i < objs.length; i++) {
507 sb.append("\n[" + (i+1) + "]: ");
508 Extension ext = (Extension)objs[i];
509 try {
510 if (OIDMap.getClass(ext.getExtensionId()) == null) {
511 sb.append(ext.toString());
512 byte[] extValue = ext.getExtensionValue();
513 if (extValue != null) {
514 DerOutputStream out = new DerOutputStream();
515 out.putOctetString(extValue);
516 extValue = out.toByteArray();
517 HexDumpEncoder enc = new HexDumpEncoder();
518 sb.append("Extension unknown: "
519 + "DER encoded OCTET string =\n"
520 + enc.encodeBuffer(extValue) + "\n");
521 }
522 } else
523 sb.append(ext.toString()); // sub-class exists
524 } catch (Exception e) {
525 sb.append(", Error parsing this extension");
526 }
527 }
528 }
529 if (signature != null) {
530 HexDumpEncoder encoder = new HexDumpEncoder();
531 sb.append("\nSignature:\n" + encoder.encodeBuffer(signature)
532 + "\n");
533 } else
534 sb.append("NOT signed yet\n");
535 return sb.toString();
536 }
537
538 /**
539 * Checks whether the given certificate is on this CRL.
540 *
541 * @param cert the certificate to check for.
542 * @return true if the given certificate is on this CRL,
543 * false otherwise.
544 */
545 public boolean isRevoked(Certificate cert) {
546 if (revokedCerts.isEmpty() || (!(cert instanceof X509Certificate))) {
547 return false;
548 }
549 X509Certificate xcert = (X509Certificate) cert;
550 X509IssuerSerial issuerSerial = new X509IssuerSerial(xcert);
551 return revokedCerts.containsKey(issuerSerial);
552 }
553
554 /**
555 * Gets the version number from this CRL.
556 * The ASN.1 definition for this is:
557 * <pre>
558 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
559 * -- v3 does not apply to CRLs but appears for consistency
560 * -- with definition of Version for certs
561 * </pre>
562 * @return the version number, i.e. 1 or 2.
563 */
564 public int getVersion() {
565 return version+1;
566 }
567
568 /**
569 * Gets the issuer distinguished name from this CRL.
570 * The issuer name identifies the entity who has signed (and
571 * issued the CRL). The issuer name field contains an
572 * X.500 distinguished name (DN).
573 * The ASN.1 definition for this is:
574 * <pre>
575 * issuer Name
576 *
577 * Name ::= CHOICE { RDNSequence }
578 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
579 * RelativeDistinguishedName ::=
580 * SET OF AttributeValueAssertion
581 *
582 * AttributeValueAssertion ::= SEQUENCE {
583 * AttributeType,
584 * AttributeValue }
585 * AttributeType ::= OBJECT IDENTIFIER
586 * AttributeValue ::= ANY
587 * </pre>
588 * The Name describes a hierarchical name composed of attributes,
589 * such as country name, and corresponding values, such as US.
590 * The type of the component AttributeValue is determined by the
591 * AttributeType; in general it will be a directoryString.
592 * A directoryString is usually one of PrintableString,
593 * TeletexString or UniversalString.
594 * @return the issuer name.
595 */
596 public Principal getIssuerDN() {
597 return (Principal)issuer;
598 }
599
600 /**
601 * Return the issuer as X500Principal. Overrides method in X509CRL
602 * to provide a slightly more efficient version.
603 */
604 public X500Principal getIssuerX500Principal() {
605 if (issuerPrincipal == null) {
606 issuerPrincipal = issuer.asX500Principal();
607 }
608 return issuerPrincipal;
609 }
610
611 /**
612 * Gets the thisUpdate date from the CRL.
613 * The ASN.1 definition for this is:
614 *
615 * @return the thisUpdate date from the CRL.
616 */
617 public Date getThisUpdate() {
618 return (new Date(thisUpdate.getTime()));
619 }
620
621 /**
622 * Gets the nextUpdate date from the CRL.
623 *
624 * @return the nextUpdate date from the CRL, or null if
625 * not present.
626 */
627 public Date getNextUpdate() {
628 if (nextUpdate == null)
629 return null;
630 return (new Date(nextUpdate.getTime()));
631 }
632
633 /**
634 * Gets the CRL entry with the given serial number from this CRL.
635 *
636 * @return the entry with the given serial number, or <code>null</code> if
637 * no such entry exists in the CRL.
638 * @see X509CRLEntry
639 */
640 public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
641 if (revokedCerts.isEmpty()) {
642 return null;
643 }
644 // assume this is a direct CRL entry (cert and CRL issuer are the same)
645 X509IssuerSerial issuerSerial = new X509IssuerSerial
646 (getIssuerX500Principal(), serialNumber);
647 return revokedCerts.get(issuerSerial);
648 }
649
650 /**
651 * Gets the CRL entry for the given certificate.
652 */
653 public X509CRLEntry getRevokedCertificate(X509Certificate cert) {
654 if (revokedCerts.isEmpty()) {
655 return null;
656 }
657 X509IssuerSerial issuerSerial = new X509IssuerSerial(cert);
658 return revokedCerts.get(issuerSerial);
659 }
660
661 /**
662 * Gets all the revoked certificates from the CRL.
663 * A Set of X509CRLEntry.
664 *
665 * @return all the revoked certificates or <code>null</code> if there are
666 * none.
667 * @see X509CRLEntry
668 */
669 public Set<X509CRLEntry> getRevokedCertificates() {
670 if (revokedCerts.isEmpty()) {
671 return null;
672 } else {
673 return new HashSet<X509CRLEntry>(revokedCerts.values());
674 }
675 }
676
677 /**
678 * Gets the DER encoded CRL information, the
679 * <code>tbsCertList</code> from this CRL.
680 * This can be used to verify the signature independently.
681 *
682 * @return the DER encoded CRL information.
683 * @exception CRLException on encoding errors.
684 */
685 public byte[] getTBSCertList() throws CRLException {
686 if (tbsCertList == null)
687 throw new CRLException("Uninitialized CRL");
688 byte[] dup = new byte[tbsCertList.length];
689 System.arraycopy(tbsCertList, 0, dup, 0, dup.length);
690 return dup;
691 }
692
693 /**
694 * Gets the raw Signature bits from the CRL.
695 *
696 * @return the signature.
697 */
698 public byte[] getSignature() {
699 if (signature == null)
700 return null;
701 byte[] dup = new byte[signature.length];
702 System.arraycopy(signature, 0, dup, 0, dup.length);
703 return dup;
704 }
705
706 /**
707 * Gets the signature algorithm name for the CRL
708 * signature algorithm. For example, the string "SHA1withDSA".
709 * The ASN.1 definition for this is:
710 * <pre>
711 * AlgorithmIdentifier ::= SEQUENCE {
712 * algorithm OBJECT IDENTIFIER,
713 * parameters ANY DEFINED BY algorithm OPTIONAL }
714 * -- contains a value of the type
715 * -- registered for use with the
716 * -- algorithm object identifier value
717 * </pre>
718 *
719 * @return the signature algorithm name.
720 */
721 public String getSigAlgName() {
722 if (sigAlgId == null)
723 return null;
724 return sigAlgId.getName();
725 }
726
727 /**
728 * Gets the signature algorithm OID string from the CRL.
729 * An OID is represented by a set of positive whole number separated
730 * by ".", that means,<br>
731 * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
732 * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
733 * with DSA signature algorithm defined in
734 * <a href="http://www.ietf.org/rfc/rfc3279.txt">RFC 3279: Algorithms and
735 * Identifiers for the Internet X.509 Public Key Infrastructure Certificate
736 * and CRL Profile</a>.
737 *
738 * @return the signature algorithm oid string.
739 */
740 public String getSigAlgOID() {
741 if (sigAlgId == null)
742 return null;
743 ObjectIdentifier oid = sigAlgId.getOID();
744 return oid.toString();
745 }
746
747 /**
748 * Gets the DER encoded signature algorithm parameters from this
749 * CRL's signature algorithm. In most cases, the signature
750 * algorithm parameters are null, the parameters are usually
751 * supplied with the Public Key.
752 *
753 * @return the DER encoded signature algorithm parameters, or
754 * null if no parameters are present.
755 */
756 public byte[] getSigAlgParams() {
757 if (sigAlgId == null)
758 return null;
759 try {
760 return sigAlgId.getEncodedParams();
761 } catch (IOException e) {
762 return null;
763 }
764 }
765
766 /**
767 * return the AuthorityKeyIdentifier, if any.
768 *
769 * @returns AuthorityKeyIdentifier or null
770 * (if no AuthorityKeyIdentifierExtension)
771 * @throws IOException on error
772 */
773 public KeyIdentifier getAuthKeyId() throws IOException {
774 AuthorityKeyIdentifierExtension aki = getAuthKeyIdExtension();
775 if (aki != null) {
776 KeyIdentifier keyId = (KeyIdentifier)aki.get(aki.KEY_ID);
777 return keyId;
778 } else {
779 return null;
780 }
781 }
782
783 /**
784 * return the AuthorityKeyIdentifierExtension, if any.
785 *
786 * @returns AuthorityKeyIdentifierExtension or null (if no such extension)
787 * @throws IOException on error
788 */
789 public AuthorityKeyIdentifierExtension getAuthKeyIdExtension()
790 throws IOException {
791 Object obj = getExtension(PKIXExtensions.AuthorityKey_Id);
792 return (AuthorityKeyIdentifierExtension)obj;
793 }
794
795 /**
796 * return the CRLNumberExtension, if any.
797 *
798 * @returns CRLNumberExtension or null (if no such extension)
799 * @throws IOException on error
800 */
801 public CRLNumberExtension getCRLNumberExtension() throws IOException {
802 Object obj = getExtension(PKIXExtensions.CRLNumber_Id);
803 return (CRLNumberExtension)obj;
804 }
805
806 /**
807 * return the CRL number from the CRLNumberExtension, if any.
808 *
809 * @returns number or null (if no such extension)
810 * @throws IOException on error
811 */
812 public BigInteger getCRLNumber() throws IOException {
813 CRLNumberExtension numExt = getCRLNumberExtension();
814 if (numExt != null) {
815 BigInteger num = (BigInteger)numExt.get(numExt.NUMBER);
816 return num;
817 } else {
818 return null;
819 }
820 }
821
822 /**
823 * return the DeltaCRLIndicatorExtension, if any.
824 *
825 * @returns DeltaCRLIndicatorExtension or null (if no such extension)
826 * @throws IOException on error
827 */
828 public DeltaCRLIndicatorExtension getDeltaCRLIndicatorExtension()
829 throws IOException {
830
831 Object obj = getExtension(PKIXExtensions.DeltaCRLIndicator_Id);
832 return (DeltaCRLIndicatorExtension)obj;
833 }
834
835 /**
836 * return the base CRL number from the DeltaCRLIndicatorExtension, if any.
837 *
838 * @returns number or null (if no such extension)
839 * @throws IOException on error
840 */
841 public BigInteger getBaseCRLNumber() throws IOException {
842 DeltaCRLIndicatorExtension dciExt = getDeltaCRLIndicatorExtension();
843 if (dciExt != null) {
844 BigInteger num = (BigInteger)dciExt.get(dciExt.NUMBER);
845 return num;
846 } else {
847 return null;
848 }
849 }
850
851 /**
852 * return the IssuerAlternativeNameExtension, if any.
853 *
854 * @returns IssuerAlternativeNameExtension or null (if no such extension)
855 * @throws IOException on error
856 */
857 public IssuerAlternativeNameExtension getIssuerAltNameExtension()
858 throws IOException {
859 Object obj = getExtension(PKIXExtensions.IssuerAlternativeName_Id);
860 return (IssuerAlternativeNameExtension)obj;
861 }
862
863 /**
864 * return the IssuingDistributionPointExtension, if any.
865 *
866 * @returns IssuingDistributionPointExtension or null
867 * (if no such extension)
868 * @throws IOException on error
869 */
870 public IssuingDistributionPointExtension
871 getIssuingDistributionPointExtension() throws IOException {
872
873 Object obj = getExtension(PKIXExtensions.IssuingDistributionPoint_Id);
874 return (IssuingDistributionPointExtension) obj;
875 }
876
877 /**
878 * Return true if a critical extension is found that is
879 * not supported, otherwise return false.
880 */
881 public boolean hasUnsupportedCriticalExtension() {
882 if (extensions == null)
883 return false;
884 return extensions.hasUnsupportedCriticalExtension();
885 }
886
887 /**
888 * Gets a Set of the extension(s) marked CRITICAL in the
889 * CRL. In the returned set, each extension is represented by
890 * its OID string.
891 *
892 * @return a set of the extension oid strings in the
893 * CRL that are marked critical.
894 */
895 public Set<String> getCriticalExtensionOIDs() {
896 if (extensions == null) {
897 return null;
898 }
899 Set<String> extSet = new HashSet<String>();
900 for (Extension ex : extensions.getAllExtensions()) {
901 if (ex.isCritical()) {
902 extSet.add(ex.getExtensionId().toString());
903 }
904 }
905 return extSet;
906 }
907
908 /**
909 * Gets a Set of the extension(s) marked NON-CRITICAL in the
910 * CRL. In the returned set, each extension is represented by
911 * its OID string.
912 *
913 * @return a set of the extension oid strings in the
914 * CRL that are NOT marked critical.
915 */
916 public Set<String> getNonCriticalExtensionOIDs() {
917 if (extensions == null) {
918 return null;
919 }
920 Set<String> extSet = new HashSet<String>();
921 for (Extension ex : extensions.getAllExtensions()) {
922 if (!ex.isCritical()) {
923 extSet.add(ex.getExtensionId().toString());
924 }
925 }
926 return extSet;
927 }
928
929 /**
930 * Gets the DER encoded OCTET string for the extension value
931 * (<code>extnValue</code>) identified by the passed in oid String.
932 * The <code>oid</code> string is
933 * represented by a set of positive whole number separated
934 * by ".", that means,<br>
935 * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
936 *
937 * @param oid the Object Identifier value for the extension.
938 * @return the der encoded octet string of the extension value.
939 */
940 public byte[] getExtensionValue(String oid) {
941 if (extensions == null)
942 return null;
943 try {
944 String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
945 Extension crlExt = null;
946
947 if (extAlias == null) { // may be unknown
948 ObjectIdentifier findOID = new ObjectIdentifier(oid);
949 Extension ex = null;
950 ObjectIdentifier inCertOID;
951 for (Enumeration<Extension> e = extensions.getElements();
952 e.hasMoreElements();) {
953 ex = e.nextElement();
954 inCertOID = ex.getExtensionId();
955 if (inCertOID.equals(findOID)) {
956 crlExt = ex;
957 break;
958 }
959 }
960 } else
961 crlExt = extensions.get(extAlias);
962 if (crlExt == null)
963 return null;
964 byte[] extData = crlExt.getExtensionValue();
965 if (extData == null)
966 return null;
967 DerOutputStream out = new DerOutputStream();
968 out.putOctetString(extData);
969 return out.toByteArray();
970 } catch (Exception e) {
971 return null;
972 }
973 }
974
975 /**
976 * get an extension
977 *
978 * @param oid ObjectIdentifier of extension desired
979 * @returns Object of type <extension> or null, if not found
980 * @throws IOException on error
981 */
982 public Object getExtension(ObjectIdentifier oid) {
983 if (extensions == null)
984 return null;
985
986 // XXX Consider cloning this
987 return extensions.get(OIDMap.getName(oid));
988 }
989
990 /*
991 * Parses an X.509 CRL, should be used only by constructors.
992 */
993 private void parse(DerValue val) throws CRLException, IOException {
994 // check if can over write the certificate
995 if (readOnly)
996 throw new CRLException("cannot over-write existing CRL");
997
998 if ( val.getData() == null || val.tag != DerValue.tag_Sequence)
999 throw new CRLException("Invalid DER-encoded CRL data");
1000
1001 signedCRL = val.toByteArray();
1002 DerValue seq[] = new DerValue[3];
1003
1004 seq[0] = val.data.getDerValue();
1005 seq[1] = val.data.getDerValue();
1006 seq[2] = val.data.getDerValue();
1007
1008 if (val.data.available() != 0)
1009 throw new CRLException("signed overrun, bytes = "
1010 + val.data.available());
1011
1012 if (seq[0].tag != DerValue.tag_Sequence)
1013 throw new CRLException("signed CRL fields invalid");
1014
1015 sigAlgId = AlgorithmId.parse(seq[1]);
1016 signature = seq[2].getBitString();
1017
1018 if (seq[1].data.available() != 0)
1019 throw new CRLException("AlgorithmId field overrun");
1020
1021 if (seq[2].data.available() != 0)
1022 throw new CRLException("Signature field overrun");
1023
1024 // the tbsCertsList
1025 tbsCertList = seq[0].toByteArray();
1026
1027 // parse the information
1028 DerInputStream derStrm = seq[0].data;
1029 DerValue tmp;
1030 byte nextByte;
1031
1032 // version (optional if v1)
1033 version = 0; // by default, version = v1 == 0
1034 nextByte = (byte)derStrm.peekByte();
1035 if (nextByte == DerValue.tag_Integer) {
1036 version = derStrm.getInteger();
1037 if (version != 1) // i.e. v2
1038 throw new CRLException("Invalid version");
1039 }
1040 tmp = derStrm.getDerValue();
1041
1042 // signature
1043 AlgorithmId tmpId = AlgorithmId.parse(tmp);
1044
1045 // the "inner" and "outer" signature algorithms must match
1046 if (! tmpId.equals(sigAlgId))
1047 throw new CRLException("Signature algorithm mismatch");
1048 infoSigAlgId = tmpId;
1049
1050 // issuer
1051 issuer = new X500Name(derStrm);
1052 if (issuer.isEmpty()) {
1053 throw new CRLException("Empty issuer DN not allowed in X509CRLs");
1054 }
1055
1056 // thisUpdate
1057 // check if UTCTime encoded or GeneralizedTime
1058
1059 nextByte = (byte)derStrm.peekByte();
1060 if (nextByte == DerValue.tag_UtcTime) {
1061 thisUpdate = derStrm.getUTCTime();
1062 } else if (nextByte == DerValue.tag_GeneralizedTime) {
1063 thisUpdate = derStrm.getGeneralizedTime();
1064 } else {
1065 throw new CRLException("Invalid encoding for thisUpdate"
1066 + " (tag=" + nextByte + ")");
1067 }
1068
1069 if (derStrm.available() == 0)
1070 return; // done parsing no more optional fields present
1071
1072 // nextUpdate (optional)
1073 nextByte = (byte)derStrm.peekByte();
1074 if (nextByte == DerValue.tag_UtcTime) {
1075 nextUpdate = derStrm.getUTCTime();
1076 } else if (nextByte == DerValue.tag_GeneralizedTime) {
1077 nextUpdate = derStrm.getGeneralizedTime();
1078 } // else it is not present
1079
1080 if (derStrm.available() == 0)
1081 return; // done parsing no more optional fields present
1082
1083 // revokedCertificates (optional)
1084 nextByte = (byte)derStrm.peekByte();
1085 if ((nextByte == DerValue.tag_SequenceOf)
1086 && (! ((nextByte & 0x0c0) == 0x080))) {
1087 DerValue[] badCerts = derStrm.getSequence(4);
1088
1089 X500Principal crlIssuer = getIssuerX500Principal();
1090 X500Principal badCertIssuer = crlIssuer;
1091 for (int i = 0; i < badCerts.length; i++) {
1092 X509CRLEntryImpl entry = new X509CRLEntryImpl(badCerts[i]);
1093 badCertIssuer = getCertIssuer(entry, badCertIssuer);
1094 entry.setCertificateIssuer(crlIssuer, badCertIssuer);
1095 X509IssuerSerial issuerSerial = new X509IssuerSerial
1096 (badCertIssuer, entry.getSerialNumber());
1097 revokedCerts.put(issuerSerial, entry);
1098 }
1099 }
1100
1101 if (derStrm.available() == 0)
1102 return; // done parsing no extensions
1103
1104 // crlExtensions (optional)
1105 tmp = derStrm.getDerValue();
1106 if (tmp.isConstructed() && tmp.isContextSpecific((byte)0)) {
1107 extensions = new CRLExtensions(tmp.data);
1108 }
1109 readOnly = true;
1110 }
1111
1112 /**
1113 * Extract the issuer X500Principal from an X509CRL. Parses the encoded
1114 * form of the CRL to preserve the principal's ASN.1 encoding.
1115 *
1116 * Called by java.security.cert.X509CRL.getIssuerX500Principal().
1117 */
1118 public static X500Principal getIssuerX500Principal(X509CRL crl) {
1119 try {
1120 byte[] encoded = crl.getEncoded();
1121 DerInputStream derIn = new DerInputStream(encoded);
1122 DerValue tbsCert = derIn.getSequence(3)[0];
1123 DerInputStream tbsIn = tbsCert.data;
1124
1125 DerValue tmp;
1126 // skip version number if present
1127 byte nextByte = (byte)tbsIn.peekByte();
1128 if (nextByte == DerValue.tag_Integer) {
1129 tmp = tbsIn.getDerValue();
1130 }
1131
1132 tmp = tbsIn.getDerValue(); // skip signature
1133 tmp = tbsIn.getDerValue(); // issuer
1134 byte[] principalBytes = tmp.toByteArray();
1135 return new X500Principal(principalBytes);
1136 } catch (Exception e) {
1137 throw new RuntimeException("Could not parse issuer", e);
1138 }
1139 }
1140
1141 /**
1142 * Returned the encoding of the given certificate for internal use.
1143 * Callers must guarantee that they neither modify it nor expose it
1144 * to untrusted code. Uses getEncodedInternal() if the certificate
1145 * is instance of X509CertImpl, getEncoded() otherwise.
1146 */
1147 public static byte[] getEncodedInternal(X509CRL crl) throws CRLException {
1148 if (crl instanceof X509CRLImpl) {
1149 return ((X509CRLImpl)crl).getEncodedInternal();
1150 } else {
1151 return crl.getEncoded();
1152 }
1153 }
1154
1155 /**
1156 * Utility method to convert an arbitrary instance of X509CRL
1157 * to a X509CRLImpl. Does a cast if possible, otherwise reparses
1158 * the encoding.
1159 */
1160 public static X509CRLImpl toImpl(X509CRL crl)
1161 throws CRLException {
1162 if (crl instanceof X509CRLImpl) {
1163 return (X509CRLImpl)crl;
1164 } else {
1165 return X509Factory.intern(crl);
1166 }
1167 }
1168
1169 /**
1170 * Returns the X500 certificate issuer DN of a CRL entry.
1171 *
1172 * @param entry the entry to check
1173 * @param prevCertIssuer the previous entry's certificate issuer
1174 * @return the X500Principal in a CertificateIssuerExtension, or
1175 * prevCertIssuer if it does not exist
1176 */
1177 private X500Principal getCertIssuer(X509CRLEntryImpl entry,
1178 X500Principal prevCertIssuer) throws IOException {
1179
1180 CertificateIssuerExtension ciExt =
1181 entry.getCertificateIssuerExtension();
1182 if (ciExt != null) {
1183 GeneralNames names = (GeneralNames)
1184 ciExt.get(CertificateIssuerExtension.ISSUER);
1185 X500Name issuerDN = (X500Name) names.get(0).getName();
1186 return issuerDN.asX500Principal();
1187 } else {
1188 return prevCertIssuer;
1189 }
1190 }
1191
1192 /**
1193 * Immutable X.509 Certificate Issuer DN and serial number pair
1194 */
1195 private final static class X509IssuerSerial {
1196 final X500Principal issuer;
1197 final BigInteger serial;
1198 volatile int hashcode = 0;
1199
1200 /**
1201 * Create an X509IssuerSerial.
1202 *
1203 * @param issuer the issuer DN
1204 * @param serial the serial number
1205 */
1206 X509IssuerSerial(X500Principal issuer, BigInteger serial) {
1207 this.issuer = issuer;
1208 this.serial = serial;
1209 }
1210
1211 /**
1212 * Construct an X509IssuerSerial from an X509Certificate.
1213 */
1214 X509IssuerSerial(X509Certificate cert) {
1215 this(cert.getIssuerX500Principal(), cert.getSerialNumber());
1216 }
1217
1218 /**
1219 * Returns the issuer.
1220 *
1221 * @return the issuer
1222 */
1223 X500Principal getIssuer() {
1224 return issuer;
1225 }
1226
1227 /**
1228 * Returns the serial number.
1229 *
1230 * @return the serial number
1231 */
1232 BigInteger getSerial() {
1233 return serial;
1234 }
1235
1236 /**
1237 * Compares this X509Serial with another and returns true if they
1238 * are equivalent.
1239 *
1240 * @param o the other object to compare with
1241 * @return true if equal, false otherwise
1242 */
1243 public boolean equals(Object o) {
1244 if (o == this) {
1245 return true;
1246 }
1247
1248 if (!(o instanceof X509IssuerSerial)) {
1249 return false;
1250 }
1251
1252 X509IssuerSerial other = (X509IssuerSerial) o;
1253 if (serial.equals(other.getSerial()) &&
1254 issuer.equals(other.getIssuer())) {
1255 return true;
1256 }
1257 return false;
1258 }
1259
1260 /**
1261 * Returns a hash code value for this X509IssuerSerial.
1262 *
1263 * @return the hash code value
1264 */
1265 public int hashCode() {
1266 if (hashcode == 0) {
1267 int result = 17;
1268 result = 37*result + issuer.hashCode();
1269 result = 37*result + serial.hashCode();
1270 hashcode = result;
1271 }
1272 return hashcode;
1273 }
1274 }
1275}