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 * Creates a new CRL distribution points extension from the provided generic 128 * extension. 129 * 130 * @param extension The extension to decode as a CRL distribution points 131 * extension. 132 * 133 * @throws CertException If the provided extension cannot be decoded as a 134 * CRL distribution points extension. 135 */ 136 CRLDistributionPointsExtension(final X509CertificateExtension extension) 137 throws CertException 138 { 139 super(extension); 140 141 try 142 { 143 final ASN1Element[] elements = 144 ASN1Sequence.decodeAsSequence(extension.getValue()).elements(); 145 final ArrayList<CRLDistributionPoint> dps = 146 new ArrayList<>(elements.length); 147 for (final ASN1Element e : elements) 148 { 149 dps.add(new CRLDistributionPoint(e)); 150 } 151 152 crlDistributionPoints = Collections.unmodifiableList(dps); 153 } 154 catch (final Exception e) 155 { 156 Debug.debugException(e); 157 throw new CertException( 158 ERR_CRL_DP_EXTENSION_CANNOT_PARSE.get( 159 String.valueOf(extension), StaticUtils.getExceptionMessage(e)), 160 e); 161 } 162 } 163 164 165 166 /** 167 * Encodes the provided information into a form for use as the value for this 168 * extension. 169 * 170 * @param crlDistributionPoints The distribution points to include in this 171 * extension. It must not be {@code null} or 172 * empty. 173 * 174 * @return The encoded value. 175 * 176 * @throws CertException If a problem is encountered while trying to encode 177 * this extension. 178 */ 179 private static byte[] encodeValue( 180 final List<CRLDistributionPoint> crlDistributionPoints) 181 throws CertException 182 { 183 final ArrayList<ASN1Element> elements = 184 new ArrayList<>(crlDistributionPoints.size()); 185 for (final CRLDistributionPoint p : crlDistributionPoints) 186 { 187 elements.add(p.encode()); 188 } 189 190 return new ASN1Sequence(elements).encode(); 191 } 192 193 194 195 /** 196 * Retrieves the list of CRL distribution points included in this extension. 197 * 198 * @return The list of CRL distribution points included in this extension. 199 */ 200 public List<CRLDistributionPoint> getCRLDistributionPoints() 201 { 202 return crlDistributionPoints; 203 } 204 205 206 207 /** 208 * {@inheritDoc} 209 */ 210 @Override() 211 public String getExtensionName() 212 { 213 return INFO_CRL_DP_EXTENSION_NAME.get(); 214 } 215 216 217 218 /** 219 * {@inheritDoc} 220 */ 221 @Override() 222 public void toString(final StringBuilder buffer) 223 { 224 buffer.append("CRLDistributionPointsExtension(oid='"); 225 buffer.append(getOID()); 226 buffer.append("', isCritical="); 227 buffer.append(isCritical()); 228 buffer.append(", distributionPoints={"); 229 230 final Iterator<CRLDistributionPoint> iterator = 231 crlDistributionPoints.iterator(); 232 while (iterator.hasNext()) 233 { 234 iterator.next().toString(buffer); 235 if (iterator.hasNext()) 236 { 237 buffer.append(", "); 238 } 239 } 240 241 buffer.append("})"); 242 } 243}