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