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