1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.server;
20
21 import java.security.cert.X509Certificate;
22
23 import javax.net.ssl.SSLContext;
24 import javax.net.ssl.SSLEngine;
25 import javax.net.ssl.SSLSession;
26 import javax.servlet.ServletRequest;
27
28 import org.eclipse.jetty.http.BadMessageException;
29 import org.eclipse.jetty.http.HttpScheme;
30 import org.eclipse.jetty.io.ssl.SslConnection;
31 import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
32 import org.eclipse.jetty.util.TypeUtil;
33 import org.eclipse.jetty.util.log.Log;
34 import org.eclipse.jetty.util.log.Logger;
35 import org.eclipse.jetty.util.ssl.SniX509ExtendedKeyManager;
36 import org.eclipse.jetty.util.ssl.SslContextFactory;
37 import org.eclipse.jetty.util.ssl.X509;
38
39
40
41
42
43
44 public class SecureRequestCustomizer implements HttpConfiguration.Customizer
45 {
46 private static final Logger LOG = Log.getLogger(SecureRequestCustomizer.class);
47
48
49
50
51 public static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
52
53 private boolean _sniHostCheck;
54
55
56 public SecureRequestCustomizer()
57 {
58 this(true);
59 }
60
61 public SecureRequestCustomizer(boolean sniHostCheck)
62 {
63 _sniHostCheck=sniHostCheck;
64 }
65
66 @Override
67 public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
68 {
69 if (request.getHttpChannel().getEndPoint() instanceof DecryptedEndPoint)
70 {
71 request.setScheme(HttpScheme.HTTPS.asString());
72 request.setSecure(true);
73 SslConnection.DecryptedEndPoint ssl_endp = (DecryptedEndPoint)request.getHttpChannel().getEndPoint();
74 SslConnection sslConnection = ssl_endp.getSslConnection();
75 SSLEngine sslEngine=sslConnection.getSSLEngine();
76 customize(sslEngine,request);
77 }
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 public void customize(SSLEngine sslEngine, Request request)
103 {
104 request.setScheme(HttpScheme.HTTPS.asString());
105 SSLSession sslSession = sslEngine.getSession();
106
107 if (_sniHostCheck)
108 {
109 String name = request.getServerName();
110 X509 x509 = (X509)sslSession.getValue(SniX509ExtendedKeyManager.SNI_X509);
111
112 if (x509!=null && !x509.matches(name))
113 {
114 LOG.warn("Host {} does not match SNI {}",name,x509);
115 throw new BadMessageException(400,"Host does not match SNI");
116 }
117
118 if (LOG.isDebugEnabled())
119 LOG.debug("Host {} matched SNI {}",name,x509);
120 }
121
122 try
123 {
124 String cipherSuite=sslSession.getCipherSuite();
125 Integer keySize;
126 X509Certificate[] certs;
127 String idStr;
128
129 CachedInfo cachedInfo=(CachedInfo)sslSession.getValue(CACHED_INFO_ATTR);
130 if (cachedInfo!=null)
131 {
132 keySize=cachedInfo.getKeySize();
133 certs=cachedInfo.getCerts();
134 idStr=cachedInfo.getIdStr();
135 }
136 else
137 {
138 keySize=SslContextFactory.deduceKeyLength(cipherSuite);
139 certs=SslContextFactory.getCertChain(sslSession);
140 byte[] bytes = sslSession.getId();
141 idStr = TypeUtil.toHexString(bytes);
142 cachedInfo=new CachedInfo(keySize,certs,idStr);
143 sslSession.putValue(CACHED_INFO_ATTR,cachedInfo);
144 }
145
146 if (certs!=null)
147 request.setAttribute("javax.servlet.request.X509Certificate",certs);
148
149 request.setAttribute("javax.servlet.request.cipher_suite",cipherSuite);
150 request.setAttribute("javax.servlet.request.key_size",keySize);
151 request.setAttribute("javax.servlet.request.ssl_session_id", idStr);
152 }
153 catch (Exception e)
154 {
155 LOG.warn(Log.EXCEPTION,e);
156 }
157 }
158
159 @Override
160 public String toString()
161 {
162 return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
163 }
164
165
166
167
168
169 private static class CachedInfo
170 {
171 private final X509Certificate[] _certs;
172 private final Integer _keySize;
173 private final String _idStr;
174
175 CachedInfo(Integer keySize, X509Certificate[] certs,String idStr)
176 {
177 this._keySize=keySize;
178 this._certs=certs;
179 this._idStr=idStr;
180 }
181
182 X509Certificate[] getCerts()
183 {
184 return _certs;
185 }
186
187 Integer getKeySize()
188 {
189 return _keySize;
190 }
191
192 String getIdStr()
193 {
194 return _idStr;
195 }
196 }
197 }