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