View Javadoc
1   /*
2    * Copyright 2019 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  
17  package io.netty.handler.ssl.util;
18  
19  import io.netty.util.concurrent.FastThreadLocal;
20  import io.netty.util.internal.ObjectUtil;
21  import io.netty.util.internal.PlatformDependent;
22  import io.netty.util.internal.StringUtil;
23  import io.netty.util.internal.SuppressJava6Requirement;
24  import java.security.InvalidAlgorithmParameterException;
25  import java.security.KeyStore;
26  import java.security.KeyStoreException;
27  import java.security.Provider;
28  import javax.net.ssl.ManagerFactoryParameters;
29  import javax.net.ssl.KeyManager;
30  import javax.net.ssl.KeyManagerFactory;
31  import javax.net.ssl.KeyManagerFactorySpi;
32  import javax.net.ssl.X509ExtendedKeyManager;
33  import javax.net.ssl.X509KeyManager;
34  
35  /**
36   * Helps to implement a custom {@link KeyManagerFactory}.
37   */
38  public abstract class SimpleKeyManagerFactory extends KeyManagerFactory {
39  
40      private static final Provider PROVIDER = new Provider("", 0.0, "") {
41          private static final long serialVersionUID = -2680540247105807895L;
42      };
43  
44      /**
45       * {@link SimpleKeyManagerFactorySpi} must have a reference to {@link SimpleKeyManagerFactory}
46       * to delegate its callbacks back to {@link SimpleKeyManagerFactory}.  However, it is impossible to do so,
47       * because {@link KeyManagerFactory} requires {@link KeyManagerFactorySpi} at construction time and
48       * does not provide a way to access it later.
49       *
50       * To work around this issue, we use an ugly hack which uses a {@link FastThreadLocal }.
51       */
52      private static final FastThreadLocal<SimpleKeyManagerFactorySpi> CURRENT_SPI =
53              new FastThreadLocal<SimpleKeyManagerFactorySpi>() {
54                  @Override
55                  protected SimpleKeyManagerFactorySpi initialValue() {
56                      return new SimpleKeyManagerFactorySpi();
57                  }
58              };
59  
60      /**
61       * Creates a new instance.
62       */
63      protected SimpleKeyManagerFactory() {
64          this(StringUtil.EMPTY_STRING);
65      }
66  
67      /**
68       * Creates a new instance.
69       *
70       * @param name the name of this {@link KeyManagerFactory}
71       */
72      protected SimpleKeyManagerFactory(String name) {
73          super(CURRENT_SPI.get(), PROVIDER, ObjectUtil.checkNotNull(name, "name"));
74          CURRENT_SPI.get().init(this);
75          CURRENT_SPI.remove();
76      }
77  
78      /**
79       * Initializes this factory with a source of certificate authorities and related key material.
80       *
81       * @see KeyManagerFactorySpi#engineInit(KeyStore, char[])
82       */
83      protected abstract void engineInit(KeyStore keyStore, char[] var2) throws Exception;
84  
85      /**
86       * Initializes this factory with a source of provider-specific key material.
87       *
88       * @see KeyManagerFactorySpi#engineInit(ManagerFactoryParameters)
89       */
90      protected abstract void engineInit(ManagerFactoryParameters managerFactoryParameters) throws Exception;
91  
92      /**
93       * Returns one key manager for each type of key material.
94       *
95       * @see KeyManagerFactorySpi#engineGetKeyManagers()
96       */
97      protected abstract KeyManager[] engineGetKeyManagers();
98  
99      private static final class SimpleKeyManagerFactorySpi extends KeyManagerFactorySpi {
100 
101         private SimpleKeyManagerFactory parent;
102         private volatile KeyManager[] keyManagers;
103 
104         void init(SimpleKeyManagerFactory parent) {
105             this.parent = parent;
106         }
107 
108         @Override
109         protected void engineInit(KeyStore keyStore, char[] pwd) throws KeyStoreException {
110             try {
111                 parent.engineInit(keyStore, pwd);
112             } catch (KeyStoreException e) {
113                 throw e;
114             } catch (Exception e) {
115                 throw new KeyStoreException(e);
116             }
117         }
118 
119         @Override
120         protected void engineInit(
121                 ManagerFactoryParameters managerFactoryParameters) throws InvalidAlgorithmParameterException {
122             try {
123                 parent.engineInit(managerFactoryParameters);
124             } catch (InvalidAlgorithmParameterException e) {
125                 throw e;
126             } catch (Exception e) {
127                 throw new InvalidAlgorithmParameterException(e);
128             }
129         }
130 
131         @Override
132         protected KeyManager[] engineGetKeyManagers() {
133             KeyManager[] keyManagers = this.keyManagers;
134             if (keyManagers == null) {
135                 keyManagers = parent.engineGetKeyManagers();
136                 if (PlatformDependent.javaVersion() >= 7) {
137                     wrapIfNeeded(keyManagers);
138                 }
139                 this.keyManagers = keyManagers;
140             }
141             return keyManagers.clone();
142         }
143 
144         @SuppressJava6Requirement(reason = "Usage guarded by java version check")
145         private static void wrapIfNeeded(KeyManager[] keyManagers) {
146             for (int i = 0; i < keyManagers.length; i++) {
147                 final KeyManager tm = keyManagers[i];
148                 if (tm instanceof X509KeyManager && !(tm instanceof X509ExtendedKeyManager)) {
149                     keyManagers[i] = new X509KeyManagerWrapper((X509KeyManager) tm);
150                 }
151             }
152         }
153     }
154 }