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