OpenSSLSignature.java revision a3de55ddf81f95c7c0fc1b8767ccb1ecfa251c83
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.apache.harmony.xnet.provider.jsse;
18
19import java.security.InvalidKeyException;
20import java.security.InvalidParameterException;
21import java.security.NoSuchAlgorithmException;
22import java.security.PrivateKey;
23import java.security.PublicKey;
24import java.security.Signature;
25import java.security.SignatureException;
26import java.security.interfaces.DSAParams;
27import java.security.interfaces.DSAPublicKey;
28import java.security.interfaces.RSAPublicKey;
29import java.util.HashMap;
30import java.util.Map;
31
32/**
33 * Implements the subset of the JDK Signature interface needed for
34 * signature verification using OpenSSL.
35 */
36public class OpenSSLSignature extends Signature {
37
38    private static Map<String,Class<? extends OpenSSLSignature>> jdkToOpenSsl
39            = new HashMap<String,Class<? extends OpenSSLSignature>>();
40
41    static {
42        // TODO Finish OpenSSLSignature implementation and move
43        // registration information to the OpenSSLProvider
44        jdkToOpenSsl.put("MD5WithRSAEncryption", MD5RSA.class);
45        jdkToOpenSsl.put("MD5WithRSA", MD5RSA.class);
46        jdkToOpenSsl.put("MD5/RSA", MD5RSA.class);
47        jdkToOpenSsl.put("1.2.840.113549.1.1.4", MD5RSA.class);
48        jdkToOpenSsl.put("1.2.840.113549.2.5with1.2.840.113549.1.1.1", MD5RSA.class);
49
50        jdkToOpenSsl.put("SHA1WithRSAEncryption", SHA1RSA.class);
51        jdkToOpenSsl.put("SHA1WithRSA", SHA1RSA.class);
52        jdkToOpenSsl.put("SHA1/RSA", SHA1RSA.class);
53        jdkToOpenSsl.put("SHA-1/RSA", SHA1RSA.class);
54        jdkToOpenSsl.put("1.2.840.113549.1.1.5", SHA1RSA.class);
55        jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.113549.1.1.1", SHA1RSA.class);
56        jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.113549.1.1.5", SHA1RSA.class);
57        jdkToOpenSsl.put("1.3.14.3.2.29", SHA1RSA.class);
58
59        jdkToOpenSsl.put("SHA256WithRSAEncryption", SHA256RSA.class);
60        jdkToOpenSsl.put("SHA256WithRSA", SHA256RSA.class);
61        jdkToOpenSsl.put("1.2.840.113549.1.1.11", SHA256RSA.class);
62
63        jdkToOpenSsl.put("SHA384WithRSAEncryption", SHA384RSA.class);
64        jdkToOpenSsl.put("SHA384WithRSA", SHA384RSA.class);
65        jdkToOpenSsl.put("1.2.840.113549.1.1.12", SHA384RSA.class);
66
67        jdkToOpenSsl.put("SHA512WithRSAEncryption", SHA512RSA.class);
68        jdkToOpenSsl.put("SHA512WithRSA", SHA512RSA.class);
69        jdkToOpenSsl.put("1.2.840.113549.1.1.13", SHA512RSA.class);
70
71        jdkToOpenSsl.put("SHA1withDSA", SHA1DSA.class);
72        jdkToOpenSsl.put("SHA/DSA", SHA1DSA.class);
73        jdkToOpenSsl.put("DSA", SHA1DSA.class);
74        jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.10040.4.1", SHA1DSA.class);
75        jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.10040.4.3", SHA1DSA.class);
76        jdkToOpenSsl.put("DSAWithSHA1", SHA1DSA.class);
77        jdkToOpenSsl.put("1.2.840.10040.4.3", SHA1DSA.class);
78    }
79
80    /**
81     * Holds a pointer to the native message digest context.
82     */
83    private final int ctx;
84
85    /**
86     * Holds a pointer to the native DSA key.
87     */
88    private int dsa;
89
90    /**
91     * Holds a pointer to the native RSA key.
92     */
93    private int rsa;
94
95    /**
96     * Holds the OpenSSL name of the algorithm (lower case, no dashes).
97     */
98    private final String evpAlgorithm;
99
100    /**
101     * Holds a dummy buffer for writing single bytes to the digest.
102     */
103    private final byte[] singleByte = new byte[1];
104
105    /**
106     * Creates a new OpenSSLSignature instance for the given algorithm name.
107     *
108     * @param algorithm The name of the algorithm, e.g. "SHA1WithRSA".
109     *
110     * @return The new OpenSSLSignature instance.
111     *
112     * @throws RuntimeException In case of problems.
113     */
114    public static OpenSSLSignature getInstance(String algorithm) throws NoSuchAlgorithmException {
115        // System.out.println("getInstance() invoked with " + algorithm);
116
117        Class <? extends OpenSSLSignature> clazz = jdkToOpenSsl.get(algorithm);
118        if (clazz == null) {
119            throw new NoSuchAlgorithmException(algorithm);
120        }
121        try {
122            return clazz.newInstance();
123        } catch (InstantiationException e) {
124            throw new NoSuchAlgorithmException(algorithm, e);
125        } catch (IllegalAccessException e) {
126            throw new NoSuchAlgorithmException(algorithm, e);
127        }
128    }
129
130    /**
131     * Creates a new OpenSSLSignature instance for the given algorithm name.
132     *
133     * @param algorithm OpenSSL name of the algorithm, e.g. "RSA-SHA1".
134     */
135    private OpenSSLSignature(String algorithm) throws NoSuchAlgorithmException {
136        super(algorithm);
137
138        // We don't support MD2
139        if ("RSA-MD2".equals(algorithm)) {
140            throw new NoSuchAlgorithmException(algorithm);
141        }
142
143        this.evpAlgorithm = algorithm;
144        this.ctx = NativeCrypto.EVP_MD_CTX_create();
145    }
146
147    @Override
148    protected void engineUpdate(byte input) {
149        singleByte[0] = input;
150        engineUpdate(singleByte, 0, 1);
151    }
152
153    @Override
154    protected void engineUpdate(byte[] input, int offset, int len) {
155        if (state == SIGN) {
156            throw new UnsupportedOperationException();
157        } else {
158            NativeCrypto.EVP_VerifyUpdate(ctx, input, offset, len);
159        }
160    }
161
162    @Override
163    protected Object engineGetParameter(String param) throws InvalidParameterException {
164        return null;
165    }
166
167    @Override
168    protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
169        throw new UnsupportedOperationException();
170    }
171
172    @Override
173    protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
174        // System.out.println("engineInitVerify() invoked with "
175        //                    + publicKey.getClass().getCanonicalName());
176
177        if (publicKey instanceof DSAPublicKey) {
178            try {
179                DSAPublicKey dsaPublicKey = (DSAPublicKey)publicKey;
180                DSAParams dsaParams = dsaPublicKey.getParams();
181                dsa = NativeCrypto.EVP_PKEY_new_DSA(dsaParams.getP().toByteArray(),
182                        dsaParams.getQ().toByteArray(), dsaParams.getG().toByteArray(),
183                        dsaPublicKey.getY().toByteArray(), null);
184
185            } catch (Exception ex) {
186                throw new InvalidKeyException(ex.toString());
187            }
188        } else if (publicKey instanceof RSAPublicKey) {
189            try {
190                RSAPublicKey rsaPublicKey = (RSAPublicKey)publicKey;
191                rsa = NativeCrypto.EVP_PKEY_new_RSA(rsaPublicKey.getModulus().toByteArray(),
192                        rsaPublicKey.getPublicExponent().toByteArray(), null, null, null);
193
194            } catch (Exception ex) {
195                throw new InvalidKeyException(ex.toString());
196            }
197        } else {
198            throw new InvalidKeyException("Need DSA or RSA public key");
199        }
200
201        try {
202            NativeCrypto.EVP_VerifyInit(ctx, evpAlgorithm);
203        } catch (Exception ex) {
204            throw new RuntimeException(ex);
205        }
206    }
207
208    @Override
209    protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
210    }
211
212    @Override
213    protected byte[] engineSign() throws SignatureException {
214        throw new UnsupportedOperationException();
215    }
216
217    @Override
218    protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
219        int handle = (rsa != 0) ? rsa : dsa;
220
221        if (handle == 0) {
222            // This can't actually happen, but you never know...
223            throw new SignatureException("Need DSA or RSA public key");
224        }
225
226        try {
227            int result = NativeCrypto.EVP_VerifyFinal(ctx, sigBytes, 0, sigBytes.length, handle);
228            return result == 1;
229        } catch (Exception ex) {
230            throw new SignatureException(ex);
231        }
232
233    }
234
235    @Override
236    protected void finalize() throws Throwable {
237        super.finalize();
238
239        if (dsa != 0) {
240            NativeCrypto.EVP_PKEY_free(dsa);
241        }
242
243        if (rsa != 0) {
244            NativeCrypto.EVP_PKEY_free(rsa);
245        }
246
247        if (ctx != 0) {
248            NativeCrypto.EVP_MD_CTX_destroy(ctx);
249        }
250    }
251
252    public static final class MD5RSA extends OpenSSLSignature {
253        public MD5RSA() throws NoSuchAlgorithmException {
254            super("RSA-MD5");
255        }
256    }
257    public static final class SHA1RSA extends OpenSSLSignature {
258        public SHA1RSA() throws NoSuchAlgorithmException {
259            super("RSA-SHA1");
260        }
261    }
262    public static final class SHA256RSA extends OpenSSLSignature {
263        public SHA256RSA() throws NoSuchAlgorithmException {
264            super("RSA-SHA256");
265        }
266    }
267    public static final class SHA384RSA extends OpenSSLSignature {
268        public SHA384RSA() throws NoSuchAlgorithmException {
269            super("RSA-SHA384");
270        }
271    }
272    public static final class SHA512RSA extends OpenSSLSignature {
273        public SHA512RSA() throws NoSuchAlgorithmException {
274            super("RSA-SHA512");
275        }
276    }
277    public static final class SHA1DSA extends OpenSSLSignature {
278        public SHA1DSA() throws NoSuchAlgorithmException {
279            super("DSA-SHA1");
280        }
281    }
282}
283
284