1 /*
2 * JBoss, Home of Professional Open Source.
3 * Copyright 2014 Red Hat, Inc., and individual contributors
4 * as indicated by the @author tags.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 package io.undertow.servlet.handlers.security;
20
21 import java.io.ByteArrayInputStream;
22 import java.security.cert.X509Certificate;
23 import javax.servlet.ServletRequest;
24
25 import io.undertow.server.HttpHandler;
26 import io.undertow.server.HttpServerExchange;
27 import io.undertow.server.SSLSessionInfo;
28 import io.undertow.servlet.handlers.ServletRequestContext;
29
30 /**
31 * Handler that associates SSL metadata with request
32 * <p>
33 * cipher suite - javax.servlet.request.cipher_suite String
34 * bit size of the algorithm - javax.servlet.request.key_size Integer
35 * SSL session id - javax.servlet.request.ssl_session_id String
36 *
37 * @author <a href="mailto:tomaz.cerar@redhat.com">Tomaz Cerar</a> (c) 2013 Red Hat Inc.
38 */
39 public class SSLInformationAssociationHandler implements HttpHandler {
40 private final HttpHandler next;
41
42 public SSLInformationAssociationHandler(final HttpHandler next) {
43 this.next = next;
44 }
45
46 /**
47 * Given the name of a TLS/SSL cipher suite, return an int representing it effective stream
48 * cipher key strength. i.e. How much entropy material is in the key material being fed into the
49 * encryption routines.
50 * <p>
51 * http://www.thesprawl.org/research/tls-and-ssl-cipher-suites/
52 * </p>
53 *
54 * @param cipherSuite String name of the TLS cipher suite.
55 * @return int indicating the effective key entropy bit-length.
56 */
57 public static int getKeyLength(String cipherSuite) {
58 // Roughly ordered from most common to least common.
59 if (cipherSuite == null) {
60 return 0;
61 } else if (cipherSuite.contains("WITH_AES_256_")) {
62 return 256;
63 } else if (cipherSuite.contains("WITH_RC4_128_")) {
64 return 128;
65 } else if (cipherSuite.contains("WITH_AES_128_")) {
66 return 128;
67 } else if (cipherSuite.contains("WITH_RC4_40_")) {
68 return 40;
69 } else if (cipherSuite.contains("WITH_3DES_EDE_CBC_")) {
70 return 168;
71 } else if (cipherSuite.contains("WITH_IDEA_CBC_")) {
72 return 128;
73 } else if (cipherSuite.contains("WITH_RC2_CBC_40_")) {
74 return 40;
75 } else if (cipherSuite.contains("WITH_DES40_CBC_")) {
76 return 40;
77 } else if (cipherSuite.contains("WITH_DES_CBC_")) {
78 return 56;
79 } else {
80 return 0;
81 }
82 }
83
84
85 /* ------------------------------------------------------------ */
86
87 /**
88 * Return the chain of X509 certificates used to negotiate the SSL Session.
89 * <p>
90 * We convert JSSE's javax.security.cert.X509Certificate[] to servlet's java.security.cert.X509Certificate[]
91 *
92 * @param session the javax.net.ssl.SSLSession to use as the source of the cert chain.
93 * @return the chain of java.security.cert.X509Certificates used to
94 * negotiate the SSL connection. <br>
95 * Will be null if the chain is missing or empty.
96 */
97 private X509Certificate[] getCerts(SSLSessionInfo session) {
98 try {
99 javax.security.cert.X509Certificate[] javaxCerts = session.getPeerCertificateChain();
100 if (javaxCerts == null || javaxCerts.length == 0) {
101 return null;
102 }
103 X509Certificate[] javaCerts = new X509Certificate[javaxCerts.length];
104 java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509");
105 for (int i = 0; i < javaxCerts.length; i++) {
106 byte[] bytes = javaxCerts[i].getEncoded();
107 ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
108 javaCerts[i] = (X509Certificate) cf.generateCertificate(stream);
109 }
110
111 return javaCerts;
112 } catch (Exception e) {
113 return null;
114 }
115 }
116
117 @Override
118 public void handleRequest(HttpServerExchange exchange) throws Exception {
119 ServletRequest request = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getServletRequest();
120 SSLSessionInfo ssl = exchange.getConnection().getSslSessionInfo();
121 if (ssl != null) {
122 String cipherSuite = ssl.getCipherSuite();
123 request.setAttribute("javax.servlet.request.cipher_suite", cipherSuite);
124 request.setAttribute("javax.servlet.request.key_size", getKeyLength(cipherSuite));
125 request.setAttribute("javax.servlet.request.ssl_session_id", ssl.getSessionId());
126 X509Certificate[] certs = getCerts(ssl);
127 if (certs != null) {
128 request.setAttribute("javax.servlet.request.X509Certificate", certs);
129 }
130
131 }
132 next.handleRequest(exchange);
133 }
134
135 }
136