Home | History | Annotate | Download | only in conscrypt
      1 /*
      2  * Copyright 2014 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.lang.reflect.Method;
     20 import java.net.Socket;
     21 import javax.crypto.SecretKey;
     22 import javax.net.ssl.SSLEngine;
     23 
     24 /**
     25  * Reflection-based {@link PSKKeyManager} adaptor for objects which expose all the methods of the
     26  * {@code PSKKeyManager} interface but do not implement the interface.
     27  *
     28  * <p>This is expected to be useful on platforms where there are multiple instances of the
     29  * {@code PSKKeyManager} interface.
     30  *
     31  * Visible for testing only.
     32  *
     33  * @deprecated This abstraction is deprecated because it does not work with TLS 1.3.
     34  * @hide
     35  */
     36 @Deprecated
     37 public class DuckTypedPSKKeyManager implements PSKKeyManager {
     38 
     39     private final Object mDelegate;
     40 
     41     private DuckTypedPSKKeyManager(Object delegate) {
     42         mDelegate = delegate;
     43     }
     44 
     45     /**
     46      * Gets an instance of {@code DuckTypedPSKKeyManager} which delegates all invocations of methods
     47      * of the {@link PSKKeyManager} interface to the same methods of the provided object.
     48      *
     49      * @throws NoSuchMethodException if {@code obj} does not implement a method of the
     50      *         {@code PSKKeyManager} interface.
     51      */
     52     public static DuckTypedPSKKeyManager getInstance(Object obj) throws NoSuchMethodException {
     53         Class<?> sourceClass = obj.getClass();
     54         for (Method targetMethod : PSKKeyManager.class.getMethods()) {
     55             if (targetMethod.isSynthetic()) {
     56                 continue;
     57             }
     58             // Check that obj exposes the target method (same name and parameter types)
     59             Method sourceMethod =
     60                     sourceClass.getMethod(targetMethod.getName(), targetMethod.getParameterTypes());
     61             // Check that the return type of obj's method matches the target method.
     62             Class<?> sourceReturnType = sourceMethod.getReturnType();
     63             Class<?> targetReturnType = targetMethod.getReturnType();
     64             if (!targetReturnType.isAssignableFrom(sourceReturnType)) {
     65                 throw new NoSuchMethodException(sourceMethod + " return value (" + sourceReturnType
     66                         + ") incompatible with target return value (" + targetReturnType + ")");
     67             }
     68         }
     69 
     70         return new DuckTypedPSKKeyManager(obj);
     71     }
     72 
     73     @Override
     74     public String chooseServerKeyIdentityHint(Socket socket) {
     75         try {
     76             return (String) mDelegate.getClass()
     77                     .getMethod("chooseServerKeyIdentityHint", Socket.class)
     78                     .invoke(mDelegate, socket);
     79         } catch (Exception e) {
     80             throw new RuntimeException("Failed to invoke chooseServerKeyIdentityHint", e);
     81         }
     82     }
     83 
     84     @Override
     85     public String chooseServerKeyIdentityHint(SSLEngine engine) {
     86         try {
     87             return (String) mDelegate.getClass()
     88                     .getMethod("chooseServerKeyIdentityHint", SSLEngine.class)
     89                     .invoke(mDelegate, engine);
     90         } catch (Exception e) {
     91             throw new RuntimeException("Failed to invoke chooseServerKeyIdentityHint", e);
     92         }
     93     }
     94 
     95     @Override
     96     public String chooseClientKeyIdentity(String identityHint, Socket socket) {
     97         try {
     98             return (String) mDelegate.getClass()
     99                     .getMethod("chooseClientKeyIdentity", String.class, Socket.class)
    100                     .invoke(mDelegate, identityHint, socket);
    101         } catch (Exception e) {
    102             throw new RuntimeException("Failed to invoke chooseClientKeyIdentity", e);
    103         }
    104     }
    105 
    106     @Override
    107     public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) {
    108         try {
    109             return (String) mDelegate.getClass()
    110                     .getMethod("chooseClientKeyIdentity", String.class, SSLEngine.class)
    111                     .invoke(mDelegate, identityHint, engine);
    112         } catch (Exception e) {
    113             throw new RuntimeException("Failed to invoke chooseClientKeyIdentity", e);
    114         }
    115     }
    116 
    117     @Override
    118     public SecretKey getKey(String identityHint, String identity, Socket socket) {
    119         try {
    120             return (SecretKey) mDelegate.getClass()
    121                     .getMethod("getKey", String.class, String.class, Socket.class)
    122                     .invoke(mDelegate, identityHint, identity, socket);
    123         } catch (Exception e) {
    124             throw new RuntimeException("Failed to invoke getKey", e);
    125         }
    126     }
    127 
    128     @Override
    129     public SecretKey getKey(String identityHint, String identity, SSLEngine engine) {
    130         try {
    131             return (SecretKey) mDelegate.getClass()
    132                     .getMethod("getKey", String.class, String.class, SSLEngine.class)
    133                     .invoke(mDelegate, identityHint, identity, engine);
    134         } catch (Exception e) {
    135             throw new RuntimeException("Failed to invoke getKey", e);
    136         }
    137     }
    138 }
    139