1package org.bouncycastle.operator.jcajce;
2
3import java.io.ByteArrayInputStream;
4import java.io.IOException;
5import java.security.AlgorithmParameters;
6import java.security.GeneralSecurityException;
7import java.security.KeyFactory;
8import java.security.MessageDigest;
9import java.security.NoSuchAlgorithmException;
10import java.security.NoSuchProviderException;
11import java.security.PublicKey;
12import java.security.Signature;
13import java.security.cert.CertificateException;
14import java.security.cert.CertificateFactory;
15import java.security.cert.X509Certificate;
16import java.security.spec.InvalidKeySpecException;
17import java.security.spec.PSSParameterSpec;
18import java.security.spec.X509EncodedKeySpec;
19import java.util.HashMap;
20import java.util.Map;
21
22import javax.crypto.Cipher;
23
24import org.bouncycastle.asn1.ASN1Encodable;
25import org.bouncycastle.asn1.ASN1ObjectIdentifier;
26import org.bouncycastle.asn1.DERNull;
27// BEGIN android-removed
28// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
29// END android-removed
30import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
31import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
32import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
33import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
34import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
35import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
36import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
37import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
38import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
39import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
40import org.bouncycastle.cert.X509CertificateHolder;
41import org.bouncycastle.jcajce.JcaJceHelper;
42import org.bouncycastle.jcajce.JcaJceUtils;
43import org.bouncycastle.operator.OperatorCreationException;
44
45class OperatorHelper
46{
47    private static final Map oids = new HashMap();
48    private static final Map asymmetricWrapperAlgNames = new HashMap();
49    private static final Map symmetricWrapperAlgNames = new HashMap();
50    private static final Map symmetricKeyAlgNames = new HashMap();
51
52    static
53    {
54        //
55        // reverse mappings
56        //
57        oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
58        oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
59        oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
60        oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
61        oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
62        // BEGIN android-removed
63        // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
64        // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
65        // END android-removed
66
67        oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
68        // BEGIN android-removed
69        // oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
70        // END android-removed
71        oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
72        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
73        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
74        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
75        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
76        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
77        oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
78        oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
79        oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
80        oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
81
82        oids.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
83        oids.put(NISTObjectIdentifiers.id_sha224, "SHA-224");
84        oids.put(NISTObjectIdentifiers.id_sha256, "SHA-256");
85        oids.put(NISTObjectIdentifiers.id_sha384, "SHA-384");
86        oids.put(NISTObjectIdentifiers.id_sha512, "SHA-512");
87        oids.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD-128");
88        oids.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD-160");
89        oids.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD-256");
90
91        asymmetricWrapperAlgNames.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding");
92
93        symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWrap");
94        symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2Wrap");
95        symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes128_wrap, "AESWrap");
96        symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes192_wrap, "AESWrap");
97        symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes256_wrap, "AESWrap");
98        symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia128_wrap, "CamelliaWrap");
99        symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia192_wrap, "CamelliaWrap");
100        symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia256_wrap, "CamelliaWrap");
101        symmetricWrapperAlgNames.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, "SEEDWrap");
102        symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
103
104        symmetricKeyAlgNames.put(NISTObjectIdentifiers.aes, "AES");
105        symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes128_CBC, "AES");
106        symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes192_CBC, "AES");
107        symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes256_CBC, "AES");
108        symmetricKeyAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
109        symmetricKeyAlgNames.put(PKCSObjectIdentifiers.RC2_CBC, "RC2");
110    }
111
112    private JcaJceHelper helper;
113
114    OperatorHelper(JcaJceHelper helper)
115    {
116        this.helper = helper;
117    }
118
119    Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames)
120        throws OperatorCreationException
121    {
122        try
123        {
124            String cipherName = null;
125
126            if (!extraAlgNames.isEmpty())
127            {
128                cipherName = (String)extraAlgNames.get(algorithm);
129            }
130
131            if (cipherName == null)
132            {
133                cipherName = (String)asymmetricWrapperAlgNames.get(algorithm);
134            }
135
136            if (cipherName != null)
137            {
138                try
139                {
140                    // this is reversed as the Sun policy files now allow unlimited strength RSA
141                    return helper.createCipher(cipherName);
142                }
143                catch (NoSuchAlgorithmException e)
144                {
145                    // try alternate for RSA
146                    if (cipherName.equals("RSA/ECB/PKCS1Padding"))
147                    {
148                        try
149                        {
150                            return helper.createCipher("RSA/NONE/PKCS1Padding");
151                        }
152                        catch (NoSuchAlgorithmException ex)
153                        {
154                            // Ignore
155                        }
156                    }
157                    // Ignore
158                }
159            }
160
161            return helper.createCipher(algorithm.getId());
162        }
163        catch (GeneralSecurityException e)
164        {
165            throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
166        }
167    }
168
169    Cipher createSymmetricWrapper(ASN1ObjectIdentifier algorithm)
170        throws OperatorCreationException
171    {
172        try
173        {
174            String cipherName = (String)symmetricWrapperAlgNames.get(algorithm);
175
176            if (cipherName != null)
177            {
178                try
179                {
180                    // this is reversed as the Sun policy files now allow unlimited strength RSA
181                    return helper.createCipher(cipherName);
182                }
183                catch (NoSuchAlgorithmException e)
184                {
185                    // Ignore
186                }
187            }
188            return helper.createCipher(algorithm.getId());
189        }
190        catch (GeneralSecurityException e)
191        {
192            throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
193        }
194    }
195
196    AlgorithmParameters createAlgorithmParameters(AlgorithmIdentifier cipherAlgId)
197        throws OperatorCreationException
198    {
199        AlgorithmParameters parameters;
200
201        if (cipherAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
202        {
203            return null;
204        }
205
206        try
207        {
208            parameters = helper.createAlgorithmParameters(cipherAlgId.getAlgorithm().getId());
209        }
210        catch (NoSuchAlgorithmException e)
211        {
212            return null;   // There's a good chance there aren't any!
213        }
214        catch (NoSuchProviderException e)
215        {
216            throw new OperatorCreationException("cannot create algorithm parameters: " + e.getMessage(), e);
217        }
218
219        try
220        {
221            parameters.init(cipherAlgId.getParameters().toASN1Primitive().getEncoded());
222        }
223        catch (IOException e)
224        {
225            throw new OperatorCreationException("cannot initialise algorithm parameters: " + e.getMessage(), e);
226        }
227
228        return parameters;
229    }
230
231    MessageDigest createDigest(AlgorithmIdentifier digAlgId)
232        throws GeneralSecurityException
233    {
234        MessageDigest dig;
235
236        try
237        {
238            dig = helper.createDigest(getDigestAlgName(digAlgId.getAlgorithm()));
239        }
240        catch (NoSuchAlgorithmException e)
241        {
242            //
243            // try an alternate
244            //
245            if (oids.get(digAlgId.getAlgorithm()) != null)
246            {
247                String  digestAlgorithm = (String)oids.get(digAlgId.getAlgorithm());
248
249                dig = helper.createDigest(digestAlgorithm);
250            }
251            else
252            {
253                throw e;
254            }
255        }
256
257        return dig;
258    }
259
260    Signature createSignature(AlgorithmIdentifier sigAlgId)
261        throws GeneralSecurityException
262    {
263        Signature   sig;
264
265        try
266        {
267            sig = helper.createSignature(getSignatureName(sigAlgId));
268        }
269        catch (NoSuchAlgorithmException e)
270        {
271            //
272            // try an alternate
273            //
274            if (oids.get(sigAlgId.getAlgorithm()) != null)
275            {
276                String  signatureAlgorithm = (String)oids.get(sigAlgId.getAlgorithm());
277
278                sig = helper.createSignature(signatureAlgorithm);
279            }
280            else
281            {
282                throw e;
283            }
284        }
285
286        return sig;
287    }
288
289    public Signature createRawSignature(AlgorithmIdentifier algorithm)
290    {
291        Signature   sig;
292
293        try
294        {
295            String algName = getSignatureName(algorithm);
296
297            algName = "NONE" + algName.substring(algName.indexOf("WITH"));
298
299            sig = helper.createSignature(algName);
300
301            // RFC 4056
302            // When the id-RSASSA-PSS algorithm identifier is used for a signature,
303            // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params.
304            if (algorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
305            {
306                AlgorithmParameters params = helper.createAlgorithmParameters(algName);
307
308                JcaJceUtils.loadParameters(params, algorithm.getParameters());
309
310                PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class);
311                sig.setParameter(spec);
312            }
313        }
314        catch (Exception e)
315        {
316            return null;
317        }
318
319        return sig;
320    }
321
322    private static String getSignatureName(
323        AlgorithmIdentifier sigAlgId)
324    {
325        ASN1Encodable params = sigAlgId.getParameters();
326
327        if (params != null && !DERNull.INSTANCE.equals(params))
328        {
329            if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
330            {
331                RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
332                return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1";
333            }
334        }
335
336        if (oids.containsKey(sigAlgId.getAlgorithm()))
337        {
338            return (String)oids.get(sigAlgId.getAlgorithm());
339        }
340
341        return sigAlgId.getAlgorithm().getId();
342    }
343
344    private static String getDigestAlgName(
345        ASN1ObjectIdentifier digestAlgOID)
346    {
347        if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
348        {
349            return "MD5";
350        }
351        else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
352        {
353            return "SHA1";
354        }
355        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
356        {
357            return "SHA224";
358        }
359        else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
360        {
361            return "SHA256";
362        }
363        else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
364        {
365            return "SHA384";
366        }
367        else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
368        {
369            return "SHA512";
370        }
371        // BEGIN android-removed
372        // else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
373        // {
374        //     return "RIPEMD128";
375        // }
376        // else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
377        // {
378        //     return "RIPEMD160";
379        // }
380        // else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
381        // {
382        //     return "RIPEMD256";
383        // }
384        // else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
385        // {
386        //     return "GOST3411";
387        // }
388        // END android-removed
389        else
390        {
391            return digestAlgOID.getId();
392        }
393    }
394
395    public X509Certificate convertCertificate(X509CertificateHolder certHolder)
396        throws CertificateException
397    {
398
399        try
400        {
401            CertificateFactory certFact = helper.createCertificateFactory("X.509");
402
403            return (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded()));
404        }
405        catch (IOException e)
406        {
407            throw new OpCertificateException("cannot get encoded form of certificate: " + e.getMessage(), e);
408        }
409        catch (NoSuchAlgorithmException e)
410        {
411            throw new OpCertificateException("cannot create certificate factory: " + e.getMessage(), e);
412        }
413        catch (NoSuchProviderException e)
414        {
415            throw new OpCertificateException("cannot find factory provider: " + e.getMessage(), e);
416        }
417    }
418
419    public PublicKey convertPublicKey(SubjectPublicKeyInfo publicKeyInfo)
420        throws OperatorCreationException
421    {
422        try
423        {
424            KeyFactory keyFact = helper.createKeyFactory(publicKeyInfo.getAlgorithm().getAlgorithm().getId());
425
426            return keyFact.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
427        }
428        catch (IOException e)
429        {
430            throw new OperatorCreationException("cannot get encoded form of key: " + e.getMessage(), e);
431        }
432        catch (NoSuchAlgorithmException e)
433        {
434            throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
435        }
436        catch (NoSuchProviderException e)
437        {
438            throw new OperatorCreationException("cannot find factory provider: " + e.getMessage(), e);
439        }
440        catch (InvalidKeySpecException e)
441        {
442            throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
443        }
444    }
445
446    // TODO: put somewhere public so cause easily accessed
447    private static class OpCertificateException
448        extends CertificateException
449    {
450        private Throwable cause;
451
452        public OpCertificateException(String msg, Throwable cause)
453        {
454            super(msg);
455
456            this.cause = cause;
457        }
458
459        public Throwable getCause()
460        {
461            return cause;
462        }
463    }
464
465    String getKeyAlgorithmName(ASN1ObjectIdentifier oid)
466    {
467
468        String name = (String)symmetricKeyAlgNames.get(oid);
469
470        if (name != null)
471        {
472            return name;
473        }
474
475        return oid.getId();
476    }
477}
478