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