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