]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
TLS server: OCSP stapling
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 22 Dec 2015 15:53:45 +0000 (17:53 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 22 Dec 2015 15:53:45 +0000 (17:53 +0200)
This adds support for hostapd-as-authentication-server to be build with
the internal TLS implementation and OCSP stapling server side support.
This is more or less identical to the design used with OpenSSL, i.e.,
the cached response is read from the ocsp_stapling_response=<file> and
sent as a response if the client requests it during the TLS handshake.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/crypto/tls_internal.c
src/tls/tlsv1_cred.c
src/tls/tlsv1_cred.h
src/tls/tlsv1_server_i.h
src/tls/tlsv1_server_read.c
src/tls/tlsv1_server_write.c

index 8b90d56526b24d0351b1adb3449a035bb2cd9628..4b87b304f09536edd927a30eebc9b178178369c7 100644 (file)
@@ -331,6 +331,10 @@ int tls_global_set_params(void *tls_ctx,
                return -1;
        }
 
+       if (params->ocsp_stapling_response)
+               cred->ocsp_stapling_response =
+                       os_strdup(params->ocsp_stapling_response);
+
        return 0;
 #else /* CONFIG_TLS_INTERNAL_SERVER */
        return -1;
index 92f97c7f7f67f128ab9ddd97483fcb5fb264484d..732ed4aa19fb008c6c494da933cb50d3f5efb7ec 100644 (file)
@@ -36,6 +36,7 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred)
        crypto_private_key_free(cred->key);
        os_free(cred->dh_p);
        os_free(cred->dh_g);
+       os_free(cred->ocsp_stapling_response);
        os_free(cred);
 }
 
index b4bfe38d53bb3dbff138ef82bff8b95b3e1e6953..cbf4d39e418c82f8db9b77ccdb4499883216580d 100644 (file)
@@ -24,6 +24,8 @@ struct tlsv1_credentials {
        size_t dh_p_len;
        u8 *dh_g; /* generator */
        size_t dh_g_len;
+
+       char *ocsp_stapling_response;
 };
 
 
index 96d79b3a8ba25152e1729865300cb7e499941168..81439d15ea6dc88fa0411835a69010a7c711bc05 100644 (file)
@@ -55,6 +55,7 @@ struct tlsv1_server {
        void *log_cb_ctx;
 
        int use_session_ticket;
+       unsigned int status_request:1;
 
        u8 *dh_secret;
        size_t dh_secret_len;
index 8347d7accd6d8a41e35404ae280540efd8e9227d..5109b60716e46e4acf7e2b330ac4553c311bd396 100644 (file)
@@ -267,6 +267,8 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
                                                  ext_len);
                                        conn->session_ticket_len = ext_len;
                                }
+                       } else if (ext_type == TLS_EXT_STATUS_REQUEST) {
+                               conn->status_request = 1;
                        }
 
                        pos += ext_len;
index e7c5e2254e6d2c0e04df2573b4e80ff6a046498e..dafe3f970d8a10f170efd673444e0f8af75223fa 100644 (file)
@@ -42,7 +42,7 @@ static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
 static int tls_write_server_hello(struct tlsv1_server *conn,
                                  u8 **msgpos, u8 *end)
 {
-       u8 *pos, *rhdr, *hs_start, *hs_length;
+       u8 *pos, *rhdr, *hs_start, *hs_length, *ext_start;
        struct os_time now;
        size_t rlen;
 
@@ -97,6 +97,20 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
        /* CompressionMethod compression_method */
        *pos++ = TLS_COMPRESSION_NULL;
 
+       /* Extension */
+       ext_start = pos;
+       pos += 2;
+
+       if (conn->status_request) {
+               /* Add a status_request extension with empty extension_data */
+               /* ExtensionsType extension_type = status_request(5) */
+               WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
+               pos += 2;
+               /* opaque extension_data<0..2^16-1> length */
+               WPA_PUT_BE16(pos, 0);
+               pos += 2;
+       }
+
        if (conn->session_ticket && conn->session_ticket_cb) {
                int res = conn->session_ticket_cb(
                        conn->session_ticket_cb_ctx,
@@ -133,6 +147,11 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
                 */
        }
 
+       if (pos == ext_start + 2)
+               pos -= 2; /* no extensions */
+       else
+               WPA_PUT_BE16(ext_start, pos - ext_start - 2);
+
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
        tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
@@ -244,6 +263,85 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
 }
 
 
+static int tls_write_server_certificate_status(struct tlsv1_server *conn,
+                                              u8 **msgpos, u8 *end)
+{
+       u8 *pos, *rhdr, *hs_start, *hs_length;
+       char *resp;
+       size_t rlen, len;
+
+       if (!conn->status_request)
+               return 0; /* Client did not request certificate status */
+       if (!conn->cred->ocsp_stapling_response)
+               return 0; /* No cached OCSP stapling response */
+       resp = os_readfile(conn->cred->ocsp_stapling_response, &len);
+       if (!resp)
+               return 0; /* No cached OCSP stapling response */
+
+       pos = *msgpos;
+       if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + len >
+           (unsigned int) (end - pos)) {
+               tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                  TLS_ALERT_INTERNAL_ERROR);
+               os_free(resp);
+               return -1;
+       }
+
+       tlsv1_server_log(conn, "Send CertificateStatus");
+       rhdr = pos;
+       pos += TLS_RECORD_HEADER_LEN;
+
+       /* opaque fragment[TLSPlaintext.length] */
+
+       /* Handshake */
+       hs_start = pos;
+       /* HandshakeType msg_type */
+       *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS;
+       /* uint24 length (to be filled) */
+       hs_length = pos;
+       pos += 3;
+
+       /* body - CertificateStatus
+        *
+        * struct {
+        *     CertificateStatusType status_type;
+        *     select (status_type) {
+        *         case ocsp: OCSPResponse;
+        *     } response;
+        * } CertificateStatus;
+        *
+        * opaque OCSPResponse<1..2^24-1>;
+        */
+
+       /* CertificateStatusType status_type */
+       *pos++ = 1; /* ocsp(1) */
+       /* uint24 length of OCSPResponse */
+       WPA_PUT_BE24(pos, len);
+       pos += 3;
+       os_memcpy(pos, resp, len);
+       os_free(resp);
+       pos += len;
+
+       WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+       if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+                             rhdr, end - rhdr, hs_start, pos - hs_start,
+                             &rlen) < 0) {
+               wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+               tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                  TLS_ALERT_INTERNAL_ERROR);
+               return -1;
+       }
+       pos = rhdr + rlen;
+
+       tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+       *msgpos = pos;
+
+       return 0;
+}
+
+
 static int tls_write_server_key_exchange(struct tlsv1_server *conn,
                                         u8 **msgpos, u8 *end)
 {
@@ -814,6 +912,16 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
        *out_len = 0;
 
        msglen = 1000 + tls_server_cert_chain_der_len(conn);
+       if (conn->status_request && conn->cred->ocsp_stapling_response) {
+               char *resp;
+               size_t len;
+
+               resp = os_readfile(conn->cred->ocsp_stapling_response, &len);
+               if (resp) {
+                       msglen += 10 + len;
+                       os_free(resp);
+               }
+       }
 
        msg = os_malloc(msglen);
        if (msg == NULL)
@@ -844,6 +952,7 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
 
        /* Full handshake */
        if (tls_write_server_certificate(conn, &pos, end) < 0 ||
+           tls_write_server_certificate_status(conn, &pos, end) < 0 ||
            tls_write_server_key_exchange(conn, &pos, end) < 0 ||
            tls_write_server_certificate_request(conn, &pos, end) < 0 ||
            tls_write_server_hello_done(conn, &pos, end) < 0) {