2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 * @author Alexander Y. Kleymenov
23 package org.apache.harmony.security.x509;
25 import java.io.IOException;
26 import java.math.BigInteger;
27 import java.util.Arrays;
28 import java.util.Date;
29 import java.util.Iterator;
30 import java.util.List;
31 import javax.security.auth.x500.X500Principal;
32 import org.apache.harmony.security.asn1.ASN1Explicit;
33 import org.apache.harmony.security.asn1.ASN1Integer;
34 import org.apache.harmony.security.asn1.ASN1Sequence;
35 import org.apache.harmony.security.asn1.ASN1SequenceOf;
36 import org.apache.harmony.security.asn1.ASN1Type;
37 import org.apache.harmony.security.asn1.BerInputStream;
38 import org.apache.harmony.security.x501.Name;
42 * The class encapsulates the ASN.1 DER encoding/decoding work
43 * with TBSCertList structure which is the part of X.509 CRL
44 * (as specified in RFC 3280 -
45 * Internet X.509 Public Key Infrastructure.
46 * Certificate and Certificate Revocation List (CRL) Profile.
47 * http://www.ietf.org/rfc/rfc3280.txt):
50 * TBSCertList ::= SEQUENCE {
51 * version Version OPTIONAL,
52 * -- if present, MUST be v2
53 * signature AlgorithmIdentifier,
56 * nextUpdate Time OPTIONAL,
57 * revokedCertificates SEQUENCE OF SEQUENCE {
58 * userCertificate CertificateSerialNumber,
59 * revocationDate Time,
60 * crlEntryExtensions Extensions OPTIONAL
61 * -- if present, MUST be v2
63 * crlExtensions [0] EXPLICIT Extensions OPTIONAL
64 * -- if present, MUST be v2
68 public class TBSCertList {
70 // the value of version field of the structure
71 private final int version;
72 // the value of signature field of the structure
73 private final AlgorithmIdentifier signature;
74 // the value of issuer field of the structure
75 private final Name issuer;
76 // the value of thisUpdate of the structure
77 private final Date thisUpdate;
78 // the value of nextUpdate of the structure
79 private final Date nextUpdate;
80 // the value of revokedCertificates of the structure
81 private final List revokedCertificates;
82 // the value of crlExtensions field of the structure
83 private final Extensions crlExtensions;
84 // the ASN.1 encoded form of TBSCertList
85 private byte[] encoding;
87 public static class RevokedCertificate {
88 private final BigInteger userCertificate;
89 private final Date revocationDate;
90 private final Extensions crlEntryExtensions;
92 private boolean issuerRetrieved;
93 private X500Principal issuer;
94 private byte[] encoding;
96 public RevokedCertificate(BigInteger userCertificate,
97 Date revocationDate, Extensions crlEntryExtensions) {
98 this.userCertificate = userCertificate;
99 this.revocationDate = revocationDate;
100 this.crlEntryExtensions = crlEntryExtensions;
103 public Extensions getCrlEntryExtensions() {
104 return crlEntryExtensions;
107 public BigInteger getUserCertificate() {
108 return userCertificate;
111 public Date getRevocationDate() {
112 return revocationDate;
116 * Returns the value of Certificate Issuer Extension, if it is
119 public X500Principal getIssuer() {
120 if (crlEntryExtensions == null) {
123 if (!issuerRetrieved) {
126 crlEntryExtensions.valueOfCertificateIssuerExtension();
127 } catch (IOException e) {
130 issuerRetrieved = true;
135 public byte[] getEncoded() {
136 if (encoding == null) {
137 encoding = ASN1.encode(this);
142 public boolean equals(Object rc) {
143 if (!(rc instanceof RevokedCertificate)) {
146 RevokedCertificate rcert = (RevokedCertificate) rc;
147 return userCertificate.equals(rcert.userCertificate)
148 && ((revocationDate.getTime() / 1000)
149 == (rcert.revocationDate.getTime() / 1000))
150 && ((crlEntryExtensions == null)
151 ? rcert.crlEntryExtensions == null
152 : crlEntryExtensions.equals(rcert.crlEntryExtensions));
155 public int hashCode() {
156 return userCertificate.hashCode() * 37 + (int)revocationDate.getTime() / 1000
157 + (crlEntryExtensions == null ? 0 : crlEntryExtensions.hashCode());
161 * Places the string representation of extension value
162 * into the StringBuffer object.
164 public void dumpValue(StringBuffer buffer, String prefix) {
165 buffer.append(prefix).append("Certificate Serial Number: ")
166 .append(userCertificate).append('\n');
167 buffer.append(prefix).append("Revocation Date: ")
168 .append(revocationDate);
169 if (crlEntryExtensions != null) {
170 buffer.append('\n').append(prefix)
171 .append("CRL Entry Extensions: [");
172 crlEntryExtensions.dumpValue(buffer, prefix + " ");
173 buffer.append(prefix).append(']');
177 public static final ASN1Sequence ASN1 = new ASN1Sequence(
178 new ASN1Type[] {ASN1Integer.getInstance(), Time.ASN1,
184 protected Object getDecodedObject(BerInputStream in) {
185 Object[] values = (Object[]) in.content;
187 return new RevokedCertificate(
188 new BigInteger((byte[]) values[0]),
190 (Extensions) values[2]
194 protected void getValues(Object object, Object[] values) {
195 RevokedCertificate rcert = (RevokedCertificate) object;
197 values[0] = rcert.userCertificate.toByteArray();
198 values[1] = rcert.revocationDate;
199 values[2] = rcert.crlEntryExtensions;
205 * Constructs the instance of TBSCertList without optional fields.
206 * Take a note, that regarding to the rfc 3280 (p. 49):
207 * "When CRLs are issued, the CRLs MUST be version 2 CRLs, include the date
208 * by which the next CRL will be issued in the nextUpdate field (section
209 * 5.1.2.5), include the CRL number extension (section 5.2.3), and include
210 * the authority key identifier extension (section 5.2.1). Conforming
211 * applications that support CRLs are REQUIRED to process both version 1 and
212 * version 2 complete CRLs that provide revocation information for all
213 * certificates issued by one CA. Conforming applications are NOT REQUIRED
214 * to support processing of delta CRLs, indirect CRLs, or CRLs with a scope
215 * other than all certificates issued by one CA."
216 * @param signature: AlgorithmIdentifier
217 * @param issuer: Name
218 * @param thisUpdate: Time
220 public TBSCertList(AlgorithmIdentifier signature,
221 Name issuer, Date thisUpdate) {
223 this.signature = signature;
224 this.issuer = issuer;
225 this.thisUpdate = thisUpdate;
226 this.nextUpdate = null;
227 this.revokedCertificates = null;
228 this.crlExtensions = null;
232 * Constructs the instance of TBSCertList with all optional fields
233 * @param version: version of the CRL. Should be 1 or 2.
234 * Note that if the version of CRL is 1, then nextUpdate,
235 * crlExtensions fields of CRL and crlEntryExtensions field
236 * of CRL entry must not be presented in CRL.
237 * FIXME: do check for it.
238 * @param signature: AlgorithmIdentifier
239 * @param issuer: Name
240 * @param thisUpdate: Time
241 * @param nextUpdate: Time
242 * @param revokedCertificates: List
243 * @param crlExtensions: Extensions
245 public TBSCertList(int version, AlgorithmIdentifier signature,
246 Name issuer, Date thisUpdate, Date nextUpdate,
247 List revokedCertificates, Extensions crlExtensions) {
248 this.version = version;
249 this.signature = signature;
250 this.issuer = issuer;
251 this.thisUpdate = thisUpdate;
252 this.nextUpdate = nextUpdate;
253 this.revokedCertificates = revokedCertificates;
254 this.crlExtensions = crlExtensions;
257 // Constructs the object with associated ASN.1 encoding
258 private TBSCertList(int version, AlgorithmIdentifier signature,
259 Name issuer, Date thisUpdate, Date nextUpdate,
260 List revokedCertificates, Extensions crlExtensions,
262 this.version = version;
263 this.signature = signature;
264 this.issuer = issuer;
265 this.thisUpdate = thisUpdate;
266 this.nextUpdate = nextUpdate;
267 this.revokedCertificates = revokedCertificates;
268 this.crlExtensions = crlExtensions;
269 this.encoding = encoding;
273 * Returns the value of version field of the structure.
276 public int getVersion() {
281 * Returns the value of signature field of the structure.
284 public AlgorithmIdentifier getSignature() {
289 * Returns the value of issuer field of the structure.
292 public Name getIssuer() {
297 * Returns the value of thisUpdate field of the structure.
300 public Date getThisUpdate() {
305 * Returns the value of nextUpdate field of the structure.
308 public Date getNextUpdate() {
313 * Returns the value of revokedCertificates field of the structure.
314 * @return revokedCertificates
316 public List getRevokedCertificates() {
317 return revokedCertificates;
321 * Returns the value of crlExtensions field of the structure.
324 public Extensions getCrlExtensions() {
325 return crlExtensions;
329 * Returns ASN.1 encoded form of this X.509 TBSCertList value.
330 * @return a byte array containing ASN.1 encode form.
332 public byte[] getEncoded() {
333 if (encoding == null) {
334 encoding = ASN1.encode(this);
339 public boolean equals(Object tbs) {
340 if (!(tbs instanceof TBSCertList)) {
343 TBSCertList tbscert = (TBSCertList) tbs;
344 return (version == tbscert.version)
345 && (signature.equals(tbscert.signature))
346 // FIXME use Name.equals when it will be implemented
347 && (Arrays.equals(issuer.getEncoded(), tbscert.issuer.getEncoded()))
348 && ((thisUpdate.getTime() / 1000)
349 == (tbscert.thisUpdate.getTime() / 1000))
350 && ((nextUpdate == null)
351 ? tbscert.nextUpdate == null
352 : ((nextUpdate.getTime() / 1000)
353 == (tbscert.nextUpdate.getTime() / 1000)))
354 && ((((revokedCertificates == null)
355 || (tbscert.revokedCertificates == null))
356 && (revokedCertificates == tbscert.revokedCertificates))
357 || (revokedCertificates.containsAll(tbscert.revokedCertificates)
358 && (revokedCertificates.size()
359 == tbscert.revokedCertificates.size())))
360 && ((crlExtensions == null)
361 ? tbscert.crlExtensions == null
362 : crlExtensions.equals(tbscert.crlExtensions));
365 public int hashCode() {
366 return ((version * 37 + signature.hashCode()) * 37
367 + issuer.getEncoded().hashCode()) * 37
368 + (int)thisUpdate.getTime() / 1000;
372 * Places the string representation of extension value
373 * into the StringBuffer object.
375 public void dumpValue(StringBuffer buffer) {
376 buffer.append("X.509 CRL v").append(version);
377 buffer.append("\nSignature Algorithm: [");
378 signature.dumpValue(buffer);
380 buffer.append("\nIssuer: ").append(issuer.getName(X500Principal.RFC2253));
381 buffer.append("\n\nThis Update: ").append(thisUpdate);
382 buffer.append("\nNext Update: ").append(nextUpdate).append('\n');
383 if (revokedCertificates != null) {
384 buffer.append("\nRevoked Certificates: ")
385 .append(revokedCertificates.size()).append(" [");
387 for (Iterator it = revokedCertificates.iterator();it.hasNext();) {
388 buffer.append("\n [").append(number++).append(']');
389 ((RevokedCertificate) it.next()).dumpValue(buffer, " ");
392 buffer.append("]\n");
394 if (crlExtensions != null) {
395 buffer.append("\nCRL Extensions: ")
396 .append(crlExtensions.size()).append(" [");
397 crlExtensions.dumpValue(buffer, " ");
398 buffer.append("]\n");
403 * X.509 TBSCertList encoder/decoder.
405 public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
406 ASN1Integer.getInstance(), // version
407 AlgorithmIdentifier.ASN1, // signature
409 Time.ASN1, // thisUpdate
410 Time.ASN1, // nextUpdate
411 new ASN1SequenceOf(RevokedCertificate.ASN1), // revokedCertificates
412 new ASN1Explicit(0, Extensions.ASN1) // crlExtensions
421 protected Object getDecodedObject(BerInputStream in)
423 Object[] values = (Object[]) in.content;
424 return new TBSCertList(
427 : ASN1Integer.toIntValue(values[0])+1,
428 (AlgorithmIdentifier) values[1],
433 (Extensions) values[6],
438 protected void getValues(Object object, Object[] values) {
439 TBSCertList tbs = (TBSCertList) object;
440 values[0] = (tbs.version > 1)
441 ? ASN1Integer.fromIntValue(tbs.version - 1) : null;
442 values[1] = tbs.signature;
443 values[2] = tbs.issuer;
444 values[3] = tbs.thisUpdate;
445 values[4] = tbs.nextUpdate;
446 values[5] = tbs.revokedCertificates;
447 values[6] = tbs.crlExtensions;