1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.handler.ssl.util;
18
19 import io.netty.util.internal.PlatformDependent;
20 import io.netty.util.internal.logging.InternalLogger;
21 import io.netty.util.internal.logging.InternalLoggerFactory;
22
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.math.BigInteger;
27 import java.security.AccessController;
28 import java.security.KeyPair;
29 import java.security.PrivateKey;
30 import java.security.PrivilegedAction;
31 import java.security.PublicKey;
32 import java.security.SecureRandom;
33 import java.security.cert.X509Certificate;
34 import java.util.ArrayList;
35 import java.util.Date;
36 import java.util.List;
37
38 import static io.netty.handler.ssl.util.SelfSignedCertificate.newSelfSignedCertificate;
39
40
41
42
43 final class OpenJdkSelfSignedCertGenerator {
44 private static final InternalLogger logger =
45 InternalLoggerFactory.getInstance(OpenJdkSelfSignedCertGenerator.class);
46 private static final Method CERT_INFO_SET_HANDLE;
47 private static final Constructor<?> ISSUER_NAME_CONSTRUCTOR;
48 private static final Constructor<?> CERT_IMPL_CONSTRUCTOR;
49 private static final Constructor<?> X509_CERT_INFO_CONSTRUCTOR;
50 private static final Constructor<?> CERTIFICATE_VERSION_CONSTRUCTOR;
51 private static final Constructor<?> CERTIFICATE_SUBJECT_NAME_CONSTRUCTOR;
52 private static final Constructor<?> X500_NAME_CONSTRUCTOR;
53 private static final Constructor<?> CERTIFICATE_SERIAL_NUMBER_CONSTRUCTOR;
54 private static final Constructor<?> CERTIFICATE_VALIDITY_CONSTRUCTOR;
55 private static final Constructor<?> CERTIFICATE_X509_KEY_CONSTRUCTOR;
56 private static final Constructor<?> CERTIFICATE_ALORITHM_ID_CONSTRUCTOR;
57 private static final Method CERT_IMPL_GET_HANDLE;
58 private static final Method CERT_IMPL_SIGN_HANDLE;
59 private static final Method ALGORITHM_ID_GET_HANDLE;
60
61 private static final boolean SUPPORTED;
62
63 static {
64 final Class<?> x509CertInfoClass;
65 final Class<?> x500NameClass;
66 final Class<?> certificateIssuerNameClass;
67 final Class<?> x509CertImplClass;
68 final Class<?> certificateVersionClass;
69 final Class<?> certificateSubjectNameClass;
70 final Class<?> certificateSerialNumberClass;
71 final Class<?> certificateValidityClass;
72 final Class<?> certificateX509KeyClass;
73 final Class<?> algorithmIdClass;
74 final Class<?> certificateAlgorithmIdClass;
75
76 boolean supported;
77 Method certInfoSetHandle = null;
78 Constructor<?> x509CertInfoConstructor = null;
79 Constructor<?> issuerNameConstructor = null;
80 Constructor<?> certImplConstructor = null;
81 Constructor<?> x500NameConstructor = null;
82 Constructor<?> certificateVersionConstructor = null;
83 Constructor<?> certificateSubjectNameConstructor = null;
84 Constructor<?> certificateSerialNumberConstructor = null;
85 Constructor<?> certificateValidityConstructor = null;
86 Constructor<?> certificateX509KeyConstructor = null;
87 Constructor<?> certificateAlgorithmIdConstructor = null;
88 Method certImplGetHandle = null;
89 Method certImplSignHandle = null;
90 Method algorithmIdGetHandle = null;
91
92 try {
93 Object maybeClasses = AccessController.doPrivileged(new PrivilegedAction<Object>() {
94 @Override
95 public Object run() {
96 try {
97 List<Class<?>> classes = new ArrayList<Class<?>>();
98 classes.add(Class.forName("sun.security.x509.X509CertInfo", false,
99 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
100 classes.add(Class.forName("sun.security.x509.X500Name", false,
101 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
102 classes.add(Class.forName("sun.security.x509.CertificateIssuerName", false,
103 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
104 classes.add(Class.forName("sun.security.x509.X509CertImpl", false,
105 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
106 classes.add(Class.forName("sun.security.x509.CertificateVersion", false,
107 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
108 classes.add(Class.forName("sun.security.x509.CertificateSubjectName", false,
109 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
110 classes.add(Class.forName("sun.security.x509.CertificateSerialNumber", false,
111 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
112 classes.add(Class.forName("sun.security.x509.CertificateValidity", false,
113 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
114 classes.add(Class.forName("sun.security.x509.CertificateX509Key", false,
115 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
116 classes.add(Class.forName("sun.security.x509.AlgorithmId", false,
117 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
118 classes.add(Class.forName("sun.security.x509.CertificateAlgorithmId", false,
119 PlatformDependent.getClassLoader(OpenJdkSelfSignedCertGenerator.class)));
120
121 return classes;
122 } catch (Throwable cause) {
123 return cause;
124 }
125 }
126 });
127 if (maybeClasses instanceof List) {
128 @SuppressWarnings("unchecked") List<Class<?>> classes = (List<Class<?>>) maybeClasses;
129 x509CertInfoClass = classes.get(0);
130 x500NameClass = classes.get(1);
131 certificateIssuerNameClass = classes.get(2);
132 x509CertImplClass = classes.get(3);
133 certificateVersionClass = classes.get(4);
134 certificateSubjectNameClass = classes.get(5);
135 certificateSerialNumberClass = classes.get(6);
136 certificateValidityClass = classes.get(7);
137 certificateX509KeyClass = classes.get(8);
138 algorithmIdClass = classes.get(9);
139 certificateAlgorithmIdClass = classes.get(10);
140 } else {
141 throw (Throwable) maybeClasses;
142 }
143
144 Object maybeConstructors = AccessController.doPrivileged(new PrivilegedAction<Object>() {
145 @Override
146 public Object run() {
147 try {
148 List<Constructor<?>> constructors = new ArrayList<Constructor<?>>();
149 constructors.add(
150 x509CertInfoClass.getConstructor()
151 );
152 constructors.add(certificateIssuerNameClass.getConstructor(x500NameClass));
153 constructors.add(x509CertImplClass.getConstructor(x509CertInfoClass));
154 constructors.add(x500NameClass.getConstructor(String.class));
155 constructors.add(certificateVersionClass.getConstructor(int.class));
156 constructors.add(certificateSubjectNameClass.getConstructor(x500NameClass));
157 constructors.add(certificateSerialNumberClass.getConstructor(BigInteger.class));
158 constructors.add(certificateValidityClass.getConstructor(Date.class, Date.class));
159 constructors.add(certificateX509KeyClass.getConstructor(PublicKey.class));
160 constructors.add(certificateAlgorithmIdClass.getConstructor(algorithmIdClass));
161 return constructors;
162 } catch (Throwable cause) {
163 return cause;
164 }
165 }
166 });
167 if (maybeConstructors instanceof List) {
168 @SuppressWarnings("unchecked")
169 List<Constructor<?>> constructorList = (List<Constructor<?>>) maybeConstructors;
170 x509CertInfoConstructor = constructorList.get(0);
171 issuerNameConstructor = constructorList.get(1);
172 certImplConstructor = constructorList.get(2);
173 x500NameConstructor = constructorList.get(3);
174 certificateVersionConstructor = constructorList.get(4);
175 certificateSubjectNameConstructor = constructorList.get(5);
176 certificateSerialNumberConstructor = constructorList.get(6);
177 certificateValidityConstructor = constructorList.get(7);
178 certificateX509KeyConstructor = constructorList.get(8);
179 certificateAlgorithmIdConstructor = constructorList.get(9);
180 } else {
181 throw (Throwable) maybeConstructors;
182 }
183
184 Object maybeMethods = AccessController.doPrivileged(new PrivilegedAction<Object>() {
185 @Override
186 public Object run() {
187 try {
188 List<Method> methods = new ArrayList<Method>();
189 methods.add(x509CertInfoClass.getDeclaredMethod("set", String.class, Object.class));
190 methods.add(x509CertImplClass.getDeclaredMethod("get", String.class));
191
192 methods.add(x509CertImplClass.getDeclaredMethod(
193 "sign", PrivateKey.class, String.class));
194 methods.add(algorithmIdClass.getDeclaredMethod("get", String.class));
195 return methods;
196 } catch (Throwable cause) {
197 return cause;
198 }
199 }
200 });
201 if (maybeMethods instanceof List) {
202 @SuppressWarnings("unchecked") List<Method> methodHandles = (List<Method>) maybeMethods;
203 certInfoSetHandle = methodHandles.get(0);
204 certImplGetHandle = methodHandles.get(1);
205 certImplSignHandle = methodHandles.get(2);
206 algorithmIdGetHandle = methodHandles.get(3);
207 } else {
208 throw (Throwable) maybeMethods;
209 }
210 supported = true;
211 } catch (Throwable cause) {
212 supported = false;
213 logger.debug(OpenJdkSelfSignedCertGenerator.class.getSimpleName() + " not supported", cause);
214 }
215 CERT_INFO_SET_HANDLE = certInfoSetHandle;
216 X509_CERT_INFO_CONSTRUCTOR = x509CertInfoConstructor;
217 ISSUER_NAME_CONSTRUCTOR = issuerNameConstructor;
218 CERTIFICATE_VERSION_CONSTRUCTOR = certificateVersionConstructor;
219 CERTIFICATE_SUBJECT_NAME_CONSTRUCTOR = certificateSubjectNameConstructor;
220 CERT_IMPL_CONSTRUCTOR = certImplConstructor;
221 X500_NAME_CONSTRUCTOR = x500NameConstructor;
222 CERTIFICATE_SERIAL_NUMBER_CONSTRUCTOR = certificateSerialNumberConstructor;
223 CERTIFICATE_VALIDITY_CONSTRUCTOR = certificateValidityConstructor;
224 CERTIFICATE_X509_KEY_CONSTRUCTOR = certificateX509KeyConstructor;
225 CERT_IMPL_GET_HANDLE = certImplGetHandle;
226 CERT_IMPL_SIGN_HANDLE = certImplSignHandle;
227 ALGORITHM_ID_GET_HANDLE = algorithmIdGetHandle;
228 CERTIFICATE_ALORITHM_ID_CONSTRUCTOR = certificateAlgorithmIdConstructor;
229 SUPPORTED = supported;
230 }
231
232 static String[] generate(String fqdn, KeyPair keypair, SecureRandom random, Date notBefore, Date notAfter,
233 String algorithm) throws Exception {
234 if (!SUPPORTED) {
235 throw new UnsupportedOperationException(
236 OpenJdkSelfSignedCertGenerator.class.getSimpleName() + " not supported on the used JDK version");
237 }
238 try {
239 PrivateKey key = keypair.getPrivate();
240
241
242 Object info = X509_CERT_INFO_CONSTRUCTOR.newInstance();
243 Object owner = X500_NAME_CONSTRUCTOR.newInstance("CN=" + fqdn);
244
245 CERT_INFO_SET_HANDLE.invoke(info, "version", CERTIFICATE_VERSION_CONSTRUCTOR.newInstance(2));
246 CERT_INFO_SET_HANDLE.invoke(info, "serialNumber",
247 CERTIFICATE_SERIAL_NUMBER_CONSTRUCTOR.newInstance(new BigInteger(64, random)));
248 try {
249 CERT_INFO_SET_HANDLE.invoke(info, "subject", CERTIFICATE_SUBJECT_NAME_CONSTRUCTOR.newInstance(owner));
250 } catch (InvocationTargetException ex) {
251 CERT_INFO_SET_HANDLE.invoke(info, "subject", owner);
252 }
253 try {
254 CERT_INFO_SET_HANDLE.invoke(info, "issuer", ISSUER_NAME_CONSTRUCTOR.newInstance(owner));
255 } catch (InvocationTargetException ex) {
256 CERT_INFO_SET_HANDLE.invoke(info, "issuer", owner);
257 }
258 CERT_INFO_SET_HANDLE.invoke(info, "validity",
259 CERTIFICATE_VALIDITY_CONSTRUCTOR.newInstance(notBefore, notAfter));
260 CERT_INFO_SET_HANDLE.invoke(info, "key", CERTIFICATE_X509_KEY_CONSTRUCTOR.newInstance(keypair.getPublic()));
261 CERT_INFO_SET_HANDLE.invoke(info, "algorithmID",
262
263 CERTIFICATE_ALORITHM_ID_CONSTRUCTOR.newInstance(
264 ALGORITHM_ID_GET_HANDLE.invoke(null, "1.2.840.113549.1.1.11")));
265
266
267 Object cert = CERT_IMPL_CONSTRUCTOR.newInstance(info);
268 CERT_IMPL_SIGN_HANDLE.invoke(cert, key,
269 algorithm.equalsIgnoreCase("EC") ? "SHA256withECDSA" : "SHA256withRSA");
270
271
272 CERT_INFO_SET_HANDLE.invoke(info, "algorithmID.algorithm",
273 CERT_IMPL_GET_HANDLE.invoke(cert, "x509.algorithm"));
274 cert = CERT_IMPL_CONSTRUCTOR.newInstance(info);
275 CERT_IMPL_SIGN_HANDLE.invoke(cert, key,
276 algorithm.equalsIgnoreCase("EC") ? "SHA256withECDSA" : "SHA256withRSA");
277
278 X509Certificate x509Cert = (X509Certificate) cert;
279 x509Cert.verify(keypair.getPublic());
280
281 return newSelfSignedCertificate(fqdn, key, x509Cert);
282 } catch (Throwable cause) {
283 if (cause instanceof Exception) {
284 throw (Exception) cause;
285 }
286 if (cause instanceof Error) {
287 throw (Error) cause;
288 }
289 throw new IllegalStateException(cause);
290 }
291 }
292
293 private OpenJdkSelfSignedCertGenerator() {
294 }
295 }