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