Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / crypto / tls_internal.c
index 64124d8..704751d 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * TLS interface functions and an internal TLS implementation
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  *
  * This file interface functions for hostapd/wpa_supplicant to use the
  * integrated TLSv1 implementation.
@@ -34,6 +28,7 @@ struct tls_global {
 struct tls_connection {
        struct tlsv1_client *client;
        struct tlsv1_server *server;
+       struct tls_global *global;
 };
 
 
@@ -91,6 +86,7 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
        conn = os_zalloc(sizeof(*conn));
        if (conn == NULL)
                return NULL;
+       conn->global = global;
 
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
        if (!global->server) {
@@ -115,6 +111,28 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags)
+{
+       if (conn->server)
+               tlsv1_server_set_test_flags(conn->server, flags);
+}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void tls_connection_set_log_cb(struct tls_connection *conn,
+                              void (*log_cb)(void *ctx, const char *msg),
+                              void *ctx)
+{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+       if (conn->server)
+               tlsv1_server_set_log_cb(conn->server, log_cb, ctx);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+}
+
+
 void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
 {
        if (conn == NULL)
@@ -172,6 +190,36 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
        if (cred == NULL)
                return -1;
 
+       if (params->subject_match) {
+               wpa_printf(MSG_INFO, "TLS: subject_match not supported");
+               tlsv1_cred_free(cred);
+               return -1;
+       }
+
+       if (params->altsubject_match) {
+               wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
+               tlsv1_cred_free(cred);
+               return -1;
+       }
+
+       if (params->suffix_match) {
+               wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
+               tlsv1_cred_free(cred);
+               return -1;
+       }
+
+       if (params->domain_match) {
+               wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+               tlsv1_cred_free(cred);
+               return -1;
+       }
+
+       if (params->openssl_ciphers) {
+               wpa_printf(MSG_INFO, "TLS: openssl_ciphers not supported");
+               tlsv1_cred_free(cred);
+               return -1;
+       }
+
        if (tlsv1_set_ca_cert(cred, params->ca_cert,
                              params->ca_cert_blob, params->ca_cert_blob_len,
                              params->ca_path)) {
@@ -211,6 +259,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                return -1;
        }
 
+       tlsv1_client_set_time_checks(
+               conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
+
        return 0;
 #else /* CONFIG_TLS_INTERNAL_CLIENT */
        return -1;
@@ -277,7 +328,8 @@ int tls_global_set_verify(void *tls_ctx, int check_crl)
 
 
 int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
-                             int verify_peer)
+                             int verify_peer, unsigned int flags,
+                             const u8 *session_ctx, size_t session_ctx_len)
 {
 #ifdef CONFIG_TLS_INTERNAL_SERVER
        if (conn->server)
@@ -287,23 +339,30 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-                         int tls_ia)
+int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
+                             struct tls_random *data)
 {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+       if (conn->client)
+               return tlsv1_client_get_random(conn->client, data);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+       if (conn->server)
+               return tlsv1_server_get_random(conn->server, data);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
        return -1;
 }
 
 
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
-                           struct tls_keys *keys)
+static int tls_get_keyblock_size(struct tls_connection *conn)
 {
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
        if (conn->client)
-               return tlsv1_client_get_keys(conn->client, keys);
+               return tlsv1_client_get_keyblock_size(conn->client);
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
        if (conn->server)
-               return tlsv1_server_get_keys(conn->server, keys);
+               return tlsv1_server_get_keyblock_size(conn->server);
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
        return -1;
 }
@@ -311,23 +370,41 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
 
 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
                       const char *label, int server_random_first,
-                      u8 *out, size_t out_len)
-{
+                      int skip_keyblock, u8 *out, size_t out_len)
+{
+       int ret = -1, skip = 0;
+       u8 *tmp_out = NULL;
+       u8 *_out = out;
+
+       if (skip_keyblock) {
+               skip = tls_get_keyblock_size(conn);
+               if (skip < 0)
+                       return -1;
+               tmp_out = os_malloc(skip + out_len);
+               if (!tmp_out)
+                       return -1;
+               _out = tmp_out;
+       }
+
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
        if (conn->client) {
-               return tlsv1_client_prf(conn->client, label,
-                                       server_random_first,
-                                       out, out_len);
+               ret = tlsv1_client_prf(conn->client, label,
+                                      server_random_first,
+                                      _out, out_len);
        }
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
        if (conn->server) {
-               return tlsv1_server_prf(conn->server, label,
-                                       server_random_first,
-                                       out, out_len);
+               ret = tlsv1_server_prf(conn->server, label,
+                                      server_random_first,
+                                      _out, out_len);
        }
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
-       return -1;
+       if (ret == 0 && skip_keyblock)
+               os_memcpy(out, _out + skip, out_len);
+       bin_clear_free(tmp_out, skip);
+
+       return ret;
 }
 
 
@@ -336,6 +413,17 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
                                         const struct wpabuf *in_data,
                                         struct wpabuf **appl_data)
 {
+       return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
+                                        NULL);
+}
+
+
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+                                         struct tls_connection *conn,
+                                         const struct wpabuf *in_data,
+                                         struct wpabuf **appl_data,
+                                         int *need_more_data)
+{
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
        u8 *res, *ad;
        size_t res_len, ad_len;
@@ -348,7 +436,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
        res = tlsv1_client_handshake(conn->client,
                                     in_data ? wpabuf_head(in_data) : NULL,
                                     in_data ? wpabuf_len(in_data) : 0,
-                                    &res_len, &ad, &ad_len);
+                                    &res_len, &ad, &ad_len, need_more_data);
        if (res == NULL)
                return NULL;
        out = wpabuf_alloc_ext_data(res, res_len);
@@ -459,23 +547,23 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
                                       struct tls_connection *conn,
                                       const struct wpabuf *in_data)
 {
+       return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
+}
+
+
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+                                       struct tls_connection *conn,
+                                       const struct wpabuf *in_data,
+                                       int *need_more_data)
+{
+       if (need_more_data)
+               *need_more_data = 0;
+
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
        if (conn->client) {
-               struct wpabuf *buf;
-               int res;
-               buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
-               if (buf == NULL)
-                       return NULL;
-               res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
-                                          wpabuf_len(in_data),
-                                          wpabuf_mhead(buf),
-                                          wpabuf_size(buf));
-               if (res < 0) {
-                       wpabuf_free(buf);
-                       return NULL;
-               }
-               wpabuf_put(buf, res);
-               return buf;
+               return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
+                                           wpabuf_len(in_data),
+                                           need_more_data);
        }
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
@@ -530,6 +618,14 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 }
 
 
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+                   char *buf, size_t buflen)
+{
+       /* TODO */
+       return -1;
+}
+
+
 int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
                   char *buf, size_t buflen)
 {
@@ -587,65 +683,51 @@ int tls_connection_get_write_alerts(void *tls_ctx,
 }
 
 
-int tls_connection_get_keyblock_size(void *tls_ctx,
-                                    struct tls_connection *conn)
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+                                        struct tls_connection *conn,
+                                        tls_session_ticket_cb cb,
+                                        void *ctx)
 {
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
-       if (conn->client)
-               return tlsv1_client_get_keyblock_size(conn->client);
+       if (conn->client) {
+               tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
+               return 0;
+       }
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
-       if (conn->server)
-               return tlsv1_server_get_keyblock_size(conn->server);
+       if (conn->server) {
+               tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
+               return 0;
+       }
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
        return -1;
 }
 
 
-unsigned int tls_capabilities(void *tls_ctx)
+int tls_get_library_version(char *buf, size_t buf_len)
 {
-       return 0;
+       return os_snprintf(buf, buf_len, "internal");
 }
 
 
-struct wpabuf * tls_connection_ia_send_phase_finished(
-       void *tls_ctx, struct tls_connection *conn, int final)
+void tls_connection_set_success_data(struct tls_connection *conn,
+                                    struct wpabuf *data)
 {
-       return NULL;
 }
 
 
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-                                          struct tls_connection *conn)
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
 {
-       return -1;
 }
 
 
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-                                          struct tls_connection *conn,
-                                          const u8 *key, size_t key_len)
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
 {
-       return -1;
+       return NULL;
 }
 
 
-int tls_connection_set_session_ticket_cb(void *tls_ctx,
-                                        struct tls_connection *conn,
-                                        tls_session_ticket_cb cb,
-                                        void *ctx)
+void tls_connection_remove_session(struct tls_connection *conn)
 {
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-       if (conn->client) {
-               tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
-               return 0;
-       }
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-       if (conn->server) {
-               tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
-               return 0;
-       }
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-       return -1;
 }