1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.jetty.security;
16
17 import java.io.ByteArrayInputStream;
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.InetAddress;
22 import java.net.ServerSocket;
23 import java.net.Socket;
24 import java.net.SocketAddress;
25 import java.security.KeyStore;
26 import java.security.SecureRandom;
27 import java.security.Security;
28 import java.security.cert.X509Certificate;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Iterator;
32 import java.util.List;
33
34 import javax.net.ssl.KeyManager;
35 import javax.net.ssl.KeyManagerFactory;
36 import javax.net.ssl.SSLContext;
37 import javax.net.ssl.SSLException;
38 import javax.net.ssl.SSLPeerUnverifiedException;
39 import javax.net.ssl.SSLServerSocket;
40 import javax.net.ssl.SSLServerSocketFactory;
41 import javax.net.ssl.SSLSession;
42 import javax.net.ssl.SSLSocket;
43 import javax.net.ssl.TrustManager;
44 import javax.net.ssl.TrustManagerFactory;
45
46 import org.mortbay.io.EndPoint;
47 import org.mortbay.io.bio.SocketEndPoint;
48 import org.mortbay.jetty.HttpSchemes;
49 import org.mortbay.jetty.Request;
50 import org.mortbay.jetty.bio.SocketConnector;
51 import org.mortbay.log.Log;
52 import org.mortbay.resource.Resource;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class SslSocketConnector extends SocketConnector
70 {
71
72
73
74 static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
75
76
77 public static final String DEFAULT_KEYSTORE = System.getProperty("user.home") + File.separator
78 + ".keystore";
79
80
81 public static final String KEYPASSWORD_PROPERTY = "jetty.ssl.keypassword";
82
83
84 public static final String PASSWORD_PROPERTY = "jetty.ssl.password";
85
86
87
88
89
90
91
92
93
94
95
96
97 private static X509Certificate[] getCertChain(SSLSession sslSession)
98 {
99 try
100 {
101 javax.security.cert.X509Certificate javaxCerts[] = sslSession.getPeerCertificateChain();
102 if (javaxCerts == null || javaxCerts.length == 0)
103 return null;
104
105 int length = javaxCerts.length;
106 X509Certificate[] javaCerts = new X509Certificate[length];
107
108 java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509");
109 for (int i = 0; i < length; i++)
110 {
111 byte bytes[] = javaxCerts[i].getEncoded();
112 ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
113 javaCerts[i] = (X509Certificate) cf.generateCertificate(stream);
114 }
115
116 return javaCerts;
117 }
118 catch (SSLPeerUnverifiedException pue)
119 {
120 return null;
121 }
122 catch (Exception e)
123 {
124 Log.warn(Log.EXCEPTION, e);
125 return null;
126 }
127 }
128
129
130
131 private String _excludeCipherSuites[] = null;
132
133
134 private String _keystore=DEFAULT_KEYSTORE ;
135 private String _keystoreType = "JKS";
136
137
138 private boolean _needClientAuth = false;
139 private transient Password _password;
140 private transient Password _keyPassword;
141 private transient Password _trustPassword;
142 private String _protocol= "TLS";
143 private String _provider;
144 private String _secureRandomAlgorithm;
145 private String _sslKeyManagerFactoryAlgorithm = (Security.getProperty("ssl.KeyManagerFactory.algorithm")==null?"SunX509":Security.getProperty("ssl.KeyManagerFactory.algorithm"));
146 private String _sslTrustManagerFactoryAlgorithm = (Security.getProperty("ssl.TrustManagerFactory.algorithm")==null?"SunX509":Security.getProperty("ssl.TrustManagerFactory.algorithm"));
147
148 private String _truststore;
149 private String _truststoreType = "JKS";
150
151
152 private boolean _wantClientAuth = false;
153 private int _handshakeTimeout = 0;
154
155
156
157
158
159
160 public SslSocketConnector()
161 {
162 super();
163 }
164
165
166
167 public void accept(int acceptorID)
168 throws IOException, InterruptedException
169 {
170 Socket socket = _serverSocket.accept();
171 configure(socket);
172
173 Connection connection=new SslConnection(socket);
174 connection.dispatch();
175 }
176
177
178 protected void configure(Socket socket)
179 throws IOException
180 {
181 super.configure(socket);
182 }
183
184
185 protected SSLServerSocketFactory createFactory()
186 throws Exception
187 {
188 if (_truststore==null)
189 {
190 _truststore=_keystore;
191 _truststoreType=_keystoreType;
192 }
193
194 KeyManager[] keyManagers = null;
195 InputStream keystoreInputStream = null;
196 if (_keystore != null)
197 keystoreInputStream = Resource.newResource(_keystore).getInputStream();
198 KeyStore keyStore = KeyStore.getInstance(_keystoreType);
199 keyStore.load(keystoreInputStream, _password==null?null:_password.toString().toCharArray());
200
201 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_sslKeyManagerFactoryAlgorithm);
202 keyManagerFactory.init(keyStore,_keyPassword==null?null:_keyPassword.toString().toCharArray());
203 keyManagers = keyManagerFactory.getKeyManagers();
204
205 TrustManager[] trustManagers = null;
206 InputStream truststoreInputStream = null;
207 if (_truststore != null)
208 truststoreInputStream = Resource.newResource(_truststore).getInputStream();
209 KeyStore trustStore = KeyStore.getInstance(_truststoreType);
210 trustStore.load(truststoreInputStream,_trustPassword==null?null:_trustPassword.toString().toCharArray());
211
212 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_sslTrustManagerFactoryAlgorithm);
213 trustManagerFactory.init(trustStore);
214 trustManagers = trustManagerFactory.getTrustManagers();
215
216
217 SecureRandom secureRandom = _secureRandomAlgorithm==null?null:SecureRandom.getInstance(_secureRandomAlgorithm);
218
219 SSLContext context = _provider==null?SSLContext.getInstance(_protocol):SSLContext.getInstance(_protocol, _provider);
220
221 context.init(keyManagers, trustManagers, secureRandom);
222
223 return context.getServerSocketFactory();
224 }
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245 public void customize(EndPoint endpoint, Request request)
246 throws IOException
247 {
248 super.customize(endpoint, request);
249 request.setScheme(HttpSchemes.HTTPS);
250
251 SocketEndPoint socket_end_point = (SocketEndPoint)endpoint;
252 SSLSocket sslSocket = (SSLSocket)socket_end_point.getTransport();
253
254 try
255 {
256 SSLSession sslSession = sslSocket.getSession();
257 String cipherSuite = sslSession.getCipherSuite();
258 Integer keySize;
259 X509Certificate[] certs;
260
261 CachedInfo cachedInfo = (CachedInfo) sslSession.getValue(CACHED_INFO_ATTR);
262 if (cachedInfo != null)
263 {
264 keySize = cachedInfo.getKeySize();
265 certs = cachedInfo.getCerts();
266 }
267 else
268 {
269 keySize = new Integer(ServletSSL.deduceKeyLength(cipherSuite));
270 certs = getCertChain(sslSession);
271 cachedInfo = new CachedInfo(keySize, certs);
272 sslSession.putValue(CACHED_INFO_ATTR, cachedInfo);
273 }
274
275 if (certs != null)
276 request.setAttribute("javax.servlet.request.X509Certificate", certs);
277 else if (_needClientAuth)
278 throw new IllegalStateException("no client auth");
279
280 request.setAttribute("javax.servlet.request.cipher_suite", cipherSuite);
281 request.setAttribute("javax.servlet.request.key_size", keySize);
282 }
283 catch (Exception e)
284 {
285 Log.warn(Log.EXCEPTION, e);
286 }
287 }
288
289
290 public String[] getExcludeCipherSuites() {
291 return _excludeCipherSuites;
292 }
293
294
295 public String getKeystore()
296 {
297 return _keystore;
298 }
299
300
301 public String getKeystoreType()
302 {
303 return (_keystoreType);
304 }
305
306
307 public boolean getNeedClientAuth()
308 {
309 return _needClientAuth;
310 }
311
312
313 public String getProtocol()
314 {
315 return _protocol;
316 }
317
318
319 public String getProvider() {
320 return _provider;
321 }
322
323
324 public String getSecureRandomAlgorithm()
325 {
326 return (this._secureRandomAlgorithm);
327 }
328
329
330 public String getSslKeyManagerFactoryAlgorithm()
331 {
332 return (this._sslKeyManagerFactoryAlgorithm);
333 }
334
335
336 public String getSslTrustManagerFactoryAlgorithm()
337 {
338 return (this._sslTrustManagerFactoryAlgorithm);
339 }
340
341
342 public String getTruststore()
343 {
344 return _truststore;
345 }
346
347
348 public String getTruststoreType()
349 {
350 return _truststoreType;
351 }
352
353
354 public boolean getWantClientAuth()
355 {
356 return _wantClientAuth;
357 }
358
359
360
361
362
363
364
365
366
367 public boolean isConfidential(Request request)
368 {
369 final int confidentialPort = getConfidentialPort();
370 return confidentialPort == 0 || confidentialPort == request.getServerPort();
371 }
372
373
374
375
376
377
378
379
380
381 public boolean isIntegral(Request request)
382 {
383 final int integralPort = getIntegralPort();
384 return integralPort == 0 || integralPort == request.getServerPort();
385 }
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400 protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
401 {
402 SSLServerSocketFactory factory = null;
403 SSLServerSocket socket = null;
404
405 try
406 {
407 factory = createFactory();
408
409 socket = (SSLServerSocket) (host==null?
410 factory.createServerSocket(port,backlog):
411 factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
412
413 if (_wantClientAuth)
414 socket.setWantClientAuth(_wantClientAuth);
415 if (_needClientAuth)
416 socket.setNeedClientAuth(_needClientAuth);
417
418 if (_excludeCipherSuites != null && _excludeCipherSuites.length >0)
419 {
420 List excludedCSList = Arrays.asList(_excludeCipherSuites);
421 String[] enabledCipherSuites = socket.getEnabledCipherSuites();
422 List enabledCSList = new ArrayList(Arrays.asList(enabledCipherSuites));
423 Iterator exIter = excludedCSList.iterator();
424
425 while (exIter.hasNext())
426 {
427 String cipherName = (String)exIter.next();
428 if (enabledCSList.contains(cipherName))
429 {
430 enabledCSList.remove(cipherName);
431 }
432 }
433 enabledCipherSuites = (String[])enabledCSList.toArray(new String[enabledCSList.size()]);
434
435 socket.setEnabledCipherSuites(enabledCipherSuites);
436 }
437
438 }
439 catch (IOException e)
440 {
441 throw e;
442 }
443 catch (Exception e)
444 {
445 Log.warn(Log.EXCEPTION, e);
446 throw new IOException("Could not create JsseListener: " + e.toString());
447 }
448 return socket;
449 }
450
451
452
453
454
455 public void setExcludeCipherSuites(String[] cipherSuites) {
456 this._excludeCipherSuites = cipherSuites;
457 }
458
459
460 public void setKeyPassword(String password)
461 {
462 _keyPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
463 }
464
465
466
467
468
469 public void setKeystore(String keystore)
470 {
471 _keystore = keystore;
472 }
473
474
475 public void setKeystoreType(String keystoreType)
476 {
477 _keystoreType = keystoreType;
478 }
479
480
481
482
483
484
485
486 public void setNeedClientAuth(boolean needClientAuth)
487 {
488 _needClientAuth = needClientAuth;
489 }
490
491
492 public void setPassword(String password)
493 {
494 _password = Password.getPassword(PASSWORD_PROPERTY,password,null);
495 }
496
497
498 public void setTrustPassword(String password)
499 {
500 _trustPassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
501 }
502
503
504 public void setProtocol(String protocol)
505 {
506 _protocol = protocol;
507 }
508
509
510 public void setProvider(String _provider) {
511 this._provider = _provider;
512 }
513
514
515 public void setSecureRandomAlgorithm(String algorithm)
516 {
517 this._secureRandomAlgorithm = algorithm;
518 }
519
520
521 public void setSslKeyManagerFactoryAlgorithm(String algorithm)
522 {
523 this._sslKeyManagerFactoryAlgorithm = algorithm;
524 }
525
526
527 public void setSslTrustManagerFactoryAlgorithm(String algorithm)
528 {
529 this._sslTrustManagerFactoryAlgorithm = algorithm;
530 }
531
532
533 public void setTruststore(String truststore)
534 {
535 _truststore = truststore;
536 }
537
538
539 public void setTruststoreType(String truststoreType)
540 {
541 _truststoreType = truststoreType;
542 }
543
544
545
546
547
548
549
550
551
552 public void setWantClientAuth(boolean wantClientAuth)
553 {
554 _wantClientAuth = wantClientAuth;
555 }
556
557
558
559
560
561
562 public void setHandshakeTimeout (int msec)
563 {
564 _handshakeTimeout = msec;
565 }
566
567
568 public int getHandshakeTimeout ()
569 {
570 return _handshakeTimeout;
571 }
572
573
574
575
576 private class CachedInfo
577 {
578 private X509Certificate[] _certs;
579 private Integer _keySize;
580
581 CachedInfo(Integer keySize, X509Certificate[] certs)
582 {
583 this._keySize = keySize;
584 this._certs = certs;
585 }
586
587 X509Certificate[] getCerts()
588 {
589 return _certs;
590 }
591
592 Integer getKeySize()
593 {
594 return _keySize;
595 }
596 }
597
598
599 public class SslConnection extends Connection
600 {
601 public SslConnection(Socket socket) throws IOException
602 {
603 super(socket);
604 }
605
606 public void run()
607 {
608 try
609 {
610 int handshakeTimeout = getHandshakeTimeout();
611 int oldTimeout = _socket.getSoTimeout();
612 if (handshakeTimeout > 0)
613 _socket.setSoTimeout(handshakeTimeout);
614
615 ((SSLSocket)_socket).startHandshake();
616
617 if (handshakeTimeout>0)
618 _socket.setSoTimeout(oldTimeout);
619
620 super.run();
621 }
622 catch (SSLException e)
623 {
624 Log.debug(e);
625 try{close();}
626 catch(IOException e2){Log.ignore(e2);}
627 }
628 catch (IOException e)
629 {
630 Log.debug(e);
631 try{close();}
632 catch(IOException e2){Log.ignore(e2);}
633 }
634 }
635 }
636
637 }