1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.server.ssl;
15
16 import java.io.ByteArrayInputStream;
17 import java.io.File;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.net.InetAddress;
21 import java.net.ServerSocket;
22 import java.net.Socket;
23 import java.net.SocketAddress;
24 import java.security.KeyStore;
25 import java.security.SecureRandom;
26 import java.security.Security;
27 import java.security.cert.X509Certificate;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Iterator;
31 import java.util.List;
32
33 import javax.net.ssl.KeyManager;
34 import javax.net.ssl.KeyManagerFactory;
35 import javax.net.ssl.SSLContext;
36 import javax.net.ssl.SSLException;
37 import javax.net.ssl.SSLPeerUnverifiedException;
38 import javax.net.ssl.SSLServerSocket;
39 import javax.net.ssl.SSLServerSocketFactory;
40 import javax.net.ssl.SSLSession;
41 import javax.net.ssl.SSLSocket;
42 import javax.net.ssl.TrustManager;
43 import javax.net.ssl.TrustManagerFactory;
44
45 import org.eclipse.jetty.http.HttpSchemes;
46 import org.eclipse.jetty.http.security.Password;
47 import org.eclipse.jetty.io.EndPoint;
48 import org.eclipse.jetty.io.bio.SocketEndPoint;
49 import org.eclipse.jetty.server.Request;
50 import org.eclipse.jetty.server.bio.SocketConnector;
51 import org.eclipse.jetty.util.TypeUtil;
52 import org.eclipse.jetty.util.log.Log;
53 import org.eclipse.jetty.util.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
135 private String _excludeCipherSuites[] = null;
136
137
138 private String _keystore=DEFAULT_KEYSTORE ;
139 private String _keystoreType = "JKS";
140
141
142 private boolean _needClientAuth = false;
143 private transient Password _password;
144 private transient Password _keyPassword;
145 private transient Password _trustPassword;
146 private String _protocol= "TLS";
147 private String _provider;
148 private String _secureRandomAlgorithm;
149 private String _sslKeyManagerFactoryAlgorithm = (Security.getProperty("ssl.KeyManagerFactory.algorithm")==null?"SunX509":Security.getProperty("ssl.KeyManagerFactory.algorithm"));
150 private String _sslTrustManagerFactoryAlgorithm = (Security.getProperty("ssl.TrustManagerFactory.algorithm")==null?"SunX509":Security.getProperty("ssl.TrustManagerFactory.algorithm"));
151
152 private String _truststore;
153 private String _truststoreType = "JKS";
154
155
156 private boolean _wantClientAuth = false;
157 private int _handshakeTimeout = 0;
158
159 private SSLContext _context;
160
161
162
163
164
165
166 public SslSocketConnector()
167 {
168 super();
169 }
170
171
172
173 public void accept(int acceptorID)
174 throws IOException, InterruptedException
175 {
176 Socket socket = _serverSocket.accept();
177 configure(socket);
178
179 Connection connection=new SslConnection(socket);
180 connection.dispatch();
181 }
182
183
184 protected void configure(Socket socket)
185 throws IOException
186 {
187 super.configure(socket);
188 }
189
190
191 protected SSLServerSocketFactory createFactory()
192 throws Exception
193 {
194 SSLContext context = _context;
195 if (context == null) {
196 if (_truststore==null)
197 {
198 _truststore=_keystore;
199 _truststoreType=_keystoreType;
200 }
201
202 KeyManager[] keyManagers = null;
203 InputStream keystoreInputStream = null;
204 if (_keystore != null)
205 keystoreInputStream = Resource.newResource(_keystore).getInputStream();
206 KeyStore keyStore = KeyStore.getInstance(_keystoreType);
207 keyStore.load(keystoreInputStream, _password==null?null:_password.toString().toCharArray());
208
209 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_sslKeyManagerFactoryAlgorithm);
210 keyManagerFactory.init(keyStore,_keyPassword==null?null:_keyPassword.toString().toCharArray());
211 keyManagers = keyManagerFactory.getKeyManagers();
212
213 TrustManager[] trustManagers = null;
214 InputStream truststoreInputStream = null;
215 if (_truststore != null)
216 truststoreInputStream = Resource.newResource(_truststore).getInputStream();
217 KeyStore trustStore = KeyStore.getInstance(_truststoreType);
218 trustStore.load(truststoreInputStream,_trustPassword==null?null:_trustPassword.toString().toCharArray());
219
220 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_sslTrustManagerFactoryAlgorithm);
221 trustManagerFactory.init(trustStore);
222 trustManagers = trustManagerFactory.getTrustManagers();
223
224
225 SecureRandom secureRandom = _secureRandomAlgorithm==null?null:SecureRandom.getInstance(_secureRandomAlgorithm);
226
227 context = _provider==null?SSLContext.getInstance(_protocol):SSLContext.getInstance(_protocol, _provider);
228
229 context.init(keyManagers, trustManagers, secureRandom);
230 }
231
232 return context.getServerSocketFactory();
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255 public void customize(EndPoint endpoint, Request request)
256 throws IOException
257 {
258 super.customize(endpoint, request);
259 request.setScheme(HttpSchemes.HTTPS);
260
261 SocketEndPoint socket_end_point = (SocketEndPoint)endpoint;
262 SSLSocket sslSocket = (SSLSocket)socket_end_point.getTransport();
263
264 try
265 {
266 SSLSession sslSession = sslSocket.getSession();
267 String cipherSuite = sslSession.getCipherSuite();
268 Integer keySize;
269 String idStr;
270 X509Certificate[] certs;
271
272 CachedInfo cachedInfo = (CachedInfo) sslSession.getValue(CACHED_INFO_ATTR);
273 if (cachedInfo != null)
274 {
275 keySize = cachedInfo.getKeySize();
276 certs = cachedInfo.getCerts();
277 idStr = cachedInfo.getIdStr();
278 }
279 else
280 {
281 keySize = new Integer(ServletSSL.deduceKeyLength(cipherSuite));
282 certs = getCertChain(sslSession);
283 byte[] idBytes = sslSession.getId();
284 idStr = TypeUtil.toHexString(idBytes);
285 cachedInfo = new CachedInfo(keySize, certs,idStr);
286 sslSession.putValue(CACHED_INFO_ATTR, cachedInfo);
287 }
288
289 if (certs != null)
290 request.setAttribute("javax.servlet.request.X509Certificate", certs);
291 else if (_needClientAuth)
292 throw new IllegalStateException("no client auth");
293
294 request.setAttribute("javax.servlet.request.ssl_session_id", idStr);
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 public void setSslContext(SSLContext sslContext)
560 {
561 _context = sslContext;
562 }
563
564
565
566
567
568
569
570
571
572 public void setWantClientAuth(boolean wantClientAuth)
573 {
574 _wantClientAuth = wantClientAuth;
575 }
576
577
578
579
580
581
582 public void setHandshakeTimeout (int msec)
583 {
584 _handshakeTimeout = msec;
585 }
586
587
588 public int getHandshakeTimeout ()
589 {
590 return _handshakeTimeout;
591 }
592
593
594
595
596 private class CachedInfo
597 {
598 private final X509Certificate[] _certs;
599 private final Integer _keySize;
600 private final String _idStr;
601
602
603 CachedInfo(Integer keySize, X509Certificate[] certs,String id)
604 {
605 this._keySize = keySize;
606 this._certs = certs;
607 this._idStr = id;
608 }
609
610 X509Certificate[] getCerts()
611 {
612 return _certs;
613 }
614
615 Integer getKeySize()
616 {
617 return _keySize;
618 }
619
620 String getIdStr ()
621 {
622 return _idStr;
623 }
624 }
625
626
627 public class SslConnection extends Connection
628 {
629 public SslConnection(Socket socket) throws IOException
630 {
631 super(socket);
632 }
633
634 public void run()
635 {
636 try
637 {
638 int handshakeTimeout = getHandshakeTimeout();
639 int oldTimeout = _socket.getSoTimeout();
640 if (handshakeTimeout > 0)
641 _socket.setSoTimeout(handshakeTimeout);
642
643 ((SSLSocket)_socket).startHandshake();
644
645 if (handshakeTimeout>0)
646 _socket.setSoTimeout(oldTimeout);
647
648 super.run();
649 }
650 catch (SSLException e)
651 {
652 Log.debug(e);
653 try{close();}
654 catch(IOException e2){Log.ignore(e2);}
655 }
656 catch (IOException e)
657 {
658 Log.debug(e);
659 try{close();}
660 catch(IOException e2){Log.ignore(e2);}
661 }
662 }
663 }
664
665 }