// --- BEGIN COPYRIGHT BLOCK --- // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; version 2 of the License. // // This program 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 for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // (C) 2007 Red Hat, Inc. // All rights reserved. // --- END COPYRIGHT BLOCK --- package netscape.security.x509; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.cert.CertificateException; import java.util.Enumeration; import java.util.Vector; import org.mozilla.jss.asn1.ASN1Util; import netscape.security.util.BitArray; import netscape.security.util.DerOutputStream; import netscape.security.util.DerValue; /** * A critical CRL extension that identifies the CRL distribution point * for a particular CRL * *
* issuingDistributionPoint ::= SEQUENCE {
* distributionPoint [0] DistributionPointName OPTIONAL,
* onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
* onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
* onlySomeReasons [3] ReasonFlags OPTIONAL,
* indirectCRL [4] BOOLEAN DEFAULT FALSE }
*
* 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) }
*
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
*
* GeneralName ::= CHOICE {
* otherName [0] OtherName,
* 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}
*
* OtherName ::= SEQUENCE {
* type-id OBJECT IDENTIFIER,
* value [0] EXPLICIT ANY DEFINED BY type-id }
*
* EDIPartyName ::= SEQUENCE {
* nameAssigner [0] DirectoryString OPTIONAL,
* partyName [1] DirectoryString }
*
* RelativeDistinguishedName ::=
* SET OF AttributeTypeAndValue
*
* AttributeTypeAndValue ::= SEQUENCE {
* type AttributeType,
* value AttributeValue }
*
* AttributeType ::= OBJECT IDENTIFIER
*
* AttributeValue ::= ANY DEFINED BY AttributeType
*
*/
public class IssuingDistributionPointExtension extends Extension
implements CertAttrSet {
/**
*
*/
private static final long serialVersionUID = -1281544042375527550L;
/**
* The Object Identifier for this extension.
*/
public static final String OID = "2.5.29.28";
/**
* Attribute names.
*/
public static final String NAME = "IssuingDistributionPoint";
public static final String ISSUING_DISTRIBUTION_POINT = "issuing_distribution_point";
// Private data members
private IssuingDistributionPoint issuingDistributionPoint = null;
// Cached DER-encoding to improve performance.
private byte[] cachedEncoding = null;
static {
try {
OIDMap.addAttribute(IssuingDistributionPointExtension.class.getName(),
OID, NAME);
} catch (CertificateException e) {
}
}
/**
* This constructor is very important, since it will be called
* by the system.
*/
public IssuingDistributionPointExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
this.critical = critical.booleanValue();
this.extensionValue = ((byte[]) value).clone();
byte[] extValue = this.extensionValue;
issuingDistributionPoint = new IssuingDistributionPoint();
DerValue val = new DerValue(extValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding of IssuingDistributionPoint");
}
while (val.data.available() != 0) {
DerValue opt = val.data.getDerValue();
if (opt != null) {
for (int i = 0; i < 5; i++) {
if (opt.isContextSpecific((byte) i)) {
if ((i == 0 && opt.isConstructed() && opt.data.available() != 0) ||
(i != 0 && (!opt.isConstructed()) && opt.data.available() != 0)) {
if (i == 0) {
DerValue opt1 = opt.data.getDerValue();
if (opt1 != null) {
if (opt1.isContextSpecific((byte) 0)) {
if (opt1.isConstructed() && opt1.data.available() != 0) {
opt1.resetTag(DerValue.tag_Sequence);
try {
GeneralNames fullName = new GeneralNames(opt1);
if (fullName != null) {
issuingDistributionPoint.setFullName(fullName);
}
} catch (GeneralNamesException e) {
throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e);
} catch (IOException e) {
throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e);
}
} else {
throw new IOException("Invalid encoding of IssuingDistributionPoint");
}
} else if (opt1.isContextSpecific((byte) 1)) {
if (opt1.isConstructed() && opt1.data.available() != 0) {
opt1.resetTag(DerValue.tag_Set);
try {
RDN relativeName = new RDN(opt1);
if (relativeName != null) {
issuingDistributionPoint.setRelativeName(relativeName);
}
} catch (IOException e) {
throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e);
}
} else {
throw new IOException("Invalid encoding of IssuingDistributionPoint");
}
}
}
} else if (i == 3) {
opt.resetTag(DerValue.tag_BitString);
try {
BitArray reasons = opt.getUnalignedBitString();
if (reasons == null) {
throw new IOException("Unable to get the unaligned bit string.");
}
issuingDistributionPoint.setOnlySomeReasons(reasons);
@SuppressWarnings("unused")
byte[] a = reasons.toByteArray(); // check for errors
} catch (IOException e) {
throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e);
}
} else {
opt.resetTag(DerValue.tag_Boolean);
try {
boolean b = opt.getBoolean();
if (i == 1) {
issuingDistributionPoint.setOnlyContainsUserCerts(b);
} else if (i == 2) {
issuingDistributionPoint.setOnlyContainsCACerts(b);
} else if (i == 4) {
issuingDistributionPoint.setIndirectCRL(b);
}
} catch (IOException e) {
throw new IOException("Invalid encoding of IssuingDistributionPoint " + e, e);
}
}
} else {
throw new IOException("Invalid encoding of IssuingDistributionPoint");
}
}
}
} else {
throw new IOException("Invalid encoding of IssuingDistributionPoint");
}
}
}
/**
* Creates a new IssuingDistributionPoint extension, with the given
* issuing distribution point as the first element.
*/
public IssuingDistributionPointExtension(IssuingDistributionPoint idp) {
this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
this.critical = true;
issuingDistributionPoint = idp;
}
/**
* Returns the issuing distribution point.
*/
public IssuingDistributionPoint getIssuingDistributionPoint() {
return issuingDistributionPoint;
}
/**
* Sets the criticality of this extension. PKIX dictates that this
* extension SHOULD be critical, so applications can make it not critical
* if they have a very good reason. By default, the extension is critical.
*/
public void setCritical(boolean critical) {
this.critical = critical;
}
/**
* Gets the criticality of this extension. PKIX dictates that this
* extension SHOULD be critical, so by default, the extension is critical.
*/
public boolean getCritical(boolean critical) {
return this.critical;
}
/**
* Encodes this extension to the given DerOutputStream.
* This method re-encodes each time it is called, so it is not very
* efficient.
*/
public void encode(DerOutputStream out) throws IOException {
extensionValue = ASN1Util.encode(issuingDistributionPoint);
super.encode(out);
}
/**
* Should be called if any change is made to this data structure
* so that the cached DER encoding can be discarded.
*/
public void flushCachedEncoding() {
cachedEncoding = null;
}
/**
* Returns a printable representation of the IssuingDistributionPointExtension
*/
@Override
public String toString() {
return NAME;
}
/**
* DER-encodes this extension to the given OutputStream.
*/
public void encode(OutputStream ostream)
throws CertificateException, IOException {
if (cachedEncoding == null) {
// only re-encode if necessary
DerOutputStream tmp = new DerOutputStream();
encode(tmp);
cachedEncoding = tmp.toByteArray();
}
ostream.write(cachedEncoding);
}
public void decode(InputStream in)
throws CertificateException, IOException {
throw new IOException("Not supported");
}
public void set(String name, Object obj)
throws CertificateException, IOException {
if (name.equalsIgnoreCase(ISSUING_DISTRIBUTION_POINT)) {
if (!(obj instanceof IssuingDistributionPoint)) {
throw new IOException("Attribute value should be of type IssuingDistributionPoint.");
}
issuingDistributionPoint = (IssuingDistributionPoint) obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:IssuingDistributionPointExtension");
}
}
public Object get(String name)
throws CertificateException, IOException {
if (name.equalsIgnoreCase(ISSUING_DISTRIBUTION_POINT)) {
return issuingDistributionPoint;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:IssuingDistributionPointExtension");
}
}
public void delete(String name)
throws CertificateException, IOException {
if (name.equalsIgnoreCase(ISSUING_DISTRIBUTION_POINT)) {
issuingDistributionPoint = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:IssuingDistributionPointExtension");
}
}
public Enumeration