Path: blob/master/src/java.base/share/classes/sun/security/x509/DistributionPoint.java
41159 views
/*1* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.x509;2627import java.io.IOException;28import java.util.*;2930import sun.security.util.BitArray;31import sun.security.util.DerOutputStream;32import sun.security.util.DerValue;3334/**35* Represent the DistributionPoint sequence used in the CRL36* Distribution Points Extension (OID = 2.5.29.31).37* <p>38* The ASN.1 definition for this is:39* <pre>40* DistributionPoint ::= SEQUENCE {41* distributionPoint [0] DistributionPointName OPTIONAL,42* reasons [1] ReasonFlags OPTIONAL,43* cRLIssuer [2] GeneralNames OPTIONAL }44*45* DistributionPointName ::= CHOICE {46* fullName [0] GeneralNames,47* nameRelativeToCRLIssuer [1] RelativeDistinguishedName }48*49* ReasonFlags ::= BIT STRING {50* unused (0),51* keyCompromise (1),52* cACompromise (2),53* affiliationChanged (3),54* superseded (4),55* cessationOfOperation (5),56* certificateHold (6),57* privilegeWithdrawn (7),58* aACompromise (8) }59*60* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName61*62* GeneralName ::= CHOICE {63* otherName [0] INSTANCE OF OTHER-NAME,64* rfc822Name [1] IA5String,65* dNSName [2] IA5String,66* x400Address [3] ORAddress,67* directoryName [4] Name,68* ediPartyName [5] EDIPartyName,69* uniformResourceIdentifier [6] IA5String,70* iPAddress [7] OCTET STRING,71* registeredID [8] OBJECT IDENTIFIER }72*73* RelativeDistinguishedName ::=74* SET OF AttributeTypeAndValue75*76* AttributeTypeAndValue ::= SEQUENCE {77* type AttributeType,78* value AttributeValue }79*80* AttributeType ::= OBJECT IDENTIFIER81*82* AttributeValue ::= ANY DEFINED BY AttributeType83* </pre>84* <p>85* Instances of this class are designed to be immutable. However, since this86* is an internal API we do not use defensive cloning for values for87* performance reasons. It is the responsibility of the consumer to ensure88* that no mutable elements are modified.89*90* @author Anne Anderson91* @author Andreas Sterbenz92* @since 1.4.293* @see CRLDistributionPointsExtension94*/95public class DistributionPoint {9697// reason flag bits98// NOTE that these are NOT quite the same as the CRL reason code extension99public static final int KEY_COMPROMISE = 1;100public static final int CA_COMPROMISE = 2;101public static final int AFFILIATION_CHANGED = 3;102public static final int SUPERSEDED = 4;103public static final int CESSATION_OF_OPERATION = 5;104public static final int CERTIFICATE_HOLD = 6;105public static final int PRIVILEGE_WITHDRAWN = 7;106public static final int AA_COMPROMISE = 8;107108private static final String[] REASON_STRINGS = {109null,110"key compromise",111"CA compromise",112"affiliation changed",113"superseded",114"cessation of operation",115"certificate hold",116"privilege withdrawn",117"AA compromise",118};119120// context specific tag values121private static final byte TAG_DIST_PT = 0;122private static final byte TAG_REASONS = 1;123private static final byte TAG_ISSUER = 2;124125private static final byte TAG_FULL_NAME = 0;126private static final byte TAG_REL_NAME = 1;127128// only one of fullName and relativeName can be set129private GeneralNames fullName;130private RDN relativeName;131132// reasonFlags or null133private boolean[] reasonFlags;134135// crlIssuer or null136private GeneralNames crlIssuer;137138// cached hashCode value139private volatile int hashCode;140141/**142* Constructor for the class using GeneralNames for DistributionPointName143*144* @param fullName the GeneralNames of the distribution point; may be null145* @param reasonFlags the CRL reasons included in the CRL at this distribution146* point; may be null147* @param crlIssuer the name(s) of the CRL issuer for the CRL at this148* distribution point; may be null149*/150public DistributionPoint(GeneralNames fullName, boolean[] reasonFlags,151GeneralNames crlIssuer) {152if ((fullName == null) && (crlIssuer == null)) {153throw new IllegalArgumentException154("fullName and crlIssuer may not both be null");155}156this.fullName = fullName;157this.reasonFlags = reasonFlags;158this.crlIssuer = crlIssuer;159}160161/**162* Constructor for the class using RelativeDistinguishedName for163* DistributionPointName164*165* @param relativeName the RelativeDistinguishedName of the distribution166* point; may not be null167* @param reasonFlags the CRL reasons included in the CRL at this distribution168* point; may be null169* @param crlIssuer the name(s) of the CRL issuer for the CRL at this170* distribution point; may not be null or empty.171*/172public DistributionPoint(RDN relativeName, boolean[] reasonFlags,173GeneralNames crlIssuer) {174if ((relativeName == null) && (crlIssuer == null)) {175throw new IllegalArgumentException176("relativeName and crlIssuer may not both be null");177}178this.relativeName = relativeName;179this.reasonFlags = reasonFlags;180this.crlIssuer = crlIssuer;181}182183/**184* Create the object from the passed DER encoded form.185*186* @param val the DER encoded form of the DistributionPoint187* @throws IOException on error188*/189public DistributionPoint(DerValue val) throws IOException {190if (val.tag != DerValue.tag_Sequence) {191throw new IOException("Invalid encoding of DistributionPoint.");192}193194// Note that all the fields in DistributionPoint are defined as195// being OPTIONAL, i.e., there could be an empty SEQUENCE, resulting196// in val.data being null.197while ((val.data != null) && (val.data.available() != 0)) {198DerValue opt = val.data.getDerValue();199200if (opt.isContextSpecific(TAG_DIST_PT) && opt.isConstructed()) {201if ((fullName != null) || (relativeName != null)) {202throw new IOException("Duplicate DistributionPointName in "203+ "DistributionPoint.");204}205DerValue distPnt = opt.data.getDerValue();206if (distPnt.isContextSpecific(TAG_FULL_NAME)207&& distPnt.isConstructed()) {208distPnt.resetTag(DerValue.tag_Sequence);209fullName = new GeneralNames(distPnt);210} else if (distPnt.isContextSpecific(TAG_REL_NAME)211&& distPnt.isConstructed()) {212distPnt.resetTag(DerValue.tag_Set);213relativeName = new RDN(distPnt);214} else {215throw new IOException("Invalid DistributionPointName in "216+ "DistributionPoint");217}218} else if (opt.isContextSpecific(TAG_REASONS)219&& !opt.isConstructed()) {220if (reasonFlags != null) {221throw new IOException("Duplicate Reasons in " +222"DistributionPoint.");223}224opt.resetTag(DerValue.tag_BitString);225reasonFlags = (opt.getUnalignedBitString()).toBooleanArray();226} else if (opt.isContextSpecific(TAG_ISSUER)227&& opt.isConstructed()) {228if (crlIssuer != null) {229throw new IOException("Duplicate CRLIssuer in " +230"DistributionPoint.");231}232opt.resetTag(DerValue.tag_Sequence);233crlIssuer = new GeneralNames(opt);234} else {235throw new IOException("Invalid encoding of " +236"DistributionPoint.");237}238}239if ((crlIssuer == null) && (fullName == null) && (relativeName == null)) {240throw new IOException("One of fullName, relativeName, "241+ " and crlIssuer has to be set");242}243}244245/**246* Return the full distribution point name or null if not set.247*/248public GeneralNames getFullName() {249return fullName;250}251252/**253* Return the relative distribution point name or null if not set.254*/255public RDN getRelativeName() {256return relativeName;257}258259/**260* Return the reason flags or null if not set.261*/262public boolean[] getReasonFlags() {263return reasonFlags;264}265266/**267* Return the CRL issuer name or null if not set.268*/269public GeneralNames getCRLIssuer() {270return crlIssuer;271}272273/**274* Write the DistributionPoint value to the DerOutputStream.275*276* @param out the DerOutputStream to write the extension to.277* @exception IOException on error.278*/279public void encode(DerOutputStream out) throws IOException {280DerOutputStream tagged = new DerOutputStream();281282// NOTE: only one of pointNames and pointRDN can be set283if ((fullName != null) || (relativeName != null)) {284DerOutputStream distributionPoint = new DerOutputStream();285if (fullName != null) {286DerOutputStream derOut = new DerOutputStream();287fullName.encode(derOut);288distributionPoint.writeImplicit(289DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_FULL_NAME),290derOut);291} else if (relativeName != null) {292DerOutputStream derOut = new DerOutputStream();293relativeName.encode(derOut);294distributionPoint.writeImplicit(295DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_REL_NAME),296derOut);297}298tagged.write(299DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_DIST_PT),300distributionPoint);301}302if (reasonFlags != null) {303DerOutputStream reasons = new DerOutputStream();304BitArray rf = new BitArray(reasonFlags);305reasons.putTruncatedUnalignedBitString(rf);306tagged.writeImplicit(307DerValue.createTag(DerValue.TAG_CONTEXT, false, TAG_REASONS),308reasons);309}310if (crlIssuer != null) {311DerOutputStream issuer = new DerOutputStream();312crlIssuer.encode(issuer);313tagged.writeImplicit(314DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_ISSUER),315issuer);316}317out.write(DerValue.tag_Sequence, tagged);318}319320/**321* Compare an object to this DistributionPoint for equality.322*323* @param obj Object to be compared to this324* @return true if objects match; false otherwise325*/326public boolean equals(Object obj) {327if (this == obj) {328return true;329}330if (obj instanceof DistributionPoint == false) {331return false;332}333DistributionPoint other = (DistributionPoint)obj;334335boolean equal = Objects.equals(this.fullName, other.fullName)336&& Objects.equals(this.relativeName, other.relativeName)337&& Objects.equals(this.crlIssuer, other.crlIssuer)338&& Arrays.equals(this.reasonFlags, other.reasonFlags);339return equal;340}341342public int hashCode() {343int hash = hashCode;344if (hash == 0) {345hash = 1;346if (fullName != null) {347hash += fullName.hashCode();348}349if (relativeName != null) {350hash += relativeName.hashCode();351}352if (crlIssuer != null) {353hash += crlIssuer.hashCode();354}355if (reasonFlags != null) {356for (int i = 0; i < reasonFlags.length; i++) {357if (reasonFlags[i]) {358hash += i;359}360}361}362hashCode = hash;363}364return hash;365}366367/**368* Return a string representation for reasonFlag bit 'reason'.369*/370private static String reasonToString(int reason) {371if ((reason > 0) && (reason < REASON_STRINGS.length)) {372return REASON_STRINGS[reason];373}374return "Unknown reason " + reason;375}376377/**378* Return a printable string of the Distribution Point.379*/380public String toString() {381StringBuilder sb = new StringBuilder();382sb.append("DistributionPoint:\n ");383if (fullName != null) {384sb.append(fullName);385}386if (relativeName != null) {387sb.append(relativeName);388}389sb.append('\n');390391if (reasonFlags != null) {392sb.append(" ReasonFlags:\n");393for (int i = 0; i < reasonFlags.length; i++) {394if (reasonFlags[i]) {395sb.append(" ")396.append(reasonToString(i))397.append('\n');398}399}400}401if (crlIssuer != null) {402sb.append(" CRLIssuer:")403.append(crlIssuer)404.append('\n');405}406return sb.toString();407}408409}410411412