1/*
2 * Copyright (C) 2012 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.conscrypt;
18
19import java.security.InvalidKeyException;
20import java.security.NoSuchAlgorithmException;
21import java.security.PrivateKey;
22import javax.crypto.SecretKey;
23
24public class OpenSSLEngine {
25    static {
26        NativeCrypto.ENGINE_load_dynamic();
27    }
28
29    private static final Object mLoadingLock = new Object();
30
31    /** The ENGINE's native handle. */
32    private final long ctx;
33
34    public static OpenSSLEngine getInstance(String engine) throws IllegalArgumentException {
35        if (engine == null) {
36            throw new NullPointerException("engine == null");
37        }
38
39        final long engineCtx;
40        synchronized (mLoadingLock) {
41            engineCtx = NativeCrypto.ENGINE_by_id(engine);
42            if (engineCtx == 0) {
43                throw new IllegalArgumentException("Unknown ENGINE id: " + engine);
44            }
45
46            NativeCrypto.ENGINE_add(engineCtx);
47        }
48
49        return new OpenSSLEngine(engineCtx);
50    }
51
52    private OpenSSLEngine(long engineCtx) {
53        ctx = engineCtx;
54
55        if (NativeCrypto.ENGINE_init(engineCtx) == 0) {
56            NativeCrypto.ENGINE_free(engineCtx);
57            throw new IllegalArgumentException("Could not initialize engine");
58        }
59    }
60
61    public PrivateKey getPrivateKeyById(String id) throws InvalidKeyException {
62        if (id == null) {
63            throw new NullPointerException("id == null");
64        }
65
66        final long keyRef = NativeCrypto.ENGINE_load_private_key(ctx, id);
67        if (keyRef == 0) {
68            return null;
69        }
70
71        OpenSSLKey pkey = new OpenSSLKey(keyRef, this, id);
72        try {
73            return pkey.getPrivateKey();
74        } catch (NoSuchAlgorithmException e) {
75            throw new InvalidKeyException(e);
76        }
77    }
78
79    public SecretKey getSecretKeyById(String id, String algorithm) throws InvalidKeyException {
80        if (id == null) {
81            throw new NullPointerException("id == null");
82        }
83
84        final long keyRef = NativeCrypto.ENGINE_load_private_key(ctx, id);
85        if (keyRef == 0) {
86            return null;
87        }
88
89        OpenSSLKey pkey = new OpenSSLKey(keyRef, this, id);
90        try {
91            return pkey.getSecretKey(algorithm);
92        } catch (NoSuchAlgorithmException e) {
93            throw new InvalidKeyException(e);
94        }
95    }
96
97    long getEngineContext() {
98        return ctx;
99    }
100
101    @Override
102    protected void finalize() throws Throwable {
103        try {
104            NativeCrypto.ENGINE_finish(ctx);
105            NativeCrypto.ENGINE_free(ctx);
106        } finally {
107            super.finalize();
108        }
109    }
110
111    @Override
112    public boolean equals(Object o) {
113        if (o == this) {
114            return true;
115        }
116
117        if (!(o instanceof OpenSSLEngine)) {
118            return false;
119        }
120
121        OpenSSLEngine other = (OpenSSLEngine) o;
122
123        if (other.getEngineContext() == ctx) {
124            return true;
125        }
126
127        final String id = NativeCrypto.ENGINE_get_id(ctx);
128        if (id == null) {
129            return false;
130        }
131
132        return id.equals(NativeCrypto.ENGINE_get_id(other.getEngineContext()));
133    }
134
135    @Override
136    public int hashCode() {
137      return (int) ctx;
138    }
139}
140