1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.jboss.netty.handler.ssl.util;
18
19 import org.jboss.netty.buffer.ChannelBuffers;
20 import org.jboss.netty.handler.codec.base64.Base64;
21 import org.jboss.netty.logging.InternalLogger;
22 import org.jboss.netty.logging.InternalLoggerFactory;
23 import org.jboss.netty.util.CharsetUtil;
24
25 import java.io.File;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.security.KeyPair;
30 import java.security.KeyPairGenerator;
31 import java.security.NoSuchAlgorithmException;
32 import java.security.PrivateKey;
33 import java.security.SecureRandom;
34 import java.security.cert.CertificateEncodingException;
35 import java.security.cert.CertificateException;
36 import java.security.cert.X509Certificate;
37 import java.util.Date;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public final class SelfSignedCertificate {
56
57 private static final InternalLogger logger = InternalLoggerFactory.getInstance(SelfSignedCertificate.class);
58
59
60 static final Date NOT_BEFORE = new Date(System.currentTimeMillis() - 86400000L * 365);
61
62 static final Date NOT_AFTER = new Date(253402300799000L);
63
64 private final File certificate;
65 private final File privateKey;
66
67
68
69
70 public SelfSignedCertificate() throws CertificateException {
71 this("example.com");
72 }
73
74
75
76
77
78
79 public SelfSignedCertificate(String fqdn) throws CertificateException {
80
81
82 this(fqdn, ThreadLocalInsecureRandom.current(), 1024);
83 }
84
85
86
87
88
89
90
91
92 public SelfSignedCertificate(String fqdn, SecureRandom random, int bits) throws CertificateException {
93
94 final KeyPair keypair;
95 try {
96 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
97 keyGen.initialize(bits, random);
98 keypair = keyGen.generateKeyPair();
99 } catch (NoSuchAlgorithmException e) {
100
101 throw new Error(e);
102 }
103
104 String[] paths;
105 try {
106
107 paths = OpenJdkSelfSignedCertGenerator.generate(fqdn, keypair, random);
108 } catch (Throwable t) {
109 logger.debug("Failed to generate a self-signed X.509 certificate using sun.security.x509:", t);
110 try {
111
112 paths = BouncyCastleSelfSignedCertGenerator.generate(fqdn, keypair, random);
113 } catch (Throwable t2) {
114 logger.debug("Failed to generate a self-signed X.509 certificate using Bouncy Castle:", t2);
115 throw new CertificateException(
116 "No provider succeeded to generate a self-signed certificate. " +
117 "See debug log for the root cause.");
118 }
119 }
120
121 certificate = new File(paths[0]);
122 privateKey = new File(paths[1]);
123 }
124
125
126
127
128 public File certificate() {
129 return certificate;
130 }
131
132
133
134
135 public File privateKey() {
136 return privateKey;
137 }
138
139
140
141
142 public void delete() {
143 safeDelete(certificate);
144 safeDelete(privateKey);
145 }
146
147 static String[] newSelfSignedCertificate(
148 String fqdn, PrivateKey key, X509Certificate cert) throws IOException, CertificateEncodingException {
149
150
151 String keyText = "-----BEGIN PRIVATE KEY-----\n" +
152 Base64.encode(ChannelBuffers.wrappedBuffer(key.getEncoded()), true).toString(CharsetUtil.US_ASCII) +
153 "\n-----END PRIVATE KEY-----\n";
154
155 File keyFile = File.createTempFile("keyutil_" + fqdn + '_', ".key");
156 keyFile.deleteOnExit();
157
158 OutputStream keyOut = new FileOutputStream(keyFile);
159 try {
160 keyOut.write(keyText.getBytes(CharsetUtil.US_ASCII.name()));
161 keyOut.close();
162 keyOut = null;
163 } finally {
164 if (keyOut != null) {
165 safeClose(keyFile, keyOut);
166 safeDelete(keyFile);
167 }
168 }
169
170
171 String certText = "-----BEGIN CERTIFICATE-----\n" +
172 Base64.encode(ChannelBuffers.wrappedBuffer(cert.getEncoded()), true).toString(CharsetUtil.US_ASCII) +
173 "\n-----END CERTIFICATE-----\n";
174
175 File certFile = File.createTempFile("keyutil_" + fqdn + '_', ".crt");
176 certFile.deleteOnExit();
177
178 OutputStream certOut = new FileOutputStream(certFile);
179 try {
180 certOut.write(certText.getBytes(CharsetUtil.US_ASCII.name()));
181 certOut.close();
182 certOut = null;
183 } finally {
184 if (certOut != null) {
185 safeClose(certFile, certOut);
186 safeDelete(certFile);
187 safeDelete(keyFile);
188 }
189 }
190
191 return new String[] { certFile.getPath(), keyFile.getPath() };
192 }
193
194 private static void safeDelete(File certFile) {
195 if (!certFile.delete()) {
196 logger.warn("Failed to delete a file: " + certFile);
197 }
198 }
199
200 private static void safeClose(File keyFile, OutputStream keyOut) {
201 try {
202 keyOut.close();
203 } catch (IOException e) {
204 logger.warn("Failed to close a file: " + keyFile, e);
205 }
206 }
207 }