001/* 002 * Copyright 2017-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2017-2018 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.util.ssl.cert; 022 023 024 025import java.util.ArrayList; 026import java.util.Collections; 027import java.util.Iterator; 028import java.util.List; 029 030import com.unboundid.asn1.ASN1Element; 031import com.unboundid.asn1.ASN1Sequence; 032import com.unboundid.util.Debug; 033import com.unboundid.util.NotMutable; 034import com.unboundid.util.OID; 035import com.unboundid.util.StaticUtils; 036import com.unboundid.util.ThreadSafety; 037import com.unboundid.util.ThreadSafetyLevel; 038 039import static com.unboundid.util.ssl.cert.CertMessages.*; 040 041 042 043/** 044 * This class provides an implementation of the CRL distribution points X.509 045 * certificate extension as described in 046 * <A HREF="https://www.ietf.org/rfc/rfc5280.txt">RFC 5280</A> section 4.2.1.13. 047 * This can be used to provide information about the location of certificate 048 * revocation lists (CRLs) that can be examined to check the validity of this 049 * certificate. 050 * <BR><BR> 051 * The OID for this extension is 2.5.29.31 and the value has the following 052 * encoding: 053 * <PRE> 054 * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint 055 * 056 * DistributionPoint ::= SEQUENCE { 057 * distributionPoint [0] DistributionPointName OPTIONAL, 058 * reasons [1] ReasonFlags OPTIONAL, 059 * cRLIssuer [2] GeneralNames OPTIONAL } 060 * 061 * DistributionPointName ::= CHOICE { 062 * fullName [0] GeneralNames, 063 * nameRelativeToCRLIssuer [1] RelativeDistinguishedName } 064 * 065 * ReasonFlags ::= BIT STRING { 066 * unused (0), 067 * keyCompromise (1), 068 * cACompromise (2), 069 * affiliationChanged (3), 070 * superseded (4), 071 * cessationOfOperation (5), 072 * certificateHold (6), 073 * privilegeWithdrawn (7), 074 * aACompromise (8) } 075 * </PRE> 076 */ 077@NotMutable() 078@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 079public final class CRLDistributionPointsExtension 080 extends X509CertificateExtension 081{ 082 /** 083 * The OID (2.5.29.31) for CRL distribution points extensions. 084 */ 085 public static final OID CRL_DISTRIBUTION_POINTS_OID = new OID("2.5.29.31"); 086 087 088 089 /** 090 * The serial version UID for this serializable class. 091 */ 092 private static final long serialVersionUID = -4710958813506834961L; 093 094 095 096 // The list of CRL distribution points included in this extension. 097 private final List<CRLDistributionPoint> crlDistributionPoints; 098 099 100 101 /** 102 * Creates a new CRL distribution points extension with the provided 103 * information. 104 * 105 * @param isCritical Indicates whether this extension should be 106 * considered critical. 107 * @param crlDistributionPoints The distribution points to include in this 108 * extension. It must not be {@code null} or 109 * empty. 110 * 111 * @throws CertException If a problem is encountered while trying to encode 112 * the value for this extension. 113 */ 114 CRLDistributionPointsExtension(final boolean isCritical, 115 final List<CRLDistributionPoint> crlDistributionPoints) 116 throws CertException 117 { 118 super(CRL_DISTRIBUTION_POINTS_OID, isCritical, 119 encodeValue(crlDistributionPoints)); 120 121 this.crlDistributionPoints = crlDistributionPoints; 122 } 123 124 125 126 127 /** 128 * Creates a new CRL distribution points extension from the provided generic 129 * extension. 130 * 131 * @param extension The extension to decode as a CRL distribution points 132 * extension. 133 * 134 * @throws CertException If the provided extension cannot be decoded as a 135 * CRL distribution points extension. 136 */ 137 CRLDistributionPointsExtension(final X509CertificateExtension extension) 138 throws CertException 139 { 140 super(extension); 141 142 try 143 { 144 final ASN1Element[] elements = 145 ASN1Sequence.decodeAsSequence(extension.getValue()).elements(); 146 final ArrayList<CRLDistributionPoint> dps = 147 new ArrayList<>(elements.length); 148 for (final ASN1Element e : elements) 149 { 150 dps.add(new CRLDistributionPoint(e)); 151 } 152 153 crlDistributionPoints = Collections.unmodifiableList(dps); 154 } 155 catch (final Exception e) 156 { 157 Debug.debugException(e); 158 throw new CertException( 159 ERR_CRL_DP_EXTENSION_CANNOT_PARSE.get( 160 String.valueOf(extension), StaticUtils.getExceptionMessage(e)), 161 e); 162 } 163 } 164 165 166 167 /** 168 * Encodes the provided information into a form for use as the value for this 169 * extension. 170 * 171 * @param crlDistributionPoints The distribution points to include in this 172 * extension. It must not be {@code null} or 173 * empty. 174 * 175 * @return The encoded value. 176 * 177 * @throws CertException If a problem is encountered while trying to encode 178 * this extension. 179 */ 180 private static byte[] encodeValue( 181 final List<CRLDistributionPoint> crlDistributionPoints) 182 throws CertException 183 { 184 final ArrayList<ASN1Element> elements = 185 new ArrayList<>(crlDistributionPoints.size()); 186 for (final CRLDistributionPoint p : crlDistributionPoints) 187 { 188 elements.add(p.encode()); 189 } 190 191 return new ASN1Sequence(elements).encode(); 192 } 193 194 195 196 /** 197 * Retrieves the list of CRL distribution points included in this extension. 198 * 199 * @return The list of CRL distribution points included in this extension. 200 */ 201 public List<CRLDistributionPoint> getCRLDistributionPoints() 202 { 203 return crlDistributionPoints; 204 } 205 206 207 208 /** 209 * {@inheritDoc} 210 */ 211 @Override() 212 public String getExtensionName() 213 { 214 return INFO_CRL_DP_EXTENSION_NAME.get(); 215 } 216 217 218 219 /** 220 * {@inheritDoc} 221 */ 222 @Override() 223 public void toString(final StringBuilder buffer) 224 { 225 buffer.append("CRLDistributionPointsExtension(oid='"); 226 buffer.append(getOID()); 227 buffer.append("', isCritical="); 228 buffer.append(isCritical()); 229 buffer.append(", distributionPoints={"); 230 231 final Iterator<CRLDistributionPoint> iterator = 232 crlDistributionPoints.iterator(); 233 while (iterator.hasNext()) 234 { 235 iterator.next().toString(buffer); 236 if (iterator.hasNext()) 237 { 238 buffer.append(", "); 239 } 240 } 241 242 buffer.append("})"); 243 } 244}