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