Browse Source

Merge branch 'feature/internal_tls_code_update' into 'master'

wpa_supplicant: sync eap code with upstream

See merge request espressif/esp-idf!16962
Kapil Gupta 4 years ago
parent
commit
72e53d116a
52 changed files with 5808 additions and 4579 deletions
  1. 13 6
      components/wpa_supplicant/CMakeLists.txt
  2. 13 0
      components/wpa_supplicant/Kconfig
  3. 1 1
      components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c
  4. 94 39
      components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-rsa.c
  5. 133 27
      components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls.c
  6. 3 3
      components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c
  7. 2 2
      components/wpa_supplicant/esp_supplicant/src/esp_wpa2.c
  8. 4 4
      components/wpa_supplicant/include/utils/wpa_debug.h
  9. 6 3
      components/wpa_supplicant/port/include/os.h
  10. 0 8
      components/wpa_supplicant/port/include/supplicant_opt.h
  11. 1 1
      components/wpa_supplicant/port/os_xtensa.c
  12. 2 0
      components/wpa_supplicant/src/crypto/crypto_internal.c
  13. 1 1
      components/wpa_supplicant/src/crypto/crypto_ops.c
  14. 0 3441
      components/wpa_supplicant/src/crypto/libtommath.h
  15. 1 0
      components/wpa_supplicant/src/crypto/sha384.h
  16. 167 27
      components/wpa_supplicant/src/crypto/tls.h
  17. 177 24
      components/wpa_supplicant/src/crypto/tls_internal.c
  18. 2 4
      components/wpa_supplicant/src/eap_peer/eap.c
  19. 1 1
      components/wpa_supplicant/src/eap_peer/eap_fast.c
  20. 1 1
      components/wpa_supplicant/src/eap_peer/eap_fast_common.c
  21. 1 1
      components/wpa_supplicant/src/eap_peer/eap_mschapv2.c
  22. 1 1
      components/wpa_supplicant/src/eap_peer/eap_peap.c
  23. 1 1
      components/wpa_supplicant/src/eap_peer/eap_tls.c
  24. 1 1
      components/wpa_supplicant/src/eap_peer/eap_tls_common.c
  25. 1 1
      components/wpa_supplicant/src/eap_peer/eap_ttls.c
  26. 457 13
      components/wpa_supplicant/src/tls/asn1.c
  27. 149 3
      components/wpa_supplicant/src/tls/asn1.h
  28. 2 8
      components/wpa_supplicant/src/tls/bignum.h
  29. 168 24
      components/wpa_supplicant/src/tls/pkcs1.c
  30. 7 0
      components/wpa_supplicant/src/tls/pkcs1.h
  31. 431 39
      components/wpa_supplicant/src/tls/pkcs5.c
  32. 28 46
      components/wpa_supplicant/src/tls/pkcs8.c
  33. 6 15
      components/wpa_supplicant/src/tls/rsa.c
  34. 155 84
      components/wpa_supplicant/src/tls/tlsv1_client.c
  35. 11 2
      components/wpa_supplicant/src/tls/tlsv1_client.h
  36. 20 2
      components/wpa_supplicant/src/tls/tlsv1_client_i.h
  37. 759 0
      components/wpa_supplicant/src/tls/tlsv1_client_ocsp.c
  38. 557 44
      components/wpa_supplicant/src/tls/tlsv1_client_read.c
  39. 152 53
      components/wpa_supplicant/src/tls/tlsv1_client_write.c
  40. 35 29
      components/wpa_supplicant/src/tls/tlsv1_common.c
  41. 2 1
      components/wpa_supplicant/src/tls/tlsv1_common.h
  42. 751 41
      components/wpa_supplicant/src/tls/tlsv1_cred.c
  43. 8 0
      components/wpa_supplicant/src/tls/tlsv1_cred.h
  44. 27 33
      components/wpa_supplicant/src/tls/tlsv1_record.c
  45. 276 69
      components/wpa_supplicant/src/tls/tlsv1_server.c
  46. 11 1
      components/wpa_supplicant/src/tls/tlsv1_server.h
  47. 18 0
      components/wpa_supplicant/src/tls/tlsv1_server_i.h
  48. 278 246
      components/wpa_supplicant/src/tls/tlsv1_server_read.c
  49. 339 49
      components/wpa_supplicant/src/tls/tlsv1_server_write.c
  50. 491 177
      components/wpa_supplicant/src/tls/x509v3.c
  51. 42 1
      components/wpa_supplicant/src/tls/x509v3.h
  52. 1 1
      examples/wifi/wifi_eap_fast/sdkconfig.defaults

+ 13 - 6
components/wpa_supplicant/CMakeLists.txt

@@ -66,7 +66,7 @@ if(CONFIG_ESP_WIFI_SOFTAP_SUPPORT)
     set(esp_srcs ${esp_srcs} "esp_supplicant/src/esp_hostap.c")
     set(esp_srcs ${esp_srcs} "esp_supplicant/src/esp_hostap.c")
 endif()
 endif()
 
 
-if(CONFIG_WPA_MBEDTLS_CRYPTO)
+if(CONFIG_WPA_MBEDTLS_TLS_CLIENT)
     set(tls_src "esp_supplicant/src/crypto/tls_mbedtls.c")
     set(tls_src "esp_supplicant/src/crypto/tls_mbedtls.c")
 else()
 else()
     set(tls_src
     set(tls_src
@@ -77,16 +77,14 @@ else()
     "src/tls/pkcs8.c"
     "src/tls/pkcs8.c"
     "src/tls/bignum.c"
     "src/tls/bignum.c"
     "src/tls/rsa.c"
     "src/tls/rsa.c"
-    "src/tls/tls_internal.c"
+    "src/crypto/tls_internal.c"
     "src/tls/tlsv1_client.c"
     "src/tls/tlsv1_client.c"
     "src/tls/tlsv1_client_read.c"
     "src/tls/tlsv1_client_read.c"
     "src/tls/tlsv1_client_write.c"
     "src/tls/tlsv1_client_write.c"
     "src/tls/tlsv1_common.c"
     "src/tls/tlsv1_common.c"
     "src/tls/tlsv1_cred.c"
     "src/tls/tlsv1_cred.c"
     "src/tls/tlsv1_record.c"
     "src/tls/tlsv1_record.c"
-    "src/tls/tlsv1_server.c"
-    "src/tls/tlsv1_server_read.c"
-    "src/tls/tlsv1_server_write.c"
+    "src/tls/tlsv1_client_ocsp.c"
     "src/tls/x509v3.c")
     "src/tls/x509v3.c")
 endif()
 endif()
 
 
@@ -94,6 +92,7 @@ if(CONFIG_WPA_MBEDTLS_CRYPTO)
     set(crypto_src
     set(crypto_src
     "esp_supplicant/src/crypto/crypto_mbedtls.c"
     "esp_supplicant/src/crypto/crypto_mbedtls.c"
     "esp_supplicant/src/crypto/crypto_mbedtls-bignum.c"
     "esp_supplicant/src/crypto/crypto_mbedtls-bignum.c"
+    "esp_supplicant/src/crypto/crypto_mbedtls-rsa.c"
     "esp_supplicant/src/crypto/crypto_mbedtls-ec.c")
     "esp_supplicant/src/crypto/crypto_mbedtls-ec.c")
     # Add internal RC4 if RC4 is disabled in mbedtls
     # Add internal RC4 if RC4 is disabled in mbedtls
     if(CONFIG_MBEDTLS_RC4_DISABLED)
     if(CONFIG_MBEDTLS_RC4_DISABLED)
@@ -193,7 +192,6 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
     EAP_TTLS
     EAP_TTLS
     EAP_TLS
     EAP_TLS
     EAP_PEAP
     EAP_PEAP
-    EAP_FAST
     USE_WPA2_TASK
     USE_WPA2_TASK
     CONFIG_WPS2
     CONFIG_WPS2
     CONFIG_WPS_PIN
     CONFIG_WPS_PIN
@@ -235,4 +233,13 @@ endif()
 if(CONFIG_WPA_11R_SUPPORT)
 if(CONFIG_WPA_11R_SUPPORT)
     target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_IEEE80211R)
     target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_IEEE80211R)
 endif()
 endif()
+if(NOT CONFIG_WPA_MBEDTLS_TLS_CLIENT)
+    target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_TLS_INTERNAL_CLIENT
+                CONFIG_TLSV11 CONFIG_TLSV12 CONFIG_INTERNAL_SHA384 CONFIG_INTERNAL_SHA512 EAP_FAST)
+endif()
+if(CONFIG_WPA_MBEDTLS_CRYPTO)
+    target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_CRYPTO_MBEDTLS)
+else()
+    target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_CRYPTO_INTERNAL)
+endif()
 set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)
 set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)

+ 13 - 0
components/wpa_supplicant/Kconfig

@@ -11,6 +11,19 @@ menu "Supplicant"
         help
         help
             Select this option to use MbedTLS crypto APIs which utilize hardware acceleration.
             Select this option to use MbedTLS crypto APIs which utilize hardware acceleration.
 
 
+    if WPA_MBEDTLS_CRYPTO
+        config WPA_MBEDTLS_TLS_CLIENT
+            bool "Use MbedTLS TLS client for WiFi Enterprise connection"
+            default y
+            select MBEDTLS_TLS_ENABLED
+            help
+                Select this option to use MbedTLS TLS client for WPA2 enterprise connection.
+                Please note that from MbedTLS-3.0 onwards, MbedTLS does not support SSL-3.0
+                TLS-v1.0, TLS-v1.1 versions. Incase your server is using one of these version,
+                it is advisable to update your server.
+                Please disable this option for compatibilty with older TLS versions.
+    endif
+
     config WPA_WAPI_PSK
     config WPA_WAPI_PSK
         bool "Enable WAPI PSK support"
         bool "Enable WAPI PSK support"
         default n
         default n

+ 1 - 1
components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c

@@ -32,7 +32,7 @@ struct crypto_ec {
 	mbedtls_ecp_group group;
 	mbedtls_ecp_group group;
 };
 };
 
 
-int crypto_rng_wrapper(void *ctx, unsigned char *buf, size_t len)
+static int crypto_rng_wrapper(void *ctx, unsigned char *buf, size_t len)
 {
 {
 	return random_get_bytes(buf, len);
 	return random_get_bytes(buf, len);
 }
 }

+ 94 - 39
components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-rsa.c

@@ -13,7 +13,7 @@
 #include "crypto.h"
 #include "crypto.h"
 #include "common/defs.h"
 #include "common/defs.h"
 
 
-#ifdef USE_MBEDTLS_CRYPTO
+#ifdef CONFIG_CRYPTO_MBEDTLS
 #include "mbedtls/entropy.h"
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
 #include "mbedtls/ctr_drbg.h"
 
 
@@ -26,6 +26,7 @@
 struct crypto_public_key;
 struct crypto_public_key;
 struct crypto_private_key;
 struct crypto_private_key;
 
 
+#ifdef DEBUG_PRINT
 static void crypto_dump_verify_info(u32 flags)
 static void crypto_dump_verify_info(u32 flags)
 {
 {
 	char dump_buffer[1024];
 	char dump_buffer[1024];
@@ -33,6 +34,14 @@ static void crypto_dump_verify_info(u32 flags)
 	mbedtls_x509_crt_verify_info(dump_buffer, 1024, "  ! ", flags );
 	mbedtls_x509_crt_verify_info(dump_buffer, 1024, "  ! ", flags );
 	wpa_printf(MSG_ERROR, "%s", dump_buffer);
 	wpa_printf(MSG_ERROR, "%s", dump_buffer);
 }
 }
+#else
+static void crypto_dump_verify_info(u32 flags) { }
+#endif
+
+static int crypto_rng_wrapper(void *ctx, unsigned char *buf, size_t len)
+{
+	return os_get_random(buf, len);
+}
 
 
 int crypto_verify_cert(const u8 *cert_start, int certlen, const u8 *ca_cert_start, int ca_certlen)
 int crypto_verify_cert(const u8 *cert_start, int certlen, const u8 *ca_cert_start, int ca_certlen)
 {
 {
@@ -110,7 +119,8 @@ struct crypto_private_key *  crypto_private_key_import(const u8 *key,
 
 
 	mbedtls_pk_init(pkey);
 	mbedtls_pk_init(pkey);
 
 
-	ret = mbedtls_pk_parse_key(pkey, key, len, (const unsigned char *)passwd, passwd ? os_strlen(passwd) : 0);
+	ret = mbedtls_pk_parse_key(pkey, key, len, (const unsigned char *)passwd,
+			passwd ? os_strlen(passwd) : 0, crypto_rng_wrapper, NULL);
 
 
 	if (ret < 0) {
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "failed to parse private key");
 		wpa_printf(MSG_ERROR, "failed to parse private key");
@@ -201,13 +211,13 @@ int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
 	}
 	}
 
 
 	ret = mbedtls_rsa_pkcs1_encrypt(mbedtls_pk_rsa(*pkey), mbedtls_ctr_drbg_random,
 	ret = mbedtls_rsa_pkcs1_encrypt(mbedtls_pk_rsa(*pkey), mbedtls_ctr_drbg_random,
-			ctr_drbg, MBEDTLS_RSA_PUBLIC, inlen, in, out);
+					ctr_drbg, inlen, in, out);
 
 
 	if(ret != 0) {
 	if(ret != 0) {
 		wpa_printf(MSG_ERROR, " failed  !  mbedtls_rsa_pkcs1_encrypt returned -0x%04x", -ret);
 		wpa_printf(MSG_ERROR, " failed  !  mbedtls_rsa_pkcs1_encrypt returned -0x%04x", -ret);
 		goto cleanup;
 		goto cleanup;
 	}
 	}
-	*outlen = mbedtls_pk_rsa(*pkey)->len;
+	*outlen = mbedtls_pk_rsa(*pkey)->MBEDTLS_PRIVATE(len);
 
 
 cleanup:
 cleanup:
 	mbedtls_ctr_drbg_free( ctr_drbg );
 	mbedtls_ctr_drbg_free( ctr_drbg );
@@ -246,9 +256,9 @@ int  crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
 	if (ret < 0)
 	if (ret < 0)
 		goto cleanup;
 		goto cleanup;
 
 
-	i =  mbedtls_pk_rsa(*pkey)->len;
+	i =  mbedtls_pk_rsa(*pkey)->MBEDTLS_PRIVATE(len);
 	ret = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(mbedtls_pk_rsa(*pkey), mbedtls_ctr_drbg_random,
 	ret = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(mbedtls_pk_rsa(*pkey), mbedtls_ctr_drbg_random,
-			ctr_drbg, MBEDTLS_RSA_PRIVATE, &i, in, out, *outlen);
+			ctr_drbg, &i, in, out, *outlen);
 
 
 	*outlen = i;
 	*outlen = i;
 
 
@@ -267,17 +277,37 @@ int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
 		u8 *out, size_t *outlen)
 		u8 *out, size_t *outlen)
 {
 {
 	int ret;
 	int ret;
+	const char *pers = "rsa_encrypt";
 	mbedtls_pk_context *pkey  = (mbedtls_pk_context *)key;
 	mbedtls_pk_context *pkey  = (mbedtls_pk_context *)key;
+	mbedtls_entropy_context *entropy = os_malloc(sizeof(*entropy));
+	mbedtls_ctr_drbg_context *ctr_drbg = os_malloc(sizeof(*ctr_drbg));
 
 
-	if((ret = mbedtls_rsa_pkcs1_sign(mbedtls_pk_rsa(*pkey), NULL, NULL, MBEDTLS_RSA_PRIVATE,
-					(mbedtls_pk_rsa(*pkey))->hash_id,
-					inlen, in, out)) != 0 ) {
-		wpa_printf(MSG_ERROR, " failed  ! mbedtls_rsa_pkcs1_sign returned %d", ret );
+	if (!pkey || !entropy || !ctr_drbg) {
+		if (entropy)
+			os_free(entropy);
+		if (ctr_drbg)
+			os_free(ctr_drbg);
 		return -1;
 		return -1;
 	}
 	}
-	*outlen = mbedtls_pk_rsa(*pkey)->len;
+	mbedtls_ctr_drbg_init( ctr_drbg );
+	mbedtls_entropy_init( entropy );
+	ret = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func,
+			entropy, (const unsigned char *) pers,
+			strlen(pers));
 
 
-	return 0;
+	if((ret = mbedtls_rsa_pkcs1_sign(mbedtls_pk_rsa(*pkey), mbedtls_ctr_drbg_random, ctr_drbg,
+					(mbedtls_pk_rsa(*pkey))->MBEDTLS_PRIVATE(hash_id),
+					inlen, in, out)) != 0 ) {
+		wpa_printf(MSG_ERROR, " failed  ! mbedtls_rsa_pkcs1_sign returned %d", ret );
+		goto cleanup;
+	}
+	*outlen = mbedtls_pk_rsa(*pkey)->MBEDTLS_PRIVATE(len);
+cleanup:
+	mbedtls_ctr_drbg_free( ctr_drbg );
+	mbedtls_entropy_free( entropy );
+	os_free(entropy);
+	os_free(ctr_drbg);
+	return ret;
 }
 }
 
 
 
 
@@ -302,44 +332,69 @@ void  crypto_private_key_free(struct crypto_private_key *key)
 	os_free(pkey);
 	os_free(pkey);
 }
 }
 
 
-
 int  crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
 int  crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
 		const u8 *crypt, size_t crypt_len,
 		const u8 *crypt, size_t crypt_len,
 		u8 *plain, size_t *plain_len)
 		u8 *plain, size_t *plain_len)
 {
 {
-	const char *pers = "rsa_decrypt";
+	size_t len;
+	u8 *pos;
 	mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
 	mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
-	mbedtls_ctr_drbg_context ctr_drbg;
-	mbedtls_entropy_context entropy;
-	size_t i;
 
 
-	mbedtls_entropy_init( &entropy );
-	mbedtls_ctr_drbg_init( &ctr_drbg );
+	len = *plain_len;
+	if (mbedtls_rsa_public(mbedtls_pk_rsa(*pkey), crypt, plain) < 0)
+		return -1;
 
 
-	int ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func,
-			&entropy, (const unsigned char *) pers,
-			strlen( pers ) );
-	if(ret != 0) {
-		wpa_printf(MSG_ERROR, " failed  ! mbedtls_ctr_drbg_seed returned %d",
-				ret );
-		goto cleanup;
+	/*
+	 * PKCS #1 v1.5, 8.1:
+	 *
+	 * EB = 00 || BT || PS || 00 || D
+	 * BT = 00 or 01
+	 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
+	 * k = length of modulus in octets
+	 *
+	 * Based on 10.1.3, "The block type shall be 01" for a signature.
+	 */
+
+	if (len < 3 + 8 + 16 /* min hash len */ ||
+	    plain[0] != 0x00 || plain[1] != 0x01) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+			   "structure");
+		wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
+		return -1;
 	}
 	}
 
 
-	i =  mbedtls_pk_rsa(*pkey)->len;
-	ret = mbedtls_rsa_pkcs1_decrypt(mbedtls_pk_rsa(*pkey), mbedtls_ctr_drbg_random,
-			&ctr_drbg, MBEDTLS_RSA_PUBLIC, &i,
-			crypt, plain, *plain_len);
-	if( ret != 0 ) {
-		wpa_printf(MSG_ERROR, " failed ! mbedtls_rsa_pkcs1_decrypt returned %d",
-				ret );
-		goto cleanup;
+	pos = plain + 3;
+	/* BT = 01 */
+	if (plain[2] != 0xff) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+			   "PS (BT=01)");
+		wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
+		return -1;
+	}
+	while (pos < plain + len && *pos == 0xff)
+		pos++;
+
+	if (pos - plain - 2 < 8) {
+		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
+		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
+			   "padding");
+		wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
+		return -1;
 	}
 	}
-	*plain_len = i;
 
 
-cleanup:
-	mbedtls_entropy_free( &entropy );
-	mbedtls_ctr_drbg_free( &ctr_drbg );
+	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+			   "structure (2)");
+		wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
+		return -1;
+	}
+	pos++;
+	len -= pos - plain;
 
 
-	return ret;
+	/* Strip PKCS #1 header */
+	os_memmove(plain, pos, len);
+	*plain_len = len;
+
+	return 0;
 }
 }
 #endif
 #endif

+ 133 - 27
components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls.c

@@ -28,9 +28,10 @@
 #include "common.h"
 #include "common.h"
 #include "utils/wpabuf.h"
 #include "utils/wpabuf.h"
 #include "dh_group5.h"
 #include "dh_group5.h"
+#include "md5.h"
 #include "sha1.h"
 #include "sha1.h"
 #include "sha256.h"
 #include "sha256.h"
-#include "md5.h"
+#include "sha384.h"
 #include "aes_wrap.h"
 #include "aes_wrap.h"
 #include "crypto.h"
 #include "crypto.h"
 #include "mbedtls/esp_config.h"
 #include "mbedtls/esp_config.h"
@@ -95,6 +96,12 @@ int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 	return digest_vector(MBEDTLS_MD_SHA384, num_elem, addr, len, mac);
 	return digest_vector(MBEDTLS_MD_SHA384, num_elem, addr, len, mac);
 }
 }
 
 
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	return digest_vector(MBEDTLS_MD_SHA512, num_elem, addr, len, mac);
+}
+
 int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
 {
 	return digest_vector(MBEDTLS_MD_SHA1, num_elem, addr, len, mac);
 	return digest_vector(MBEDTLS_MD_SHA1, num_elem, addr, len, mac);
@@ -122,21 +129,41 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 	struct crypto_hash *ctx;
 	struct crypto_hash *ctx;
 	mbedtls_md_type_t md_type;
 	mbedtls_md_type_t md_type;
 	const mbedtls_md_info_t *md_info;
 	const mbedtls_md_info_t *md_info;
+	int ret;
+	int is_hmac = 0;
 
 
 	switch (alg) {
 	switch (alg) {
-		case CRYPTO_HASH_ALG_HMAC_MD5:
-			md_type = MBEDTLS_MD_MD5;
-			break;
-		case CRYPTO_HASH_ALG_HMAC_SHA1:
-			md_type = MBEDTLS_MD_SHA1;
-			break;
-		case CRYPTO_HASH_ALG_HMAC_SHA256:
-			md_type = MBEDTLS_MD_SHA256;
-			break;
-		default:
-			return NULL;
+	case CRYPTO_HASH_ALG_MD5:
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		md_type = MBEDTLS_MD_MD5;
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		md_type = MBEDTLS_MD_SHA1;
+		break;
+	case CRYPTO_HASH_ALG_SHA256:
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		md_type = MBEDTLS_MD_SHA256;
+		break;
+	case CRYPTO_HASH_ALG_SHA384:
+		md_type = MBEDTLS_MD_SHA384;
+		break;
+	case CRYPTO_HASH_ALG_SHA512:
+		md_type = MBEDTLS_MD_SHA512;
+		break;
+	default:
+		return NULL;
 	}
 	}
 
 
+	switch (alg) {
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		is_hmac = 1;
+		break;
+	default:
+		break;
+	}
 	ctx = os_zalloc(sizeof(*ctx));
 	ctx = os_zalloc(sizeof(*ctx));
 	if (ctx == NULL) {
 	if (ctx == NULL) {
 		return NULL;
 		return NULL;
@@ -153,6 +180,15 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 	if (mbedtls_md_hmac_starts(&ctx->ctx, key, key_len) != 0) {
 	if (mbedtls_md_hmac_starts(&ctx->ctx, key, key_len) != 0) {
 		goto cleanup;
 		goto cleanup;
 	}
 	}
+	if (is_hmac) {
+		ret = mbedtls_md_hmac_starts(&ctx->ctx, key, key_len);
+	} else {
+		ret = mbedtls_md_starts(&ctx->ctx);
+	}
+	if (ret < 0) {
+		goto cleanup;
+	}
+
 	return ctx;
 	return ctx;
 cleanup:
 cleanup:
 	os_free(ctx);
 	os_free(ctx);
@@ -166,7 +202,11 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
 	if (ctx == NULL) {
 	if (ctx == NULL) {
 		return;
 		return;
 	}
 	}
-	ret = mbedtls_md_hmac_update(&ctx->ctx, data, len);
+	if (ctx->ctx.MBEDTLS_PRIVATE(hmac_ctx)) {
+		ret = mbedtls_md_hmac_update(&ctx->ctx, data, len);
+	} else {
+		ret = mbedtls_md_update(&ctx->ctx, data, len);
+	}
 	if (ret != 0) {
 	if (ret != 0) {
 		wpa_printf(MSG_ERROR, "%s: mbedtls_md_hmac_update failed", __func__);
 		wpa_printf(MSG_ERROR, "%s: mbedtls_md_hmac_update failed", __func__);
 	}
 	}
@@ -174,18 +214,70 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
 
 
 int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
 int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
 {
 {
-	int ret;
+	int ret = 0;
+	mbedtls_md_type_t md_type;
 
 
 	if (ctx == NULL) {
 	if (ctx == NULL) {
 		return -2;
 		return -2;
 	}
 	}
 
 
 	if (mac == NULL || len == NULL) {
 	if (mac == NULL || len == NULL) {
-		mbedtls_md_free(&ctx->ctx);
-		bin_clear_free(ctx, sizeof(*ctx));
-		return 0;
+		goto err;
+	}
+	md_type = mbedtls_md_get_type(ctx->ctx.MBEDTLS_PRIVATE(md_info));
+	switch(md_type) {
+	case MBEDTLS_MD_MD5:
+		if (*len < MD5_MAC_LEN) {
+			*len = MD5_MAC_LEN;
+			ret = -1;
+			goto err;
+		}
+		*len = MD5_MAC_LEN;
+		break;
+	case MBEDTLS_MD_SHA1:
+		if (*len < SHA1_MAC_LEN) {
+			*len = SHA1_MAC_LEN;
+			ret = -1;
+			goto err;
+		}
+		*len = SHA1_MAC_LEN;
+		break;
+	case MBEDTLS_MD_SHA256:
+		if (*len < SHA256_MAC_LEN) {
+			*len = SHA256_MAC_LEN;
+			ret = -1;
+			goto err;
+		}
+		*len = SHA256_MAC_LEN;
+		break;
+	case MBEDTLS_MD_SHA384:
+		if (*len < SHA384_MAC_LEN) {
+			*len = SHA384_MAC_LEN;
+			ret = -1;
+			goto err;
+		}
+		*len = SHA384_MAC_LEN;
+		break;
+	case MBEDTLS_MD_SHA512:
+		if (*len < SHA512_MAC_LEN) {
+			*len = SHA512_MAC_LEN;
+			ret = -1;
+			goto err;
+		}
+		*len = SHA512_MAC_LEN;
+		break;
+	default:
+		*len = 0;
+		ret = -1;
+		goto err;
+	}
+	if (ctx->ctx.MBEDTLS_PRIVATE(hmac_ctx)) {
+		ret = mbedtls_md_hmac_finish(&ctx->ctx, mac);
+	} else {
+		ret = mbedtls_md_finish(&ctx->ctx, mac);
 	}
 	}
-	ret = mbedtls_md_hmac_finish(&ctx->ctx, mac);
+
+err:
 	mbedtls_md_free(&ctx->ctx);
 	mbedtls_md_free(&ctx->ctx);
 	bin_clear_free(ctx, sizeof(*ctx));
 	bin_clear_free(ctx, sizeof(*ctx));
 
 
@@ -398,6 +490,7 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
 
 
 }
 }
 
 
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
 struct crypto_cipher {
 struct crypto_cipher {
 	mbedtls_cipher_context_t ctx_enc;
 	mbedtls_cipher_context_t ctx_enc;
 	mbedtls_cipher_context_t ctx_dec;
 	mbedtls_cipher_context_t ctx_dec;
@@ -405,7 +498,7 @@ struct crypto_cipher {
 
 
 static int crypto_init_cipher_ctx(mbedtls_cipher_context_t *ctx,
 static int crypto_init_cipher_ctx(mbedtls_cipher_context_t *ctx,
 				  const mbedtls_cipher_info_t *cipher_info,
 				  const mbedtls_cipher_info_t *cipher_info,
-				  const u8 *iv, const u8 *key,
+				  const u8 *iv, const u8 *key, size_t key_len,
 				  mbedtls_operation_t operation)
 				  mbedtls_operation_t operation)
 {
 {
 	mbedtls_cipher_init(ctx);
 	mbedtls_cipher_init(ctx);
@@ -416,8 +509,7 @@ static int crypto_init_cipher_ctx(mbedtls_cipher_context_t *ctx,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (mbedtls_cipher_setkey(ctx, key, cipher_info->MBEDTLS_PRIVATE(key_bitlen),
-				 operation) != 0) {
+	if (mbedtls_cipher_setkey(ctx, key, key_len * 8, operation) != 0) {
 		wpa_printf(MSG_ERROR, "mbedtls_cipher_setkey returned error");
 		wpa_printf(MSG_ERROR, "mbedtls_cipher_setkey returned error");
 		return -1;
 		return -1;
 	}
 	}
@@ -490,15 +582,21 @@ struct crypto_cipher *crypto_cipher_init(enum crypto_cipher_alg alg,
 
 
 	/* Init both ctx encryption/decryption */
 	/* Init both ctx encryption/decryption */
 	if (crypto_init_cipher_ctx(&ctx->ctx_enc, cipher_info, iv, key,
 	if (crypto_init_cipher_ctx(&ctx->ctx_enc, cipher_info, iv, key,
-				   MBEDTLS_ENCRYPT) < 0) {
+				   key_len, MBEDTLS_ENCRYPT) < 0) {
 		goto cleanup;
 		goto cleanup;
 	}
 	}
 
 
 	if (crypto_init_cipher_ctx(&ctx->ctx_dec, cipher_info, iv, key,
 	if (crypto_init_cipher_ctx(&ctx->ctx_dec, cipher_info, iv, key,
-				   MBEDTLS_DECRYPT) < 0) {
+				   key_len, MBEDTLS_DECRYPT) < 0) {
 		goto cleanup;
 		goto cleanup;
 	}
 	}
 
 
+	if (mbedtls_cipher_set_padding_mode(&ctx->ctx_enc, MBEDTLS_PADDING_NONE) < 0) {
+		goto cleanup;
+	}
+	if (mbedtls_cipher_set_padding_mode(&ctx->ctx_dec, MBEDTLS_PADDING_NONE) < 0) {
+		goto cleanup;
+	}
 	return ctx;
 	return ctx;
 
 
 cleanup:
 cleanup:
@@ -506,12 +604,11 @@ cleanup:
 	return NULL;
 	return NULL;
 }
 }
 
 
-#if 0
 int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
 int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
 			  u8 *crypt, size_t len)
 			  u8 *crypt, size_t len)
 {
 {
 	int ret;
 	int ret;
-	size_t olen = 1200;
+	size_t olen = 0;
 
 
 	ret = mbedtls_cipher_update(&ctx->ctx_enc, plain, len, crypt, &olen);
 	ret = mbedtls_cipher_update(&ctx->ctx_enc, plain, len, crypt, &olen);
 	if (ret != 0) {
 	if (ret != 0) {
@@ -530,7 +627,7 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
 			  u8 *plain, size_t len)
 			  u8 *plain, size_t len)
 {
 {
 	int ret;
 	int ret;
-	size_t olen = 1200;
+	size_t olen = 0;
 
 
 	ret = mbedtls_cipher_update(&ctx->ctx_dec, crypt, len, plain, &olen);
 	ret = mbedtls_cipher_update(&ctx->ctx_dec, crypt, len, plain, &olen);
 	if (ret != 0) {
 	if (ret != 0) {
@@ -544,7 +641,6 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
 
 
 	return 0;
 	return 0;
 }
 }
-#endif
 
 
 void crypto_cipher_deinit(struct crypto_cipher *ctx)
 void crypto_cipher_deinit(struct crypto_cipher *ctx)
 {
 {
@@ -552,6 +648,7 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx)
 	mbedtls_cipher_free(&ctx->ctx_dec);
 	mbedtls_cipher_free(&ctx->ctx_dec);
 	os_free(ctx);
 	os_free(ctx);
 }
 }
+#endif
 
 
 int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
 int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
 		    u8 *data, size_t data_len)
 		    u8 *data, size_t data_len)
@@ -909,3 +1006,12 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
 
 
 	return 0;
 	return 0;
 }
 }
+
+int crypto_global_init(void)
+{
+	return 0;
+}
+
+void crypto_global_deinit(void)
+{
+}

+ 3 - 3
components/wpa_supplicant/esp_supplicant/src/crypto/tls_mbedtls.c

@@ -7,7 +7,7 @@
 #include "utils/includes.h"
 #include "utils/includes.h"
 #include "utils/common.h"
 #include "utils/common.h"
 
 
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
 #include "crypto/md5.h"
 #include "crypto/md5.h"
 #include "crypto/sha256.h"
 #include "crypto/sha256.h"
@@ -608,7 +608,7 @@ exit:
 	return ret;
 	return ret;
 }
 }
 
 
-void *tls_init()
+void *tls_init(const struct tls_config *conf)
 {
 {
 	tls_instance_count++;
 	tls_instance_count++;
 	return &tls_instance_count;
 	return &tls_instance_count;
@@ -660,7 +660,7 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
 	return 0;
 	return 0;
 }
 }
 
 
-int tls_global_set_verify(void *tls_ctx, int check_crl)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
 {
 {
 	wpa_printf(MSG_INFO, "TLS: global settings are not supported");
 	wpa_printf(MSG_INFO, "TLS: global settings are not supported");
 	return -1;
 	return -1;

+ 2 - 2
components/wpa_supplicant/esp_supplicant/src/esp_wpa2.c

@@ -25,7 +25,7 @@
 #include "crypto/crypto.h"
 #include "crypto/crypto.h"
 
 
 #include "utils/ext_password.h"
 #include "utils/ext_password.h"
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_config.h"
 #include "eap_peer/eap_config.h"
 #include "eap_peer/eap.h"
 #include "eap_peer/eap.h"
@@ -717,7 +717,7 @@ static int eap_peer_sm_init(void)
         goto _err;
         goto _err;
     }
     }
 
 
-    sm->ssl_ctx = tls_init();
+    sm->ssl_ctx = tls_init(NULL);
     if (sm->ssl_ctx == NULL) {
     if (sm->ssl_ctx == NULL) {
         wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS context.");
         wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS context.");
         ret = ESP_FAIL;
         ret = ESP_FAIL;

+ 4 - 4
components/wpa_supplicant/include/utils/wpa_debug.h

@@ -65,12 +65,12 @@ void wpa_debug_print_timestamp(void);
 #define wpa_dbg(ctx, level, fmt, args...) wpa_printf(level, fmt, ##args)
 #define wpa_dbg(ctx, level, fmt, args...) wpa_printf(level, fmt, ##args)
 
 
 void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len);
 void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len);
-static inline void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
+static inline void wpa_hexdump_ascii(int level, const char *title, const void *buf, size_t len)
 {
 {
 
 
 }
 }
 
 
-static inline void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, size_t len)
+static inline void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, size_t len)
 {
 {
 }
 }
 
 
@@ -128,7 +128,7 @@ static inline void wpa_hexdump_buf_key(int level, const char *title,
  * the hex numbers and ASCII characters (for printable range) are shown. 16
  * the hex numbers and ASCII characters (for printable range) are shown. 16
  * bytes per line will be shown.
  * bytes per line will be shown.
  */
  */
-void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+void wpa_hexdump_ascii(int level, const char *title, const void *buf,
 		       size_t len);
 		       size_t len);
 
 
 /**
 /**
@@ -145,7 +145,7 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
  * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
  * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
  * default, does not include secret keys (passwords, etc.) in debug output.
  * default, does not include secret keys (passwords, etc.) in debug output.
  */
  */
-void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
 			   size_t len);
 			   size_t len);
 #else
 #else
 #define wpa_printf(level,fmt, args...) do {} while(0)
 #define wpa_printf(level,fmt, args...) do {} while(0)

+ 6 - 3
components/wpa_supplicant/port/include/os.h

@@ -185,7 +185,11 @@ int os_unsetenv(const char *name);
  * binary and text files can be read with this function. The caller is
  * binary and text files can be read with this function. The caller is
  * responsible for freeing the returned buffer with os_free().
  * responsible for freeing the returned buffer with os_free().
  */
  */
-char * os_readfile(const char *name, size_t *len);
+/* We don't support file reading support */
+static inline char *os_readfile(const char *name, size_t *len)
+{
+	return NULL;
+}
 
 
 /*
 /*
  * The following functions are wrapper for standard ANSI C or POSIX functions.
  * The following functions are wrapper for standard ANSI C or POSIX functions.
@@ -250,7 +254,6 @@ char * ets_strdup(const char *s);
 #define os_memcmp_const(s1, s2, n) memcmp((s1), (s2), (n))
 #define os_memcmp_const(s1, s2, n) memcmp((s1), (s2), (n))
 #endif
 #endif
 
 
-
 #ifndef os_strlen
 #ifndef os_strlen
 #define os_strlen(s) strlen(s)
 #define os_strlen(s) strlen(s)
 #endif
 #endif
@@ -316,7 +319,7 @@ static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
 	return os_realloc(ptr, nmemb * size);
 	return os_realloc(ptr, nmemb * size);
 }
 }
 
 
-#ifdef USE_MBEDTLS_CRYPTO
+#ifdef CONFIG_CRYPTO_MBEDTLS
 void forced_memzero(void *ptr, size_t len);
 void forced_memzero(void *ptr, size_t len);
 #else
 #else
 /* Try to prevent most compilers from optimizing out clearing of memory that
 /* Try to prevent most compilers from optimizing out clearing of memory that

+ 0 - 8
components/wpa_supplicant/port/include/supplicant_opt.h

@@ -9,14 +9,6 @@
 
 
 #include "sdkconfig.h"
 #include "sdkconfig.h"
 
 
-#if CONFIG_WPA_MBEDTLS_CRYPTO
-#define USE_MBEDTLS_CRYPTO 1
-#else
-#define CONFIG_TLS_INTERNAL_CLIENT
-#define CONFIG_CRYPTO_INTERNAL
-#define CONFIG_TLSV12
-#endif
-
 #if CONFIG_WPA_DEBUG_PRINT
 #if CONFIG_WPA_DEBUG_PRINT
 #define DEBUG_PRINT
 #define DEBUG_PRINT
 #endif
 #endif

+ 1 - 1
components/wpa_supplicant/port/os_xtensa.c

@@ -61,7 +61,7 @@ void os_sleep(os_time_t sec, os_time_t usec)
     }
     }
 }
 }
 
 
-#ifdef USE_MBEDTLS_CRYPTO
+#ifdef CONFIG_CRYPTO_MBEDTLS
 void forced_memzero(void *ptr, size_t len)
 void forced_memzero(void *ptr, size_t len)
 {
 {
     mbedtls_platform_zeroize(ptr, len);
     mbedtls_platform_zeroize(ptr, len);

+ 2 - 0
components/wpa_supplicant/src/crypto/crypto_internal.c

@@ -11,6 +11,8 @@
 #include "common.h"
 #include "common.h"
 #include "crypto.h"
 #include "crypto.h"
 #include "sha256_i.h"
 #include "sha256_i.h"
+#include "sha384_i.h"
+#include "sha512_i.h"
 #include "sha1_i.h"
 #include "sha1_i.h"
 #include "md5_i.h"
 #include "md5_i.h"
 
 

+ 1 - 1
components/wpa_supplicant/src/crypto/crypto_ops.c

@@ -48,7 +48,7 @@ static int esp_aes_gmac(const u8 *key, size_t key_len, const u8 *iv, size_t iv_l
 
 
 /*
 /*
  * This structure is used to set the cyrpto callback function for station to connect when in security mode.
  * This structure is used to set the cyrpto callback function for station to connect when in security mode.
- * These functions either call MbedTLS API's if USE_MBEDTLS_CRYPTO flag is set through Kconfig, or native
+ * These functions either call MbedTLS API's if CONFIG_CRYPTO_MBEDTLS flag is set through Kconfig, or native
  * API's otherwise. We recommend setting the flag since MbedTLS API's utilize hardware acceleration while
  * API's otherwise. We recommend setting the flag since MbedTLS API's utilize hardware acceleration while
  * native API's are use software implementations.
  * native API's are use software implementations.
  */
  */

+ 0 - 3441
components/wpa_supplicant/src/crypto/libtommath.h

@@ -1,3441 +0,0 @@
-/*
- * Minimal code for RSA support from LibTomMath 0.41
- * http://libtom.org/
- * http://libtom.org/files/ltm-0.41.tar.bz2
- * This library was released in public domain by Tom St Denis.
- *
- * The combination in this file may not use all of the optimized algorithms
- * from LibTomMath and may be considerable slower than the LibTomMath with its
- * default settings. The main purpose of having this version here is to make it
- * easier to build bignum.c wrapper without having to install and build an
- * external library.
- *
- * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
- * libtommath.c file instead of using the external LibTomMath library.
- */
-//#include "c_types.h"
-#include "os.h"
-#include "stdarg.h"
-
-
-#ifndef CHAR_BIT
-#define CHAR_BIT 8
-#endif
-
-#define BN_MP_INVMOD_C
-#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would
-			   * require BN_MP_EXPTMOD_FAST_C instead */
-#define BN_S_MP_MUL_DIGS_C
-#define BN_MP_INVMOD_SLOW_C
-#define BN_S_MP_SQR_C
-#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
-				 * would require other than mp_reduce */
-
-#ifdef LTM_FAST
-
-/* Use faster div at the cost of about 1 kB */
-#define BN_MP_MUL_D_C
-
-/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */
-#define BN_MP_EXPTMOD_FAST_C
-#define BN_MP_MONTGOMERY_SETUP_C
-#define BN_FAST_MP_MONTGOMERY_REDUCE_C
-#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
-#define BN_MP_MUL_2_C
-
-/* Include faster sqr at the cost of about 0.5 kB in code */
-#define BN_FAST_S_MP_SQR_C
-
-#else /* LTM_FAST */
-
-#define BN_MP_DIV_SMALL
-#define BN_MP_INIT_MULTI_C
-#define BN_MP_CLEAR_MULTI_C
-#define BN_MP_ABS_C
-#endif /* LTM_FAST */
-
-/* Current uses do not require support for negative exponent in exptmod, so we
- * can save about 1.5 kB in leaving out invmod. */
-#define LTM_NO_NEG_EXP
-
-/* from tommath.h */
-
-#ifndef MIN
-   #define MIN(x,y) ((x)<(y)?(x):(y))
-#endif
-
-#ifndef MAX
-   #define MAX(x,y) ((x)>(y)?(x):(y))
-#endif
-
-#define  OPT_CAST(x) (x *)
-
-typedef unsigned long mp_digit;
-typedef u64 mp_word;
-
-#define DIGIT_BIT          28
-#define MP_28BIT
-
-
-#define XMALLOC  os_malloc
-#define XFREE    os_free
-#define XREALLOC os_realloc
-
-
-#define MP_MASK          ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
-
-#define MP_LT        -1   /* less than */
-#define MP_EQ         0   /* equal to */
-#define MP_GT         1   /* greater than */
-
-#define MP_ZPOS       0   /* positive integer */
-#define MP_NEG        1   /* negative */
-
-#define MP_OKAY       0   /* ok result */
-#define MP_MEM        -2  /* out of mem */
-#define MP_VAL        -3  /* invalid input */
-
-#define MP_YES        1   /* yes response */
-#define MP_NO         0   /* no response */
-
-typedef int           mp_err;
-
-/* define this to use lower memory usage routines (exptmods mostly) */
-#define MP_LOW_MEM
-
-/* default precision */
-#ifndef MP_PREC
-   #ifndef MP_LOW_MEM
-      #define MP_PREC                 32     /* default digits of precision */
-   #else
-      #define MP_PREC                 8      /* default digits of precision */
-   #endif
-#endif
-
-/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
-#define MP_WARRAY               (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
-
-/* the infamous mp_int structure */
-typedef struct  {
-    int used, alloc, sign;
-    mp_digit *dp;
-} mp_int;
-
-
-/* ---> Basic Manipulations <--- */
-#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
-#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
-#define mp_isodd(a)  (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
-
-
-/* prototypes for copied functions */
-#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
-static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
-static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
-static int s_mp_sqr(mp_int * a, mp_int * b);
-static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
-
-static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
-
-#ifdef BN_MP_INIT_MULTI_C
-static int mp_init_multi(mp_int *mp, ...);
-#endif
-#ifdef BN_MP_CLEAR_MULTI_C
-static void mp_clear_multi(mp_int *mp, ...);
-#endif
-static int mp_lshd(mp_int * a, int b);
-static void mp_set(mp_int * a, mp_digit b);
-static void mp_clamp(mp_int * a);
-static void mp_exch(mp_int * a, mp_int * b);
-static void mp_rshd(mp_int * a, int b);
-static void mp_zero(mp_int * a);
-static int mp_mod_2d(mp_int * a, int b, mp_int * c);
-static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
-static int mp_init_copy(mp_int * a, mp_int * b);
-static int mp_mul_2d(mp_int * a, int b, mp_int * c);
-#ifndef LTM_NO_NEG_EXP
-static int mp_div_2(mp_int * a, mp_int * b);
-static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
-static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
-#endif /* LTM_NO_NEG_EXP */
-static int mp_copy(mp_int * a, mp_int * b);
-static int mp_count_bits(mp_int * a);
-static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
-static int mp_mod(mp_int * a, mp_int * b, mp_int * c);
-static int mp_grow(mp_int * a, int size);
-static int mp_cmp_mag(mp_int * a, mp_int * b);
-#ifdef BN_MP_ABS_C
-static int mp_abs(mp_int * a, mp_int * b);
-#endif
-static int mp_sqr(mp_int * a, mp_int * b);
-static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
-static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
-static int mp_2expt(mp_int * a, int b);
-static int mp_reduce_setup(mp_int * a, mp_int * b);
-static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
-static int mp_init_size(mp_int * a, int size);
-#ifdef BN_MP_EXPTMOD_FAST_C
-static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
-#endif /* BN_MP_EXPTMOD_FAST_C */
-#ifdef BN_FAST_S_MP_SQR_C
-static int fast_s_mp_sqr (mp_int * a, mp_int * b);
-#endif /* BN_FAST_S_MP_SQR_C */
-#ifdef BN_MP_MUL_D_C
-static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
-#endif /* BN_MP_MUL_D_C */
-
-
-
-/* functions from bn_<func name>.c */
-
-
-/* reverse an array, used for radix code */
-static void
-bn_reverse (unsigned char *s, int len)
-{
-  int     ix, iy;
-  unsigned char t;
-
-  ix = 0;
-  iy = len - 1;
-  while (ix < iy) {
-    t     = s[ix];
-    s[ix] = s[iy];
-    s[iy] = t;
-    ++ix;
-    --iy;
-  }
-}
-
-
-/* low level addition, based on HAC pp.594, Algorithm 14.7 */
-static int
-s_mp_add (mp_int * a, mp_int * b, mp_int * c)
-{
-  mp_int *x;
-  int     olduse, res, min, max;
-
-  /* find sizes, we let |a| <= |b| which means we have to sort
-   * them.  "x" will point to the input with the most digits
-   */
-  if (a->used > b->used) {
-    min = b->used;
-    max = a->used;
-    x = a;
-  } else {
-    min = a->used;
-    max = b->used;
-    x = b;
-  }
-
-  /* init result */
-  if (c->alloc < max + 1) {
-    if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* get old used digit count and set new one */
-  olduse = c->used;
-  c->used = max + 1;
-
-  {
-    register mp_digit u, *tmpa, *tmpb, *tmpc;
-    register int i;
-
-    /* alias for digit pointers */
-
-    /* first input */
-    tmpa = a->dp;
-
-    /* second input */
-    tmpb = b->dp;
-
-    /* destination */
-    tmpc = c->dp;
-
-    /* zero the carry */
-    u = 0;
-    for (i = 0; i < min; i++) {
-      /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
-      *tmpc = *tmpa++ + *tmpb++ + u;
-
-      /* U = carry bit of T[i] */
-      u = *tmpc >> ((mp_digit)DIGIT_BIT);
-
-      /* take away carry bit from T[i] */
-      *tmpc++ &= MP_MASK;
-    }
-
-    /* now copy higher words if any, that is in A+B
-     * if A or B has more digits add those in
-     */
-    if (min != max) {
-      for (; i < max; i++) {
-        /* T[i] = X[i] + U */
-        *tmpc = x->dp[i] + u;
-
-        /* U = carry bit of T[i] */
-        u = *tmpc >> ((mp_digit)DIGIT_BIT);
-
-        /* take away carry bit from T[i] */
-        *tmpc++ &= MP_MASK;
-      }
-    }
-
-    /* add carry */
-    *tmpc++ = u;
-
-    /* clear digits above oldused */
-    for (i = c->used; i < olduse; i++) {
-      *tmpc++ = 0;
-    }
-  }
-
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
-static int
-s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
-{
-  int     olduse, res, min, max;
-
-  /* find sizes */
-  min = b->used;
-  max = a->used;
-
-  /* init result */
-  if (c->alloc < max) {
-    if ((res = mp_grow (c, max)) != MP_OKAY) {
-      return res;
-    }
-  }
-  olduse = c->used;
-  c->used = max;
-
-  {
-    register mp_digit u, *tmpa, *tmpb, *tmpc;
-    register int i;
-
-    /* alias for digit pointers */
-    tmpa = a->dp;
-    tmpb = b->dp;
-    tmpc = c->dp;
-
-    /* set carry to zero */
-    u = 0;
-    for (i = 0; i < min; i++) {
-      /* T[i] = A[i] - B[i] - U */
-      *tmpc = *tmpa++ - *tmpb++ - u;
-
-      /* U = carry bit of T[i]
-       * Note this saves performing an AND operation since
-       * if a carry does occur it will propagate all the way to the
-       * MSB.  As a result a single shift is enough to get the carry
-       */
-      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
-
-      /* Clear carry from T[i] */
-      *tmpc++ &= MP_MASK;
-    }
-
-    /* now copy higher words if any, e.g. if A has more digits than B  */
-    for (; i < max; i++) {
-      /* T[i] = A[i] - U */
-      *tmpc = *tmpa++ - u;
-
-      /* U = carry bit of T[i] */
-      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
-
-      /* Clear carry from T[i] */
-      *tmpc++ &= MP_MASK;
-    }
-
-    /* clear digits above used (since we may not have grown result above) */
-    for (i = c->used; i < olduse; i++) {
-      *tmpc++ = 0;
-    }
-  }
-
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-/* init a new mp_int */
-static int
-mp_init (mp_int * a)
-{
-  int i;
-
-  /* allocate memory required and clear it */
-  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
-  if (a->dp == NULL) {
-    return MP_MEM;
-  }
-
-  /* set the digits to zero */
-  for (i = 0; i < MP_PREC; i++) {
-      a->dp[i] = 0;
-  }
-
-  /* set the used to zero, allocated digits to the default precision
-   * and sign to positive */
-  a->used  = 0;
-  a->alloc = MP_PREC;
-  a->sign  = MP_ZPOS;
-
-  return MP_OKAY;
-}
-
-
-/* clear one (frees)  */
-static void
-mp_clear (mp_int * a)
-{
-  int i;
-
-  /* only do anything if a hasn't been freed previously */
-  if (a->dp != NULL) {
-    /* first zero the digits */
-    for (i = 0; i < a->used; i++) {
-        a->dp[i] = 0;
-    }
-
-    /* free ram */
-    XFREE(a->dp);
-
-    /* reset members to make debugging easier */
-    a->dp    = NULL;
-    a->alloc = a->used = 0;
-    a->sign  = MP_ZPOS;
-  }
-}
-
-
-/* high level addition (handles signs) */
-static int
-mp_add (mp_int * a, mp_int * b, mp_int * c)
-{
-  int     sa, sb, res;
-
-  /* get sign of both inputs */
-  sa = a->sign;
-  sb = b->sign;
-
-  /* handle two cases, not four */
-  if (sa == sb) {
-    /* both positive or both negative */
-    /* add their magnitudes, copy the sign */
-    c->sign = sa;
-    res = s_mp_add (a, b, c);
-  } else {
-    /* one positive, the other negative */
-    /* subtract the one with the greater magnitude from */
-    /* the one of the lesser magnitude.  The result gets */
-    /* the sign of the one with the greater magnitude. */
-    if (mp_cmp_mag (a, b) == MP_LT) {
-      c->sign = sb;
-      res = s_mp_sub (b, a, c);
-    } else {
-      c->sign = sa;
-      res = s_mp_sub (a, b, c);
-    }
-  }
-  return res;
-}
-
-
-/* high level subtraction (handles signs) */
-static int
-mp_sub (mp_int * a, mp_int * b, mp_int * c)
-{
-  int     sa, sb, res;
-
-  sa = a->sign;
-  sb = b->sign;
-
-  if (sa != sb) {
-    /* subtract a negative from a positive, OR */
-    /* subtract a positive from a negative. */
-    /* In either case, ADD their magnitudes, */
-    /* and use the sign of the first number. */
-    c->sign = sa;
-    res = s_mp_add (a, b, c);
-  } else {
-    /* subtract a positive from a positive, OR */
-    /* subtract a negative from a negative. */
-    /* First, take the difference between their */
-    /* magnitudes, then... */
-    if (mp_cmp_mag (a, b) != MP_LT) {
-      /* Copy the sign from the first */
-      c->sign = sa;
-      /* The first has a larger or equal magnitude */
-      res = s_mp_sub (a, b, c);
-    } else {
-      /* The result has the *opposite* sign from */
-      /* the first number. */
-      c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
-      /* The second has a larger magnitude */
-      res = s_mp_sub (b, a, c);
-    }
-  }
-  return res;
-}
-
-
-/* high level multiplication (handles sign) */
-static int
-mp_mul (mp_int * a, mp_int * b, mp_int * c)
-{
-  int     res, neg;
-  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
-
-  /* use Toom-Cook? */
-#ifdef BN_MP_TOOM_MUL_C
-  if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
-    res = mp_toom_mul(a, b, c);
-  } else
-#endif
-#ifdef BN_MP_KARATSUBA_MUL_C
-  /* use Karatsuba? */
-  if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
-    res = mp_karatsuba_mul (a, b, c);
-  } else
-#endif
-  {
-    /* can we use the fast multiplier?
-     *
-     * The fast multiplier can be used if the output will
-     * have less than MP_WARRAY digits and the number of
-     * digits won't affect carry propagation
-     */
-#ifdef BN_FAST_S_MP_MUL_DIGS_C
-    int     digs = a->used + b->used + 1;
-
-    if ((digs < MP_WARRAY) &&
-        MIN(a->used, b->used) <=
-        (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
-      res = fast_s_mp_mul_digs (a, b, c, digs);
-    } else
-#endif
-#ifdef BN_S_MP_MUL_DIGS_C
-      res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
-#else
-#error mp_mul could fail
-      res = MP_VAL;
-#endif
-
-  }
-  c->sign = (c->used > 0) ? neg : MP_ZPOS;
-  return res;
-}
-
-
-/* d = a * b (mod c) */
-static int
-mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
-{
-  int     res;
-  mp_int  t;
-
-  if ((res = mp_init (&t)) != MP_OKAY) {
-    return res;
-  }
-
-  if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
-    mp_clear (&t);
-    return res;
-  }
-  res = mp_mod (&t, c, d);
-  mp_clear (&t);
-  return res;
-}
-
-
-/* c = a mod b, 0 <= c < b */
-static int
-mp_mod (mp_int * a, mp_int * b, mp_int * c)
-{
-  mp_int  t;
-  int     res;
-
-  if ((res = mp_init (&t)) != MP_OKAY) {
-    return res;
-  }
-
-  if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
-    mp_clear (&t);
-    return res;
-  }
-
-  if (t.sign != b->sign) {
-    res = mp_add (b, &t, c);
-  } else {
-    res = MP_OKAY;
-    mp_exch (&t, c);
-  }
-
-  mp_clear (&t);
-  return res;
-}
-
-
-/* this is a shell function that calls either the normal or Montgomery
- * exptmod functions.  Originally the call to the montgomery code was
- * embedded in the normal function but that wasted a lot of stack space
- * for nothing (since 99% of the time the Montgomery code would be called)
- */
-static int
-mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
-{
-  int dr;
-
-  /* modulus P must be positive */
-  if (P->sign == MP_NEG) {
-     return MP_VAL;
-  }
-
-  /* if exponent X is negative we have to recurse */
-  if (X->sign == MP_NEG) {
-#ifdef LTM_NO_NEG_EXP
-        return MP_VAL;
-#else /* LTM_NO_NEG_EXP */
-#ifdef BN_MP_INVMOD_C
-     mp_int tmpG, tmpX;
-     int err;
-
-     /* first compute 1/G mod P */
-     if ((err = mp_init(&tmpG)) != MP_OKAY) {
-        return err;
-     }
-     if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
-        mp_clear(&tmpG);
-        return err;
-     }
-
-     /* now get |X| */
-     if ((err = mp_init(&tmpX)) != MP_OKAY) {
-        mp_clear(&tmpG);
-        return err;
-     }
-     if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
-        mp_clear_multi(&tmpG, &tmpX, NULL);
-        return err;
-     }
-
-     /* and now compute (1/G)**|X| instead of G**X [X < 0] */
-     err = mp_exptmod(&tmpG, &tmpX, P, Y);
-     mp_clear_multi(&tmpG, &tmpX, NULL);
-     return err;
-#else
-#error mp_exptmod would always fail
-     /* no invmod */
-     return MP_VAL;
-#endif
-#endif /* LTM_NO_NEG_EXP */
-  }
-
-/* modified diminished radix reduction */
-#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
-  if (mp_reduce_is_2k_l(P) == MP_YES) {
-     return s_mp_exptmod(G, X, P, Y, 1);
-  }
-#endif
-
-#ifdef BN_MP_DR_IS_MODULUS_C
-  /* is it a DR modulus? */
-  dr = mp_dr_is_modulus(P);
-#else
-  /* default to no */
-  dr = 0;
-#endif
-
-#ifdef BN_MP_REDUCE_IS_2K_C
-  /* if not, is it a unrestricted DR modulus? */
-  if (dr == 0) {
-     dr = mp_reduce_is_2k(P) << 1;
-  }
-#endif
-
-  /* if the modulus is odd or dr != 0 use the montgomery method */
-#ifdef BN_MP_EXPTMOD_FAST_C
-  if (mp_isodd (P) == 1 || dr !=  0) {
-    return mp_exptmod_fast (G, X, P, Y, dr);
-  } else {
-#endif
-#ifdef BN_S_MP_EXPTMOD_C
-    (void) dr;
-    /* otherwise use the generic Barrett reduction technique */
-    return s_mp_exptmod (G, X, P, Y, 0);
-#else
-#error mp_exptmod could fail
-    /* no exptmod for evens */
-    return MP_VAL;
-#endif
-#ifdef BN_MP_EXPTMOD_FAST_C
-  }
-#endif
-}
-
-
-/* compare two ints (signed)*/
-static int
-mp_cmp (mp_int * a, mp_int * b)
-{
-  /* compare based on sign */
-  if (a->sign != b->sign) {
-     if (a->sign == MP_NEG) {
-        return MP_LT;
-     } else {
-        return MP_GT;
-     }
-  }
-
-  /* compare digits */
-  if (a->sign == MP_NEG) {
-     /* if negative compare opposite direction */
-     return mp_cmp_mag(b, a);
-  } else {
-     return mp_cmp_mag(a, b);
-  }
-}
-
-
-/* compare a digit */
-static int
-mp_cmp_d(mp_int * a, mp_digit b)
-{
-  /* compare based on sign */
-  if (a->sign == MP_NEG) {
-    return MP_LT;
-  }
-
-  /* compare based on magnitude */
-  if (a->used > 1) {
-    return MP_GT;
-  }
-
-  /* compare the only digit of a to b */
-  if (a->dp[0] > b) {
-    return MP_GT;
-  } else if (a->dp[0] < b) {
-    return MP_LT;
-  } else {
-    return MP_EQ;
-  }
-}
-
-
-#ifndef LTM_NO_NEG_EXP
-/* hac 14.61, pp608 */
-static int
-mp_invmod (mp_int * a, mp_int * b, mp_int * c)
-{
-  /* b cannot be negative */
-  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
-    return MP_VAL;
-  }
-
-#ifdef BN_FAST_MP_INVMOD_C
-  /* if the modulus is odd we can use a faster routine instead */
-  if (mp_isodd (b) == 1) {
-    return fast_mp_invmod (a, b, c);
-  }
-#endif
-
-#ifdef BN_MP_INVMOD_SLOW_C
-  return mp_invmod_slow(a, b, c);
-#endif
-
-#ifndef BN_FAST_MP_INVMOD_C
-#ifndef BN_MP_INVMOD_SLOW_C
-#error mp_invmod would always fail
-#endif
-#endif
-  return MP_VAL;
-}
-#endif /* LTM_NO_NEG_EXP */
-
-
-/* get the size for an unsigned equivalent */
-static int
-mp_unsigned_bin_size (mp_int * a)
-{
-  int     size = mp_count_bits (a);
-  return (size / 8 + ((size & 7) != 0 ? 1 : 0));
-}
-
-
-#ifndef LTM_NO_NEG_EXP
-/* hac 14.61, pp608 */
-static int
-mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
-{
-  mp_int  x, y, u, v, A, B, C, D;
-  int     res;
-
-  /* b cannot be negative */
-  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
-    return MP_VAL;
-  }
-
-  /* init temps */
-  if ((res = mp_init_multi(&x, &y, &u, &v,
-                           &A, &B, &C, &D, NULL)) != MP_OKAY) {
-     return res;
-  }
-
-  /* x = a, y = b */
-  if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
-      goto LBL_ERR;
-  }
-  if ((res = mp_copy (b, &y)) != MP_OKAY) {
-    goto LBL_ERR;
-  }
-
-  /* 2. [modified] if x,y are both even then return an error! */
-  if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
-    res = MP_VAL;
-    goto LBL_ERR;
-  }
-
-  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
-  if ((res = mp_copy (&x, &u)) != MP_OKAY) {
-    goto LBL_ERR;
-  }
-  if ((res = mp_copy (&y, &v)) != MP_OKAY) {
-    goto LBL_ERR;
-  }
-  mp_set (&A, 1);
-  mp_set (&D, 1);
-
-top:
-  /* 4.  while u is even do */
-  while (mp_iseven (&u) == 1) {
-    /* 4.1 u = u/2 */
-    if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-    /* 4.2 if A or B is odd then */
-    if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
-      /* A = (A+y)/2, B = (B-x)/2 */
-      if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-      if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-    }
-    /* A = A/2, B = B/2 */
-    if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-    if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-  }
-
-  /* 5.  while v is even do */
-  while (mp_iseven (&v) == 1) {
-    /* 5.1 v = v/2 */
-    if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-    /* 5.2 if C or D is odd then */
-    if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
-      /* C = (C+y)/2, D = (D-x)/2 */
-      if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-      if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-    }
-    /* C = C/2, D = D/2 */
-    if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-    if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-  }
-
-  /* 6.  if u >= v then */
-  if (mp_cmp (&u, &v) != MP_LT) {
-    /* u = u - v, A = A - C, B = B - D */
-    if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-
-    if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-
-    if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-  } else {
-    /* v - v - u, C = C - A, D = D - B */
-    if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-
-    if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-
-    if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-  }
-
-  /* if not zero goto step 4 */
-  if (mp_iszero (&u) == 0)
-    goto top;
-
-  /* now a = C, b = D, gcd == g*v */
-
-  /* if v != 1 then there is no inverse */
-  if (mp_cmp_d (&v, 1) != MP_EQ) {
-    res = MP_VAL;
-    goto LBL_ERR;
-  }
-
-  /* if its too low */
-  while (mp_cmp_d(&C, 0) == MP_LT) {
-      if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-  }
-
-  /* too big */
-  while (mp_cmp_mag(&C, b) != MP_LT) {
-      if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-  }
-
-  /* C is now the inverse */
-  mp_exch (&C, c);
-  res = MP_OKAY;
-LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
-  return res;
-}
-#endif /* LTM_NO_NEG_EXP */
-
-
-/* compare maginitude of two ints (unsigned) */
-static int
-mp_cmp_mag (mp_int * a, mp_int * b)
-{
-  int     n;
-  mp_digit *tmpa, *tmpb;
-
-  /* compare based on # of non-zero digits */
-  if (a->used > b->used) {
-    return MP_GT;
-  }
-
-  if (a->used < b->used) {
-    return MP_LT;
-  }
-
-  /* alias for a */
-  tmpa = a->dp + (a->used - 1);
-
-  /* alias for b */
-  tmpb = b->dp + (a->used - 1);
-
-  /* compare based on digits  */
-  for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
-    if (*tmpa > *tmpb) {
-      return MP_GT;
-    }
-
-    if (*tmpa < *tmpb) {
-      return MP_LT;
-    }
-  }
-  return MP_EQ;
-}
-
-
-/* reads a unsigned char array, assumes the msb is stored first [big endian] */
-static int
-mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
-{
-  int     res;
-
-  /* make sure there are at least two digits */
-  if (a->alloc < 2) {
-     if ((res = mp_grow(a, 2)) != MP_OKAY) {
-        return res;
-     }
-  }
-
-  /* zero the int */
-  mp_zero (a);
-
-  /* read the bytes in */
-  while (c-- > 0) {
-    if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
-      return res;
-    }
-
-#ifndef MP_8BIT
-      a->dp[0] |= *b++;
-      a->used += 1;
-#else
-      a->dp[0] = (*b & MP_MASK);
-      a->dp[1] |= ((*b++ >> 7U) & 1);
-      a->used += 2;
-#endif
-  }
-  mp_clamp (a);
-  return MP_OKAY;
-}
-
-
-/* store in unsigned [big endian] format */
-static int
-mp_to_unsigned_bin (mp_int * a, unsigned char *b)
-{
-  int     x, res;
-  mp_int  t;
-
-  if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
-    return res;
-  }
-
-  x = 0;
-  while (mp_iszero (&t) == 0) {
-#ifndef MP_8BIT
-      b[x++] = (unsigned char) (t.dp[0] & 255);
-#else
-      b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
-#endif
-    if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
-      mp_clear (&t);
-      return res;
-    }
-  }
-  bn_reverse (b, x);
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
-static int
-mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
-{
-  mp_digit D, r, rr;
-  int     x, res;
-  mp_int  t;
-
-
-  /* if the shift count is <= 0 then we do no work */
-  if (b <= 0) {
-    res = mp_copy (a, c);
-    if (d != NULL) {
-      mp_zero (d);
-    }
-    return res;
-  }
-
-  if ((res = mp_init (&t)) != MP_OKAY) {
-    return res;
-  }
-
-  /* get the remainder */
-  if (d != NULL) {
-    if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
-      mp_clear (&t);
-      return res;
-    }
-  }
-
-  /* copy */
-  if ((res = mp_copy (a, c)) != MP_OKAY) {
-    mp_clear (&t);
-    return res;
-  }
-
-  /* shift by as many digits in the bit count */
-  if (b >= (int)DIGIT_BIT) {
-    mp_rshd (c, b / DIGIT_BIT);
-  }
-
-  /* shift any bit count < DIGIT_BIT */
-  D = (mp_digit) (b % DIGIT_BIT);
-  if (D != 0) {
-    register mp_digit *tmpc, mask, shift;
-
-    /* mask */
-    mask = (((mp_digit)1) << D) - 1;
-
-    /* shift for lsb */
-    shift = DIGIT_BIT - D;
-
-    /* alias */
-    tmpc = c->dp + (c->used - 1);
-
-    /* carry */
-    r = 0;
-    for (x = c->used - 1; x >= 0; x--) {
-      /* get the lower  bits of this word in a temp */
-      rr = *tmpc & mask;
-
-      /* shift the current word and mix in the carry bits from the previous word */
-      *tmpc = (*tmpc >> D) | (r << shift);
-      --tmpc;
-
-      /* set the carry to the carry bits of the current word found above */
-      r = rr;
-    }
-  }
-  mp_clamp (c);
-  if (d != NULL) {
-    mp_exch (&t, d);
-  }
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-static int
-mp_init_copy (mp_int * a, mp_int * b)
-{
-  int     res;
-
-  if ((res = mp_init (a)) != MP_OKAY) {
-    return res;
-  }
-  return mp_copy (b, a);
-}
-
-
-/* set to zero */
-static void
-mp_zero (mp_int * a)
-{
-  int       n;
-  mp_digit *tmp;
-
-  a->sign = MP_ZPOS;
-  a->used = 0;
-
-  tmp = a->dp;
-  for (n = 0; n < a->alloc; n++) {
-     *tmp++ = 0;
-  }
-}
-
-
-/* copy, b = a */
-static int
-mp_copy (mp_int * a, mp_int * b)
-{
-  int     res, n;
-
-  /* if dst == src do nothing */
-  if (a == b) {
-    return MP_OKAY;
-  }
-
-  /* grow dest */
-  if (b->alloc < a->used) {
-     if ((res = mp_grow (b, a->used)) != MP_OKAY) {
-        return res;
-     }
-  }
-
-  /* zero b and copy the parameters over */
-  {
-    register mp_digit *tmpa, *tmpb;
-
-    /* pointer aliases */
-
-    /* source */
-    tmpa = a->dp;
-
-    /* destination */
-    tmpb = b->dp;
-
-    /* copy all the digits */
-    for (n = 0; n < a->used; n++) {
-      *tmpb++ = *tmpa++;
-    }
-
-    /* clear high digits */
-    for (; n < b->used; n++) {
-      *tmpb++ = 0;
-    }
-  }
-
-  /* copy used count and sign */
-  b->used = a->used;
-  b->sign = a->sign;
-  return MP_OKAY;
-}
-
-
-/* shift right a certain amount of digits */
-static void
-mp_rshd (mp_int * a, int b)
-{
-  int     x;
-
-  /* if b <= 0 then ignore it */
-  if (b <= 0) {
-    return;
-  }
-
-  /* if b > used then simply zero it and return */
-  if (a->used <= b) {
-    mp_zero (a);
-    return;
-  }
-
-  {
-    register mp_digit *bottom, *top;
-
-    /* shift the digits down */
-
-    /* bottom */
-    bottom = a->dp;
-
-    /* top [offset into digits] */
-    top = a->dp + b;
-
-    /* this is implemented as a sliding window where
-     * the window is b-digits long and digits from
-     * the top of the window are copied to the bottom
-     *
-     * e.g.
-
-     b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
-                 /\                   |      ---->
-                  \-------------------/      ---->
-     */
-    for (x = 0; x < (a->used - b); x++) {
-      *bottom++ = *top++;
-    }
-
-    /* zero the top digits */
-    for (; x < a->used; x++) {
-      *bottom++ = 0;
-    }
-  }
-
-  /* remove excess digits */
-  a->used -= b;
-}
-
-
-/* swap the elements of two integers, for cases where you can't simply swap the
- * mp_int pointers around
- */
-static void
-mp_exch (mp_int * a, mp_int * b)
-{
-  mp_int  t;
-
-  t  = *a;
-  *a = *b;
-  *b = t;
-}
-
-
-/* trim unused digits
- *
- * This is used to ensure that leading zero digits are
- * trimed and the leading "used" digit will be non-zero
- * Typically very fast.  Also fixes the sign if there
- * are no more leading digits
- */
-static void
-mp_clamp (mp_int * a)
-{
-  /* decrease used while the most significant digit is
-   * zero.
-   */
-  while (a->used > 0 && a->dp[a->used - 1] == 0) {
-    --(a->used);
-  }
-
-  /* reset the sign flag if used == 0 */
-  if (a->used == 0) {
-    a->sign = MP_ZPOS;
-  }
-}
-
-
-/* grow as required */
-static int
-mp_grow (mp_int * a, int size)
-{
-  int     i;
-  mp_digit *tmp;
-
-  /* if the alloc size is smaller alloc more ram */
-  if (a->alloc < size) {
-    /* ensure there are always at least MP_PREC digits extra on top */
-    size += (MP_PREC * 2) - (size % MP_PREC);
-
-    /* reallocate the array a->dp
-     *
-     * We store the return in a temporary variable
-     * in case the operation failed we don't want
-     * to overwrite the dp member of a.
-     */
-    tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
-    if (tmp == NULL) {
-      /* reallocation failed but "a" is still valid [can be freed] */
-      return MP_MEM;
-    }
-
-    /* reallocation succeeded so set a->dp */
-    a->dp = tmp;
-
-    /* zero excess digits */
-    i        = a->alloc;
-    a->alloc = size;
-    for (; i < a->alloc; i++) {
-      a->dp[i] = 0;
-    }
-  }
-  return MP_OKAY;
-}
-
-
-#ifdef BN_MP_ABS_C
-/* b = |a|
- *
- * Simple function copies the input and fixes the sign to positive
- */
-static int
-mp_abs (mp_int * a, mp_int * b)
-{
-  int     res;
-
-  /* copy a to b */
-  if (a != b) {
-     if ((res = mp_copy (a, b)) != MP_OKAY) {
-       return res;
-     }
-  }
-
-  /* force the sign of b to positive */
-  b->sign = MP_ZPOS;
-
-  return MP_OKAY;
-}
-#endif
-
-
-/* set to a digit */
-static void
-mp_set (mp_int * a, mp_digit b)
-{
-  mp_zero (a);
-  a->dp[0] = b & MP_MASK;
-  a->used  = (a->dp[0] != 0) ? 1 : 0;
-}
-
-
-#ifndef LTM_NO_NEG_EXP
-/* b = a/2 */
-static int
-mp_div_2(mp_int * a, mp_int * b)
-{
-  int     x, res, oldused;
-
-  /* copy */
-  if (b->alloc < a->used) {
-    if ((res = mp_grow (b, a->used)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  oldused = b->used;
-  b->used = a->used;
-  {
-    register mp_digit r, rr, *tmpa, *tmpb;
-
-    /* source alias */
-    tmpa = a->dp + b->used - 1;
-
-    /* dest alias */
-    tmpb = b->dp + b->used - 1;
-
-    /* carry */
-    r = 0;
-    for (x = b->used - 1; x >= 0; x--) {
-      /* get the carry for the next iteration */
-      rr = *tmpa & 1;
-
-      /* shift the current digit, add in carry and store */
-      *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
-
-      /* forward carry to next iteration */
-      r = rr;
-    }
-
-    /* zero excess digits */
-    tmpb = b->dp + b->used;
-    for (x = b->used; x < oldused; x++) {
-      *tmpb++ = 0;
-    }
-  }
-  b->sign = a->sign;
-  mp_clamp (b);
-  return MP_OKAY;
-}
-#endif /* LTM_NO_NEG_EXP */
-
-
-/* shift left by a certain bit count */
-static int
-mp_mul_2d (mp_int * a, int b, mp_int * c)
-{
-  mp_digit d;
-  int      res;
-
-  /* copy */
-  if (a != c) {
-     if ((res = mp_copy (a, c)) != MP_OKAY) {
-       return res;
-     }
-  }
-
-  if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
-     if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
-       return res;
-     }
-  }
-
-  /* shift by as many digits in the bit count */
-  if (b >= (int)DIGIT_BIT) {
-    if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* shift any bit count < DIGIT_BIT */
-  d = (mp_digit) (b % DIGIT_BIT);
-  if (d != 0) {
-    register mp_digit *tmpc, shift, mask, r, rr;
-    register int x;
-
-    /* bitmask for carries */
-    mask = (((mp_digit)1) << d) - 1;
-
-    /* shift for msbs */
-    shift = DIGIT_BIT - d;
-
-    /* alias */
-    tmpc = c->dp;
-
-    /* carry */
-    r    = 0;
-    for (x = 0; x < c->used; x++) {
-      /* get the higher bits of the current word */
-      rr = (*tmpc >> shift) & mask;
-
-      /* shift the current word and OR in the carry */
-      *tmpc = ((*tmpc << d) | r) & MP_MASK;
-      ++tmpc;
-
-      /* set the carry to the carry bits of the current word */
-      r = rr;
-    }
-
-    /* set final carry */
-    if (r != 0) {
-       c->dp[(c->used)++] = r;
-    }
-  }
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-#ifdef BN_MP_INIT_MULTI_C
-static int
-mp_init_multi(mp_int *mp, ...)
-{
-    mp_err res = MP_OKAY;      /* Assume ok until proven otherwise */
-    int n = 0;                 /* Number of ok inits */
-    mp_int* cur_arg = mp;
-    va_list args;
-
-    va_start(args, mp);        /* init args to next argument from caller */
-    while (cur_arg != NULL) {
-        if (mp_init(cur_arg) != MP_OKAY) {
-            /* Oops - error! Back-track and mp_clear what we already
-               succeeded in init-ing, then return error.
-            */
-            va_list clean_args;
-
-            /* end the current list */
-            va_end(args);
-
-            /* now start cleaning up */
-            cur_arg = mp;
-            va_start(clean_args, mp);
-            while (n--) {
-                mp_clear(cur_arg);
-                cur_arg = va_arg(clean_args, mp_int*);
-            }
-            va_end(clean_args);
-            res = MP_MEM;
-            break;
-        }
-        n++;
-        cur_arg = va_arg(args, mp_int*);
-    }
-    va_end(args);
-    return res;                /* Assumed ok, if error flagged above. */
-}
-#endif
-
-
-#ifdef BN_MP_CLEAR_MULTI_C
-static void
-mp_clear_multi(mp_int *mp, ...)
-{
-    mp_int* next_mp = mp;
-    va_list args;
-    va_start(args, mp);
-    while (next_mp != NULL) {
-        mp_clear(next_mp);
-        next_mp = va_arg(args, mp_int*);
-    }
-    va_end(args);
-}
-#endif
-
-
-/* shift left a certain amount of digits */
-static int
-mp_lshd (mp_int * a, int b)
-{
-  int     x, res;
-
-  /* if its less than zero return */
-  if (b <= 0) {
-    return MP_OKAY;
-  }
-
-  /* grow to fit the new digits */
-  if (a->alloc < a->used + b) {
-     if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
-       return res;
-     }
-  }
-
-  {
-    register mp_digit *top, *bottom;
-
-    /* increment the used by the shift amount then copy upwards */
-    a->used += b;
-
-    /* top */
-    top = a->dp + a->used - 1;
-
-    /* base */
-    bottom = a->dp + a->used - 1 - b;
-
-    /* much like mp_rshd this is implemented using a sliding window
-     * except the window goes the otherway around.  Copying from
-     * the bottom to the top.  see bn_mp_rshd.c for more info.
-     */
-    for (x = a->used - 1; x >= b; x--) {
-      *top-- = *bottom--;
-    }
-
-    /* zero the lower digits */
-    top = a->dp;
-    for (x = 0; x < b; x++) {
-      *top++ = 0;
-    }
-  }
-  return MP_OKAY;
-}
-
-
-/* returns the number of bits in an int */
-static int
-mp_count_bits (mp_int * a)
-{
-  int     r;
-  mp_digit q;
-
-  /* shortcut */
-  if (a->used == 0) {
-    return 0;
-  }
-
-  /* get number of digits and add that */
-  r = (a->used - 1) * DIGIT_BIT;
-
-  /* take the last digit and count the bits in it */
-  q = a->dp[a->used - 1];
-  while (q > ((mp_digit) 0)) {
-    ++r;
-    q >>= ((mp_digit) 1);
-  }
-  return r;
-}
-
-
-/* calc a value mod 2**b */
-static int
-mp_mod_2d (mp_int * a, int b, mp_int * c)
-{
-  int     x, res;
-
-  /* if b is <= 0 then zero the int */
-  if (b <= 0) {
-    mp_zero (c);
-    return MP_OKAY;
-  }
-
-  /* if the modulus is larger than the value than return */
-  if (b >= (int) (a->used * DIGIT_BIT)) {
-    res = mp_copy (a, c);
-    return res;
-  }
-
-  /* copy */
-  if ((res = mp_copy (a, c)) != MP_OKAY) {
-    return res;
-  }
-
-  /* zero digits above the last digit of the modulus */
-  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
-    c->dp[x] = 0;
-  }
-  /* clear the digit that is not completely outside/inside the modulus */
-  c->dp[b / DIGIT_BIT] &=
-    (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-#ifdef BN_MP_DIV_SMALL
-
-/* slower bit-bang division... also smaller */
-static int
-mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
-{
-   mp_int ta, tb, tq, q;
-   int    res, n, n2;
-
-  /* is divisor zero ? */
-  if (mp_iszero (b) == 1) {
-    return MP_VAL;
-  }
-
-  /* if a < b then q=0, r = a */
-  if (mp_cmp_mag (a, b) == MP_LT) {
-    if (d != NULL) {
-      res = mp_copy (a, d);
-    } else {
-      res = MP_OKAY;
-    }
-    if (c != NULL) {
-      mp_zero (c);
-    }
-    return res;
-  }
-
-  /* init our temps */
-  if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
-     return res;
-  }
-
-
-  mp_set(&tq, 1);
-  n = mp_count_bits(a) - mp_count_bits(b);
-  if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
-      ((res = mp_abs(b, &tb)) != MP_OKAY) ||
-      ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
-      ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
-      goto LBL_ERR;
-  }
-
-  while (n-- >= 0) {
-     if (mp_cmp(&tb, &ta) != MP_GT) {
-        if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
-            ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
-           goto LBL_ERR;
-        }
-     }
-     if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
-         ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
-           goto LBL_ERR;
-     }
-  }
-
-  /* now q == quotient and ta == remainder */
-  n  = a->sign;
-  n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
-  if (c != NULL) {
-     mp_exch(c, &q);
-     c->sign  = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
-  }
-  if (d != NULL) {
-     mp_exch(d, &ta);
-     d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
-  }
-LBL_ERR:
-   mp_clear_multi(&ta, &tb, &tq, &q, NULL);
-   return res;
-}
-
-#else
-
-/* integer signed division.
- * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
- * HAC pp.598 Algorithm 14.20
- *
- * Note that the description in HAC is horribly
- * incomplete.  For example, it doesn't consider
- * the case where digits are removed from 'x' in
- * the inner loop.  It also doesn't consider the
- * case that y has fewer than three digits, etc..
- *
- * The overall algorithm is as described as
- * 14.20 from HAC but fixed to treat these cases.
-*/
-static int
-mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
-{
-  mp_int  q, x, y, t1, t2;
-  int     res, n, t, i, norm, neg;
-
-  /* is divisor zero ? */
-  if (mp_iszero (b) == 1) {
-    return MP_VAL;
-  }
-
-  /* if a < b then q=0, r = a */
-  if (mp_cmp_mag (a, b) == MP_LT) {
-    if (d != NULL) {
-      res = mp_copy (a, d);
-    } else {
-      res = MP_OKAY;
-    }
-    if (c != NULL) {
-      mp_zero (c);
-    }
-    return res;
-  }
-
-  if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
-    return res;
-  }
-  q.used = a->used + 2;
-
-  if ((res = mp_init (&t1)) != MP_OKAY) {
-    goto LBL_Q;
-  }
-
-  if ((res = mp_init (&t2)) != MP_OKAY) {
-    goto LBL_T1;
-  }
-
-  if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
-    goto LBL_T2;
-  }
-
-  if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
-    goto LBL_X;
-  }
-
-  /* fix the sign */
-  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
-  x.sign = y.sign = MP_ZPOS;
-
-  /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
-  norm = mp_count_bits(&y) % DIGIT_BIT;
-  if (norm < (int)(DIGIT_BIT-1)) {
-     norm = (DIGIT_BIT-1) - norm;
-     if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
-       goto LBL_Y;
-     }
-     if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
-       goto LBL_Y;
-     }
-  } else {
-     norm = 0;
-  }
-
-  /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
-  n = x.used - 1;
-  t = y.used - 1;
-
-  /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
-  if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
-    goto LBL_Y;
-  }
-
-  while (mp_cmp (&x, &y) != MP_LT) {
-    ++(q.dp[n - t]);
-    if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
-      goto LBL_Y;
-    }
-  }
-
-  /* reset y by shifting it back down */
-  mp_rshd (&y, n - t);
-
-  /* step 3. for i from n down to (t + 1) */
-  for (i = n; i >= (t + 1); i--) {
-    if (i > x.used) {
-      continue;
-    }
-
-    /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
-     * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
-    if (x.dp[i] == y.dp[t]) {
-      q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
-    } else {
-      mp_word tmp;
-      tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
-      tmp |= ((mp_word) x.dp[i - 1]);
-      tmp /= ((mp_word) y.dp[t]);
-      if (tmp > (mp_word) MP_MASK)
-        tmp = MP_MASK;
-      q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
-    }
-
-    /* while (q{i-t-1} * (yt * b + y{t-1})) >
-             xi * b**2 + xi-1 * b + xi-2
-
-       do q{i-t-1} -= 1;
-    */
-    q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
-    do {
-      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
-
-      /* find left hand */
-      mp_zero (&t1);
-      t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
-      t1.dp[1] = y.dp[t];
-      t1.used = 2;
-      if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
-        goto LBL_Y;
-      }
-
-      /* find right hand */
-      t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
-      t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
-      t2.dp[2] = x.dp[i];
-      t2.used = 3;
-    } while (mp_cmp_mag(&t1, &t2) == MP_GT);
-
-    /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
-    if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
-      goto LBL_Y;
-    }
-
-    if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
-      goto LBL_Y;
-    }
-
-    if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
-      goto LBL_Y;
-    }
-
-    /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
-    if (x.sign == MP_NEG) {
-      if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
-        goto LBL_Y;
-      }
-      if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
-        goto LBL_Y;
-      }
-      if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
-        goto LBL_Y;
-      }
-
-      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
-    }
-  }
-
-  /* now q is the quotient and x is the remainder
-   * [which we have to normalize]
-   */
-
-  /* get sign before writing to c */
-  x.sign = x.used == 0 ? MP_ZPOS : a->sign;
-
-  if (c != NULL) {
-    mp_clamp (&q);
-    mp_exch (&q, c);
-    c->sign = neg;
-  }
-
-  if (d != NULL) {
-    mp_div_2d (&x, norm, &x, NULL);
-    mp_exch (&x, d);
-  }
-
-  res = MP_OKAY;
-
-LBL_Y:mp_clear (&y);
-LBL_X:mp_clear (&x);
-LBL_T2:mp_clear (&t2);
-LBL_T1:mp_clear (&t1);
-LBL_Q:mp_clear (&q);
-  return res;
-}
-
-#endif
-
-
-#ifdef MP_LOW_MEM
-   #define TAB_SIZE 32
-#else
-   #define TAB_SIZE 256
-#endif
-
-static int
-s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
-{
-  mp_int  M[TAB_SIZE], res, mu;
-  mp_digit buf;
-  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
-  int (*redux)(mp_int*,mp_int*,mp_int*);
-
-  /* find window size */
-  x = mp_count_bits (X);
-  if (x <= 7) {
-    winsize = 2;
-  } else if (x <= 36) {
-    winsize = 3;
-  } else if (x <= 140) {
-    winsize = 4;
-  } else if (x <= 450) {
-    winsize = 5;
-  } else if (x <= 1303) {
-    winsize = 6;
-  } else if (x <= 3529) {
-    winsize = 7;
-  } else {
-    winsize = 8;
-  }
-
-#ifdef MP_LOW_MEM
-    if (winsize > 5) {
-       winsize = 5;
-    }
-#endif
-
-  /* init M array */
-  /* init first cell */
-  if ((err = mp_init(&M[1])) != MP_OKAY) {
-     return err;
-  }
-
-  /* now init the second half of the array */
-  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
-    if ((err = mp_init(&M[x])) != MP_OKAY) {
-      for (y = 1<<(winsize-1); y < x; y++) {
-        mp_clear (&M[y]);
-      }
-      mp_clear(&M[1]);
-      return err;
-    }
-  }
-
-  /* create mu, used for Barrett reduction */
-  if ((err = mp_init (&mu)) != MP_OKAY) {
-    goto LBL_M;
-  }
-
-  if (redmode == 0) {
-     if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
-        goto LBL_MU;
-     }
-     redux = mp_reduce;
-  } else {
-     if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
-        goto LBL_MU;
-     }
-     redux = mp_reduce_2k_l;
-  }
-
-  /* create M table
-   *
-   * The M table contains powers of the base,
-   * e.g. M[x] = G**x mod P
-   *
-   * The first half of the table is not
-   * computed though accept for M[0] and M[1]
-   */
-  if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
-    goto LBL_MU;
-  }
-
-  /* compute the value at M[1<<(winsize-1)] by squaring
-   * M[1] (winsize-1) times
-   */
-  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
-    goto LBL_MU;
-  }
-
-  for (x = 0; x < (winsize - 1); x++) {
-    /* square it */
-    if ((err = mp_sqr (&M[1 << (winsize - 1)],
-                       &M[1 << (winsize - 1)])) != MP_OKAY) {
-      goto LBL_MU;
-    }
-
-    /* reduce modulo P */
-    if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
-      goto LBL_MU;
-    }
-  }
-
-  /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
-   * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
-   */
-  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
-    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
-      goto LBL_MU;
-    }
-    if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
-      goto LBL_MU;
-    }
-  }
-
-  /* setup result */
-  if ((err = mp_init (&res)) != MP_OKAY) {
-    goto LBL_MU;
-  }
-  mp_set (&res, 1);
-
-  /* set initial mode and bit cnt */
-  mode   = 0;
-  bitcnt = 1;
-  buf    = 0;
-  digidx = X->used - 1;
-  bitcpy = 0;
-  bitbuf = 0;
-
-  for (;;) {
-    /* grab next digit as required */
-    if (--bitcnt == 0) {
-      /* if digidx == -1 we are out of digits */
-      if (digidx == -1) {
-        break;
-      }
-      /* read next digit and reset the bitcnt */
-      buf    = X->dp[digidx--];
-      bitcnt = (int) DIGIT_BIT;
-    }
-
-    /* grab the next msb from the exponent */
-    y     = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
-    buf <<= (mp_digit)1;
-
-    /* if the bit is zero and mode == 0 then we ignore it
-     * These represent the leading zero bits before the first 1 bit
-     * in the exponent.  Technically this opt is not required but it
-     * does lower the # of trivial squaring/reductions used
-     */
-    if (mode == 0 && y == 0) {
-      continue;
-    }
-
-    /* if the bit is zero and mode == 1 then we square */
-    if (mode == 1 && y == 0) {
-      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      continue;
-    }
-
-    /* else we add it to the window */
-    bitbuf |= (y << (winsize - ++bitcpy));
-    mode    = 2;
-
-    if (bitcpy == winsize) {
-      /* ok window is filled so square as required and multiply  */
-      /* square first */
-      for (x = 0; x < winsize; x++) {
-        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-      }
-
-      /* then multiply */
-      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-
-      /* empty window and reset */
-      bitcpy = 0;
-      bitbuf = 0;
-      mode   = 1;
-    }
-  }
-
-  /* if bits remain then square/multiply */
-  if (mode == 2 && bitcpy > 0) {
-    /* square then multiply if the bit is set */
-    for (x = 0; x < bitcpy; x++) {
-      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-
-      bitbuf <<= 1;
-      if ((bitbuf & (1 << winsize)) != 0) {
-        /* then multiply */
-        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-      }
-    }
-  }
-
-  mp_exch (&res, Y);
-  err = MP_OKAY;
-LBL_RES:mp_clear (&res);
-LBL_MU:mp_clear (&mu);
-LBL_M:
-  mp_clear(&M[1]);
-  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
-    mp_clear (&M[x]);
-  }
-  return err;
-}
-
-
-/* computes b = a*a */
-static int
-mp_sqr (mp_int * a, mp_int * b)
-{
-  int     res;
-
-#ifdef BN_MP_TOOM_SQR_C
-  /* use Toom-Cook? */
-  if (a->used >= TOOM_SQR_CUTOFF) {
-    res = mp_toom_sqr(a, b);
-  /* Karatsuba? */
-  } else
-#endif
-#ifdef BN_MP_KARATSUBA_SQR_C
-if (a->used >= KARATSUBA_SQR_CUTOFF) {
-    res = mp_karatsuba_sqr (a, b);
-  } else
-#endif
-  {
-#ifdef BN_FAST_S_MP_SQR_C
-    /* can we use the fast comba multiplier? */
-    if ((a->used * 2 + 1) < MP_WARRAY &&
-         a->used <
-         (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
-      res = fast_s_mp_sqr (a, b);
-    } else
-#endif
-#ifdef BN_S_MP_SQR_C
-      res = s_mp_sqr (a, b);
-#else
-#error mp_sqr could fail
-      res = MP_VAL;
-#endif
-  }
-  b->sign = MP_ZPOS;
-  return res;
-}
-
-
-/* reduces a modulo n where n is of the form 2**p - d
-   This differs from reduce_2k since "d" can be larger
-   than a single digit.
-*/
-static int
-mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
-{
-   mp_int q;
-   int    p, res;
-
-   if ((res = mp_init(&q)) != MP_OKAY) {
-      return res;
-   }
-
-   p = mp_count_bits(n);
-top:
-   /* q = a/2**p, a = a mod 2**p */
-   if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
-      goto ERR;
-   }
-
-   /* q = q * d */
-   if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
-      goto ERR;
-   }
-
-   /* a = a + q */
-   if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
-      goto ERR;
-   }
-
-   if (mp_cmp_mag(a, n) != MP_LT) {
-      s_mp_sub(a, n, a);
-      goto top;
-   }
-
-ERR:
-   mp_clear(&q);
-   return res;
-}
-
-
-/* determines the setup value */
-static int
-mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
-{
-   int    res;
-   mp_int tmp;
-
-   if ((res = mp_init(&tmp)) != MP_OKAY) {
-      return res;
-   }
-
-   if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
-      goto ERR;
-   }
-
-   if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
-      goto ERR;
-   }
-
-ERR:
-   mp_clear(&tmp);
-   return res;
-}
-
-
-/* computes a = 2**b
- *
- * Simple algorithm which zeroes the int, grows it then just sets one bit
- * as required.
- */
-static int
-mp_2expt (mp_int * a, int b)
-{
-  int     res;
-
-  /* zero a as per default */
-  mp_zero (a);
-
-  /* grow a to accommodate the single bit */
-  if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
-    return res;
-  }
-
-  /* set the used count of where the bit will go */
-  a->used = b / DIGIT_BIT + 1;
-
-  /* put the single bit in its place */
-  a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
-
-  return MP_OKAY;
-}
-
-
-/* pre-calculate the value required for Barrett reduction
- * For a given modulus "b" it calulates the value required in "a"
- */
-static int
-mp_reduce_setup (mp_int * a, mp_int * b)
-{
-  int     res;
-
-  if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
-    return res;
-  }
-  return mp_div (a, b, a, NULL);
-}
-
-
-/* reduces x mod m, assumes 0 < x < m**2, mu is
- * precomputed via mp_reduce_setup.
- * From HAC pp.604 Algorithm 14.42
- */
-static int
-mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
-{
-  mp_int  q;
-  int     res, um = m->used;
-
-  /* q = x */
-  if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
-    return res;
-  }
-
-  /* q1 = x / b**(k-1)  */
-  mp_rshd (&q, um - 1);
-
-  /* according to HAC this optimization is ok */
-  if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
-    if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-  } else {
-#ifdef BN_S_MP_MUL_HIGH_DIGS_C
-    if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
-    if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-#else
-    {
-#error mp_reduce would always fail
-      res = MP_VAL;
-      goto CLEANUP;
-    }
-#endif
-  }
-
-  /* q3 = q2 / b**(k+1) */
-  mp_rshd (&q, um + 1);
-
-  /* x = x mod b**(k+1), quick (no division) */
-  if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
-    goto CLEANUP;
-  }
-
-  /* q = q * m mod b**(k+1), quick (no division) */
-  if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
-    goto CLEANUP;
-  }
-
-  /* x = x - q */
-  if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
-    goto CLEANUP;
-  }
-
-  /* If x < 0, add b**(k+1) to it */
-  if (mp_cmp_d (x, 0) == MP_LT) {
-    mp_set (&q, 1);
-    if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-    if ((res = mp_add (x, &q, x)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-  }
-
-  /* Back off if it's too big */
-  while (mp_cmp (x, m) != MP_LT) {
-    if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-  }
-
-CLEANUP:
-  mp_clear (&q);
-
-  return res;
-}
-
-
-/* multiplies |a| * |b| and only computes up to digs digits of result
- * HAC pp. 595, Algorithm 14.12  Modified so you can control how
- * many digits of output are created.
- */
-static int
-s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
-{
-  mp_int  t;
-  int     res, pa, pb, ix, iy;
-  mp_digit u;
-  mp_word r;
-  mp_digit tmpx, *tmpt, *tmpy;
-
-  /* can we use the fast multiplier? */
-  if (((digs) < MP_WARRAY) &&
-      MIN (a->used, b->used) <
-          (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
-    return fast_s_mp_mul_digs (a, b, c, digs);
-  }
-
-  if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
-    return res;
-  }
-  t.used = digs;
-
-  /* compute the digits of the product directly */
-  pa = a->used;
-  for (ix = 0; ix < pa; ix++) {
-    /* set the carry to zero */
-    u = 0;
-
-    /* limit ourselves to making digs digits of output */
-    pb = MIN (b->used, digs - ix);
-
-    /* setup some aliases */
-    /* copy of the digit from a used within the nested loop */
-    tmpx = a->dp[ix];
-
-    /* an alias for the destination shifted ix places */
-    tmpt = t.dp + ix;
-
-    /* an alias for the digits of b */
-    tmpy = b->dp;
-
-    /* compute the columns of the output and propagate the carry */
-    for (iy = 0; iy < pb; iy++) {
-      /* compute the column as a mp_word */
-      r       = ((mp_word)*tmpt) +
-                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
-                ((mp_word) u);
-
-      /* the new column is the lower part of the result */
-      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
-
-      /* get the carry word from the result */
-      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
-    }
-    /* set carry if it is placed below digs */
-    if (ix + iy < digs) {
-      *tmpt = u;
-    }
-  }
-
-  mp_clamp (&t);
-  mp_exch (&t, c);
-
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-/* Fast (comba) multiplier
- *
- * This is the fast column-array [comba] multiplier.  It is
- * designed to compute the columns of the product first
- * then handle the carries afterwards.  This has the effect
- * of making the nested loops that compute the columns very
- * simple and schedulable on super-scalar processors.
- *
- * This has been modified to produce a variable number of
- * digits of output so if say only a half-product is required
- * you don't have to compute the upper half (a feature
- * required for fast Barrett reduction).
- *
- * Based on Algorithm 14.12 on pp.595 of HAC.
- *
- */
-static int
-fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
-{
-  int     olduse, res, pa, ix, iz;
-  mp_digit W[MP_WARRAY];
-  register mp_word  _W;
-
-  /* grow the destination as required */
-  if (c->alloc < digs) {
-    if ((res = mp_grow (c, digs)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* number of output digits to produce */
-  pa = MIN(digs, a->used + b->used);
-
-  /* clear the carry */
-  _W = 0;
-  for (ix = 0; ix < pa; ix++) {
-      int      tx, ty;
-      int      iy;
-      mp_digit *tmpx, *tmpy;
-
-      /* get offsets into the two bignums */
-      ty = MIN(b->used-1, ix);
-      tx = ix - ty;
-
-      /* setup temp aliases */
-      tmpx = a->dp + tx;
-      tmpy = b->dp + ty;
-
-      /* this is the number of times the loop will iterrate, essentially
-         while (tx++ < a->used && ty-- >= 0) { ... }
-       */
-      iy = MIN(a->used-tx, ty+1);
-
-      /* execute loop */
-      for (iz = 0; iz < iy; ++iz) {
-         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
-
-      }
-
-      /* store term */
-      W[ix] = ((mp_digit)_W) & MP_MASK;
-
-      /* make next carry */
-      _W = _W >> ((mp_word)DIGIT_BIT);
- }
-
-  /* setup dest */
-  olduse  = c->used;
-  c->used = pa;
-
-  {
-    register mp_digit *tmpc;
-    tmpc = c->dp;
-    for (ix = 0; ix < pa+1; ix++) {
-      /* now extract the previous digit [below the carry] */
-      *tmpc++ = W[ix];
-    }
-
-    /* clear unused digits [that existed in the old copy of c] */
-    for (; ix < olduse; ix++) {
-      *tmpc++ = 0;
-    }
-  }
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-/* init an mp_init for a given size */
-static int
-mp_init_size (mp_int * a, int size)
-{
-  int x;
-
-  /* pad size so there are always extra digits */
-  size += (MP_PREC * 2) - (size % MP_PREC);
-
-  /* alloc mem */
-  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
-  if (a->dp == NULL) {
-    return MP_MEM;
-  }
-
-  /* set the members */
-  a->used  = 0;
-  a->alloc = size;
-  a->sign  = MP_ZPOS;
-
-  /* zero the digits */
-  for (x = 0; x < size; x++) {
-      a->dp[x] = 0;
-  }
-
-  return MP_OKAY;
-}
-
-
-/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
-static int
-s_mp_sqr (mp_int * a, mp_int * b)
-{
-  mp_int  t;
-  int     res, ix, iy, pa;
-  mp_word r;
-  mp_digit u, tmpx, *tmpt;
-
-  pa = a->used;
-  if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
-    return res;
-  }
-
-  /* default used is maximum possible size */
-  t.used = 2*pa + 1;
-
-  for (ix = 0; ix < pa; ix++) {
-    /* first calculate the digit at 2*ix */
-    /* calculate double precision result */
-    r = ((mp_word) t.dp[2*ix]) +
-        ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
-
-    /* store lower part in result */
-    t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
-
-    /* get the carry */
-    u           = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
-
-    /* left hand side of A[ix] * A[iy] */
-    tmpx        = a->dp[ix];
-
-    /* alias for where to store the results */
-    tmpt        = t.dp + (2*ix + 1);
-
-    for (iy = ix + 1; iy < pa; iy++) {
-      /* first calculate the product */
-      r       = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
-
-      /* now calculate the double precision result, note we use
-       * addition instead of *2 since it's easier to optimize
-       */
-      r       = ((mp_word) *tmpt) + r + r + ((mp_word) u);
-
-      /* store lower part */
-      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
-
-      /* get carry */
-      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
-    }
-    /* propagate upwards */
-    while (u != ((mp_digit) 0)) {
-      r       = ((mp_word) *tmpt) + ((mp_word) u);
-      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
-      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
-    }
-  }
-
-  mp_clamp (&t);
-  mp_exch (&t, b);
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-/* multiplies |a| * |b| and does not compute the lower digs digits
- * [meant to get the higher part of the product]
- */
-static int
-s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
-{
-  mp_int  t;
-  int     res, pa, pb, ix, iy;
-  mp_digit u;
-  mp_word r;
-  mp_digit tmpx, *tmpt, *tmpy;
-
-  /* can we use the fast multiplier? */
-#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
-  if (((a->used + b->used + 1) < MP_WARRAY)
-      && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
-    return fast_s_mp_mul_high_digs (a, b, c, digs);
-  }
-#endif
-
-  if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
-    return res;
-  }
-  t.used = a->used + b->used + 1;
-
-  pa = a->used;
-  pb = b->used;
-  for (ix = 0; ix < pa; ix++) {
-    /* clear the carry */
-    u = 0;
-
-    /* left hand side of A[ix] * B[iy] */
-    tmpx = a->dp[ix];
-
-    /* alias to the address of where the digits will be stored */
-    tmpt = &(t.dp[digs]);
-
-    /* alias for where to read the right hand side from */
-    tmpy = b->dp + (digs - ix);
-
-    for (iy = digs - ix; iy < pb; iy++) {
-      /* calculate the double precision result */
-      r       = ((mp_word)*tmpt) +
-                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
-                ((mp_word) u);
-
-      /* get the lower part */
-      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
-
-      /* carry the carry */
-      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
-    }
-    *tmpt = u;
-  }
-  mp_clamp (&t);
-  mp_exch (&t, c);
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-#ifdef BN_MP_MONTGOMERY_SETUP_C
-/* setups the montgomery reduction stuff */
-static int
-mp_montgomery_setup (mp_int * n, mp_digit * rho)
-{
-  mp_digit x, b;
-
-/* fast inversion mod 2**k
- *
- * Based on the fact that
- *
- * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
- *                    =>  2*X*A - X*X*A*A = 1
- *                    =>  2*(1) - (1)     = 1
- */
-  b = n->dp[0];
-
-  if ((b & 1) == 0) {
-    return MP_VAL;
-  }
-
-  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
-  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
-#if !defined(MP_8BIT)
-  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
-#endif
-#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
-  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
-#endif
-#ifdef MP_64BIT
-  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
-#endif
-
-  /* rho = -1/m mod b */
-  *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
-
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
-/* computes xR**-1 == x (mod N) via Montgomery Reduction
- *
- * This is an optimized implementation of montgomery_reduce
- * which uses the comba method to quickly calculate the columns of the
- * reduction.
- *
- * Based on Algorithm 14.32 on pp.601 of HAC.
-*/
-int
-fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
-{
-  int     ix, res, olduse;
-  mp_word W[MP_WARRAY];
-
-  /* get old used count */
-  olduse = x->used;
-
-  /* grow a as required */
-  if (x->alloc < n->used + 1) {
-    if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* first we have to get the digits of the input into
-   * an array of double precision words W[...]
-   */
-  {
-    register mp_word *_W;
-    register mp_digit *tmpx;
-
-    /* alias for the W[] array */
-    _W   = W;
-
-    /* alias for the digits of  x*/
-    tmpx = x->dp;
-
-    /* copy the digits of a into W[0..a->used-1] */
-    for (ix = 0; ix < x->used; ix++) {
-      *_W++ = *tmpx++;
-    }
-
-    /* zero the high words of W[a->used..m->used*2] */
-    for (; ix < n->used * 2 + 1; ix++) {
-      *_W++ = 0;
-    }
-  }
-
-  /* now we proceed to zero successive digits
-   * from the least significant upwards
-   */
-  for (ix = 0; ix < n->used; ix++) {
-    /* mu = ai * m' mod b
-     *
-     * We avoid a double precision multiplication (which isn't required)
-     * by casting the value down to a mp_digit.  Note this requires
-     * that W[ix-1] have  the carry cleared (see after the inner loop)
-     */
-    register mp_digit mu;
-    mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
-
-    /* a = a + mu * m * b**i
-     *
-     * This is computed in place and on the fly.  The multiplication
-     * by b**i is handled by offseting which columns the results
-     * are added to.
-     *
-     * Note the comba method normally doesn't handle carries in the
-     * inner loop In this case we fix the carry from the previous
-     * column since the Montgomery reduction requires digits of the
-     * result (so far) [see above] to work.  This is
-     * handled by fixing up one carry after the inner loop.  The
-     * carry fixups are done in order so after these loops the
-     * first m->used words of W[] have the carries fixed
-     */
-    {
-      register int iy;
-      register mp_digit *tmpn;
-      register mp_word *_W;
-
-      /* alias for the digits of the modulus */
-      tmpn = n->dp;
-
-      /* Alias for the columns set by an offset of ix */
-      _W = W + ix;
-
-      /* inner loop */
-      for (iy = 0; iy < n->used; iy++) {
-          *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
-      }
-    }
-
-    /* now fix carry for next digit, W[ix+1] */
-    W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
-  }
-
-  /* now we have to propagate the carries and
-   * shift the words downward [all those least
-   * significant digits we zeroed].
-   */
-  {
-    register mp_digit *tmpx;
-    register mp_word *_W, *_W1;
-
-    /* nox fix rest of carries */
-
-    /* alias for current word */
-    _W1 = W + ix;
-
-    /* alias for next word, where the carry goes */
-    _W = W + ++ix;
-
-    for (; ix <= n->used * 2 + 1; ix++) {
-      *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
-    }
-
-    /* copy out, A = A/b**n
-     *
-     * The result is A/b**n but instead of converting from an
-     * array of mp_word to mp_digit than calling mp_rshd
-     * we just copy them in the right order
-     */
-
-    /* alias for destination word */
-    tmpx = x->dp;
-
-    /* alias for shifted double precision result */
-    _W = W + n->used;
-
-    for (ix = 0; ix < n->used + 1; ix++) {
-      *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
-    }
-
-    /* zero oldused digits, if the input a was larger than
-     * m->used+1 we'll have to clear the digits
-     */
-    for (; ix < olduse; ix++) {
-      *tmpx++ = 0;
-    }
-  }
-
-  /* set the max used and clamp */
-  x->used = n->used + 1;
-  mp_clamp (x);
-
-  /* if A >= m then A = A - m */
-  if (mp_cmp_mag (x, n) != MP_LT) {
-    return s_mp_sub (x, n, x);
-  }
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_MP_MUL_2_C
-/* b = a*2 */
-static int
-mp_mul_2(mp_int * a, mp_int * b)
-{
-  int     x, res, oldused;
-
-  /* grow to accommodate result */
-  if (b->alloc < a->used + 1) {
-    if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  oldused = b->used;
-  b->used = a->used;
-
-  {
-    register mp_digit r, rr, *tmpa, *tmpb;
-
-    /* alias for source */
-    tmpa = a->dp;
-
-    /* alias for dest */
-    tmpb = b->dp;
-
-    /* carry */
-    r = 0;
-    for (x = 0; x < a->used; x++) {
-
-      /* get what will be the *next* carry bit from the
-       * MSB of the current digit
-       */
-      rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
-
-      /* now shift up this digit, add in the carry [from the previous] */
-      *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
-
-      /* copy the carry that would be from the source
-       * digit into the next iteration
-       */
-      r = rr;
-    }
-
-    /* new leading digit? */
-    if (r != 0) {
-      /* add a MSB which is always 1 at this point */
-      *tmpb = 1;
-      ++(b->used);
-    }
-
-    /* now zero any excess digits on the destination
-     * that we didn't write to
-     */
-    tmpb = b->dp + b->used;
-    for (x = b->used; x < oldused; x++) {
-      *tmpb++ = 0;
-    }
-  }
-  b->sign = a->sign;
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
-/*
- * shifts with subtractions when the result is greater than b.
- *
- * The method is slightly modified to shift B unconditionally up to just under
- * the leading bit of b.  This saves a lot of multiple precision shifting.
- */
-static int
-mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
-{
-  int     x, bits, res;
-
-  /* how many bits of last digit does b use */
-  bits = mp_count_bits (b) % DIGIT_BIT;
-
-  if (b->used > 1) {
-     if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
-        return res;
-     }
-  } else {
-     mp_set(a, 1);
-     bits = 1;
-  }
-
-
-  /* now compute C = A * B mod b */
-  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
-    if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
-      return res;
-    }
-    if (mp_cmp_mag (a, b) != MP_LT) {
-      if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
-        return res;
-      }
-    }
-  }
-
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_MP_EXPTMOD_FAST_C
-/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
- *
- * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
- * The value of k changes based on the size of the exponent.
- *
- * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
- */
-
-static int
-mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
-{
-  mp_int  M[TAB_SIZE], res;
-  mp_digit buf, mp;
-  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
-
-  /* use a pointer to the reduction algorithm.  This allows us to use
-   * one of many reduction algorithms without modding the guts of
-   * the code with if statements everywhere.
-   */
-  int     (*redux)(mp_int*,mp_int*,mp_digit);
-
-  /* find window size */
-  x = mp_count_bits (X);
-  if (x <= 7) {
-    winsize = 2;
-  } else if (x <= 36) {
-    winsize = 3;
-  } else if (x <= 140) {
-    winsize = 4;
-  } else if (x <= 450) {
-    winsize = 5;
-  } else if (x <= 1303) {
-    winsize = 6;
-  } else if (x <= 3529) {
-    winsize = 7;
-  } else {
-    winsize = 8;
-  }
-
-#ifdef MP_LOW_MEM
-  if (winsize > 5) {
-     winsize = 5;
-  }
-#endif
-
-  /* init M array */
-  /* init first cell */
-  if ((err = mp_init(&M[1])) != MP_OKAY) {
-     return err;
-  }
-
-  /* now init the second half of the array */
-  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
-    if ((err = mp_init(&M[x])) != MP_OKAY) {
-      for (y = 1<<(winsize-1); y < x; y++) {
-        mp_clear (&M[y]);
-      }
-      mp_clear(&M[1]);
-      return err;
-    }
-  }
-
-  /* determine and setup reduction code */
-  if (redmode == 0) {
-#ifdef BN_MP_MONTGOMERY_SETUP_C
-     /* now setup montgomery  */
-     if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
-        goto LBL_M;
-     }
-#else
-     err = MP_VAL;
-     goto LBL_M;
-#endif
-
-     /* automatically pick the comba one if available (saves quite a few calls/ifs) */
-#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
-     if (((P->used * 2 + 1) < MP_WARRAY) &&
-          P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
-        redux = fast_mp_montgomery_reduce;
-     } else
-#endif
-     {
-#ifdef BN_MP_MONTGOMERY_REDUCE_C
-        /* use slower baseline Montgomery method */
-        redux = mp_montgomery_reduce;
-#else
-        err = MP_VAL;
-        goto LBL_M;
-#endif
-     }
-  } else if (redmode == 1) {
-#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
-     /* setup DR reduction for moduli of the form B**k - b */
-     mp_dr_setup(P, &mp);
-     redux = mp_dr_reduce;
-#else
-     err = MP_VAL;
-     goto LBL_M;
-#endif
-  } else {
-#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
-     /* setup DR reduction for moduli of the form 2**k - b */
-     if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
-        goto LBL_M;
-     }
-     redux = mp_reduce_2k;
-#else
-     err = MP_VAL;
-     goto LBL_M;
-#endif
-  }
-
-  /* setup result */
-  if ((err = mp_init (&res)) != MP_OKAY) {
-    goto LBL_M;
-  }
-
-  /* create M table
-   *
-
-   *
-   * The first half of the table is not computed though accept for M[0] and M[1]
-   */
-
-  if (redmode == 0) {
-#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
-     /* now we need R mod m */
-     if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
-       goto LBL_RES;
-     }
-#else
-     err = MP_VAL;
-     goto LBL_RES;
-#endif
-
-     /* now set M[1] to G * R mod m */
-     if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
-       goto LBL_RES;
-     }
-  } else {
-     mp_set(&res, 1);
-     if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
-        goto LBL_RES;
-     }
-  }
-
-  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
-  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
-    goto LBL_RES;
-  }
-
-  for (x = 0; x < (winsize - 1); x++) {
-    if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
-      goto LBL_RES;
-    }
-    if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
-      goto LBL_RES;
-    }
-  }
-
-  /* create upper table */
-  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
-    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
-      goto LBL_RES;
-    }
-    if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
-      goto LBL_RES;
-    }
-  }
-
-  /* set initial mode and bit cnt */
-  mode   = 0;
-  bitcnt = 1;
-  buf    = 0;
-  digidx = X->used - 1;
-  bitcpy = 0;
-  bitbuf = 0;
-
-  for (;;) {
-    /* grab next digit as required */
-    if (--bitcnt == 0) {
-      /* if digidx == -1 we are out of digits so break */
-      if (digidx == -1) {
-        break;
-      }
-      /* read next digit and reset bitcnt */
-      buf    = X->dp[digidx--];
-      bitcnt = (int)DIGIT_BIT;
-    }
-
-    /* grab the next msb from the exponent */
-    y     = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
-    buf <<= (mp_digit)1;
-
-    /* if the bit is zero and mode == 0 then we ignore it
-     * These represent the leading zero bits before the first 1 bit
-     * in the exponent.  Technically this opt is not required but it
-     * does lower the # of trivial squaring/reductions used
-     */
-    if (mode == 0 && y == 0) {
-      continue;
-    }
-
-    /* if the bit is zero and mode == 1 then we square */
-    if (mode == 1 && y == 0) {
-      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, mp)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      continue;
-    }
-
-    /* else we add it to the window */
-    bitbuf |= (y << (winsize - ++bitcpy));
-    mode    = 2;
-
-    if (bitcpy == winsize) {
-      /* ok window is filled so square as required and multiply  */
-      /* square first */
-      for (x = 0; x < winsize; x++) {
-        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-        if ((err = redux (&res, P, mp)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-      }
-
-      /* then multiply */
-      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, mp)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-
-      /* empty window and reset */
-      bitcpy = 0;
-      bitbuf = 0;
-      mode   = 1;
-    }
-  }
-
-  /* if bits remain then square/multiply */
-  if (mode == 2 && bitcpy > 0) {
-    /* square then multiply if the bit is set */
-    for (x = 0; x < bitcpy; x++) {
-      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, mp)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-
-      /* get next bit of the window */
-      bitbuf <<= 1;
-      if ((bitbuf & (1 << winsize)) != 0) {
-        /* then multiply */
-        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-        if ((err = redux (&res, P, mp)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-      }
-    }
-  }
-
-  if (redmode == 0) {
-     /* fixup result if Montgomery reduction is used
-      * recall that any value in a Montgomery system is
-      * actually multiplied by R mod n.  So we have
-      * to reduce one more time to cancel out the factor
-      * of R.
-      */
-     if ((err = redux(&res, P, mp)) != MP_OKAY) {
-       goto LBL_RES;
-     }
-  }
-
-  /* swap res with Y */
-  mp_exch (&res, Y);
-  err = MP_OKAY;
-LBL_RES:mp_clear (&res);
-LBL_M:
-  mp_clear(&M[1]);
-  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
-    mp_clear (&M[x]);
-  }
-  return err;
-}
-#endif
-
-
-#ifdef BN_FAST_S_MP_SQR_C
-/* the jist of squaring...
- * you do like mult except the offset of the tmpx [one that
- * starts closer to zero] can't equal the offset of tmpy.
- * So basically you set up iy like before then you min it with
- * (ty-tx) so that it never happens.  You double all those
- * you add in the inner loop
-
-After that loop you do the squares and add them in.
-*/
-
-static int
-fast_s_mp_sqr (mp_int * a, mp_int * b)
-{
-  int       olduse, res, pa, ix, iz;
-  mp_digit   W[MP_WARRAY], *tmpx;
-  mp_word   W1;
-
-  /* grow the destination as required */
-  pa = a->used + a->used;
-  if (b->alloc < pa) {
-    if ((res = mp_grow (b, pa)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* number of output digits to produce */
-  W1 = 0;
-  for (ix = 0; ix < pa; ix++) {
-      int      tx, ty, iy;
-      mp_word  _W;
-      mp_digit *tmpy;
-
-      /* clear counter */
-      _W = 0;
-
-      /* get offsets into the two bignums */
-      ty = MIN(a->used-1, ix);
-      tx = ix - ty;
-
-      /* setup temp aliases */
-      tmpx = a->dp + tx;
-      tmpy = a->dp + ty;
-
-      /* this is the number of times the loop will iterrate, essentially
-         while (tx++ < a->used && ty-- >= 0) { ... }
-       */
-      iy = MIN(a->used-tx, ty+1);
-
-      /* now for squaring tx can never equal ty
-       * we halve the distance since they approach at a rate of 2x
-       * and we have to round because odd cases need to be executed
-       */
-      iy = MIN(iy, (ty-tx+1)>>1);
-
-      /* execute loop */
-      for (iz = 0; iz < iy; iz++) {
-         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
-      }
-
-      /* double the inner product and add carry */
-      _W = _W + _W + W1;
-
-      /* even columns have the square term in them */
-      if ((ix&1) == 0) {
-         _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
-      }
-
-      /* store it */
-      W[ix] = (mp_digit)(_W & MP_MASK);
-
-      /* make next carry */
-      W1 = _W >> ((mp_word)DIGIT_BIT);
-  }
-
-  /* setup dest */
-  olduse  = b->used;
-  b->used = a->used+a->used;
-
-  {
-    mp_digit *tmpb;
-    tmpb = b->dp;
-    for (ix = 0; ix < pa; ix++) {
-      *tmpb++ = W[ix] & MP_MASK;
-    }
-
-    /* clear unused digits [that existed in the old copy of c] */
-    for (; ix < olduse; ix++) {
-      *tmpb++ = 0;
-    }
-  }
-  mp_clamp (b);
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_MP_MUL_D_C
-/* multiply by a digit */
-static int
-mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
-{
-  mp_digit u, *tmpa, *tmpc;
-  mp_word  r;
-  int      ix, res, olduse;
-
-  /* make sure c is big enough to hold a*b */
-  if (c->alloc < a->used + 1) {
-    if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* get the original destinations used count */
-  olduse = c->used;
-
-  /* set the sign */
-  c->sign = a->sign;
-
-  /* alias for a->dp [source] */
-  tmpa = a->dp;
-
-  /* alias for c->dp [dest] */
-  tmpc = c->dp;
-
-  /* zero carry */
-  u = 0;
-
-  /* compute columns */
-  for (ix = 0; ix < a->used; ix++) {
-    /* compute product and carry sum for this term */
-    r       = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
-
-    /* mask off higher bits to get a single digit */
-    *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
-
-    /* send carry into next iteration */
-    u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
-  }
-
-  /* store final carry [if any] and increment ix offset  */
-  *tmpc++ = u;
-  ++ix;
-
-  /* now zero digits above the top */
-  while (ix++ < olduse) {
-     *tmpc++ = 0;
-  }
-
-  /* set used count */
-  c->used = a->used + 1;
-  mp_clamp(c);
-
-  return MP_OKAY;
-}
-#endif

+ 1 - 0
components/wpa_supplicant/src/crypto/sha384.h

@@ -10,6 +10,7 @@
 #define SHA384_H
 #define SHA384_H
 
 
 #define SHA384_MAC_LEN 48
 #define SHA384_MAC_LEN 48
+#define SHA512_MAC_LEN 64
 
 
 int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
 int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
 		       const u8 *addr[], const size_t *len, u8 *mac);
 		       const u8 *addr[], const size_t *len, u8 *mac);

+ 167 - 27
components/wpa_supplicant/src/tls/tls.h → components/wpa_supplicant/src/crypto/tls.h

@@ -38,7 +38,26 @@ enum tls_fail_reason {
 	TLS_FAIL_SUBJECT_MISMATCH = 5,
 	TLS_FAIL_SUBJECT_MISMATCH = 5,
 	TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
 	TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
 	TLS_FAIL_BAD_CERTIFICATE = 7,
 	TLS_FAIL_BAD_CERTIFICATE = 7,
-	TLS_FAIL_SERVER_CHAIN_PROBE = 8
+	TLS_FAIL_SERVER_CHAIN_PROBE = 8,
+	TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
+	TLS_FAIL_DOMAIN_MISMATCH = 10,
+	TLS_FAIL_INSUFFICIENT_KEY_LEN = 11,
+	TLS_FAIL_DN_MISMATCH = 12,
+};
+
+
+#define TLS_MAX_ALT_SUBJECT 10
+
+struct tls_cert_data {
+	int depth;
+	const char *subject;
+	const struct wpabuf *cert;
+	const u8 *hash;
+	size_t hash_len;
+	const char *altsubject[TLS_MAX_ALT_SUBJECT];
+	int num_altsubject;
+	const char *serial_num;
+	int tod;
 };
 };
 
 
 union tls_event_data {
 union tls_event_data {
@@ -50,13 +69,7 @@ union tls_event_data {
 		const struct wpabuf *cert;
 		const struct wpabuf *cert;
 	} cert_fail;
 	} cert_fail;
 
 
-	struct {
-		int depth;
-		const char *subject;
-		const struct wpabuf *cert;
-		const u8 *hash;
-		size_t hash_len;
-	} peer_cert;
+	struct tls_cert_data peer_cert;
 
 
 	struct {
 	struct {
 		int is_local;
 		int is_local;
@@ -71,6 +84,10 @@ struct tls_config {
 	const char *pkcs11_module_path;
 	const char *pkcs11_module_path;
 	int fips_mode;
 	int fips_mode;
 	int cert_in_cb;
 	int cert_in_cb;
+	const char *openssl_ciphers;
+	unsigned int tls_session_lifetime;
+	unsigned int crl_reload_interval;
+	unsigned int tls_flags;
 
 
 	void (*event_cb)(void *ctx, enum tls_event ev,
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
 			 union tls_event_data *data);
@@ -82,8 +99,19 @@ struct tls_config {
 #define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
 #define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
 #define TLS_CONN_REQUEST_OCSP BIT(3)
 #define TLS_CONN_REQUEST_OCSP BIT(3)
 #define TLS_CONN_REQUIRE_OCSP BIT(4)
 #define TLS_CONN_REQUIRE_OCSP BIT(4)
-#define TLS_CONN_SUITEB BIT(11)
+#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
+#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
 #define TLS_CONN_EAP_FAST BIT(7)
 #define TLS_CONN_EAP_FAST BIT(7)
+#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
+#define TLS_CONN_EXT_CERT_CHECK BIT(9)
+#define TLS_CONN_REQUIRE_OCSP_ALL BIT(10)
+#define TLS_CONN_SUITEB BIT(11)
+#define TLS_CONN_SUITEB_NO_ECDH BIT(12)
+#define TLS_CONN_DISABLE_TLSv1_3 BIT(13)
+#define TLS_CONN_ENABLE_TLSv1_0 BIT(14)
+#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
+#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
+#define TLS_CONN_TEAP_ANON_DH BIT(17)
 #define TLS_CONN_USE_DEFAULT_CERT_BUNDLE BIT(18)
 #define TLS_CONN_USE_DEFAULT_CERT_BUNDLE BIT(18)
 
 
 /**
 /**
@@ -97,6 +125,19 @@ struct tls_config {
  * %NULL to allow all subjects
  * %NULL to allow all subjects
  * @altsubject_match: String to match in the alternative subject of the peer
  * @altsubject_match: String to match in the alternative subject of the peer
  * certificate or %NULL to allow all alternative subjects
  * certificate or %NULL to allow all alternative subjects
+ * @suffix_match: Semicolon deliminated string of values to suffix match against
+ * the dNSName or CN of the peer certificate or %NULL to allow all domain names.
+ * This may allow subdomains and wildcard certificates. Each domain name label
+ * must have a full case-insensitive match.
+ * @domain_match: String to match in the dNSName or CN of the peer
+ * certificate or %NULL to allow all domain names. This requires a full,
+ * case-insensitive match.
+ *
+ * More than one match string can be provided by using semicolons to
+ * separate the strings (e.g., example.org;example.com). When multiple
+ * strings are specified, a match with any one of the values is
+ * considered a sufficient match for the certificate, i.e., the
+ * conditions are ORed together.
  * @client_cert: File or reference name for client X.509 certificate in PEM or
  * @client_cert: File or reference name for client X.509 certificate in PEM or
  * DER format
  * DER format
  * @client_cert_blob: client_cert as inlined data or %NULL if not used
  * @client_cert_blob: client_cert as inlined data or %NULL if not used
@@ -119,9 +160,16 @@ struct tls_config {
  * specific for now)
  * specific for now)
  * @cert_id: the certificate's id when using engine
  * @cert_id: the certificate's id when using engine
  * @ca_cert_id: the CA certificate's id when using engine
  * @ca_cert_id: the CA certificate's id when using engine
+ * @openssl_ciphers: OpenSSL cipher configuration
+ * @openssl_ecdh_curves: OpenSSL ECDH curve configuration. %NULL for auto if
+ *	supported, empty string to disable, or a colon-separated curve list.
  * @flags: Parameter options (TLS_CONN_*)
  * @flags: Parameter options (TLS_CONN_*)
  * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
  * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
  *	or %NULL if OCSP is not enabled
  *	or %NULL if OCSP is not enabled
+ * @ocsp_stapling_response_multi: DER encoded file with cached OCSP stapling
+ *	response list (OCSPResponseList for ocsp_multi in RFC 6961) or %NULL if
+ *	ocsp_multi is not enabled
+ * @check_cert_subject: Client certificate subject name matching string
  *
  *
  * TLS connection parameters to be configured with tls_connection_set_params()
  * TLS connection parameters to be configured with tls_connection_set_params()
  * and tls_global_set_params().
  * and tls_global_set_params().
@@ -138,13 +186,18 @@ struct tls_connection_params {
 	const char *ca_path;
 	const char *ca_path;
 	const char *subject_match;
 	const char *subject_match;
 	const char *altsubject_match;
 	const char *altsubject_match;
+	const char *suffix_match;
+	const char *domain_match;
 	const char *client_cert;
 	const char *client_cert;
+	const char *client_cert2;
 	const u8 *client_cert_blob;
 	const u8 *client_cert_blob;
 	size_t client_cert_blob_len;
 	size_t client_cert_blob_len;
 	const char *private_key;
 	const char *private_key;
+	const char *private_key2;
 	const u8 *private_key_blob;
 	const u8 *private_key_blob;
 	size_t private_key_blob_len;
 	size_t private_key_blob_len;
 	const char *private_key_passwd;
 	const char *private_key_passwd;
+	const char *private_key_passwd2;
 	const char *dh_file;
 	const char *dh_file;
 	const u8 *dh_blob;
 	const u8 *dh_blob;
 	size_t dh_blob_len;
 	size_t dh_blob_len;
@@ -156,9 +209,13 @@ struct tls_connection_params {
 	const char *key_id;
 	const char *key_id;
 	const char *cert_id;
 	const char *cert_id;
 	const char *ca_cert_id;
 	const char *ca_cert_id;
+	const char *openssl_ciphers;
+	const char *openssl_ecdh_curves;
 
 
 	unsigned int flags;
 	unsigned int flags;
 	const char *ocsp_stapling_response;
 	const char *ocsp_stapling_response;
+	const char *ocsp_stapling_response_multi;
+	const char *check_cert_subject;
 };
 };
 
 
 
 
@@ -174,7 +231,7 @@ struct tls_connection_params {
  * authentication types), the TLS library wrapper should maintain a reference
  * authentication types), the TLS library wrapper should maintain a reference
  * counter and do global initialization only when moving from 0 to 1 reference.
  * counter and do global initialization only when moving from 0 to 1 reference.
  */
  */
-void * tls_init(void);
+void * tls_init(const struct tls_config *conf);
 
 
 /**
 /**
  * tls_deinit - Deinitialize TLS library
  * tls_deinit - Deinitialize TLS library
@@ -221,6 +278,18 @@ void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
  */
  */
 int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
 int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
 
 
+/**
+ * tls_connection_peer_serial_num - Fetch peer certificate serial number
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Allocated string buffer containing the peer certificate serial
+ * number or %NULL on error.
+ *
+ * The caller is responsible for freeing the returned buffer with os_free().
+ */
+char * tls_connection_peer_serial_num(void *tls_ctx,
+				      struct tls_connection *conn);
+
 /**
 /**
  * tls_connection_shutdown - Shutdown TLS connection
  * tls_connection_shutdown - Shutdown TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @tls_ctx: TLS context data from tls_init()
@@ -235,6 +304,7 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
 
 
 enum {
 enum {
+	TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN = -4,
 	TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
 	TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
 	TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
 	TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
 };
 };
@@ -245,10 +315,12 @@ enum {
  * @conn: Connection context data from tls_connection_init()
  * @conn: Connection context data from tls_connection_init()
  * @params: Connection parameters
  * @params: Connection parameters
  * Returns: 0 on success, -1 on failure,
  * Returns: 0 on success, -1 on failure,
- * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
- * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
+ * failure, or
  * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
  * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
- * PKCS#11 engine private key.
+ * PKCS#11 engine private key, or
+ * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
+ * failure.
  */
  */
 int __must_check
 int __must_check
 tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
@@ -259,10 +331,12 @@ tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
  * @tls_ctx: TLS context data from tls_init()
  * @tls_ctx: TLS context data from tls_init()
  * @params: Global TLS parameters
  * @params: Global TLS parameters
  * Returns: 0 on success, -1 on failure,
  * Returns: 0 on success, -1 on failure,
- * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
- * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
+ * failure, or
  * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
  * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
- * PKCS#11 engine private key.
+ * PKCS#11 engine private key, or
+ * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
+ * failure.
  */
  */
 int __must_check tls_global_set_params(
 int __must_check tls_global_set_params(
 	void *tls_ctx, const struct tls_connection_params *params);
 	void *tls_ctx, const struct tls_connection_params *params);
@@ -272,9 +346,11 @@ int __must_check tls_global_set_params(
  * @tls_ctx: TLS context data from tls_init()
  * @tls_ctx: TLS context data from tls_init()
  * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
  * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
  * 2 = verify CRL for all certificates
  * 2 = verify CRL for all certificates
+ * @strict: 0 = allow CRL time errors, 1 = do not allow CRL time errors
  * Returns: 0 on success, -1 on failure
  * Returns: 0 on success, -1 on failure
  */
  */
-int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
+int __must_check tls_global_set_verify(void *tls_ctx, int check_crl,
+				       int strict);
 
 
 /**
 /**
  * tls_connection_set_verify - Set certificate verification options
  * tls_connection_set_verify - Set certificate verification options
@@ -286,7 +362,7 @@ int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
  * @session_ctx_len: Length of @session_ctx in bytes.
  * @session_ctx_len: Length of @session_ctx in bytes.
  * Returns: 0 on success, -1 on failure
  * Returns: 0 on success, -1 on failure
  */
  */
-int tls_connection_set_verify(void *tls_ctx,
+int __must_check tls_connection_set_verify(void *tls_ctx,
 					   struct tls_connection *conn,
 					   struct tls_connection *conn,
 					   int verify_peer,
 					   int verify_peer,
 					   unsigned int flags,
 					   unsigned int flags,
@@ -460,6 +536,19 @@ int __must_check tls_connection_set_cipher_list(void *tls_ctx,
 						struct tls_connection *conn,
 						struct tls_connection *conn,
 						u8 *ciphers);
 						u8 *ciphers);
 
 
+/**
+ * tls_get_version - Get the current TLS version number
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @buf: Buffer for returning the TLS version number
+ * @buflen: buf size
+ * Returns: 0 on success, -1 on failure
+ *
+ * Get the currently used TLS version number.
+ */
+int __must_check tls_get_version(void *tls_ctx, struct tls_connection *conn,
+				 char *buf, size_t buflen);
+
 /**
 /**
  * tls_get_cipher - Get current cipher name
  * tls_get_cipher - Get current cipher name
  * @tls_ctx: TLS context data from tls_init()
  * @tls_ctx: TLS context data from tls_init()
@@ -527,13 +616,6 @@ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
 int tls_connection_get_write_alerts(void *tls_ctx,
 int tls_connection_get_write_alerts(void *tls_ctx,
 				    struct tls_connection *conn);
 				    struct tls_connection *conn);
 
 
-/**
- * tls_capabilities - Get supported TLS capabilities
- * @tls_ctx: TLS context data from tls_init()
- * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
- */
-unsigned int tls_capabilities(void *tls_ctx);
-
 typedef int (*tls_session_ticket_cb)
 typedef int (*tls_session_ticket_cb)
 (void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
 (void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
  const u8 *server_random, u8 *master_secret);
  const u8 *server_random, u8 *master_secret);
@@ -542,7 +624,65 @@ int __must_check  tls_connection_set_session_ticket_cb(
 	void *tls_ctx, struct tls_connection *conn,
 	void *tls_ctx, struct tls_connection *conn,
 	tls_session_ticket_cb cb, void *ctx);
 	tls_session_ticket_cb cb, void *ctx);
 
 
-int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
-             const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
+void tls_connection_set_log_cb(struct tls_connection *conn,
+			       void (*log_cb)(void *ctx, const char *msg),
+			       void *ctx);
+
+#define TLS_BREAK_VERIFY_DATA BIT(0)
+#define TLS_BREAK_SRV_KEY_X_HASH BIT(1)
+#define TLS_BREAK_SRV_KEY_X_SIGNATURE BIT(2)
+#define TLS_DHE_PRIME_511B BIT(3)
+#define TLS_DHE_PRIME_767B BIT(4)
+#define TLS_DHE_PRIME_15 BIT(5)
+#define TLS_DHE_PRIME_58B BIT(6)
+#define TLS_DHE_NON_PRIME BIT(7)
+
+void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
+
+int tls_get_library_version(char *buf, size_t buf_len);
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+				     struct wpabuf *data);
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn);
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn);
+
+void tls_connection_remove_session(struct tls_connection *conn);
+
+/**
+ * tls_get_tls_unique - Fetch "tls-unique" for channel binding
+ * @conn: Connection context data from tls_connection_init()
+ * @buf: Buffer for returning the value
+ * @max_len: Maximum length of the buffer in bytes
+ * Returns: Number of bytes written to buf or -1 on error
+ *
+ * This function can be used to fetch "tls-unique" (RFC 5929, Section 3) which
+ * is the first TLS Finished message sent in the most recent TLS handshake of
+ * the TLS connection.
+ */
+int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len);
+
+/**
+ * tls_connection_get_cipher_suite - Get current TLS cipher suite
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: TLS cipher suite of the current connection or 0 on error
+ */
+u16 tls_connection_get_cipher_suite(struct tls_connection *conn);
+
+/**
+ * tls_connection_get_peer_subject - Get peer subject
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Peer subject or %NULL if not authenticated or not available
+ */
+const char * tls_connection_get_peer_subject(struct tls_connection *conn);
+
+/**
+ * tls_connection_get_own_cert_used - Was own certificate used
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: true if own certificate was used during authentication
+ */
+bool tls_connection_get_own_cert_used(struct tls_connection *conn);
 
 
 #endif /* TLS_H */
 #endif /* TLS_H */

+ 177 - 24
components/wpa_supplicant/src/tls/tls_internal.c → components/wpa_supplicant/src/crypto/tls_internal.c

@@ -1,6 +1,6 @@
 /*
 /*
  * TLS interface functions and an internal TLS implementation
  * TLS interface functions and an internal TLS implementation
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
@@ -9,30 +9,35 @@
  * integrated TLSv1 implementation.
  * integrated TLSv1 implementation.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
-#include "crypto/sha1.h"
-#include "crypto/md5.h"
-#include "tls/tls.h"
+#include "common.h"
+#include "tls.h"
 #include "tls/tlsv1_client.h"
 #include "tls/tlsv1_client.h"
 #include "tls/tlsv1_server.h"
 #include "tls/tlsv1_server.h"
 
 
+
 static int tls_ref_count = 0;
 static int tls_ref_count = 0;
 
 
 struct tls_global {
 struct tls_global {
 	int server;
 	int server;
 	struct tlsv1_credentials *server_cred;
 	struct tlsv1_credentials *server_cred;
 	int check_crl;
 	int check_crl;
+
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+	int cert_in_cb;
 };
 };
 
 
 struct tls_connection {
 struct tls_connection {
 	struct tlsv1_client *client;
 	struct tlsv1_client *client;
 	struct tlsv1_server *server;
 	struct tlsv1_server *server;
+	struct tls_global *global;
 };
 };
 
 
 
 
-void * tls_init(void)
+void * tls_init(const struct tls_config *conf)
 {
 {
 	struct tls_global *global;
 	struct tls_global *global;
 
 
@@ -48,9 +53,14 @@ void * tls_init(void)
 	}
 	}
 	tls_ref_count++;
 	tls_ref_count++;
 
 
-	global = (struct tls_global *)os_zalloc(sizeof(*global));
+	global = os_zalloc(sizeof(*global));
 	if (global == NULL)
 	if (global == NULL)
 		return NULL;
 		return NULL;
+	if (conf) {
+		global->event_cb = conf->event_cb;
+		global->cb_ctx = conf->cb_ctx;
+		global->cert_in_cb = conf->cert_in_cb;
+	}
 
 
 	return global;
 	return global;
 }
 }
@@ -64,10 +74,12 @@ void tls_deinit(void *ssl_ctx)
 		tlsv1_client_global_deinit();
 		tlsv1_client_global_deinit();
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
 #ifdef CONFIG_TLS_INTERNAL_SERVER
-		tlsv1_cred_free(global->server_cred);
 		tlsv1_server_global_deinit();
 		tlsv1_server_global_deinit();
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
 	}
 	}
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	tlsv1_cred_free(global->server_cred);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 	os_free(global);
 	os_free(global);
 }
 }
 
 
@@ -83,9 +95,11 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
 	struct tls_connection *conn;
 	struct tls_connection *conn;
 	struct tls_global *global = tls_ctx;
 	struct tls_global *global = tls_ctx;
 
 
-	conn = (struct tls_connection *)os_zalloc(sizeof(*conn));
+	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
 	if (conn == NULL)
 		return NULL;
 		return NULL;
+	conn->global = global;
+
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 	if (!global->server) {
 	if (!global->server) {
 		conn->client = tlsv1_client_init();
 		conn->client = tlsv1_client_init();
@@ -93,6 +107,8 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
 			os_free(conn);
 			os_free(conn);
 			return NULL;
 			return NULL;
 		}
 		}
+		tlsv1_client_set_cb(conn->client, global->event_cb,
+				    global->cb_ctx, global->cert_in_cb);
 	}
 	}
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
 #ifdef CONFIG_TLS_INTERNAL_SERVER
@@ -109,6 +125,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)
 void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
 {
 {
 	if (conn == NULL)
 	if (conn == NULL)
@@ -139,6 +177,14 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
 }
 }
 
 
 
 
+char * tls_connection_peer_serial_num(void *tls_ctx,
+				      struct tls_connection *conn)
+{
+	/* TODO */
+	return NULL;
+}
+
+
 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
 {
 {
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
@@ -162,10 +208,52 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 	if (conn->client == NULL)
 	if (conn->client == NULL)
 		return -1;
 		return -1;
 
 
+	if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+		wpa_printf(MSG_INFO,
+			   "TLS: tls_ext_cert_check=1 not supported");
+		return -1;
+	}
+
 	cred = tlsv1_cred_alloc();
 	cred = tlsv1_cred_alloc();
 	if (cred == NULL)
 	if (cred == NULL)
 		return -1;
 		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 (params->openssl_ecdh_curves) {
+		wpa_printf(MSG_INFO, "TLS: openssl_ecdh_curves not supported");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
 	if (tlsv1_set_ca_cert(cred, params->ca_cert,
 	if (tlsv1_set_ca_cert(cred, params->ca_cert,
 			      params->ca_cert_blob, params->ca_cert_blob_len,
 			      params->ca_cert_blob, params->ca_cert_blob_len,
 			      params->ca_path)) {
 			      params->ca_path)) {
@@ -193,13 +281,19 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 		return -1;
 		return -1;
 	}
 	}
 
 
+	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
+			       params->dh_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
 	if (tlsv1_client_set_cred(conn->client, cred) < 0) {
 	if (tlsv1_client_set_cred(conn->client, cred) < 0) {
 		tlsv1_cred_free(cred);
 		tlsv1_cred_free(cred);
 		return -1;
 		return -1;
 	}
 	}
 
 
-	tlsv1_client_set_time_checks(
-		conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
+	tlsv1_client_set_flags(conn->client, params->flags);
 
 
 	return 0;
 	return 0;
 #else /* CONFIG_TLS_INTERNAL_CLIENT */
 #else /* CONFIG_TLS_INTERNAL_CLIENT */
@@ -215,6 +309,9 @@ int tls_global_set_params(void *tls_ctx,
 	struct tls_global *global = tls_ctx;
 	struct tls_global *global = tls_ctx;
 	struct tlsv1_credentials *cred;
 	struct tlsv1_credentials *cred;
 
 
+	if (params->check_cert_subject)
+		return -1; /* not yet supported */
+
 	/* Currently, global parameters are only set when running in server
 	/* Currently, global parameters are only set when running in server
 	 * mode. */
 	 * mode. */
 	global->server = 1;
 	global->server = 1;
@@ -251,6 +348,13 @@ int tls_global_set_params(void *tls_ctx,
 		return -1;
 		return -1;
 	}
 	}
 
 
+	if (params->ocsp_stapling_response)
+		cred->ocsp_stapling_response =
+			os_strdup(params->ocsp_stapling_response);
+	if (params->ocsp_stapling_response_multi)
+		cred->ocsp_stapling_response_multi =
+			os_strdup(params->ocsp_stapling_response_multi);
+
 	return 0;
 	return 0;
 #else /* CONFIG_TLS_INTERNAL_SERVER */
 #else /* CONFIG_TLS_INTERNAL_SERVER */
 	return -1;
 	return -1;
@@ -258,7 +362,7 @@ int tls_global_set_params(void *tls_ctx,
 }
 }
 
 
 
 
-int tls_global_set_verify(void *tls_ctx, int check_crl)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
 {
 {
 	struct tls_global *global = tls_ctx;
 	struct tls_global *global = tls_ctx;
 	global->check_crl = check_crl;
 	global->check_crl = check_crl;
@@ -279,7 +383,7 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
 
 
 
 
 int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
 int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
-			    struct tls_random *data)
+			      struct tls_random *data)
 {
 {
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 	if (conn->client)
 	if (conn->client)
@@ -328,15 +432,15 @@ static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
 
 
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 	if (conn->client) {
 	if (conn->client) {
-		ret = tlsv1_client_prf(conn->client, label,
-				       server_random_first,
+		ret = tlsv1_client_prf(conn->client, label, context,
+				       context_len, server_random_first,
 				       _out, skip + out_len);
 				       _out, skip + out_len);
 	}
 	}
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
 #ifdef CONFIG_TLS_INTERNAL_SERVER
 	if (conn->server) {
 	if (conn->server) {
-		ret = tlsv1_server_prf(conn->server, label,
-				       server_random_first,
+		ret = tlsv1_server_prf(conn->server, label, context,
+				       context_len, server_random_first,
 				       _out, skip + out_len);
 				       _out, skip + out_len);
 	}
 	}
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
@@ -394,9 +498,8 @@ struct wpabuf * tls_connection_handshake2(void *tls_ctx,
 				     in_data ? wpabuf_head(in_data) : NULL,
 				     in_data ? wpabuf_head(in_data) : NULL,
 				     in_data ? wpabuf_len(in_data) : 0,
 				     in_data ? wpabuf_len(in_data) : 0,
 				     &res_len, &ad, &ad_len, need_more_data);
 				     &res_len, &ad, &ad_len, need_more_data);
-	if (res == NULL) {
+	if (res == NULL)
 		return NULL;
 		return NULL;
-	}
 	out = wpabuf_alloc_ext_data(res, res_len);
 	out = wpabuf_alloc_ext_data(res, res_len);
 	if (out == NULL) {
 	if (out == NULL) {
 		os_free(res);
 		os_free(res);
@@ -576,6 +679,19 @@ 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)
+{
+	if (conn == NULL)
+		return -1;
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_version(conn->client, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+	return -1;
+}
+
+
 int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
 int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
 		   char *buf, size_t buflen)
 		   char *buf, size_t buflen)
 {
 {
@@ -616,12 +732,20 @@ int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
 
 
 int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
 int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
 {
 {
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_failed(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 	return 0;
 	return 0;
 }
 }
 
 
 
 
 int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
 int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
 {
 {
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_read_alerts(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 	return 0;
 	return 0;
 }
 }
 
 
@@ -629,13 +753,13 @@ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
 int tls_connection_get_write_alerts(void *tls_ctx,
 int tls_connection_get_write_alerts(void *tls_ctx,
 				    struct tls_connection *conn)
 				    struct tls_connection *conn)
 {
 {
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_write_alerts(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 	return 0;
 	return 0;
 }
 }
 
 
-unsigned int tls_capabilities(void *tls_ctx)
-{
-	return 0;
-}
 
 
 int tls_connection_set_session_ticket_cb(void *tls_ctx,
 int tls_connection_set_session_ticket_cb(void *tls_ctx,
 					 struct tls_connection *conn,
 					 struct tls_connection *conn,
@@ -656,3 +780,32 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
 #endif /* CONFIG_TLS_INTERNAL_SERVER */
 	return -1;
 	return -1;
 }
 }
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+	return os_snprintf(buf, buf_len, "internal");
+}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+				     struct wpabuf *data)
+{
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+	return NULL;
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+}

+ 2 - 4
components/wpa_supplicant/src/eap_peer/eap.c

@@ -30,7 +30,7 @@
 #include "crypto/sha256.h"
 #include "crypto/sha256.h"
 
 
 #include "utils/ext_password.h"
 #include "utils/ext_password.h"
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_config.h"
 #include "eap_peer/eap_config.h"
 #include "eap_peer/eap.h"
 #include "eap_peer/eap.h"
@@ -296,12 +296,10 @@ int eap_peer_register_methods(void)
 		ret = eap_peer_mschapv2_register();
 		ret = eap_peer_mschapv2_register();
 #endif
 #endif
 
 
-#ifndef USE_MBEDTLS_CRYPTO
 #ifdef EAP_FAST
 #ifdef EAP_FAST
 	if (ret == 0)
 	if (ret == 0)
 		ret = eap_peer_fast_register();
 		ret = eap_peer_fast_register();
 #endif
 #endif
-#endif
 
 
 #ifdef EAP_PEAP
 #ifdef EAP_PEAP
 	if (ret == 0)
 	if (ret == 0)
@@ -620,7 +618,7 @@ int eap_peer_config_init(
 			config_methods[allowed_method_count].vendor = EAP_VENDOR_IETF;
 			config_methods[allowed_method_count].vendor = EAP_VENDOR_IETF;
 			config_methods[allowed_method_count++].method = EAP_TYPE_TLS;
 			config_methods[allowed_method_count++].method = EAP_TYPE_TLS;
 		}
 		}
-#ifndef USE_MBEDTLS_CRYPTO
+#ifdef EAP_FAST
 		if (g_wpa_pac_file) {
 		if (g_wpa_pac_file) {
 			//set EAP-FAST
 			//set EAP-FAST
 			config_methods[allowed_method_count].vendor = EAP_VENDOR_IETF;
 			config_methods[allowed_method_count].vendor = EAP_VENDOR_IETF;

+ 1 - 1
components/wpa_supplicant/src/eap_peer/eap_fast.c

@@ -9,7 +9,7 @@
 #include "includes.h"
 #include "includes.h"
 
 
 #include "common.h"
 #include "common.h"
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
 #include "eap_peer/eap_tlv_common.h"
 #include "eap_peer/eap_tlv_common.h"
 #include "eap_peer/eap_methods.h"
 #include "eap_peer/eap_methods.h"

+ 1 - 1
components/wpa_supplicant/src/eap_peer/eap_fast_common.c

@@ -10,7 +10,7 @@
 
 
 #include "common.h"
 #include "common.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "eap_peer/eap_defs.h"
 #include "eap_peer/eap_defs.h"
 #include "eap_peer/eap_tlv_common.h"
 #include "eap_peer/eap_tlv_common.h"
 #include "eap_peer/eap_fast_common.h"
 #include "eap_peer/eap_fast_common.h"

+ 1 - 1
components/wpa_supplicant/src/eap_peer/eap_mschapv2.c

@@ -12,7 +12,7 @@
 #include "rsn_supp/wpa.h"
 #include "rsn_supp/wpa.h"
 #include "crypto/random.h"
 #include "crypto/random.h"
 #include "crypto/ms_funcs.h"
 #include "crypto/ms_funcs.h"
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_defs.h"
 #include "eap_peer/eap_defs.h"
 #include "eap_peer/eap_tls_common.h"
 #include "eap_peer/eap_tls_common.h"

+ 1 - 1
components/wpa_supplicant/src/eap_peer/eap_peap.c

@@ -10,7 +10,7 @@
 #ifdef EAP_PEAP
 #ifdef EAP_PEAP
 #include "utils/common.h"
 #include "utils/common.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "eap_peer/eap_tlv_common.h"
 #include "eap_peer/eap_tlv_common.h"
 #include "eap_peer/eap_peap_common.h"
 #include "eap_peer/eap_peap_common.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_i.h"

+ 1 - 1
components/wpa_supplicant/src/eap_peer/eap_tls.c

@@ -9,7 +9,7 @@
 
 
 #ifdef EAP_TLS
 #ifdef EAP_TLS
 #include "utils/common.h"
 #include "utils/common.h"
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_defs.h"
 #include "eap_peer/eap_defs.h"
 #include "eap_peer/eap_tls_common.h"
 #include "eap_peer/eap_tls_common.h"

+ 1 - 1
components/wpa_supplicant/src/eap_peer/eap_tls_common.c

@@ -10,7 +10,7 @@
 
 
 #include "utils/common.h"
 #include "utils/common.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_i.h"
 #include "eap_peer/eap_tls_common.h"
 #include "eap_peer/eap_tls_common.h"
 #include "eap_peer/eap_config.h"
 #include "eap_peer/eap_config.h"

+ 1 - 1
components/wpa_supplicant/src/eap_peer/eap_ttls.c

@@ -12,7 +12,7 @@
 #include "utils/common.h"
 #include "utils/common.h"
 #include "crypto/ms_funcs.h"
 #include "crypto/ms_funcs.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
-#include "tls/tls.h"
+#include "crypto/tls.h"
 #include "eap_peer/chap.h"
 #include "eap_peer/chap.h"
 #include "eap_peer/eap.h"
 #include "eap_peer/eap.h"
 #include "eap_peer/eap_ttls.h"
 #include "eap_peer/eap_ttls.h"

+ 457 - 13
components/wpa_supplicant/src/tls/asn1.c

@@ -1,15 +1,172 @@
 /*
 /*
  * ASN.1 DER parsing
  * ASN.1 DER parsing
- * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
+
+#include "common.h"
+#include "utils/wpabuf.h"
+#include "asn1.h"
+
+const struct asn1_oid asn1_sha1_oid = {
+	.oid = { 1, 3, 14, 3, 2, 26 },
+	.len = 6
+};
+
+const struct asn1_oid asn1_sha256_oid = {
+	.oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
+	.len = 9
+};
+
+const struct asn1_oid asn1_ec_public_key_oid = {
+	.oid = { 1, 2, 840, 10045, 2, 1 },
+	.len = 6
+};
+
+const struct asn1_oid asn1_prime256v1_oid = {
+	.oid = { 1, 2, 840, 10045, 3, 1, 7 },
+	.len = 7
+};
+
+const struct asn1_oid asn1_secp384r1_oid = {
+	.oid = { 1, 3, 132, 0, 34 },
+	.len = 5
+};
+
+const struct asn1_oid asn1_secp521r1_oid = {
+	.oid = { 1, 3, 132, 0, 35 },
+	.len = 5
+};
+
+const struct asn1_oid asn1_brainpoolP256r1_oid = {
+	.oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 },
+	.len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP384r1_oid = {
+	.oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 },
+	.len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP512r1_oid = {
+	.oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 },
+	.len = 10
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = {
+	.oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 },
+	.len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = {
+	.oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 },
+	.len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = {
+	.oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 },
+	.len = 9
+};
+
+const struct asn1_oid asn1_pbkdf2_oid = {
+	.oid = { 1, 2, 840, 113549, 1, 5, 12 },
+	.len = 7
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = {
+	.oid = { 1, 2, 840, 113549, 2, 9 },
+	.len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = {
+	.oid = { 1, 2, 840, 113549, 2, 10 },
+	.len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = {
+	.oid = { 1, 2, 840, 113549, 2, 11 },
+	.len = 6
+};
+
+const struct asn1_oid asn1_dpp_config_params_oid = {
+	.oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 },
+	.len = 10
+};
+
+const struct asn1_oid asn1_dpp_asymmetric_key_package_oid = {
+	.oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 },
+	.len = 10
+};
+
+
+static int asn1_valid_der_boolean(struct asn1_hdr *hdr)
+{
+	/* Enforce DER requirements for a single way of encoding a BOOLEAN */
+	if (hdr->length != 1) {
+		wpa_printf(MSG_DEBUG, "ASN.1: Unexpected BOOLEAN length (%u)",
+			   hdr->length);
+		return 0;
+	}
+
+	if (hdr->payload[0] != 0 && hdr->payload[0] != 0xff) {
+		wpa_printf(MSG_DEBUG,
+			   "ASN.1: Invalid BOOLEAN value 0x%x (DER requires 0 or 0xff)",
+			   hdr->payload[0]);
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static int asn1_valid_der(struct asn1_hdr *hdr)
+{
+	if (hdr->class != ASN1_CLASS_UNIVERSAL)
+		return 1;
+	if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr))
+		return 0;
+	if (hdr->tag == ASN1_TAG_NULL && hdr->length != 0)
+		return 0;
+
+	/* Check for allowed primitive/constructed values */
+	if (hdr->constructed &&
+	    (hdr->tag == ASN1_TAG_BOOLEAN ||
+	     hdr->tag == ASN1_TAG_INTEGER ||
+	     hdr->tag == ASN1_TAG_NULL ||
+	     hdr->tag == ASN1_TAG_OID ||
+	     hdr->tag == ANS1_TAG_RELATIVE_OID ||
+	     hdr->tag == ASN1_TAG_REAL ||
+	     hdr->tag == ASN1_TAG_ENUMERATED ||
+	     hdr->tag == ASN1_TAG_BITSTRING ||
+	     hdr->tag == ASN1_TAG_OCTETSTRING ||
+	     hdr->tag == ASN1_TAG_NUMERICSTRING ||
+	     hdr->tag == ASN1_TAG_PRINTABLESTRING ||
+	     hdr->tag == ASN1_TAG_T61STRING ||
+	     hdr->tag == ASN1_TAG_VIDEOTEXSTRING ||
+	     hdr->tag == ASN1_TAG_VISIBLESTRING ||
+	     hdr->tag == ASN1_TAG_IA5STRING ||
+	     hdr->tag == ASN1_TAG_GRAPHICSTRING ||
+	     hdr->tag == ASN1_TAG_GENERALSTRING ||
+	     hdr->tag == ASN1_TAG_UNIVERSALSTRING ||
+	     hdr->tag == ASN1_TAG_UTF8STRING ||
+	     hdr->tag == ASN1_TAG_BMPSTRING ||
+	     hdr->tag == ASN1_TAG_CHARACTERSTRING ||
+	     hdr->tag == ASN1_TAG_UTCTIME ||
+	     hdr->tag == ASN1_TAG_GENERALIZEDTIME ||
+	     hdr->tag == ASN1_TAG_TIME))
+		return 0;
+	if (!hdr->constructed &&
+	    (hdr->tag == ASN1_TAG_SEQUENCE ||
+	     hdr->tag == ASN1_TAG_SET))
+		return 0;
+
+	return 1;
+}
 
 
-#include "utils/common.h"
-#include "tls/asn1.h"
 
 
 int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
 int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
 {
 {
@@ -20,26 +177,51 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
 	pos = buf;
 	pos = buf;
 	end = buf + len;
 	end = buf + len;
 
 
+	if (pos >= end) {
+		wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
+		return -1;
+	}
 	hdr->identifier = *pos++;
 	hdr->identifier = *pos++;
 	hdr->class = hdr->identifier >> 6;
 	hdr->class = hdr->identifier >> 6;
 	hdr->constructed = !!(hdr->identifier & (1 << 5));
 	hdr->constructed = !!(hdr->identifier & (1 << 5));
 
 
 	if ((hdr->identifier & 0x1f) == 0x1f) {
 	if ((hdr->identifier & 0x1f) == 0x1f) {
+		size_t ext_len = 0;
+
 		hdr->tag = 0;
 		hdr->tag = 0;
+		if (pos == end || (*pos & 0x7f) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "ASN.1: Invalid extended tag (first octet has to be included with at least one nonzero bit for the tag value)");
+			return -1;
+		}
 		do {
 		do {
 			if (pos >= end) {
 			if (pos >= end) {
 				wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
 				wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
 					   "underflow");
 					   "underflow");
 				return -1;
 				return -1;
 			}
 			}
+			ext_len++;
 			tmp = *pos++;
 			tmp = *pos++;
-			wpa_printf(MSG_DEBUG, "ASN.1: Extended tag data: "
+			wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
 				   "0x%02x", tmp);
 				   "0x%02x", tmp);
 			hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
 			hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
 		} while (tmp & 0x80);
 		} while (tmp & 0x80);
+		wpa_printf(MSG_MSGDUMP, "ASN.1: Extended Tag: 0x%x (len=%zu)",
+			   hdr->tag, ext_len);
+		if ((hdr->class != ASN1_CLASS_PRIVATE && hdr->tag < 31) ||
+		    ext_len * 7 > sizeof(hdr->tag) * 8) {
+			wpa_printf(MSG_DEBUG,
+				   "ASN.1: Invalid or unsupported (too large) extended Tag: 0x%x (len=%zu)",
+				   hdr->tag, ext_len);
+			return -1;
+		}
 	} else
 	} else
 		hdr->tag = hdr->identifier & 0x1f;
 		hdr->tag = hdr->identifier & 0x1f;
 
 
+	if (pos >= end) {
+		wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
+		return -1;
+	}
 	tmp = *pos++;
 	tmp = *pos++;
 	if (tmp & 0x80) {
 	if (tmp & 0x80) {
 		if (tmp == 0xff) {
 		if (tmp == 0xff) {
@@ -49,6 +231,11 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
 		}
 		}
 		tmp &= 0x7f; /* number of subsequent octets */
 		tmp &= 0x7f; /* number of subsequent octets */
 		hdr->length = 0;
 		hdr->length = 0;
+		if (tmp == 0 || pos == end || *pos == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "ASN.1: Definite long form of the length does not start with a nonzero value");
+			return -1;
+		}
 		if (tmp > 4) {
 		if (tmp > 4) {
 			wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
 			wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
 			return -1;
 			return -1;
@@ -61,6 +248,11 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
 			}
 			}
 			hdr->length = (hdr->length << 8) | *pos++;
 			hdr->length = (hdr->length << 8) | *pos++;
 		}
 		}
+		if (hdr->length < 128) {
+			wpa_printf(MSG_DEBUG,
+				   "ASN.1: Definite long form of the length used with too short length");
+			return -1;
+		}
 	} else {
 	} else {
 		/* Short form - length 0..127 in one octet */
 		/* Short form - length 0..127 in one octet */
 		hdr->length = tmp;
 		hdr->length = tmp;
@@ -72,10 +264,29 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
 	}
 	}
 
 
 	hdr->payload = pos;
 	hdr->payload = pos;
+
+	if (!asn1_valid_der(hdr)) {
+		asn1_print_hdr(hdr, "ASN.1: Invalid DER encoding: ");
+		return -1;
+	}
 	return 0;
 	return 0;
 }
 }
 
 
 
 
+void asn1_print_hdr(const struct asn1_hdr *hdr, const char *title)
+{
+	wpa_printf(MSG_DEBUG, "%sclass %d constructed %d tag 0x%x",
+		   title, hdr->class, hdr->constructed, hdr->tag);
+}
+
+
+void asn1_unexpected(const struct asn1_hdr *hdr, const char *title)
+{
+	wpa_printf(MSG_DEBUG, "%s - found class %d constructed %d tag 0x%x",
+		   title, hdr->class, hdr->constructed, hdr->tag);
+}
+
+
 int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
 int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
 {
 {
 	const u8 *pos, *end;
 	const u8 *pos, *end;
@@ -125,12 +336,9 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
 {
 {
 	struct asn1_hdr hdr;
 	struct asn1_hdr hdr;
 
 
-	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
-		return -1;
-
-	if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
-		wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
-			   "tag 0x%x", hdr.class, hdr.tag);
+	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 ||
+	    !asn1_is_oid(&hdr)) {
+		asn1_unexpected(&hdr, "ASN.1: Expected OID");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -140,7 +348,7 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
 }
 }
 
 
 
 
-void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
+void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len)
 {
 {
 	char *pos = buf;
 	char *pos = buf;
 	size_t i;
 	size_t i;
@@ -155,7 +363,7 @@ void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
 		ret = os_snprintf(pos, buf + len - pos,
 		ret = os_snprintf(pos, buf + len - pos,
 				  "%s%lu",
 				  "%s%lu",
 				  i == 0 ? "" : ".", oid->oid[i]);
 				  i == 0 ? "" : ".", oid->oid[i]);
-		if (ret < 0 || ret >= buf + len - pos)
+		if (os_snprintf_error(buf + len - pos, ret))
 			break;
 			break;
 		pos += ret;
 		pos += ret;
 	}
 	}
@@ -204,3 +412,239 @@ unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
 
 
 	return val;
 	return val;
 }
 }
+
+
+int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
+{
+	size_t i;
+
+	if (a->len != b->len)
+		return 0;
+
+	for (i = 0; i < a->len; i++) {
+		if (a->oid[i] != b->oid[i])
+			return 0;
+	}
+
+	return 1;
+}
+
+
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next)
+{
+	struct asn1_hdr hdr;
+	size_t left;
+	const u8 *pos;
+	int value;
+
+	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 ||
+	    !asn1_is_integer(&hdr)) {
+		asn1_unexpected(&hdr, "ASN.1: Expected INTEGER");
+		return -1;
+	}
+
+	*next = hdr.payload + hdr.length;
+	pos = hdr.payload;
+	left = hdr.length;
+	if (left > sizeof(value)) {
+		wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)",
+			   hdr.length);
+		return -1;
+	}
+	value = 0;
+	while (left) {
+		value <<= 8;
+		value |= *pos++;
+		left--;
+	}
+
+	*integer = value;
+	return 0;
+}
+
+
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+		      const u8 **next)
+{
+	if (asn1_get_next(buf, len, hdr) < 0 || !asn1_is_sequence(hdr)) {
+		asn1_unexpected(hdr, "ASN.1: Expected SEQUENCE");
+		return -1;
+	}
+
+	if (next)
+		*next = hdr->payload + hdr->length;
+	return 0;
+}
+
+
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+		    const u8 **params, size_t *params_len, const u8 **next)
+{
+	const u8 *pos = buf, *end = buf + len;
+	struct asn1_hdr hdr;
+
+	/*
+	 * AlgorithmIdentifier ::= SEQUENCE {
+	 *     algorithm            OBJECT IDENTIFIER,
+	 *     parameters           ANY DEFINED BY algorithm OPTIONAL}
+	 */
+	if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 ||
+	    asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0)
+		return -1;
+
+	if (params && params_len) {
+		*params = pos;
+		*params_len = hdr.payload + hdr.length - pos;
+	}
+
+	return 0;
+}
+
+
+void asn1_put_integer(struct wpabuf *buf, int val)
+{
+	u8 bin[4];
+	int zeros;
+
+	WPA_PUT_BE32(bin, val);
+	zeros = 0;
+	while (zeros < 3 && bin[zeros] == 0)
+		zeros++;
+	wpabuf_put_u8(buf, ASN1_TAG_INTEGER);
+	wpabuf_put_u8(buf, 4 - zeros);
+	wpabuf_put_data(buf, &bin[zeros], 4 - zeros);
+}
+
+
+static void asn1_put_len(struct wpabuf *buf, size_t len)
+{
+	if (len <= 0x7f) {
+		wpabuf_put_u8(buf, len);
+	} else if (len <= 0xff) {
+		wpabuf_put_u8(buf, 0x80 | 1);
+		wpabuf_put_u8(buf, len);
+	} else if (len <= 0xffff) {
+		wpabuf_put_u8(buf, 0x80 | 2);
+		wpabuf_put_be16(buf, len);
+	} else if (len <= 0xffffff) {
+		wpabuf_put_u8(buf, 0x80 | 3);
+		wpabuf_put_be24(buf, len);
+	} else {
+		wpabuf_put_u8(buf, 0x80 | 4);
+		wpabuf_put_be32(buf, len);
+	}
+}
+
+
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val)
+{
+	wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING);
+	asn1_put_len(buf, wpabuf_len(val));
+	wpabuf_put_buf(buf, val);
+}
+
+
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid)
+{
+	u8 *len;
+	size_t i;
+
+	if (oid->len < 2)
+		return;
+	wpabuf_put_u8(buf, ASN1_TAG_OID);
+	len = wpabuf_put(buf, 1);
+	wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]);
+	for (i = 2; i < oid->len; i++) {
+		unsigned long val = oid->oid[i];
+		u8 bytes[8];
+		int idx = 0;
+
+		while (val) {
+			bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f);
+			idx++;
+			val >>= 7;
+		}
+		if (idx == 0) {
+			bytes[idx] = 0;
+			idx = 1;
+		}
+		while (idx > 0) {
+			idx--;
+			wpabuf_put_u8(buf, bytes[idx]);
+		}
+	}
+	*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+		  size_t len)
+{
+	wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag);
+	asn1_put_len(buf, len);
+}
+
+
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload)
+{
+	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE,
+		     wpabuf_len(payload));
+	wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload)
+{
+	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET,
+		     wpabuf_len(payload));
+	wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_utf8string(struct wpabuf *buf, const char *val)
+{
+	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING,
+		     os_strlen(val));
+	wpabuf_put_str(buf, val);
+}
+
+
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+				  const struct wpabuf *params)
+{
+	struct wpabuf *buf;
+	size_t len;
+
+	/*
+	 * AlgorithmIdentifier ::= SEQUENCE {
+	 *    algorithm		OBJECT IDENTIFIER,
+	 *    parameters	ANY DEFINED BY algorithm OPTIONAL}
+	 */
+
+	len = 100;
+	if (params)
+		len += wpabuf_len(params);
+	buf = wpabuf_alloc(len);
+	if (!buf)
+		return NULL;
+	asn1_put_oid(buf, oid);
+	if (params)
+		wpabuf_put_buf(buf, params);
+	return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag)
+{
+	struct wpabuf *res;
+
+	if (!buf)
+		return NULL;
+	res = wpabuf_alloc(10 + wpabuf_len(buf));
+	if (res) {
+		asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf));
+		wpabuf_put_buf(res, buf);
+	}
+	wpabuf_clear_free(buf);
+	return res;
+}

+ 149 - 3
components/wpa_supplicant/src/tls/asn1.h

@@ -20,13 +20,15 @@
 #define ASN1_TAG_EXTERNAL	0x08 /* not yet parsed */
 #define ASN1_TAG_EXTERNAL	0x08 /* not yet parsed */
 #define ASN1_TAG_REAL		0x09 /* not yet parsed */
 #define ASN1_TAG_REAL		0x09 /* not yet parsed */
 #define ASN1_TAG_ENUMERATED	0x0A /* not yet parsed */
 #define ASN1_TAG_ENUMERATED	0x0A /* not yet parsed */
+#define ASN1_TAG_EMBEDDED_PDV	0x0B /* not yet parsed */
 #define ASN1_TAG_UTF8STRING	0x0C /* not yet parsed */
 #define ASN1_TAG_UTF8STRING	0x0C /* not yet parsed */
 #define ANS1_TAG_RELATIVE_OID	0x0D
 #define ANS1_TAG_RELATIVE_OID	0x0D
+#define ASN1_TAG_TIME		0x0E
 #define ASN1_TAG_SEQUENCE	0x10 /* shall be constructed */
 #define ASN1_TAG_SEQUENCE	0x10 /* shall be constructed */
 #define ASN1_TAG_SET		0x11
 #define ASN1_TAG_SET		0x11
 #define ASN1_TAG_NUMERICSTRING	0x12 /* not yet parsed */
 #define ASN1_TAG_NUMERICSTRING	0x12 /* not yet parsed */
 #define ASN1_TAG_PRINTABLESTRING	0x13
 #define ASN1_TAG_PRINTABLESTRING	0x13
-#define ASN1_TAG_TG1STRING	0x14 /* not yet parsed */
+#define ASN1_TAG_T61STRING	0x14 /* not yet parsed */
 #define ASN1_TAG_VIDEOTEXSTRING	0x15 /* not yet parsed */
 #define ASN1_TAG_VIDEOTEXSTRING	0x15 /* not yet parsed */
 #define ASN1_TAG_IA5STRING	0x16
 #define ASN1_TAG_IA5STRING	0x16
 #define ASN1_TAG_UTCTIME	0x17
 #define ASN1_TAG_UTCTIME	0x17
@@ -35,7 +37,8 @@
 #define ASN1_TAG_VISIBLESTRING	0x1A
 #define ASN1_TAG_VISIBLESTRING	0x1A
 #define ASN1_TAG_GENERALSTRING	0x1B /* not yet parsed */
 #define ASN1_TAG_GENERALSTRING	0x1B /* not yet parsed */
 #define ASN1_TAG_UNIVERSALSTRING	0x1C /* not yet parsed */
 #define ASN1_TAG_UNIVERSALSTRING	0x1C /* not yet parsed */
-#define ASN1_TAG_BMPSTRING	0x1D /* not yet parsed */
+#define ASN1_TAG_CHARACTERSTRING	0x1D /* not yet parsed */
+#define ASN1_TAG_BMPSTRING	0x1E /* not yet parsed */
 
 
 #define ASN1_CLASS_UNIVERSAL		0
 #define ASN1_CLASS_UNIVERSAL		0
 #define ASN1_CLASS_APPLICATION		1
 #define ASN1_CLASS_APPLICATION		1
@@ -57,10 +60,153 @@ struct asn1_oid {
 
 
 
 
 int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
 int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
+void asn1_print_hdr(const struct asn1_hdr *hdr, const char *title);
+void asn1_unexpected(const struct asn1_hdr *hdr, const char *title);
 int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid);
 int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid);
 int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
 int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
 		 const u8 **next);
 		 const u8 **next);
-void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len);
+void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len);
 unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
 unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
+int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b);
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next);
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+		      const u8 **next);
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+		    const u8 **params, size_t *params_len, const u8 **next);
+void asn1_put_integer(struct wpabuf *buf, int val);
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val);
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid);
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+		  size_t len);
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_utf8string(struct wpabuf *buf, const char *val);
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+				  const struct wpabuf *params);
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag);
+
+static inline bool asn1_is_oid(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_OID;
+}
+
+static inline bool asn1_is_boolean(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_BOOLEAN;
+}
+
+static inline bool asn1_is_integer(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_INTEGER;
+}
+
+static inline bool asn1_is_enumerated(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_ENUMERATED;
+}
+
+static inline bool asn1_is_sequence(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_SEQUENCE;
+}
+
+static inline bool asn1_is_set(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_SET;
+}
+
+static inline bool asn1_is_octetstring(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_OCTETSTRING;
+}
+
+static inline bool asn1_is_bitstring(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_BITSTRING;
+}
+
+static inline bool asn1_is_utctime(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_UTCTIME;
+}
+
+static inline bool asn1_is_generalizedtime(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_GENERALIZEDTIME;
+}
+
+static inline bool asn1_is_string_type(const struct asn1_hdr *hdr)
+{
+	if (hdr->class != ASN1_CLASS_UNIVERSAL || hdr->constructed)
+		return false;
+	return hdr->tag == ASN1_TAG_UTF8STRING ||
+		hdr->tag == ASN1_TAG_NUMERICSTRING ||
+		hdr->tag == ASN1_TAG_PRINTABLESTRING ||
+		hdr->tag == ASN1_TAG_T61STRING ||
+		hdr->tag == ASN1_TAG_VIDEOTEXSTRING ||
+		hdr->tag == ASN1_TAG_IA5STRING ||
+		hdr->tag == ASN1_TAG_GRAPHICSTRING ||
+		hdr->tag == ASN1_TAG_VISIBLESTRING ||
+		hdr->tag == ASN1_TAG_GENERALSTRING ||
+		hdr->tag == ASN1_TAG_UNIVERSALSTRING ||
+		hdr->tag == ASN1_TAG_CHARACTERSTRING ||
+		hdr->tag == ASN1_TAG_BMPSTRING;
+}
+
+static inline bool asn1_is_bmpstring(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_BMPSTRING;
+}
+
+static inline bool asn1_is_utf8string(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_UTF8STRING;
+}
+
+static inline bool asn1_is_null(const struct asn1_hdr *hdr)
+{
+	return hdr->class == ASN1_CLASS_UNIVERSAL &&
+		hdr->tag == ASN1_TAG_NULL;
+}
+
+static inline bool asn1_is_cs_tag(const struct asn1_hdr *hdr, unsigned int tag)
+{
+	return hdr->class == ASN1_CLASS_CONTEXT_SPECIFIC &&
+		hdr->tag == tag;
+}
+
+extern const struct asn1_oid asn1_sha1_oid;
+extern const struct asn1_oid asn1_sha256_oid;
+extern const struct asn1_oid asn1_ec_public_key_oid;
+extern const struct asn1_oid asn1_prime256v1_oid;
+extern const struct asn1_oid asn1_secp384r1_oid;
+extern const struct asn1_oid asn1_secp521r1_oid;
+extern const struct asn1_oid asn1_brainpoolP256r1_oid;
+extern const struct asn1_oid asn1_brainpoolP384r1_oid;
+extern const struct asn1_oid asn1_brainpoolP512r1_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_pbkdf2_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid;
+extern const struct asn1_oid asn1_dpp_config_params_oid;
+extern const struct asn1_oid asn1_dpp_asymmetric_key_package_oid;
 
 
 #endif /* ASN1_H */
 #endif /* ASN1_H */

+ 2 - 8
components/wpa_supplicant/src/tls/bignum.h

@@ -2,14 +2,8 @@
  * Big number math
  * Big number math
  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2006, 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.
  */
  */
 
 
 #ifndef BIGNUM_H
 #ifndef BIGNUM_H

+ 168 - 24
components/wpa_supplicant/src/tls/pkcs1.c

@@ -1,16 +1,18 @@
 /*
 /*
  * PKCS #1 (RSA Encryption)
  * PKCS #1 (RSA Encryption)
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
-#include "tls/rsa.h"
-#include "tls/pkcs1.h"
+#include "common.h"
+#include "crypto/crypto.h"
+#include "rsa.h"
+#include "asn1.h"
+#include "pkcs1.h"
 
 
 
 
 static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
 static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
@@ -113,6 +115,11 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
 		pos++;
 		pos++;
 	if (pos == end)
 	if (pos == end)
 		return -1;
 		return -1;
+	if (pos - out - 2 < 8) {
+		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
+		wpa_printf(MSG_INFO, "LibTomCrypt: Too short padding");
+		return -1;
+	}
 	pos++;
 	pos++;
 
 
 	*outlen -= pos - out;
 	*outlen -= pos - out;
@@ -142,46 +149,41 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
 	 * BT = 00 or 01
 	 * BT = 00 or 01
 	 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
 	 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
 	 * k = length of modulus in octets
 	 * k = length of modulus in octets
+	 *
+	 * Based on 10.1.3, "The block type shall be 01" for a signature.
 	 */
 	 */
 
 
 	if (len < 3 + 8 + 16 /* min hash len */ ||
 	if (len < 3 + 8 + 16 /* min hash len */ ||
-	    plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
+	    plain[0] != 0x00 || plain[1] != 0x01) {
 		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
 		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
 			   "structure");
 			   "structure");
+		wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
 		return -1;
 		return -1;
 	}
 	}
 
 
 	pos = plain + 3;
 	pos = plain + 3;
-	if (plain[1] == 0x00) {
-		/* BT = 00 */
-		if (plain[2] != 0x00) {
-			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
-				   "PS (BT=00)");
-			return -1;
-		}
-		while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
-			pos++;
-	} else {
-		/* BT = 01 */
-		if (plain[2] != 0xff) {
-			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
-				   "PS (BT=01)");
-			return -1;
-		}
-		while (pos < plain + len && *pos == 0xff)
-			pos++;
+	/* BT = 01 */
+	if (plain[2] != 0xff) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+			   "PS (BT=01)");
+		wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
+		return -1;
 	}
 	}
+	while (pos < plain + len && *pos == 0xff)
+		pos++;
 
 
 	if (pos - plain - 2 < 8) {
 	if (pos - plain - 2 < 8) {
 		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
 		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
 		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
 		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
 			   "padding");
 			   "padding");
+		wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
 		return -1;
 		return -1;
 	}
 	}
 
 
 	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
 	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
 		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
 		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
 			   "structure (2)");
 			   "structure (2)");
+		wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
 		return -1;
 		return -1;
 	}
 	}
 	pos++;
 	pos++;
@@ -193,3 +195,145 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
 
 
 	return 0;
 	return 0;
 }
 }
+
+
+int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
+		      const u8 *s, size_t s_len,
+		      const struct asn1_oid *hash_alg,
+		      const u8 *hash, size_t hash_len)
+{
+	int res;
+	u8 *decrypted;
+	size_t decrypted_len;
+	const u8 *pos, *end, *next, *da_end;
+	struct asn1_hdr hdr;
+	struct asn1_oid oid;
+
+	decrypted = os_malloc(s_len);
+	if (decrypted == NULL)
+		return -1;
+	decrypted_len = s_len;
+	res = crypto_public_key_decrypt_pkcs1(pk, s, s_len, decrypted,
+					      &decrypted_len);
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "PKCS #1: RSA decrypt failed");
+		os_free(decrypted);
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "Decrypted(S)", decrypted, decrypted_len);
+
+	/*
+	 * PKCS #1 v1.5, 10.1.2:
+	 *
+	 * DigestInfo ::= SEQUENCE {
+	 *     digestAlgorithm DigestAlgorithmIdentifier,
+	 *     digest Digest
+	 * }
+	 *
+	 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+	 *
+	 * Digest ::= OCTET STRING
+	 *
+	 */
+	if (asn1_get_next(decrypted, decrypted_len, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #1: Expected SEQUENCE (DigestInfo)");
+		os_free(decrypted);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "PKCS #1: DigestInfo",
+		    hdr.payload, hdr.length);
+
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	/*
+	 * X.509:
+	 * AlgorithmIdentifier ::= SEQUENCE {
+	 *     algorithm            OBJECT IDENTIFIER,
+	 *     parameters           ANY DEFINED BY algorithm OPTIONAL
+	 * }
+	 */
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #1: Expected SEQUENCE (AlgorithmIdentifier)");
+		os_free(decrypted);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "PKCS #1: DigestAlgorithmIdentifier",
+		    hdr.payload, hdr.length);
+	da_end = hdr.payload + hdr.length;
+
+	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #1: Failed to parse digestAlgorithm");
+		os_free(decrypted);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "PKCS #1: Digest algorithm parameters",
+		    next, da_end - next);
+
+	/*
+	 * RFC 5754: The correct encoding for the SHA2 algorithms would be to
+	 * omit the parameters, but there are implementation that encode these
+	 * as a NULL element. Allow these two cases and reject anything else.
+	 */
+	if (da_end > next &&
+	    (asn1_get_next(next, da_end - next, &hdr) < 0 ||
+	     !asn1_is_null(&hdr) ||
+	     hdr.payload + hdr.length != da_end)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #1: Unexpected digest algorithm parameters");
+		os_free(decrypted);
+		return -1;
+	}
+
+	if (!asn1_oid_equal(&oid, hash_alg)) {
+		char txt[100], txt2[100];
+		asn1_oid_to_str(&oid, txt, sizeof(txt));
+		asn1_oid_to_str(hash_alg, txt2, sizeof(txt2));
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #1: Hash alg OID mismatch: was %s, expected %s",
+			   txt, txt2);
+		os_free(decrypted);
+		return -1;
+	}
+
+	/* Digest ::= OCTET STRING */
+	pos = da_end;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #1: Expected OCTETSTRING (Digest)");
+		os_free(decrypted);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "PKCS #1: Decrypted Digest",
+		    hdr.payload, hdr.length);
+
+	if (hdr.length != hash_len ||
+	    os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
+		wpa_printf(MSG_INFO, "PKCS #1: Digest value does not match calculated hash");
+		os_free(decrypted);
+		return -1;
+	}
+
+	os_free(decrypted);
+
+	if (hdr.payload + hdr.length != decrypted + decrypted_len) {
+		wpa_printf(MSG_INFO,
+			   "PKCS #1: Extra data after signature - reject");
+
+		wpa_hexdump(MSG_DEBUG, "PKCS #1: Extra data",
+			    hdr.payload + hdr.length,
+			    decrypted + decrypted_len - hdr.payload -
+			    hdr.length);
+		return -1;
+	}
+
+	return 0;
+}

+ 7 - 0
components/wpa_supplicant/src/tls/pkcs1.h

@@ -9,6 +9,9 @@
 #ifndef PKCS1_H
 #ifndef PKCS1_H
 #define PKCS1_H
 #define PKCS1_H
 
 
+struct crypto_public_key;
+struct asn1_oid;
+
 int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
 int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
 		  int use_private, const u8 *in, size_t inlen,
 		  int use_private, const u8 *in, size_t inlen,
 		  u8 *out, size_t *outlen);
 		  u8 *out, size_t *outlen);
@@ -18,5 +21,9 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
 int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
 int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
 			     const u8 *crypt, size_t crypt_len,
 			     const u8 *crypt, size_t crypt_len,
 			     u8 *plain, size_t *plain_len);
 			     u8 *plain, size_t *plain_len);
+int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
+		      const u8 *s, size_t s_len,
+		      const struct asn1_oid *hash_alg,
+		      const u8 *hash, size_t hash_len);
 
 
 #endif /* PKCS1_H */
 #endif /* PKCS1_H */

+ 431 - 39
components/wpa_supplicant/src/tls/pkcs5.c

@@ -1,48 +1,263 @@
 /*
 /*
  * PKCS #5 (Password-based Encryption)
  * PKCS #5 (Password-based Encryption)
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
+#include "common.h"
 #include "crypto/crypto.h"
 #include "crypto/crypto.h"
 #include "crypto/md5.h"
 #include "crypto/md5.h"
-#include "tls/asn1.h"
-#include "tls/pkcs5.h"
+#include "crypto/sha1.h"
+#include "asn1.h"
+#include "pkcs5.h"
 
 
-#include "eap_peer/eap_i.h"
 
 
 struct pkcs5_params {
 struct pkcs5_params {
 	enum pkcs5_alg {
 	enum pkcs5_alg {
 		PKCS5_ALG_UNKNOWN,
 		PKCS5_ALG_UNKNOWN,
-		PKCS5_ALG_MD5_DES_CBC
+		PKCS5_ALG_MD5_DES_CBC,
+		PKCS5_ALG_PBES2,
+		PKCS5_ALG_SHA1_3DES_CBC,
 	} alg;
 	} alg;
-	u8 salt[8];
+	u8 salt[64];
 	size_t salt_len;
 	size_t salt_len;
 	unsigned int iter_count;
 	unsigned int iter_count;
+	enum pbes2_enc_alg {
+		PBES2_ENC_ALG_UNKNOWN,
+		PBES2_ENC_ALG_DES_EDE3_CBC,
+	} enc_alg;
+	u8 iv[8];
+	size_t iv_len;
 };
 };
 
 
 
 
+static int oid_is_rsadsi(struct asn1_oid *oid)
+{
+	return oid->len >= 4 &&
+		oid->oid[0] == 1 /* iso */ &&
+		oid->oid[1] == 2 /* member-body */ &&
+		oid->oid[2] == 840 /* us */ &&
+		oid->oid[3] == 113549 /* rsadsi */;
+}
+
+
+static int pkcs5_is_oid(struct asn1_oid *oid, unsigned long alg)
+{
+	return oid->len == 7 &&
+		oid_is_rsadsi(oid) &&
+		oid->oid[4] == 1 /* pkcs */ &&
+		oid->oid[5] == 5 /* pkcs-5 */ &&
+		oid->oid[6] == alg;
+}
+
+
+static int enc_alg_is_oid(struct asn1_oid *oid, unsigned long alg)
+{
+	return oid->len == 6 &&
+		oid_is_rsadsi(oid) &&
+		oid->oid[4] == 3 /* encryptionAlgorithm */ &&
+		oid->oid[5] == alg;
+}
+
+
+static int pkcs12_is_pbe_oid(struct asn1_oid *oid, unsigned long alg)
+{
+	return oid->len == 8 &&
+		oid_is_rsadsi(oid) &&
+		oid->oid[4] == 1 /* pkcs */ &&
+		oid->oid[5] == 12 /* pkcs-12 */ &&
+		oid->oid[6] == 1 /* pkcs-12PbeIds */ &&
+		oid->oid[7] == alg;
+}
+
+
 static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
 static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
 {
 {
-	if (oid->len == 7 &&
-	    oid->oid[0] == 1 /* iso */ &&
-	    oid->oid[1] == 2 /* member-body */ &&
-	    oid->oid[2] == 840 /* us */ &&
-	    oid->oid[3] == 113549 /* rsadsi */ &&
-	    oid->oid[4] == 1 /* pkcs */ &&
-	    oid->oid[5] == 5 /* pkcs-5 */ &&
-	    oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */)
+	if (pkcs5_is_oid(oid, 3)) /* pbeWithMD5AndDES-CBC (PBES1) */
 		return PKCS5_ALG_MD5_DES_CBC;
 		return PKCS5_ALG_MD5_DES_CBC;
-
+	if (pkcs12_is_pbe_oid(oid, 3)) /* pbeWithSHAAnd3-KeyTripleDES-CBC */
+		return PKCS5_ALG_SHA1_3DES_CBC;
+	if (pkcs5_is_oid(oid, 13)) /* id-PBES2 (PBES2) */
+		return PKCS5_ALG_PBES2;
 	return PKCS5_ALG_UNKNOWN;
 	return PKCS5_ALG_UNKNOWN;
 }
 }
 
 
 
 
+static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
+				  const u8 *enc_alg_end)
+{
+	struct asn1_hdr hdr;
+	const u8 *end, *kdf_end;
+	struct asn1_oid oid;
+	char obuf[80];
+
+	/*
+	 * RFC 2898, Ch. A.4
+	 *
+	 * PBES2-params ::= SEQUENCE {
+	 *     keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+	 *     encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
+	 *
+	 * PBES2-KDFs ALGORITHM-IDENTIFIER ::=
+	 *     { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
+	 */
+
+	if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #5: Expected SEQUENCE (PBES2-params)");
+		return -1;
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #5: Expected SEQUENCE (keyDerivationFunc)");
+		return -1;
+	}
+
+	pos = hdr.payload;
+	kdf_end = end = hdr.payload + hdr.length;
+
+	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #5: Failed to parse OID (keyDerivationFunc algorithm)");
+		return -1;
+	}
+
+	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+	wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 keyDerivationFunc algorithm %s",
+		   obuf);
+	if (!pkcs5_is_oid(&oid, 12)) /* id-PBKDF2 */ {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #5: Unsupported PBES2 keyDerivationFunc algorithm %s",
+			   obuf);
+		return -1;
+	}
+
+	/*
+	 * RFC 2898, C.
+	 *
+	 * PBKDF2-params ::= SEQUENCE {
+	 *     salt CHOICE {
+	 *       specified OCTET STRING,
+	 *       otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+	 *     },
+	 *     iterationCount INTEGER (1..MAX),
+	 *     keyLength INTEGER (1..MAX) OPTIONAL,
+	 *     prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
+	 *     algid-hmacWithSHA1
+	 * }
+	 */
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #5: Expected SEQUENCE (PBKDF2-params)");
+		return -1;
+	}
+
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	/* For now, only support the salt CHOICE specified (OCTET STRING) */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr) ||
+	    hdr.length > sizeof(params->salt)) {
+		asn1_unexpected(&hdr,
+				"PKCS #5: Expected OCTET STRING (salt.specified)");
+		return -1;
+	}
+	pos = hdr.payload + hdr.length;
+	os_memcpy(params->salt, hdr.payload, hdr.length);
+	params->salt_len = hdr.length;
+	wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", params->salt, params->salt_len);
+
+	/* iterationCount INTEGER */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
+		asn1_unexpected(&hdr, "PKCS #5: Expected INTEGER");
+		return -1;
+	}
+	if (hdr.length == 1) {
+		params->iter_count = *hdr.payload;
+	} else if (hdr.length == 2) {
+		params->iter_count = WPA_GET_BE16(hdr.payload);
+	} else if (hdr.length == 4) {
+		params->iter_count = WPA_GET_BE32(hdr.payload);
+	} else {
+		wpa_hexdump(MSG_DEBUG,
+			    "PKCS #5: Unsupported INTEGER value (iterationCount)",
+			    hdr.payload, hdr.length);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
+		   params->iter_count);
+	if (params->iter_count == 0 || params->iter_count > 0xffff) {
+		wpa_printf(MSG_INFO, "PKCS #5: Unsupported iterationCount=0x%x",
+			   params->iter_count);
+		return -1;
+	}
+
+	/* For now, ignore optional keyLength and prf */
+
+	pos = kdf_end;
+
+	/* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} */
+
+	if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #5: Expected SEQUENCE (encryptionScheme)");
+		return -1;
+	}
+
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #5: Failed to parse OID (encryptionScheme algorithm)");
+		return -1;
+	}
+
+	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+	wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 encryptionScheme algorithm %s",
+		   obuf);
+	if (enc_alg_is_oid(&oid, 7)) {
+		params->enc_alg = PBES2_ENC_ALG_DES_EDE3_CBC;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #5: Unsupported PBES2 encryptionScheme algorithm %s",
+			   obuf);
+		return -1;
+	}
+
+	/*
+	 * RFC 2898, B.2.2:
+	 * The parameters field associated with this OID in an
+	 * AlgorithmIdentifier shall have type OCTET STRING (SIZE(8)),
+	 * specifying the initialization vector for CBC mode.
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr) || hdr.length != 8) {
+		asn1_unexpected(&hdr,
+				"PKCS #5: Expected OCTET STRING (SIZE(8)) (IV)");
+		return -1;
+	}
+	os_memcpy(params->iv, hdr.payload, hdr.length);
+	params->iv_len = hdr.length;
+	wpa_hexdump(MSG_DEBUG, "PKCS #5: IV", params->iv, params->iv_len);
+
+	return 0;
+}
+
+
 static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
 static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
 			    struct pkcs5_params *params)
 			    struct pkcs5_params *params)
 {
 {
@@ -72,32 +287,39 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
 		return -1;
 		return -1;
 	}
 	}
 
 
+	if (params->alg == PKCS5_ALG_PBES2)
+		return pkcs5_get_params_pbes2(params, pos, enc_alg_end);
+
+	/* PBES1 */
+
 	/*
 	/*
 	 * PKCS#5, Section 8
 	 * PKCS#5, Section 8
 	 * PBEParameter ::= SEQUENCE {
 	 * PBEParameter ::= SEQUENCE {
 	 *   salt OCTET STRING SIZE(8),
 	 *   salt OCTET STRING SIZE(8),
 	 *   iterationCount INTEGER }
 	 *   iterationCount INTEGER }
+	 *
+	 * Note: The same implementation can be used to parse the PKCS #12
+	 * version described in RFC 7292, C:
+	 * pkcs-12PbeParams ::= SEQUENCE {
+	 *     salt        OCTET STRING,
+	 *     iterations  INTEGER
+	 * }
 	 */
 	 */
 
 
 	if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
 	if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
-			   "(PBEParameter) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #5: Expected SEQUENCE (PBEParameter)");
 		return -1;
 		return -1;
 	}
 	}
 	pos = hdr.payload;
 	pos = hdr.payload;
 	end = hdr.payload + hdr.length;
 	end = hdr.payload + hdr.length;
 
 
-	/* salt OCTET STRING SIZE(8) */
+	/* salt OCTET STRING SIZE(8) (PKCS #5) or OCTET STRING (PKCS #12) */
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_OCTETSTRING ||
-	    hdr.length != 8) {
-		wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
-			   "(salt) - found class %d tag 0x%x size %d",
-			   hdr.class, hdr.tag, hdr.length);
+	    !asn1_is_octetstring(&hdr) || hdr.length > sizeof(params->salt)) {
+		asn1_unexpected(&hdr,
+				"PKCS #5: Expected OCTETSTRING SIZE(8) (salt)");
 		return -1;
 		return -1;
 	}
 	}
 	pos = hdr.payload + hdr.length;
 	pos = hdr.payload + hdr.length;
@@ -108,9 +330,8 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
 
 
 	/* iterationCount INTEGER */
 	/* iterationCount INTEGER */
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found "
-			   "class %d tag 0x%x", hdr.class, hdr.tag);
+	    !asn1_is_integer(&hdr)) {
+		asn1_unexpected(&hdr, "PKCS #5: Expected INTEGER");
 		return -1;
 		return -1;
 	}
 	}
 	if (hdr.length == 1)
 	if (hdr.length == 1)
@@ -137,6 +358,174 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
 }
 }
 
 
 
 
+static struct crypto_cipher *
+pkcs5_crypto_init_pbes2(struct pkcs5_params *params, const char *passwd)
+{
+	u8 key[24];
+
+	if (params->enc_alg != PBES2_ENC_ALG_DES_EDE3_CBC ||
+	    params->iv_len != 8)
+		return NULL;
+
+	wpa_hexdump_ascii_key(MSG_DEBUG, "PKCS #5: PBES2 password for PBKDF2",
+			      passwd, os_strlen(passwd));
+	wpa_hexdump(MSG_DEBUG, "PKCS #5: PBES2 salt for PBKDF2",
+		    params->salt, params->salt_len);
+	wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 PBKDF2 iterations: %u",
+		   params->iter_count);
+	if (pbkdf2_sha1(passwd, params->salt, params->salt_len,
+			params->iter_count, key, sizeof(key)) < 0)
+		return NULL;
+	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES EDE3 key", key, sizeof(key));
+	wpa_hexdump(MSG_DEBUG, "PKCS #5: DES IV", params->iv, params->iv_len);
+
+	return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, params->iv,
+				  key, sizeof(key));
+}
+
+
+static void add_byte_array_mod(u8 *a, const u8 *b, size_t len)
+{
+	size_t i;
+	unsigned int carry = 0;
+
+	for (i = len - 1; i < len; i--) {
+		carry = carry + a[i] + b[i];
+		a[i] = carry & 0xff;
+		carry >>= 8;
+	}
+}
+
+
+static int pkcs12_key_gen(const u8 *pw, size_t pw_len, const u8 *salt,
+			  size_t salt_len, u8 id, unsigned int iter,
+			  size_t out_len, u8 *out)
+{
+	unsigned int u, v, S_len, P_len, i;
+	u8 *D = NULL, *I = NULL, *B = NULL, *pos;
+	int res = -1;
+
+	/* RFC 7292, B.2 */
+	u = SHA1_MAC_LEN;
+	v = 64;
+
+	/* D = copies of ID */
+	D = os_malloc(v);
+	if (!D)
+		goto done;
+	os_memset(D, id, v);
+
+	/* S = copies of salt; P = copies of password, I = S || P */
+	S_len = v * ((salt_len + v - 1) / v);
+	P_len = v * ((pw_len + v - 1) / v);
+	I = os_malloc(S_len + P_len);
+	if (!I)
+		goto done;
+	pos = I;
+	if (salt_len) {
+		for (i = 0; i < S_len; i++)
+			*pos++ = salt[i % salt_len];
+	}
+	if (pw_len) {
+		for (i = 0; i < P_len; i++)
+			*pos++ = pw[i % pw_len];
+	}
+
+	B = os_malloc(v);
+	if (!B)
+		goto done;
+
+	for (;;) {
+		u8 hash[SHA1_MAC_LEN];
+		const u8 *addr[2];
+		size_t len[2];
+
+		addr[0] = D;
+		len[0] = v;
+		addr[1] = I;
+		len[1] = S_len + P_len;
+		if (sha1_vector(2, addr, len, hash) < 0)
+			goto done;
+
+		addr[0] = hash;
+		len[0] = SHA1_MAC_LEN;
+		for (i = 1; i < iter; i++) {
+			if (sha1_vector(1, addr, len, hash) < 0)
+				goto done;
+		}
+
+		if (out_len <= u) {
+			os_memcpy(out, hash, out_len);
+			res = 0;
+			goto done;
+		}
+
+		os_memcpy(out, hash, u);
+		out += u;
+		out_len -= u;
+
+		/* I_j = (I_j + B + 1) mod 2^(v*8) */
+		/* B = copies of Ai (final hash value) */
+		for (i = 0; i < v; i++)
+			B[i] = hash[i % u];
+		inc_byte_array(B, v);
+		for (i = 0; i < S_len + P_len; i += v)
+			add_byte_array_mod(&I[i], B, v);
+	}
+
+done:
+	os_free(B);
+	os_free(I);
+	os_free(D);
+	return res;
+}
+
+
+#define PKCS12_ID_ENC 1
+#define PKCS12_ID_IV 2
+#define PKCS12_ID_MAC 3
+
+static struct crypto_cipher *
+pkcs12_crypto_init_sha1(struct pkcs5_params *params, const char *passwd)
+{
+	unsigned int i;
+	u8 *pw;
+	size_t pw_len;
+	u8 key[24];
+	u8 iv[8];
+
+	if (params->alg != PKCS5_ALG_SHA1_3DES_CBC)
+		return NULL;
+
+	pw_len = passwd ? os_strlen(passwd) : 0;
+	pw = os_malloc(2 * (pw_len + 1));
+	if (!pw)
+		return NULL;
+	if (pw_len) {
+		for (i = 0; i <= pw_len; i++)
+			WPA_PUT_BE16(&pw[2 * i], passwd[i]);
+		pw_len = 2 * (pw_len + 1);
+	}
+
+	if (pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
+			   PKCS12_ID_ENC, params->iter_count,
+			   sizeof(key), key) < 0 ||
+	    pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
+			   PKCS12_ID_IV, params->iter_count,
+			   sizeof(iv), iv) < 0) {
+		os_free(pw);
+		return NULL;
+	}
+
+	os_free(pw);
+
+	wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES key", key, sizeof(key));
+	wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES IV", iv, sizeof(iv));
+
+	return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, iv, key, sizeof(key));
+}
+
+
 static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
 static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
 						const char *passwd)
 						const char *passwd)
 {
 {
@@ -145,9 +534,14 @@ static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
 	const u8 *addr[2];
 	const u8 *addr[2];
 	size_t len[2];
 	size_t len[2];
 
 
-	if (params->alg != PKCS5_ALG_MD5_DES_CBC) {
+	if (params->alg == PKCS5_ALG_PBES2)
+		return pkcs5_crypto_init_pbes2(params, passwd);
+
+	if (params->alg == PKCS5_ALG_SHA1_3DES_CBC)
+		return pkcs12_crypto_init_sha1(params, passwd);
+
+	if (params->alg != PKCS5_ALG_MD5_DES_CBC)
 		return NULL;
 		return NULL;
-	}
 
 
 	addr[0] = (const u8 *) passwd;
 	addr[0] = (const u8 *) passwd;
 	len[0] = os_strlen(passwd);
 	len[0] = os_strlen(passwd);
@@ -166,14 +560,14 @@ static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
 	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
 	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
 
 
 	return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
 	return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
-
 }
 }
 
 
+
 u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
 u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
 		   const u8 *enc_data, size_t enc_data_len,
 		   const u8 *enc_data, size_t enc_data_len,
 		   const char *passwd, size_t *data_len)
 		   const char *passwd, size_t *data_len)
 {
 {
-	struct crypto_cipher *ctx = NULL;
+	struct crypto_cipher *ctx;
 	u8 *eb, pad;
 	u8 *eb, pad;
 	struct pkcs5_params params;
 	struct pkcs5_params params;
 	unsigned int i;
 	unsigned int i;
@@ -184,7 +578,6 @@ u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
 	}
 	}
 
 
 	ctx = pkcs5_crypto_init(&params, passwd);
 	ctx = pkcs5_crypto_init(&params, passwd);
-
 	if (ctx == NULL) {
 	if (ctx == NULL) {
 		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
 		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
 		return NULL;
 		return NULL;
@@ -204,13 +597,12 @@ u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	if ((int)crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
+	if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
 		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
 		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
 		crypto_cipher_deinit(ctx);
 		crypto_cipher_deinit(ctx);
 		os_free(eb);
 		os_free(eb);
 		return NULL;
 		return NULL;
 	}
 	}
-
 	crypto_cipher_deinit(ctx);
 	crypto_cipher_deinit(ctx);
 
 
 	pad = eb[enc_data_len - 1];
 	pad = eb[enc_data_len - 1];

+ 28 - 46
components/wpa_supplicant/src/tls/pkcs8.c

@@ -6,14 +6,15 @@
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
+
+#include "common.h"
+#include "asn1.h"
+#include "bignum.h"
+#include "rsa.h"
+#include "pkcs5.h"
+#include "pkcs8.h"
 
 
-#include "utils/common.h"
-#include "tls/asn1.h"
-#include "tls/bignum.h"
-#include "tls/rsa.h"
-#include "tls/pkcs5.h"
-#include "tls/pkcs8.h"
 
 
 struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
 struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
 {
 {
@@ -26,22 +27,17 @@ struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
 	/* PKCS #8, Chapter 6 */
 	/* PKCS #8, Chapter 6 */
 
 
 	/* PrivateKeyInfo ::= SEQUENCE */
 	/* PrivateKeyInfo ::= SEQUENCE */
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
-			   "header (SEQUENCE); assume PKCS #8 not used");
+	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #8: Does not start with PKCS #8 header (SEQUENCE)");
 		return NULL;
 		return NULL;
 	}
 	}
 	pos = hdr.payload;
 	pos = hdr.payload;
 	end = pos + hdr.length;
 	end = pos + hdr.length;
 
 
 	/* version Version (Version ::= INTEGER) */
 	/* version Version (Version ::= INTEGER) */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
-			   "class %d tag 0x%x; assume PKCS #8 not used",
-			   hdr.class, hdr.tag);
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
+		asn1_unexpected(&hdr, "PKCS #8: Expected INTEGER");
 		return NULL;
 		return NULL;
 	}
 	}
 
 
@@ -67,13 +63,9 @@ struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
 
 
 	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
 	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
 	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
 	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
-			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
-			   "assume PKCS #8 not used",
-			   hdr.class, hdr.tag);
+	if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #8: Expected SEQUENCE (AlgorithmIdentifier); assume PKCS #8 not used");
 		return NULL;
 		return NULL;
 	}
 	}
 
 
@@ -103,11 +95,9 @@ struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
 
 
 	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
 	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_OCTETSTRING) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
-			   "(privateKey) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #8: Expected OCTETSTRING (privateKey)");
 		return NULL;
 		return NULL;
 	}
 	}
 	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
 	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
@@ -138,12 +128,9 @@ pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
 	 * EncryptedData ::= OCTET STRING
 	 * EncryptedData ::= OCTET STRING
 	 */
 	 */
 
 
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
-			   "header (SEQUENCE); assume encrypted PKCS #8 not "
-			   "used");
+	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #8: Does not start with PKCS #8 header (SEQUENCE); assume encrypted PKCS #8 not used");
 		return NULL;
 		return NULL;
 	}
 	}
 	pos = hdr.payload;
 	pos = hdr.payload;
@@ -151,12 +138,9 @@ pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
 
 
 	/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
 	/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
-			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
-			   "assume encrypted PKCS #8 not used",
-			   hdr.class, hdr.tag);
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #8: Expected SEQUENCE (AlgorithmIdentifier); assume encrypted PKCS #8 not used");
 		return NULL;
 		return NULL;
 	}
 	}
 	enc_alg = hdr.payload;
 	enc_alg = hdr.payload;
@@ -165,11 +149,9 @@ pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
 
 
 	/* encryptedData EncryptedData */
 	/* encryptedData EncryptedData */
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_OCTETSTRING) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
-			   "(encryptedData) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #8: Expected OCTETSTRING (encryptedData)");
 		return NULL;
 		return NULL;
 	}
 	}
 
 

+ 6 - 15
components/wpa_supplicant/src/tls/rsa.c

@@ -37,9 +37,8 @@ static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,
 		return NULL;
 		return NULL;
 
 
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d "
-			   "tag 0x%x", hdr.class, hdr.tag);
+	    !asn1_is_integer(&hdr)) {
+		asn1_unexpected(&hdr, "RSA: Expected INTEGER");
 		return NULL;
 		return NULL;
 	}
 	}
 
 
@@ -84,12 +83,8 @@ crypto_rsa_import_public_key(const u8 *buf, size_t len)
 	 * }
 	 * }
 	 */
 	 */
 
 
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
-			   "(public key) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
+	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr, "RSA: Expected SEQUENCE (public key)");
 		goto error;
 		goto error;
 	}
 	}
 	pos = hdr.payload;
 	pos = hdr.payload;
@@ -191,12 +186,8 @@ crypto_rsa_import_private_key(const u8 *buf, size_t len)
 	 *
 	 *
 	 * Version ::= INTEGER -- shall be 0 for this version of the standard
 	 * Version ::= INTEGER -- shall be 0 for this version of the standard
 	 */
 	 */
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
-			   "(public key) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
+	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr, "RSA: Expected SEQUENCE (public key)");
 		goto error;
 		goto error;
 	}
 	}
 	pos = hdr.payload;
 	pos = hdr.payload;

+ 155 - 84
components/wpa_supplicant/src/tls/tlsv1_client.c

@@ -1,20 +1,21 @@
 /*
 /*
  * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
  * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
+#include "common.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
-#include "tls/tls.h"
-#include "tls/tlsv1_common.h"
-#include "tls/tlsv1_record.h"
-#include "tls/tlsv1_client.h"
-#include "tls/tlsv1_client_i.h"
+#include "crypto/tls.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
 
 
 /* TODO:
 /* TODO:
  * Support for a message fragmented across several records (RFC 2246, 6.2.1)
  * Support for a message fragmented across several records (RFC 2246, 6.2.1)
@@ -37,9 +38,33 @@ void tlsv1_client_free_dh(struct tlsv1_client *conn)
 }
 }
 
 
 
 
-int tls_derive_pre_master_secret(u8 *pre_master_secret)
+u16 tls_client_highest_ver(struct tlsv1_client *conn)
 {
 {
-	WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
+	u16 tls_version = TLS_VERSION;
+
+	/* Pick the highest locally enabled TLS version */
+#ifdef CONFIG_TLSV12
+	if ((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
+	    tls_version == TLS_VERSION_1_2)
+		tls_version = TLS_VERSION_1_1;
+#endif /* CONFIG_TLSV12 */
+#ifdef CONFIG_TLSV11
+	if ((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
+	    tls_version == TLS_VERSION_1_1)
+		tls_version = TLS_VERSION_1;
+#endif /* CONFIG_TLSV11 */
+	if ((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
+	    tls_version == TLS_VERSION_1)
+		return 0;
+
+	return tls_version;
+}
+
+
+int tls_derive_pre_master_secret(struct tlsv1_client *conn,
+				 u8 *pre_master_secret)
+{
+	WPA_PUT_BE16(pre_master_secret, tls_client_highest_ver(conn));
 	if (os_get_random(pre_master_secret + 2,
 	if (os_get_random(pre_master_secret + 2,
 			  TLS_PRE_MASTER_SECRET_LEN - 2))
 			  TLS_PRE_MASTER_SECRET_LEN - 2))
 		return -1;
 		return -1;
@@ -110,7 +135,6 @@ int tls_derive_keys(struct tlsv1_client *conn,
 		pos += conn->rl.iv_size;
 		pos += conn->rl.iv_size;
 		/* server_write_IV */
 		/* server_write_IV */
 		os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
 		os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
-		pos += conn->rl.iv_size;
 	} else {
 	} else {
 		/*
 		/*
 		 * Use IV field to set the mask value for TLS v1.1. A fixed
 		 * Use IV field to set the mask value for TLS v1.1. A fixed
@@ -245,7 +269,7 @@ failed:
 					      conn->alert_description,
 					      conn->alert_description,
 					      out_len);
 					      out_len);
 	} else if (msg == NULL) {
 	} else if (msg == NULL) {
-		msg = (u8 *)os_zalloc(1);
+		msg = os_zalloc(1);
 		*out_len = 0;
 		*out_len = 0;
 	}
 	}
 
 
@@ -444,7 +468,7 @@ struct tlsv1_client * tlsv1_client_init(void)
 	size_t count;
 	size_t count;
 	u16 *suites;
 	u16 *suites;
 
 
-	conn = (struct tlsv1_client *)os_zalloc(sizeof(*conn));
+	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
 	if (conn == NULL)
 		return NULL;
 		return NULL;
 
 
@@ -459,13 +483,16 @@ struct tlsv1_client * tlsv1_client_init(void)
 
 
 	count = 0;
 	count = 0;
 	suites = conn->cipher_suites;
 	suites = conn->cipher_suites;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
-#ifdef CONFIG_DES3
+	suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-#endif //CONFIG_DES3
 	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
 	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
 	conn->num_cipher_suites = count;
 	conn->num_cipher_suites = count;
@@ -491,6 +518,7 @@ void tlsv1_client_deinit(struct tlsv1_client *conn)
 	tlsv1_client_free_dh(conn);
 	tlsv1_client_free_dh(conn);
 	tlsv1_cred_free(conn->cred);
 	tlsv1_cred_free(conn->cred);
 	wpabuf_free(conn->partial_input);
 	wpabuf_free(conn->partial_input);
+	x509_certificate_chain_free(conn->server_cert);
 	os_free(conn);
 	os_free(conn);
 }
 }
 
 
@@ -510,6 +538,8 @@ int tlsv1_client_established(struct tlsv1_client *conn)
  * tlsv1_client_prf - Use TLS-PRF to derive keying material
  * tlsv1_client_prf - Use TLS-PRF to derive keying material
  * @conn: TLSv1 client connection data from tlsv1_client_init()
  * @conn: TLSv1 client connection data from tlsv1_client_init()
  * @label: Label (e.g., description of the key) for PRF
  * @label: Label (e.g., description of the key) for PRF
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
  * @server_random_first: seed is 0 = client_random|server_random,
  * @server_random_first: seed is 0 = client_random|server_random,
  * 1 = server_random|client_random
  * 1 = server_random|client_random
  * @out: Buffer for output data from TLS-PRF
  * @out: Buffer for output data from TLS-PRF
@@ -517,13 +547,26 @@ int tlsv1_client_established(struct tlsv1_client *conn)
  * Returns: 0 on success, -1 on failure
  * Returns: 0 on success, -1 on failure
  */
  */
 int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
 int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+		     const u8 *context, size_t context_len,
 		     int server_random_first, u8 *out, size_t out_len)
 		     int server_random_first, u8 *out, size_t out_len)
 {
 {
-	u8 seed[2 * TLS_RANDOM_LEN];
+	u8 *seed, *pos;
+	size_t seed_len = 2 * TLS_RANDOM_LEN;
+	int res;
 
 
 	if (conn->state != ESTABLISHED)
 	if (conn->state != ESTABLISHED)
 		return -1;
 		return -1;
 
 
+	if (context_len > 65535)
+		return -1;
+
+	if (context)
+		seed_len += 2 + context_len;
+
+	seed = os_malloc(seed_len);
+	if (!seed)
+		return -1;
+
 	if (server_random_first) {
 	if (server_random_first) {
 		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
 		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
 		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
 		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
@@ -534,9 +577,18 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
 			  TLS_RANDOM_LEN);
 			  TLS_RANDOM_LEN);
 	}
 	}
 
 
-	return tls_prf(conn->rl.tls_version,
-		       conn->master_secret, TLS_MASTER_SECRET_LEN,
-		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+	if (context) {
+		pos = seed + 2 * TLS_RANDOM_LEN;
+		WPA_PUT_BE16(pos, context_len);
+		pos += 2;
+		os_memcpy(pos, context, context_len);
+	}
+
+	res = tls_prf(conn->rl.tls_version,
+		      conn->master_secret, TLS_MASTER_SECRET_LEN,
+		      label, seed, seed_len, out, out_len);
+	os_free(seed);
+	return res;
 }
 }
 
 
 
 
@@ -552,7 +604,6 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
 int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
 int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
 			    size_t buflen)
 			    size_t buflen)
 {
 {
-#ifndef ESPRESSIF_USE
 	char *cipher;
 	char *cipher;
 
 
 	switch (conn->rl.cipher_suite) {
 	switch (conn->rl.cipher_suite) {
@@ -562,18 +613,32 @@ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
 	case TLS_RSA_WITH_RC4_128_SHA:
 	case TLS_RSA_WITH_RC4_128_SHA:
 		cipher = "RC4-SHA";
 		cipher = "RC4-SHA";
 		break;
 		break;
-#ifdef CONFIG_DES
 	case TLS_RSA_WITH_DES_CBC_SHA:
 	case TLS_RSA_WITH_DES_CBC_SHA:
 		cipher = "DES-CBC-SHA";
 		cipher = "DES-CBC-SHA";
 		break;
 		break;
-#endif
-#ifdef CONFIG_DES3
 	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
 	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
 		cipher = "DES-CBC3-SHA";
 		cipher = "DES-CBC3-SHA";
 		break;
 		break;
-#endif
-	case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
-		cipher = "ADH-AES-128-SHA256";
+	case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+		cipher = "DHE-RSA-DES-CBC-SHA";
+		break;
+	case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+		cipher = "DHE-RSA-DES-CBC3-SHA";
+		break;
+	case TLS_DH_anon_WITH_RC4_128_MD5:
+		cipher = "ADH-RC4-MD5";
+		break;
+	case TLS_DH_anon_WITH_DES_CBC_SHA:
+		cipher = "ADH-DES-SHA";
+		break;
+	case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+		cipher = "ADH-DES-CBC3-SHA";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "AES-128-SHA";
+		break;
+	case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "DHE-RSA-AES-128-SHA";
 		break;
 		break;
 	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
 	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
 		cipher = "ADH-AES-128-SHA";
 		cipher = "ADH-AES-128-SHA";
@@ -581,68 +646,37 @@ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
 	case TLS_RSA_WITH_AES_256_CBC_SHA:
 	case TLS_RSA_WITH_AES_256_CBC_SHA:
 		cipher = "AES-256-SHA";
 		cipher = "AES-256-SHA";
 		break;
 		break;
-	case TLS_RSA_WITH_AES_256_CBC_SHA256:
-		cipher = "AES-256-SHA256";
+	case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+		cipher = "DHE-RSA-AES-256-SHA";
 		break;
 		break;
-	case TLS_RSA_WITH_AES_128_CBC_SHA:
-		cipher = "AES-128-SHA";
+	case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+		cipher = "ADH-AES-256-SHA";
 		break;
 		break;
 	case TLS_RSA_WITH_AES_128_CBC_SHA256:
 	case TLS_RSA_WITH_AES_128_CBC_SHA256:
 		cipher = "AES-128-SHA256";
 		cipher = "AES-128-SHA256";
 		break;
 		break;
+	case TLS_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "AES-256-SHA256";
+		break;
+	case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+		cipher = "DHE-RSA-AES-128-SHA256";
+		break;
+	case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "DHE-RSA-AES-256-SHA256";
+		break;
+	case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+		cipher = "ADH-AES-128-SHA256";
+		break;
+	case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+		cipher = "ADH-AES-256-SHA256";
+		break;
 	default:
 	default:
 		return -1;
 		return -1;
 	}
 	}
 
 
-	os_memcpy((u8 *)buf, (u8 *)cipher, buflen);
-
+	if (os_strlcpy(buf, cipher, buflen) >= buflen)
+		return -1;
 	return 0;
 	return 0;
-#else
-    char cipher[20];
-
-    switch (conn->rl.cipher_suite) {
-        case TLS_RSA_WITH_RC4_128_MD5:
-            strcpy(cipher, "RC4-MD5");
-            break;
-        case TLS_RSA_WITH_RC4_128_SHA:
-            strcpy(cipher, "RC4-SHA");
-            break;
-#ifdef CONFIG_DES
-        case TLS_RSA_WITH_DES_CBC_SHA:
-            strcpy(cipher, "DES-CBC-SHA");
-            break;
-#endif
-#ifdef CONFIG_DES3
-        case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-            strcpy(cipher, "DES-CBC3-SHA");
-            break;
-#endif
-        case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
-            strcpy(cipher, "ADH-AES-128-SHA256");
-            break;
-        case TLS_DH_anon_WITH_AES_128_CBC_SHA:
-            strcpy(cipher, "ADH-AES-128-SHA");
-            break;
-        case TLS_RSA_WITH_AES_256_CBC_SHA:
-            strcpy(cipher, "AES-256-SHA");
-            break;
-        case TLS_RSA_WITH_AES_256_CBC_SHA256:
-            strcpy(cipher, "AES-256-SHA256");
-            break;
-        case TLS_RSA_WITH_AES_128_CBC_SHA:
-            strcpy(cipher, "AES-128-SHA");
-            break;
-        case TLS_RSA_WITH_AES_128_CBC_SHA256:
-            strcpy(cipher, "AES-128-SHA256");
-            break;
-        default:
-            return -1;
-    }
-
-    os_memcpy((u8 *)buf, (u8 *)cipher, buflen);
-
-    return 0;
-#endif
 }
 }
 
 
 
 
@@ -786,13 +820,9 @@ int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
 		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
-#ifdef CONFIG_DES3
 		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
-#endif
 		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
 		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
-#ifdef CONFIG_DES
 		suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
-#endif
 
 
 		/*
 		/*
 		 * Cisco AP (at least 350 and 1200 series) local authentication
 		 * Cisco AP (at least 350 and 1200 series) local authentication
@@ -830,9 +860,15 @@ int tlsv1_client_set_cred(struct tlsv1_client *conn,
 }
 }
 
 
 
 
-void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)
+/**
+ * tlsv1_client_set_flags - Set connection flags
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @flags: TLS_CONN_* bitfield
+ */
+void tlsv1_client_set_flags(struct tlsv1_client *conn, unsigned int flags)
 {
 {
-	conn->disable_time_checks = !enabled;
+	conn->flags = flags;
+	conn->rl.tls_version = tls_client_highest_ver(conn);
 }
 }
 
 
 
 
@@ -845,3 +881,38 @@ void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
 	conn->session_ticket_cb = cb;
 	conn->session_ticket_cb = cb;
 	conn->session_ticket_cb_ctx = ctx;
 	conn->session_ticket_cb_ctx = ctx;
 }
 }
+
+
+void tlsv1_client_set_cb(struct tlsv1_client *conn,
+			 void (*event_cb)(void *ctx, enum tls_event ev,
+					  union tls_event_data *data),
+			 void *cb_ctx,
+			 int cert_in_cb)
+{
+	conn->event_cb = event_cb;
+	conn->cb_ctx = cb_ctx;
+	conn->cert_in_cb = !!cert_in_cb;
+}
+
+
+int tlsv1_client_get_version(struct tlsv1_client *conn, char *buf,
+			     size_t buflen)
+{
+	if (!conn)
+		return -1;
+	switch (conn->rl.tls_version) {
+	case TLS_VERSION_1:
+		os_strlcpy(buf, "TLSv1", buflen);
+		break;
+	case TLS_VERSION_1_1:
+		os_strlcpy(buf, "TLSv1.1", buflen);
+		break;
+	case TLS_VERSION_1_2:
+		os_strlcpy(buf, "TLSv1.2", buflen);
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}

+ 11 - 2
components/wpa_supplicant/src/tls/tlsv1_client.h

@@ -1,6 +1,6 @@
 /*
 /*
  * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
  * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
@@ -19,6 +19,7 @@ struct tlsv1_client * tlsv1_client_init(void);
 void tlsv1_client_deinit(struct tlsv1_client *conn);
 void tlsv1_client_deinit(struct tlsv1_client *conn);
 int tlsv1_client_established(struct tlsv1_client *conn);
 int tlsv1_client_established(struct tlsv1_client *conn);
 int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
 int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+		     const u8 *context, size_t context_len,
 		     int server_random_first, u8 *out, size_t out_len);
 		     int server_random_first, u8 *out, size_t out_len);
 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
 			    const u8 *in_data, size_t in_len,
 			    const u8 *in_data, size_t in_len,
@@ -41,7 +42,7 @@ int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
 int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
 int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
 int tlsv1_client_set_cred(struct tlsv1_client *conn,
 int tlsv1_client_set_cred(struct tlsv1_client *conn,
 			  struct tlsv1_credentials *cred);
 			  struct tlsv1_credentials *cred);
-void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled);
+void tlsv1_client_set_flags(struct tlsv1_client *conn, unsigned int flags);
 
 
 typedef int (*tlsv1_client_session_ticket_cb)
 typedef int (*tlsv1_client_session_ticket_cb)
 (void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
 (void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
@@ -51,4 +52,12 @@ void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
 					tlsv1_client_session_ticket_cb cb,
 					tlsv1_client_session_ticket_cb cb,
 					void *ctx);
 					void *ctx);
 
 
+void tlsv1_client_set_cb(struct tlsv1_client *conn,
+			 void (*event_cb)(void *ctx, enum tls_event ev,
+					  union tls_event_data *data),
+			 void *cb_ctx,
+			 int cert_in_cb);
+int tlsv1_client_get_version(struct tlsv1_client *conn, char *buf,
+			     size_t buflen);
+
 #endif /* TLSV1_CLIENT_H */
 #endif /* TLSV1_CLIENT_H */

+ 20 - 2
components/wpa_supplicant/src/tls/tlsv1_client_i.h

@@ -29,11 +29,14 @@ struct tlsv1_client {
 	u8 alert_level;
 	u8 alert_level;
 	u8 alert_description;
 	u8 alert_description;
 
 
+	unsigned int flags; /* TLS_CONN_* bitfield */
+
 	unsigned int certificate_requested:1;
 	unsigned int certificate_requested:1;
 	unsigned int session_resumed:1;
 	unsigned int session_resumed:1;
 	unsigned int session_ticket_included:1;
 	unsigned int session_ticket_included:1;
 	unsigned int use_session_ticket:1;
 	unsigned int use_session_ticket:1;
-	unsigned int disable_time_checks:1;
+	unsigned int cert_in_cb:1;
+	unsigned int ocsp_resp_received:1;
 
 
 	struct crypto_public_key *server_rsa_key;
 	struct crypto_public_key *server_rsa_key;
 
 
@@ -64,12 +67,20 @@ struct tlsv1_client {
 	void *session_ticket_cb_ctx;
 	void *session_ticket_cb_ctx;
 
 
 	struct wpabuf *partial_input;
 	struct wpabuf *partial_input;
+
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+
+	struct x509_certificate *server_cert;
 };
 };
 
 
 
 
 void tls_alert(struct tlsv1_client *conn, u8 level, u8 description);
 void tls_alert(struct tlsv1_client *conn, u8 level, u8 description);
 void tlsv1_client_free_dh(struct tlsv1_client *conn);
 void tlsv1_client_free_dh(struct tlsv1_client *conn);
-int tls_derive_pre_master_secret(u8 *pre_master_secret);
+u16 tls_client_highest_ver(struct tlsv1_client *conn);
+int tls_derive_pre_master_secret(struct tlsv1_client *conn,
+				 u8 *pre_master_secret);
 int tls_derive_keys(struct tlsv1_client *conn,
 int tls_derive_keys(struct tlsv1_client *conn,
 		    const u8 *pre_master_secret, size_t pre_master_secret_len);
 		    const u8 *pre_master_secret, size_t pre_master_secret_len);
 u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len);
 u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len);
@@ -81,4 +92,11 @@ int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
 				   const u8 *buf, size_t *len,
 				   const u8 *buf, size_t *len,
 				   u8 **out_data, size_t *out_len);
 				   u8 **out_data, size_t *out_len);
 
 
+enum tls_ocsp_result {
+	TLS_OCSP_NO_RESPONSE, TLS_OCSP_INVALID, TLS_OCSP_GOOD, TLS_OCSP_REVOKED
+};
+
+enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
+					       const u8 *resp, size_t len);
+
 #endif /* TLSV1_CLIENT_I_H */
 #endif /* TLSV1_CLIENT_I_H */

+ 759 - 0
components/wpa_supplicant/src/tls/tlsv1_client_ocsp.c

@@ -0,0 +1,759 @@
+/*
+ * TLSv1 client - OCSP
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+#include "crypto/sha1.h"
+#include "asn1.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+
+/* RFC 6960, 4.2.1: OCSPResponseStatus ::= ENUMERATED */
+enum ocsp_response_status {
+	OCSP_RESP_STATUS_SUCCESSFUL = 0,
+	OCSP_RESP_STATUS_MALFORMED_REQ = 1,
+	OCSP_RESP_STATUS_INT_ERROR = 2,
+	OCSP_RESP_STATUS_TRY_LATER = 3,
+	/* 4 not used */
+	OCSP_RESP_STATUS_SIG_REQUIRED = 5,
+	OCSP_RESP_STATUS_UNAUTHORIZED = 6,
+};
+
+
+static int is_oid_basic_ocsp_resp(struct asn1_oid *oid)
+{
+	return oid->len == 10 &&
+		oid->oid[0] == 1 /* iso */ &&
+		oid->oid[1] == 3 /* identified-organization */ &&
+		oid->oid[2] == 6 /* dod */ &&
+		oid->oid[3] == 1 /* internet */ &&
+		oid->oid[4] == 5 /* security */ &&
+		oid->oid[5] == 5 /* mechanisms */ &&
+		oid->oid[6] == 7 /* id-pkix */ &&
+		oid->oid[7] == 48 /* id-ad */ &&
+		oid->oid[8] == 1 /* id-pkix-ocsp */ &&
+		oid->oid[9] == 1 /* id-pkix-ocsp-basic */;
+}
+
+
+static int ocsp_responder_id_match(struct x509_certificate *signer,
+				   struct x509_name *name, const u8 *key_hash)
+{
+	if (key_hash) {
+		u8 hash[SHA1_MAC_LEN];
+		const u8 *addr[1] = { signer->public_key };
+		size_t len[1] = { signer->public_key_len };
+
+		if (sha1_vector(1, addr, len, hash) < 0)
+			return 0;
+		return os_memcmp(hash, key_hash, SHA1_MAC_LEN) == 0;
+	}
+
+	return x509_name_compare(&signer->subject, name) == 0;
+}
+
+
+static unsigned int ocsp_hash_data(struct asn1_oid *alg, const u8 *data,
+				   size_t data_len, u8 *hash)
+{
+	const u8 *addr[1] = { data };
+	size_t len[1] = { data_len };
+	char buf[100];
+
+	if (x509_sha1_oid(alg)) {
+		if (sha1_vector(1, addr, len, hash) < 0)
+			return 0;
+		wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA1)", hash, 20);
+		return 20;
+	}
+
+	if (x509_sha256_oid(alg)) {
+		if (sha256_vector(1, addr, len, hash) < 0)
+			return 0;
+		wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA256)", hash, 32);
+		return 32;
+	}
+
+	if (x509_sha384_oid(alg)) {
+		if (sha384_vector(1, addr, len, hash) < 0)
+			return 0;
+		wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA384)", hash, 48);
+		return 48;
+	}
+
+	if (x509_sha512_oid(alg)) {
+		if (sha512_vector(1, addr, len, hash) < 0)
+			return 0;
+		wpa_hexdump(MSG_MSGDUMP, "OCSP: Hash (SHA512)", hash, 64);
+		return 64;
+	}
+
+
+	asn1_oid_to_str(alg, buf, sizeof(buf));
+	wpa_printf(MSG_DEBUG, "OCSP: Could not calculate hash with alg %s",
+		   buf);
+	return 0;
+}
+
+
+static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
+					    struct x509_certificate *cert,
+					    struct x509_certificate *issuer,
+					    const u8 *resp, size_t len,
+					    enum tls_ocsp_result *res)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+	struct x509_algorithm_identifier alg;
+	const u8 *name_hash, *key_hash;
+	size_t name_hash_len, key_hash_len;
+	const u8 *serial_number;
+	size_t serial_number_len;
+	u8 hash[64];
+	unsigned int hash_len;
+	unsigned int cert_status;
+	os_time_t update;
+	struct os_time now;
+
+	wpa_hexdump(MSG_MSGDUMP, "OCSP: SingleResponse", resp, len);
+
+	/*
+	 * SingleResponse ::= SEQUENCE {
+	 *    certID                       CertID,
+	 *    certStatus                   CertStatus,
+	 *    thisUpdate                   GeneralizedTime,
+	 *    nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
+	 *    singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
+	 */
+
+	/* CertID ::= SEQUENCE */
+	if (asn1_get_next(resp, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr, "OCSP: Expected SEQUENCE (CertID)");
+		return -1;
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	/*
+	 * CertID ::= SEQUENCE {
+	 *    hashAlgorithm           AlgorithmIdentifier,
+	 *    issuerNameHash          OCTET STRING,
+	 *    issuerKeyHash           OCTET STRING,
+	 *    serialNumber            CertificateSerialNumber }
+	 */
+
+	/* hashAlgorithm  AlgorithmIdentifier */
+	if (x509_parse_algorithm_identifier(pos, end - pos, &alg, &pos))
+		return -1;
+
+	/* issuerNameHash  OCTET STRING */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected OCTET STRING (issuerNameHash)");
+		return -1;
+	}
+	name_hash = hdr.payload;
+	name_hash_len = hdr.length;
+	wpa_hexdump(MSG_DEBUG, "OCSP: issuerNameHash",
+		    name_hash, name_hash_len);
+	pos = hdr.payload + hdr.length;
+
+	wpa_hexdump(MSG_DEBUG, "OCSP: Issuer subject DN",
+		    issuer->subject_dn, issuer->subject_dn_len);
+	hash_len = ocsp_hash_data(&alg.oid, issuer->subject_dn,
+				  issuer->subject_dn_len, hash);
+	if (hash_len == 0 || name_hash_len != hash_len ||
+	    os_memcmp(name_hash, hash, hash_len) != 0) {
+		wpa_printf(MSG_DEBUG, "OCSP: issuerNameHash mismatch");
+		wpa_hexdump(MSG_DEBUG, "OCSP: Calculated issuerNameHash",
+			    hash, hash_len);
+		return -1;
+	}
+
+	/* issuerKeyHash  OCTET STRING */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected OCTET STRING (issuerKeyHash)");
+		return -1;
+	}
+	key_hash = hdr.payload;
+	key_hash_len = hdr.length;
+	wpa_hexdump(MSG_DEBUG, "OCSP: issuerKeyHash", key_hash, key_hash_len);
+	pos = hdr.payload + hdr.length;
+
+	hash_len = ocsp_hash_data(&alg.oid, issuer->public_key,
+				  issuer->public_key_len, hash);
+	if (hash_len == 0 || key_hash_len != hash_len ||
+	    os_memcmp(key_hash, hash, hash_len) != 0) {
+		wpa_printf(MSG_DEBUG, "OCSP: issuerKeyHash mismatch");
+		wpa_hexdump(MSG_DEBUG, "OCSP: Calculated issuerKeyHash",
+			    hash, hash_len);
+		return -1;
+	}
+
+	/* serialNumber CertificateSerialNumber ::= INTEGER */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_integer(&hdr) ||
+	    hdr.length < 1 || hdr.length > X509_MAX_SERIAL_NUM_LEN) {
+		asn1_unexpected(&hdr,
+				"OCSP: No INTEGER tag found for serialNumber");
+		return -1;
+	}
+	serial_number = hdr.payload;
+	serial_number_len = hdr.length;
+	while (serial_number_len > 0 && serial_number[0] == 0) {
+		serial_number++;
+		serial_number_len--;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "OCSP: serialNumber", serial_number,
+		    serial_number_len);
+
+	if (serial_number_len != cert->serial_number_len ||
+	    os_memcmp(serial_number, cert->serial_number,
+		      serial_number_len) != 0) {
+		wpa_printf(MSG_DEBUG, "OCSP: serialNumber mismatch");
+		return -1;
+	}
+
+	pos = end;
+	end = resp + len;
+
+	/* certStatus CertStatus ::= CHOICE
+	 *
+	 * CertStatus ::= CHOICE {
+	 *     good        [0]     IMPLICIT NULL,
+	 *     revoked     [1]     IMPLICIT RevokedInfo,
+	 *     unknown     [2]     IMPLICIT UnknownInfo }
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+		asn1_unexpected(&hdr, "OCSP: Expected CHOICE (CertStatus)");
+		return -1;
+	}
+	cert_status = hdr.tag;
+	wpa_printf(MSG_DEBUG, "OCSP: certStatus=%u", cert_status);
+	wpa_hexdump(MSG_DEBUG, "OCSP: CertStatus additional data",
+		    hdr.payload, hdr.length);
+	pos = hdr.payload + hdr.length;
+
+	os_get_time(&now);
+	/* thisUpdate  GeneralizedTime */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_generalizedtime(&hdr) ||
+	    x509_parse_time(hdr.payload, hdr.length, hdr.tag, &update) < 0) {
+		wpa_printf(MSG_DEBUG, "OCSP: Failed to parse thisUpdate");
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "OCSP: thisUpdate %lu", (unsigned long) update);
+	pos = hdr.payload + hdr.length;
+	if ((unsigned long) now.sec < (unsigned long) update) {
+		wpa_printf(MSG_DEBUG,
+			   "OCSP: thisUpdate time in the future (response not yet valid)");
+		return -1;
+	}
+
+	/* nextUpdate  [0]  EXPLICIT GeneralizedTime OPTIONAL */
+	if (pos < end) {
+		if (asn1_get_next(pos, end - pos, &hdr) < 0)
+			return -1;
+		if (asn1_is_cs_tag(&hdr, 0) && hdr.constructed) {
+			const u8 *next = hdr.payload + hdr.length;
+
+			if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+			    !asn1_is_generalizedtime(&hdr) ||
+			    x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+					    &update) < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "OCSP: Failed to parse nextUpdate");
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "OCSP: nextUpdate %lu",
+				   (unsigned long) update);
+			pos = next;
+			if ((unsigned long) now.sec > (unsigned long) update) {
+				wpa_printf(MSG_DEBUG, "OCSP: nextUpdate time in the past (response has expired)");
+				return -1;
+			}
+		}
+	}
+
+	/* singleExtensions  [1]  EXPLICIT Extensions OPTIONAL */
+	if (pos < end) {
+		wpa_hexdump(MSG_MSGDUMP, "OCSP: singleExtensions",
+			    pos, end - pos);
+		/* Ignore for now */
+	}
+
+	if (cert_status == 0 /* good */)
+		*res = TLS_OCSP_GOOD;
+	else if (cert_status == 1 /* revoked */)
+		*res = TLS_OCSP_REVOKED;
+	else
+		return -1;
+	return 0;
+}
+
+
+static enum tls_ocsp_result
+tls_process_ocsp_responses(struct tlsv1_client *conn,
+			   struct x509_certificate *cert,
+			   struct x509_certificate *issuer, const u8 *resp,
+			   size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+	enum tls_ocsp_result res;
+
+	pos = resp;
+	end = resp + len;
+	while (pos < end) {
+		/* SingleResponse ::= SEQUENCE */
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    !asn1_is_sequence(&hdr)) {
+			asn1_unexpected(&hdr,
+					"OCSP: Expected SEQUENCE (SingleResponse)");
+			return TLS_OCSP_INVALID;
+		}
+		if (tls_process_ocsp_single_response(conn, cert, issuer,
+						     hdr.payload, hdr.length,
+						     &res) == 0)
+			return res;
+		pos = hdr.payload + hdr.length;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "OCSP: Did not find a response matching the server certificate");
+	return TLS_OCSP_NO_RESPONSE;
+}
+
+
+static enum tls_ocsp_result
+tls_process_basic_ocsp_response(struct tlsv1_client *conn,
+				struct x509_certificate *srv_cert,
+				const u8 *resp, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+	const u8 *resp_data, *sign_value, *key_hash = NULL, *responses;
+	const u8 *resp_data_signed;
+	size_t resp_data_len, sign_value_len, responses_len;
+	size_t resp_data_signed_len;
+	struct x509_algorithm_identifier alg;
+	struct x509_certificate *certs = NULL, *last_cert = NULL;
+	struct x509_certificate *issuer, *signer;
+	struct x509_name name; /* used if key_hash == NULL */
+	char buf[100];
+	os_time_t produced_at;
+	enum tls_ocsp_result res;
+
+	wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len);
+
+	os_memset(&name, 0, sizeof(name));
+
+	/*
+	 * RFC 6960, 4.2.1:
+	 * BasicOCSPResponse       ::= SEQUENCE {
+	 *    tbsResponseData      ResponseData,
+	 *    signatureAlgorithm   AlgorithmIdentifier,
+	 *    signature            BIT STRING,
+	 *    certs            [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+	 */
+
+	if (asn1_get_next(resp, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected SEQUENCE (BasicOCSPResponse)");
+		return TLS_OCSP_INVALID;
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	/* ResponseData ::= SEQUENCE */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected SEQUENCE (ResponseData)");
+		return TLS_OCSP_INVALID;
+	}
+	resp_data = hdr.payload;
+	resp_data_len = hdr.length;
+	resp_data_signed = pos;
+	pos = hdr.payload + hdr.length;
+	resp_data_signed_len = pos - resp_data_signed;
+
+	/* signatureAlgorithm  AlgorithmIdentifier */
+	if (x509_parse_algorithm_identifier(pos, end - pos, &alg, &pos))
+		return TLS_OCSP_INVALID;
+
+	/* signature  BIT STRING */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_bitstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected BITSTRING (signature)");
+		return TLS_OCSP_INVALID;
+	}
+	if (hdr.length < 1)
+		return TLS_OCSP_INVALID;
+	pos = hdr.payload;
+	if (*pos) {
+		wpa_printf(MSG_DEBUG, "OCSP: BITSTRING - %d unused bits", *pos);
+		/* PKCS #1 v1.5 10.2.1:
+		 * It is an error if the length in bits of the signature S is
+		 * not a multiple of eight.
+		 */
+		return TLS_OCSP_INVALID;
+	}
+	sign_value = pos + 1;
+	sign_value_len = hdr.length - 1;
+	pos += hdr.length;
+	wpa_hexdump(MSG_MSGDUMP, "OCSP: signature", sign_value, sign_value_len);
+
+	/* certs  [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL */
+	if (pos < end) {
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    !hdr.constructed || !asn1_is_cs_tag(&hdr, 0)) {
+			asn1_unexpected(&hdr,
+					"OCSP: Expected [0] EXPLICIT (certs)");
+			return TLS_OCSP_INVALID;
+		}
+		wpa_hexdump(MSG_MSGDUMP, "OCSP: certs",
+			    hdr.payload, hdr.length);
+		pos = hdr.payload;
+		end = hdr.payload + hdr.length;
+		while (pos < end) {
+			struct x509_certificate *cert;
+
+			if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+			    !asn1_is_sequence(&hdr)) {
+				asn1_unexpected(&hdr,
+						"OCSP: Expected SEQUENCE (Certificate)");
+				goto fail;
+			}
+
+			cert = x509_certificate_parse(hdr.payload, hdr.length);
+			if (!cert)
+				goto fail;
+			if (last_cert) {
+				last_cert->next = cert;
+				last_cert = cert;
+			} else {
+				last_cert = certs = cert;
+			}
+			pos = hdr.payload + hdr.length;
+		}
+	}
+
+	/*
+	 * ResponseData ::= SEQUENCE {
+	 *    version              [0] EXPLICIT Version DEFAULT v1,
+	 *    responderID              ResponderID,
+	 *    producedAt               GeneralizedTime,
+	 *    responses                SEQUENCE OF SingleResponse,
+	 *    responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+	 */
+	pos = resp_data;
+	end = resp_data + resp_data_len;
+	wpa_hexdump(MSG_MSGDUMP, "OCSP: ResponseData", pos, end - pos);
+
+	/*
+	 * version [0] EXPLICIT Version DEFAULT v1
+	 * Version ::= INTEGER { v1(0) }
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) == 0 && hdr.constructed &&
+	    asn1_is_cs_tag(&hdr, 0)) {
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    !asn1_is_integer(&hdr) || hdr.length != 1) {
+			asn1_unexpected(&hdr,
+					"OCSP: No INTEGER (len=1) tag found for version field");
+			goto fail;
+		}
+		wpa_printf(MSG_DEBUG, "OCSP: ResponseData version %u",
+			   hdr.payload[0]);
+		if (hdr.payload[0] != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "OCSP: Unsupported ResponseData version %u",
+				   hdr.payload[0]);
+			goto no_resp;
+		}
+		pos = hdr.payload + hdr.length;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "OCSP: Default ResponseData version (v1)");
+	}
+
+	/*
+	 * ResponderID ::= CHOICE {
+	 *    byName              [1] Name,
+	 *    byKey               [2] KeyHash }
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+		asn1_unexpected(&hdr, "OCSP: Expected CHOICE (ResponderID)");
+		goto fail;
+	}
+
+	if (hdr.tag == 1) {
+		/* Name */
+		if (x509_parse_name(hdr.payload, hdr.length, &name, &pos) < 0)
+			goto fail;
+		x509_name_string(&name, buf, sizeof(buf));
+		wpa_printf(MSG_DEBUG, "OCSP: ResponderID byName Name: %s", buf);
+	} else if (hdr.tag == 2) {
+		/* KeyHash ::= OCTET STRING */
+		if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+		    !asn1_is_octetstring(&hdr)) {
+			asn1_unexpected(&hdr,
+					"OCSP: Expected OCTET STRING (KeyHash)");
+			goto fail;
+		}
+		key_hash = hdr.payload;
+		wpa_hexdump(MSG_DEBUG, "OCSP: ResponderID byKey KeyHash",
+			    key_hash, hdr.length);
+		if (hdr.length != SHA1_MAC_LEN) {
+			wpa_printf(MSG_DEBUG,
+				   "OCSP: Unexpected byKey KeyHash length %u - expected %u for SHA-1",
+				   hdr.length, SHA1_MAC_LEN);
+			goto fail;
+		}
+		pos = hdr.payload + hdr.length;
+	} else {
+		wpa_printf(MSG_DEBUG, "OCSP: Unexpected ResponderID CHOICE %u",
+			   hdr.tag);
+		goto fail;
+	}
+
+	/* producedAt  GeneralizedTime */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_generalizedtime(&hdr) ||
+	    x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+			    &produced_at) < 0) {
+		wpa_printf(MSG_DEBUG, "OCSP: Failed to parse producedAt");
+		goto fail;
+	}
+	wpa_printf(MSG_DEBUG, "OCSP: producedAt %lu",
+		   (unsigned long) produced_at);
+	pos = hdr.payload + hdr.length;
+
+	/* responses  SEQUENCE OF SingleResponse */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected SEQUENCE (responses)");
+		goto fail;
+	}
+	responses = hdr.payload;
+	responses_len = hdr.length;
+	wpa_hexdump(MSG_MSGDUMP, "OCSP: responses", responses, responses_len);
+	pos = hdr.payload + hdr.length;
+
+	if (pos < end) {
+		/* responseExtensions  [1] EXPLICIT Extensions OPTIONAL */
+		wpa_hexdump(MSG_MSGDUMP, "OCSP: responseExtensions",
+			    pos, end - pos);
+		/* Ignore for now. */
+	}
+
+	if (!srv_cert) {
+		wpa_printf(MSG_DEBUG,
+			   "OCSP: Server certificate not known - cannot check OCSP response");
+		goto no_resp;
+	}
+
+	if (srv_cert->next) {
+		/* Issuer has already been verified in the chain */
+		issuer = srv_cert->next;
+	} else {
+		/* Find issuer from the set of trusted certificates */
+		for (issuer = conn->cred ? conn->cred->trusted_certs : NULL;
+		     issuer; issuer = issuer->next) {
+			if (x509_name_compare(&srv_cert->issuer,
+					      &issuer->subject) == 0)
+				break;
+		}
+	}
+	if (!issuer) {
+		wpa_printf(MSG_DEBUG,
+			   "OCSP: Server certificate issuer not known - cannot check OCSP response");
+		goto no_resp;
+	}
+
+	if (ocsp_responder_id_match(issuer, &name, key_hash)) {
+		wpa_printf(MSG_DEBUG,
+			   "OCSP: Server certificate issuer certificate matches ResponderID");
+		signer = issuer;
+	} else {
+		for (signer = certs; signer; signer = signer->next) {
+			if (!ocsp_responder_id_match(signer, &name, key_hash) ||
+			    x509_name_compare(&srv_cert->issuer,
+					      &issuer->subject) != 0 ||
+			    !(signer->ext_key_usage &
+			      X509_EXT_KEY_USAGE_OCSP) ||
+			    x509_certificate_check_signature(issuer, signer) <
+			    0)
+				continue;
+			wpa_printf(MSG_DEBUG,
+				   "OCSP: An extra certificate from the response matches ResponderID and is trusted as an OCSP signer");
+			break;
+		}
+		if (!signer) {
+			wpa_printf(MSG_DEBUG,
+				   "OCSP: Could not find OCSP signer certificate");
+			goto no_resp;
+		}
+	}
+
+	x509_free_name(&name);
+	os_memset(&name, 0, sizeof(name));
+	x509_certificate_chain_free(certs);
+	certs = NULL;
+
+	if (x509_check_signature(signer, &alg, sign_value, sign_value_len,
+				 resp_data_signed, resp_data_signed_len) < 0) {
+		    wpa_printf(MSG_DEBUG, "OCSP: Invalid signature");
+		    return TLS_OCSP_INVALID;
+	}
+
+	res = tls_process_ocsp_responses(conn, srv_cert, issuer,
+					 responses, responses_len);
+	if (res == TLS_OCSP_REVOKED)
+		srv_cert->ocsp_revoked = 1;
+	else if (res == TLS_OCSP_GOOD)
+		srv_cert->ocsp_good = 1;
+	return res;
+
+no_resp:
+	x509_free_name(&name);
+	x509_certificate_chain_free(certs);
+	return TLS_OCSP_NO_RESPONSE;
+
+fail:
+	x509_free_name(&name);
+	x509_certificate_chain_free(certs);
+	return TLS_OCSP_INVALID;
+}
+
+
+enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
+					       const u8 *resp, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+	u8 resp_status;
+	struct asn1_oid oid;
+	char obuf[80];
+	struct x509_certificate *cert;
+	enum tls_ocsp_result res = TLS_OCSP_NO_RESPONSE;
+	enum tls_ocsp_result res_first = res;
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: OCSPResponse", resp, len);
+
+	/*
+	 * RFC 6960, 4.2.1:
+	 * OCSPResponse ::= SEQUENCE {
+	 *    responseStatus  OCSPResponseStatus,
+	 *    responseBytes   [0] EXPLICIT ResponseBytes OPTIONAL }
+	 */
+
+	if (asn1_get_next(resp, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected SEQUENCE (OCSPResponse)");
+		return TLS_OCSP_INVALID;
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	/* OCSPResponseStatus ::= ENUMERATED */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_enumerated(&hdr) || hdr.length != 1) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected ENUMERATED (responseStatus)");
+		return TLS_OCSP_INVALID;
+	}
+	resp_status = hdr.payload[0];
+	wpa_printf(MSG_DEBUG, "OCSP: responseStatus %u", resp_status);
+	pos = hdr.payload + hdr.length;
+	if (resp_status != OCSP_RESP_STATUS_SUCCESSFUL) {
+		wpa_printf(MSG_DEBUG, "OCSP: No stapling result");
+		return TLS_OCSP_NO_RESPONSE;
+	}
+
+	/* responseBytes   [0] EXPLICIT ResponseBytes OPTIONAL */
+	if (pos == end)
+		return TLS_OCSP_NO_RESPONSE;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+	    !asn1_is_cs_tag(&hdr, 0)) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected [0] EXPLICIT (responseBytes)");
+		return TLS_OCSP_INVALID;
+	}
+
+	/*
+	 * ResponseBytes ::= SEQUENCE {
+	 *     responseType   OBJECT IDENTIFIER,
+	 *     response       OCTET STRING }
+	 */
+
+	if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"OCSP: Expected SEQUENCE (ResponseBytes)");
+		return TLS_OCSP_INVALID;
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	/* responseType   OBJECT IDENTIFIER */
+	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "OCSP: Failed to parse OID (responseType)");
+		return TLS_OCSP_INVALID;
+	}
+	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+	wpa_printf(MSG_DEBUG, "OCSP: responseType %s", obuf);
+	if (!is_oid_basic_ocsp_resp(&oid)) {
+		wpa_printf(MSG_DEBUG, "OCSP: Ignore unsupported response type");
+		return TLS_OCSP_NO_RESPONSE;
+	}
+
+	/* response       OCTET STRING */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr, "OCSP: Expected OCTET STRING (response)");
+		return TLS_OCSP_INVALID;
+	}
+
+	cert = conn->server_cert;
+	while (cert) {
+		if (!cert->ocsp_good && !cert->ocsp_revoked) {
+			char sbuf[128];
+
+			x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
+			wpa_printf(MSG_DEBUG,
+				   "OCSP: Trying to find certificate status for %s",
+				   sbuf);
+
+			res = tls_process_basic_ocsp_response(conn, cert,
+							      hdr.payload,
+							      hdr.length);
+			if (cert == conn->server_cert)
+				res_first = res;
+		}
+		if (res == TLS_OCSP_REVOKED || cert->issuer_trusted)
+			break;
+		cert = cert->next;
+	}
+	return res == TLS_OCSP_REVOKED ? res : res_first;
+}

+ 557 - 44
components/wpa_supplicant/src/tls/tlsv1_client_read.c

@@ -1,24 +1,23 @@
 /*
 /*
  * TLSv1 client - read handshake message
  * TLSv1 client - read handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
+#include "common.h"
 #include "crypto/md5.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
 #include "crypto/sha256.h"
-#include "tls/tls.h"
-#include "tls/x509v3.h"
-#include "tls/tlsv1_common.h"
-#include "tls/tlsv1_record.h"
-#include "tls/tlsv1_client.h"
-#include "tls/tlsv1_client_i.h"
-#include "eap_peer/eap_i.h"
+#include "crypto/tls.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
 
 
 static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
 static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
 					   const u8 *in_data, size_t *in_len);
 					   const u8 *in_data, size_t *in_len);
@@ -28,6 +27,57 @@ static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
 					 const u8 *in_data, size_t *in_len);
 					 const u8 *in_data, size_t *in_len);
 
 
 
 
+static int tls_version_disabled(struct tlsv1_client *conn, u16 ver)
+{
+	return (((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
+		 ver == TLS_VERSION_1) ||
+		((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
+		 ver == TLS_VERSION_1_1) ||
+		((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
+		 ver == TLS_VERSION_1_2));
+}
+
+
+static int tls_process_server_hello_extensions(struct tlsv1_client *conn,
+					       const u8 *pos, size_t len)
+{
+	const u8 *end = pos + len;
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello extensions",
+		    pos, len);
+	while (pos < end) {
+		u16 elen;
+
+		if (end - pos < 4) {
+			wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension header");
+			return -1;
+		}
+
+#ifdef DEBUG_PRINT
+		u16 ext;
+		ext = WPA_GET_BE16(pos);
+		wpa_printf(MSG_DEBUG, "TLSv1: ServerHello ExtensionType %u",
+			   ext);
+#endif
+		pos += 2;
+		elen = WPA_GET_BE16(pos);
+		pos += 2;
+
+		if (elen > end - pos) {
+			wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension");
+			return -1;
+		}
+
+		wpa_hexdump(MSG_DEBUG, "TLSv1: ServerHello extension data",
+			    pos, elen);
+
+		pos += elen;
+	}
+
+	return 0;
+}
+
+
 static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
 static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
 				    const u8 *in_data, size_t *in_len)
 				    const u8 *in_data, size_t *in_len)
 {
 {
@@ -77,7 +127,8 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
 	if (end - pos < 2)
 	if (end - pos < 2)
 		goto decode_error;
 		goto decode_error;
 	tls_version = WPA_GET_BE16(pos);
 	tls_version = WPA_GET_BE16(pos);
-	if (!tls_version_ok(tls_version)) {
+	if (!tls_version_ok(tls_version) ||
+	    tls_version_disabled(conn, tls_version)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
 			   "ServerHello %u.%u", pos[0], pos[1]);
 			   "ServerHello %u.%u", pos[0], pos[1]);
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -166,8 +217,24 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
 	}
 	}
 	pos++;
 	pos++;
 
 
+	if (end - pos >= 2) {
+		u16 ext_len;
+
+		ext_len = WPA_GET_BE16(pos);
+		pos += 2;
+		if (end - pos < ext_len) {
+			wpa_printf(MSG_INFO,
+				   "TLSv1: Invalid ServerHello extension length: %u (left: %u)",
+				   ext_len, (unsigned int) (end - pos));
+			goto decode_error;
+		}
+
+		if (tls_process_server_hello_extensions(conn, pos, ext_len))
+			goto decode_error;
+		pos += ext_len;
+	}
+
 	if (end != pos) {
 	if (end != pos) {
-		/* TODO: ServerHello extensions */
 		wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
 		wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
 			    "end of ServerHello", pos, end - pos);
 			    "end of ServerHello", pos, end - pos);
 		goto decode_error;
 		goto decode_error;
@@ -212,6 +279,83 @@ decode_error:
 }
 }
 
 
 
 
+static void tls_peer_cert_event(struct tlsv1_client *conn, int depth,
+				struct x509_certificate *cert)
+{
+	union tls_event_data ev;
+	struct wpabuf *cert_buf = NULL;
+#ifdef CONFIG_SHA256
+	u8 hash[32];
+#endif /* CONFIG_SHA256 */
+	char subject[128];
+
+	if (!conn->event_cb)
+		return;
+
+	os_memset(&ev, 0, sizeof(ev));
+	if ((conn->cred && conn->cred->cert_probe) || conn->cert_in_cb) {
+		cert_buf = wpabuf_alloc_copy(cert->cert_start,
+					     cert->cert_len);
+		ev.peer_cert.cert = cert_buf;
+	}
+#ifdef CONFIG_SHA256
+	if (cert_buf) {
+		const u8 *addr[1];
+		size_t len[1];
+		addr[0] = wpabuf_head(cert_buf);
+		len[0] = wpabuf_len(cert_buf);
+		if (sha256_vector(1, addr, len, hash) == 0) {
+			ev.peer_cert.hash = hash;
+			ev.peer_cert.hash_len = sizeof(hash);
+		}
+	}
+#endif /* CONFIG_SHA256 */
+
+	ev.peer_cert.depth = depth;
+	x509_name_string(&cert->subject, subject, sizeof(subject));
+	ev.peer_cert.subject = subject;
+
+	if (cert->extensions_present & X509_EXT_CERTIFICATE_POLICY) {
+		if (cert->certificate_policy & X509_EXT_CERT_POLICY_TOD_STRICT)
+			ev.peer_cert.tod = 1;
+		else if (cert->certificate_policy &
+			 X509_EXT_CERT_POLICY_TOD_TOFU)
+			ev.peer_cert.tod = 2;
+	}
+
+	conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+	wpabuf_free(cert_buf);
+}
+
+
+static void tls_cert_chain_failure_event(struct tlsv1_client *conn, int depth,
+					 struct x509_certificate *cert,
+					 enum tls_fail_reason reason,
+					 const char *reason_txt)
+{
+#ifndef ESP_SUPPLICANT
+	struct wpabuf *cert_buf = NULL;
+	union tls_event_data ev;
+	char subject[128];
+
+	if (!conn->event_cb || !cert)
+		return;
+
+	os_memset(&ev, 0, sizeof(ev));
+	ev.cert_fail.depth = depth;
+	x509_name_string(&cert->subject, subject, sizeof(subject));
+	ev.peer_cert.subject = subject;
+	ev.cert_fail.reason = reason;
+	ev.cert_fail.reason_txt = reason_txt;
+	cert_buf = wpabuf_alloc_copy(cert->cert_start,
+				     cert->cert_len);
+	ev.cert_fail.cert = cert_buf;
+	conn->event_cb(conn->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+	wpabuf_free(cert_buf);
+#endif
+}
+
+
 static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
 static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
 				   const u8 *in_data, size_t *in_len)
 				   const u8 *in_data, size_t *in_len)
 {
 {
@@ -271,7 +415,8 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Received Certificate (certificate_list len %lu)",
+	wpa_printf(MSG_DEBUG,
+		   "TLSv1: Received Certificate (certificate_list len %lu)",
 		   (unsigned long) len);
 		   (unsigned long) len);
 
 
 	/*
 	/*
@@ -354,6 +499,8 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
 			return -1;
 			return -1;
 		}
 		}
 
 
+		tls_peer_cert_event(conn, idx, cert);
+
 		if (last == NULL)
 		if (last == NULL)
 			chain = cert;
 			chain = cert;
 		else
 		else
@@ -364,31 +511,99 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
 		pos += cert_len;
 		pos += cert_len;
 	}
 	}
 
 
-	if (conn->cred &&
-	    x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
-					    &reason, conn->disable_time_checks)
-	    < 0) {
+	if (conn->cred && conn->cred->server_cert_only && chain) {
+		u8 hash[SHA256_MAC_LEN];
+		char buf[128];
+
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Validate server certificate hash");
+		x509_name_string(&chain->subject, buf, sizeof(buf));
+		wpa_printf(MSG_DEBUG, "TLSv1: 0: %s", buf);
+		if (sha256_vector(1, &chain->cert_start, &chain->cert_len,
+				  hash) < 0 ||
+		    os_memcmp(conn->cred->srv_cert_hash, hash,
+			      SHA256_MAC_LEN) != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "TLSv1: Server certificate hash mismatch");
+			wpa_hexdump(MSG_MSGDUMP, "TLSv1: SHA256 hash",
+				    hash, SHA256_MAC_LEN);
+			if (conn->event_cb) {
+				union tls_event_data ev;
+
+				os_memset(&ev, 0, sizeof(ev));
+				ev.cert_fail.reason = TLS_FAIL_UNSPECIFIED;
+				ev.cert_fail.reason_txt =
+					"Server certificate mismatch";
+				ev.cert_fail.subject = buf;
+				conn->event_cb(conn->cb_ctx,
+					       TLS_CERT_CHAIN_FAILURE, &ev);
+			}
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_BAD_CERTIFICATE);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+	} else if (conn->cred && conn->cred->cert_probe) {
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Reject server certificate on probe-only run");
+		if (conn->event_cb) {
+			union tls_event_data ev;
+			char buf[128];
+
+			os_memset(&ev, 0, sizeof(ev));
+			ev.cert_fail.reason = TLS_FAIL_SERVER_CHAIN_PROBE;
+			ev.cert_fail.reason_txt =
+				"Server certificate chain probe";
+			if (chain) {
+				x509_name_string(&chain->subject, buf,
+						 sizeof(buf));
+				ev.cert_fail.subject = buf;
+			}
+			conn->event_cb(conn->cb_ctx, TLS_CERT_CHAIN_FAILURE,
+				       &ev);
+		}
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_BAD_CERTIFICATE);
+		x509_certificate_chain_free(chain);
+		return -1;
+	} else if (conn->cred && conn->cred->ca_cert_verify &&
+		   x509_certificate_chain_validate(
+			   conn->cred->trusted_certs, chain, &reason,
+			   !!(conn->flags & TLS_CONN_DISABLE_TIME_CHECKS))
+		   < 0) {
 		int tls_reason;
 		int tls_reason;
 		wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
 		wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
 			   "validation failed (reason=%d)", reason);
 			   "validation failed (reason=%d)", reason);
 		switch (reason) {
 		switch (reason) {
 		case X509_VALIDATE_BAD_CERTIFICATE:
 		case X509_VALIDATE_BAD_CERTIFICATE:
 			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
 			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+			tls_cert_chain_failure_event(
+				conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
+				"bad certificate");
 			break;
 			break;
 		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
 		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
 			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
 			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
 			break;
 			break;
 		case X509_VALIDATE_CERTIFICATE_REVOKED:
 		case X509_VALIDATE_CERTIFICATE_REVOKED:
 			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
 			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+			tls_cert_chain_failure_event(
+				conn, 0, chain, TLS_FAIL_REVOKED,
+				"certificate revoked");
 			break;
 			break;
 		case X509_VALIDATE_CERTIFICATE_EXPIRED:
 		case X509_VALIDATE_CERTIFICATE_EXPIRED:
 			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
 			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+			tls_cert_chain_failure_event(
+				conn, 0, chain, TLS_FAIL_EXPIRED,
+				"certificate has expired or is not yet valid");
 			break;
 			break;
 		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
 		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
 			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
 			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
 			break;
 			break;
 		case X509_VALIDATE_UNKNOWN_CA:
 		case X509_VALIDATE_UNKNOWN_CA:
 			tls_reason = TLS_ALERT_UNKNOWN_CA;
 			tls_reason = TLS_ALERT_UNKNOWN_CA;
+			tls_cert_chain_failure_event(
+				conn, 0, chain, TLS_FAIL_UNTRUSTED,
+				"unknown CA");
 			break;
 			break;
 		default:
 		default:
 			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
 			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
@@ -399,21 +614,66 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	x509_certificate_chain_free(chain);
+	if (conn->cred && !conn->cred->server_cert_only && chain &&
+	    (chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
+	    !(chain->ext_key_usage &
+	      (X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_SERVER_AUTH))) {
+		tls_cert_chain_failure_event(
+			conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
+			"certificate not allowed for server authentication");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_BAD_CERTIFICATE);
+		x509_certificate_chain_free(chain);
+		return -1;
+	}
+
+	if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+		x509_certificate_chain_free(conn->server_cert);
+		conn->server_cert = chain;
+	} else {
+		x509_certificate_chain_free(chain);
+	}
 
 
 	*in_len = end - in_data;
 	*in_len = end - in_data;
+
 	conn->state = SERVER_KEY_EXCHANGE;
 	conn->state = SERVER_KEY_EXCHANGE;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 
 
+static unsigned int count_bits(const u8 *val, size_t len)
+{
+	size_t i;
+	unsigned int bits;
+	u8 tmp;
+
+	for (i = 0; i < len; i++) {
+		if (val[i])
+			break;
+	}
+	if (i == len)
+		return 0;
+
+	bits = (len - i - 1) * 8;
+	tmp = val[i];
+	while (tmp) {
+		bits++;
+		tmp >>= 1;
+	}
+
+	return bits;
+}
+
+
 static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 					const u8 *buf, size_t len,
 					const u8 *buf, size_t len,
 					tls_key_exchange key_exchange)
 					tls_key_exchange key_exchange)
 {
 {
 	const u8 *pos, *end, *server_params, *server_params_end;
 	const u8 *pos, *end, *server_params, *server_params_end;
 	u8 alert;
 	u8 alert;
+	unsigned int bits;
+	u16 val;
 
 
 	tlsv1_client_free_dh(conn);
 	tlsv1_client_free_dh(conn);
 
 
@@ -423,31 +683,38 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 	if (end - pos < 3)
 	if (end - pos < 3)
 		goto fail;
 		goto fail;
 	server_params = pos;
 	server_params = pos;
-	conn->dh_p_len = WPA_GET_BE16(pos);
+	val = WPA_GET_BE16(pos);
 	pos += 2;
 	pos += 2;
-	if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
-			   (unsigned long) conn->dh_p_len);
+	if (val == 0 || val > (size_t) (end - pos)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %u", val);
 		goto fail;
 		goto fail;
 	}
 	}
-	conn->dh_p = os_malloc(conn->dh_p_len);
+	conn->dh_p_len = val;
+	bits = count_bits(pos, conn->dh_p_len);
+	if (bits < 768) {
+		wpa_printf(MSG_INFO, "TLSv1: Reject under 768-bit DH prime (insecure; only %u bits)",
+			   bits);
+		wpa_hexdump(MSG_DEBUG, "TLSv1: Rejected DH prime",
+			    pos, conn->dh_p_len);
+		goto fail;
+	}
+	conn->dh_p = os_memdup(pos, conn->dh_p_len);
 	if (conn->dh_p == NULL)
 	if (conn->dh_p == NULL)
 		goto fail;
 		goto fail;
-	os_memcpy(conn->dh_p, pos, conn->dh_p_len);
 	pos += conn->dh_p_len;
 	pos += conn->dh_p_len;
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
 		    conn->dh_p, conn->dh_p_len);
 		    conn->dh_p, conn->dh_p_len);
 
 
 	if (end - pos < 3)
 	if (end - pos < 3)
 		goto fail;
 		goto fail;
-	conn->dh_g_len = WPA_GET_BE16(pos);
+	val = WPA_GET_BE16(pos);
 	pos += 2;
 	pos += 2;
-	if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
+	if (val == 0 || val > (size_t) (end - pos))
 		goto fail;
 		goto fail;
-	conn->dh_g = os_malloc(conn->dh_g_len);
+	conn->dh_g_len = val;
+	conn->dh_g = os_memdup(pos, conn->dh_g_len);
 	if (conn->dh_g == NULL)
 	if (conn->dh_g == NULL)
 		goto fail;
 		goto fail;
-	os_memcpy(conn->dh_g, pos, conn->dh_g_len);
 	pos += conn->dh_g_len;
 	pos += conn->dh_g_len;
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
 		    conn->dh_g, conn->dh_g_len);
 		    conn->dh_g, conn->dh_g_len);
@@ -456,14 +723,14 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 
 
 	if (end - pos < 3)
 	if (end - pos < 3)
 		goto fail;
 		goto fail;
-	conn->dh_ys_len = WPA_GET_BE16(pos);
+	val = WPA_GET_BE16(pos);
 	pos += 2;
 	pos += 2;
-	if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
+	if (val == 0 || val > (size_t) (end - pos))
 		goto fail;
 		goto fail;
-	conn->dh_ys = os_malloc(conn->dh_ys_len);
+	conn->dh_ys_len = val;
+	conn->dh_ys = os_memdup(pos, conn->dh_ys_len);
 	if (conn->dh_ys == NULL)
 	if (conn->dh_ys == NULL)
 		goto fail;
 		goto fail;
-	os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
 	pos += conn->dh_ys_len;
 	pos += conn->dh_ys_len;
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
 		    conn->dh_ys, conn->dh_ys_len);
 		    conn->dh_ys, conn->dh_ys_len);
@@ -487,7 +754,9 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
 			 */
 			 */
 			if (end - pos < 2)
 			if (end - pos < 2)
 				goto fail;
 				goto fail;
-			if ((pos[0] != TLS_HASH_ALG_SHA256) ||
+			if ((pos[0] != TLS_HASH_ALG_SHA256 &&
+			     pos[0] != TLS_HASH_ALG_SHA384 &&
+			     pos[0] != TLS_HASH_ALG_SHA512) ||
 			    pos[1] != TLS_SIGN_ALG_RSA) {
 			    pos[1] != TLS_SIGN_ALG_RSA) {
 				wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
 				wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
 					   pos[0], pos[1]);
 					   pos[0], pos[1]);
@@ -531,6 +800,229 @@ fail:
 }
 }
 
 
 
 
+static enum tls_ocsp_result
+tls_process_certificate_status_ocsp_response(struct tlsv1_client *conn,
+					     const u8 *pos, size_t len)
+{
+	const u8 *end = pos + len;
+	u32 ocsp_resp_len;
+
+	/* opaque OCSPResponse<1..2^24-1>; */
+	if (end - pos < 3) {
+		wpa_printf(MSG_INFO, "TLSv1: Too short OCSPResponse");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return TLS_OCSP_INVALID;
+	}
+	ocsp_resp_len = WPA_GET_BE24(pos);
+	pos += 3;
+	if (end - pos < ocsp_resp_len) {
+		wpa_printf(MSG_INFO, "TLSv1: Truncated OCSPResponse");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return TLS_OCSP_INVALID;
+	}
+
+	return tls_process_ocsp_response(conn, pos, ocsp_resp_len);
+}
+
+
+static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type, status_type;
+	enum tls_ocsp_result res;
+	struct x509_certificate *cert;
+	int depth;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Expected Handshake; received content type 0x%x",
+			   ct);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Too short CertificateStatus (left=%lu)",
+			   (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	type = *pos++;
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Mismatch in CertificateStatus length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	end = pos + len;
+
+	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS) {
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Received unexpected handshake message %d (expected CertificateStatus)",
+			   type);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateStatus");
+
+	/*
+	 * struct {
+	 *     CertificateStatusType status_type;
+	 *     select (status_type) {
+	 *         case ocsp: OCSPResponse;
+	 *         case ocsp_multi: OCSPResponseList;
+	 *     } response;
+	 * } CertificateStatus;
+	 */
+	if (end - pos < 1) {
+		wpa_printf(MSG_INFO, "TLSv1: Too short CertificateStatus");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	status_type = *pos++;
+	wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatus status_type %u",
+		   status_type);
+
+	if (status_type == 1 /* ocsp */) {
+		res = tls_process_certificate_status_ocsp_response(
+			conn, pos, end - pos);
+	} else if (status_type == 2 /* ocsp_multi */) {
+		int good = 0, revoked = 0;
+		u32 resp_len;
+
+		res = TLS_OCSP_NO_RESPONSE;
+
+		/*
+		 * opaque OCSPResponse<0..2^24-1>;
+		 *
+		 * struct {
+		 *   OCSPResponse ocsp_response_list<1..2^24-1>;
+		 * } OCSPResponseList;
+		 */
+		if (end - pos < 3) {
+			wpa_printf(MSG_DEBUG,
+				   "TLSv1: Truncated OCSPResponseList");
+			res = TLS_OCSP_INVALID;
+			goto done;
+		}
+		resp_len = WPA_GET_BE24(pos);
+		pos += 3;
+		if (end - pos < resp_len) {
+			wpa_printf(MSG_DEBUG,
+				   "TLSv1: Truncated OCSPResponseList(len=%u)",
+				   resp_len);
+			res = TLS_OCSP_INVALID;
+			goto done;
+		}
+		end = pos + resp_len;
+
+		while (end - pos >= 3) {
+			resp_len = WPA_GET_BE24(pos);
+			pos += 3;
+			if (resp_len > end - pos) {
+				wpa_printf(MSG_DEBUG,
+					   "TLSv1: Truncated OCSPResponse(len=%u; left=%d) in ocsp_multi",
+					   resp_len, (int) (end - pos));
+				res = TLS_OCSP_INVALID;
+				break;
+			}
+			if (!resp_len)
+				continue; /* Skip an empty response */
+			res = tls_process_certificate_status_ocsp_response(
+				conn, pos - 3, resp_len + 3);
+			if (res == TLS_OCSP_REVOKED)
+				revoked++;
+			else if (res == TLS_OCSP_GOOD)
+				good++;
+			pos += resp_len;
+		}
+
+		if (revoked)
+			res = TLS_OCSP_REVOKED;
+		else if (good)
+			res = TLS_OCSP_GOOD;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Ignore unsupported CertificateStatus");
+		goto skip;
+	}
+
+done:
+	if (res == TLS_OCSP_REVOKED) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_CERTIFICATE_REVOKED);
+		for (cert = conn->server_cert, depth = 0; cert;
+		     cert = cert->next, depth++) {
+			if (cert->ocsp_revoked) {
+				tls_cert_chain_failure_event(
+					conn, depth, cert, TLS_FAIL_REVOKED,
+					"certificate revoked");
+			}
+		}
+		return -1;
+	}
+
+	if (conn->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+		/*
+		 * Verify that each certificate on the chain that is not part
+		 * of the trusted certificates has a good status. If not,
+		 * terminate handshake.
+		 */
+		for (cert = conn->server_cert, depth = 0; cert;
+		     cert = cert->next, depth++) {
+			if (!cert->ocsp_good) {
+				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					  TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+				tls_cert_chain_failure_event(
+					conn, depth, cert,
+					TLS_FAIL_UNSPECIFIED,
+					"bad certificate status response");
+				return -1;
+			}
+			if (cert->issuer_trusted)
+				break;
+		}
+	}
+
+	if ((conn->flags & TLS_CONN_REQUIRE_OCSP) && res != TLS_OCSP_GOOD) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  res == TLS_OCSP_INVALID ? TLS_ALERT_DECODE_ERROR :
+			  TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+		if (conn->server_cert)
+			tls_cert_chain_failure_event(
+				conn, 0, conn->server_cert,
+				TLS_FAIL_UNSPECIFIED,
+				"bad certificate status response");
+		return -1;
+	}
+
+	conn->ocsp_resp_received = 1;
+
+skip:
+	*in_len = end - in_data;
+
+	conn->state = SERVER_KEY_EXCHANGE;
+
+	return 0;
+}
+
+
 static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
 static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
 					   const u8 *in_data, size_t *in_len)
 					   const u8 *in_data, size_t *in_len)
 {
 {
@@ -572,6 +1064,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
 
 
 	end = pos + len;
 	end = pos + len;
 
 
+	if ((conn->flags & TLS_CONN_REQUEST_OCSP) &&
+	    type == TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS)
+		return tls_process_certificate_status(conn, ct, in_data,
+						      in_len);
 	if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
 	if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
 		return tls_process_certificate_request(conn, ct, in_data,
 		return tls_process_certificate_request(conn, ct, in_data,
 						       in_len);
 						       in_len);
@@ -581,7 +1077,9 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
 	if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
 	if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
 		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
 			   "message %d (expected ServerKeyExchange/"
 			   "message %d (expected ServerKeyExchange/"
-			   "CertificateRequest/ServerHelloDone)", type);
+			   "CertificateRequest/ServerHelloDone%s)", type,
+			   (conn->flags & TLS_CONN_REQUEST_OCSP) ?
+			   "/CertificateStatus" : "");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_UNEXPECTED_MESSAGE);
 			  TLS_ALERT_UNEXPECTED_MESSAGE);
 		return -1;
 		return -1;
@@ -615,6 +1113,7 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
 	}
 	}
 
 
 	*in_len = end - in_data;
 	*in_len = end - in_data;
+
 	conn->state = SERVER_CERTIFICATE_REQUEST;
 	conn->state = SERVER_CERTIFICATE_REQUEST;
 
 
 	return 0;
 	return 0;
@@ -678,6 +1177,7 @@ static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
 	conn->certificate_requested = 1;
 	conn->certificate_requested = 1;
 
 
 	*in_len = end - in_data;
 	*in_len = end - in_data;
+
 	conn->state = SERVER_HELLO_DONE;
 	conn->state = SERVER_HELLO_DONE;
 
 
 	return 0;
 	return 0;
@@ -733,7 +1233,17 @@ static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
 
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
 	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
 
 
+	if ((conn->flags & TLS_CONN_REQUIRE_OCSP) &&
+	    !conn->ocsp_resp_received) {
+		wpa_printf(MSG_INFO,
+			   "TLSv1: No OCSP response received - reject handshake");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+		return -1;
+	}
+
 	*in_len = end - in_data;
 	*in_len = end - in_data;
+
 	conn->state = CLIENT_KEY_EXCHANGE;
 	conn->state = CLIENT_KEY_EXCHANGE;
 
 
 	return 0;
 	return 0;
@@ -767,7 +1277,7 @@ static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
 					  TLS_ALERT_HANDSHAKE_FAILURE);
 					  TLS_ALERT_HANDSHAKE_FAILURE);
 				return -1;
 				return -1;
 			}
 			}
-            printf("[Debug] set the state to server certificate \n");
+
 			conn->state = SERVER_CERTIFICATE;
 			conn->state = SERVER_CERTIFICATE;
 			return tls_process_certificate(conn, ct, in_data,
 			return tls_process_certificate(conn, ct, in_data,
 						       in_len);
 						       in_len);
@@ -804,6 +1314,7 @@ static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
 	}
 	}
 
 
 	*in_len = pos + 1 - in_data;
 	*in_len = pos + 1 - in_data;
+
 	conn->state = SERVER_FINISHED;
 	conn->state = SERVER_FINISHED;
 
 
 	return 0;
 	return 0;
@@ -874,9 +1385,11 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
 #ifdef CONFIG_TLSV12
 #ifdef CONFIG_TLSV12
 	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
 	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
 		hlen = SHA256_MAC_LEN;
 		hlen = SHA256_MAC_LEN;
-	    if (conn->verify.sha256_server == NULL ||
-			crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) < 0) {
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR);
+		if (conn->verify.sha256_server == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+		    < 0) {
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
 			conn->verify.sha256_server = NULL;
 			conn->verify.sha256_server = NULL;
 			return -1;
 			return -1;
 		}
 		}
@@ -923,8 +1436,10 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
 			verify_data, TLS_VERIFY_DATA_LEN);
 			verify_data, TLS_VERIFY_DATA_LEN);
 
 
-	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+	if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
 		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
 		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_DECRYPT_ERROR);
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -934,6 +1449,7 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
 
 
 	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
 	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
 		CHANGE_CIPHER_SPEC : ACK_FINISHED;
 		CHANGE_CIPHER_SPEC : ACK_FINISHED;
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1027,10 +1543,8 @@ int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
 			return -1;
 			return -1;
 		break;
 		break;
 	case SERVER_FINISHED:
 	case SERVER_FINISHED:
-		if (tls_process_server_finished(conn, ct, buf, len)) {
-			printf("[debug] server finish process fall \n");
+		if (tls_process_server_finished(conn, ct, buf, len))
 			return -1;
 			return -1;
-		}
 		break;
 		break;
 	case ACK_FINISHED:
 	case ACK_FINISHED:
 		if (out_data &&
 		if (out_data &&
@@ -1045,9 +1559,8 @@ int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (ct == TLS_CONTENT_TYPE_HANDSHAKE) {
+	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
 		tls_verify_hash_add(&conn->verify, buf, *len);
 		tls_verify_hash_add(&conn->verify, buf, *len);
-	}
 
 
 	return 0;
 	return 0;
 }
 }

+ 152 - 53
components/wpa_supplicant/src/tls/tlsv1_client_write.c

@@ -1,26 +1,25 @@
 /*
 /*
  * TLSv1 client - write handshake message
  * TLSv1 client - write handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
+#include "common.h"
 #include "crypto/md5.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
 #include "crypto/sha256.h"
+#include "crypto/tls.h"
 #include "crypto/random.h"
 #include "crypto/random.h"
-#include "tls/tls.h"
-#include "tls/x509v3.h"
-#include "tls/tlsv1_common.h"
-#include "tls/tlsv1_record.h"
-#include "tls/tlsv1_client.h"
-#include "tls/tlsv1_client_i.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
 
 
-#include "eap_peer/eap_i.h"
 
 
 static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
 static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
 {
 {
@@ -49,11 +48,21 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
 	struct os_time now;
 	struct os_time now;
 	size_t len, i;
 	size_t len, i;
 	u8 *ext_start;
 	u8 *ext_start;
+	u16 tls_version = tls_client_highest_ver(conn);
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
+	if (!tls_version) {
+		wpa_printf(MSG_INFO, "TLSv1: No TLS version allowed");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello (ver %s)",
+		   tls_version_str(tls_version));
 	*out_len = 0;
 	*out_len = 0;
 
 
 	os_get_time(&now);
 	os_get_time(&now);
+#ifdef TEST_FUZZ
+	now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
 	WPA_PUT_BE32(conn->client_random, now.sec);
 	WPA_PUT_BE32(conn->client_random, now.sec);
 	if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
 	if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
 		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
 		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
@@ -83,7 +92,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
 	pos += 3;
 	pos += 3;
 	/* body - ClientHello */
 	/* body - ClientHello */
 	/* ProtocolVersion client_version */
 	/* ProtocolVersion client_version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
+	WPA_PUT_BE16(pos, tls_version);
 	pos += 2;
 	pos += 2;
 	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
 	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
 	os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
 	os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
@@ -117,12 +126,16 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
 		WPA_PUT_BE16(pos, TLS_EXT_SIGNATURE_ALGORITHMS);
 		WPA_PUT_BE16(pos, TLS_EXT_SIGNATURE_ALGORITHMS);
 		pos += 2;
 		pos += 2;
 		/* opaque extension_data<0..2^16-1> length */
 		/* opaque extension_data<0..2^16-1> length */
-		WPA_PUT_BE16(pos, 4);
+		WPA_PUT_BE16(pos, 8);
 		pos += 2;
 		pos += 2;
 		/* supported_signature_algorithms<2..2^16-2> length */
 		/* supported_signature_algorithms<2..2^16-2> length */
-		WPA_PUT_BE16(pos, 2);
+		WPA_PUT_BE16(pos, 6);
 		pos += 2;
 		pos += 2;
 		/* supported_signature_algorithms */
 		/* supported_signature_algorithms */
+		*pos++ = TLS_HASH_ALG_SHA512;
+		*pos++ = TLS_SIGN_ALG_RSA;
+		*pos++ = TLS_HASH_ALG_SHA384;
+		*pos++ = TLS_SIGN_ALG_RSA;
 		*pos++ = TLS_HASH_ALG_SHA256;
 		*pos++ = TLS_HASH_ALG_SHA256;
 		*pos++ = TLS_SIGN_ALG_RSA;
 		*pos++ = TLS_SIGN_ALG_RSA;
 	}
 	}
@@ -134,6 +147,84 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
 		pos += conn->client_hello_ext_len;
 		pos += conn->client_hello_ext_len;
 	}
 	}
 
 
+	if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Add status_request extension for OCSP stapling");
+		/* 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, 5);
+		pos += 2;
+
+		/*
+		 * RFC 6066, 8:
+		 * struct {
+		 *     CertificateStatusType status_type;
+		 *     select (status_type) {
+		 *         case ocsp: OCSPStatusRequest;
+		 *     } request;
+		 * } CertificateStatusRequest;
+		 *
+		 * enum { ocsp(1), (255) } CertificateStatusType;
+		 */
+		*pos++ = 1; /* status_type = ocsp(1) */
+
+		/*
+		 * struct {
+		 *     ResponderID responder_id_list<0..2^16-1>;
+		 *     Extensions  request_extensions;
+		 * } OCSPStatusRequest;
+		 *
+		 * opaque ResponderID<1..2^16-1>;
+		 * opaque Extensions<0..2^16-1>;
+		 */
+		WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+		pos += 2;
+		WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+		pos += 2;
+
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Add status_request_v2 extension for OCSP stapling");
+		/* ExtensionsType extension_type = status_request_v2(17) */
+		WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+		pos += 2;
+		/* opaque extension_data<0..2^16-1> length */
+		WPA_PUT_BE16(pos, 7);
+		pos += 2;
+
+		/*
+		 * RFC 6961, 2.2:
+		 * struct {
+		 *     CertificateStatusType status_type;
+		 *     uint16 request_length;
+		 *     select (status_type) {
+		 *         case ocsp: OCSPStatusRequest;
+		 *         case ocsp_multi: OCSPStatusRequest;
+		 *     } request;
+		 * } CertificateStatusRequestItemV2;
+		 *
+		 * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+		 *
+		 * struct {
+		 * CertificateStatusRequestItemV2
+		 *     certificate_status_req_list<1..2^16-1>;
+		 * } CertificateStatusRequestListV2;
+		 */
+
+		/* certificate_status_req_list<1..2^16-1> */
+		WPA_PUT_BE16(pos, 5);
+		pos += 2;
+
+		/* CertificateStatusRequestItemV2 */
+		*pos++ = 2; /* status_type = ocsp_multi(2) */
+		/* OCSPStatusRequest as shown above for v1 */
+		WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+		pos += 2;
+		WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+		pos += 2;
+	}
+
 	if (pos == ext_start + 2)
 	if (pos == ext_start + 2)
 		pos -= 2; /* no extensions */
 		pos -= 2; /* no extensions */
 	else
 	else
@@ -166,6 +257,11 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
 	struct x509_certificate *cert;
 	struct x509_certificate *cert;
 
 
 	pos = *msgpos;
 	pos = *msgpos;
+	if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
 
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
 	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
 	rhdr = pos;
 	rhdr = pos;
@@ -186,7 +282,7 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
 	pos += 3;
 	pos += 3;
 	cert = conn->cred ? conn->cred->cert : NULL;
 	cert = conn->cred ? conn->cred->cert : NULL;
 	while (cert) {
 	while (cert) {
-		if (pos + 3 + cert->cert_len > end) {
+		if (3 + cert->cert_len > (size_t) (end - pos)) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
 			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
 				   "for Certificate (cert_len=%lu left=%lu)",
 				   "for Certificate (cert_len=%lu left=%lu)",
 				   (unsigned long) cert->cert_len,
 				   (unsigned long) cert->cert_len,
@@ -237,7 +333,7 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
 }
 }
 
 
 
 
-static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
+static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
 {
 {
 	/* ClientDiffieHellmanPublic */
 	/* ClientDiffieHellmanPublic */
 	u8 *csecret, *csecret_start, *dh_yc, *shared;
 	u8 *csecret, *csecret_start, *dh_yc, *shared;
@@ -283,12 +379,12 @@ static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
 		os_free(csecret);
 		os_free(csecret);
 		return -1;
 		return -1;
 	}
 	}
-	if(crypto_mod_exp(conn->dh_g, conn->dh_g_len,
-				                    csecret_start, csecret_len,
-				                    conn->dh_p, conn->dh_p_len,
-				                    dh_yc, &dh_yc_len)) {
-        tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			TLS_ALERT_INTERNAL_ERROR);
+	if (crypto_mod_exp(conn->dh_g, conn->dh_g_len,
+			   csecret_start, csecret_len,
+			   conn->dh_p, conn->dh_p_len,
+			   dh_yc, &dh_yc_len)) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
 		os_free(csecret);
 		os_free(csecret);
 		os_free(dh_yc);
 		os_free(dh_yc);
 		return -1;
 		return -1;
@@ -297,9 +393,16 @@ static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
 		    dh_yc, dh_yc_len);
 		    dh_yc, dh_yc_len);
 
 
+	if (end - *pos < 2) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		os_free(dh_yc);
+		return -1;
+	}
 	WPA_PUT_BE16(*pos, dh_yc_len);
 	WPA_PUT_BE16(*pos, dh_yc_len);
 	*pos += 2;
 	*pos += 2;
-	if (*pos + dh_yc_len > end) {
+	if (dh_yc_len > (size_t) (end - *pos)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
 			   "message buffer for Yc");
 			   "message buffer for Yc");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -324,12 +427,12 @@ static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
 	}
 	}
 
 
 	/* shared = Ys^csecret mod p */
 	/* shared = Ys^csecret mod p */
-	if(crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
-				                    csecret_start, csecret_len,
-				                    conn->dh_p, conn->dh_p_len,
-				                    shared, &shared_len)) {
-	    tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  	  TLS_ALERT_INTERNAL_ERROR);
+	if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
+			   csecret_start, csecret_len,
+			   conn->dh_p, conn->dh_p_len,
+			   shared, &shared_len)) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
 		os_free(csecret);
 		os_free(csecret);
 		os_free(shared);
 		os_free(shared);
 		return -1;
 		return -1;
@@ -359,7 +462,7 @@ static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
 	size_t clen;
 	size_t clen;
 	int res;
 	int res;
 
 
-	if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
+	if (tls_derive_pre_master_secret(conn, pre_master_secret) < 0 ||
 	    tls_derive_keys(conn, pre_master_secret,
 	    tls_derive_keys(conn, pre_master_secret,
 			    TLS_PRE_MASTER_SECRET_LEN)) {
 			    TLS_PRE_MASTER_SECRET_LEN)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
@@ -431,8 +534,8 @@ static int tls_write_client_key_exchange(struct tlsv1_client *conn,
 	hs_length = pos;
 	hs_length = pos;
 	pos += 3;
 	pos += 3;
 	/* body - ClientKeyExchange */
 	/* body - ClientKeyExchange */
-	if (keyx == TLS_KEY_X_DH_anon) {
-		if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
+	if (keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) {
+		if (tlsv1_key_x_dh(conn, &pos, end) < 0)
 			return -1;
 			return -1;
 	} else {
 	} else {
 		if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
 		if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
@@ -464,7 +567,6 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
 	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
 	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
 	size_t rlen, hlen, clen;
 	size_t rlen, hlen, clen;
 	u8 hash[100], *hpos;
 	u8 hash[100], *hpos;
-	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
 
 
 	pos = *msgpos;
 	pos = *msgpos;
 
 
@@ -511,7 +613,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
 		    0) {
 		    0) {
 			conn->verify.sha256_cert = NULL;
 			conn->verify.sha256_cert = NULL;
 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				    TLS_ALERT_INTERNAL_ERROR);
+				  TLS_ALERT_INTERNAL_ERROR);
 			return -1;
 			return -1;
 		}
 		}
 		conn->verify.sha256_cert = NULL;
 		conn->verify.sha256_cert = NULL;
@@ -537,21 +639,17 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
 	} else {
 	} else {
 #endif /* CONFIG_TLSV12 */
 #endif /* CONFIG_TLSV12 */
 
 
-	if (alg == SIGN_ALG_RSA) {
-		hlen = MD5_MAC_LEN;
-		if (conn->verify.md5_cert == NULL ||
-		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
-		{
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_INTERNAL_ERROR);
-			conn->verify.md5_cert = NULL;
-			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
-			conn->verify.sha1_cert = NULL;
-			return -1;
-		}
-		hpos += MD5_MAC_LEN;
-	} else
-		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_cert == NULL ||
+	    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_cert = NULL;
+		crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+		conn->verify.sha1_cert = NULL;
+		return -1;
+	}
+	hpos += MD5_MAC_LEN;
 
 
 	conn->verify.md5_cert = NULL;
 	conn->verify.md5_cert = NULL;
 	hlen = SHA1_MAC_LEN;
 	hlen = SHA1_MAC_LEN;
@@ -564,8 +662,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
 	}
 	}
 	conn->verify.sha1_cert = NULL;
 	conn->verify.sha1_cert = NULL;
 
 
-	if (alg == SIGN_ALG_RSA)
-		hlen += MD5_MAC_LEN;
+	hlen += MD5_MAC_LEN;
 
 
 #ifdef CONFIG_TLSV12
 #ifdef CONFIG_TLSV12
 	}
 	}
@@ -688,7 +785,7 @@ static int tls_write_client_finished(struct tlsv1_client *conn,
 		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
 		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
 		    < 0) {
 		    < 0) {
 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				    TLS_ALERT_INTERNAL_ERROR);
+				  TLS_ALERT_INTERNAL_ERROR);
 			conn->verify.sha256_client = NULL;
 			conn->verify.sha256_client = NULL;
 			return -1;
 			return -1;
 		}
 		}
@@ -796,6 +893,7 @@ static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
 	}
 	}
 
 
 	*out_len = pos - msg;
 	*out_len = pos - msg;
+
 	conn->state = SERVER_CHANGE_CIPHER_SPEC;
 	conn->state = SERVER_CHANGE_CIPHER_SPEC;
 
 
 	return msg;
 	return msg;
@@ -826,7 +924,8 @@ static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
 
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
 	wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
 		   "successfully");
 		   "successfully");
-
+	if (!conn->session_resumed && conn->use_session_ticket)
+		conn->session_resumed = 1;
 	conn->state = ESTABLISHED;
 	conn->state = ESTABLISHED;
 
 
 	return msg;
 	return msg;

+ 35 - 29
components/wpa_supplicant/src/tls/tlsv1_common.c

@@ -1,21 +1,19 @@
 /*
 /*
  * TLSv1 common routines
  * TLSv1 common routines
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
+#include "common.h"
 #include "crypto/md5.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
 #include "crypto/sha256.h"
-#include "tls/tls.h"
-#include "tls/x509v3.h"
-#include "tls/tlsv1_common.h"
-#include "eap_peer/eap_i.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
 
 
 
 
 /*
 /*
@@ -32,44 +30,47 @@ static const struct tls_cipher_suite tls_cipher_suites[] = {
 	  TLS_HASH_MD5 },
 	  TLS_HASH_MD5 },
 	{ TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
 	{ TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
 	  TLS_HASH_SHA },
 	  TLS_HASH_SHA },
-#ifdef CONFIG_DES
 	{ TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC,
 	{ TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC,
 	  TLS_HASH_SHA },
 	  TLS_HASH_SHA },
-#endif
-#ifdef CONFIG_DES3
 	{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
 	{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
 	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
 	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
-#endif
+	{ TLS_DHE_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_DHE_RSA, TLS_CIPHER_DES_CBC,
+	  TLS_HASH_SHA},
+	{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
  	{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
  	{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
 	  TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
-#ifdef CONFIG_DES
  	{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
  	{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_DES_CBC, TLS_HASH_SHA },
 	  TLS_CIPHER_DES_CBC, TLS_HASH_SHA },
-#endif
-#ifdef CONFIG_DES3
  	{ TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon,
  	{ TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
 	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
-#endif
 	{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
 	{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
 	  TLS_HASH_SHA },
 	  TLS_HASH_SHA },
+	{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
 	{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
 	{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
 	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
 	{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
 	{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
 	  TLS_HASH_SHA },
 	  TLS_HASH_SHA },
+	{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
 	{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
 	{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
 	{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
 	{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
 	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
 	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
 	{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
 	{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+	{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+	{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
 	{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
 	{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
 	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
 	{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
 	{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
 	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
 };
 };
 
 
-#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
-#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
+#define NUM_TLS_CIPHER_SUITES ARRAY_SIZE(tls_cipher_suites)
 
 
 
 
 static const struct tls_cipher_data tls_ciphers[] = {
 static const struct tls_cipher_data tls_ciphers[] = {
@@ -83,23 +84,19 @@ static const struct tls_cipher_data tls_ciphers[] = {
 	  CRYPTO_CIPHER_ALG_RC4 },
 	  CRYPTO_CIPHER_ALG_RC4 },
 	{ TLS_CIPHER_RC4_128,      TLS_CIPHER_STREAM, 16, 16,  0,
 	{ TLS_CIPHER_RC4_128,      TLS_CIPHER_STREAM, 16, 16,  0,
 	  CRYPTO_CIPHER_ALG_RC4 },
 	  CRYPTO_CIPHER_ALG_RC4 },
-#ifdef CONFIG_DES
 	{ TLS_CIPHER_DES40_CBC,    TLS_CIPHER_BLOCK,   5,  8,  8,
 	{ TLS_CIPHER_DES40_CBC,    TLS_CIPHER_BLOCK,   5,  8,  8,
 	  CRYPTO_CIPHER_ALG_DES },
 	  CRYPTO_CIPHER_ALG_DES },
 	{ TLS_CIPHER_DES_CBC,      TLS_CIPHER_BLOCK,   8,  8,  8,
 	{ TLS_CIPHER_DES_CBC,      TLS_CIPHER_BLOCK,   8,  8,  8,
 	  CRYPTO_CIPHER_ALG_DES },
 	  CRYPTO_CIPHER_ALG_DES },
-#endif
-#ifdef CONFIG_DES3
 	{ TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK,  24, 24,  8,
 	{ TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK,  24, 24,  8,
 	  CRYPTO_CIPHER_ALG_3DES },
 	  CRYPTO_CIPHER_ALG_3DES },
-#endif
 	{ TLS_CIPHER_AES_128_CBC,  TLS_CIPHER_BLOCK,  16, 16, 16,
 	{ TLS_CIPHER_AES_128_CBC,  TLS_CIPHER_BLOCK,  16, 16, 16,
 	  CRYPTO_CIPHER_ALG_AES },
 	  CRYPTO_CIPHER_ALG_AES },
 	{ TLS_CIPHER_AES_256_CBC,  TLS_CIPHER_BLOCK,  32, 32, 16,
 	{ TLS_CIPHER_AES_256_CBC,  TLS_CIPHER_BLOCK,  32, 32, 16,
 	  CRYPTO_CIPHER_ALG_AES }
 	  CRYPTO_CIPHER_ALG_AES }
 };
 };
 
 
-#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
+#define NUM_TLS_CIPHER_DATA ARRAY_SIZE(tls_ciphers)
 
 
 
 
 /**
 /**
@@ -222,12 +219,13 @@ int tls_verify_hash_init(struct tls_verify_hash *verify)
 		return -1;
 		return -1;
 	}
 	}
 #ifdef CONFIG_TLSV12
 #ifdef CONFIG_TLSV12
-  verify->sha256_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
-  verify->sha256_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
-  verify->sha256_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
-
-	if (verify->sha256_client == NULL ||
-		verify->sha256_server == NULL ||
+	verify->sha256_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+						 0);
+	verify->sha256_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+						 0);
+	verify->sha256_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+					       0);
+	if (verify->sha256_client == NULL || verify->sha256_server == NULL ||
 	    verify->sha256_cert == NULL) {
 	    verify->sha256_cert == NULL) {
 		tls_verify_hash_free(verify);
 		tls_verify_hash_free(verify);
 		return -1;
 		return -1;
@@ -254,7 +252,7 @@ void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
 	}
 	}
 #ifdef CONFIG_TLSV12
 #ifdef CONFIG_TLSV12
 	if (verify->sha256_client)
 	if (verify->sha256_client)
-	  crypto_hash_update(verify->sha256_client, buf, len);
+		crypto_hash_update(verify->sha256_client, buf, len);
 	if (verify->sha256_server)
 	if (verify->sha256_server)
 		crypto_hash_update(verify->sha256_server, buf, len);
 		crypto_hash_update(verify->sha256_server, buf, len);
 	if (verify->sha256_cert)
 	if (verify->sha256_cert)
@@ -352,6 +350,14 @@ int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_alg,
 		alg = CRYPTO_HASH_ALG_SHA256;
 		alg = CRYPTO_HASH_ALG_SHA256;
 		hlen = SHA256_MAC_LEN;
 		hlen = SHA256_MAC_LEN;
 		break;
 		break;
+	case TLS_HASH_ALG_SHA384:
+		alg = CRYPTO_HASH_ALG_SHA384;
+		hlen = 48;
+		break;
+	case TLS_HASH_ALG_SHA512:
+		alg = CRYPTO_HASH_ALG_SHA512;
+		hlen = 64;
+		break;
 	default:
 	default:
 		return -1;
 		return -1;
 	}
 	}

+ 2 - 1
components/wpa_supplicant/src/tls/tlsv1_common.h

@@ -1,6 +1,6 @@
 /*
 /*
  * TLSv1 common definitions
  * TLSv1 common definitions
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
@@ -170,6 +170,7 @@ enum {
 #define TLS_EXT_TRUNCATED_HMAC			4 /* RFC 4366 */
 #define TLS_EXT_TRUNCATED_HMAC			4 /* RFC 4366 */
 #define TLS_EXT_STATUS_REQUEST			5 /* RFC 4366 */
 #define TLS_EXT_STATUS_REQUEST			5 /* RFC 4366 */
 #define TLS_EXT_SIGNATURE_ALGORITHMS		13 /* RFC 5246 */
 #define TLS_EXT_SIGNATURE_ALGORITHMS		13 /* RFC 5246 */
+#define TLS_EXT_STATUS_REQUEST_V2		17 /* RFC 6961 */
 #define TLS_EXT_SESSION_TICKET			35 /* RFC 4507 */
 #define TLS_EXT_SESSION_TICKET			35 /* RFC 4507 */
 
 
 #define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
 #define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */

+ 751 - 41
components/wpa_supplicant/src/tls/tlsv1_cred.c

@@ -1,23 +1,27 @@
 /*
 /*
  * TLSv1 credentials
  * TLSv1 credentials
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
-#include "utils/base64.h"
+#include "common.h"
+#include "base64.h"
 #include "crypto/crypto.h"
 #include "crypto/crypto.h"
-#include "tls/x509v3.h"
-#include "tls/tlsv1_cred.h"
+#include "crypto/sha1.h"
+#include "pkcs5.h"
+#include "pkcs8.h"
+#include "x509v3.h"
+#include "tlsv1_cred.h"
+
 
 
 struct tlsv1_credentials * tlsv1_cred_alloc(void)
 struct tlsv1_credentials * tlsv1_cred_alloc(void)
 {
 {
 	struct tlsv1_credentials *cred;
 	struct tlsv1_credentials *cred;
-	cred = (struct tlsv1_credentials *)os_zalloc(sizeof(*cred));
+	cred = os_zalloc(sizeof(*cred));
 	return cred;
 	return cred;
 }
 }
 
 
@@ -32,6 +36,8 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred)
 	crypto_private_key_free(cred->key);
 	crypto_private_key_free(cred->key);
 	os_free(cred->dh_p);
 	os_free(cred->dh_p);
 	os_free(cred->dh_g);
 	os_free(cred->dh_g);
+	os_free(cred->ocsp_stapling_response);
+	os_free(cred->ocsp_stapling_response_multi);
 	os_free(cred);
 	os_free(cred);
 }
 }
 
 
@@ -124,7 +130,7 @@ static int tlsv1_add_cert(struct x509_certificate **chain,
 			return -1;
 			return -1;
 		}
 		}
 
 
-		der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
+		der = base64_decode((const char *) pos, end - pos, &der_len);
 		if (der == NULL) {
 		if (der == NULL) {
 			wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
 			wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
 				   "certificate");
 				   "certificate");
@@ -156,10 +162,11 @@ static int tlsv1_set_cert_chain(struct x509_certificate **chain,
 		return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
 		return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
 
 
 	if (cert) {
 	if (cert) {
-		u8 *buf = NULL;
-		size_t len = 0;
+		u8 *buf;
+		size_t len;
 		int ret;
 		int ret;
 
 
+		buf = (u8 *) os_readfile(cert, &len);
 		if (buf == NULL) {
 		if (buf == NULL) {
 			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
 			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
 				   cert);
 				   cert);
@@ -188,6 +195,43 @@ int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
 		      const u8 *cert_blob, size_t cert_blob_len,
 		      const u8 *cert_blob, size_t cert_blob_len,
 		      const char *path)
 		      const char *path)
 {
 {
+	if (cert && os_strncmp(cert, "hash://", 7) == 0) {
+		const char *pos = cert + 7;
+		if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "TLSv1: Unsupported ca_cert hash value '%s'",
+				   cert);
+			return -1;
+		}
+		pos += 14;
+		if (os_strlen(pos) != 32 * 2) {
+			wpa_printf(MSG_DEBUG,
+				   "TLSv1: Unexpected SHA256 hash length in ca_cert '%s'",
+				   cert);
+			return -1;
+		}
+		if (hexstr2bin(pos, cred->srv_cert_hash, 32) < 0) {
+			wpa_printf(MSG_DEBUG,
+				   "TLSv1: Invalid SHA256 hash value in ca_cert '%s'",
+				   cert);
+			return -1;
+		}
+		cred->server_cert_only = 1;
+		cred->ca_cert_verify = 0;
+		wpa_printf(MSG_DEBUG,
+			   "TLSv1: Checking only server certificate match");
+		return 0;
+	}
+
+	if (cert && os_strncmp(cert, "probe://", 8) == 0) {
+		cred->cert_probe = 1;
+		cred->ca_cert_verify = 0;
+		wpa_printf(MSG_DEBUG, "TLSv1: Only probe server certificate");
+		return 0;
+	}
+
+	cred->ca_cert_verify = cert || cert_blob || path;
+
 	if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
 	if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
 				 cert_blob, cert_blob_len) < 0)
 				 cert_blob, cert_blob_len) < 0)
 		return -1;
 		return -1;
@@ -249,7 +293,7 @@ static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
 		}
 		}
 	}
 	}
 
 
-	der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
+	der = base64_decode((const char *) pos, end - pos, &der_len);
 	if (!der)
 	if (!der)
 		return NULL;
 		return NULL;
 	pkey = crypto_private_key_import(der, der_len, NULL);
 	pkey = crypto_private_key_import(der, der_len, NULL);
@@ -277,7 +321,7 @@ static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
 	if (!end)
 	if (!end)
 		return NULL;
 		return NULL;
 
 
-	der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
+	der = base64_decode((const char *) pos, end - pos, &der_len);
 	if (!der)
 	if (!der)
 		return NULL;
 		return NULL;
 	pkey = crypto_private_key_import(der, der_len, passwd);
 	pkey = crypto_private_key_import(der, der_len, passwd);
@@ -286,6 +330,679 @@ static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
 }
 }
 
 
 
 
+#ifdef PKCS12_FUNCS
+
+static int oid_is_rsadsi(struct asn1_oid *oid)
+{
+	return oid->len >= 4 &&
+		oid->oid[0] == 1 /* iso */ &&
+		oid->oid[1] == 2 /* member-body */ &&
+		oid->oid[2] == 840 /* us */ &&
+		oid->oid[3] == 113549 /* rsadsi */;
+}
+
+
+static int pkcs12_is_bagtype_oid(struct asn1_oid *oid, unsigned long type)
+{
+	return oid->len == 9 &&
+		oid_is_rsadsi(oid) &&
+		oid->oid[4] == 1 /* pkcs */ &&
+		oid->oid[5] == 12 /* pkcs-12 */ &&
+		oid->oid[6] == 10 &&
+		oid->oid[7] == 1 /* bagtypes */ &&
+		oid->oid[8] == type;
+}
+
+
+static int is_oid_pkcs7(struct asn1_oid *oid)
+{
+	return oid->len == 7 &&
+		oid->oid[0] == 1 /* iso */ &&
+		oid->oid[1] == 2 /* member-body */ &&
+		oid->oid[2] == 840 /* us */ &&
+		oid->oid[3] == 113549 /* rsadsi */ &&
+		oid->oid[4] == 1 /* pkcs */ &&
+		oid->oid[5] == 7 /* pkcs-7 */;
+}
+
+
+static int is_oid_pkcs7_data(struct asn1_oid *oid)
+{
+	return is_oid_pkcs7(oid) && oid->oid[6] == 1 /* data */;
+}
+
+
+static int is_oid_pkcs7_enc_data(struct asn1_oid *oid)
+{
+	return is_oid_pkcs7(oid) && oid->oid[6] == 6 /* encryptedData */;
+}
+
+
+static int is_oid_pkcs9(struct asn1_oid *oid)
+{
+	return oid->len >= 6 &&
+		oid->oid[0] == 1 /* iso */ &&
+		oid->oid[1] == 2 /* member-body */ &&
+		oid->oid[2] == 840 /* us */ &&
+		oid->oid[3] == 113549 /* rsadsi */ &&
+		oid->oid[4] == 1 /* pkcs */ &&
+		oid->oid[5] == 9 /* pkcs-9 */;
+}
+
+
+static int is_oid_pkcs9_friendly_name(struct asn1_oid *oid)
+{
+	return oid->len == 7 && is_oid_pkcs9(oid) &&
+		oid->oid[6] == 20;
+}
+
+
+static int is_oid_pkcs9_local_key_id(struct asn1_oid *oid)
+{
+	return oid->len == 7 && is_oid_pkcs9(oid) &&
+		oid->oid[6] == 21;
+}
+
+
+static int is_oid_pkcs9_x509_cert(struct asn1_oid *oid)
+{
+	return oid->len == 8 && is_oid_pkcs9(oid) &&
+		oid->oid[6] == 22 /* certTypes */ &&
+		oid->oid[7] == 1 /* x509Certificate */;
+}
+
+
+static int pkcs12_keybag(struct tlsv1_credentials *cred,
+			 const u8 *buf, size_t len)
+{
+	/* TODO */
+	return 0;
+}
+
+
+static int pkcs12_pkcs8_keybag(struct tlsv1_credentials *cred,
+			       const u8 *buf, size_t len,
+			       const char *passwd)
+{
+	struct crypto_private_key *key;
+
+	/* PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo */
+	key = pkcs8_enc_key_import(buf, len, passwd);
+	if (!key)
+		return -1;
+
+	wpa_printf(MSG_DEBUG,
+		   "PKCS #12: Successfully decrypted PKCS8ShroudedKeyBag");
+	crypto_private_key_free(cred->key);
+	cred->key = key;
+
+	return 0;
+}
+
+
+static int pkcs12_certbag(struct tlsv1_credentials *cred,
+			  const u8 *buf, size_t len)
+{
+	struct asn1_hdr hdr;
+	struct asn1_oid oid;
+	char obuf[80];
+	const u8 *pos, *end;
+
+	/*
+	 * CertBag ::= SEQUENCE {
+	 *     certId      BAG-TYPE.&id   ({CertTypes}),
+	 *     certValue   [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
+	 * }
+	 */
+
+	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr, "PKCS #12: Expected SEQUENCE (CertBag)");
+		return -1;
+	}
+
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #12: Failed to parse OID (certId)");
+		return -1;
+	}
+
+	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+	wpa_printf(MSG_DEBUG, "PKCS #12: certId %s", obuf);
+
+	if (!is_oid_pkcs9_x509_cert(&oid)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #12: Ignored unsupported certificate type (certId %s)",
+			   obuf);
+	}
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+	    !asn1_is_cs_tag(&hdr, 0)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected [0] EXPLICIT (certValue)");
+		return -1;
+	}
+
+	if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected OCTET STRING (x509Certificate)");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "PKCS #12: x509Certificate",
+		    hdr.payload, hdr.length);
+	if (cred->cert) {
+		struct x509_certificate *cert;
+
+		wpa_printf(MSG_DEBUG, "PKCS #12: Ignore extra certificate");
+		cert = x509_certificate_parse(hdr.payload, hdr.length);
+		if (!cert) {
+			wpa_printf(MSG_DEBUG,
+				   "PKCS #12: Failed to parse x509Certificate");
+			return 0;
+		}
+		x509_certificate_chain_free(cert);
+
+		return 0;
+	}
+	return tlsv1_set_cert(cred, NULL, hdr.payload, hdr.length);
+}
+
+
+static int pkcs12_parse_attr_friendly_name(const u8 *pos, const u8 *end)
+{
+	struct asn1_hdr hdr;
+
+	/*
+	 * RFC 2985, 5.5.1:
+	 * friendlyName ATTRIBUTE ::= {
+	 *         WITH SYNTAX BMPString (SIZE(1..pkcs-9-ub-friendlyName))
+	 *         EQUALITY MATCHING RULE caseIgnoreMatch
+	 *         SINGLE VALUE TRUE
+	 *          ID pkcs-9-at-friendlyName
+	 * }
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_bmpstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected BMPSTRING (friendlyName)");
+		return 0;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "PKCS #12: friendlyName",
+			  hdr.payload, hdr.length);
+	return 0;
+}
+
+
+static int pkcs12_parse_attr_local_key_id(const u8 *pos, const u8 *end)
+{
+	struct asn1_hdr hdr;
+
+	/*
+	 * RFC 2985, 5.5.2:
+	 * localKeyId ATTRIBUTE ::= {
+	 *         WITH SYNTAX OCTET STRING
+	 *         EQUALITY MATCHING RULE octetStringMatch
+	 *         SINGLE VALUE TRUE
+	 *         ID pkcs-9-at-localKeyId
+	 * }
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected OCTET STRING (localKeyID)");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "PKCS #12: localKeyID",
+			hdr.payload, hdr.length);
+	return 0;
+}
+
+
+static int pkcs12_parse_attr(const u8 *pos, size_t len)
+{
+	const u8 *end = pos + len;
+	struct asn1_hdr hdr;
+	struct asn1_oid a_oid;
+	char obuf[80];
+
+	/*
+	 * PKCS12Attribute ::= SEQUENCE {
+	 * attrId      ATTRIBUTE.&id ({PKCS12AttrSet}),
+	 * attrValues  SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
+	 * }
+	 */
+
+	if (asn1_get_oid(pos, end - pos, &a_oid, &pos)) {
+		wpa_printf(MSG_DEBUG, "PKCS #12: Failed to parse OID (attrId)");
+		return -1;
+	}
+
+	asn1_oid_to_str(&a_oid, obuf, sizeof(obuf));
+	wpa_printf(MSG_DEBUG, "PKCS #12: attrId %s", obuf);
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) {
+		asn1_unexpected(&hdr, "PKCS #12: Expected SET (attrValues)");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: attrValues",
+			hdr.payload, hdr.length);
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	if (is_oid_pkcs9_friendly_name(&a_oid))
+		return pkcs12_parse_attr_friendly_name(pos, end);
+	if (is_oid_pkcs9_local_key_id(&a_oid))
+		return pkcs12_parse_attr_local_key_id(pos, end);
+
+	wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unknown attribute");
+	return 0;
+}
+
+
+static int pkcs12_safebag(struct tlsv1_credentials *cred,
+			  const u8 *buf, size_t len, const char *passwd)
+{
+	struct asn1_hdr hdr;
+	struct asn1_oid oid;
+	char obuf[80];
+	const u8 *pos = buf, *end = buf + len;
+	const u8 *value;
+	size_t value_len;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: SafeBag", buf, len);
+
+	/* BAG-TYPE ::= TYPE-IDENTIFIER */
+	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #12: Failed to parse OID (BAG-TYPE)");
+		return -1;
+	}
+
+	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+	wpa_printf(MSG_DEBUG, "PKCS #12: BAG-TYPE %s", obuf);
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+	    !asn1_is_cs_tag(&hdr, 0)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected [0] EXPLICIT (bagValue)");
+		return 0;
+	}
+	value = hdr.payload;
+	value_len = hdr.length;
+	wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagValue", value, value_len);
+	pos = hdr.payload + hdr.length;
+
+	if (pos < end) {
+		/* bagAttributes  SET OF PKCS12Attribute OPTIONAL */
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    !asn1_is_set(&hdr)) {
+			asn1_unexpected(&hdr,
+					"PKCS #12: Expected SET (bagAttributes)");
+			return -1;
+		}
+		wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagAttributes",
+				hdr.payload, hdr.length);
+
+		pos = hdr.payload;
+		end = hdr.payload + hdr.length;
+		while (pos < end) {
+			/* PKCS12Attribute ::= SEQUENCE */
+			if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+			    !asn1_is_sequence(&hdr)) {
+				asn1_unexpected(&hdr,
+						"PKCS #12: Expected SEQUENCE (PKCS12Attribute)");
+				return -1;
+			}
+			if (pkcs12_parse_attr(hdr.payload, hdr.length) < 0)
+				return -1;
+			pos = hdr.payload + hdr.length;
+		}
+	}
+
+	if (pkcs12_is_bagtype_oid(&oid, 1))
+		return pkcs12_keybag(cred, value, value_len);
+	if (pkcs12_is_bagtype_oid(&oid, 2))
+		return pkcs12_pkcs8_keybag(cred, value, value_len, passwd);
+	if (pkcs12_is_bagtype_oid(&oid, 3))
+		return pkcs12_certbag(cred, value, value_len);
+
+	wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unsupported BAG-TYPE");
+	return 0;
+}
+
+
+static int pkcs12_safecontents(struct tlsv1_credentials *cred,
+			       const u8 *buf, size_t len,
+			       const char *passwd)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+
+	/* SafeContents ::= SEQUENCE OF SafeBag */
+	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected SEQUENCE (SafeContents)");
+		return -1;
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	/*
+	 * SafeBag ::= SEQUENCE {
+	 *   bagId          BAG-TYPE.&id ({PKCS12BagSet})
+	 *   bagValue       [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
+	 *   bagAttributes  SET OF PKCS12Attribute OPTIONAL
+	 * }
+	 */
+
+	while (pos < end) {
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    !asn1_is_sequence(&hdr)) {
+			asn1_unexpected(&hdr,
+					"PKCS #12: Expected SEQUENCE (SafeBag)");
+			return -1;
+		}
+		if (pkcs12_safebag(cred, hdr.payload, hdr.length, passwd) < 0)
+			return -1;
+		pos = hdr.payload + hdr.length;
+	}
+
+	return 0;
+}
+
+
+static int pkcs12_parse_content_data(struct tlsv1_credentials *cred,
+				     const u8 *pos, const u8 *end,
+				     const char *passwd)
+{
+	struct asn1_hdr hdr;
+
+	/* Data ::= OCTET STRING */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr, "PKCS #12: Expected OCTET STRING (Data)");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data", hdr.payload, hdr.length);
+
+	return pkcs12_safecontents(cred, hdr.payload, hdr.length, passwd);
+}
+
+
+static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
+					 const u8 *pos, const u8 *end,
+					 const char *passwd)
+{
+	struct asn1_hdr hdr;
+	struct asn1_oid oid;
+	char buf[80];
+	const u8 *enc_alg;
+	u8 *data;
+	size_t enc_alg_len, data_len;
+	int res = -1;
+
+	/*
+	 * EncryptedData ::= SEQUENCE {
+	 *   version Version,
+	 *   encryptedContentInfo EncryptedContentInfo }
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected SEQUENCE (EncryptedData)");
+		return 0;
+	}
+	pos = hdr.payload;
+
+	/* Version ::= INTEGER */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: No INTEGER tag found for version");
+		return -1;
+	}
+	if (hdr.length != 1 || hdr.payload[0] != 0) {
+		wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized PKCS #7 version");
+		return -1;
+	}
+	pos = hdr.payload + hdr.length;
+
+	wpa_hexdump(MSG_MSGDUMP, "PKCS #12: EncryptedContentInfo",
+		    pos, end - pos);
+
+	/*
+	 * EncryptedContentInfo ::= SEQUENCE {
+	 *   contentType ContentType,
+	 *   contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+	 *   encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected SEQUENCE (EncryptedContentInfo)");
+		return -1;
+	}
+
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	/* ContentType ::= OBJECT IDENTIFIER */
+	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
+		return -1;
+	}
+	asn1_oid_to_str(&oid, buf, sizeof(buf));
+	wpa_printf(MSG_DEBUG, "PKCS #12: EncryptedContentInfo::contentType %s",
+		   buf);
+
+	if (!is_oid_pkcs7_data(&oid)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #12: Unsupported EncryptedContentInfo::contentType %s",
+			   buf);
+		return 0;
+	}
+
+	/* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected SEQUENCE (ContentEncryptionAlgorithmIdentifier)");
+		return -1;
+	}
+	enc_alg = hdr.payload;
+	enc_alg_len = hdr.length;
+	pos = hdr.payload + hdr.length;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.constructed ||
+	    !asn1_is_cs_tag(&hdr, 0)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected [0] IMPLICIT (encryptedContent)");
+		return -1;
+	}
+
+	/* EncryptedContent ::= OCTET STRING */
+	data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
+			     passwd, &data_len);
+	if (data) {
+		wpa_hexdump_key(MSG_MSGDUMP,
+				"PKCS #12: Decrypted encryptedContent",
+				data, data_len);
+		res = pkcs12_safecontents(cred, data, data_len, passwd);
+		os_free(data);
+	}
+
+	return res;
+}
+
+
+static int pkcs12_parse_content(struct tlsv1_credentials *cred,
+				const u8 *buf, size_t len,
+				const char *passwd)
+{
+	const u8 *pos = buf;
+	const u8 *end = buf + len;
+	struct asn1_oid oid;
+	char txt[80];
+	struct asn1_hdr hdr;
+
+	wpa_hexdump(MSG_MSGDUMP, "PKCS #12: ContentInfo", buf, len);
+
+	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
+		return 0;
+	}
+
+	asn1_oid_to_str(&oid, txt, sizeof(txt));
+	wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", txt);
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+	    !asn1_is_cs_tag(&hdr, 0)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected [0] EXPLICIT (content)");
+		return 0;
+	}
+	pos = hdr.payload;
+
+	if (is_oid_pkcs7_data(&oid))
+		return pkcs12_parse_content_data(cred, pos, end, passwd);
+	if (is_oid_pkcs7_enc_data(&oid))
+		return pkcs12_parse_content_enc_data(cred, pos, end, passwd);
+
+	wpa_printf(MSG_DEBUG, "PKCS #12: Ignored unsupported contentType %s",
+		   txt);
+
+	return 0;
+}
+
+
+static int pkcs12_parse(struct tlsv1_credentials *cred,
+			const u8 *key, size_t len, const char *passwd)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+	struct asn1_oid oid;
+	char buf[80];
+
+	/*
+	 * PFX ::= SEQUENCE {
+	 *     version     INTEGER {v3(3)}(v3,...),
+	 *     authSafe    ContentInfo,
+	 *     macData     MacData OPTIONAL
+	 * }
+	 */
+
+	if (asn1_get_next(key, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected SEQUENCE (PFX); assume PKCS #12 not used");
+		return -1;
+	}
+
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: No INTEGER tag found for version");
+		return -1;
+	}
+	if (hdr.length != 1 || hdr.payload[0] != 3) {
+		wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized version");
+		return -1;
+	}
+	pos = hdr.payload + hdr.length;
+
+	/*
+	 * ContentInfo ::= SEQUENCE {
+	 *   contentType ContentType,
+	 *   content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+	 */
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected SEQUENCE (authSafe); assume PKCS #12 not used");
+		return -1;
+	}
+
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	/* ContentType ::= OBJECT IDENTIFIER */
+	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG,
+			   "PKCS #12: Could not find OBJECT IDENTIFIER (contentType); assume PKCS #12 not used");
+		return -1;
+	}
+	asn1_oid_to_str(&oid, buf, sizeof(buf));
+	wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", buf);
+	if (!is_oid_pkcs7_data(&oid)) {
+		wpa_printf(MSG_DEBUG, "PKCS #12: Unsupported contentType %s",
+			   buf);
+		return -1;
+	}
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed ||
+	    !asn1_is_cs_tag(&hdr, 0)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected [0] EXPLICIT (content); assume PKCS #12 not used");
+		return -1;
+	}
+
+	pos = hdr.payload;
+
+	/* Data ::= OCTET STRING */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_octetstring(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected OCTET STRING (Data); assume PKCS #12 not used");
+		return -1;
+	}
+
+	/*
+	 * AuthenticatedSafe ::= SEQUENCE OF ContentInfo
+	 *     -- Data if unencrypted
+	 *     -- EncryptedData if password-encrypted
+	 *     -- EnvelopedData if public key-encrypted
+	 */
+	wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data content",
+		    hdr.payload, hdr.length);
+
+	if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+	    !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"PKCS #12: Expected SEQUENCE within Data content; assume PKCS #12 not used");
+		return -1;
+	}
+
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	while (end > pos) {
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    !asn1_is_sequence(&hdr)) {
+			asn1_unexpected(&hdr,
+					"PKCS #12: Expected SEQUENCE (ContentInfo); assume PKCS #12 not used");
+			return -1;
+		}
+		if (pkcs12_parse_content(cred, hdr.payload, hdr.length,
+					 passwd) < 0)
+			return -1;
+
+		pos = hdr.payload + hdr.length;
+	}
+
+	return 0;
+}
+
+#endif /* PKCS12_FUNCS */
+
+
 static int tlsv1_set_key(struct tlsv1_credentials *cred,
 static int tlsv1_set_key(struct tlsv1_credentials *cred,
 			 const u8 *key, size_t len, const char *passwd)
 			 const u8 *key, size_t len, const char *passwd)
 {
 {
@@ -294,6 +1011,10 @@ static int tlsv1_set_key(struct tlsv1_credentials *cred,
 		cred->key = tlsv1_set_key_pem(key, len);
 		cred->key = tlsv1_set_key_pem(key, len);
 	if (cred->key == NULL)
 	if (cred->key == NULL)
 		cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
 		cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
+#ifdef PKCS12_FUNCS
+	if (!cred->key)
+		pkcs12_parse(cred, key, len, passwd);
+#endif /* PKCS12_FUNCS */
 	if (cred->key == NULL) {
 	if (cred->key == NULL) {
 		wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
 		wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
 		return -1;
 		return -1;
@@ -327,10 +1048,11 @@ int tlsv1_set_private_key(struct tlsv1_credentials *cred,
 				     private_key_passwd);
 				     private_key_passwd);
 
 
 	if (private_key) {
 	if (private_key) {
-		u8 *buf = NULL;
-		size_t len = 0;
+		u8 *buf;
+		size_t len;
 		int ret;
 		int ret;
 
 
+		buf = (u8 *) os_readfile(private_key, &len);
 		if (buf == NULL) {
 		if (buf == NULL) {
 			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
 			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
 				   private_key);
 				   private_key);
@@ -363,24 +1085,17 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
 	 */
 	 */
 
 
 	/* DHParamer ::= SEQUENCE */
 	/* DHParamer ::= SEQUENCE */
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
-			   "valid SEQUENCE - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
+	if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
+		asn1_unexpected(&hdr,
+				"DH: DH parameters did not start with a valid SEQUENCE");
 		return -1;
 		return -1;
 	}
 	}
 	pos = hdr.payload;
 	pos = hdr.payload;
 
 
 	/* prime INTEGER */
 	/* prime INTEGER */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0)
-		return -1;
-
-	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
-			   "class=%d tag=0x%x", hdr.class, hdr.tag);
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_integer(&hdr)) {
+		asn1_unexpected(&hdr, "DH: No INTEGER tag found for p");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -388,21 +1103,16 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
 	if (hdr.length == 0)
 	if (hdr.length == 0)
 		return -1;
 		return -1;
 	os_free(cred->dh_p);
 	os_free(cred->dh_p);
-	cred->dh_p = os_malloc(hdr.length);
+	cred->dh_p = os_memdup(hdr.payload, hdr.length);
 	if (cred->dh_p == NULL)
 	if (cred->dh_p == NULL)
 		return -1;
 		return -1;
-	os_memcpy(cred->dh_p, hdr.payload, hdr.length);
 	cred->dh_p_len = hdr.length;
 	cred->dh_p_len = hdr.length;
 	pos = hdr.payload + hdr.length;
 	pos = hdr.payload + hdr.length;
 
 
 	/* base INTEGER */
 	/* base INTEGER */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0)
-		return -1;
-
-	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
-			   "class=%d tag=0x%x", hdr.class, hdr.tag);
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    !asn1_is_integer(&hdr)) {
+		asn1_unexpected(&hdr, "DH: No INTEGER tag found for g");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -410,10 +1120,9 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
 	if (hdr.length == 0)
 	if (hdr.length == 0)
 		return -1;
 		return -1;
 	os_free(cred->dh_g);
 	os_free(cred->dh_g);
-	cred->dh_g = os_malloc(hdr.length);
+	cred->dh_g = os_memdup(hdr.payload, hdr.length);
 	if (cred->dh_g == NULL)
 	if (cred->dh_g == NULL)
 		return -1;
 		return -1;
-	os_memcpy(cred->dh_g, hdr.payload, hdr.length);
 	cred->dh_g_len = hdr.length;
 	cred->dh_g_len = hdr.length;
 
 
 	return 0;
 	return 0;
@@ -449,7 +1158,7 @@ static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
+	der = base64_decode((const char *) pos, end - pos, &der_len);
 	if (der == NULL) {
 	if (der == NULL) {
 		wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
 		wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
 		return -1;
 		return -1;
@@ -483,10 +1192,11 @@ int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
 		return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
 		return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
 
 
 	if (dh_file) {
 	if (dh_file) {
-		u8 *buf = NULL;
-		size_t len = 0;
+		u8 *buf;
+		size_t len;
 		int ret;
 		int ret;
 
 
+		buf = (u8 *) os_readfile(dh_file, &len);
 		if (buf == NULL) {
 		if (buf == NULL) {
 			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
 			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
 				   dh_file);
 				   dh_file);

+ 8 - 0
components/wpa_supplicant/src/tls/tlsv1_cred.h

@@ -14,11 +14,19 @@ struct tlsv1_credentials {
 	struct x509_certificate *cert;
 	struct x509_certificate *cert;
 	struct crypto_private_key *key;
 	struct crypto_private_key *key;
 
 
+	unsigned int cert_probe:1;
+	unsigned int ca_cert_verify:1;
+	unsigned int server_cert_only:1;
+	u8 srv_cert_hash[32];
+
 	/* Diffie-Hellman parameters */
 	/* Diffie-Hellman parameters */
 	u8 *dh_p; /* prime */
 	u8 *dh_p; /* prime */
 	size_t dh_p_len;
 	size_t dh_p_len;
 	u8 *dh_g; /* generator */
 	u8 *dh_g; /* generator */
 	size_t dh_g_len;
 	size_t dh_g_len;
+
+	char *ocsp_stapling_response;
+	char *ocsp_stapling_response_multi;
 };
 };
 
 
 
 

+ 27 - 33
components/wpa_supplicant/src/tls/tlsv1_record.c

@@ -6,16 +6,15 @@
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
+#include "common.h"
 #include "crypto/md5.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
 #include "crypto/sha256.h"
-#include "tls/tlsv1_common.h"
-#include "tls/tlsv1_record.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
 
 
-#include "eap_peer/eap_i.h"
 
 
 /**
 /**
  * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
  * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
@@ -83,13 +82,11 @@ int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
 	if (rl->write_cbc) {
 	if (rl->write_cbc) {
 		crypto_cipher_deinit(rl->write_cbc);
 		crypto_cipher_deinit(rl->write_cbc);
 		rl->write_cbc = NULL;
 		rl->write_cbc = NULL;
-
 	}
 	}
 	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
 	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
 		rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
 		rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
-									rl->write_iv, rl->write_key,
-									rl->key_material_len);
-
+						   rl->write_iv, rl->write_key,
+						   rl->key_material_len);
 		if (rl->write_cbc == NULL) {
 		if (rl->write_cbc == NULL) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
 				   "cipher");
 				   "cipher");
@@ -112,19 +109,18 @@ int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
 int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
 int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
 {
 {
 	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
 	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
-		   "0x%04x \n", rl->cipher_suite);
+		   "0x%04x", rl->cipher_suite);
 	rl->read_cipher_suite = rl->cipher_suite;
 	rl->read_cipher_suite = rl->cipher_suite;
 	os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
 	os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
 
 
 	if (rl->read_cbc) {
 	if (rl->read_cbc) {
 		crypto_cipher_deinit(rl->read_cbc);
 		crypto_cipher_deinit(rl->read_cbc);
-		rl->read_cbc =  NULL;
+		rl->read_cbc = NULL;
 	}
 	}
-
 	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
 	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
 		rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
 		rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
-									rl->read_iv, rl->read_key,
-									rl->key_material_len);
+						  rl->read_iv, rl->read_key,
+						  rl->key_material_len);
 		if (rl->read_cbc == NULL) {
 		if (rl->read_cbc == NULL) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
 				   "cipher");
 				   "cipher");
@@ -156,7 +152,7 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
 		      size_t *out_len)
 		      size_t *out_len)
 {
 {
 	u8 *pos, *ct_start, *length, *cpayload;
 	u8 *pos, *ct_start, *length, *cpayload;
-	struct crypto_hash *hmac = NULL;
+	struct crypto_hash *hmac;
 	size_t clen;
 	size_t clen;
 	int explicit_iv;
 	int explicit_iv;
 
 
@@ -208,7 +204,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
 		 * TLSCompressed.version + TLSCompressed.length +
 		 * TLSCompressed.version + TLSCompressed.length +
 		 * TLSCompressed.fragment
 		 * TLSCompressed.fragment
 		 */
 		 */
-		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret, rl->hash_size);
+		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
+					rl->hash_size);
 		if (hmac == NULL) {
 		if (hmac == NULL) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
 				   "to initialize HMAC");
 				   "to initialize HMAC");
@@ -223,15 +220,14 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
 				   "enough room for MAC");
 				   "enough room for MAC");
 			crypto_hash_finish(hmac, NULL, NULL);
 			crypto_hash_finish(hmac, NULL, NULL);
-
 			return -1;
 			return -1;
 		}
 		}
 
 
-		if ((int)crypto_hash_finish(hmac, pos, &clen) < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC");
+		if (crypto_hash_finish(hmac, pos, &clen) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to calculate HMAC");
 			return -1;
 			return -1;
 		}
 		}
-
 		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
 		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
 			    pos, clen);
 			    pos, clen);
 		pos += clen;
 		pos += clen;
@@ -250,8 +246,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
 			pos += pad + 1;
 			pos += pad + 1;
 		}
 		}
 
 
-		if ((int)crypto_cipher_encrypt(rl->write_cbc, cpayload,
-							cpayload, pos - cpayload) < 0)
+		if (crypto_cipher_encrypt(rl->write_cbc, cpayload,
+					  cpayload, pos - cpayload) < 0)
 			return -1;
 			return -1;
 	}
 	}
 
 
@@ -285,7 +281,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
 {
 {
 	size_t i, rlen, hlen;
 	size_t i, rlen, hlen;
 	u8 padlen;
 	u8 padlen;
-	struct crypto_hash *hmac = NULL;
+	struct crypto_hash *hmac;
 	u8 len[2], hash[100];
 	u8 len[2], hash[100];
 	int force_mac_error = 0;
 	int force_mac_error = 0;
 	u8 ct;
 	u8 ct;
@@ -358,12 +354,11 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
 
 
 	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
 	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
 		size_t plen;
 		size_t plen;
-		if ((int)crypto_cipher_decrypt(rl->read_cbc, in_data,
-					                        out_data, in_len) < 0) {
+		if (crypto_cipher_decrypt(rl->read_cbc, in_data,
+					  out_data, in_len) < 0) {
 			*alert = TLS_ALERT_DECRYPTION_FAILED;
 			*alert = TLS_ALERT_DECRYPTION_FAILED;
 			return -1;
 			return -1;
 		}
 		}
-
 		plen = in_len;
 		plen = in_len;
 		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
 		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
 				"data", out_data, plen);
 				"data", out_data, plen);
@@ -438,8 +433,8 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
 
 
 		plen -= rl->hash_size;
 		plen -= rl->hash_size;
 
 
-		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size);
-
+		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
+					rl->hash_size);
 		if (hmac == NULL) {
 		if (hmac == NULL) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
 				   "to initialize HMAC");
 				   "to initialize HMAC");
@@ -453,16 +448,15 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
 		WPA_PUT_BE16(len, plen);
 		WPA_PUT_BE16(len, plen);
 		crypto_hash_update(hmac, len, 2);
 		crypto_hash_update(hmac, len, 2);
 		crypto_hash_update(hmac, out_data, plen);
 		crypto_hash_update(hmac, out_data, plen);
-
 		hlen = sizeof(hash);
 		hlen = sizeof(hash);
-		if ((int)crypto_hash_finish(hmac, hash, &hlen) < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC");
+		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to calculate HMAC");
 			*alert = TLS_ALERT_INTERNAL_ERROR;
 			*alert = TLS_ALERT_INTERNAL_ERROR;
 			return -1;
 			return -1;
 		}
 		}
-
 		if (hlen != rl->hash_size ||
 		if (hlen != rl->hash_size ||
-		    os_memcmp(hash, out_data + plen, hlen) != 0 ||
+		    os_memcmp_const(hash, out_data + plen, hlen) != 0 ||
 		    force_mac_error) {
 		    force_mac_error) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
 			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
 				   "received message (force_mac_error=%d)",
 				   "received message (force_mac_error=%d)",

+ 276 - 69
components/wpa_supplicant/src/tls/tlsv1_server.c

@@ -1,26 +1,51 @@
 /*
 /*
  * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
  * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
+#include "common.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
-#include "tls/tls.h"
-#include "tls/tlsv1_common.h"
-#include "tls/tlsv1_record.h"
-#include "tls/tlsv1_server.h"
-#include "tls/tlsv1_server_i.h"
+#include "crypto/tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
 
 
 /* TODO:
 /* TODO:
  * Support for a message fragmented across several records (RFC 2246, 6.2.1)
  * Support for a message fragmented across several records (RFC 2246, 6.2.1)
  */
  */
 
 
 
 
+void tlsv1_server_log(struct tlsv1_server *conn, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	int buflen;
+
+	va_start(ap, fmt);
+	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+	va_end(ap);
+
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	va_start(ap, fmt);
+	vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+
+	wpa_printf(MSG_DEBUG, "TLSv1: %s", buf);
+	if (conn->log_cb)
+		conn->log_cb(conn->log_cb_ctx, buf);
+
+	os_free(buf);
+}
+
+
 void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
 void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
 {
 {
 	conn->alert_level = level;
 	conn->alert_level = level;
@@ -139,7 +164,8 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
 			/* need more data */
 			/* need more data */
 			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
 			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
 				   "yet supported");
 				   "yet supported");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
 			goto failed;
 			goto failed;
 		}
 		}
 		ct = pos[0];
 		ct = pos[0];
@@ -179,6 +205,7 @@ failed:
 		msg = tlsv1_server_send_alert(conn, conn->alert_level,
 		msg = tlsv1_server_send_alert(conn, conn->alert_level,
 					      conn->alert_description,
 					      conn->alert_description,
 					      out_len);
 					      out_len);
+		conn->write_alerts++;
 	}
 	}
 
 
 	return msg;
 	return msg;
@@ -250,8 +277,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
 		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
 		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
 					    out_pos, &olen, &alert);
 					    out_pos, &olen, &alert);
 		if (used < 0) {
 		if (used < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
-				   "failed");
+			tlsv1_server_log(conn, "Record layer processing failed");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
 			return -1;
 			return -1;
 		}
 		}
@@ -265,14 +291,14 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
 
 
 		if (ct == TLS_CONTENT_TYPE_ALERT) {
 		if (ct == TLS_CONTENT_TYPE_ALERT) {
 			if (olen < 2) {
 			if (olen < 2) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
-					   "underflow");
+				tlsv1_server_log(conn, "Alert underflow");
 				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 						   TLS_ALERT_DECODE_ERROR);
 						   TLS_ALERT_DECODE_ERROR);
 				return -1;
 				return -1;
 			}
 			}
-			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
-				   out_pos[0], out_pos[1]);
+			tlsv1_server_log(conn, "Received alert %d:%d",
+					 out_pos[0], out_pos[1]);
+			conn->read_alerts++;
 			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
 			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
 				/* Continue processing */
 				/* Continue processing */
 				pos += used;
 				pos += used;
@@ -285,13 +311,23 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
 		}
 		}
 
 
 		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
 		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
-				   "0x%x", pos[0]);
+			tlsv1_server_log(conn, "Unexpected content type 0x%x",
+					 pos[0]);
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_UNEXPECTED_MESSAGE);
 					   TLS_ALERT_UNEXPECTED_MESSAGE);
 			return -1;
 			return -1;
 		}
 		}
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+		if ((conn->test_flags &
+		     (TLS_BREAK_VERIFY_DATA | TLS_BREAK_SRV_KEY_X_HASH |
+		      TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+		    !conn->test_failure_reported) {
+			tlsv1_server_log(conn, "TEST-FAILURE: Client ApplData received after invalid handshake");
+			conn->test_failure_reported = 1;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 		out_pos += olen;
 		out_pos += olen;
 		if (out_pos > out_end) {
 		if (out_pos > out_end) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
 			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -344,7 +380,7 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
 	size_t count;
 	size_t count;
 	u16 *suites;
 	u16 *suites;
 
 
-	conn = (struct tlsv1_server *)os_zalloc(sizeof(*conn));
+	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
 	if (conn == NULL)
 		return NULL;
 		return NULL;
 
 
@@ -361,11 +397,16 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
 
 
 	count = 0;
 	count = 0;
 	suites = conn->cipher_suites;
 	suites = conn->cipher_suites;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+	suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
-#ifdef CONFIG_DES3
+	suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-#endif
 	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
 	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
 	conn->num_cipher_suites = count;
 	conn->num_cipher_suites = count;
@@ -421,6 +462,8 @@ int tlsv1_server_established(struct tlsv1_server *conn)
  * tlsv1_server_prf - Use TLS-PRF to derive keying material
  * tlsv1_server_prf - Use TLS-PRF to derive keying material
  * @conn: TLSv1 server connection data from tlsv1_server_init()
  * @conn: TLSv1 server connection data from tlsv1_server_init()
  * @label: Label (e.g., description of the key) for PRF
  * @label: Label (e.g., description of the key) for PRF
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
  * @server_random_first: seed is 0 = client_random|server_random,
  * @server_random_first: seed is 0 = client_random|server_random,
  * 1 = server_random|client_random
  * 1 = server_random|client_random
  * @out: Buffer for output data from TLS-PRF
  * @out: Buffer for output data from TLS-PRF
@@ -428,13 +471,26 @@ int tlsv1_server_established(struct tlsv1_server *conn)
  * Returns: 0 on success, -1 on failure
  * Returns: 0 on success, -1 on failure
  */
  */
 int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
 int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+		     const u8 *context, size_t context_len,
 		     int server_random_first, u8 *out, size_t out_len)
 		     int server_random_first, u8 *out, size_t out_len)
 {
 {
-	u8 seed[2 * TLS_RANDOM_LEN];
+	u8 *seed, *pos;
+	size_t seed_len = 2 * TLS_RANDOM_LEN;
+	int res;
 
 
 	if (conn->state != ESTABLISHED)
 	if (conn->state != ESTABLISHED)
 		return -1;
 		return -1;
 
 
+	if (context_len > 65535)
+		return -1;
+
+	if (context)
+		seed_len += 2 + context_len;
+
+	seed = os_malloc(seed_len);
+	if (!seed)
+		return -1;
+
 	if (server_random_first) {
 	if (server_random_first) {
 		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
 		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
 		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
 		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
@@ -445,9 +501,18 @@ int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
 			  TLS_RANDOM_LEN);
 			  TLS_RANDOM_LEN);
 	}
 	}
 
 
-	return tls_prf(conn->rl.tls_version,
-		       conn->master_secret, TLS_MASTER_SECRET_LEN,
-		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+	if (context) {
+		pos = seed + 2 * TLS_RANDOM_LEN;
+		WPA_PUT_BE16(pos, context_len);
+		pos += 2;
+		os_memcpy(pos, context, context_len);
+	}
+
+	res = tls_prf(conn->rl.tls_version,
+		      conn->master_secret, TLS_MASTER_SECRET_LEN,
+		      label, seed, seed_len, out, out_len);
+	os_free(seed);
+	return res;
 }
 }
 
 
 
 
@@ -463,8 +528,7 @@ int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
 int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
 int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
 			    size_t buflen)
 			    size_t buflen)
 {
 {
-#ifndef ESPRESSIF_USE
-    char *cipher;
+	char *cipher;
 
 
 	switch (conn->rl.cipher_suite) {
 	switch (conn->rl.cipher_suite) {
 	case TLS_RSA_WITH_RC4_128_MD5:
 	case TLS_RSA_WITH_RC4_128_MD5:
@@ -473,67 +537,70 @@ int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
 	case TLS_RSA_WITH_RC4_128_SHA:
 	case TLS_RSA_WITH_RC4_128_SHA:
 		cipher = "RC4-SHA";
 		cipher = "RC4-SHA";
 		break;
 		break;
-#ifdef CONFIG_DES
 	case TLS_RSA_WITH_DES_CBC_SHA:
 	case TLS_RSA_WITH_DES_CBC_SHA:
 		cipher = "DES-CBC-SHA";
 		cipher = "DES-CBC-SHA";
 		break;
 		break;
-#endif
-#ifdef CONFIG_DES3
 	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
 	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
 		cipher = "DES-CBC3-SHA";
 		cipher = "DES-CBC3-SHA";
 		break;
 		break;
-#endif
+	case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+		cipher = "DHE-RSA-DES-CBC-SHA";
+		break;
+	case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+		cipher = "DHE-RSA-DES-CBC3-SHA";
+		break;
+	case TLS_DH_anon_WITH_RC4_128_MD5:
+		cipher = "ADH-RC4-MD5";
+		break;
+	case TLS_DH_anon_WITH_DES_CBC_SHA:
+		cipher = "ADH-DES-SHA";
+		break;
+	case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+		cipher = "ADH-DES-CBC3-SHA";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "AES-128-SHA";
+		break;
+	case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "DHE-RSA-AES-128-SHA";
+		break;
 	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
 	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
 		cipher = "ADH-AES-128-SHA";
 		cipher = "ADH-AES-128-SHA";
 		break;
 		break;
 	case TLS_RSA_WITH_AES_256_CBC_SHA:
 	case TLS_RSA_WITH_AES_256_CBC_SHA:
 		cipher = "AES-256-SHA";
 		cipher = "AES-256-SHA";
 		break;
 		break;
-	case TLS_RSA_WITH_AES_128_CBC_SHA:
-		cipher = "AES-128-SHA";
+	case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+		cipher = "DHE-RSA-AES-256-SHA";
+		break;
+	case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+		cipher = "ADH-AES-256-SHA";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA256:
+		cipher = "AES-128-SHA256";
+		break;
+	case TLS_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "AES-256-SHA256";
+		break;
+	case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+		cipher = "DHE-RSA-AES-128-SHA256";
+		break;
+	case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "DHE-RSA-AES-256-SHA256";
+		break;
+	case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+		cipher = "ADH-AES-128-SHA256";
+		break;
+	case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+		cipher = "ADH-AES-256-SHA256";
 		break;
 		break;
 	default:
 	default:
 		return -1;
 		return -1;
 	}
 	}
 
 
-	//if (os_strlcpy(buf, cipher, buflen) >= buflen)
-	//	return -1;
-
-	os_memcpy((u8 *)buf, (u8 *)cipher, buflen);
-
+	if (os_strlcpy(buf, cipher, buflen) >= buflen)
+		return -1;
 	return 0;
 	return 0;
-#else
-    char cipher[20];
-
-    switch (conn->rl.cipher_suite) {
-        case TLS_RSA_WITH_RC4_128_MD5:
-		    strcpy(cipher, "RC4-MD5");
-		    break;
-        case TLS_RSA_WITH_RC4_128_SHA:
-            strcpy(cipher, "RC4-SHA");
-            break;
-        case TLS_RSA_WITH_DES_CBC_SHA:
-            strcpy(cipher, "DES-CBC-SHA");
-            break;
-        case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-            strcpy(cipher, "DES-CBC3-SHA");
-            break;
-        case TLS_DH_anon_WITH_AES_128_CBC_SHA:
-            strcpy(cipher, "ADH-AES-128-SHA");
-            break;
-        case TLS_RSA_WITH_AES_256_CBC_SHA:
-            strcpy(cipher, "AES-256-SHA");
-            break;
-        case TLS_RSA_WITH_AES_128_CBC_SHA:
-            strcpy(cipher, "AES-128-SHA");
-            break;
-        default:
-            return -1;
-	}
-    os_memcpy((u8 *)buf, (u8 *)cipher, buflen);
-
-    return 0;
-#endif
 }
 }
 
 
 
 
@@ -658,3 +725,143 @@ void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
 	conn->session_ticket_cb = cb;
 	conn->session_ticket_cb = cb;
 	conn->session_ticket_cb_ctx = ctx;
 	conn->session_ticket_cb_ctx = ctx;
 }
 }
+
+
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+			     void (*cb)(void *ctx, const char *msg), void *ctx)
+{
+	conn->log_cb = cb;
+	conn->log_cb_ctx = ctx;
+}
+
+
+int tlsv1_server_get_failed(struct tlsv1_server *conn)
+{
+	return conn->state == FAILED;
+}
+
+
+int tlsv1_server_get_read_alerts(struct tlsv1_server *conn)
+{
+	return conn->read_alerts;
+}
+
+
+int tlsv1_server_get_write_alerts(struct tlsv1_server *conn)
+{
+	return conn->write_alerts;
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags)
+{
+	conn->test_flags = flags;
+}
+
+
+static const u8 test_tls_prime15[1] = {
+	15
+};
+
+static const u8 test_tls_prime511b[64] = {
+	0x50, 0xfb, 0xf1, 0xae, 0x01, 0xf1, 0xfe, 0xe6,
+	0xe1, 0xae, 0xdc, 0x1e, 0xbe, 0xfb, 0x9e, 0x58,
+	0x9a, 0xd7, 0x54, 0x9d, 0x6b, 0xb3, 0x78, 0xe2,
+	0x39, 0x7f, 0x30, 0x01, 0x25, 0xa1, 0xf9, 0x7c,
+	0x55, 0x0e, 0xa1, 0x15, 0xcc, 0x36, 0x34, 0xbb,
+	0x6c, 0x8b, 0x64, 0x45, 0x15, 0x7f, 0xd3, 0xe7,
+	0x31, 0xc8, 0x8e, 0x56, 0x8e, 0x95, 0xdc, 0xea,
+	0x9e, 0xdf, 0xf7, 0x56, 0xdd, 0xb0, 0x34, 0xdb
+};
+
+static const u8 test_tls_prime767b[96] = {
+	0x4c, 0xdc, 0xb8, 0x21, 0x20, 0x9d, 0xe8, 0xa3,
+	0x53, 0xd9, 0x1c, 0x18, 0xc1, 0x3a, 0x58, 0x67,
+	0xa7, 0x85, 0xf9, 0x28, 0x9b, 0xce, 0xc0, 0xd1,
+	0x05, 0x84, 0x61, 0x97, 0xb2, 0x86, 0x1c, 0xd0,
+	0xd1, 0x96, 0x23, 0x29, 0x8c, 0xc5, 0x30, 0x68,
+	0x3e, 0xf9, 0x05, 0xba, 0x60, 0xeb, 0xdb, 0xee,
+	0x2d, 0xdf, 0x84, 0x65, 0x49, 0x87, 0x90, 0x2a,
+	0xc9, 0x8e, 0x34, 0x63, 0x6d, 0x9a, 0x2d, 0x32,
+	0x1c, 0x46, 0xd5, 0x4e, 0x20, 0x20, 0x90, 0xac,
+	0xd5, 0x48, 0x79, 0x99, 0x0c, 0xe6, 0xed, 0xbf,
+	0x79, 0xc2, 0x47, 0x50, 0x95, 0x38, 0x38, 0xbc,
+	0xde, 0xb0, 0xd2, 0xe8, 0x97, 0xcb, 0x22, 0xbb
+};
+
+static const u8 test_tls_prime58[128] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0xc1, 0xba, 0xc8, 0x25, 0xbe, 0x2d, 0xf3
+};
+
+static const u8 test_tls_non_prime[] = {
+	/*
+	 * This is not a prime and the value has the following factors:
+	 * 13736783488716579923 * 16254860191773456563 * 18229434976173670763 *
+	 * 11112313018289079419 * 10260802278580253339 * 12394009491575311499 *
+	 * 12419059668711064739 * 14317973192687985827 * 10498605410533203179 *
+	 * 16338688760390249003 * 11128963991123878883 * 12990532258280301419 *
+	 * 3
+	 */
+	0x0C, 0x8C, 0x36, 0x9C, 0x6F, 0x71, 0x2E, 0xA7,
+	0xAB, 0x32, 0xD3, 0x0F, 0x68, 0x3D, 0xB2, 0x6D,
+	0x81, 0xDD, 0xC4, 0x84, 0x0D, 0x9C, 0x6E, 0x36,
+	0x29, 0x70, 0xF3, 0x1E, 0x9A, 0x42, 0x0B, 0x67,
+	0x82, 0x6B, 0xB1, 0xF2, 0xAF, 0x55, 0x28, 0xE7,
+	0xDB, 0x67, 0x6C, 0xF7, 0x6B, 0xAC, 0xAC, 0xE5,
+	0xF7, 0x9F, 0xD4, 0x63, 0x55, 0x70, 0x32, 0x7C,
+	0x70, 0xFB, 0xAF, 0xB8, 0xEB, 0x37, 0xCF, 0x3F,
+	0xFE, 0x94, 0x73, 0xF9, 0x7A, 0xC7, 0x12, 0x2E,
+	0x9B, 0xB4, 0x7D, 0x08, 0x60, 0x83, 0x43, 0x52,
+	0x83, 0x1E, 0xA5, 0xFC, 0xFA, 0x87, 0x12, 0xF4,
+	0x64, 0xE2, 0xCE, 0x71, 0x17, 0x72, 0xB6, 0xAB
+};
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p,
+			   size_t *dh_p_len)
+{
+	*dh_p = conn->cred->dh_p;
+	*dh_p_len = conn->cred->dh_p_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	if (conn->test_flags & TLS_DHE_PRIME_511B) {
+		tlsv1_server_log(conn, "TESTING: Use short 511-bit prime with DHE");
+		*dh_p = test_tls_prime511b;
+		*dh_p_len = sizeof(test_tls_prime511b);
+	} else if (conn->test_flags & TLS_DHE_PRIME_767B) {
+		tlsv1_server_log(conn, "TESTING: Use short 767-bit prime with DHE");
+		*dh_p = test_tls_prime767b;
+		*dh_p_len = sizeof(test_tls_prime767b);
+	} else if (conn->test_flags & TLS_DHE_PRIME_15) {
+		tlsv1_server_log(conn, "TESTING: Use bogus 15 \"prime\" with DHE");
+		*dh_p = test_tls_prime15;
+		*dh_p_len = sizeof(test_tls_prime15);
+	} else if (conn->test_flags & TLS_DHE_PRIME_58B) {
+		tlsv1_server_log(conn, "TESTING: Use short 58-bit prime in long container with DHE");
+		*dh_p = test_tls_prime58;
+		*dh_p_len = sizeof(test_tls_prime58);
+	} else if (conn->test_flags & TLS_DHE_NON_PRIME) {
+		tlsv1_server_log(conn, "TESTING: Use claim non-prime as the DHE prime");
+		*dh_p = test_tls_non_prime;
+		*dh_p_len = sizeof(test_tls_non_prime);
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+}

+ 11 - 1
components/wpa_supplicant/src/tls/tlsv1_server.h

@@ -1,6 +1,6 @@
 /*
 /*
  * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
  * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
@@ -19,6 +19,7 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred);
 void tlsv1_server_deinit(struct tlsv1_server *conn);
 void tlsv1_server_deinit(struct tlsv1_server *conn);
 int tlsv1_server_established(struct tlsv1_server *conn);
 int tlsv1_server_established(struct tlsv1_server *conn);
 int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
 int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+		     const u8 *context, size_t context_len,
 		     int server_random_first, u8 *out, size_t out_len);
 		     int server_random_first, u8 *out, size_t out_len);
 u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
 u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
 			    const u8 *in_data, size_t in_len, size_t *out_len);
 			    const u8 *in_data, size_t in_len, size_t *out_len);
@@ -45,4 +46,13 @@ void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
 					tlsv1_server_session_ticket_cb cb,
 					tlsv1_server_session_ticket_cb cb,
 					void *ctx);
 					void *ctx);
 
 
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+			     void (*cb)(void *ctx, const char *msg), void *ctx);
+
+int tlsv1_server_get_failed(struct tlsv1_server *conn);
+int tlsv1_server_get_read_alerts(struct tlsv1_server *conn);
+int tlsv1_server_get_write_alerts(struct tlsv1_server *conn);
+
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags);
+
 #endif /* TLSV1_SERVER_H */
 #endif /* TLSV1_SERVER_H */

+ 18 - 0
components/wpa_supplicant/src/tls/tlsv1_server_i.h

@@ -30,6 +30,8 @@ struct tlsv1_server {
 	u8 alert_level;
 	u8 alert_level;
 	u8 alert_description;
 	u8 alert_description;
 
 
+	int read_alerts, write_alerts;
+
 	struct crypto_public_key *client_rsa_key;
 	struct crypto_public_key *client_rsa_key;
 
 
 	struct tls_verify_hash verify;
 	struct tls_verify_hash verify;
@@ -51,13 +53,27 @@ struct tlsv1_server {
 	tlsv1_server_session_ticket_cb session_ticket_cb;
 	tlsv1_server_session_ticket_cb session_ticket_cb;
 	void *session_ticket_cb_ctx;
 	void *session_ticket_cb_ctx;
 
 
+	void (*log_cb)(void *ctx, const char *msg);
+	void *log_cb_ctx;
+
 	int use_session_ticket;
 	int use_session_ticket;
+	unsigned int status_request:1;
+	unsigned int status_request_v2:1;
+	unsigned int status_request_multi:1;
 
 
 	u8 *dh_secret;
 	u8 *dh_secret;
 	size_t dh_secret_len;
 	size_t dh_secret_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+	u32 test_flags;
+	int test_failure_reported;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 };
 
 
 
 
+void tlsv1_server_log(struct tlsv1_server *conn, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+
 void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
 void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
 int tlsv1_server_derive_keys(struct tlsv1_server *conn,
 int tlsv1_server_derive_keys(struct tlsv1_server *conn,
 			     const u8 *pre_master_secret,
 			     const u8 *pre_master_secret,
@@ -67,5 +83,7 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
 			     u8 description, size_t *out_len);
 			     u8 description, size_t *out_len);
 int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
 int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
 				   const u8 *buf, size_t *len);
 				   const u8 *buf, size_t *len);
+void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p,
+			   size_t *dh_p_len);
 
 
 #endif /* TLSV1_SERVER_I_H */
 #endif /* TLSV1_SERVER_I_H */

File diff suppressed because it is too large
+ 278 - 246
components/wpa_supplicant/src/tls/tlsv1_server_read.c


+ 339 - 49
components/wpa_supplicant/src/tls/tlsv1_server_write.c

@@ -1,33 +1,32 @@
 /*
 /*
  * TLSv1 server - write handshake message
  * TLSv1 server - write handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
  *
  *
  * This software may be distributed under the terms of the BSD license.
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * See README for more details.
  */
  */
 
 
-#include "utils/includes.h"
+#include "includes.h"
 
 
-#include "utils/common.h"
+#include "common.h"
 #include "crypto/md5.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
 #include "crypto/sha1.h"
 #include "crypto/sha256.h"
 #include "crypto/sha256.h"
+#include "crypto/tls.h"
 #include "crypto/random.h"
 #include "crypto/random.h"
-#include "tls/tls.h"
-#include "tls/x509v3.h"
-#include "tls/tlsv1_common.h"
-#include "tls/tlsv1_record.h"
-#include "tls/tlsv1_server.h"
-#include "tls/tlsv1_server_i.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
 
 
-#include "eap_peer/eap_i.h"
 
 
 static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
 static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
 {
 {
 	size_t len = 0;
 	size_t len = 0;
 	struct x509_certificate *cert;
 	struct x509_certificate *cert;
 
 
-	cert = conn->cred->cert;
+	cert = conn->cred ? conn->cred->cert : NULL;
 	while (cert) {
 	while (cert) {
 		len += 3 + cert->cert_len;
 		len += 3 + cert->cert_len;
 		if (x509_certificate_self_signed(cert))
 		if (x509_certificate_self_signed(cert))
@@ -43,17 +42,20 @@ static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
 static int tls_write_server_hello(struct tlsv1_server *conn,
 static int tls_write_server_hello(struct tlsv1_server *conn,
 				  u8 **msgpos, u8 *end)
 				  u8 **msgpos, u8 *end)
 {
 {
-	u8 *pos, *rhdr, *hs_start, *hs_length;
+	u8 *pos, *rhdr, *hs_start, *hs_length, *ext_start;
 	struct os_time now;
 	struct os_time now;
 	size_t rlen;
 	size_t rlen;
 
 
 	pos = *msgpos;
 	pos = *msgpos;
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
+	tlsv1_server_log(conn, "Send ServerHello");
 	rhdr = pos;
 	rhdr = pos;
 	pos += TLS_RECORD_HEADER_LEN;
 	pos += TLS_RECORD_HEADER_LEN;
 
 
 	os_get_time(&now);
 	os_get_time(&now);
+#ifdef TEST_FUZZ
+	now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
 	WPA_PUT_BE32(conn->server_random, now.sec);
 	WPA_PUT_BE32(conn->server_random, now.sec);
 	if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
 	if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
 		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
 		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
@@ -98,6 +100,32 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
 	/* CompressionMethod compression_method */
 	/* CompressionMethod compression_method */
 	*pos++ = TLS_COMPRESSION_NULL;
 	*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->status_request_v2) {
+		/*
+		  Add a status_request_v2 extension with empty extension_data
+		*/
+		/* ExtensionsType extension_type = status_request_v2(17) */
+		WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+		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) {
 	if (conn->session_ticket && conn->session_ticket_cb) {
 		int res = conn->session_ticket_cb(
 		int res = conn->session_ticket_cb(
 			conn->session_ticket_cb_ctx,
 			conn->session_ticket_cb_ctx,
@@ -105,8 +133,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
 			conn->client_random, conn->server_random,
 			conn->client_random, conn->server_random,
 			conn->master_secret);
 			conn->master_secret);
 		if (res < 0) {
 		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
-				   "indicated failure");
+			tlsv1_server_log(conn, "SessionTicket callback indicated failure");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 					   TLS_ALERT_HANDSHAKE_FAILURE);
 					   TLS_ALERT_HANDSHAKE_FAILURE);
 			return -1;
 			return -1;
@@ -135,6 +162,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);
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
 
@@ -170,8 +202,13 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
 	}
 	}
 
 
 	pos = *msgpos;
 	pos = *msgpos;
+	if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+	tlsv1_server_log(conn, "Send Certificate");
 	rhdr = pos;
 	rhdr = pos;
 	pos += TLS_RECORD_HEADER_LEN;
 	pos += TLS_RECORD_HEADER_LEN;
 
 
@@ -190,7 +227,7 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
 	pos += 3;
 	pos += 3;
 	cert = conn->cred->cert;
 	cert = conn->cred->cert;
 	while (cert) {
 	while (cert) {
-		if (pos + 3 + cert->cert_len > end) {
+		if (3 + cert->cert_len > (size_t) (end - pos)) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
 			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
 				   "for Certificate (cert_len=%lu left=%lu)",
 				   "for Certificate (cert_len=%lu left=%lu)",
 				   (unsigned long) cert->cert_len,
 				   (unsigned long) cert->cert_len,
@@ -241,15 +278,104 @@ 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,
+					       int ocsp_multi,
+					       char *ocsp_resp,
+					       size_t ocsp_resp_len)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen;
+
+	if (!ocsp_resp) {
+		 /*
+		  * Client did not request certificate status or there is no
+		  * matching response cached.
+		  */
+		return 0;
+	}
+
+	pos = *msgpos;
+	if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + ocsp_resp_len >
+	    (unsigned int) (end - pos)) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	tlsv1_server_log(conn, "Send CertificateStatus (multi=%d)", ocsp_multi);
+	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;
+	 *         case ocsp_multi: OCSPResponseList;
+	 *     } response;
+	 * } CertificateStatus;
+	 *
+	 * opaque OCSPResponse<1..2^24-1>;
+	 *
+	 * struct {
+	 *   OCSPResponse ocsp_response_list<1..2^24-1>;
+	 * } OCSPResponseList;
+	 */
+
+	/* CertificateStatusType status_type */
+	if (ocsp_multi)
+		*pos++ = 2; /* ocsp_multi(2) */
+	else
+		*pos++ = 1; /* ocsp(1) */
+	/* uint24 length of OCSPResponse */
+	WPA_PUT_BE24(pos, ocsp_resp_len);
+	pos += 3;
+	os_memcpy(pos, ocsp_resp, ocsp_resp_len);
+	pos += ocsp_resp_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,
 static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 					 u8 **msgpos, u8 *end)
 					 u8 **msgpos, u8 *end)
 {
 {
 	tls_key_exchange keyx;
 	tls_key_exchange keyx;
 	const struct tls_cipher_suite *suite;
 	const struct tls_cipher_suite *suite;
-	u8 *pos, *rhdr, *hs_start, *hs_length;
+	u8 *pos, *rhdr, *hs_start, *hs_length, *server_params;
 	size_t rlen;
 	size_t rlen;
 	u8 *dh_ys;
 	u8 *dh_ys;
 	size_t dh_ys_len;
 	size_t dh_ys_len;
+	const u8 *dh_p;
+	size_t dh_p_len;
 
 
 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
 	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
 	if (suite == NULL)
 	if (suite == NULL)
@@ -262,8 +388,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 		return 0;
 		return 0;
 	}
 	}
 
 
-	if (keyx != TLS_KEY_X_DH_anon) {
-		/* TODO? */
+	if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) {
 		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
 		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
 			   "supported with key exchange type %d", keyx);
 			   "supported with key exchange type %d", keyx);
 		return -1;
 		return -1;
@@ -276,8 +401,10 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 		return -1;
 		return -1;
 	}
 	}
 
 
+	tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
+
 	os_free(conn->dh_secret);
 	os_free(conn->dh_secret);
-	conn->dh_secret_len = conn->cred->dh_p_len;
+	conn->dh_secret_len = dh_p_len;
 	conn->dh_secret = os_malloc(conn->dh_secret_len);
 	conn->dh_secret = os_malloc(conn->dh_secret_len);
 	if (conn->dh_secret == NULL) {
 	if (conn->dh_secret == NULL) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
@@ -296,8 +423,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
-	    0)
+	if (os_memcmp(conn->dh_secret, dh_p, conn->dh_secret_len) > 0)
 		conn->dh_secret[0] = 0; /* make sure secret < p */
 		conn->dh_secret[0] = 0; /* make sure secret < p */
 
 
 	pos = conn->dh_secret;
 	pos = conn->dh_secret;
@@ -312,7 +438,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 			conn->dh_secret, conn->dh_secret_len);
 			conn->dh_secret, conn->dh_secret_len);
 
 
 	/* Ys = g^secret mod p */
 	/* Ys = g^secret mod p */
-	dh_ys_len = conn->cred->dh_p_len;
+	dh_ys_len = dh_p_len;
 	dh_ys = os_malloc(dh_ys_len);
 	dh_ys = os_malloc(dh_ys_len);
 	if (dh_ys == NULL) {
 	if (dh_ys == NULL) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
@@ -322,16 +448,14 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 		return -1;
 		return -1;
 	}
 	}
 	if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
 	if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
-					        conn->dh_secret, conn->dh_secret_len,
-					        conn->cred->dh_p, conn->cred->dh_p_len,
-					        dh_ys, &dh_ys_len)) {
+			   conn->dh_secret, conn->dh_secret_len,
+			   dh_p, dh_p_len, dh_ys, &dh_ys_len)) {
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				        TLS_ALERT_INTERNAL_ERROR);
+				   TLS_ALERT_INTERNAL_ERROR);
 		os_free(dh_ys);
 		os_free(dh_ys);
 		return -1;
 		return -1;
 	}
 	}
 
 
-
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
 	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
 		    dh_ys, dh_ys_len);
 		    dh_ys, dh_ys_len);
 
 
@@ -356,7 +480,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 
 
 	pos = *msgpos;
 	pos = *msgpos;
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
+	tlsv1_server_log(conn, "Send ServerKeyExchange");
 	rhdr = pos;
 	rhdr = pos;
 	pos += TLS_RECORD_HEADER_LEN;
 	pos += TLS_RECORD_HEADER_LEN;
 
 
@@ -371,8 +495,9 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 	pos += 3;
 	pos += 3;
 
 
 	/* body - ServerDHParams */
 	/* body - ServerDHParams */
+	server_params = pos;
 	/* dh_p */
 	/* dh_p */
-	if (pos + 2 + conn->cred->dh_p_len > end) {
+	if (2 + dh_p_len > (size_t) (end - pos)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
 			   "dh_p");
 			   "dh_p");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -380,13 +505,13 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 		os_free(dh_ys);
 		os_free(dh_ys);
 		return -1;
 		return -1;
 	}
 	}
-	WPA_PUT_BE16(pos, conn->cred->dh_p_len);
+	WPA_PUT_BE16(pos, dh_p_len);
 	pos += 2;
 	pos += 2;
-	os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
-	pos += conn->cred->dh_p_len;
+	os_memcpy(pos, dh_p, dh_p_len);
+	pos += dh_p_len;
 
 
 	/* dh_g */
 	/* dh_g */
-	if (pos + 2 + conn->cred->dh_g_len > end) {
+	if (2 + conn->cred->dh_g_len > (size_t) (end - pos)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
 			   "dh_g");
 			   "dh_g");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -400,7 +525,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 	pos += conn->cred->dh_g_len;
 	pos += conn->cred->dh_g_len;
 
 
 	/* dh_Ys */
 	/* dh_Ys */
-	if (pos + 2 + dh_ys_len > end) {
+	if (2 + dh_ys_len > (size_t) (end - pos)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
 		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
 			   "dh_Ys");
 			   "dh_Ys");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -414,6 +539,139 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 	pos += dh_ys_len;
 	pos += dh_ys_len;
 	os_free(dh_ys);
 	os_free(dh_ys);
 
 
+	/*
+	 * select (SignatureAlgorithm)
+	 * {   case anonymous: struct { };
+	 *     case rsa:
+	 *         digitally-signed struct {
+	 *             opaque md5_hash[16];
+	 *             opaque sha_hash[20];
+	 *         };
+	 *     case dsa:
+	 *         digitally-signed struct {
+	 *             opaque sha_hash[20];
+	 *         };
+	 * } Signature;
+	 *
+	 * md5_hash
+	 *     MD5(ClientHello.random + ServerHello.random + ServerParams);
+	 *
+	 * sha_hash
+	 *     SHA(ClientHello.random + ServerHello.random + ServerParams);
+	 */
+
+	if (keyx == TLS_KEY_X_DHE_RSA) {
+		u8 hash[100];
+		u8 *signed_start;
+		size_t clen;
+		int hlen;
+
+		if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+#ifdef CONFIG_TLSV12
+			hlen = tlsv12_key_x_server_params_hash(
+				conn->rl.tls_version, TLS_HASH_ALG_SHA256,
+				conn->client_random,
+				conn->server_random, server_params,
+				pos - server_params, hash + 19);
+
+			/*
+			 * RFC 5246, 4.7:
+			 * TLS v1.2 adds explicit indication of the used
+			 * signature and hash algorithms.
+			 *
+			 * struct {
+			 *   HashAlgorithm hash;
+			 *   SignatureAlgorithm signature;
+			 * } SignatureAndHashAlgorithm;
+			 */
+			if (hlen < 0 || end - pos < 2) {
+				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+						   TLS_ALERT_INTERNAL_ERROR);
+				return -1;
+			}
+			*pos++ = TLS_HASH_ALG_SHA256;
+			*pos++ = TLS_SIGN_ALG_RSA;
+
+			/*
+			 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+			 *
+			 * DigestInfo ::= SEQUENCE {
+			 *   digestAlgorithm DigestAlgorithm,
+			 *   digest OCTET STRING
+			 * }
+			 *
+			 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+			 *
+			 * DER encoded DigestInfo for SHA256 per RFC 3447:
+			 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
+			 * 04 20 || H
+			 */
+			hlen += 19;
+			os_memcpy(hash,
+				  "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+				  "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+
+#else /* CONFIG_TLSV12 */
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+#endif /* CONFIG_TLSV12 */
+		} else {
+			hlen = tls_key_x_server_params_hash(
+				conn->rl.tls_version, conn->client_random,
+				conn->server_random, server_params,
+				pos - server_params, hash);
+		}
+
+		if (hlen < 0) {
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+
+		wpa_hexdump(MSG_MSGDUMP, "TLS: ServerKeyExchange signed_params hash",
+			    hash, hlen);
+#ifdef CONFIG_TESTING_OPTIONS
+		if (conn->test_flags & TLS_BREAK_SRV_KEY_X_HASH) {
+			tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params hash");
+			hash[hlen - 1] ^= 0x80;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+		/*
+		 * RFC 2246, 4.7:
+		 * In digital signing, one-way hash functions are used as input
+		 * for a signing algorithm. A digitally-signed element is
+		 * encoded as an opaque vector <0..2^16-1>, where the length is
+		 * specified by the signing algorithm and key.
+		 *
+		 * In RSA signing, a 36-byte structure of two hashes (one SHA
+		 * and one MD5) is signed (encrypted with the private key). It
+		 * is encoded with PKCS #1 block type 0 or type 1 as described
+		 * in [PKCS1].
+		 */
+		signed_start = pos; /* length to be filled */
+		pos += 2;
+		clen = end - pos;
+		if (conn->cred == NULL ||
+		    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
+						  pos, &clen) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		WPA_PUT_BE16(signed_start, clen);
+#ifdef CONFIG_TESTING_OPTIONS
+		if (conn->test_flags & TLS_BREAK_SRV_KEY_X_SIGNATURE) {
+			tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params signature");
+			pos[clen - 1] ^= 0x80;
+		}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+		pos += clen;
+	}
+
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
@@ -447,7 +705,7 @@ static int tls_write_server_certificate_request(struct tlsv1_server *conn,
 
 
 	pos = *msgpos;
 	pos = *msgpos;
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
+	tlsv1_server_log(conn, "Send CertificateRequest");
 	rhdr = pos;
 	rhdr = pos;
 	pos += TLS_RECORD_HEADER_LEN;
 	pos += TLS_RECORD_HEADER_LEN;
 
 
@@ -507,7 +765,7 @@ static int tls_write_server_hello_done(struct tlsv1_server *conn,
 	size_t rlen;
 	size_t rlen;
 	u8 payload[4];
 	u8 payload[4];
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
+	tlsv1_server_log(conn, "Send ServerHelloDone");
 
 
 	/* opaque fragment[TLSPlaintext.length] */
 	/* opaque fragment[TLSPlaintext.length] */
 
 
@@ -543,7 +801,7 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
 	size_t rlen;
 	size_t rlen;
 	u8 payload[1];
 	u8 payload[1];
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+	tlsv1_server_log(conn, "Send ChangeCipherSpec");
 
 
 	payload[0] = TLS_CHANGE_CIPHER_SPEC;
 	payload[0] = TLS_CHANGE_CIPHER_SPEC;
 
 
@@ -580,7 +838,7 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
 
 
 	pos = *msgpos;
 	pos = *msgpos;
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+	tlsv1_server_log(conn, "Send Finished");
 
 
 	/* Encrypted Handshake Message: Finished */
 	/* Encrypted Handshake Message: Finished */
 
 
@@ -588,11 +846,11 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
 	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
 	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
 		hlen = SHA256_MAC_LEN;
 		hlen = SHA256_MAC_LEN;
 		if (conn->verify.sha256_server == NULL ||
 		if (conn->verify.sha256_server == NULL ||
-			crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
-			< 0) {
+		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+		    < 0) {
 			conn->verify.sha256_server = NULL;
 			conn->verify.sha256_server = NULL;
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					        TLS_ALERT_INTERNAL_ERROR);
+					   TLS_ALERT_INTERNAL_ERROR);
 			return -1;
 			return -1;
 		}
 		}
 		conn->verify.sha256_server = NULL;
 		conn->verify.sha256_server = NULL;
@@ -637,6 +895,12 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
 	}
 	}
 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
 			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
 			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
+#ifdef CONFIG_TESTING_OPTIONS
+	if (conn->test_flags & TLS_BREAK_VERIFY_DATA) {
+		tlsv1_server_log(conn, "TESTING: Break verify_data (server)");
+		verify_data[1 + 3 + 1] ^= 0x80;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 
 	/* Handshake */
 	/* Handshake */
 	pos = hs_start = verify_data;
 	pos = hs_start = verify_data;
@@ -667,24 +931,46 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
 {
 {
 	u8 *msg, *end, *pos;
 	u8 *msg, *end, *pos;
 	size_t msglen;
 	size_t msglen;
+	int ocsp_multi = 0;
+	char *ocsp_resp = NULL;
+	size_t ocsp_resp_len = 0;
 
 
 	*out_len = 0;
 	*out_len = 0;
 
 
-	msglen = 1000 + tls_server_cert_chain_der_len(conn);
+	if (conn->status_request_multi &&
+	    conn->cred->ocsp_stapling_response_multi) {
+		ocsp_resp = os_readfile(
+			conn->cred->ocsp_stapling_response_multi,
+			&ocsp_resp_len);
+		ocsp_multi = 1;
+	} else if ((conn->status_request || conn->status_request_v2) &&
+		   conn->cred->ocsp_stapling_response) {
+		ocsp_resp = os_readfile(conn->cred->ocsp_stapling_response,
+					&ocsp_resp_len);
+	}
+	if (!ocsp_resp)
+		ocsp_resp_len = 0;
+
+	msglen = 1000 + tls_server_cert_chain_der_len(conn) + ocsp_resp_len;
 
 
 	msg = os_malloc(msglen);
 	msg = os_malloc(msglen);
-	if (msg == NULL)
+	if (msg == NULL) {
+		os_free(ocsp_resp);
 		return NULL;
 		return NULL;
+	}
 
 
 	pos = msg;
 	pos = msg;
 	end = msg + msglen;
 	end = msg + msglen;
 
 
 	if (tls_write_server_hello(conn, &pos, end) < 0) {
 	if (tls_write_server_hello(conn, &pos, end) < 0) {
 		os_free(msg);
 		os_free(msg);
+		os_free(ocsp_resp);
 		return NULL;
 		return NULL;
 	}
 	}
 
 
 	if (conn->use_session_ticket) {
 	if (conn->use_session_ticket) {
+		os_free(ocsp_resp);
+
 		/* Abbreviated handshake using session ticket; RFC 4507 */
 		/* Abbreviated handshake using session ticket; RFC 4507 */
 		if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
 		if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
 		    tls_write_server_finished(conn, &pos, end) < 0) {
 		    tls_write_server_finished(conn, &pos, end) < 0) {
@@ -701,12 +987,16 @@ static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
 
 
 	/* Full handshake */
 	/* Full handshake */
 	if (tls_write_server_certificate(conn, &pos, end) < 0 ||
 	if (tls_write_server_certificate(conn, &pos, end) < 0 ||
+	    tls_write_server_certificate_status(conn, &pos, end, ocsp_multi,
+						ocsp_resp, ocsp_resp_len) < 0 ||
 	    tls_write_server_key_exchange(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_certificate_request(conn, &pos, end) < 0 ||
 	    tls_write_server_hello_done(conn, &pos, end) < 0) {
 	    tls_write_server_hello_done(conn, &pos, end) < 0) {
 		os_free(msg);
 		os_free(msg);
+		os_free(ocsp_resp);
 		return NULL;
 		return NULL;
 	}
 	}
+	os_free(ocsp_resp);
 
 
 	*out_len = pos - msg;
 	*out_len = pos - msg;
 
 
@@ -738,7 +1028,7 @@ static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
 
 
 	*out_len = pos - msg;
 	*out_len = pos - msg;
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
+	tlsv1_server_log(conn, "Handshake completed successfully");
 	conn->state = ESTABLISHED;
 	conn->state = ESTABLISHED;
 
 
 	return msg;
 	return msg;
@@ -757,8 +1047,8 @@ u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
 			/* Abbreviated handshake was already completed. */
 			/* Abbreviated handshake was already completed. */
 			return NULL;
 			return NULL;
 		}
 		}
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
-			   "generating reply", conn->state);
+		tlsv1_server_log(conn, "Unexpected state %d while generating reply",
+				 conn->state);
 		return NULL;
 		return NULL;
 	}
 	}
 }
 }
@@ -769,7 +1059,7 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
 {
 {
 	u8 *alert, *pos, *length;
 	u8 *alert, *pos, *length;
 
 
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+	tlsv1_server_log(conn, "Send Alert(%d:%d)", level, description);
 	*out_len = 0;
 	*out_len = 0;
 
 
 	alert = os_malloc(10);
 	alert = os_malloc(10);

File diff suppressed because it is too large
+ 491 - 177
components/wpa_supplicant/src/tls/x509v3.c


+ 42 - 1
components/wpa_supplicant/src/tls/x509v3.h

@@ -45,13 +45,18 @@ struct x509_name {
 	struct asn1_oid rid; /* registeredID */
 	struct asn1_oid rid; /* registeredID */
 };
 };
 
 
+#define X509_MAX_SERIAL_NUM_LEN 20
+
 struct x509_certificate {
 struct x509_certificate {
 	struct x509_certificate *next;
 	struct x509_certificate *next;
 	enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;
 	enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;
-	unsigned long serial_number;
+	u8 serial_number[X509_MAX_SERIAL_NUM_LEN];
+	size_t serial_number_len;
 	struct x509_algorithm_identifier signature;
 	struct x509_algorithm_identifier signature;
 	struct x509_name issuer;
 	struct x509_name issuer;
 	struct x509_name subject;
 	struct x509_name subject;
+	u8 *subject_dn;
+	size_t subject_dn_len;
 	os_time_t not_before;
 	os_time_t not_before;
 	os_time_t not_after;
 	os_time_t not_after;
 	struct x509_algorithm_identifier public_key_alg;
 	struct x509_algorithm_identifier public_key_alg;
@@ -68,6 +73,8 @@ struct x509_certificate {
 #define X509_EXT_KEY_USAGE			(1 << 2)
 #define X509_EXT_KEY_USAGE			(1 << 2)
 #define X509_EXT_SUBJECT_ALT_NAME		(1 << 3)
 #define X509_EXT_SUBJECT_ALT_NAME		(1 << 3)
 #define X509_EXT_ISSUER_ALT_NAME		(1 << 4)
 #define X509_EXT_ISSUER_ALT_NAME		(1 << 4)
+#define X509_EXT_EXT_KEY_USAGE			(1 << 5)
+#define X509_EXT_CERTIFICATE_POLICY		(1 << 6)
 
 
 	/* BasicConstraints */
 	/* BasicConstraints */
 	int ca; /* cA */
 	int ca; /* cA */
@@ -85,6 +92,19 @@ struct x509_certificate {
 #define X509_KEY_USAGE_ENCIPHER_ONLY		(1 << 7)
 #define X509_KEY_USAGE_ENCIPHER_ONLY		(1 << 7)
 #define X509_KEY_USAGE_DECIPHER_ONLY		(1 << 8)
 #define X509_KEY_USAGE_DECIPHER_ONLY		(1 << 8)
 
 
+	/* ExtKeyUsage */
+	unsigned long ext_key_usage;
+#define X509_EXT_KEY_USAGE_ANY			(1 << 0)
+#define X509_EXT_KEY_USAGE_SERVER_AUTH		(1 << 1)
+#define X509_EXT_KEY_USAGE_CLIENT_AUTH		(1 << 2)
+#define X509_EXT_KEY_USAGE_OCSP			(1 << 3)
+
+	/* CertificatePolicy */
+	unsigned long certificate_policy;
+#define X509_EXT_CERT_POLICY_ANY		(1 << 0)
+#define X509_EXT_CERT_POLICY_TOD_STRICT		(1 << 1)
+#define X509_EXT_CERT_POLICY_TOD_TOFU		(1 << 2)
+
 	/*
 	/*
 	 * The DER format certificate follows struct x509_certificate. These
 	 * The DER format certificate follows struct x509_certificate. These
 	 * pointers point to that buffer.
 	 * pointers point to that buffer.
@@ -93,6 +113,11 @@ struct x509_certificate {
 	size_t cert_len;
 	size_t cert_len;
 	const u8 *tbs_cert_start;
 	const u8 *tbs_cert_start;
 	size_t tbs_cert_len;
 	size_t tbs_cert_len;
+
+	/* Meta data used for certificate validation */
+	unsigned int ocsp_good:1;
+	unsigned int ocsp_revoked:1;
+	unsigned int issuer_trusted:1;
 };
 };
 
 
 enum {
 enum {
@@ -106,10 +131,21 @@ enum {
 };
 };
 
 
 void x509_certificate_free(struct x509_certificate *cert);
 void x509_certificate_free(struct x509_certificate *cert);
+int x509_parse_algorithm_identifier(const u8 *buf, size_t len,
+				    struct x509_algorithm_identifier *id,
+				    const u8 **next);
+int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
+		    const u8 **next);
+int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val);
 struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len);
 struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len);
+void x509_free_name(struct x509_name *name);
 void x509_name_string(struct x509_name *name, char *buf, size_t len);
 void x509_name_string(struct x509_name *name, char *buf, size_t len);
 int x509_name_compare(struct x509_name *a, struct x509_name *b);
 int x509_name_compare(struct x509_name *a, struct x509_name *b);
 void x509_certificate_chain_free(struct x509_certificate *cert);
 void x509_certificate_chain_free(struct x509_certificate *cert);
+int x509_check_signature(struct x509_certificate *issuer,
+			 struct x509_algorithm_identifier *signature,
+			 const u8 *sign_value, size_t sign_value_len,
+			 const u8 *signed_data, size_t signed_data_len);
 int x509_certificate_check_signature(struct x509_certificate *issuer,
 int x509_certificate_check_signature(struct x509_certificate *issuer,
 				     struct x509_certificate *cert);
 				     struct x509_certificate *cert);
 int x509_certificate_chain_validate(struct x509_certificate *trusted,
 int x509_certificate_chain_validate(struct x509_certificate *trusted,
@@ -120,4 +156,9 @@ x509_certificate_get_subject(struct x509_certificate *chain,
 			     struct x509_name *name);
 			     struct x509_name *name);
 int x509_certificate_self_signed(struct x509_certificate *cert);
 int x509_certificate_self_signed(struct x509_certificate *cert);
 
 
+int x509_sha1_oid(struct asn1_oid *oid);
+int x509_sha256_oid(struct asn1_oid *oid);
+int x509_sha384_oid(struct asn1_oid *oid);
+int x509_sha512_oid(struct asn1_oid *oid);
+
 #endif /* X509V3_H */
 #endif /* X509V3_H */

+ 1 - 1
examples/wifi/wifi_eap_fast/sdkconfig.defaults

@@ -1 +1 @@
-CONFIG_WPA_MBEDTLS_CRYPTO=n
+CONFIG_WPA_MBEDTLS_TLS_CLIENT=n

Some files were not shown because too many files changed in this diff