1package org.bouncycastle.x509;
2
3import org.bouncycastle.asn1.ASN1Encodable;
4import org.bouncycastle.asn1.DEREncodable;
5import org.bouncycastle.asn1.DERInteger;
6import org.bouncycastle.asn1.DERNull;
7import org.bouncycastle.asn1.DERObjectIdentifier;
8import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
9import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
10import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
11import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
12import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
13import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
14import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
15import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
16import org.bouncycastle.jce.X509Principal;
17import org.bouncycastle.util.Strings;
18
19import javax.security.auth.x500.X500Principal;
20import java.io.IOException;
21import java.security.InvalidKeyException;
22import java.security.NoSuchAlgorithmException;
23import java.security.NoSuchProviderException;
24import java.security.PrivateKey;
25import java.security.Provider;
26import java.security.SecureRandom;
27import java.security.Security;
28import java.security.Signature;
29import java.security.SignatureException;
30import java.util.ArrayList;
31import java.util.Enumeration;
32import java.util.HashSet;
33import java.util.Hashtable;
34import java.util.Iterator;
35import java.util.List;
36import java.util.Set;
37
38class X509Util
39{
40    private static Hashtable algorithms = new Hashtable();
41    private static Hashtable params = new Hashtable();
42    private static Set       noParams = new HashSet();
43
44    static
45    {
46        // BEGIN android-removed
47        // algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
48        // algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
49        // END android-removed
50        algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
51        algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
52        algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
53        algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
54        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
55        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
56        algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
57        algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
58        algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
59        algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
60        algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
61        algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
62        algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
63        algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
64        algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
65        algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
66        algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
67        algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
68        algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
69        algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
70        algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
71        algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
72        algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
73        algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
74        algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
75        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
76        algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
77        algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
78        algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
79        algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
80        algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
81        algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
82        algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
83        algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
84        algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
85        algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
86        algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
87        algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
88
89        //
90        // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
91        // The parameters field SHALL be NULL for RSA based signature algorithms.
92        //
93        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
94        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
95        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
96        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
97        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
98        noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
99        noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
100        noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
101
102        //
103        // RFC 4491
104        //
105        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
106        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
107
108        //
109        // explicit params
110        //
111        // BEGIN android-changed
112        AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
113        // END android-changed
114        params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
115
116        // BEGIN android-changed
117        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
118        // END android-changed
119        params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
120
121        // BEGIN android-changed
122        AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
123        // END android-changed
124        params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
125
126        // BEGIN android-changed
127        AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
128        // END android-changed
129        params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
130
131        // BEGIN android-changed
132        AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
133        // END android-changed
134        params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
135    }
136
137    private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
138    {
139        return new RSASSAPSSparams(
140            hashAlgId,
141            new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
142            new DERInteger(saltSize),
143            new DERInteger(1));
144    }
145
146    static DERObjectIdentifier getAlgorithmOID(
147        String algorithmName)
148    {
149        algorithmName = Strings.toUpperCase(algorithmName);
150
151        if (algorithms.containsKey(algorithmName))
152        {
153            return (DERObjectIdentifier)algorithms.get(algorithmName);
154        }
155
156        return new DERObjectIdentifier(algorithmName);
157    }
158
159    static AlgorithmIdentifier getSigAlgID(
160        DERObjectIdentifier sigOid,
161        String              algorithmName)
162    {
163        if (noParams.contains(sigOid))
164        {
165            return new AlgorithmIdentifier(sigOid);
166        }
167
168        algorithmName = Strings.toUpperCase(algorithmName);
169
170        if (params.containsKey(algorithmName))
171        {
172            return new AlgorithmIdentifier(sigOid, (DEREncodable)params.get(algorithmName));
173        }
174        else
175        {
176            // BEGIN android-changed
177            return new AlgorithmIdentifier(sigOid, DERNull.INSTANCE);
178            // END android-changed
179        }
180    }
181
182    static Iterator getAlgNames()
183    {
184        Enumeration e = algorithms.keys();
185        List        l = new ArrayList();
186
187        while (e.hasMoreElements())
188        {
189            l.add(e.nextElement());
190        }
191
192        return l.iterator();
193    }
194
195    static Signature getSignatureInstance(
196        String algorithm)
197        throws NoSuchAlgorithmException
198    {
199        return Signature.getInstance(algorithm);
200    }
201
202    static Signature getSignatureInstance(
203        String algorithm,
204        String provider)
205        throws NoSuchProviderException, NoSuchAlgorithmException
206    {
207        if (provider != null)
208        {
209            return Signature.getInstance(algorithm, provider);
210        }
211        else
212        {
213            return Signature.getInstance(algorithm);
214        }
215    }
216
217    static byte[] calculateSignature(
218        DERObjectIdentifier sigOid,
219        String              sigName,
220        PrivateKey          key,
221        SecureRandom        random,
222        ASN1Encodable       object)
223        throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
224    {
225        Signature sig;
226
227        if (sigOid == null)
228        {
229            throw new IllegalStateException("no signature algorithm specified");
230        }
231
232        sig = X509Util.getSignatureInstance(sigName);
233
234        if (random != null)
235        {
236            sig.initSign(key, random);
237        }
238        else
239        {
240            sig.initSign(key);
241        }
242
243        sig.update(object.getEncoded(ASN1Encodable.DER));
244
245        return sig.sign();
246    }
247
248    static byte[] calculateSignature(
249        DERObjectIdentifier sigOid,
250        String              sigName,
251        String              provider,
252        PrivateKey          key,
253        SecureRandom        random,
254        ASN1Encodable       object)
255        throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
256    {
257        Signature sig;
258
259        if (sigOid == null)
260        {
261            throw new IllegalStateException("no signature algorithm specified");
262        }
263
264        sig = X509Util.getSignatureInstance(sigName, provider);
265
266        if (random != null)
267        {
268            sig.initSign(key, random);
269        }
270        else
271        {
272            sig.initSign(key);
273        }
274
275        sig.update(object.getEncoded(ASN1Encodable.DER));
276
277        return sig.sign();
278    }
279
280    static X509Principal convertPrincipal(
281        X500Principal principal)
282    {
283        try
284        {
285            return new X509Principal(principal.getEncoded());
286        }
287        catch (IOException e)
288        {
289            throw new IllegalArgumentException("cannot convert principal");
290        }
291    }
292
293    static class Implementation
294    {
295        Object      engine;
296        Provider provider;
297
298        Implementation(
299            Object      engine,
300            Provider    provider)
301        {
302            this.engine = engine;
303            this.provider = provider;
304        }
305
306        Object getEngine()
307        {
308            return engine;
309        }
310
311        Provider getProvider()
312        {
313            return provider;
314        }
315    }
316
317    /**
318     * see if we can find an algorithm (or its alias and what it represents) in
319     * the property table for the given provider.
320     */
321    static Implementation getImplementation(
322        String      baseName,
323        String      algorithm,
324        Provider    prov)
325        throws NoSuchAlgorithmException
326    {
327        algorithm = Strings.toUpperCase(algorithm);
328
329        String      alias;
330
331        while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null)
332        {
333            algorithm = alias;
334        }
335
336        String      className = prov.getProperty(baseName + "." + algorithm);
337
338        if (className != null)
339        {
340            try
341            {
342                Class       cls;
343                ClassLoader clsLoader = prov.getClass().getClassLoader();
344
345                if (clsLoader != null)
346                {
347                    cls = clsLoader.loadClass(className);
348                }
349                else
350                {
351                    cls = Class.forName(className);
352                }
353
354                return new Implementation(cls.newInstance(), prov);
355            }
356            catch (ClassNotFoundException e)
357            {
358                throw new IllegalStateException(
359                    "algorithm " + algorithm + " in provider " + prov.getName() + " but no class \"" + className + "\" found!");
360            }
361            catch (Exception e)
362            {
363                throw new IllegalStateException(
364                    "algorithm " + algorithm + " in provider " + prov.getName() + " but class \"" + className + "\" inaccessible!");
365            }
366        }
367
368        throw new NoSuchAlgorithmException("cannot find implementation " + algorithm + " for provider " + prov.getName());
369    }
370
371    /**
372     * return an implementation for a given algorithm/provider.
373     * If the provider is null, we grab the first avalaible who has the required algorithm.
374     */
375    static Implementation getImplementation(
376        String      baseName,
377        String      algorithm)
378        throws NoSuchAlgorithmException
379    {
380        Provider[] prov = Security.getProviders();
381
382        //
383        // search every provider looking for the algorithm we want.
384        //
385        for (int i = 0; i != prov.length; i++)
386        {
387            //
388            // try case insensitive
389            //
390            Implementation imp = getImplementation(baseName, Strings.toUpperCase(algorithm), prov[i]);
391            if (imp != null)
392            {
393                return imp;
394            }
395
396            try
397            {
398                imp = getImplementation(baseName, algorithm, prov[i]);
399            }
400            catch (NoSuchAlgorithmException e)
401            {
402                // continue
403            }
404        }
405
406        throw new NoSuchAlgorithmException("cannot find implementation " + algorithm);
407    }
408
409    static Provider getProvider(String provider)
410        throws NoSuchProviderException
411    {
412        Provider prov = Security.getProvider(provider);
413
414        if (prov == null)
415        {
416            throw new NoSuchProviderException("Provider " + provider + " not found");
417        }
418
419        return prov;
420    }
421}
422