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