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