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.IOException;
18 import java.io.InputStream;
19 import java.nio.channels.SelectionKey;
20 import java.nio.channels.SocketChannel;
21 import java.security.KeyStore;
22 import java.security.SecureRandom;
23 import java.security.cert.X509Certificate;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.List;
27
28 import javax.net.ssl.KeyManager;
29 import javax.net.ssl.KeyManagerFactory;
30 import javax.net.ssl.SSLContext;
31 import javax.net.ssl.SSLEngine;
32 import javax.net.ssl.SSLPeerUnverifiedException;
33 import javax.net.ssl.SSLSession;
34 import javax.net.ssl.SSLSocket;
35 import javax.net.ssl.TrustManager;
36 import javax.net.ssl.TrustManagerFactory;
37
38 import org.eclipse.jetty.http.HttpParser;
39 import org.eclipse.jetty.http.HttpSchemes;
40 import org.eclipse.jetty.http.security.Password;
41 import org.eclipse.jetty.http.ssl.SslSelectChannelEndPoint;
42 import org.eclipse.jetty.io.Buffer;
43 import org.eclipse.jetty.io.Buffers;
44 import org.eclipse.jetty.io.Connection;
45 import org.eclipse.jetty.io.EndPoint;
46 import org.eclipse.jetty.io.ThreadLocalBuffers;
47 import org.eclipse.jetty.io.bio.SocketEndPoint;
48 import org.eclipse.jetty.io.nio.DirectNIOBuffer;
49 import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
50 import org.eclipse.jetty.io.nio.SelectorManager.SelectSet;
51 import org.eclipse.jetty.server.HttpConnection;
52 import org.eclipse.jetty.server.Request;
53 import org.eclipse.jetty.server.nio.SelectChannelConnector;
54 import org.eclipse.jetty.util.TypeUtil;
55 import org.eclipse.jetty.util.log.Log;
56 import org.eclipse.jetty.util.resource.Resource;
57
58
59
60
61
62
63
64
65
66
67 public class SslSelectChannelConnector extends SelectChannelConnector implements SslConnector
68 {
69
70
71
72
73 static final String CACHED_INFO_ATTR=CachedInfo.class.getName();
74
75
76 private String _excludeCipherSuites[]=null;
77
78
79 private String _keystorePath=DEFAULT_KEYSTORE;
80 private String _keystoreType="JKS";
81
82
83 private boolean _needClientAuth=false;
84 private boolean _wantClientAuth=false;
85
86 private transient Password _password;
87 private transient Password _keyPassword;
88 private transient Password _trustPassword;
89 private String _protocol="TLS";
90 private String _provider;
91 private String _secureRandomAlgorithm;
92 private String _sslKeyManagerFactoryAlgorithm="SunX509";
93 private String _sslTrustManagerFactoryAlgorithm="SunX509";
94 private String _truststorePath;
95 private String _truststoreType="JKS";
96 private SSLContext _context;
97 Buffers _sslBuffers;
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 private static X509Certificate[] getCertChain(SSLSession sslSession)
115 {
116 try
117 {
118 javax.security.cert.X509Certificate javaxCerts[]=sslSession.getPeerCertificateChain();
119 if (javaxCerts==null||javaxCerts.length==0)
120 return null;
121
122 int length=javaxCerts.length;
123 X509Certificate[] javaCerts=new X509Certificate[length];
124
125 java.security.cert.CertificateFactory cf=java.security.cert.CertificateFactory.getInstance("X.509");
126 for (int i=0; i<length; i++)
127 {
128 byte bytes[]=javaxCerts[i].getEncoded();
129 ByteArrayInputStream stream=new ByteArrayInputStream(bytes);
130 javaCerts[i]=(X509Certificate)cf.generateCertificate(stream);
131 }
132
133 return javaCerts;
134 }
135 catch (SSLPeerUnverifiedException pue)
136 {
137 return null;
138 }
139 catch (Exception e)
140 {
141 Log.warn(Log.EXCEPTION,e);
142 return null;
143 }
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173 @Override
174 public void customize(EndPoint endpoint, Request request) throws IOException
175 {
176 super.customize(endpoint,request);
177 request.setScheme(HttpSchemes.HTTPS);
178
179 SslSelectChannelEndPoint sslHttpChannelEndpoint=(SslSelectChannelEndPoint)endpoint;
180
181 SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine();
182
183 try
184 {
185 SSLSession sslSession=sslEngine.getSession();
186 String cipherSuite=sslSession.getCipherSuite();
187 Integer keySize;
188 X509Certificate[] certs;
189 String idStr;
190
191 CachedInfo cachedInfo=(CachedInfo)sslSession.getValue(CACHED_INFO_ATTR);
192 if (cachedInfo!=null)
193 {
194 keySize=cachedInfo.getKeySize();
195 certs=cachedInfo.getCerts();
196 idStr=cachedInfo.getIdStr();
197 }
198 else
199 {
200 keySize=new Integer(ServletSSL.deduceKeyLength(cipherSuite));
201 certs=getCertChain(sslSession);
202 byte[] bytes = sslSession.getId();
203 idStr = TypeUtil.toHexString(bytes);
204 cachedInfo=new CachedInfo(keySize,certs,idStr);
205 sslSession.putValue(CACHED_INFO_ATTR,cachedInfo);
206 }
207
208 if (certs!=null)
209 request.setAttribute("javax.servlet.request.X509Certificate",certs);
210
211 request.setAttribute("javax.servlet.request.cipher_suite",cipherSuite);
212 request.setAttribute("javax.servlet.request.key_size",keySize);
213 request.setAttribute("javax.servlet.request.ssl_session_id", idStr);
214 }
215 catch (Exception e)
216 {
217 Log.warn(Log.EXCEPTION,e);
218 }
219 }
220
221
222 public SslSelectChannelConnector()
223 {
224 }
225
226
227
228
229
230 public String[] getExcludeCipherSuites()
231 {
232 return _excludeCipherSuites;
233 }
234
235
236
237
238
239 public void setExcludeCipherSuites(String[] cipherSuites)
240 {
241 this._excludeCipherSuites=cipherSuites;
242 }
243
244
245
246
247
248 public void setPassword(String password)
249 {
250 _password=Password.getPassword(PASSWORD_PROPERTY,password,null);
251 }
252
253
254
255
256
257 public void setTrustPassword(String password)
258 {
259 _trustPassword=Password.getPassword(PASSWORD_PROPERTY,password,null);
260 }
261
262
263
264
265
266 public void setKeyPassword(String password)
267 {
268 _keyPassword=Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
269 }
270
271
272
273
274
275
276 public String getAlgorithm()
277 {
278 return getSslKeyManagerFactoryAlgorithm();
279 }
280
281
282
283
284
285
286 public void setAlgorithm(String algorithm)
287 {
288 setSslKeyManagerFactoryAlgorithm(algorithm);
289 setSslTrustManagerFactoryAlgorithm(algorithm);
290 }
291
292
293
294
295
296 public String getProtocol()
297 {
298 return _protocol;
299 }
300
301
302
303
304
305 public void setProtocol(String protocol)
306 {
307 _protocol=protocol;
308 }
309
310
311
312
313
314 public void setKeystore(String keystore)
315 {
316 _keystorePath=keystore;
317 }
318
319
320
321
322
323 public String getKeystore()
324 {
325 return _keystorePath;
326 }
327
328
329
330
331
332 public String getKeystoreType()
333 {
334 return (_keystoreType);
335 }
336
337
338
339
340
341 public boolean getNeedClientAuth()
342 {
343 return _needClientAuth;
344 }
345
346
347
348
349
350 public boolean getWantClientAuth()
351 {
352 return _wantClientAuth;
353 }
354
355
356
357
358
359 public void setNeedClientAuth(boolean needClientAuth)
360 {
361 _needClientAuth=needClientAuth;
362 }
363
364
365
366
367
368 public void setWantClientAuth(boolean wantClientAuth)
369 {
370 _wantClientAuth=wantClientAuth;
371 }
372
373
374
375
376
377 public void setKeystoreType(String keystoreType)
378 {
379 _keystoreType=keystoreType;
380 }
381
382
383
384
385
386 public String getProvider()
387 {
388 return _provider;
389 }
390
391
392
393
394
395 public String getSecureRandomAlgorithm()
396 {
397 return (this._secureRandomAlgorithm);
398 }
399
400
401
402
403
404 public String getSslKeyManagerFactoryAlgorithm()
405 {
406 return (this._sslKeyManagerFactoryAlgorithm);
407 }
408
409
410
411
412
413 public String getSslTrustManagerFactoryAlgorithm()
414 {
415 return (this._sslTrustManagerFactoryAlgorithm);
416 }
417
418
419
420
421
422 public String getTruststore()
423 {
424 return _truststorePath;
425 }
426
427
428
429
430
431 public String getTruststoreType()
432 {
433 return _truststoreType;
434 }
435
436
437
438
439
440 public void setProvider(String provider)
441 {
442 _provider=provider;
443 }
444
445
446
447
448
449 public void setSecureRandomAlgorithm(String algorithm)
450 {
451 this._secureRandomAlgorithm=algorithm;
452 }
453
454
455
456
457
458 public void setSslKeyManagerFactoryAlgorithm(String algorithm)
459 {
460 this._sslKeyManagerFactoryAlgorithm=algorithm;
461 }
462
463
464
465
466
467 public void setSslTrustManagerFactoryAlgorithm(String algorithm)
468 {
469 this._sslTrustManagerFactoryAlgorithm=algorithm;
470 }
471
472
473
474
475
476 public void setTruststore(String truststore)
477 {
478 _truststorePath=truststore;
479 }
480
481
482
483
484
485 public void setTruststoreType(String truststoreType)
486 {
487 _truststoreType=truststoreType;
488 }
489
490
491
492
493
494 public void setSslContext(SSLContext sslContext)
495 {
496 _context = sslContext;
497 }
498
499
500
501
502
503
504 public SSLContext getSslContext()
505 {
506 try
507 {
508 if (_context == null)
509 _context=createSSLContext();
510 }
511 catch(Exception e)
512 {
513 throw new RuntimeException(e);
514 }
515
516 return _context;
517 }
518
519
520
521
522
523
524
525
526
527
528 public boolean isConfidential(Request request)
529 {
530 final int confidentialPort=getConfidentialPort();
531 return confidentialPort==0||confidentialPort==request.getServerPort();
532 }
533
534
535
536
537
538
539
540
541
542
543 public boolean isIntegral(Request request)
544 {
545 final int integralPort=getIntegralPort();
546 return integralPort==0||integralPort==request.getServerPort();
547 }
548
549
550 protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
551 {
552 return new SslSelectChannelEndPoint(_sslBuffers,channel,selectSet,key,createSSLEngine());
553 }
554
555
556 protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint)
557 {
558 HttpConnection connection=(HttpConnection)super.newConnection(channel,endpoint);
559 ((HttpParser)connection.getParser()).setForceContentBuffer(true);
560 return connection;
561 }
562
563
564 protected SSLEngine createSSLEngine() throws IOException
565 {
566 SSLEngine engine=null;
567 try
568 {
569 engine=_context.createSSLEngine();
570 engine.setUseClientMode(false);
571
572 if (_wantClientAuth)
573 engine.setWantClientAuth(_wantClientAuth);
574 if (_needClientAuth)
575 engine.setNeedClientAuth(_needClientAuth);
576
577 if (_excludeCipherSuites!=null&&_excludeCipherSuites.length>0)
578 {
579 List<String> excludedCSList=Arrays.asList(_excludeCipherSuites);
580 String[] enabledCipherSuites=engine.getEnabledCipherSuites();
581 List<String> enabledCSList=new ArrayList<String>(Arrays.asList(enabledCipherSuites));
582
583 for (String cipherName : excludedCSList)
584 {
585 if (enabledCSList.contains(cipherName))
586 {
587 enabledCSList.remove(cipherName);
588 }
589 }
590 enabledCipherSuites=enabledCSList.toArray(new String[enabledCSList.size()]);
591
592 engine.setEnabledCipherSuites(enabledCipherSuites);
593 }
594
595 }
596 catch (Exception e)
597 {
598 Log.warn("Error creating sslEngine -- closing this connector",e);
599 close();
600 throw new IllegalStateException(e);
601 }
602 return engine;
603 }
604
605
606 protected void doStart() throws Exception
607 {
608 if (_context == null)
609 _context=createSSLContext();
610
611 SSLEngine engine=createSSLEngine();
612 SSLSession ssl_session=engine.getSession();
613
614 ThreadLocalBuffers buffers = new ThreadLocalBuffers()
615 {
616 @Override
617 protected Buffer newBuffer(int size)
618 {
619
620 return new DirectNIOBuffer(size);
621 }
622 @Override
623 protected Buffer newHeader(int size)
624 {
625
626 return new DirectNIOBuffer(size);
627 }
628 @Override
629 protected boolean isHeader(Buffer buffer)
630 {
631 return true;
632 }
633 };
634 buffers.setBufferSize(ssl_session.getApplicationBufferSize());
635 buffers.setHeaderSize(ssl_session.getApplicationBufferSize());
636 _sslBuffers=buffers;
637
638 if (getRequestHeaderSize()<ssl_session.getApplicationBufferSize())
639 setRequestHeaderSize(ssl_session.getApplicationBufferSize());
640 if (getRequestBufferSize()<ssl_session.getApplicationBufferSize())
641 setRequestBufferSize(ssl_session.getApplicationBufferSize());
642
643 super.doStart();
644 }
645
646
647 protected SSLContext createSSLContext() throws Exception
648 {
649 KeyManager[] keyManagers=getKeyManagers();
650
651 TrustManager[] trustManagers=getTrustManagers();
652
653 SecureRandom secureRandom=_secureRandomAlgorithm==null?null:SecureRandom.getInstance(_secureRandomAlgorithm);
654 SSLContext context=_provider==null?SSLContext.getInstance(_protocol):SSLContext.getInstance(_protocol,_provider);
655 context.init(keyManagers,trustManagers,secureRandom);
656 return context;
657 }
658
659
660 protected KeyManager[] getKeyManagers() throws Exception
661 {
662 KeyStore keyStore = getKeyStore(_keystorePath, _keystoreType, _password==null?null:_password.toString());
663
664 KeyManagerFactory keyManagerFactory=KeyManagerFactory.getInstance(_sslKeyManagerFactoryAlgorithm);
665 keyManagerFactory.init(keyStore,_keyPassword==null?(_password==null?null:_password.toString().toCharArray()):_keyPassword.toString().toCharArray());
666 return keyManagerFactory.getKeyManagers();
667 }
668
669
670 protected TrustManager[] getTrustManagers() throws Exception
671 {
672 if (_truststorePath==null)
673 {
674 _truststorePath=_keystorePath;
675 _truststoreType=_keystoreType;
676 _trustPassword = _password;
677 _sslTrustManagerFactoryAlgorithm = _sslKeyManagerFactoryAlgorithm;
678 }
679
680 KeyStore trustStore = getKeyStore(_truststorePath, _truststoreType, _trustPassword==null?null:_trustPassword.toString());
681
682 TrustManagerFactory trustManagerFactory=TrustManagerFactory.getInstance(_sslTrustManagerFactoryAlgorithm);
683 trustManagerFactory.init(trustStore);
684 return trustManagerFactory.getTrustManagers();
685 }
686
687
688 protected KeyStore getKeyStore(String keystorePath, String keystoreType, String keystorePassword) throws Exception
689 {
690 KeyStore keystore;
691 InputStream keystoreInputStream = null;
692 try
693 {
694 if (keystorePath!=null)
695 keystoreInputStream = Resource.newResource(keystorePath).getInputStream();
696 keystore=KeyStore.getInstance(keystoreType);
697 keystore.load(keystoreInputStream,keystorePassword==null?null:keystorePassword.toString().toCharArray());
698 return keystore;
699 }
700 finally
701 {
702 if (keystoreInputStream != null)
703 keystoreInputStream.close();
704 }
705 }
706
707
708
709
710
711
712
713
714 private class CachedInfo
715 {
716 private final X509Certificate[] _certs;
717 private final Integer _keySize;
718 private final String _idStr;
719
720 CachedInfo(Integer keySize, X509Certificate[] certs,String idStr)
721 {
722 this._keySize=keySize;
723 this._certs=certs;
724 this._idStr=idStr;
725 }
726
727 X509Certificate[] getCerts()
728 {
729 return _certs;
730 }
731
732 Integer getKeySize()
733 {
734 return _keySize;
735 }
736
737 String getIdStr()
738 {
739 return _idStr;
740 }
741 }
742
743 }