mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
wpa_supplicant: sync eap code with upstream
This commit is contained in:
parent
36321fda82
commit
c2429f1cf9
@ -66,7 +66,7 @@ if(CONFIG_ESP_WIFI_SOFTAP_SUPPORT)
|
||||
set(esp_srcs ${esp_srcs} "esp_supplicant/src/esp_hostap.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_WPA_MBEDTLS_CRYPTO)
|
||||
if(CONFIG_WPA_MBEDTLS_TLS_CLIENT)
|
||||
set(tls_src "esp_supplicant/src/crypto/tls_mbedtls.c")
|
||||
else()
|
||||
set(tls_src
|
||||
@ -77,16 +77,14 @@ else()
|
||||
"src/tls/pkcs8.c"
|
||||
"src/tls/bignum.c"
|
||||
"src/tls/rsa.c"
|
||||
"src/tls/tls_internal.c"
|
||||
"src/crypto/tls_internal.c"
|
||||
"src/tls/tlsv1_client.c"
|
||||
"src/tls/tlsv1_client_read.c"
|
||||
"src/tls/tlsv1_client_write.c"
|
||||
"src/tls/tlsv1_common.c"
|
||||
"src/tls/tlsv1_cred.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")
|
||||
endif()
|
||||
|
||||
@ -94,6 +92,7 @@ if(CONFIG_WPA_MBEDTLS_CRYPTO)
|
||||
set(crypto_src
|
||||
"esp_supplicant/src/crypto/crypto_mbedtls.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")
|
||||
# Add internal RC4 if RC4 is disabled in mbedtls
|
||||
if(CONFIG_MBEDTLS_RC4_DISABLED)
|
||||
@ -193,7 +192,6 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
EAP_TTLS
|
||||
EAP_TLS
|
||||
EAP_PEAP
|
||||
EAP_FAST
|
||||
USE_WPA2_TASK
|
||||
CONFIG_WPS2
|
||||
CONFIG_WPS_PIN
|
||||
@ -235,4 +233,13 @@ endif()
|
||||
if(CONFIG_WPA_11R_SUPPORT)
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_IEEE80211R)
|
||||
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)
|
||||
|
@ -11,6 +11,19 @@ menu "Supplicant"
|
||||
help
|
||||
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
|
||||
bool "Enable WAPI PSK support"
|
||||
default n
|
||||
|
@ -32,7 +32,7 @@ struct crypto_ec {
|
||||
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);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "crypto.h"
|
||||
#include "common/defs.h"
|
||||
|
||||
#ifdef USE_MBEDTLS_CRYPTO
|
||||
#ifdef CONFIG_CRYPTO_MBEDTLS
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
struct crypto_public_key;
|
||||
struct crypto_private_key;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
static void crypto_dump_verify_info(u32 flags)
|
||||
{
|
||||
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 );
|
||||
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)
|
||||
{
|
||||
@ -110,7 +119,8 @@ struct crypto_private_key * crypto_private_key_import(const u8 *key,
|
||||
|
||||
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) {
|
||||
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,
|
||||
ctr_drbg, MBEDTLS_RSA_PUBLIC, inlen, in, out);
|
||||
ctr_drbg, inlen, in, out);
|
||||
|
||||
if(ret != 0) {
|
||||
wpa_printf(MSG_ERROR, " failed ! mbedtls_rsa_pkcs1_encrypt returned -0x%04x", -ret);
|
||||
goto cleanup;
|
||||
}
|
||||
*outlen = mbedtls_pk_rsa(*pkey)->len;
|
||||
*outlen = mbedtls_pk_rsa(*pkey)->MBEDTLS_PRIVATE(len);
|
||||
|
||||
cleanup:
|
||||
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)
|
||||
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,
|
||||
ctr_drbg, MBEDTLS_RSA_PRIVATE, &i, in, out, *outlen);
|
||||
ctr_drbg, &i, in, out, *outlen);
|
||||
|
||||
*outlen = i;
|
||||
|
||||
@ -267,17 +277,37 @@ int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
|
||||
u8 *out, size_t *outlen)
|
||||
{
|
||||
int ret;
|
||||
const char *pers = "rsa_encrypt";
|
||||
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;
|
||||
}
|
||||
*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);
|
||||
}
|
||||
|
||||
|
||||
int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
|
||||
const u8 *crypt, size_t crypt_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_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;
|
||||
}
|
||||
*plain_len = i;
|
||||
while (pos < plain + len && *pos == 0xff)
|
||||
pos++;
|
||||
|
||||
cleanup:
|
||||
mbedtls_entropy_free( &entropy );
|
||||
mbedtls_ctr_drbg_free( &ctr_drbg );
|
||||
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;
|
||||
}
|
||||
|
||||
return ret;
|
||||
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;
|
||||
|
||||
/* Strip PKCS #1 header */
|
||||
os_memmove(plain, pos, len);
|
||||
*plain_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -28,9 +28,10 @@
|
||||
#include "common.h"
|
||||
#include "utils/wpabuf.h"
|
||||
#include "dh_group5.h"
|
||||
#include "md5.h"
|
||||
#include "sha1.h"
|
||||
#include "sha256.h"
|
||||
#include "md5.h"
|
||||
#include "sha384.h"
|
||||
#include "aes_wrap.h"
|
||||
#include "crypto.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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
mbedtls_md_type_t md_type;
|
||||
const mbedtls_md_info_t *md_info;
|
||||
int ret;
|
||||
int is_hmac = 0;
|
||||
|
||||
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));
|
||||
if (ctx == 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) {
|
||||
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;
|
||||
cleanup:
|
||||
os_free(ctx);
|
||||
@ -166,7 +202,11 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
|
||||
if (ctx == NULL) {
|
||||
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) {
|
||||
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 ret;
|
||||
int ret = 0;
|
||||
mbedtls_md_type_t md_type;
|
||||
|
||||
if (ctx == NULL) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (mac == NULL || len == NULL) {
|
||||
mbedtls_md_free(&ctx->ctx);
|
||||
bin_clear_free(ctx, sizeof(*ctx));
|
||||
return 0;
|
||||
goto err;
|
||||
}
|
||||
ret = mbedtls_md_hmac_finish(&ctx->ctx, mac);
|
||||
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);
|
||||
}
|
||||
|
||||
err:
|
||||
mbedtls_md_free(&ctx->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 {
|
||||
mbedtls_cipher_context_t ctx_enc;
|
||||
mbedtls_cipher_context_t ctx_dec;
|
||||
@ -405,7 +498,7 @@ struct crypto_cipher {
|
||||
|
||||
static int crypto_init_cipher_ctx(mbedtls_cipher_context_t *ctx,
|
||||
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_cipher_init(ctx);
|
||||
@ -416,8 +509,7 @@ static int crypto_init_cipher_ctx(mbedtls_cipher_context_t *ctx,
|
||||
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");
|
||||
return -1;
|
||||
}
|
||||
@ -490,15 +582,21 @@ struct crypto_cipher *crypto_cipher_init(enum crypto_cipher_alg alg,
|
||||
|
||||
/* Init both ctx encryption/decryption */
|
||||
if (crypto_init_cipher_ctx(&ctx->ctx_enc, cipher_info, iv, key,
|
||||
MBEDTLS_ENCRYPT) < 0) {
|
||||
key_len, MBEDTLS_ENCRYPT) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (crypto_init_cipher_ctx(&ctx->ctx_dec, cipher_info, iv, key,
|
||||
MBEDTLS_DECRYPT) < 0) {
|
||||
key_len, MBEDTLS_DECRYPT) < 0) {
|
||||
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;
|
||||
|
||||
cleanup:
|
||||
@ -506,12 +604,11 @@ cleanup:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
|
||||
u8 *crypt, size_t len)
|
||||
{
|
||||
int ret;
|
||||
size_t olen = 1200;
|
||||
size_t olen = 0;
|
||||
|
||||
ret = mbedtls_cipher_update(&ctx->ctx_enc, plain, len, crypt, &olen);
|
||||
if (ret != 0) {
|
||||
@ -530,7 +627,7 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
|
||||
u8 *plain, size_t len)
|
||||
{
|
||||
int ret;
|
||||
size_t olen = 1200;
|
||||
size_t olen = 0;
|
||||
|
||||
ret = mbedtls_cipher_update(&ctx->ctx_dec, crypt, len, plain, &olen);
|
||||
if (ret != 0) {
|
||||
@ -544,7 +641,6 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
os_free(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
|
||||
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;
|
||||
}
|
||||
|
||||
int crypto_global_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypto_global_deinit(void)
|
||||
{
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "crypto/sha256.h"
|
||||
@ -608,7 +608,7 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *tls_init()
|
||||
void *tls_init(const struct tls_config *conf)
|
||||
{
|
||||
tls_instance_count++;
|
||||
return &tls_instance_count;
|
||||
@ -660,7 +660,7 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
|
||||
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");
|
||||
return -1;
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
#include "utils/ext_password.h"
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_peer/eap_i.h"
|
||||
#include "eap_peer/eap_config.h"
|
||||
#include "eap_peer/eap.h"
|
||||
@ -717,7 +717,7 @@ static int eap_peer_sm_init(void)
|
||||
goto _err;
|
||||
}
|
||||
|
||||
sm->ssl_ctx = tls_init();
|
||||
sm->ssl_ctx = tls_init(NULL);
|
||||
if (sm->ssl_ctx == NULL) {
|
||||
wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS context.");
|
||||
ret = ESP_FAIL;
|
||||
|
@ -65,12 +65,12 @@ void wpa_debug_print_timestamp(void);
|
||||
#define wpa_dbg(ctx, level, fmt, args...) wpa_printf(level, fmt, ##args)
|
||||
|
||||
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
|
||||
* 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);
|
||||
|
||||
/**
|
||||
@ -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
|
||||
* 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);
|
||||
#else
|
||||
#define wpa_printf(level,fmt, args...) do {} while(0)
|
||||
|
@ -185,7 +185,11 @@ int os_unsetenv(const char *name);
|
||||
* binary and text files can be read with this function. The caller is
|
||||
* 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.
|
||||
@ -250,7 +254,6 @@ char * ets_strdup(const char *s);
|
||||
#define os_memcmp_const(s1, s2, n) memcmp((s1), (s2), (n))
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef os_strlen
|
||||
#define os_strlen(s) strlen(s)
|
||||
#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);
|
||||
}
|
||||
|
||||
#ifdef USE_MBEDTLS_CRYPTO
|
||||
#ifdef CONFIG_CRYPTO_MBEDTLS
|
||||
void forced_memzero(void *ptr, size_t len);
|
||||
#else
|
||||
/* Try to prevent most compilers from optimizing out clearing of memory that
|
||||
|
@ -9,14 +9,6 @@
|
||||
|
||||
#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
|
||||
#define DEBUG_PRINT
|
||||
#endif
|
||||
|
@ -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)
|
||||
{
|
||||
mbedtls_platform_zeroize(ptr, len);
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
#include "sha256_i.h"
|
||||
#include "sha384_i.h"
|
||||
#include "sha512_i.h"
|
||||
#include "sha1_i.h"
|
||||
#include "md5_i.h"
|
||||
|
||||
|
@ -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.
|
||||
* 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
|
||||
* native API's are use software implementations.
|
||||
*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@
|
||||
#define SHA384_H
|
||||
|
||||
#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,
|
||||
const u8 *addr[], const size_t *len, u8 *mac);
|
||||
|
@ -38,7 +38,26 @@ enum tls_fail_reason {
|
||||
TLS_FAIL_SUBJECT_MISMATCH = 5,
|
||||
TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
|
||||
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 {
|
||||
@ -50,13 +69,7 @@ union tls_event_data {
|
||||
const struct wpabuf *cert;
|
||||
} 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 {
|
||||
int is_local;
|
||||
@ -71,6 +84,10 @@ struct tls_config {
|
||||
const char *pkcs11_module_path;
|
||||
int fips_mode;
|
||||
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,
|
||||
union tls_event_data *data);
|
||||
@ -82,8 +99,19 @@ struct tls_config {
|
||||
#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
|
||||
#define TLS_CONN_REQUEST_OCSP BIT(3)
|
||||
#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_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)
|
||||
|
||||
/**
|
||||
@ -97,6 +125,19 @@ struct tls_config {
|
||||
* %NULL to allow all subjects
|
||||
* @altsubject_match: String to match in the alternative subject of the peer
|
||||
* 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
|
||||
* DER format
|
||||
* @client_cert_blob: client_cert as inlined data or %NULL if not used
|
||||
@ -119,9 +160,16 @@ struct tls_config {
|
||||
* specific for now)
|
||||
* @cert_id: the 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_*)
|
||||
* @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
|
||||
* 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()
|
||||
* and tls_global_set_params().
|
||||
@ -138,13 +186,18 @@ struct tls_connection_params {
|
||||
const char *ca_path;
|
||||
const char *subject_match;
|
||||
const char *altsubject_match;
|
||||
const char *suffix_match;
|
||||
const char *domain_match;
|
||||
const char *client_cert;
|
||||
const char *client_cert2;
|
||||
const u8 *client_cert_blob;
|
||||
size_t client_cert_blob_len;
|
||||
const char *private_key;
|
||||
const char *private_key2;
|
||||
const u8 *private_key_blob;
|
||||
size_t private_key_blob_len;
|
||||
const char *private_key_passwd;
|
||||
const char *private_key_passwd2;
|
||||
const char *dh_file;
|
||||
const u8 *dh_blob;
|
||||
size_t dh_blob_len;
|
||||
@ -156,9 +209,13 @@ struct tls_connection_params {
|
||||
const char *key_id;
|
||||
const char *cert_id;
|
||||
const char *ca_cert_id;
|
||||
const char *openssl_ciphers;
|
||||
const char *openssl_ecdh_curves;
|
||||
|
||||
unsigned int flags;
|
||||
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
|
||||
* 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
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* 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_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);
|
||||
|
||||
enum {
|
||||
TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN = -4,
|
||||
TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
|
||||
TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
|
||||
};
|
||||
@ -245,10 +315,12 @@ enum {
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @params: Connection parameters
|
||||
* 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
|
||||
* 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_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()
|
||||
* @params: Global TLS parameters
|
||||
* 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
|
||||
* 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(
|
||||
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()
|
||||
* @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
@ -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.
|
||||
* 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,
|
||||
int verify_peer,
|
||||
unsigned int flags,
|
||||
@ -460,6 +536,19 @@ int __must_check tls_connection_set_cipher_list(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
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_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,
|
||||
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)
|
||||
(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
|
||||
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,
|
||||
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 */
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* See README for more details.
|
||||
@ -9,30 +9,35 @@
|
||||
* 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_server.h"
|
||||
|
||||
|
||||
static int tls_ref_count = 0;
|
||||
|
||||
struct tls_global {
|
||||
int server;
|
||||
struct tlsv1_credentials *server_cred;
|
||||
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 tlsv1_client *client;
|
||||
struct tlsv1_server *server;
|
||||
struct tls_global *global;
|
||||
};
|
||||
|
||||
|
||||
void * tls_init(void)
|
||||
void * tls_init(const struct tls_config *conf)
|
||||
{
|
||||
struct tls_global *global;
|
||||
|
||||
@ -48,9 +53,14 @@ void * tls_init(void)
|
||||
}
|
||||
tls_ref_count++;
|
||||
|
||||
global = (struct tls_global *)os_zalloc(sizeof(*global));
|
||||
global = os_zalloc(sizeof(*global));
|
||||
if (global == 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;
|
||||
}
|
||||
@ -64,10 +74,12 @@ void tls_deinit(void *ssl_ctx)
|
||||
tlsv1_client_global_deinit();
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
tlsv1_cred_free(global->server_cred);
|
||||
tlsv1_server_global_deinit();
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
}
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
tlsv1_cred_free(global->server_cred);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
os_free(global);
|
||||
}
|
||||
|
||||
@ -83,9 +95,11 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
|
||||
struct tls_connection *conn;
|
||||
struct tls_global *global = tls_ctx;
|
||||
|
||||
conn = (struct tls_connection *)os_zalloc(sizeof(*conn));
|
||||
conn = os_zalloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
return NULL;
|
||||
conn->global = global;
|
||||
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (!global->server) {
|
||||
conn->client = tlsv1_client_init();
|
||||
@ -93,6 +107,8 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
|
||||
os_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
tlsv1_client_set_cb(conn->client, global->event_cb,
|
||||
global->cb_ctx, global->cert_in_cb);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
#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)
|
||||
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();
|
||||
if (cred == NULL)
|
||||
return -1;
|
||||
|
||||
if (params->subject_match) {
|
||||
wpa_printf(MSG_INFO, "TLS: subject_match not supported");
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (params->altsubject_match) {
|
||||
wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (params->suffix_match) {
|
||||
wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (params->domain_match) {
|
||||
wpa_printf(MSG_INFO, "TLS: domain_match not supported");
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (params->openssl_ciphers) {
|
||||
wpa_printf(MSG_INFO, "TLS: openssl_ciphers not supported");
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (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,
|
||||
params->ca_cert_blob, params->ca_cert_blob_len,
|
||||
params->ca_path)) {
|
||||
@ -193,13 +281,19 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
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) {
|
||||
tlsv1_cred_free(cred);
|
||||
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;
|
||||
#else /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
@ -215,6 +309,9 @@ int tls_global_set_params(void *tls_ctx,
|
||||
struct tls_global *global = tls_ctx;
|
||||
struct tlsv1_credentials *cred;
|
||||
|
||||
if (params->check_cert_subject)
|
||||
return -1; /* not yet supported */
|
||||
|
||||
/* Currently, global parameters are only set when running in server
|
||||
* mode. */
|
||||
global->server = 1;
|
||||
@ -251,6 +348,13 @@ int tls_global_set_params(void *tls_ctx,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (params->ocsp_stapling_response)
|
||||
cred->ocsp_stapling_response =
|
||||
os_strdup(params->ocsp_stapling_response);
|
||||
if (params->ocsp_stapling_response_multi)
|
||||
cred->ocsp_stapling_response_multi =
|
||||
os_strdup(params->ocsp_stapling_response_multi);
|
||||
|
||||
return 0;
|
||||
#else /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
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;
|
||||
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,
|
||||
struct tls_random *data)
|
||||
struct tls_random *data)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_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
|
||||
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);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_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);
|
||||
}
|
||||
#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_len(in_data) : 0,
|
||||
&res_len, &ad, &ad_len, need_more_data);
|
||||
if (res == NULL) {
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
}
|
||||
out = wpabuf_alloc_ext_data(res, res_len);
|
||||
if (out == NULL) {
|
||||
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,
|
||||
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)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_get_failed(conn->server);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned int tls_capabilities(void *tls_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tls_connection_set_session_ticket_cb(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
@ -656,3 +780,32 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
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)
|
||||
{
|
||||
}
|
@ -30,7 +30,7 @@
|
||||
#include "crypto/sha256.h"
|
||||
|
||||
#include "utils/ext_password.h"
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_peer/eap_i.h"
|
||||
#include "eap_peer/eap_config.h"
|
||||
#include "eap_peer/eap.h"
|
||||
@ -296,12 +296,10 @@ int eap_peer_register_methods(void)
|
||||
ret = eap_peer_mschapv2_register();
|
||||
#endif
|
||||
|
||||
#ifndef USE_MBEDTLS_CRYPTO
|
||||
#ifdef EAP_FAST
|
||||
if (ret == 0)
|
||||
ret = eap_peer_fast_register();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef EAP_PEAP
|
||||
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++].method = EAP_TYPE_TLS;
|
||||
}
|
||||
#ifndef USE_MBEDTLS_CRYPTO
|
||||
#ifdef EAP_FAST
|
||||
if (g_wpa_pac_file) {
|
||||
//set EAP-FAST
|
||||
config_methods[allowed_method_count].vendor = EAP_VENDOR_IETF;
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "eap_peer/eap_tlv_common.h"
|
||||
#include "eap_peer/eap_methods.h"
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_peer/eap_defs.h"
|
||||
#include "eap_peer/eap_tlv_common.h"
|
||||
#include "eap_peer/eap_fast_common.h"
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "rsn_supp/wpa.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/ms_funcs.h"
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_peer/eap_i.h"
|
||||
#include "eap_peer/eap_defs.h"
|
||||
#include "eap_peer/eap_tls_common.h"
|
||||
|
@ -10,7 +10,7 @@
|
||||
#ifdef EAP_PEAP
|
||||
#include "utils/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_peer/eap_tlv_common.h"
|
||||
#include "eap_peer/eap_peap_common.h"
|
||||
#include "eap_peer/eap_i.h"
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#ifdef EAP_TLS
|
||||
#include "utils/common.h"
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_peer/eap_i.h"
|
||||
#include "eap_peer/eap_defs.h"
|
||||
#include "eap_peer/eap_tls_common.h"
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_peer/eap_i.h"
|
||||
#include "eap_peer/eap_tls_common.h"
|
||||
#include "eap_peer/eap_config.h"
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "utils/common.h"
|
||||
#include "crypto/ms_funcs.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "tls/tls.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_peer/chap.h"
|
||||
#include "eap_peer/eap.h"
|
||||
#include "eap_peer/eap_ttls.h"
|
||||
|
@ -1,15 +1,172 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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)
|
||||
{
|
||||
@ -20,26 +177,51 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
|
||||
pos = buf;
|
||||
end = buf + len;
|
||||
|
||||
if (pos >= end) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
|
||||
return -1;
|
||||
}
|
||||
hdr->identifier = *pos++;
|
||||
hdr->class = hdr->identifier >> 6;
|
||||
hdr->constructed = !!(hdr->identifier & (1 << 5));
|
||||
|
||||
if ((hdr->identifier & 0x1f) == 0x1f) {
|
||||
size_t ext_len = 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 {
|
||||
if (pos >= end) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
|
||||
"underflow");
|
||||
return -1;
|
||||
}
|
||||
ext_len++;
|
||||
tmp = *pos++;
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Extended tag data: "
|
||||
wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
|
||||
"0x%02x", tmp);
|
||||
hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
|
||||
} 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
|
||||
hdr->tag = hdr->identifier & 0x1f;
|
||||
|
||||
if (pos >= end) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
|
||||
return -1;
|
||||
}
|
||||
tmp = *pos++;
|
||||
if (tmp & 0x80) {
|
||||
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 */
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
|
||||
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++;
|
||||
}
|
||||
if (hdr->length < 128) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ASN.1: Definite long form of the length used with too short length");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* Short form - length 0..127 in one octet */
|
||||
hdr->length = tmp;
|
||||
@ -72,10 +264,29 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
|
||||
}
|
||||
|
||||
hdr->payload = pos;
|
||||
|
||||
if (!asn1_valid_der(hdr)) {
|
||||
asn1_print_hdr(hdr, "ASN.1: Invalid DER encoding: ");
|
||||
return -1;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
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,
|
||||
"%s%lu",
|
||||
i == 0 ? "" : ".", oid->oid[i]);
|
||||
if (ret < 0 || ret >= buf + len - pos)
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
break;
|
||||
pos += ret;
|
||||
}
|
||||
@ -204,3 +412,239 @@ unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -20,13 +20,15 @@
|
||||
#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */
|
||||
#define ASN1_TAG_REAL 0x09 /* 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 ANS1_TAG_RELATIVE_OID 0x0D
|
||||
#define ASN1_TAG_TIME 0x0E
|
||||
#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */
|
||||
#define ASN1_TAG_SET 0x11
|
||||
#define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */
|
||||
#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_IA5STRING 0x16
|
||||
#define ASN1_TAG_UTCTIME 0x17
|
||||
@ -35,7 +37,8 @@
|
||||
#define ASN1_TAG_VISIBLESTRING 0x1A
|
||||
#define ASN1_TAG_GENERALSTRING 0x1B /* 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_APPLICATION 1
|
||||
@ -57,10 +60,153 @@ struct asn1_oid {
|
||||
|
||||
|
||||
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_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
|
||||
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);
|
||||
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 */
|
||||
|
@ -2,14 +2,8 @@
|
||||
* Big number math
|
||||
* 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
|
||||
|
@ -1,16 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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,
|
||||
@ -113,6 +115,11 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
|
||||
pos++;
|
||||
if (pos == end)
|
||||
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++;
|
||||
|
||||
*outlen -= pos - out;
|
||||
@ -142,46 +149,41 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
|
||||
* 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] != 0x00 && plain[1] != 0x01)) {
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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++;
|
||||
@ -193,3 +195,145 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -9,6 +9,9 @@
|
||||
#ifndef PKCS1_H
|
||||
#define PKCS1_H
|
||||
|
||||
struct crypto_public_key;
|
||||
struct asn1_oid;
|
||||
|
||||
int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
|
||||
int use_private, const u8 *in, size_t inlen,
|
||||
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,
|
||||
const u8 *crypt, size_t crypt_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 */
|
||||
|
@ -1,48 +1,263 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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/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 {
|
||||
enum pkcs5_alg {
|
||||
PKCS5_ALG_UNKNOWN,
|
||||
PKCS5_ALG_MD5_DES_CBC
|
||||
PKCS5_ALG_MD5_DES_CBC,
|
||||
PKCS5_ALG_PBES2,
|
||||
PKCS5_ALG_SHA1_3DES_CBC,
|
||||
} alg;
|
||||
u8 salt[8];
|
||||
u8 salt[64];
|
||||
size_t salt_len;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
struct pkcs5_params *params)
|
||||
{
|
||||
@ -72,32 +287,39 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (params->alg == PKCS5_ALG_PBES2)
|
||||
return pkcs5_get_params_pbes2(params, pos, enc_alg_end);
|
||||
|
||||
/* PBES1 */
|
||||
|
||||
/*
|
||||
* PKCS#5, Section 8
|
||||
* PBEParameter ::= SEQUENCE {
|
||||
* salt OCTET STRING SIZE(8),
|
||||
* 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 ||
|
||||
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;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
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 ||
|
||||
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;
|
||||
}
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
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,
|
||||
const char *passwd)
|
||||
{
|
||||
@ -145,9 +534,14 @@ static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
|
||||
const u8 *addr[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;
|
||||
}
|
||||
|
||||
addr[0] = (const u8 *) 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);
|
||||
|
||||
return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
|
||||
|
||||
}
|
||||
|
||||
|
||||
u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
|
||||
const u8 *enc_data, size_t enc_data_len,
|
||||
const char *passwd, size_t *data_len)
|
||||
{
|
||||
struct crypto_cipher *ctx = NULL;
|
||||
struct crypto_cipher *ctx;
|
||||
u8 *eb, pad;
|
||||
struct pkcs5_params params;
|
||||
unsigned int i;
|
||||
@ -184,7 +578,6 @@ u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
|
||||
}
|
||||
|
||||
ctx = pkcs5_crypto_init(¶ms, passwd);
|
||||
|
||||
if (ctx == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
|
||||
return NULL;
|
||||
@ -204,13 +597,12 @@ u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
|
||||
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");
|
||||
crypto_cipher_deinit(ctx);
|
||||
os_free(eb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
crypto_cipher_deinit(ctx);
|
||||
|
||||
pad = eb[enc_data_len - 1];
|
||||
|
@ -6,14 +6,15 @@
|
||||
* 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)
|
||||
{
|
||||
@ -26,22 +27,17 @@ struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
|
||||
/* PKCS #8, Chapter 6 */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
end = pos + hdr.length;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@ -67,13 +63,9 @@ struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
|
||||
|
||||
/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
|
||||
* (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;
|
||||
}
|
||||
|
||||
@ -103,11 +95,9 @@ struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
|
||||
|
||||
/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
|
||||
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;
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
@ -151,12 +138,9 @@ pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
|
||||
|
||||
/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
|
||||
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;
|
||||
}
|
||||
enc_alg = hdr.payload;
|
||||
@ -165,11 +149,9 @@ pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
|
||||
|
||||
/* encryptedData EncryptedData */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,8 @@ static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
|
@ -1,20 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common.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:
|
||||
* 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,
|
||||
TLS_PRE_MASTER_SECRET_LEN - 2))
|
||||
return -1;
|
||||
@ -110,7 +135,6 @@ int tls_derive_keys(struct tlsv1_client *conn,
|
||||
pos += conn->rl.iv_size;
|
||||
/* server_write_IV */
|
||||
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
|
||||
pos += conn->rl.iv_size;
|
||||
} else {
|
||||
/*
|
||||
* Use IV field to set the mask value for TLS v1.1. A fixed
|
||||
@ -245,7 +269,7 @@ failed:
|
||||
conn->alert_description,
|
||||
out_len);
|
||||
} else if (msg == NULL) {
|
||||
msg = (u8 *)os_zalloc(1);
|
||||
msg = os_zalloc(1);
|
||||
*out_len = 0;
|
||||
}
|
||||
|
||||
@ -444,7 +468,7 @@ struct tlsv1_client * tlsv1_client_init(void)
|
||||
size_t count;
|
||||
u16 *suites;
|
||||
|
||||
conn = (struct tlsv1_client *)os_zalloc(sizeof(*conn));
|
||||
conn = os_zalloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -459,13 +483,16 @@ struct tlsv1_client * tlsv1_client_init(void)
|
||||
|
||||
count = 0;
|
||||
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_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;
|
||||
#ifdef CONFIG_DES3
|
||||
suites[count++] = TLS_DHE_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_MD5;
|
||||
conn->num_cipher_suites = count;
|
||||
@ -491,6 +518,7 @@ void tlsv1_client_deinit(struct tlsv1_client *conn)
|
||||
tlsv1_client_free_dh(conn);
|
||||
tlsv1_cred_free(conn->cred);
|
||||
wpabuf_free(conn->partial_input);
|
||||
x509_certificate_chain_free(conn->server_cert);
|
||||
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
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @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,
|
||||
* 1 = server_random|client_random
|
||||
* @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
|
||||
*/
|
||||
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)
|
||||
{
|
||||
u8 seed[2 * TLS_RANDOM_LEN];
|
||||
u8 *seed, *pos;
|
||||
size_t seed_len = 2 * TLS_RANDOM_LEN;
|
||||
int res;
|
||||
|
||||
if (conn->state != ESTABLISHED)
|
||||
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) {
|
||||
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
size_t buflen)
|
||||
{
|
||||
#ifndef ESPRESSIF_USE
|
||||
char *cipher;
|
||||
|
||||
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:
|
||||
cipher = "RC4-SHA";
|
||||
break;
|
||||
#ifdef CONFIG_DES
|
||||
case TLS_RSA_WITH_DES_CBC_SHA:
|
||||
cipher = "DES-CBC-SHA";
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_DES3
|
||||
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
cipher = "DES-CBC3-SHA";
|
||||
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;
|
||||
case TLS_DH_anon_WITH_AES_128_CBC_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:
|
||||
cipher = "AES-256-SHA";
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy((u8 *)buf, (u8 *)cipher, buflen);
|
||||
|
||||
if (os_strlcpy(buf, cipher, buflen) >= buflen)
|
||||
return -1;
|
||||
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_128_CBC_SHA256;
|
||||
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
|
||||
#ifdef CONFIG_DES3
|
||||
suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
|
||||
#endif
|
||||
suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
|
||||
#ifdef CONFIG_DES
|
||||
suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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_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;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* See README for more details.
|
||||
@ -19,6 +19,7 @@ struct tlsv1_client * tlsv1_client_init(void);
|
||||
void tlsv1_client_deinit(struct tlsv1_client *conn);
|
||||
int tlsv1_client_established(struct tlsv1_client *conn);
|
||||
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);
|
||||
u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
|
||||
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_cred(struct tlsv1_client *conn,
|
||||
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)
|
||||
(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,
|
||||
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 */
|
||||
|
@ -29,11 +29,14 @@ struct tlsv1_client {
|
||||
u8 alert_level;
|
||||
u8 alert_description;
|
||||
|
||||
unsigned int flags; /* TLS_CONN_* bitfield */
|
||||
|
||||
unsigned int certificate_requested:1;
|
||||
unsigned int session_resumed:1;
|
||||
unsigned int session_ticket_included: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;
|
||||
|
||||
@ -64,12 +67,20 @@ struct tlsv1_client {
|
||||
void *session_ticket_cb_ctx;
|
||||
|
||||
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 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,
|
||||
const u8 *pre_master_secret, size_t pre_master_secret_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,
|
||||
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 */
|
||||
|
759
components/wpa_supplicant/src/tls/tlsv1_client_ocsp.c
Normal file
759
components/wpa_supplicant/src/tls/tlsv1_client_ocsp.c
Normal file
@ -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;
|
||||
}
|
@ -1,24 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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/sha1.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,
|
||||
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);
|
||||
|
||||
|
||||
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,
|
||||
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)
|
||||
goto decode_error;
|
||||
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 "
|
||||
"ServerHello %u.%u", pos[0], pos[1]);
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
@ -166,8 +217,24 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
|
||||
}
|
||||
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) {
|
||||
/* TODO: ServerHello extensions */
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
|
||||
"end of ServerHello", pos, end - pos);
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
@ -354,6 +499,8 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
|
||||
return -1;
|
||||
}
|
||||
|
||||
tls_peer_cert_event(conn, idx, cert);
|
||||
|
||||
if (last == NULL)
|
||||
chain = cert;
|
||||
else
|
||||
@ -364,31 +511,99 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
|
||||
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;
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
|
||||
"validation failed (reason=%d)", reason);
|
||||
switch (reason) {
|
||||
case X509_VALIDATE_BAD_CERTIFICATE:
|
||||
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
|
||||
tls_cert_chain_failure_event(
|
||||
conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
|
||||
"bad certificate");
|
||||
break;
|
||||
case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
|
||||
tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
|
||||
break;
|
||||
case X509_VALIDATE_CERTIFICATE_REVOKED:
|
||||
tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
|
||||
tls_cert_chain_failure_event(
|
||||
conn, 0, chain, TLS_FAIL_REVOKED,
|
||||
"certificate revoked");
|
||||
break;
|
||||
case X509_VALIDATE_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;
|
||||
case X509_VALIDATE_CERTIFICATE_UNKNOWN:
|
||||
tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
|
||||
break;
|
||||
case X509_VALIDATE_UNKNOWN_CA:
|
||||
tls_reason = TLS_ALERT_UNKNOWN_CA;
|
||||
tls_cert_chain_failure_event(
|
||||
conn, 0, chain, TLS_FAIL_UNTRUSTED,
|
||||
"unknown CA");
|
||||
break;
|
||||
default:
|
||||
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
|
||||
@ -399,21 +614,66 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
|
||||
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;
|
||||
|
||||
conn->state = SERVER_KEY_EXCHANGE;
|
||||
|
||||
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,
|
||||
const u8 *buf, size_t len,
|
||||
tls_key_exchange key_exchange)
|
||||
{
|
||||
const u8 *pos, *end, *server_params, *server_params_end;
|
||||
u8 alert;
|
||||
unsigned int bits;
|
||||
u16 val;
|
||||
|
||||
tlsv1_client_free_dh(conn);
|
||||
|
||||
@ -423,31 +683,38 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
|
||||
if (end - pos < 3)
|
||||
goto fail;
|
||||
server_params = pos;
|
||||
conn->dh_p_len = WPA_GET_BE16(pos);
|
||||
val = WPA_GET_BE16(pos);
|
||||
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;
|
||||
}
|
||||
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)
|
||||
goto fail;
|
||||
os_memcpy(conn->dh_p, pos, conn->dh_p_len);
|
||||
pos += conn->dh_p_len;
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
|
||||
conn->dh_p, conn->dh_p_len);
|
||||
|
||||
if (end - pos < 3)
|
||||
goto fail;
|
||||
conn->dh_g_len = WPA_GET_BE16(pos);
|
||||
val = WPA_GET_BE16(pos);
|
||||
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;
|
||||
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)
|
||||
goto fail;
|
||||
os_memcpy(conn->dh_g, pos, conn->dh_g_len);
|
||||
pos += conn->dh_g_len;
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
|
||||
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)
|
||||
goto fail;
|
||||
conn->dh_ys_len = WPA_GET_BE16(pos);
|
||||
val = WPA_GET_BE16(pos);
|
||||
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;
|
||||
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)
|
||||
goto fail;
|
||||
os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
|
||||
pos += conn->dh_ys_len;
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
|
||||
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)
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
|
||||
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,
|
||||
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;
|
||||
|
||||
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)
|
||||
return tls_process_certificate_request(conn, ct, in_data,
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
|
||||
"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_UNEXPECTED_MESSAGE);
|
||||
return -1;
|
||||
@ -615,6 +1113,7 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
|
||||
}
|
||||
|
||||
*in_len = end - in_data;
|
||||
|
||||
conn->state = SERVER_CERTIFICATE_REQUEST;
|
||||
|
||||
return 0;
|
||||
@ -678,6 +1177,7 @@ static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
|
||||
conn->certificate_requested = 1;
|
||||
|
||||
*in_len = end - in_data;
|
||||
|
||||
conn->state = SERVER_HELLO_DONE;
|
||||
|
||||
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");
|
||||
|
||||
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;
|
||||
|
||||
conn->state = CLIENT_KEY_EXCHANGE;
|
||||
|
||||
return 0;
|
||||
@ -767,7 +1277,7 @@ static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
|
||||
TLS_ALERT_HANDSHAKE_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
printf("[Debug] set the state to server certificate \n");
|
||||
|
||||
conn->state = SERVER_CERTIFICATE;
|
||||
return tls_process_certificate(conn, ct, in_data,
|
||||
in_len);
|
||||
@ -804,6 +1314,7 @@ static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
|
||||
}
|
||||
|
||||
*in_len = pos + 1 - in_data;
|
||||
|
||||
conn->state = SERVER_FINISHED;
|
||||
|
||||
return 0;
|
||||
@ -874,9 +1385,11 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (conn->rl.tls_version >= TLS_VERSION_1_2) {
|
||||
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;
|
||||
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)",
|
||||
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");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_DECRYPT_ERROR);
|
||||
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) ?
|
||||
CHANGE_CIPHER_SPEC : ACK_FINISHED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1027,10 +1543,8 @@ int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
|
||||
return -1;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case ACK_FINISHED:
|
||||
if (out_data &&
|
||||
@ -1045,9 +1559,8 @@ int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ct == TLS_CONTENT_TYPE_HANDSHAKE) {
|
||||
if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
|
||||
tls_verify_hash_add(&conn->verify, buf, *len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,26 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/tls.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)
|
||||
{
|
||||
@ -49,11 +48,21 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
|
||||
struct os_time now;
|
||||
size_t len, i;
|
||||
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;
|
||||
|
||||
os_get_time(&now);
|
||||
#ifdef TEST_FUZZ
|
||||
now.sec = 0xfffefdfc;
|
||||
#endif /* TEST_FUZZ */
|
||||
WPA_PUT_BE32(conn->client_random, now.sec);
|
||||
if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
|
||||
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;
|
||||
/* body - ClientHello */
|
||||
/* ProtocolVersion client_version */
|
||||
WPA_PUT_BE16(pos, TLS_VERSION);
|
||||
WPA_PUT_BE16(pos, tls_version);
|
||||
pos += 2;
|
||||
/* Random random: uint32 gmt_unix_time, opaque random_bytes */
|
||||
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);
|
||||
pos += 2;
|
||||
/* opaque extension_data<0..2^16-1> length */
|
||||
WPA_PUT_BE16(pos, 4);
|
||||
WPA_PUT_BE16(pos, 8);
|
||||
pos += 2;
|
||||
/* supported_signature_algorithms<2..2^16-2> length */
|
||||
WPA_PUT_BE16(pos, 2);
|
||||
WPA_PUT_BE16(pos, 6);
|
||||
pos += 2;
|
||||
/* 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_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;
|
||||
}
|
||||
|
||||
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)
|
||||
pos -= 2; /* no extensions */
|
||||
else
|
||||
@ -166,6 +257,11 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
|
||||
struct x509_certificate *cert;
|
||||
|
||||
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");
|
||||
rhdr = pos;
|
||||
@ -186,7 +282,7 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
|
||||
pos += 3;
|
||||
cert = conn->cred ? conn->cred->cert : NULL;
|
||||
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 "
|
||||
"for Certificate (cert_len=%lu left=%lu)",
|
||||
(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 */
|
||||
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);
|
||||
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(dh_yc);
|
||||
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)",
|
||||
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);
|
||||
*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 "
|
||||
"message buffer for Yc");
|
||||
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 */
|
||||
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(shared);
|
||||
return -1;
|
||||
@ -359,7 +462,7 @@ static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
|
||||
size_t clen;
|
||||
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_PRE_MASTER_SECRET_LEN)) {
|
||||
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;
|
||||
pos += 3;
|
||||
/* 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;
|
||||
} else {
|
||||
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;
|
||||
size_t rlen, hlen, clen;
|
||||
u8 hash[100], *hpos;
|
||||
enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
@ -511,7 +613,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
|
||||
0) {
|
||||
conn->verify.sha256_cert = NULL;
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
conn->verify.sha256_cert = NULL;
|
||||
@ -537,21 +639,17 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
|
||||
} else {
|
||||
#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;
|
||||
hlen = SHA1_MAC_LEN;
|
||||
@ -564,8 +662,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
|
||||
}
|
||||
conn->verify.sha1_cert = NULL;
|
||||
|
||||
if (alg == SIGN_ALG_RSA)
|
||||
hlen += MD5_MAC_LEN;
|
||||
hlen += MD5_MAC_LEN;
|
||||
|
||||
#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)
|
||||
< 0) {
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
conn->verify.sha256_client = NULL;
|
||||
return -1;
|
||||
}
|
||||
@ -796,6 +893,7 @@ static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
|
||||
}
|
||||
|
||||
*out_len = pos - msg;
|
||||
|
||||
conn->state = SERVER_CHANGE_CIPHER_SPEC;
|
||||
|
||||
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 "
|
||||
"successfully");
|
||||
|
||||
if (!conn->session_resumed && conn->use_session_ticket)
|
||||
conn->session_resumed = 1;
|
||||
conn->state = ESTABLISHED;
|
||||
|
||||
return msg;
|
||||
|
@ -1,21 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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/sha1.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_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
|
||||
TLS_HASH_SHA },
|
||||
#ifdef CONFIG_DES
|
||||
{ TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC,
|
||||
TLS_HASH_SHA },
|
||||
#endif
|
||||
#ifdef CONFIG_DES3
|
||||
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
|
||||
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_CIPHER_RC4_128, TLS_HASH_MD5 },
|
||||
#ifdef CONFIG_DES
|
||||
{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
|
||||
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_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_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_CIPHER_AES_128_CBC, TLS_HASH_SHA },
|
||||
{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
|
||||
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_CIPHER_AES_256_CBC, TLS_HASH_SHA },
|
||||
{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
|
||||
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
|
||||
{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
|
||||
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_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
|
||||
{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
|
||||
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[] = {
|
||||
@ -83,23 +84,19 @@ static const struct tls_cipher_data tls_ciphers[] = {
|
||||
CRYPTO_CIPHER_ALG_RC4 },
|
||||
{ TLS_CIPHER_RC4_128, TLS_CIPHER_STREAM, 16, 16, 0,
|
||||
CRYPTO_CIPHER_ALG_RC4 },
|
||||
#ifdef CONFIG_DES
|
||||
{ TLS_CIPHER_DES40_CBC, TLS_CIPHER_BLOCK, 5, 8, 8,
|
||||
CRYPTO_CIPHER_ALG_DES },
|
||||
{ TLS_CIPHER_DES_CBC, TLS_CIPHER_BLOCK, 8, 8, 8,
|
||||
CRYPTO_CIPHER_ALG_DES },
|
||||
#endif
|
||||
#ifdef CONFIG_DES3
|
||||
{ TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK, 24, 24, 8,
|
||||
CRYPTO_CIPHER_ALG_3DES },
|
||||
#endif
|
||||
{ TLS_CIPHER_AES_128_CBC, TLS_CIPHER_BLOCK, 16, 16, 16,
|
||||
CRYPTO_CIPHER_ALG_AES },
|
||||
{ TLS_CIPHER_AES_256_CBC, TLS_CIPHER_BLOCK, 32, 32, 16,
|
||||
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;
|
||||
}
|
||||
#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) {
|
||||
tls_verify_hash_free(verify);
|
||||
return -1;
|
||||
@ -254,7 +252,7 @@ void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
|
||||
}
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (verify->sha256_client)
|
||||
crypto_hash_update(verify->sha256_client, buf, len);
|
||||
crypto_hash_update(verify->sha256_client, buf, len);
|
||||
if (verify->sha256_server)
|
||||
crypto_hash_update(verify->sha256_server, buf, len);
|
||||
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;
|
||||
hlen = SHA256_MAC_LEN;
|
||||
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:
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* See README for more details.
|
||||
@ -170,6 +170,7 @@ enum {
|
||||
#define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */
|
||||
#define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */
|
||||
#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_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
|
||||
|
@ -1,23 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 "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 *cred;
|
||||
cred = (struct tlsv1_credentials *)os_zalloc(sizeof(*cred));
|
||||
cred = os_zalloc(sizeof(*cred));
|
||||
return cred;
|
||||
}
|
||||
|
||||
@ -32,6 +36,8 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred)
|
||||
crypto_private_key_free(cred->key);
|
||||
os_free(cred->dh_p);
|
||||
os_free(cred->dh_g);
|
||||
os_free(cred->ocsp_stapling_response);
|
||||
os_free(cred->ocsp_stapling_response_multi);
|
||||
os_free(cred);
|
||||
}
|
||||
|
||||
@ -124,7 +130,7 @@ static int tlsv1_add_cert(struct x509_certificate **chain,
|
||||
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) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
|
||||
"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);
|
||||
|
||||
if (cert) {
|
||||
u8 *buf = NULL;
|
||||
size_t len = 0;
|
||||
u8 *buf;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
buf = (u8 *) os_readfile(cert, &len);
|
||||
if (buf == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
|
||||
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 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,
|
||||
cert_blob, cert_blob_len) < 0)
|
||||
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)
|
||||
return 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)
|
||||
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)
|
||||
return NULL;
|
||||
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,
|
||||
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);
|
||||
if (cred->key == NULL)
|
||||
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) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
|
||||
return -1;
|
||||
@ -327,10 +1048,11 @@ int tlsv1_set_private_key(struct tlsv1_credentials *cred,
|
||||
private_key_passwd);
|
||||
|
||||
if (private_key) {
|
||||
u8 *buf = NULL;
|
||||
size_t len = 0;
|
||||
u8 *buf;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
buf = (u8 *) os_readfile(private_key, &len);
|
||||
if (buf == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
|
||||
private_key);
|
||||
@ -363,24 +1085,17 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
|
||||
*/
|
||||
|
||||
/* 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;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@ -388,21 +1103,16 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
|
||||
if (hdr.length == 0)
|
||||
return -1;
|
||||
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)
|
||||
return -1;
|
||||
os_memcpy(cred->dh_p, hdr.payload, hdr.length);
|
||||
cred->dh_p_len = hdr.length;
|
||||
pos = hdr.payload + hdr.length;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@ -410,10 +1120,9 @@ static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
|
||||
if (hdr.length == 0)
|
||||
return -1;
|
||||
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)
|
||||
return -1;
|
||||
os_memcpy(cred->dh_g, hdr.payload, hdr.length);
|
||||
cred->dh_g_len = hdr.length;
|
||||
|
||||
return 0;
|
||||
@ -449,7 +1158,7 @@ static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
|
||||
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) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
|
||||
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);
|
||||
|
||||
if (dh_file) {
|
||||
u8 *buf = NULL;
|
||||
size_t len = 0;
|
||||
u8 *buf;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
buf = (u8 *) os_readfile(dh_file, &len);
|
||||
if (buf == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
|
||||
dh_file);
|
||||
|
@ -14,11 +14,19 @@ struct tlsv1_credentials {
|
||||
struct x509_certificate *cert;
|
||||
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 */
|
||||
u8 *dh_p; /* prime */
|
||||
size_t dh_p_len;
|
||||
u8 *dh_g; /* generator */
|
||||
size_t dh_g_len;
|
||||
|
||||
char *ocsp_stapling_response;
|
||||
char *ocsp_stapling_response_multi;
|
||||
};
|
||||
|
||||
|
||||
|
@ -6,16 +6,15 @@
|
||||
* 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/sha1.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
|
||||
@ -83,13 +82,11 @@ int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
|
||||
if (rl->write_cbc) {
|
||||
crypto_cipher_deinit(rl->write_cbc);
|
||||
rl->write_cbc = NULL;
|
||||
|
||||
}
|
||||
if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
|
||||
"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)
|
||||
{
|
||||
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;
|
||||
os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
|
||||
|
||||
if (rl->read_cbc) {
|
||||
crypto_cipher_deinit(rl->read_cbc);
|
||||
rl->read_cbc = NULL;
|
||||
rl->read_cbc = NULL;
|
||||
}
|
||||
|
||||
if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
|
||||
"cipher");
|
||||
@ -156,7 +152,7 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
|
||||
size_t *out_len)
|
||||
{
|
||||
u8 *pos, *ct_start, *length, *cpayload;
|
||||
struct crypto_hash *hmac = NULL;
|
||||
struct crypto_hash *hmac;
|
||||
size_t clen;
|
||||
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.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) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
|
||||
"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 "
|
||||
"enough room for MAC");
|
||||
crypto_hash_finish(hmac, NULL, NULL);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -285,7 +281,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
|
||||
{
|
||||
size_t i, rlen, hlen;
|
||||
u8 padlen;
|
||||
struct crypto_hash *hmac = NULL;
|
||||
struct crypto_hash *hmac;
|
||||
u8 len[2], hash[100];
|
||||
int force_mac_error = 0;
|
||||
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) {
|
||||
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;
|
||||
return -1;
|
||||
}
|
||||
|
||||
plen = in_len;
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
|
||||
"data", out_data, plen);
|
||||
@ -438,8 +433,8 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
|
||||
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
|
||||
"to initialize HMAC");
|
||||
@ -453,16 +448,15 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
|
||||
WPA_PUT_BE16(len, plen);
|
||||
crypto_hash_update(hmac, len, 2);
|
||||
crypto_hash_update(hmac, out_data, plen);
|
||||
|
||||
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;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
|
||||
"received message (force_mac_error=%d)",
|
||||
|
@ -1,26 +1,51 @@
|
||||
/*
|
||||
* 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.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common.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:
|
||||
* 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)
|
||||
{
|
||||
conn->alert_level = level;
|
||||
@ -139,7 +164,8 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
|
||||
/* need more data */
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
|
||||
"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;
|
||||
}
|
||||
ct = pos[0];
|
||||
@ -179,6 +205,7 @@ failed:
|
||||
msg = tlsv1_server_send_alert(conn, conn->alert_level,
|
||||
conn->alert_description,
|
||||
out_len);
|
||||
conn->write_alerts++;
|
||||
}
|
||||
|
||||
return msg;
|
||||
@ -250,8 +277,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
|
||||
used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
|
||||
out_pos, &olen, &alert);
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
@ -265,14 +291,14 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
|
||||
|
||||
if (ct == TLS_CONTENT_TYPE_ALERT) {
|
||||
if (olen < 2) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Alert "
|
||||
"underflow");
|
||||
tlsv1_server_log(conn, "Alert underflow");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_DECODE_ERROR);
|
||||
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) {
|
||||
/* Continue processing */
|
||||
pos += used;
|
||||
@ -285,13 +311,23 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
|
||||
}
|
||||
|
||||
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,
|
||||
TLS_ALERT_UNEXPECTED_MESSAGE);
|
||||
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;
|
||||
if (out_pos > out_end) {
|
||||
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;
|
||||
u16 *suites;
|
||||
|
||||
conn = (struct tlsv1_server *)os_zalloc(sizeof(*conn));
|
||||
conn = os_zalloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -361,11 +397,16 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
|
||||
|
||||
count = 0;
|
||||
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_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;
|
||||
#ifdef CONFIG_DES3
|
||||
suites[count++] = TLS_DHE_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_MD5;
|
||||
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
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* @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,
|
||||
* 1 = server_random|client_random
|
||||
* @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
|
||||
*/
|
||||
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)
|
||||
{
|
||||
u8 seed[2 * TLS_RANDOM_LEN];
|
||||
u8 *seed, *pos;
|
||||
size_t seed_len = 2 * TLS_RANDOM_LEN;
|
||||
int res;
|
||||
|
||||
if (conn->state != ESTABLISHED)
|
||||
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) {
|
||||
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
size_t buflen)
|
||||
{
|
||||
#ifndef ESPRESSIF_USE
|
||||
char *cipher;
|
||||
char *cipher;
|
||||
|
||||
switch (conn->rl.cipher_suite) {
|
||||
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:
|
||||
cipher = "RC4-SHA";
|
||||
break;
|
||||
#ifdef CONFIG_DES
|
||||
case TLS_RSA_WITH_DES_CBC_SHA:
|
||||
cipher = "DES-CBC-SHA";
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_DES3
|
||||
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
cipher = "DES-CBC3-SHA";
|
||||
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:
|
||||
cipher = "ADH-AES-128-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA:
|
||||
cipher = "AES-256-SHA";
|
||||
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;
|
||||
default:
|
||||
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;
|
||||
#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_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 */
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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);
|
||||
int tlsv1_server_established(struct tlsv1_server *conn);
|
||||
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);
|
||||
u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
|
||||
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,
|
||||
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 */
|
||||
|
@ -30,6 +30,8 @@ struct tlsv1_server {
|
||||
u8 alert_level;
|
||||
u8 alert_description;
|
||||
|
||||
int read_alerts, write_alerts;
|
||||
|
||||
struct crypto_public_key *client_rsa_key;
|
||||
|
||||
struct tls_verify_hash verify;
|
||||
@ -51,13 +53,27 @@ struct tlsv1_server {
|
||||
tlsv1_server_session_ticket_cb session_ticket_cb;
|
||||
void *session_ticket_cb_ctx;
|
||||
|
||||
void (*log_cb)(void *ctx, const char *msg);
|
||||
void *log_cb_ctx;
|
||||
|
||||
int use_session_ticket;
|
||||
unsigned int status_request:1;
|
||||
unsigned int status_request_v2:1;
|
||||
unsigned int status_request_multi:1;
|
||||
|
||||
u8 *dh_secret;
|
||||
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);
|
||||
int tlsv1_server_derive_keys(struct tlsv1_server *conn,
|
||||
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);
|
||||
int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
|
||||
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 */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,33 +1,32 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/tls.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)
|
||||
{
|
||||
size_t len = 0;
|
||||
struct x509_certificate *cert;
|
||||
|
||||
cert = conn->cred->cert;
|
||||
cert = conn->cred ? conn->cred->cert : NULL;
|
||||
while (cert) {
|
||||
len += 3 + cert->cert_len;
|
||||
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,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length;
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length, *ext_start;
|
||||
struct os_time now;
|
||||
size_t rlen;
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
|
||||
tlsv1_server_log(conn, "Send ServerHello");
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
os_get_time(&now);
|
||||
#ifdef TEST_FUZZ
|
||||
now.sec = 0xfffefdfc;
|
||||
#endif /* TEST_FUZZ */
|
||||
WPA_PUT_BE32(conn->server_random, now.sec);
|
||||
if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
|
||||
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 */
|
||||
*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) {
|
||||
int res = conn->session_ticket_cb(
|
||||
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->master_secret);
|
||||
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,
|
||||
TLS_ALERT_HANDSHAKE_FAILURE);
|
||||
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);
|
||||
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;
|
||||
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;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
@ -190,7 +227,7 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
|
||||
pos += 3;
|
||||
cert = conn->cred->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 "
|
||||
"for Certificate (cert_len=%lu left=%lu)",
|
||||
(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,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
tls_key_exchange keyx;
|
||||
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;
|
||||
u8 *dh_ys;
|
||||
size_t dh_ys_len;
|
||||
const u8 *dh_p;
|
||||
size_t dh_p_len;
|
||||
|
||||
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
|
||||
if (suite == NULL)
|
||||
@ -262,8 +388,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
|
||||
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 "
|
||||
"supported with key exchange type %d", keyx);
|
||||
return -1;
|
||||
@ -276,8 +401,10 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
|
||||
|
||||
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);
|
||||
if (conn->dh_secret == NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
if (dh_ys == NULL) {
|
||||
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;
|
||||
}
|
||||
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,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(dh_ys);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
|
||||
dh_ys, dh_ys_len);
|
||||
|
||||
@ -356,7 +480,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
|
||||
tlsv1_server_log(conn, "Send ServerKeyExchange");
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
@ -371,8 +495,9 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
|
||||
pos += 3;
|
||||
|
||||
/* body - ServerDHParams */
|
||||
server_params = pos;
|
||||
/* 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 "
|
||||
"dh_p");
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_BE16(pos, conn->cred->dh_p_len);
|
||||
WPA_PUT_BE16(pos, dh_p_len);
|
||||
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 */
|
||||
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 "
|
||||
"dh_g");
|
||||
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;
|
||||
|
||||
/* 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 "
|
||||
"dh_Ys");
|
||||
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;
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
|
||||
tlsv1_server_log(conn, "Send CertificateRequest");
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
@ -507,7 +765,7 @@ static int tls_write_server_hello_done(struct tlsv1_server *conn,
|
||||
size_t rlen;
|
||||
u8 payload[4];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
|
||||
tlsv1_server_log(conn, "Send ServerHelloDone");
|
||||
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
@ -543,7 +801,7 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
|
||||
size_t rlen;
|
||||
u8 payload[1];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
|
||||
tlsv1_server_log(conn, "Send ChangeCipherSpec");
|
||||
|
||||
payload[0] = TLS_CHANGE_CIPHER_SPEC;
|
||||
|
||||
@ -580,7 +838,7 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
|
||||
tlsv1_server_log(conn, "Send 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) {
|
||||
hlen = SHA256_MAC_LEN;
|
||||
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;
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
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)",
|
||||
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 */
|
||||
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;
|
||||
size_t msglen;
|
||||
int ocsp_multi = 0;
|
||||
char *ocsp_resp = NULL;
|
||||
size_t ocsp_resp_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);
|
||||
if (msg == NULL)
|
||||
if (msg == NULL) {
|
||||
os_free(ocsp_resp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = msg;
|
||||
end = msg + msglen;
|
||||
|
||||
if (tls_write_server_hello(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
os_free(ocsp_resp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (conn->use_session_ticket) {
|
||||
os_free(ocsp_resp);
|
||||
|
||||
/* Abbreviated handshake using session ticket; RFC 4507 */
|
||||
if (tls_write_server_change_cipher_spec(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 */
|
||||
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_certificate_request(conn, &pos, end) < 0 ||
|
||||
tls_write_server_hello_done(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
os_free(ocsp_resp);
|
||||
return NULL;
|
||||
}
|
||||
os_free(ocsp_resp);
|
||||
|
||||
*out_len = pos - msg;
|
||||
|
||||
@ -738,7 +1028,7 @@ static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
|
||||
|
||||
*out_len = pos - msg;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
|
||||
tlsv1_server_log(conn, "Handshake completed successfully");
|
||||
conn->state = ESTABLISHED;
|
||||
|
||||
return msg;
|
||||
@ -757,8 +1047,8 @@ u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
|
||||
/* Abbreviated handshake was already completed. */
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -769,7 +1059,7 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
|
||||
{
|
||||
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;
|
||||
|
||||
alert = os_malloc(10);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -45,13 +45,18 @@ struct x509_name {
|
||||
struct asn1_oid rid; /* registeredID */
|
||||
};
|
||||
|
||||
#define X509_MAX_SERIAL_NUM_LEN 20
|
||||
|
||||
struct x509_certificate {
|
||||
struct x509_certificate *next;
|
||||
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_name issuer;
|
||||
struct x509_name subject;
|
||||
u8 *subject_dn;
|
||||
size_t subject_dn_len;
|
||||
os_time_t not_before;
|
||||
os_time_t not_after;
|
||||
struct x509_algorithm_identifier public_key_alg;
|
||||
@ -68,6 +73,8 @@ struct x509_certificate {
|
||||
#define X509_EXT_KEY_USAGE (1 << 2)
|
||||
#define X509_EXT_SUBJECT_ALT_NAME (1 << 3)
|
||||
#define X509_EXT_ISSUER_ALT_NAME (1 << 4)
|
||||
#define X509_EXT_EXT_KEY_USAGE (1 << 5)
|
||||
#define X509_EXT_CERTIFICATE_POLICY (1 << 6)
|
||||
|
||||
/* BasicConstraints */
|
||||
int ca; /* cA */
|
||||
@ -85,6 +92,19 @@ struct x509_certificate {
|
||||
#define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7)
|
||||
#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
|
||||
* pointers point to that buffer.
|
||||
@ -93,6 +113,11 @@ struct x509_certificate {
|
||||
size_t cert_len;
|
||||
const u8 *tbs_cert_start;
|
||||
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 {
|
||||
@ -106,10 +131,21 @@ enum {
|
||||
};
|
||||
|
||||
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);
|
||||
void x509_free_name(struct x509_name *name);
|
||||
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);
|
||||
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,
|
||||
struct x509_certificate *cert);
|
||||
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);
|
||||
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 */
|
||||
|
@ -1 +1 @@
|
||||
CONFIG_WPA_MBEDTLS_CRYPTO=n
|
||||
CONFIG_WPA_MBEDTLS_TLS_CLIENT=n
|
||||
|
Loading…
x
Reference in New Issue
Block a user