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