/* * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.x509; import java.io.IOException;import java.util.*; import sun.security.util.BitArray;import sun.security.util.DerOutputStream;import sun.security.util.DerValue; /** * Represent the DistributionPoint sequence used in the CRL * Distribution Points Extension (OID = 2.5.29.31). * <p> * The ASN.1 definition for this is: * <pre> * DistributionPoint ::= SEQUENCE { * distributionPoint [0] DistributionPointName OPTIONAL, * reasons [1] ReasonFlags OPTIONAL, * cRLIssuer [2] GeneralNames OPTIONAL } * * DistributionPointName ::= CHOICE { * fullName [0] GeneralNames, * nameRelativeToCRLIssuer [1] RelativeDistinguishedName } * * ReasonFlags ::= BIT STRING { * unused (0), * keyCompromise (1), * cACompromise (2), * affiliationChanged (3), * superseded (4), * cessationOfOperation (5), * certificateHold (6), * privilegeWithdrawn (7), * aACompromise (8) } * * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName * * GeneralName ::= CHOICE { * otherName [0] INSTANCE OF OTHER-NAME, * rfc822Name [1] IA5String, * dNSName [2] IA5String, * x400Address [3] ORAddress, * directoryName [4] Name, * ediPartyName [5] EDIPartyName, * uniformResourceIdentifier [6] IA5String, * iPAddress [7] OCTET STRING, * registeredID [8] OBJECT IDENTIFIER } * * RelativeDistinguishedName ::= * SET OF AttributeTypeAndValue * * AttributeTypeAndValue ::= SEQUENCE { * type AttributeType, * value AttributeValue } * * AttributeType ::= OBJECT IDENTIFIER * * AttributeValue ::= ANY DEFINED BY AttributeType * </pre> * <p> * Instances of this class are designed to be immutable. However, since this * is an internal API we do not use defensive cloning for values for * performance reasons. It is the responsibility of the consumer to ensure * that no mutable elements are modified. * * @author Anne Anderson * @author Andreas Sterbenz * @since 1.4.2 * @see CRLDistributionPointsExtension */public class DistributionPoint { // reason flag bits // NOTE that these are NOT quite the same as the CRL reason code extension public final static int KEY_COMPROMISE = 1; public final static int CA_COMPROMISE = 2; public final static int AFFILIATION_CHANGED = 3; public final static int SUPERSEDED = 4; public final static int CESSATION_OF_OPERATION = 5; public final static int CERTIFICATE_HOLD = 6; public final static int PRIVILEGE_WITHDRAWN = 7; public final static int AA_COMPROMISE = 8; private static final String[] REASON_STRINGS = { null, "key compromise", "CA compromise", "affiliation changed", "superseded", "cessation of operation", "certificate hold", "privilege withdrawn", "AA compromise", }; // context specific tag values private static final byte TAG_DIST_PT = 0; private static final byte TAG_REASONS = 1; private static final byte TAG_ISSUER = 2; private static final byte TAG_FULL_NAME = 0; private static final byte TAG_REL_NAME = 1; // only one of fullName and relativeName can be set private GeneralNames fullName; private RDN relativeName; // reasonFlags or null private boolean[] reasonFlags; // crlIssuer or null private GeneralNames crlIssuer; // cached hashCode value private volatile int hashCode; /** * Constructor for the class using GeneralNames for DistributionPointName * * @param fullName the GeneralNames of the distribution point; may be null * @param reasons the CRL reasons included in the CRL at this distribution * point; may be null * @param issuer the name(s) of the CRL issuer for the CRL at this * distribution point; may be null */ public DistributionPoint(GeneralNames fullName, boolean[] reasonFlags, GeneralNames crlIssuer) { if ((fullName == null) && (crlIssuer == null)) { throw new IllegalArgumentException ("fullName and crlIssuer may not both be null"); } this.fullName = fullName; this.reasonFlags = reasonFlags; this.crlIssuer = crlIssuer; } /** * Constructor for the class using RelativeDistinguishedName for * DistributionPointName * * @param relativeName the RelativeDistinguishedName of the distribution * point; may not be null * @param reasons the CRL reasons included in the CRL at this distribution * point; may be null * @param issuer the name(s) of the CRL issuer for the CRL at this * distribution point; may not be null or empty. */ public DistributionPoint(RDN relativeName, boolean[] reasonFlags, GeneralNames crlIssuer) { if ((relativeName == null) && (crlIssuer == null)) { throw new IllegalArgumentException ("relativeName and crlIssuer may not both be null"); } this.relativeName = relativeName; this.reasonFlags = reasonFlags; this.crlIssuer = crlIssuer; } /** * Create the object from the passed DER encoded form. * * @param val the DER encoded form of the DistributionPoint * @throws IOException on error */ public DistributionPoint(DerValue val) throws IOException { if (val.tag != DerValue.tag_Sequence) { throw new IOException("Invalid encoding of DistributionPoint."); } // Note that all the fields in DistributionPoint are defined as // being OPTIONAL, i.e., there could be an empty SEQUENCE, resulting // in val.data being null. while ((val.data != null) && (val.data.available() != 0)) { DerValue opt = val.data.getDerValue(); if (opt.isContextSpecific(TAG_DIST_PT) && opt.isConstructed()) { if ((fullName != null) || (relativeName != null)) { throw new IOException("Duplicate DistributionPointName in " + "DistributionPoint."); } DerValue distPnt = opt.data.getDerValue(); if (distPnt.isContextSpecific(TAG_FULL_NAME) && distPnt.isConstructed()) { distPnt.resetTag(DerValue.tag_Sequence); fullName = new GeneralNames(distPnt); } else if (distPnt.isContextSpecific(TAG_REL_NAME) && distPnt.isConstructed()) { distPnt.resetTag(DerValue.tag_Set); relativeName = new RDN(distPnt); } else { throw new IOException("Invalid DistributionPointName in " + "DistributionPoint"); } } else if (opt.isContextSpecific(TAG_REASONS) && !opt.isConstructed()) { if (reasonFlags != null) { throw new IOException("Duplicate Reasons in " + "DistributionPoint."); } opt.resetTag(DerValue.tag_BitString); reasonFlags = (opt.getUnalignedBitString()).toBooleanArray(); } else if (opt.isContextSpecific(TAG_ISSUER) && opt.isConstructed()) { if (crlIssuer != null) { throw new IOException("Duplicate CRLIssuer in " + "DistributionPoint."); } opt.resetTag(DerValue.tag_Sequence); crlIssuer = new GeneralNames(opt); } else { throw new IOException("Invalid encoding of " + "DistributionPoint."); } } if ((crlIssuer == null) && (fullName == null) && (relativeName == null)) { throw new IOException("One of fullName, relativeName, " + " and crlIssuer has to be set"); } } /** * Return the full distribution point name or null if not set. */ public GeneralNames getFullName() { return fullName; } /** * Return the relative distribution point name or null if not set. */ public RDN getRelativeName() { return relativeName; } /** * Return the reason flags or null if not set. */ public boolean[] getReasonFlags() { return reasonFlags; } /** * Return the CRL issuer name or null if not set. */ public GeneralNames getCRLIssuer() { return crlIssuer; } /** * Write the DistributionPoint value to the DerOutputStream. * * @param out the DerOutputStream to write the extension to. * @exception IOException on error. */ public void encode(DerOutputStream out) throws IOException { DerOutputStream tagged = new DerOutputStream(); // NOTE: only one of pointNames and pointRDN can be set if ((fullName != null) || (relativeName != null)) { DerOutputStream distributionPoint = new DerOutputStream(); if (fullName != null) { DerOutputStream derOut = new DerOutputStream(); fullName.encode(derOut); distributionPoint.writeImplicit( DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_FULL_NAME), derOut); } else if (relativeName != null) { DerOutputStream derOut = new DerOutputStream(); relativeName.encode(derOut); distributionPoint.writeImplicit( DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_REL_NAME), derOut); } tagged.write( DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_DIST_PT), distributionPoint); } if (reasonFlags != null) { DerOutputStream reasons = new DerOutputStream(); BitArray rf = new BitArray(reasonFlags); reasons.putTruncatedUnalignedBitString(rf); tagged.writeImplicit( DerValue.createTag(DerValue.TAG_CONTEXT, false, TAG_REASONS), reasons); } if (crlIssuer != null) { DerOutputStream issuer = new DerOutputStream(); crlIssuer.encode(issuer); tagged.writeImplicit( DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_ISSUER), issuer); } out.write(DerValue.tag_Sequence, tagged); } /** * Utility function for a.equals(b) where both a and b may be null. */ private static boolean equals(Object a, Object b) { return (a == null) ? (b == null) : a.equals(b); } /** * Compare an object to this DistributionPoint for equality. * * @param obj Object to be compared to this * @return true if objects match; false otherwise */ public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof DistributionPoint == false) { return false; } DistributionPoint other = (DistributionPoint)obj; boolean equal = equals(this.fullName, other.fullName) && equals(this.relativeName, other.relativeName) && equals(this.crlIssuer, other.crlIssuer) && Arrays.equals(this.reasonFlags, other.reasonFlags); return equal; } public int hashCode() { int hash = hashCode; if (hash == 0) { hash = 1; if (fullName != null) { hash += fullName.hashCode(); } if (relativeName != null) { hash += relativeName.hashCode(); } if (crlIssuer != null) { hash += crlIssuer.hashCode(); } if (reasonFlags != null) { for (int i = 0; i < reasonFlags.length; i++) { if (reasonFlags[i]) { hash += i; } } } hashCode = hash; } return hash; } /** * Return a string representation for reasonFlag bit 'reason'. */ private static String reasonToString(int reason) { if ((reason > 0) && (reason < REASON_STRINGS.length)) { return REASON_STRINGS[reason]; } return "Unknown reason " + reason; } /** * Return a printable string of the Distribution Point. */ public String toString() { StringBuilder sb = new StringBuilder(); if (fullName != null) { sb.append("DistributionPoint:\n " + fullName + "\n"); } if (relativeName != null) { sb.append("DistributionPoint:\n " + relativeName + "\n"); } if (reasonFlags != null) { sb.append(" ReasonFlags:\n"); for (int i = 0; i < reasonFlags.length; i++) { if (reasonFlags[i]) { sb.append(" " + reasonToString(i) + "\n"); } } } if (crlIssuer != null) { sb.append(" CRLIssuer:" + crlIssuer + "\n"); } return sb.toString(); } }
/*
* Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.util.*;
import sun.security.util.BitArray;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
/**
* Represent the DistributionPoint sequence used in the CRL
* Distribution Points Extension (OID = 2.5.29.31).
* <p>
* The ASN.1 definition for this is:
* <pre>
* DistributionPoint ::= SEQUENCE {
* distributionPoint [0] DistributionPointName OPTIONAL,
* reasons [1] ReasonFlags OPTIONAL,
* cRLIssuer [2] GeneralNames OPTIONAL }
*
* DistributionPointName ::= CHOICE {
* fullName [0] GeneralNames,
* nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
*
* ReasonFlags ::= BIT STRING {
* unused (0),
* keyCompromise (1),
* cACompromise (2),
* affiliationChanged (3),
* superseded (4),
* cessationOfOperation (5),
* certificateHold (6),
* privilegeWithdrawn (7),
* aACompromise (8) }
*
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
*
* GeneralName ::= CHOICE {
* otherName [0] INSTANCE OF OTHER-NAME,
* rfc822Name [1] IA5String,
* dNSName [2] IA5String,
* x400Address [3] ORAddress,
* directoryName [4] Name,
* ediPartyName [5] EDIPartyName,
* uniformResourceIdentifier [6] IA5String,
* iPAddress [7] OCTET STRING,
* registeredID [8] OBJECT IDENTIFIER }
*
* RelativeDistinguishedName ::=
* SET OF AttributeTypeAndValue
*
* AttributeTypeAndValue ::= SEQUENCE {
* type AttributeType,
* value AttributeValue }
*
* AttributeType ::= OBJECT IDENTIFIER
*
* AttributeValue ::= ANY DEFINED BY AttributeType
* </pre>
* <p>
* Instances of this class are designed to be immutable. However, since this
* is an internal API we do not use defensive cloning for values for
* performance reasons. It is the responsibility of the consumer to ensure
* that no mutable elements are modified.
*
* @author Anne Anderson
* @author Andreas Sterbenz
* @since 1.4.2
* @see CRLDistributionPointsExtension
*/
public class DistributionPoint {
// reason flag bits
// NOTE that these are NOT quite the same as the CRL reason code extension
public final static int KEY_COMPROMISE = 1;
public final static int CA_COMPROMISE = 2;
public final static int AFFILIATION_CHANGED = 3;
public final static int SUPERSEDED = 4;
public final static int CESSATION_OF_OPERATION = 5;
public final static int CERTIFICATE_HOLD = 6;
public final static int PRIVILEGE_WITHDRAWN = 7;
public final static int AA_COMPROMISE = 8;
private static final String[] REASON_STRINGS = {
null,
"key compromise",
"CA compromise",
"affiliation changed",
"superseded",
"cessation of operation",
"certificate hold",
"privilege withdrawn",
"AA compromise",
};
// context specific tag values
private static final byte TAG_DIST_PT = 0;
private static final byte TAG_REASONS = 1;
private static final byte TAG_ISSUER = 2;
private static final byte TAG_FULL_NAME = 0;
private static final byte TAG_REL_NAME = 1;
// only one of fullName and relativeName can be set
private GeneralNames fullName;
private RDN relativeName;
// reasonFlags or null
private boolean[] reasonFlags;
// crlIssuer or null
private GeneralNames crlIssuer;
// cached hashCode value
private volatile int hashCode;
/**
* Constructor for the class using GeneralNames for DistributionPointName
*
* @param fullName the GeneralNames of the distribution point; may be null
* @param reasons the CRL reasons included in the CRL at this distribution
* point; may be null
* @param issuer the name(s) of the CRL issuer for the CRL at this
* distribution point; may be null
*/
public DistributionPoint(GeneralNames fullName, boolean[] reasonFlags,
GeneralNames crlIssuer) {
if ((fullName == null) && (crlIssuer == null)) {
throw new IllegalArgumentException
("fullName and crlIssuer may not both be null");
}
this.fullName = fullName;
this.reasonFlags = reasonFlags;
this.crlIssuer = crlIssuer;
}
/**
* Constructor for the class using RelativeDistinguishedName for
* DistributionPointName
*
* @param relativeName the RelativeDistinguishedName of the distribution
* point; may not be null
* @param reasons the CRL reasons included in the CRL at this distribution
* point; may be null
* @param issuer the name(s) of the CRL issuer for the CRL at this
* distribution point; may not be null or empty.
*/
public DistributionPoint(RDN relativeName, boolean[] reasonFlags,
GeneralNames crlIssuer) {
if ((relativeName == null) && (crlIssuer == null)) {
throw new IllegalArgumentException
("relativeName and crlIssuer may not both be null");
}
this.relativeName = relativeName;
this.reasonFlags = reasonFlags;
this.crlIssuer = crlIssuer;
}
/**
* Create the object from the passed DER encoded form.
*
* @param val the DER encoded form of the DistributionPoint
* @throws IOException on error
*/
public DistributionPoint(DerValue val) throws IOException {
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding of DistributionPoint.");
}
// Note that all the fields in DistributionPoint are defined as
// being OPTIONAL, i.e., there could be an empty SEQUENCE, resulting
// in val.data being null.
while ((val.data != null) && (val.data.available() != 0)) {
DerValue opt = val.data.getDerValue();
if (opt.isContextSpecific(TAG_DIST_PT) && opt.isConstructed()) {
if ((fullName != null) || (relativeName != null)) {
throw new IOException("Duplicate DistributionPointName in "
+ "DistributionPoint.");
}
DerValue distPnt = opt.data.getDerValue();
if (distPnt.isContextSpecific(TAG_FULL_NAME)
&& distPnt.isConstructed()) {
distPnt.resetTag(DerValue.tag_Sequence);
fullName = new GeneralNames(distPnt);
} else if (distPnt.isContextSpecific(TAG_REL_NAME)
&& distPnt.isConstructed()) {
distPnt.resetTag(DerValue.tag_Set);
relativeName = new RDN(distPnt);
} else {
throw new IOException("Invalid DistributionPointName in "
+ "DistributionPoint");
}
} else if (opt.isContextSpecific(TAG_REASONS)
&& !opt.isConstructed()) {
if (reasonFlags != null) {
throw new IOException("Duplicate Reasons in " +
"DistributionPoint.");
}
opt.resetTag(DerValue.tag_BitString);
reasonFlags = (opt.getUnalignedBitString()).toBooleanArray();
} else if (opt.isContextSpecific(TAG_ISSUER)
&& opt.isConstructed()) {
if (crlIssuer != null) {
throw new IOException("Duplicate CRLIssuer in " +
"DistributionPoint.");
}
opt.resetTag(DerValue.tag_Sequence);
crlIssuer = new GeneralNames(opt);
} else {
throw new IOException("Invalid encoding of " +
"DistributionPoint.");
}
}
if ((crlIssuer == null) && (fullName == null) && (relativeName == null)) {
throw new IOException("One of fullName, relativeName, "
+ " and crlIssuer has to be set");
}
}
/**
* Return the full distribution point name or null if not set.
*/
public GeneralNames getFullName() {
return fullName;
}
/**
* Return the relative distribution point name or null if not set.
*/
public RDN getRelativeName() {
return relativeName;
}
/**
* Return the reason flags or null if not set.
*/
public boolean[] getReasonFlags() {
return reasonFlags;
}
/**
* Return the CRL issuer name or null if not set.
*/
public GeneralNames getCRLIssuer() {
return crlIssuer;
}
/**
* Write the DistributionPoint value to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on error.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream tagged = new DerOutputStream();
// NOTE: only one of pointNames and pointRDN can be set
if ((fullName != null) || (relativeName != null)) {
DerOutputStream distributionPoint = new DerOutputStream();
if (fullName != null) {
DerOutputStream derOut = new DerOutputStream();
fullName.encode(derOut);
distributionPoint.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_FULL_NAME),
derOut);
} else if (relativeName != null) {
DerOutputStream derOut = new DerOutputStream();
relativeName.encode(derOut);
distributionPoint.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_REL_NAME),
derOut);
}
tagged.write(
DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_DIST_PT),
distributionPoint);
}
if (reasonFlags != null) {
DerOutputStream reasons = new DerOutputStream();
BitArray rf = new BitArray(reasonFlags);
reasons.putTruncatedUnalignedBitString(rf);
tagged.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, false, TAG_REASONS),
reasons);
}
if (crlIssuer != null) {
DerOutputStream issuer = new DerOutputStream();
crlIssuer.encode(issuer);
tagged.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_ISSUER),
issuer);
}
out.write(DerValue.tag_Sequence, tagged);
}
/**
* Utility function for a.equals(b) where both a and b may be null.
*/
private static boolean equals(Object a, Object b) {
return (a == null) ? (b == null) : a.equals(b);
}
/**
* Compare an object to this DistributionPoint for equality.
*
* @param obj Object to be compared to this
* @return true if objects match; false otherwise
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DistributionPoint == false) {
return false;
}
DistributionPoint other = (DistributionPoint)obj;
boolean equal = equals(this.fullName, other.fullName)
&& equals(this.relativeName, other.relativeName)
&& equals(this.crlIssuer, other.crlIssuer)
&& Arrays.equals(this.reasonFlags, other.reasonFlags);
return equal;
}
public int hashCode() {
int hash = hashCode;
if (hash == 0) {
hash = 1;
if (fullName != null) {
hash += fullName.hashCode();
}
if (relativeName != null) {
hash += relativeName.hashCode();
}
if (crlIssuer != null) {
hash += crlIssuer.hashCode();
}
if (reasonFlags != null) {
for (int i = 0; i < reasonFlags.length; i++) {
if (reasonFlags[i]) {
hash += i;
}
}
}
hashCode = hash;
}
return hash;
}
/**
* Return a string representation for reasonFlag bit 'reason'.
*/
private static String reasonToString(int reason) {
if ((reason > 0) && (reason < REASON_STRINGS.length)) {
return REASON_STRINGS[reason];
}
return "Unknown reason " + reason;
}
/**
* Return a printable string of the Distribution Point.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
if (fullName != null) {
sb.append("DistributionPoint:\n " + fullName + "\n");
}
if (relativeName != null) {
sb.append("DistributionPoint:\n " + relativeName + "\n");
}
if (reasonFlags != null) {
sb.append(" ReasonFlags:\n");
for (int i = 0; i < reasonFlags.length; i++) {
if (reasonFlags[i]) {
sb.append(" " + reasonToString(i) + "\n");
}
}
}
if (crlIssuer != null) {
sb.append(" CRLIssuer:" + crlIssuer + "\n");
}
return sb.toString();
}
}