Home | History | Annotate | Download | only in conscrypt
      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