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 if (_keystore != null)
238 keystoreInputStream = Resource.newResource(_keystore).getInputStream();
239 KeyStore keyStore = KeyStore.getInstance(_keystoreType);
240 keyStore.load(keystoreInputStream, _password==null?null:_password.toString().toCharArray());
241
242 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_sslKeyManagerFactoryAlgorithm);
243 keyManagerFactory.init(keyStore,_keyPassword==null?null:_keyPassword.toString().toCharArray());
244 keyManagers = keyManagerFactory.getKeyManagers();
245
246 TrustManager[] trustManagers = null;
247 InputStream truststoreInputStream = null;
248 if (_truststore != null)
249 truststoreInputStream = Resource.newResource(_truststore).getInputStream();
250 KeyStore trustStore = KeyStore.getInstance(_truststoreType);
251 trustStore.load(truststoreInputStream,_trustPassword==null?null:_trustPassword.toString().toCharArray());
252
253 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_sslTrustManagerFactoryAlgorithm);
254 trustManagerFactory.init(trustStore);
255 trustManagers = trustManagerFactory.getTrustManagers();
256
257
258 SecureRandom secureRandom = _secureRandomAlgorithm==null?null:SecureRandom.getInstance(_secureRandomAlgorithm);
259
260 SSLContext context = _provider==null?SSLContext.getInstance(_protocol):SSLContext.getInstance(_protocol, _provider);
261
262 context.init(keyManagers, trustManagers, secureRandom);
263
264 return context.getServerSocketFactory();
265 }
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 public void customize(EndPoint endpoint, Request request)
287 throws IOException
288 {
289 super.customize(endpoint, request);
290 request.setScheme(HttpSchemes.HTTPS);
291
292 SocketEndPoint socket_end_point = (SocketEndPoint)endpoint;
293 SSLSocket sslSocket = (SSLSocket)socket_end_point.getTransport();
294
295 try
296 {
297 SSLSession sslSession = sslSocket.getSession();
298 String cipherSuite = sslSession.getCipherSuite();
299 Integer keySize;
300 X509Certificate[] certs;
301
302 CachedInfo cachedInfo = (CachedInfo) sslSession.getValue(CACHED_INFO_ATTR);
303 if (cachedInfo != null)
304 {
305 keySize = cachedInfo.getKeySize();
306 certs = cachedInfo.getCerts();
307 }
308 else
309 {
310 keySize = new Integer(ServletSSL.deduceKeyLength(cipherSuite));
311 certs = getCertChain(sslSession);
312 cachedInfo = new CachedInfo(keySize, certs);
313 sslSession.putValue(CACHED_INFO_ATTR, cachedInfo);
314 }
315
316 if (certs != null)
317 request.setAttribute("javax.servlet.request.X509Certificate", certs);
318 else if (_needClientAuth)
319 throw new IllegalStateException("no client auth");
320
321 request.setAttribute("javax.servlet.request.cipher_suite", cipherSuite);
322 request.setAttribute("javax.servlet.request.key_size", keySize);
323 }
324 catch (Exception e)
325 {
326 Log.warn(Log.EXCEPTION, e);
327 }
328 }
329
330
331 public String[] getExcludeCipherSuites() {
332 return _excludeCipherSuites;
333 }
334
335
336 public String getKeystore()
337 {
338 return _keystore;
339 }
340
341
342 public String getKeystoreType()
343 {
344 return (_keystoreType);
345 }
346
347
348 public boolean getNeedClientAuth()
349 {
350 return _needClientAuth;
351 }
352
353
354 public String getProtocol()
355 {
356 return _protocol;
357 }
358
359
360 public String getProvider() {
361 return _provider;
362 }
363
364
365 public String getSecureRandomAlgorithm()
366 {
367 return (this._secureRandomAlgorithm);
368 }
369
370
371 public String getSslKeyManagerFactoryAlgorithm()
372 {
373 return (this._sslKeyManagerFactoryAlgorithm);
374 }
375
376
377 public String getSslTrustManagerFactoryAlgorithm()
378 {
379 return (this._sslTrustManagerFactoryAlgorithm);
380 }
381
382
383 public String getTruststore()
384 {
385 return _truststore;
386 }
387
388
389 public String getTruststoreType()
390 {
391 return _truststoreType;
392 }
393
394
395 public boolean getWantClientAuth()
396 {
397 return _wantClientAuth;
398 }
399
400
401
402
403
404
405
406
407
408 public boolean isConfidential(Request request)
409 {
410 final int confidentialPort = getConfidentialPort();
411 return confidentialPort == 0 || confidentialPort == request.getServerPort();
412 }
413
414
415
416
417
418
419
420
421
422 public boolean isIntegral(Request request)
423 {
424 final int integralPort = getIntegralPort();
425 return integralPort == 0 || integralPort == request.getServerPort();
426 }
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441 protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
442 {
443 SSLServerSocketFactory factory = null;
444 SSLServerSocket socket = null;
445
446 try
447 {
448 factory = createFactory();
449
450 socket = (SSLServerSocket) (host==null?
451 factory.createServerSocket(port,backlog):
452 factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
453
454 if (_wantClientAuth)
455 socket.setWantClientAuth(_wantClientAuth);
456 if (_needClientAuth)
457 socket.setNeedClientAuth(_needClientAuth);
458
459 if (_excludeCipherSuites != null && _excludeCipherSuites.length >0)
460 {
461 List excludedCSList = Arrays.asList(_excludeCipherSuites);
462 String[] enabledCipherSuites = socket.getEnabledCipherSuites();
463 List enabledCSList = new ArrayList(Arrays.asList(enabledCipherSuites));
464 Iterator exIter = excludedCSList.iterator();
465
466 while (exIter.hasNext())
467 {
468 String cipherName = (String)exIter.next();
469 if (enabledCSList.contains(cipherName))
470 {
471 enabledCSList.remove(cipherName);
472 }
473 }
474 enabledCipherSuites = (String[])enabledCSList.toArray(new String[enabledCSList.size()]);
475
476 socket.setEnabledCipherSuites(enabledCipherSuites);
477 }
478
479 }
480 catch (IOException e)
481 {
482 throw e;
483 }
484 catch (Exception e)
485 {
486 Log.warn(e.toString());
487 Log.debug(e);
488 throw new IOException("!JsseListener: " + e);
489 }
490 return socket;
491 }
492
493
494
495
496
497 public void setExcludeCipherSuites(String[] cipherSuites) {
498 this._excludeCipherSuites = cipherSuites;
499 }
500
501
502 public void setKeyPassword(String password)
503 {
504 _keyPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
505 }
506
507
508
509
510
511 public void setKeystore(String keystore)
512 {
513 _keystore = keystore;
514 }
515
516
517 public void setKeystoreType(String keystoreType)
518 {
519 _keystoreType = keystoreType;
520 }
521
522
523
524
525
526
527
528 public void setNeedClientAuth(boolean needClientAuth)
529 {
530 _needClientAuth = needClientAuth;
531 }
532
533
534 public void setPassword(String password)
535 {
536 _password = Password.getPassword(PASSWORD_PROPERTY,password,null);
537 }
538
539
540 public void setTrustPassword(String password)
541 {
542 _trustPassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
543 }
544
545
546 public void setProtocol(String protocol)
547 {
548 _protocol = protocol;
549 }
550
551
552 public void setProvider(String _provider) {
553 this._provider = _provider;
554 }
555
556
557 public void setSecureRandomAlgorithm(String algorithm)
558 {
559 this._secureRandomAlgorithm = algorithm;
560 }
561
562
563 public void setSslKeyManagerFactoryAlgorithm(String algorithm)
564 {
565 this._sslKeyManagerFactoryAlgorithm = algorithm;
566 }
567
568
569 public void setSslTrustManagerFactoryAlgorithm(String algorithm)
570 {
571 this._sslTrustManagerFactoryAlgorithm = algorithm;
572 }
573
574
575 public void setTruststore(String truststore)
576 {
577 _truststore = truststore;
578 }
579
580
581 public void setTruststoreType(String truststoreType)
582 {
583 _truststoreType = truststoreType;
584 }
585
586
587
588
589
590
591
592
593
594 public void setWantClientAuth(boolean wantClientAuth)
595 {
596 _wantClientAuth = wantClientAuth;
597 }
598
599
600
601
602
603
604 public void setHandshakeTimeout (int msec)
605 {
606 _handshakeTimeout = msec;
607 }
608
609
610 public int getHandshakeTimeout ()
611 {
612 return _handshakeTimeout;
613 }
614
615
616
617
618 private class CachedInfo
619 {
620 private X509Certificate[] _certs;
621 private Integer _keySize;
622
623 CachedInfo(Integer keySize, X509Certificate[] certs)
624 {
625 this._keySize = keySize;
626 this._certs = certs;
627 }
628
629 X509Certificate[] getCerts()
630 {
631 return _certs;
632 }
633
634 Integer getKeySize()
635 {
636 return _keySize;
637 }
638 }
639
640
641 public class SslConnection extends Connection
642 {
643 public SslConnection(Socket socket) throws IOException
644 {
645 super(socket);
646 }
647
648 public void run()
649 {
650 try
651 {
652 int handshakeTimeout = getHandshakeTimeout();
653 int oldTimeout = _socket.getSoTimeout();
654 if (handshakeTimeout > 0)
655 _socket.setSoTimeout(handshakeTimeout);
656
657 final SSLSocket ssl=(SSLSocket)_socket;
658 ssl.addHandshakeCompletedListener(new HandshakeCompletedListener()
659 {
660 boolean handshook=false;
661 public void handshakeCompleted(HandshakeCompletedEvent event)
662 {
663 if (handshook)
664 {
665 if (!_allowRenegotiate)
666 {
667 Log.warn("SSL renegotiate denied: "+ssl);
668 try{ssl.close();}catch(IOException e){Log.warn(e);}
669 }
670 }
671 else
672 handshook=true;
673 }
674 });
675 ssl.startHandshake();
676
677 if (handshakeTimeout>0)
678 _socket.setSoTimeout(oldTimeout);
679
680 super.run();
681 }
682 catch (SSLException e)
683 {
684 Log.warn(e);
685 try{close();}
686 catch(IOException e2){Log.ignore(e2);}
687 }
688 catch (IOException e)
689 {
690 Log.debug(e);
691 try{close();}
692 catch(IOException e2){Log.ignore(e2);}
693 }
694 }
695 }
696
697 }