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 17package org.conscrypt; 18 19import java.lang.reflect.Method; 20import java.net.Socket; 21import javax.crypto.SecretKey; 22import 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 36final 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