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  */
     35 @Deprecated
     36 final class DuckTypedPSKKeyManager implements PSKKeyManager {
     37 
     38     private final Object mDelegate;
     39 
     40     private DuckTypedPSKKeyManager(Object delegate) {
     41         mDelegate = delegate;
     42     }
     43 
     44     /**
     45      * Gets an instance of {@code DuckTypedPSKKeyManager} which delegates all invocations of methods
     46      * of the {@link PSKKeyManager} interface to the same methods of the provided object.
     47      *
     48      * @throws NoSuchMethodException if {@code obj} does not implement a method of the
     49      *         {@code PSKKeyManager} interface.
     50      */
     51     static DuckTypedPSKKeyManager getInstance(Object obj) throws NoSuchMethodException {
     52         Class<?> sourceClass = obj.getClass();
     53         for (Method targetMethod : PSKKeyManager.class.getMethods()) {
     54             if (targetMethod.isSynthetic()) {
     55                 continue;
     56             }
     57             // Check that obj exposes the target method (same name and parameter types)
     58             Method sourceMethod =
     59                     sourceClass.getMethod(targetMethod.getName(), targetMethod.getParameterTypes());
     60             // Check that the return type of obj's method matches the target method.
     61             Class<?> sourceReturnType = sourceMethod.getReturnType();
     62             Class<?> targetReturnType = targetMethod.getReturnType();
     63             if (!targetReturnType.isAssignableFrom(sourceReturnType)) {
     64                 throw new NoSuchMethodException(sourceMethod + " return value (" + sourceReturnType
     65                         + ") incompatible with target return value (" + targetReturnType + ")");
     66             }
     67         }
     68 
     69         return new DuckTypedPSKKeyManager(obj);
     70     }
     71 
     72     @Override
     73     public String chooseServerKeyIdentityHint(Socket socket) {
     74         try {
     75             return (String) mDelegate.getClass()
     76                     .getMethod("chooseServerKeyIdentityHint", Socket.class)
     77                     .invoke(mDelegate, socket);
     78         } catch (Exception e) {
     79             throw new RuntimeException("Failed to invoke chooseServerKeyIdentityHint", e);
     80         }
     81     }
     82 
     83     @Override
     84     public String chooseServerKeyIdentityHint(SSLEngine engine) {
     85         try {
     86             return (String) mDelegate.getClass()
     87                     .getMethod("chooseServerKeyIdentityHint", SSLEngine.class)
     88                     .invoke(mDelegate, engine);
     89         } catch (Exception e) {
     90             throw new RuntimeException("Failed to invoke chooseServerKeyIdentityHint", e);
     91         }
     92     }
     93 
     94     @Override
     95     public String chooseClientKeyIdentity(String identityHint, Socket socket) {
     96         try {
     97             return (String) mDelegate.getClass()
     98                     .getMethod("chooseClientKeyIdentity", String.class, Socket.class)
     99                     .invoke(mDelegate, identityHint, socket);
    100         } catch (Exception e) {
    101             throw new RuntimeException("Failed to invoke chooseClientKeyIdentity", e);
    102         }
    103     }
    104 
    105     @Override
    106     public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) {
    107         try {
    108             return (String) mDelegate.getClass()
    109                     .getMethod("chooseClientKeyIdentity", String.class, SSLEngine.class)
    110                     .invoke(mDelegate, identityHint, engine);
    111         } catch (Exception e) {
    112             throw new RuntimeException("Failed to invoke chooseClientKeyIdentity", e);
    113         }
    114     }
    115 
    116     @Override
    117     public SecretKey getKey(String identityHint, String identity, Socket socket) {
    118         try {
    119             return (SecretKey) mDelegate.getClass()
    120                     .getMethod("getKey", String.class, String.class, Socket.class)
    121                     .invoke(mDelegate, identityHint, identity, socket);
    122         } catch (Exception e) {
    123             throw new RuntimeException("Failed to invoke getKey", e);
    124         }
    125     }
    126 
    127     @Override
    128     public SecretKey getKey(String identityHint, String identity, SSLEngine engine) {
    129         try {
    130             return (SecretKey) mDelegate.getClass()
    131                     .getMethod("getKey", String.class, String.class, SSLEngine.class)
    132                     .invoke(mDelegate, identityHint, identity, engine);
    133         } catch (Exception e) {
    134             throw new RuntimeException("Failed to invoke getKey", e);
    135         }
    136     }
    137 }
    138