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