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