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(Log.EXCEPTION, e);
462 throw new IOException("Could not create JsseListener: " + e.toString());
463 }
464 return socket;
465 }
466
467
468
469
470
471 public void setExcludeCipherSuites(String[] cipherSuites) {
472 this._excludeCipherSuites = cipherSuites;
473 }
474
475
476 public void setKeyPassword(String password)
477 {
478 _keyPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
479 }
480
481
482
483
484
485 public void setKeystore(String keystore)
486 {
487 _keystore = keystore;
488 }
489
490
491 public void setKeystoreType(String keystoreType)
492 {
493 _keystoreType = keystoreType;
494 }
495
496
497
498
499
500
501
502 public void setNeedClientAuth(boolean needClientAuth)
503 {
504 _needClientAuth = needClientAuth;
505 }
506
507
508 public void setPassword(String password)
509 {
510 _password = Password.getPassword(PASSWORD_PROPERTY,password,null);
511 }
512
513
514 public void setTrustPassword(String password)
515 {
516 _trustPassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
517 }
518
519
520 public void setProtocol(String protocol)
521 {
522 _protocol = protocol;
523 }
524
525
526 public void setProvider(String _provider) {
527 this._provider = _provider;
528 }
529
530
531 public void setSecureRandomAlgorithm(String algorithm)
532 {
533 this._secureRandomAlgorithm = algorithm;
534 }
535
536
537 public void setSslKeyManagerFactoryAlgorithm(String algorithm)
538 {
539 this._sslKeyManagerFactoryAlgorithm = algorithm;
540 }
541
542
543 public void setSslTrustManagerFactoryAlgorithm(String algorithm)
544 {
545 this._sslTrustManagerFactoryAlgorithm = algorithm;
546 }
547
548
549 public void setTruststore(String truststore)
550 {
551 _truststore = truststore;
552 }
553
554
555 public void setTruststoreType(String truststoreType)
556 {
557 _truststoreType = truststoreType;
558 }
559
560
561
562
563
564
565
566
567
568 public void setWantClientAuth(boolean wantClientAuth)
569 {
570 _wantClientAuth = wantClientAuth;
571 }
572
573
574
575
576
577
578 public void setHandshakeTimeout (int msec)
579 {
580 _handshakeTimeout = msec;
581 }
582
583
584 public int getHandshakeTimeout ()
585 {
586 return _handshakeTimeout;
587 }
588
589
590
591
592 private class CachedInfo
593 {
594 private X509Certificate[] _certs;
595 private Integer _keySize;
596
597 CachedInfo(Integer keySize, X509Certificate[] certs)
598 {
599 this._keySize = keySize;
600 this._certs = certs;
601 }
602
603 X509Certificate[] getCerts()
604 {
605 return _certs;
606 }
607
608 Integer getKeySize()
609 {
610 return _keySize;
611 }
612 }
613
614
615 public class SslConnection extends Connection
616 {
617 public SslConnection(Socket socket) throws IOException
618 {
619 super(socket);
620 }
621
622 public void run()
623 {
624 try
625 {
626 int handshakeTimeout = getHandshakeTimeout();
627 int oldTimeout = _socket.getSoTimeout();
628 if (handshakeTimeout > 0)
629 _socket.setSoTimeout(handshakeTimeout);
630
631 ((SSLSocket)_socket).startHandshake();
632
633 if (handshakeTimeout>0)
634 _socket.setSoTimeout(oldTimeout);
635
636 super.run();
637 }
638 catch (SSLException e)
639 {
640 Log.warn(e);
641 try{close();}
642 catch(IOException e2){Log.ignore(e2);}
643 }
644 catch (IOException e)
645 {
646 Log.debug(e);
647 try{close();}
648 catch(IOException e2){Log.ignore(e2);}
649 }
650 }
651 }
652
653 }