1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.security;
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.math.BigInteger;
28 import java.net.InetAddress;
29 import java.nio.file.Files;
30 import java.nio.file.Paths;
31 import java.security.InvalidKeyException;
32 import java.security.KeyPair;
33 import java.security.KeyPairGenerator;
34 import java.security.KeyStore;
35 import java.security.KeyStoreException;
36 import java.security.NoSuchAlgorithmException;
37 import java.security.NoSuchProviderException;
38 import java.security.SecureRandom;
39 import java.security.Security;
40 import java.security.SignatureException;
41 import java.security.cert.CertificateException;
42 import java.security.cert.X509Certificate;
43 import java.util.Date;
44 import java.util.Enumeration;
45
46 import javax.net.ssl.KeyManagerFactory;
47
48 import org.apache.directory.api.util.Strings;
49
50 import sun.security.x509.AlgorithmId;
51 import sun.security.x509.BasicConstraintsExtension;
52 import sun.security.x509.CertificateAlgorithmId;
53 import sun.security.x509.CertificateExtensions;
54 import sun.security.x509.CertificateSerialNumber;
55 import sun.security.x509.CertificateValidity;
56 import sun.security.x509.CertificateVersion;
57 import sun.security.x509.CertificateX509Key;
58 import sun.security.x509.DNSName;
59 import sun.security.x509.GeneralName;
60 import sun.security.x509.GeneralNames;
61 import sun.security.x509.IPAddressName;
62 import sun.security.x509.SubjectAlternativeNameExtension;
63 import sun.security.x509.X500Name;
64 import sun.security.x509.X509CertImpl;
65 import sun.security.x509.X509CertInfo;
66
67
68
69
70
71
72 @SuppressWarnings("restriction")
73 public final class CertificateUtil
74 {
75 private static final boolean SELF_SIGNED = true;
76 private static final boolean CA_SIGNED = false;
77 private static final boolean CRITICAL = true;
78
79 private CertificateUtil()
80 {
81
82 }
83
84
85 private static void setInfo( X509CertInfo info, X500Name subject, X500Name issuer, KeyPair keyPair, int days,
86 String algoStr, boolean isCA )
87 throws CertificateException, IOException, NoSuchAlgorithmException
88 {
89 Date from = new Date();
90 Date to = new Date( from.getTime() + days * 86_400_000L );
91 CertificateValidity interval = new CertificateValidity( from, to );
92
93
94
95
96 info.set( X509CertInfo.VERSION, new CertificateVersion( CertificateVersion.V3 ) );
97
98
99
100 BigInteger serialNumber = new BigInteger( 64, new SecureRandom() );
101 info.set( X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( serialNumber ) );
102
103
104 AlgorithmId algo = AlgorithmId.get( algoStr );
105 info.set( X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId( algo ) );
106
107
108
109
110
111
112
113
114
115
116
117
118 info.set( X509CertInfo.ISSUER, issuer );
119
120
121
122
123
124 info.set( X509CertInfo.VALIDITY, interval );
125
126
127
128
129
130
131
132
133
134
135
136
137 info.set( X509CertInfo.SUBJECT, subject );
138
139
140
141
142
143 info.set( X509CertInfo.KEY, new CertificateX509Key( keyPair.getPublic() ) );
144
145
146 CertificateExtensions extensions = new CertificateExtensions();
147
148
149 GeneralNames names = new GeneralNames();
150 names.add( new GeneralName( new DNSName( InetAddress.getLocalHost().getHostName() ) ) );
151 String ipAddress = InetAddress.getLocalHost().getHostAddress();
152 names.add( new GeneralName( new IPAddressName( ipAddress ) ) );
153
154
155
156
157
158
159 SubjectAlternativeNameExtension subjectAltName = new SubjectAlternativeNameExtension( names );
160
161 extensions.set( subjectAltName.getExtensionId().toString(), subjectAltName );
162
163
164 BasicConstraintsExtension basicConstraint = new BasicConstraintsExtension( CRITICAL, isCA, -1 );
165 extensions.set( basicConstraint.getExtensionId().toString(), basicConstraint );
166
167
168 info.set( X509CertInfo.EXTENSIONS, extensions );
169 }
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 public static X509Certificate generateSelfSignedCertificate( X500Name issuer, KeyPair keyPair, int days, String algoStr )
188 throws CertificateException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException
189 {
190
191 X509CertInfo info = new X509CertInfo();
192
193
194 setInfo( info, issuer, issuer, keyPair, days, algoStr, SELF_SIGNED );
195
196
197 X509CertImpl certificate = new X509CertImpl( info );
198 certificate.sign( keyPair.getPrivate(), algoStr );
199
200 return certificate;
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 public static X509Certificate generateCertificate( X500Name subject, X500Name issuer, KeyPair keyPair, int days, String algoStr )
220 throws CertificateException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException
221 {
222
223 X509CertInfo info = new X509CertInfo();
224
225
226 setInfo( info, subject, issuer, keyPair, days, algoStr, CA_SIGNED );
227
228
229 X509CertImpl certificate = new X509CertImpl( info );
230 certificate.sign( keyPair.getPrivate(), algoStr );
231
232 return certificate;
233 }
234
235
236
237
238
239
240
241
242
243
244 public static KeyManagerFactory loadKeyStore( String keyStoreFile, String keyStorePasswordStr ) throws Exception
245 {
246 char[] keyStorePassword = Strings.isEmpty( keyStorePasswordStr ) ? null : keyStorePasswordStr.toCharArray();
247
248 if ( !Strings.isEmpty( keyStoreFile ) )
249 {
250
251 KeyStore keyStore = KeyStore.getInstance( KeyStore.getDefaultType() );
252
253 try ( InputStream is = Files.newInputStream( Paths.get( keyStoreFile ) ) )
254 {
255 keyStore.load( is, keyStorePassword );
256 }
257
258
259
260
261
262
263
264 Enumeration<String> aliases = keyStore.aliases();
265
266 if ( !aliases.hasMoreElements() )
267 {
268 throw new KeyStoreException( "Key store is empty" );
269 }
270
271 String alias = aliases.nextElement();
272
273 if ( aliases.hasMoreElements() )
274 {
275 throw new KeyStoreException( "Key store contains more than one entry" );
276 }
277
278 if ( !keyStore.isKeyEntry( alias ) )
279 {
280 throw new KeyStoreException( "Key store must contain a key entry" );
281 }
282
283 if ( keyStore.getCertificateChain( alias ) == null )
284 {
285 throw new KeyStoreException( "Key store must contain a certificate chain" );
286 }
287
288 if ( keyStore.getKey( alias, keyStorePassword ) == null )
289 {
290 throw new KeyStoreException( "Private key must be recoverable by the key store password" );
291 }
292
293
294 String algorithm = Security.getProperty( "ssl.KeyManagerFactory.algorithm" );
295
296 if ( algorithm == null )
297 {
298 algorithm = KeyManagerFactory.getDefaultAlgorithm();
299 }
300
301 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( algorithm );
302
303 keyManagerFactory.init( keyStore, keyStorePassword );
304
305 return keyManagerFactory;
306 }
307 else
308 {
309 return null;
310 }
311 }
312
313
314 public static File createTempKeyStore( String keyStoreName, char[] keyStorePassword ) throws IOException, KeyStoreException,
315 NoSuchAlgorithmException, CertificateException, InvalidKeyException, NoSuchProviderException, SignatureException
316 {
317
318 File keyStoreFile = Files.createTempFile( keyStoreName, "ks" ).toFile();
319 keyStoreFile.deleteOnExit();
320
321 KeyStore keyStore = KeyStore.getInstance( KeyStore.getDefaultType() );
322
323 try ( InputStream keyStoreData = new FileInputStream( keyStoreFile ) )
324 {
325 keyStore.load( null, keyStorePassword );
326 }
327
328
329 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "EC" );
330 KeyPair keyPair = keyPairGenerator.generateKeyPair();
331
332
333 @SuppressWarnings("restriction")
334 X500Name owner = new X500Name( "apacheds", "directory", "apache", "US" );
335
336
337 X509Certificate certificate = CertificateUtil.generateSelfSignedCertificate( owner, keyPair, 365, "SHA256WithECDSA" );
338
339 keyStore.setKeyEntry( "apachedsKey", keyPair.getPrivate(), keyStorePassword, new X509Certificate[] { certificate } );
340
341 try ( FileOutputStream out = new FileOutputStream( keyStoreFile ) )
342 {
343 keyStore.store( out, keyStorePassword );
344 }
345
346 return keyStoreFile;
347 }
348 }