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