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
23 import java.io.ByteArrayInputStream;
24 import java.io.InputStream;
25 import java.math.BigInteger;
26 import java.net.InetAddress;
27 import java.security.KeyFactory;
28 import java.security.KeyPair;
29 import java.security.KeyPairGenerator;
30 import java.security.NoSuchAlgorithmException;
31 import java.security.PrivateKey;
32 import java.security.PublicKey;
33 import java.security.Security;
34 import java.security.cert.CertificateException;
35 import java.security.cert.CertificateFactory;
36 import java.security.cert.X509Certificate;
37 import java.security.spec.EncodedKeySpec;
38 import java.security.spec.InvalidKeySpecException;
39 import java.security.spec.PKCS8EncodedKeySpec;
40 import java.security.spec.X509EncodedKeySpec;
41 import java.util.Date;
42
43 import javax.security.auth.x500.X500Principal;
44
45 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
46 import org.apache.directory.api.ldap.model.entry.Attribute;
47 import org.apache.directory.api.ldap.model.entry.Entry;
48 import org.apache.directory.api.ldap.model.exception.LdapException;
49 import org.apache.directory.server.i18n.I18n;
50 import org.bouncycastle.asn1.x509.BasicConstraints;
51 import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
52 import org.bouncycastle.asn1.x509.Extension;
53 import org.bouncycastle.asn1.x509.KeyPurposeId;
54 import org.bouncycastle.jce.provider.BouncyCastleProvider;
55 import org.bouncycastle.x509.X509V3CertificateGenerator;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59
60
61
62
63
64
65 public final class TlsKeyGenerator
66 {
67 private TlsKeyGenerator()
68 {
69 }
70
71 private static final Logger LOG = LoggerFactory.getLogger( TlsKeyGenerator.class );
72
73 public static final String TLS_KEY_INFO_OC = "tlsKeyInfo";
74 public static final String PRIVATE_KEY_AT = "privateKey";
75 public static final String PUBLIC_KEY_AT = "publicKey";
76 public static final String KEY_ALGORITHM_AT = "keyAlgorithm";
77 public static final String PRIVATE_KEY_FORMAT_AT = "privateKeyFormat";
78 public static final String PUBLIC_KEY_FORMAT_AT = "publicKeyFormat";
79 public static final String USER_CERTIFICATE_AT = "userCertificate";
80
81 private static final String BASE_DN = "OU=Directory, O=ASF, C=US";
82
83 public static final String CERTIFICATE_PRINCIPAL_DN = "CN=ApacheDS," + BASE_DN;
84
85 private static final String ALGORITHM = "RSA";
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 private static final int KEY_SIZE = 1024;
102 public static final long YEAR_MILLIS = 365L * 24L * 3600L * 1000L;
103
104 static
105 {
106 Security.addProvider( new BouncyCastleProvider() );
107 }
108
109
110
111
112
113
114
115
116
117
118 public static X509Certificate getCertificate( Entry entry ) throws LdapException
119 {
120 X509Certificate cert = null;
121 CertificateFactory certFactory = null;
122
123 try
124 {
125 certFactory = CertificateFactory.getInstance( "X.509", "BC" );
126 }
127 catch ( Exception e )
128 {
129 LdapException ne = new LdapException( I18n.err( I18n.ERR_286 ) );
130 ne.initCause( e );
131 throw ne;
132 }
133
134 byte[] certBytes = entry.get( USER_CERTIFICATE_AT ).getBytes();
135 InputStream in = new ByteArrayInputStream( certBytes );
136
137 try
138 {
139 cert = ( X509Certificate ) certFactory.generateCertificate( in );
140 }
141 catch ( CertificateException e )
142 {
143 LdapException ne = new LdapException( I18n.err( I18n.ERR_287 ) );
144 ne.initCause( e );
145 throw ne;
146 }
147
148 return cert;
149 }
150
151
152
153
154
155
156
157
158
159 public static KeyPair getKeyPair( Entry entry ) throws LdapException
160 {
161 PublicKey publicKey = null;
162 PrivateKey privateKey = null;
163
164 KeyFactory keyFactory = null;
165 try
166 {
167 keyFactory = KeyFactory.getInstance( ALGORITHM );
168 }
169 catch ( Exception e )
170 {
171 LdapException ne = new LdapException( I18n.err( I18n.ERR_288, ALGORITHM ) );
172 ne.initCause( e );
173 throw ne;
174 }
175
176 EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec( entry.get( PRIVATE_KEY_AT ).getBytes() );
177 try
178 {
179 privateKey = keyFactory.generatePrivate( privateKeySpec );
180 }
181 catch ( Exception e )
182 {
183 LdapException ne = new LdapException( I18n.err( I18n.ERR_289 ) );
184 ne.initCause( e );
185 throw ne;
186 }
187
188 EncodedKeySpec publicKeySpec = new X509EncodedKeySpec( entry.get( PUBLIC_KEY_AT ).getBytes() );
189 try
190 {
191 publicKey = keyFactory.generatePublic( publicKeySpec );
192 }
193 catch ( InvalidKeySpecException e )
194 {
195 LdapException ne = new LdapException( I18n.err( I18n.ERR_290 ) );
196 ne.initCause( e );
197 throw ne;
198 }
199
200 return new KeyPair( publicKey, privateKey );
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 public static void addKeyPair( Entry entry ) throws LdapException
219 {
220 String subjectDn = null;
221 try
222 {
223 String hostName = InetAddress.getLocalHost().getHostName();
224 subjectDn = "CN=" + hostName + "," + BASE_DN;
225 }
226 catch ( Exception e )
227 {
228 LOG.warn( "failed to create certificate subject name from host name", e );
229 subjectDn = CERTIFICATE_PRINCIPAL_DN;
230 }
231 addKeyPair( entry, CERTIFICATE_PRINCIPAL_DN, subjectDn, ALGORITHM, KEY_SIZE );
232 }
233
234
235 public static void addKeyPair( Entry entry, String issuerDN, String subjectDN, String keyAlgo ) throws LdapException
236 {
237 addKeyPair( entry, issuerDN, subjectDN, keyAlgo, KEY_SIZE );
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251 public static void addKeyPair( Entry entry, String issuerDN, String subjectDN, String keyAlgo, int keySize )
252 throws LdapException
253 {
254 Date startDate = new Date();
255 Date expiryDate = new Date( System.currentTimeMillis() + YEAR_MILLIS );
256 addKeyPair( entry, issuerDN, subjectDN, startDate, expiryDate, keyAlgo, keySize, null );
257 }
258
259
260 public static void addKeyPair( Entry entry, String issuerDN, String subjectDN, Date startDate, Date expiryDate,
261 String keyAlgo, int keySize, PrivateKey optionalSigningKey ) throws LdapException
262 {
263 Attribute objectClass = entry.get( SchemaConstants.OBJECT_CLASS_AT );
264
265 if ( objectClass == null )
266 {
267 entry.put( SchemaConstants.OBJECT_CLASS_AT, TLS_KEY_INFO_OC, SchemaConstants.INET_ORG_PERSON_OC );
268 }
269 else
270 {
271 objectClass.add( TLS_KEY_INFO_OC, SchemaConstants.INET_ORG_PERSON_OC );
272 }
273
274 KeyPairGenerator generator = null;
275 try
276 {
277 generator = KeyPairGenerator.getInstance( keyAlgo );
278 }
279 catch ( NoSuchAlgorithmException e )
280 {
281 LdapException ne = new LdapException( I18n.err( I18n.ERR_291 ) );
282 ne.initCause( e );
283 throw ne;
284 }
285
286 generator.initialize( keySize );
287 KeyPair keypair = generator.genKeyPair();
288 entry.put( KEY_ALGORITHM_AT, keyAlgo );
289
290
291 PrivateKey privateKey = keypair.getPrivate();
292 entry.put( PRIVATE_KEY_AT, privateKey.getEncoded() );
293 entry.put( PRIVATE_KEY_FORMAT_AT, privateKey.getFormat() );
294 LOG.debug( "PrivateKey: {}", privateKey );
295
296 PublicKey publicKey = keypair.getPublic();
297 entry.put( PUBLIC_KEY_AT, publicKey.getEncoded() );
298 entry.put( PUBLIC_KEY_FORMAT_AT, publicKey.getFormat() );
299 LOG.debug( "PublicKey: {}", publicKey );
300
301
302 BigInteger serialNumber = BigInteger.valueOf( System.currentTimeMillis() );
303
304 X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
305 X500Principal issuerName = new X500Principal( issuerDN );
306 X500Principal subjectName = new X500Principal( subjectDN );
307
308 certGen.setSerialNumber( serialNumber );
309 certGen.setIssuerDN( issuerName );
310 certGen.setNotBefore( startDate );
311 certGen.setNotAfter( expiryDate );
312 certGen.setSubjectDN( subjectName );
313 certGen.setPublicKey( publicKey );
314 certGen.setSignatureAlgorithm( "SHA256With" + keyAlgo );
315 certGen.addExtension( Extension.basicConstraints, false, new BasicConstraints( false ) );
316 certGen.addExtension( Extension.extendedKeyUsage, true, new ExtendedKeyUsage(
317 new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth } ) );
318
319
320
321 try
322 {
323 PrivateKey signingKey = optionalSigningKey != null ? optionalSigningKey : privateKey;
324 X509Certificate cert = certGen.generate( signingKey, "BC" );
325 entry.put( USER_CERTIFICATE_AT, cert.getEncoded() );
326 LOG.debug( "X509 Certificate: {}", cert );
327 }
328 catch ( Exception e )
329 {
330 LdapException ne = new LdapException( I18n.err( I18n.ERR_292 ) );
331 ne.initCause( e );
332 throw ne;
333 }
334
335 LOG.info( "Keys and self signed certificate successfully generated." );
336 }
337
338 }