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) { 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 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 */ 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 */ 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 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 107 long getEngineContext() { 108 return ctx; 109 } 110 111 @Override 112 protected void finalize() throws Throwable { 113 try { 114 if (!NativeCrypto.isBoringSSL) { 115 NativeCrypto.ENGINE_finish(ctx); 116 NativeCrypto.ENGINE_free(ctx); 117 } 118 } finally { 119 super.finalize(); 120 } 121 } 122 123 @Override 124 public boolean equals(Object o) { 125 if (o == this) { 126 return true; 127 } 128 129 if (!(o instanceof OpenSSLEngine)) { 130 return false; 131 } 132 133 OpenSSLEngine other = (OpenSSLEngine) o; 134 135 if (other.getEngineContext() == ctx) { 136 return true; 137 } 138 139 final String id = NativeCrypto.ENGINE_get_id(ctx); 140 if (id == null) { 141 return false; 142 } 143 144 return id.equals(NativeCrypto.ENGINE_get_id(other.getEngineContext())); 145 } 146 147 @Override 148 public int hashCode() { 149 return (int) ctx; 150 } 151 } 152