wpa_supplicant: sync eap code with upstream

This commit is contained in:
Kapil Gupta 2022-05-13 12:57:47 +08:00
parent 36321fda82
commit c2429f1cf9
52 changed files with 6008 additions and 4730 deletions

View File

@ -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)

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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)
{
}

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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"

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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)
{
}

View File

@ -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;

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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;
}

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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(&params, 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];

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View 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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);

View 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;
};

View File

@ -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)",

View File

@ -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 */
}

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

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