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