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 8b90d56..4b87b30 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 92f97c7..732ed4a 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 b4bfe38..cbf4d39 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 96d79b3..81439d1 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 8347d7a..5109b60 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 e7c5e22..dafe3f9 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) {