View Javadoc
1   /*
2    * Copyright 2016 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. 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, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.ssl;
17  
18  import io.netty.internal.tcnative.SSL;
19  
20  import javax.net.ssl.SSLException;
21  import javax.net.ssl.X509ExtendedKeyManager;
22  import javax.net.ssl.X509KeyManager;
23  import javax.security.auth.x500.X500Principal;
24  import java.security.PrivateKey;
25  import java.security.cert.X509Certificate;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.Map;
29  import java.util.Set;
30  
31  
32  /**
33   * Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and
34   * {@link X509Certificate}s.
35   */
36  final class OpenSslKeyMaterialManager {
37  
38      // Code in this class is inspired by code of conscrypts:
39      // - https://android.googlesource.com/platform/external/
40      //   conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java
41      // - https://android.googlesource.com/platform/external/
42      //   conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java
43      //
44      static final String KEY_TYPE_RSA = "RSA";
45      static final String KEY_TYPE_DH_RSA = "DH_RSA";
46      static final String KEY_TYPE_EC = "EC";
47      static final String KEY_TYPE_EC_EC = "EC_EC";
48      static final String KEY_TYPE_EC_RSA = "EC_RSA";
49  
50      // key type mappings for types.
51      private static final Map<String, String> KEY_TYPES = new HashMap<String, String>();
52      static {
53          KEY_TYPES.put("RSA", KEY_TYPE_RSA);
54          KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
55          KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
56          KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
57          KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
58          KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
59          KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
60      }
61  
62      private final OpenSslKeyMaterialProvider provider;
63  
64      OpenSslKeyMaterialManager(OpenSslKeyMaterialProvider provider) {
65          this.provider = provider;
66      }
67  
68      void setKeyMaterialServerSide(ReferenceCountedOpenSslEngine engine) throws SSLException {
69          long ssl = engine.sslPointer();
70          String[] authMethods = SSL.authenticationMethods(ssl);
71          Set<String> aliases = new HashSet<String>(authMethods.length);
72          for (String authMethod : authMethods) {
73              String type = KEY_TYPES.get(authMethod);
74              if (type != null) {
75                  String alias = chooseServerAlias(engine, type);
76                  if (alias != null && aliases.add(alias)) {
77                      OpenSslKeyMaterial keyMaterial = null;
78                      try {
79                          keyMaterial = provider.chooseKeyMaterial(engine.alloc, alias);
80                          if (keyMaterial != null) {
81                              SSL.setKeyMaterialServerSide(
82                                      ssl, keyMaterial.certificateChainAddress(), keyMaterial.privateKeyAddress());
83                          }
84                      } catch (SSLException e) {
85                          throw e;
86                      } catch (Exception e) {
87                          throw new SSLException(e);
88                      } finally {
89                          if (keyMaterial != null) {
90                              keyMaterial.release();
91                          }
92                      }
93                  }
94              }
95          }
96      }
97  
98      void setKeyMaterialClientSide(ReferenceCountedOpenSslEngine engine, long certOut, long keyOut, String[] keyTypes,
99                                    X500Principal[] issuer) throws SSLException {
100         String alias = chooseClientAlias(engine, keyTypes, issuer);
101         OpenSslKeyMaterial keyMaterial = null;
102         try {
103             keyMaterial = provider.chooseKeyMaterial(engine.alloc, alias);
104             if (keyMaterial != null) {
105                 SSL.setKeyMaterialClientSide(engine.sslPointer(), certOut, keyOut,
106                         keyMaterial.certificateChainAddress(), keyMaterial.privateKeyAddress());
107             }
108         } catch (SSLException e) {
109             throw e;
110         } catch (Exception e) {
111             throw new SSLException(e);
112         } finally {
113             if (keyMaterial != null) {
114                 keyMaterial.release();
115             }
116         }
117     }
118 
119     private String chooseClientAlias(ReferenceCountedOpenSslEngine engine,
120                                        String[] keyTypes, X500Principal[] issuer) {
121         X509KeyManager manager = provider.keyManager();
122         if (manager instanceof X509ExtendedKeyManager) {
123             return ((X509ExtendedKeyManager) manager).chooseEngineClientAlias(keyTypes, issuer, engine);
124         }
125         return manager.chooseClientAlias(keyTypes, issuer, null);
126     }
127 
128     private String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) {
129         X509KeyManager manager = provider.keyManager();
130         if (manager instanceof X509ExtendedKeyManager) {
131             return ((X509ExtendedKeyManager) manager).chooseEngineServerAlias(type, null, engine);
132         }
133         return manager.chooseServerAlias(type, null, null);
134     }
135 }