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