// --- 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 netscape.security.util.BitArray; import netscape.security.util.DerOutputStream; import netscape.security.util.DerValue; import org.mozilla.jss.asn1.ASN1Util; /** * 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); } catch (IOException e) { throw new IOException("Invalid encoding of IssuingDistributionPoint " + 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); } } else { throw new IOException("Invalid encoding of IssuingDistributionPoint"); } } } } else if (i == 3) { opt.resetTag(DerValue.tag_BitString); try { BitArray reasons = opt.getUnalignedBitString(); issuingDistributionPoint.setOnlySomeReasons(reasons); @SuppressWarnings("unused") byte[] a = reasons.toByteArray(); // check for errors } catch (IOException e) { throw new IOException("Invalid encoding of IssuingDistributionPoint " + 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); } } } 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