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