View Javadoc
1   /*
2    * Copyright 2018 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    *   https://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.buffer.ByteBufAllocator;
19  import io.netty.buffer.UnpooledByteBufAllocator;
20  import io.netty.internal.tcnative.SSL;
21  
22  import javax.net.ssl.SSLException;
23  import javax.net.ssl.X509KeyManager;
24  import java.security.PrivateKey;
25  import java.security.cert.X509Certificate;
26  
27  import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
28  
29  /**
30   * Provides {@link OpenSslKeyMaterial} for a given alias.
31   */
32  class OpenSslKeyMaterialProvider {
33  
34      private final X509KeyManager keyManager;
35      private final String password;
36  
37      OpenSslKeyMaterialProvider(X509KeyManager keyManager, String password) {
38          this.keyManager = keyManager;
39          this.password = password;
40      }
41  
42      static void validateKeyMaterialSupported(X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
43                                               boolean allowSignatureFallback)
44              throws SSLException {
45          validateSupported(keyCertChain);
46          validateSupported(key, keyPassword, allowSignatureFallback);
47      }
48  
49      private static void validateSupported(PrivateKey key, String password,
50                                            boolean allowSignatureFallback) throws SSLException {
51          if (key == null) {
52              return;
53          }
54  
55          // Skip validation for keys that don't expose encoded material
56          // These will be handled by the key fallback mechanism
57          if (key.getEncoded() == null && allowSignatureFallback) {
58              return;
59          }
60  
61          long pkeyBio = 0;
62          long pkey = 0;
63  
64          try {
65              pkeyBio = toBIO(UnpooledByteBufAllocator.DEFAULT, key);
66              pkey = SSL.parsePrivateKey(pkeyBio, password);
67          } catch (Exception e) {
68              throw new SSLException("PrivateKey type not supported " + key.getFormat(), e);
69          } finally {
70              SSL.freeBIO(pkeyBio);
71              if (pkey != 0) {
72                  SSL.freePrivateKey(pkey);
73              }
74          }
75      }
76  
77      private static void validateSupported(X509Certificate[] certificates) throws SSLException {
78          if (certificates == null || certificates.length == 0) {
79              return;
80          }
81  
82          long chainBio = 0;
83          long chain = 0;
84          PemEncoded encoded = null;
85          try {
86              encoded = PemX509Certificate.toPEM(UnpooledByteBufAllocator.DEFAULT, true, certificates);
87              chainBio = toBIO(UnpooledByteBufAllocator.DEFAULT, encoded.retain());
88              chain = SSL.parseX509Chain(chainBio);
89          } catch (Exception e) {
90              throw new SSLException("Certificate type not supported", e);
91          } finally {
92              SSL.freeBIO(chainBio);
93              if (chain != 0) {
94                  SSL.freeX509Chain(chain);
95              }
96              if (encoded != null) {
97                  encoded.release();
98              }
99          }
100     }
101 
102     /**
103      * Returns the underlying {@link X509KeyManager} that is used.
104      */
105     X509KeyManager keyManager() {
106         return keyManager;
107     }
108 
109     /**
110      * Returns the {@link OpenSslKeyMaterial} or {@code null} (if none) that should be used during the handshake by
111      * OpenSSL.
112      */
113     OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
114         X509Certificate[] certificates = keyManager.getCertificateChain(alias);
115         if (certificates == null || certificates.length == 0) {
116             return null;
117         }
118 
119         PrivateKey key = keyManager.getPrivateKey(alias);
120         PemEncoded encoded = PemX509Certificate.toPEM(allocator, true, certificates);
121         long chainBio = 0;
122         long pkeyBio = 0;
123         long chain = 0;
124         long pkey = 0;
125         try {
126             chainBio = toBIO(allocator, encoded.retain());
127             chain = SSL.parseX509Chain(chainBio);
128 
129             OpenSslKeyMaterial keyMaterial;
130             if (key instanceof OpenSslPrivateKey) {
131                 keyMaterial = ((OpenSslPrivateKey) key).newKeyMaterial(chain, certificates);
132             } else {
133                 pkeyBio = toBIO(allocator, key);
134                 pkey = key == null ? 0 : SSL.parsePrivateKey(pkeyBio, password);
135                 keyMaterial = new DefaultOpenSslKeyMaterial(chain, pkey, certificates);
136             }
137 
138             // See the chain and pkey to 0 so we will not release it as the ownership was
139             // transferred to OpenSslKeyMaterial.
140             chain = 0;
141             pkey = 0;
142             return keyMaterial;
143         } finally {
144             SSL.freeBIO(chainBio);
145             SSL.freeBIO(pkeyBio);
146             if (chain != 0) {
147                 SSL.freeX509Chain(chain);
148             }
149             if (pkey != 0) {
150                 SSL.freePrivateKey(pkey);
151             }
152             encoded.release();
153         }
154     }
155 
156     /**
157      * Will be invoked once the provider should be destroyed.
158      */
159     void destroy() {
160         // NOOP.
161     }
162 }