10b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin/*
20b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * Copyright 2014 The Android Open Source Project
30b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin *
40b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * Licensed under the Apache License, Version 2.0 (the "License");
50b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * you may not use this file except in compliance with the License.
60b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * You may obtain a copy of the License at
70b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin *
80b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin *      http://www.apache.org/licenses/LICENSE-2.0
90b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin *
100b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * Unless required by applicable law or agreed to in writing, software
110b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * distributed under the License is distributed on an "AS IS" BASIS,
120b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * See the License for the specific language governing permissions and
140b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * limitations under the License.
150b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin */
160b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
170b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubinpackage org.conscrypt;
180b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
190b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubinimport java.lang.reflect.Method;
200b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubinimport java.net.Socket;
210b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubinimport javax.crypto.SecretKey;
220b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubinimport javax.net.ssl.SSLEngine;
230b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
240b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin/**
250b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * Reflection-based {@link PSKKeyManager} adaptor for objects which expose all the methods of the
260b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * {@code PSKKeyManager} interface but do not implement the interface.
270b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin *
280b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * <p>This is expected to be useful on platforms where there are multiple instances of the
290b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin * {@code PSKKeyManager} interface.
30bd1bbfb7034028c568bb40578d6b0d7ddbdc0f15Narayan Kamath *
31ae6e905323df3356e110c15808c7d4102da554c8Nathan Mittler * Visible for testing only.
32ae6e905323df3356e110c15808c7d4102da554c8Nathan Mittler *
33248a4d021e034705e53d9b7e1da4e927dd128b01Alex Klyubin * @deprecated This abstraction is deprecated because it does not work with TLS 1.3.
340b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin */
35ae6e905323df3356e110c15808c7d4102da554c8Nathan Mittler@Deprecated
3629916ef38dc9cb4e4c6e3fdb87d4e921546d3ef4Nathan Mittlerfinal class DuckTypedPSKKeyManager implements PSKKeyManager {
370b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
380b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    private final Object mDelegate;
390b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
400b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    private DuckTypedPSKKeyManager(Object delegate) {
410b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        mDelegate = delegate;
420b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    }
430b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
440b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    /**
450b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin     * Gets an instance of {@code DuckTypedPSKKeyManager} which delegates all invocations of methods
460b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin     * of the {@link PSKKeyManager} interface to the same methods of the provided object.
470b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin     *
480b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin     * @throws NoSuchMethodException if {@code obj} does not implement a method of the
490b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin     *         {@code PSKKeyManager} interface.
500b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin     */
5129916ef38dc9cb4e4c6e3fdb87d4e921546d3ef4Nathan Mittler    static DuckTypedPSKKeyManager getInstance(Object obj) throws NoSuchMethodException {
520b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        Class<?> sourceClass = obj.getClass();
530b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        for (Method targetMethod : PSKKeyManager.class.getMethods()) {
540b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            if (targetMethod.isSynthetic()) {
550b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                continue;
560b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            }
570b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            // Check that obj exposes the target method (same name and parameter types)
580b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            Method sourceMethod =
590b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    sourceClass.getMethod(targetMethod.getName(), targetMethod.getParameterTypes());
600b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            // Check that the return type of obj's method matches the target method.
610b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            Class<?> sourceReturnType = sourceMethod.getReturnType();
620b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            Class<?> targetReturnType = targetMethod.getReturnType();
630b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            if (!targetReturnType.isAssignableFrom(sourceReturnType)) {
640b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                throw new NoSuchMethodException(sourceMethod + " return value (" + sourceReturnType
650b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                        + ") incompatible with target return value (" + targetReturnType + ")");
660b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            }
670b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        }
680b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
690b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        return new DuckTypedPSKKeyManager(obj);
700b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    }
710b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
720b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    @Override
730b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    public String chooseServerKeyIdentityHint(Socket socket) {
740b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        try {
750b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            return (String) mDelegate.getClass()
760b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .getMethod("chooseServerKeyIdentityHint", Socket.class)
770b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .invoke(mDelegate, socket);
780b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        } catch (Exception e) {
790b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            throw new RuntimeException("Failed to invoke chooseServerKeyIdentityHint", e);
800b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        }
810b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    }
820b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
830b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    @Override
840b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    public String chooseServerKeyIdentityHint(SSLEngine engine) {
850b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        try {
860b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            return (String) mDelegate.getClass()
870b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .getMethod("chooseServerKeyIdentityHint", SSLEngine.class)
880b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .invoke(mDelegate, engine);
890b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        } catch (Exception e) {
900b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            throw new RuntimeException("Failed to invoke chooseServerKeyIdentityHint", e);
910b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        }
920b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    }
930b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
940b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    @Override
950b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    public String chooseClientKeyIdentity(String identityHint, Socket socket) {
960b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        try {
970b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            return (String) mDelegate.getClass()
980b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .getMethod("chooseClientKeyIdentity", String.class, Socket.class)
990b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .invoke(mDelegate, identityHint, socket);
1000b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        } catch (Exception e) {
1010b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            throw new RuntimeException("Failed to invoke chooseClientKeyIdentity", e);
1020b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        }
1030b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    }
1040b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
1050b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    @Override
1060b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    public String chooseClientKeyIdentity(String identityHint, SSLEngine engine) {
1070b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        try {
1080b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            return (String) mDelegate.getClass()
1090b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .getMethod("chooseClientKeyIdentity", String.class, SSLEngine.class)
1100b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .invoke(mDelegate, identityHint, engine);
1110b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        } catch (Exception e) {
1120b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            throw new RuntimeException("Failed to invoke chooseClientKeyIdentity", e);
1130b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        }
1140b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    }
1150b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
1160b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    @Override
1170b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    public SecretKey getKey(String identityHint, String identity, Socket socket) {
1180b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        try {
1190b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            return (SecretKey) mDelegate.getClass()
1200b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .getMethod("getKey", String.class, String.class, Socket.class)
1210b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .invoke(mDelegate, identityHint, identity, socket);
1220b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        } catch (Exception e) {
1230b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            throw new RuntimeException("Failed to invoke getKey", e);
1240b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        }
1250b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    }
1260b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin
1270b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    @Override
1280b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    public SecretKey getKey(String identityHint, String identity, SSLEngine engine) {
1290b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        try {
1300b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            return (SecretKey) mDelegate.getClass()
1310b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .getMethod("getKey", String.class, String.class, SSLEngine.class)
1320b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin                    .invoke(mDelegate, identityHint, identity, engine);
1330b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        } catch (Exception e) {
1340b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin            throw new RuntimeException("Failed to invoke getKey", e);
1350b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin        }
1360b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin    }
1370b4bf3b34c15be6a7b3e02b4b4855049af183580Alex Klyubin}
138