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