1 package org.bouncycastle.cert; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 import java.text.ParseException; 6 import java.util.ArrayList; 7 import java.util.Arrays; 8 import java.util.Collections; 9 import java.util.Date; 10 import java.util.Enumeration; 11 import java.util.HashSet; 12 import java.util.List; 13 import java.util.Set; 14 15 import org.bouncycastle.asn1.ASN1Encodable; 16 import org.bouncycastle.asn1.ASN1EncodableVector; 17 import org.bouncycastle.asn1.ASN1Encoding; 18 import org.bouncycastle.asn1.ASN1GeneralizedTime; 19 import org.bouncycastle.asn1.ASN1Object; 20 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 21 import org.bouncycastle.asn1.ASN1Primitive; 22 import org.bouncycastle.asn1.DERBitString; 23 import org.bouncycastle.asn1.DERNull; 24 import org.bouncycastle.asn1.DERSequence; 25 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 26 import org.bouncycastle.asn1.x509.AttributeCertificate; 27 import org.bouncycastle.asn1.x509.AttributeCertificateInfo; 28 import org.bouncycastle.asn1.x509.Certificate; 29 import org.bouncycastle.asn1.x509.CertificateList; 30 import org.bouncycastle.asn1.x509.Extension; 31 import org.bouncycastle.asn1.x509.Extensions; 32 import org.bouncycastle.asn1.x509.ExtensionsGenerator; 33 import org.bouncycastle.asn1.x509.TBSCertList; 34 import org.bouncycastle.asn1.x509.TBSCertificate; 35 import org.bouncycastle.operator.ContentSigner; 36 import org.bouncycastle.util.Properties; 37 38 class CertUtils 39 { 40 private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet()); 41 private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList()); 42 parseNonEmptyASN1(byte[] encoding)43 static ASN1Primitive parseNonEmptyASN1(byte[] encoding) 44 throws IOException 45 { 46 ASN1Primitive p = ASN1Primitive.fromByteArray(encoding); 47 48 if (p == null) 49 { 50 throw new IOException("no content found"); 51 } 52 return p; 53 } 54 55 generateFullCert(ContentSigner signer, TBSCertificate tbsCert)56 static X509CertificateHolder generateFullCert(ContentSigner signer, TBSCertificate tbsCert) 57 { 58 try 59 { 60 return new X509CertificateHolder(generateStructure(tbsCert, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCert))); 61 } 62 catch (IOException e) 63 { 64 throw new IllegalStateException("cannot produce certificate signature"); 65 } 66 } 67 generateFullAttrCert(ContentSigner signer, AttributeCertificateInfo attrInfo)68 static X509AttributeCertificateHolder generateFullAttrCert(ContentSigner signer, AttributeCertificateInfo attrInfo) 69 { 70 try 71 { 72 return new X509AttributeCertificateHolder(generateAttrStructure(attrInfo, signer.getAlgorithmIdentifier(), generateSig(signer, attrInfo))); 73 } 74 catch (IOException e) 75 { 76 throw new IllegalStateException("cannot produce attribute certificate signature"); 77 } 78 } 79 generateFullCRL(ContentSigner signer, TBSCertList tbsCertList)80 static X509CRLHolder generateFullCRL(ContentSigner signer, TBSCertList tbsCertList) 81 { 82 try 83 { 84 return new X509CRLHolder(generateCRLStructure(tbsCertList, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCertList))); 85 } 86 catch (IOException e) 87 { 88 throw new IllegalStateException("cannot produce certificate signature"); 89 } 90 } 91 generateSig(ContentSigner signer, ASN1Object tbsObj)92 private static byte[] generateSig(ContentSigner signer, ASN1Object tbsObj) 93 throws IOException 94 { 95 OutputStream sOut = signer.getOutputStream(); 96 tbsObj.encodeTo(sOut, ASN1Encoding.DER); 97 sOut.close(); 98 99 return signer.getSignature(); 100 } 101 generateStructure(TBSCertificate tbsCert, AlgorithmIdentifier sigAlgId, byte[] signature)102 private static Certificate generateStructure(TBSCertificate tbsCert, AlgorithmIdentifier sigAlgId, byte[] signature) 103 { 104 ASN1EncodableVector v = new ASN1EncodableVector(); 105 106 v.add(tbsCert); 107 v.add(sigAlgId); 108 v.add(new DERBitString(signature)); 109 110 return Certificate.getInstance(new DERSequence(v)); 111 } 112 generateAttrStructure(AttributeCertificateInfo attrInfo, AlgorithmIdentifier sigAlgId, byte[] signature)113 private static AttributeCertificate generateAttrStructure(AttributeCertificateInfo attrInfo, AlgorithmIdentifier sigAlgId, byte[] signature) 114 { 115 ASN1EncodableVector v = new ASN1EncodableVector(); 116 117 v.add(attrInfo); 118 v.add(sigAlgId); 119 v.add(new DERBitString(signature)); 120 121 return AttributeCertificate.getInstance(new DERSequence(v)); 122 } 123 generateCRLStructure(TBSCertList tbsCertList, AlgorithmIdentifier sigAlgId, byte[] signature)124 private static CertificateList generateCRLStructure(TBSCertList tbsCertList, AlgorithmIdentifier sigAlgId, byte[] signature) 125 { 126 ASN1EncodableVector v = new ASN1EncodableVector(); 127 128 v.add(tbsCertList); 129 v.add(sigAlgId); 130 v.add(new DERBitString(signature)); 131 132 return CertificateList.getInstance(new DERSequence(v)); 133 } 134 getCriticalExtensionOIDs(Extensions extensions)135 static Set getCriticalExtensionOIDs(Extensions extensions) 136 { 137 if (extensions == null) 138 { 139 return EMPTY_SET; 140 } 141 142 return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs()))); 143 } 144 getNonCriticalExtensionOIDs(Extensions extensions)145 static Set getNonCriticalExtensionOIDs(Extensions extensions) 146 { 147 if (extensions == null) 148 { 149 return EMPTY_SET; 150 } 151 152 // TODO: should probably produce a set that imposes correct ordering 153 return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs()))); 154 } 155 getExtensionOIDs(Extensions extensions)156 static List getExtensionOIDs(Extensions extensions) 157 { 158 if (extensions == null) 159 { 160 return EMPTY_LIST; 161 } 162 163 return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs())); 164 } 165 addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value)166 static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value) 167 throws CertIOException 168 { 169 try 170 { 171 extGenerator.addExtension(oid, isCritical, value); 172 } 173 catch (IOException e) 174 { 175 throw new CertIOException("cannot encode extension: " + e.getMessage(), e); 176 } 177 } 178 booleanToBitString(boolean[] id)179 static DERBitString booleanToBitString(boolean[] id) 180 { 181 byte[] bytes = new byte[(id.length + 7) / 8]; 182 183 for (int i = 0; i != id.length; i++) 184 { 185 bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0; 186 } 187 188 int pad = id.length % 8; 189 190 if (pad == 0) 191 { 192 return new DERBitString(bytes); 193 } 194 else 195 { 196 return new DERBitString(bytes, 8 - pad); 197 } 198 } 199 bitStringToBoolean(DERBitString bitString)200 static boolean[] bitStringToBoolean(DERBitString bitString) 201 { 202 if (bitString != null) 203 { 204 byte[] bytes = bitString.getBytes(); 205 boolean[] boolId = new boolean[bytes.length * 8 - bitString.getPadBits()]; 206 207 for (int i = 0; i != boolId.length; i++) 208 { 209 boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; 210 } 211 212 return boolId; 213 } 214 215 return null; 216 } 217 recoverDate(ASN1GeneralizedTime time)218 static Date recoverDate(ASN1GeneralizedTime time) 219 { 220 try 221 { 222 return time.getDate(); 223 } 224 catch (ParseException e) 225 { 226 throw new IllegalStateException("unable to recover date: " + e.getMessage()); 227 } 228 } 229 isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)230 static boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) 231 { 232 if (!id1.getAlgorithm().equals(id2.getAlgorithm())) 233 { 234 return false; 235 } 236 237 if (Properties.isOverrideSet("org.bouncycastle.x509.allow_absent_equiv_NULL")) 238 { 239 if (id1.getParameters() == null) 240 { 241 if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE)) 242 { 243 return false; 244 } 245 246 return true; 247 } 248 249 if (id2.getParameters() == null) 250 { 251 if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE)) 252 { 253 return false; 254 } 255 256 return true; 257 } 258 } 259 260 if (id1.getParameters() != null) 261 { 262 return id1.getParameters().equals(id2.getParameters()); 263 } 264 265 if (id2.getParameters() != null) 266 { 267 return id2.getParameters().equals(id1.getParameters()); 268 } 269 270 return true; 271 } 272 doReplaceExtension(ExtensionsGenerator extGenerator, Extension ext)273 static ExtensionsGenerator doReplaceExtension(ExtensionsGenerator extGenerator, Extension ext) 274 { 275 boolean isReplaced = false; 276 Extensions exts = extGenerator.generate(); 277 extGenerator = new ExtensionsGenerator(); 278 279 for (Enumeration en = exts.oids(); en.hasMoreElements();) 280 { 281 ASN1ObjectIdentifier extOid = (ASN1ObjectIdentifier)en.nextElement(); 282 283 if (extOid.equals(ext.getExtnId())) 284 { 285 isReplaced = true; 286 extGenerator.addExtension(ext); 287 } 288 else 289 { 290 extGenerator.addExtension(exts.getExtension(extOid)); 291 } 292 } 293 294 if (!isReplaced) 295 { 296 throw new IllegalArgumentException("replace - original extension (OID = " + ext.getExtnId() + ") not found"); 297 } 298 299 return extGenerator; 300 } 301 doRemoveExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid)302 static ExtensionsGenerator doRemoveExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid) 303 { 304 boolean isRemoved = false; 305 Extensions exts = extGenerator.generate(); 306 extGenerator = new ExtensionsGenerator(); 307 308 for (Enumeration en = exts.oids(); en.hasMoreElements();) 309 { 310 ASN1ObjectIdentifier extOid = (ASN1ObjectIdentifier)en.nextElement(); 311 312 if (extOid.equals(oid)) 313 { 314 isRemoved = true; 315 } 316 else 317 { 318 extGenerator.addExtension(exts.getExtension(extOid)); 319 } 320 } 321 322 if (!isRemoved) 323 { 324 throw new IllegalArgumentException("remove - extension (OID = " + oid + ") not found"); 325 } 326 327 return extGenerator; 328 } 329 } 330