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 17 package org.conscrypt; 18 19 import java.security.InvalidKeyException; 20 import java.security.NoSuchAlgorithmException; 21 import java.security.PrivateKey; 22 import javax.crypto.SecretKey; 23 24 public class OpenSSLEngine { 25 static { 26 if (!NativeCrypto.isBoringSSL) { NativeCrypto.ENGINE_load_dynamic()27 NativeCrypto.ENGINE_load_dynamic(); 28 } 29 } 30 31 private static final Object mLoadingLock = new Object(); 32 33 /** The ENGINE's native handle. */ 34 private final long ctx; 35 36 /** 37 * BoringSSL doesn't really use ENGINE objects, so we just keep this single 38 * instance around to satisfy API calls. 39 */ 40 private static class BoringSSL { 41 public static final OpenSSLEngine INSTANCE = new OpenSSLEngine(); 42 } 43 getInstance(String engine)44 public static OpenSSLEngine getInstance(String engine) throws IllegalArgumentException { 45 if (NativeCrypto.isBoringSSL) { 46 return BoringSSL.INSTANCE; 47 } 48 49 if (engine == null) { 50 throw new NullPointerException("engine == null"); 51 } 52 53 final long engineCtx; 54 synchronized (mLoadingLock) { 55 engineCtx = NativeCrypto.ENGINE_by_id(engine); 56 if (engineCtx == 0) { 57 throw new IllegalArgumentException("Unknown ENGINE id: " + engine); 58 } 59 60 NativeCrypto.ENGINE_add(engineCtx); 61 } 62 63 return new OpenSSLEngine(engineCtx); 64 } 65 66 /** 67 * Used for BoringSSL. It doesn't use ENGINEs so there is no native pointer 68 * to keep track of. 69 */ OpenSSLEngine()70 private OpenSSLEngine() { 71 ctx = 0L; 72 } 73 74 /** 75 * Used when OpenSSL is in use. It uses an ENGINE instance so we need to 76 * keep track if the native pointer for later freeing. 77 * 78 * @param engineCtx the ENGINE's native handle 79 */ OpenSSLEngine(long engineCtx)80 private OpenSSLEngine(long engineCtx) { 81 ctx = engineCtx; 82 83 if (NativeCrypto.ENGINE_init(engineCtx) == 0) { 84 NativeCrypto.ENGINE_free(engineCtx); 85 throw new IllegalArgumentException("Could not initialize engine"); 86 } 87 } 88 getPrivateKeyById(String id)89 public PrivateKey getPrivateKeyById(String id) throws InvalidKeyException { 90 if (id == null) { 91 throw new NullPointerException("id == null"); 92 } 93 94 final long keyRef = NativeCrypto.ENGINE_load_private_key(ctx, id); 95 if (keyRef == 0) { 96 return null; 97 } 98 99 OpenSSLKey pkey = new OpenSSLKey(keyRef, this, id); 100 try { 101 return pkey.getPrivateKey(); 102 } catch (NoSuchAlgorithmException e) { 103 throw new InvalidKeyException(e); 104 } 105 } 106 getSecretKeyById(String id, String algorithm)107 public SecretKey getSecretKeyById(String id, String algorithm) throws InvalidKeyException { 108 if (id == null) { 109 throw new NullPointerException("id == null"); 110 } 111 112 final long keyRef = NativeCrypto.ENGINE_load_private_key(ctx, id); 113 if (keyRef == 0) { 114 return null; 115 } 116 117 OpenSSLKey pkey = new OpenSSLKey(keyRef, this, id); 118 try { 119 return pkey.getSecretKey(algorithm); 120 } catch (NoSuchAlgorithmException e) { 121 throw new InvalidKeyException(e); 122 } 123 } 124 getEngineContext()125 long getEngineContext() { 126 return ctx; 127 } 128 129 @Override finalize()130 protected void finalize() throws Throwable { 131 try { 132 if (!NativeCrypto.isBoringSSL) { 133 NativeCrypto.ENGINE_finish(ctx); 134 NativeCrypto.ENGINE_free(ctx); 135 } 136 } finally { 137 super.finalize(); 138 } 139 } 140 141 @Override equals(Object o)142 public boolean equals(Object o) { 143 if (o == this) { 144 return true; 145 } 146 147 if (!(o instanceof OpenSSLEngine)) { 148 return false; 149 } 150 151 OpenSSLEngine other = (OpenSSLEngine) o; 152 153 if (other.getEngineContext() == ctx) { 154 return true; 155 } 156 157 final String id = NativeCrypto.ENGINE_get_id(ctx); 158 if (id == null) { 159 return false; 160 } 161 162 return id.equals(NativeCrypto.ENGINE_get_id(other.getEngineContext())); 163 } 164 165 @Override hashCode()166 public int hashCode() { 167 return (int) ctx; 168 } 169 } 170