| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @author Alexander Y. Kleymenov |
| * @version $Revision$ |
| */ |
| |
| package org.apache.harmony.security.x509; |
| |
| import java.io.IOException; |
| import java.math.BigInteger; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.List; |
| import javax.security.auth.x500.X500Principal; |
| import org.apache.harmony.security.asn1.ASN1Explicit; |
| import org.apache.harmony.security.asn1.ASN1Integer; |
| import org.apache.harmony.security.asn1.ASN1Sequence; |
| import org.apache.harmony.security.asn1.ASN1SequenceOf; |
| import org.apache.harmony.security.asn1.ASN1Type; |
| import org.apache.harmony.security.asn1.BerInputStream; |
| import org.apache.harmony.security.x501.Name; |
| |
| |
| /** |
| * The class encapsulates the ASN.1 DER encoding/decoding work |
| * with TBSCertList structure which is the part of X.509 CRL |
| * (as specified in RFC 3280 - |
| * Internet X.509 Public Key Infrastructure. |
| * Certificate and Certificate Revocation List (CRL) Profile. |
| * http://www.ietf.org/rfc/rfc3280.txt): |
| * |
| * <pre> |
| * TBSCertList ::= SEQUENCE { |
| * version Version OPTIONAL, |
| * -- if present, MUST be v2 |
| * signature AlgorithmIdentifier, |
| * issuer Name, |
| * thisUpdate Time, |
| * nextUpdate Time OPTIONAL, |
| * revokedCertificates SEQUENCE OF SEQUENCE { |
| * userCertificate CertificateSerialNumber, |
| * revocationDate Time, |
| * crlEntryExtensions Extensions OPTIONAL |
| * -- if present, MUST be v2 |
| * } OPTIONAL, |
| * crlExtensions [0] EXPLICIT Extensions OPTIONAL |
| * -- if present, MUST be v2 |
| * } |
| * </pre> |
| */ |
| public class TBSCertList { |
| |
| // the value of version field of the structure |
| private final int version; |
| // the value of signature field of the structure |
| private final AlgorithmIdentifier signature; |
| // the value of issuer field of the structure |
| private final Name issuer; |
| // the value of thisUpdate of the structure |
| private final Date thisUpdate; |
| // the value of nextUpdate of the structure |
| private final Date nextUpdate; |
| // the value of revokedCertificates of the structure |
| private final List revokedCertificates; |
| // the value of crlExtensions field of the structure |
| private final Extensions crlExtensions; |
| // the ASN.1 encoded form of TBSCertList |
| private byte[] encoding; |
| |
| public static class RevokedCertificate { |
| private final BigInteger userCertificate; |
| private final Date revocationDate; |
| private final Extensions crlEntryExtensions; |
| |
| private boolean issuerRetrieved; |
| private X500Principal issuer; |
| private byte[] encoding; |
| |
| public RevokedCertificate(BigInteger userCertificate, |
| Date revocationDate, Extensions crlEntryExtensions) { |
| this.userCertificate = userCertificate; |
| this.revocationDate = revocationDate; |
| this.crlEntryExtensions = crlEntryExtensions; |
| } |
| |
| public Extensions getCrlEntryExtensions() { |
| return crlEntryExtensions; |
| } |
| |
| public BigInteger getUserCertificate() { |
| return userCertificate; |
| } |
| |
| public Date getRevocationDate() { |
| return revocationDate; |
| } |
| |
| /** |
| * Returns the value of Certificate Issuer Extension, if it is |
| * presented. |
| */ |
| public X500Principal getIssuer() { |
| if (crlEntryExtensions == null) { |
| return null; |
| } |
| if (!issuerRetrieved) { |
| try { |
| issuer = |
| crlEntryExtensions.valueOfCertificateIssuerExtension(); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| issuerRetrieved = true; |
| } |
| return issuer; |
| } |
| |
| public byte[] getEncoded() { |
| if (encoding == null) { |
| encoding = ASN1.encode(this); |
| } |
| return encoding; |
| } |
| |
| public boolean equals(Object rc) { |
| if (!(rc instanceof RevokedCertificate)) { |
| return false; |
| } |
| RevokedCertificate rcert = (RevokedCertificate) rc; |
| return userCertificate.equals(rcert.userCertificate) |
| && ((revocationDate.getTime() / 1000) |
| == (rcert.revocationDate.getTime() / 1000)) |
| && ((crlEntryExtensions == null) |
| ? rcert.crlEntryExtensions == null |
| : crlEntryExtensions.equals(rcert.crlEntryExtensions)); |
| } |
| |
| public int hashCode() { |
| return userCertificate.hashCode() * 37 + (int)revocationDate.getTime() / 1000 |
| + (crlEntryExtensions == null ? 0 : crlEntryExtensions.hashCode()); |
| } |
| |
| /** |
| * Places the string representation of extension value |
| * into the StringBuffer object. |
| */ |
| public void dumpValue(StringBuffer buffer, String prefix) { |
| buffer.append(prefix).append("Certificate Serial Number: ") |
| .append(userCertificate).append('\n'); |
| buffer.append(prefix).append("Revocation Date: ") |
| .append(revocationDate); |
| if (crlEntryExtensions != null) { |
| buffer.append('\n').append(prefix) |
| .append("CRL Entry Extensions: ["); |
| crlEntryExtensions.dumpValue(buffer, prefix + " "); |
| buffer.append(prefix).append(']'); |
| } |
| } |
| |
| public static final ASN1Sequence ASN1 = new ASN1Sequence( |
| new ASN1Type[] {ASN1Integer.getInstance(), Time.ASN1, |
| Extensions.ASN1}) { |
| { |
| setOptional(2); |
| } |
| |
| protected Object getDecodedObject(BerInputStream in) { |
| Object[] values = (Object[]) in.content; |
| |
| return new RevokedCertificate( |
| new BigInteger((byte[]) values[0]), |
| (Date) values[1], |
| (Extensions) values[2] |
| ); |
| } |
| |
| protected void getValues(Object object, Object[] values) { |
| RevokedCertificate rcert = (RevokedCertificate) object; |
| |
| values[0] = rcert.userCertificate.toByteArray(); |
| values[1] = rcert.revocationDate; |
| values[2] = rcert.crlEntryExtensions; |
| } |
| }; |
| } |
| |
| /** |
| * Constructs the instance of TBSCertList without optional fields. |
| * Take a note, that regarding to the rfc 3280 (p. 49): |
| * "When CRLs are issued, the CRLs MUST be version 2 CRLs, include the date |
| * by which the next CRL will be issued in the nextUpdate field (section |
| * 5.1.2.5), include the CRL number extension (section 5.2.3), and include |
| * the authority key identifier extension (section 5.2.1). Conforming |
| * applications that support CRLs are REQUIRED to process both version 1 and |
| * version 2 complete CRLs that provide revocation information for all |
| * certificates issued by one CA. Conforming applications are NOT REQUIRED |
| * to support processing of delta CRLs, indirect CRLs, or CRLs with a scope |
| * other than all certificates issued by one CA." |
| * @param signature: AlgorithmIdentifier |
| * @param issuer: Name |
| * @param thisUpdate: Time |
| */ |
| public TBSCertList(AlgorithmIdentifier signature, |
| Name issuer, Date thisUpdate) { |
| this.version = 1; |
| this.signature = signature; |
| this.issuer = issuer; |
| this.thisUpdate = thisUpdate; |
| this.nextUpdate = null; |
| this.revokedCertificates = null; |
| this.crlExtensions = null; |
| } |
| |
| /** |
| * Constructs the instance of TBSCertList with all optional fields |
| * @param version: version of the CRL. Should be 1 or 2. |
| * Note that if the version of CRL is 1, then nextUpdate, |
| * crlExtensions fields of CRL and crlEntryExtensions field |
| * of CRL entry must not be presented in CRL. |
| * FIXME: do check for it. |
| * @param signature: AlgorithmIdentifier |
| * @param issuer: Name |
| * @param thisUpdate: Time |
| * @param nextUpdate: Time |
| * @param revokedCertificates: List |
| * @param crlExtensions: Extensions |
| */ |
| public TBSCertList(int version, AlgorithmIdentifier signature, |
| Name issuer, Date thisUpdate, Date nextUpdate, |
| List revokedCertificates, Extensions crlExtensions) { |
| this.version = version; |
| this.signature = signature; |
| this.issuer = issuer; |
| this.thisUpdate = thisUpdate; |
| this.nextUpdate = nextUpdate; |
| this.revokedCertificates = revokedCertificates; |
| this.crlExtensions = crlExtensions; |
| } |
| |
| // Constructs the object with associated ASN.1 encoding |
| private TBSCertList(int version, AlgorithmIdentifier signature, |
| Name issuer, Date thisUpdate, Date nextUpdate, |
| List revokedCertificates, Extensions crlExtensions, |
| byte[] encoding) { |
| this.version = version; |
| this.signature = signature; |
| this.issuer = issuer; |
| this.thisUpdate = thisUpdate; |
| this.nextUpdate = nextUpdate; |
| this.revokedCertificates = revokedCertificates; |
| this.crlExtensions = crlExtensions; |
| this.encoding = encoding; |
| } |
| |
| /** |
| * Returns the value of version field of the structure. |
| * @return version |
| */ |
| public int getVersion() { |
| return version; |
| } |
| |
| /** |
| * Returns the value of signature field of the structure. |
| * @return signature |
| */ |
| public AlgorithmIdentifier getSignature() { |
| return signature; |
| } |
| |
| /** |
| * Returns the value of issuer field of the structure. |
| * @return issuer |
| */ |
| public Name getIssuer() { |
| return issuer; |
| } |
| |
| /** |
| * Returns the value of thisUpdate field of the structure. |
| * @return thisUpdate |
| */ |
| public Date getThisUpdate() { |
| return thisUpdate; |
| } |
| |
| /** |
| * Returns the value of nextUpdate field of the structure. |
| * @return nextUpdate |
| */ |
| public Date getNextUpdate() { |
| return nextUpdate; |
| } |
| |
| /** |
| * Returns the value of revokedCertificates field of the structure. |
| * @return revokedCertificates |
| */ |
| public List getRevokedCertificates() { |
| return revokedCertificates; |
| } |
| |
| /** |
| * Returns the value of crlExtensions field of the structure. |
| * @return extensions |
| */ |
| public Extensions getCrlExtensions() { |
| return crlExtensions; |
| } |
| |
| /** |
| * Returns ASN.1 encoded form of this X.509 TBSCertList value. |
| * @return a byte array containing ASN.1 encode form. |
| */ |
| public byte[] getEncoded() { |
| if (encoding == null) { |
| encoding = ASN1.encode(this); |
| } |
| return encoding; |
| } |
| |
| public boolean equals(Object tbs) { |
| if (!(tbs instanceof TBSCertList)) { |
| return false; |
| } |
| TBSCertList tbscert = (TBSCertList) tbs; |
| return (version == tbscert.version) |
| && (signature.equals(tbscert.signature)) |
| // FIXME use Name.equals when it will be implemented |
| && (Arrays.equals(issuer.getEncoded(), tbscert.issuer.getEncoded())) |
| && ((thisUpdate.getTime() / 1000) |
| == (tbscert.thisUpdate.getTime() / 1000)) |
| && ((nextUpdate == null) |
| ? tbscert.nextUpdate == null |
| : ((nextUpdate.getTime() / 1000) |
| == (tbscert.nextUpdate.getTime() / 1000))) |
| && ((((revokedCertificates == null) |
| || (tbscert.revokedCertificates == null)) |
| && (revokedCertificates == tbscert.revokedCertificates)) |
| || (revokedCertificates.containsAll(tbscert.revokedCertificates) |
| && (revokedCertificates.size() |
| == tbscert.revokedCertificates.size()))) |
| && ((crlExtensions == null) |
| ? tbscert.crlExtensions == null |
| : crlExtensions.equals(tbscert.crlExtensions)); |
| } |
| |
| public int hashCode() { |
| return ((version * 37 + signature.hashCode()) * 37 |
| + issuer.getEncoded().hashCode()) * 37 |
| + (int)thisUpdate.getTime() / 1000; |
| } |
| |
| /** |
| * Places the string representation of extension value |
| * into the StringBuffer object. |
| */ |
| public void dumpValue(StringBuffer buffer) { |
| buffer.append("X.509 CRL v").append(version); |
| buffer.append("\nSignature Algorithm: ["); |
| signature.dumpValue(buffer); |
| buffer.append(']'); |
| buffer.append("\nIssuer: ").append(issuer.getName(X500Principal.RFC2253)); |
| buffer.append("\n\nThis Update: ").append(thisUpdate); |
| buffer.append("\nNext Update: ").append(nextUpdate).append('\n'); |
| if (revokedCertificates != null) { |
| buffer.append("\nRevoked Certificates: ") |
| .append(revokedCertificates.size()).append(" ["); |
| int number = 1; |
| for (Iterator it = revokedCertificates.iterator();it.hasNext();) { |
| buffer.append("\n [").append(number++).append(']'); |
| ((RevokedCertificate) it.next()).dumpValue(buffer, " "); |
| buffer.append('\n'); |
| } |
| buffer.append("]\n"); |
| } |
| if (crlExtensions != null) { |
| buffer.append("\nCRL Extensions: ") |
| .append(crlExtensions.size()).append(" ["); |
| crlExtensions.dumpValue(buffer, " "); |
| buffer.append("]\n"); |
| } |
| } |
| |
| /** |
| * X.509 TBSCertList encoder/decoder. |
| */ |
| public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] { |
| ASN1Integer.getInstance(), // version |
| AlgorithmIdentifier.ASN1, // signature |
| Name.ASN1, // issuer |
| Time.ASN1, // thisUpdate |
| Time.ASN1, // nextUpdate |
| new ASN1SequenceOf(RevokedCertificate.ASN1), // revokedCertificates |
| new ASN1Explicit(0, Extensions.ASN1) // crlExtensions |
| }) { |
| { |
| setOptional(0); |
| setOptional(4); |
| setOptional(5); |
| setOptional(6); |
| } |
| |
| protected Object getDecodedObject(BerInputStream in) |
| throws IOException { |
| Object[] values = (Object[]) in.content; |
| return new TBSCertList( |
| (values[0] == null) |
| ? 1 |
| : ASN1Integer.toIntValue(values[0])+1, |
| (AlgorithmIdentifier) values[1], |
| (Name) values[2], |
| (Date) values[3], |
| (Date) values[4], |
| (List) values[5], |
| (Extensions) values[6], |
| in.getEncoded() |
| ); |
| } |
| |
| protected void getValues(Object object, Object[] values) { |
| TBSCertList tbs = (TBSCertList) object; |
| values[0] = (tbs.version > 1) |
| ? ASN1Integer.fromIntValue(tbs.version - 1) : null; |
| values[1] = tbs.signature; |
| values[2] = tbs.issuer; |
| values[3] = tbs.thisUpdate; |
| values[4] = tbs.nextUpdate; |
| values[5] = tbs.revokedCertificates; |
| values[6] = tbs.crlExtensions; |
| } |
| }; |
| } |
| |