mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
wpa_supplicant: Fix IOT issue with latest freeradius
Fix inter operability issue with freeradius version 3.0.21 and openssl 1.1.1f when internal tls client is used which requires extension elements in client hello. closes https://github.com/espressif/esp-idf/issues/5273 closes https://github.com/espressif/esp-idf/issues/5627
This commit is contained in:
parent
89ef69cbd0
commit
ebd1bb9a12
@ -706,18 +706,16 @@ int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
|
||||
if (data == NULL || data_len == 0)
|
||||
return 0;
|
||||
|
||||
pos = conn->client_hello_ext = os_malloc(6 + data_len);
|
||||
pos = conn->client_hello_ext = os_malloc(4 + data_len);
|
||||
if (pos == NULL)
|
||||
return -1;
|
||||
|
||||
WPA_PUT_BE16(pos, 4 + data_len);
|
||||
pos += 2;
|
||||
WPA_PUT_BE16(pos, ext_type);
|
||||
pos += 2;
|
||||
WPA_PUT_BE16(pos, data_len);
|
||||
pos += 2;
|
||||
os_memcpy(pos, data, data_len);
|
||||
conn->client_hello_ext_len = 6 + data_len;
|
||||
conn->client_hello_ext_len = 4 + data_len;
|
||||
|
||||
if (ext_type == TLS_EXT_PAC_OPAQUE) {
|
||||
conn->session_ticket_included = 1;
|
||||
|
@ -409,9 +409,11 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
|
||||
|
||||
|
||||
static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
|
||||
const u8 *buf, size_t len)
|
||||
const u8 *buf, size_t len,
|
||||
tls_key_exchange key_exchange)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
const u8 *pos, *end, *server_params, *server_params_end;
|
||||
u8 alert;
|
||||
|
||||
tlsv1_client_free_dh(conn);
|
||||
|
||||
@ -420,6 +422,7 @@ 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);
|
||||
pos += 2;
|
||||
if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
|
||||
@ -464,6 +467,60 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
|
||||
pos += conn->dh_ys_len;
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
|
||||
conn->dh_ys, conn->dh_ys_len);
|
||||
server_params_end = pos;
|
||||
|
||||
if (key_exchange == TLS_KEY_X_DHE_RSA) {
|
||||
u8 hash[64];
|
||||
int hlen;
|
||||
|
||||
if (conn->rl.tls_version == TLS_VERSION_1_2) {
|
||||
#ifdef CONFIG_TLSV12
|
||||
/*
|
||||
* RFC 5246, 4.7:
|
||||
* TLS v1.2 adds explicit indication of the used
|
||||
* signature and hash algorithms.
|
||||
*
|
||||
* struct {
|
||||
* HashAlgorithm hash;
|
||||
* SignatureAlgorithm signature;
|
||||
* } SignatureAndHashAlgorithm;
|
||||
*/
|
||||
if (end - pos < 2)
|
||||
goto fail;
|
||||
if ((pos[0] != TLS_HASH_ALG_SHA256) ||
|
||||
pos[1] != TLS_SIGN_ALG_RSA) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
|
||||
pos[0], pos[1]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hlen = tlsv12_key_x_server_params_hash(
|
||||
conn->rl.tls_version, pos[0],
|
||||
conn->client_random,
|
||||
conn->server_random, server_params,
|
||||
server_params_end - server_params, hash);
|
||||
pos += 2;
|
||||
#else /* CONFIG_TLSV12 */
|
||||
goto fail;
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
} else {
|
||||
hlen = tls_key_x_server_params_hash(
|
||||
conn->rl.tls_version, conn->client_random,
|
||||
conn->server_random, server_params,
|
||||
server_params_end - server_params, hash);
|
||||
}
|
||||
|
||||
if (hlen < 0)
|
||||
goto fail;
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash",
|
||||
hash, hlen);
|
||||
|
||||
if (tls_verify_signature(conn->rl.tls_version,
|
||||
conn->server_rsa_key,
|
||||
hash, hlen, pos, end - pos,
|
||||
&alert) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -542,8 +599,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
|
||||
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
|
||||
if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
|
||||
if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
|
||||
if (suite && (suite->key_exchange == TLS_KEY_X_DH_anon ||
|
||||
suite->key_exchange == TLS_KEY_X_DHE_RSA)) {
|
||||
if (tlsv1_process_diffie_hellman(conn, pos, len,
|
||||
suite->key_exchange) < 0) {
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_DECODE_ERROR);
|
||||
return -1;
|
||||
|
@ -48,6 +48,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
|
||||
u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
|
||||
struct os_time now;
|
||||
size_t len, i;
|
||||
u8 *ext_start;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
|
||||
*out_len = 0;
|
||||
@ -62,7 +63,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
|
||||
conn->client_random, TLS_RANDOM_LEN);
|
||||
|
||||
len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
|
||||
len = 150 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
|
||||
hello = os_malloc(len);
|
||||
if (hello == NULL)
|
||||
return NULL;
|
||||
@ -102,12 +103,42 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
|
||||
*pos++ = 1;
|
||||
*pos++ = TLS_COMPRESSION_NULL;
|
||||
|
||||
/* Extension */
|
||||
ext_start = pos;
|
||||
pos += 2;
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (conn->rl.tls_version >= TLS_VERSION_1_2) {
|
||||
/*
|
||||
* Add signature_algorithms extension since we support only
|
||||
* SHA256 (and not the default SHA1) with TLSv1.2.
|
||||
*/
|
||||
/* ExtensionsType extension_type = signature_algorithms(13) */
|
||||
WPA_PUT_BE16(pos, TLS_EXT_SIGNATURE_ALGORITHMS);
|
||||
pos += 2;
|
||||
/* opaque extension_data<0..2^16-1> length */
|
||||
WPA_PUT_BE16(pos, 4);
|
||||
pos += 2;
|
||||
/* supported_signature_algorithms<2..2^16-2> length */
|
||||
WPA_PUT_BE16(pos, 2);
|
||||
pos += 2;
|
||||
/* supported_signature_algorithms */
|
||||
*pos++ = TLS_HASH_ALG_SHA256;
|
||||
*pos++ = TLS_SIGN_ALG_RSA;
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
if (conn->client_hello_ext) {
|
||||
os_memcpy(pos, conn->client_hello_ext,
|
||||
conn->client_hello_ext_len);
|
||||
pos += conn->client_hello_ext_len;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "tls/tls.h"
|
||||
@ -333,3 +334,184 @@ int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
|
||||
return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
|
||||
outlen);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_alg,
|
||||
const u8 *client_random,
|
||||
const u8 *server_random,
|
||||
const u8 *server_params,
|
||||
size_t server_params_len, u8 *hash)
|
||||
{
|
||||
size_t hlen;
|
||||
struct crypto_hash *ctx;
|
||||
enum crypto_hash_alg alg;
|
||||
|
||||
switch (hash_alg) {
|
||||
case TLS_HASH_ALG_SHA256:
|
||||
alg = CRYPTO_HASH_ALG_SHA256;
|
||||
hlen = SHA256_MAC_LEN;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
ctx = crypto_hash_init(alg, NULL, 0);
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
|
||||
crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
|
||||
crypto_hash_update(ctx, server_params, server_params_len);
|
||||
if (crypto_hash_finish(ctx, hash, &hlen) < 0)
|
||||
return -1;
|
||||
|
||||
return hlen;
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
|
||||
int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
|
||||
const u8 *server_random,
|
||||
const u8 *server_params,
|
||||
size_t server_params_len, u8 *hash)
|
||||
{
|
||||
u8 *hpos;
|
||||
size_t hlen;
|
||||
struct crypto_hash *ctx;
|
||||
|
||||
hpos = hash;
|
||||
|
||||
ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
|
||||
crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
|
||||
crypto_hash_update(ctx, server_params, server_params_len);
|
||||
hlen = MD5_MAC_LEN;
|
||||
if (crypto_hash_finish(ctx, hash, &hlen) < 0)
|
||||
return -1;
|
||||
hpos += hlen;
|
||||
|
||||
ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
|
||||
crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
|
||||
crypto_hash_update(ctx, server_params, server_params_len);
|
||||
hlen = hash + sizeof(hash) - hpos;
|
||||
if (crypto_hash_finish(ctx, hpos, &hlen) < 0)
|
||||
return -1;
|
||||
hpos += hlen;
|
||||
return hpos - hash;
|
||||
}
|
||||
|
||||
|
||||
int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
|
||||
const u8 *data, size_t data_len,
|
||||
const u8 *pos, size_t len, u8 *alert)
|
||||
{
|
||||
u8 *buf;
|
||||
const u8 *end = pos + len;
|
||||
const u8 *decrypted;
|
||||
u16 slen;
|
||||
size_t buflen;
|
||||
|
||||
if (end - pos < 2) {
|
||||
*alert = TLS_ALERT_DECODE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
slen = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
if (end - pos < slen) {
|
||||
*alert = TLS_ALERT_DECODE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (end - pos > slen) {
|
||||
wpa_hexdump(MSG_MSGDUMP, "Additional data after Signature",
|
||||
pos + slen, end - pos - slen);
|
||||
end = pos + slen;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
|
||||
if (pk == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: No public key to verify signature");
|
||||
*alert = TLS_ALERT_INTERNAL_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
buflen = end - pos;
|
||||
buf = os_malloc(end - pos);
|
||||
if (buf == NULL) {
|
||||
*alert = TLS_ALERT_INTERNAL_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (crypto_public_key_decrypt_pkcs1(pk, pos, end - pos, buf, &buflen) <
|
||||
0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
|
||||
os_free(buf);
|
||||
*alert = TLS_ALERT_DECRYPT_ERROR;
|
||||
return -1;
|
||||
}
|
||||
decrypted = buf;
|
||||
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
|
||||
decrypted, buflen);
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (tls_version >= TLS_VERSION_1_2) {
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
if (buflen >= 19 + 32 &&
|
||||
os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
|
||||
"\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-256");
|
||||
decrypted = buf + 19;
|
||||
buflen -= 19;
|
||||
} else if (buflen >= 19 + 48 &&
|
||||
os_memcmp(buf, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01"
|
||||
"\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19) == 0)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-384");
|
||||
decrypted = buf + 19;
|
||||
buflen -= 19;
|
||||
} else if (buflen >= 19 + 64 &&
|
||||
os_memcmp(buf, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01"
|
||||
"\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19) == 0)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-512");
|
||||
decrypted = buf + 19;
|
||||
buflen -= 19;
|
||||
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
|
||||
os_free(buf);
|
||||
*alert = TLS_ALERT_DECRYPT_ERROR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
if (buflen != data_len ||
|
||||
os_memcmp_const(decrypted, data, data_len) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
|
||||
os_free(buf);
|
||||
*alert = TLS_ALERT_DECRYPT_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -169,6 +169,7 @@ enum {
|
||||
#define TLS_EXT_TRUSTED_CA_KEYS 3 /* RFC 4366 */
|
||||
#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_SESSION_TICKET 35 /* RFC 4507 */
|
||||
|
||||
#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
|
||||
@ -257,5 +258,17 @@ int tls_version_ok(u16 ver);
|
||||
const char * tls_version_str(u16 ver);
|
||||
int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
|
||||
int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_Alg,
|
||||
const u8 *client_random,
|
||||
const u8 *server_random,
|
||||
const u8 *server_params,
|
||||
size_t server_params_len, u8 *hash);
|
||||
int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
|
||||
const u8 *server_random,
|
||||
const u8 *server_params,
|
||||
size_t server_params_len, u8 *hash);
|
||||
int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
|
||||
const u8 *data, size_t data_len,
|
||||
const u8 *pos, size_t len, u8 *alert);
|
||||
|
||||
#endif /* TLSV1_COMMON_H */
|
||||
|
Loading…
Reference in New Issue
Block a user