summaryrefslogtreecommitdiffstats
path: root/contrib/wpa/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa/src/crypto')
-rw-r--r--contrib/wpa/src/crypto/aes-cbc.c6
-rw-r--r--contrib/wpa/src/crypto/aes-ctr.c28
-rw-r--r--contrib/wpa/src/crypto/aes-internal-dec.c4
-rw-r--r--contrib/wpa/src/crypto/aes-internal-enc.c7
-rw-r--r--contrib/wpa/src/crypto/aes-omac1.c3
-rw-r--r--contrib/wpa/src/crypto/aes-siv.c62
-rw-r--r--contrib/wpa/src/crypto/aes.h4
-rw-r--r--contrib/wpa/src/crypto/aes_siv.h10
-rw-r--r--contrib/wpa/src/crypto/aes_wrap.h4
-rw-r--r--contrib/wpa/src/crypto/crypto.h98
-rw-r--r--contrib/wpa/src/crypto/crypto_gnutls.c255
-rw-r--r--contrib/wpa/src/crypto/crypto_internal-modexp.c73
-rw-r--r--contrib/wpa/src/crypto/crypto_internal.c53
-rw-r--r--contrib/wpa/src/crypto/crypto_libtomcrypt.c54
-rw-r--r--contrib/wpa/src/crypto/crypto_linux.c1009
-rw-r--r--contrib/wpa/src/crypto/crypto_module_tests.c495
-rw-r--r--contrib/wpa/src/crypto/crypto_nettle.c469
-rw-r--r--contrib/wpa/src/crypto/crypto_none.c3
-rw-r--r--contrib/wpa/src/crypto/crypto_openssl.c881
-rw-r--r--contrib/wpa/src/crypto/crypto_wolfssl.c1786
-rw-r--r--contrib/wpa/src/crypto/des-internal.c17
-rw-r--r--contrib/wpa/src/crypto/dh_group5.c1
-rw-r--r--contrib/wpa/src/crypto/dh_groups.c45
-rw-r--r--contrib/wpa/src/crypto/fips_prf_openssl.c25
-rw-r--r--contrib/wpa/src/crypto/fips_prf_wolfssl.c87
-rw-r--r--contrib/wpa/src/crypto/md4-internal.c5
-rw-r--r--contrib/wpa/src/crypto/md5-internal.c3
-rw-r--r--contrib/wpa/src/crypto/ms_funcs.c47
-rw-r--r--contrib/wpa/src/crypto/ms_funcs.h8
-rw-r--r--contrib/wpa/src/crypto/random.c77
-rw-r--r--contrib/wpa/src/crypto/sha1-internal.c12
-rw-r--r--contrib/wpa/src/crypto/sha1-tlsprf.c3
-rw-r--r--contrib/wpa/src/crypto/sha256-internal.c9
-rw-r--r--contrib/wpa/src/crypto/sha256-kdf.c20
-rw-r--r--contrib/wpa/src/crypto/sha256-prf.c26
-rw-r--r--contrib/wpa/src/crypto/sha256.h12
-rw-r--r--contrib/wpa/src/crypto/sha384-internal.c92
-rw-r--r--contrib/wpa/src/crypto/sha384-kdf.c87
-rw-r--r--contrib/wpa/src/crypto/sha384-prf.c28
-rw-r--r--contrib/wpa/src/crypto/sha384.c104
-rw-r--r--contrib/wpa/src/crypto/sha384.h15
-rw-r--r--contrib/wpa/src/crypto/sha384_i.h23
-rw-r--r--contrib/wpa/src/crypto/sha512-internal.c270
-rw-r--r--contrib/wpa/src/crypto/sha512-kdf.c87
-rw-r--r--contrib/wpa/src/crypto/sha512-prf.c108
-rw-r--r--contrib/wpa/src/crypto/sha512.c104
-rw-r--r--contrib/wpa/src/crypto/sha512.h27
-rw-r--r--contrib/wpa/src/crypto/sha512_i.h25
-rw-r--r--contrib/wpa/src/crypto/tls.h98
-rw-r--r--contrib/wpa/src/crypto/tls_gnutls.c307
-rw-r--r--contrib/wpa/src/crypto/tls_internal.c108
-rw-r--r--contrib/wpa/src/crypto/tls_none.c22
-rw-r--r--contrib/wpa/src/crypto/tls_openssl.c1743
-rw-r--r--contrib/wpa/src/crypto/tls_openssl.h19
-rw-r--r--contrib/wpa/src/crypto/tls_openssl_ocsp.c846
-rw-r--r--contrib/wpa/src/crypto/tls_wolfssl.c2201
56 files changed, 11307 insertions, 708 deletions
diff --git a/contrib/wpa/src/crypto/aes-cbc.c b/contrib/wpa/src/crypto/aes-cbc.c
index 2833cfcc..0835f2c 100644
--- a/contrib/wpa/src/crypto/aes-cbc.c
+++ b/contrib/wpa/src/crypto/aes-cbc.c
@@ -28,6 +28,9 @@ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
u8 *pos = data;
int i, j, blocks;
+ if (TEST_FAIL())
+ return -1;
+
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
@@ -61,6 +64,9 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
u8 *pos = data;
int i, j, blocks;
+ if (TEST_FAIL())
+ return -1;
+
ctx = aes_decrypt_init(key, 16);
if (ctx == NULL)
return -1;
diff --git a/contrib/wpa/src/crypto/aes-ctr.c b/contrib/wpa/src/crypto/aes-ctr.c
index d4d874d..e27f3bb 100644
--- a/contrib/wpa/src/crypto/aes-ctr.c
+++ b/contrib/wpa/src/crypto/aes-ctr.c
@@ -1,5 +1,5 @@
/*
- * AES-128 CTR
+ * AES-128/192/256 CTR
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -14,15 +14,16 @@
#include "aes_wrap.h"
/**
- * aes_128_ctr_encrypt - AES-128 CTR mode encryption
- * @key: Key for encryption (16 bytes)
+ * aes_ctr_encrypt - AES-128/192/256 CTR mode encryption
+ * @key: Key for encryption (key_len bytes)
+ * @key_len: Length of the key (16, 24, or 32 bytes)
* @nonce: Nonce for counter mode (16 bytes)
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* Returns: 0 on success, -1 on failure
*/
-int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
- u8 *data, size_t data_len)
+int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
+ u8 *data, size_t data_len)
{
void *ctx;
size_t j, len, left = data_len;
@@ -30,7 +31,7 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *pos = data;
u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
- ctx = aes_encrypt_init(key, 16);
+ ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
os_memcpy(counter, nonce, AES_BLOCK_SIZE);
@@ -53,3 +54,18 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
aes_encrypt_deinit(ctx);
return 0;
}
+
+
+/**
+ * aes_128_ctr_encrypt - AES-128 CTR mode encryption
+ * @key: Key for encryption (key_len bytes)
+ * @nonce: Nonce for counter mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+ u8 *data, size_t data_len)
+{
+ return aes_ctr_encrypt(key, 16, nonce, data, data_len);
+}
diff --git a/contrib/wpa/src/crypto/aes-internal-dec.c b/contrib/wpa/src/crypto/aes-internal-dec.c
index 720c703..7482295 100644
--- a/contrib/wpa/src/crypto/aes-internal-dec.c
+++ b/contrib/wpa/src/crypto/aes-internal-dec.c
@@ -147,10 +147,12 @@ d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
PUTU32(pt + 12, s3);
}
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
u32 *rk = ctx;
rijndaelDecrypt(ctx, rk[AES_PRIV_NR_POS], crypt, plain);
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/aes-internal-enc.c b/contrib/wpa/src/crypto/aes-internal-enc.c
index f3c61b8..baeffca 100644
--- a/contrib/wpa/src/crypto/aes-internal-enc.c
+++ b/contrib/wpa/src/crypto/aes-internal-enc.c
@@ -99,6 +99,10 @@ void * aes_encrypt_init(const u8 *key, size_t len)
{
u32 *rk;
int res;
+
+ if (TEST_FAIL())
+ return NULL;
+
rk = os_malloc(AES_PRIV_SIZE);
if (rk == NULL)
return NULL;
@@ -112,10 +116,11 @@ void * aes_encrypt_init(const u8 *key, size_t len)
}
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
u32 *rk = ctx;
rijndaelEncrypt(ctx, rk[AES_PRIV_NR_POS], plain, crypt);
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/aes-omac1.c b/contrib/wpa/src/crypto/aes-omac1.c
index 375db57..8642516 100644
--- a/contrib/wpa/src/crypto/aes-omac1.c
+++ b/contrib/wpa/src/crypto/aes-omac1.c
@@ -48,6 +48,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *pos, *end;
size_t i, e, left, total_len;
+ if (TEST_FAIL())
+ return -1;
+
ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
diff --git a/contrib/wpa/src/crypto/aes-siv.c b/contrib/wpa/src/crypto/aes-siv.c
index 5ac82c2..b682f3a 100644
--- a/contrib/wpa/src/crypto/aes-siv.c
+++ b/contrib/wpa/src/crypto/aes-siv.c
@@ -61,26 +61,33 @@ static void pad_block(u8 *pad, const u8 *addr, size_t len)
}
-static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
- size_t *len, u8 *mac)
+static int aes_s2v(const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
{
u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
u8 *buf = NULL;
int ret;
size_t i;
+ const u8 *data[1];
+ size_t data_len[1];
if (!num_elem) {
os_memcpy(tmp, zero, sizeof(zero));
tmp[AES_BLOCK_SIZE - 1] = 1;
- return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ data[0] = tmp;
+ data_len[0] = sizeof(tmp);
+ return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
}
- ret = omac1_aes_128(key, zero, sizeof(zero), tmp);
+ data[0] = zero;
+ data_len[0] = sizeof(zero);
+ ret = omac1_aes_vector(key, key_len, 1, data, data_len, tmp);
if (ret)
return ret;
for (i = 0; i < num_elem - 1; i++) {
- ret = omac1_aes_128(key, addr[i], len[i], tmp2);
+ ret = omac1_aes_vector(key, key_len, 1, &addr[i], &len[i],
+ tmp2);
if (ret)
return ret;
@@ -88,13 +95,13 @@ static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
xor(tmp, tmp2);
}
if (len[i] >= AES_BLOCK_SIZE) {
- buf = os_malloc(len[i]);
+ buf = os_memdup(addr[i], len[i]);
if (!buf)
return -ENOMEM;
- os_memcpy(buf, addr[i], len[i]);
xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
- ret = omac1_aes_128(key, buf, len[i], mac);
+ data[0] = buf;
+ ret = omac1_aes_vector(key, key_len, 1, data, &len[i], mac);
bin_clear_free(buf, len[i]);
return ret;
}
@@ -103,24 +110,32 @@ static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
pad_block(tmp2, addr[i], len[i]);
xor(tmp, tmp2);
- return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ data[0] = tmp;
+ data_len[0] = sizeof(tmp);
+ return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
}
-int aes_siv_encrypt(const u8 *key, const u8 *pw,
- size_t pwlen, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *out)
+int aes_siv_encrypt(const u8 *key, size_t key_len,
+ const u8 *pw, size_t pwlen,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out)
{
const u8 *_addr[6];
size_t _len[6];
- const u8 *k1 = key, *k2 = key + 16;
+ const u8 *k1, *k2;
u8 v[AES_BLOCK_SIZE];
size_t i;
u8 *iv, *crypt_pw;
- if (num_elem > ARRAY_SIZE(_addr) - 1)
+ if (num_elem > ARRAY_SIZE(_addr) - 1 ||
+ (key_len != 32 && key_len != 48 && key_len != 64))
return -1;
+ key_len /= 2;
+ k1 = key;
+ k2 = key + key_len;
+
for (i = 0; i < num_elem; i++) {
_addr[i] = addr[i];
_len[i] = len[i];
@@ -128,7 +143,7 @@ int aes_siv_encrypt(const u8 *key, const u8 *pw,
_addr[num_elem] = pw;
_len[num_elem] = pwlen;
- if (aes_s2v(k1, num_elem + 1, _addr, _len, v))
+ if (aes_s2v(k1, key_len, num_elem + 1, _addr, _len, v))
return -1;
iv = out;
@@ -140,26 +155,31 @@ int aes_siv_encrypt(const u8 *key, const u8 *pw,
/* zero out 63rd and 31st bits of ctr (from right) */
v[8] &= 0x7f;
v[12] &= 0x7f;
- return aes_128_ctr_encrypt(k2, v, crypt_pw, pwlen);
+ return aes_ctr_encrypt(k2, key_len, v, crypt_pw, pwlen);
}
-int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+int aes_siv_decrypt(const u8 *key, size_t key_len,
+ const u8 *iv_crypt, size_t iv_c_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *out)
{
const u8 *_addr[6];
size_t _len[6];
- const u8 *k1 = key, *k2 = key + 16;
+ const u8 *k1, *k2;
size_t crypt_len;
size_t i;
int ret;
u8 iv[AES_BLOCK_SIZE];
u8 check[AES_BLOCK_SIZE];
- if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1)
+ if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1 ||
+ (key_len != 32 && key_len != 48 && key_len != 64))
return -1;
crypt_len = iv_c_len - AES_BLOCK_SIZE;
+ key_len /= 2;
+ k1 = key;
+ k2 = key + key_len;
for (i = 0; i < num_elem; i++) {
_addr[i] = addr[i];
@@ -174,11 +194,11 @@ int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
iv[8] &= 0x7f;
iv[12] &= 0x7f;
- ret = aes_128_ctr_encrypt(k2, iv, out, crypt_len);
+ ret = aes_ctr_encrypt(k2, key_len, iv, out, crypt_len);
if (ret)
return ret;
- ret = aes_s2v(k1, num_elem + 1, _addr, _len, check);
+ ret = aes_s2v(k1, key_len, num_elem + 1, _addr, _len, check);
if (ret)
return ret;
if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
diff --git a/contrib/wpa/src/crypto/aes.h b/contrib/wpa/src/crypto/aes.h
index 2de59e0..8ab3de2 100644
--- a/contrib/wpa/src/crypto/aes.h
+++ b/contrib/wpa/src/crypto/aes.h
@@ -12,10 +12,10 @@
#define AES_BLOCK_SIZE 16
void * aes_encrypt_init(const u8 *key, size_t len);
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
void aes_encrypt_deinit(void *ctx);
void * aes_decrypt_init(const u8 *key, size_t len);
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
void aes_decrypt_deinit(void *ctx);
#endif /* AES_H */
diff --git a/contrib/wpa/src/crypto/aes_siv.h b/contrib/wpa/src/crypto/aes_siv.h
index 463cf65..fb05d80 100644
--- a/contrib/wpa/src/crypto/aes_siv.h
+++ b/contrib/wpa/src/crypto/aes_siv.h
@@ -9,10 +9,12 @@
#ifndef AES_SIV_H
#define AES_SIV_H
-int aes_siv_encrypt(const u8 *key, const u8 *pw,
- size_t pwlen, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *out);
-int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+int aes_siv_encrypt(const u8 *key, size_t key_len,
+ const u8 *pw, size_t pwlen,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out);
+int aes_siv_decrypt(const u8 *key, size_t key_len,
+ const u8 *iv_crypt, size_t iv_c_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *out);
diff --git a/contrib/wpa/src/crypto/aes_wrap.h b/contrib/wpa/src/crypto/aes_wrap.h
index 4a14209..b70b1d2 100644
--- a/contrib/wpa/src/crypto/aes_wrap.h
+++ b/contrib/wpa/src/crypto/aes_wrap.h
@@ -3,7 +3,7 @@
*
* - AES Key Wrap Algorithm (RFC3394)
* - One-Key CBC MAC (OMAC1) hash with AES-128 and AES-256
- * - AES-128 CTR mode encryption
+ * - AES-128/192/256 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
* - AES-GCM
@@ -33,6 +33,8 @@ int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
int __must_check omac1_aes_256(const u8 *key, const u8 *data, size_t data_len,
u8 *mac);
int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
+int __must_check aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
+ u8 *data, size_t data_len);
int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
int __must_check aes_128_eax_encrypt(const u8 *key,
diff --git a/contrib/wpa/src/crypto/crypto.h b/contrib/wpa/src/crypto/crypto.h
index 534c4bd..12109ce 100644
--- a/contrib/wpa/src/crypto/crypto.h
+++ b/contrib/wpa/src/crypto/crypto.h
@@ -1,6 +1,6 @@
/*
* Wrapper functions for crypto libraries
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -80,12 +80,35 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
/**
+ * sha384_vector - SHA384 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac);
+
+/**
+ * sha512_vector - SHA512 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac);
+
+/**
* des_encrypt - Encrypt one block with DES
* @clear: 8 octets (in)
* @key: 7 octets (in) (no parity bits included)
* @cypher: 8 octets (out)
+ * Returns: 0 on success, -1 on failure
*/
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
/**
* aes_encrypt_init - Initialize AES for encryption
@@ -100,8 +123,9 @@ void * aes_encrypt_init(const u8 *key, size_t len);
* @ctx: Context pointer from aes_encrypt_init()
* @plain: Plaintext data to be encrypted (16 bytes)
* @crypt: Buffer for the encrypted data (16 bytes)
+ * Returns: 0 on success, -1 on failure
*/
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
/**
* aes_encrypt_deinit - Deinitialize AES encryption
@@ -122,8 +146,9 @@ void * aes_decrypt_init(const u8 *key, size_t len);
* @ctx: Context pointer from aes_encrypt_init()
* @crypt: Encrypted data (16 bytes)
* @plain: Buffer for the decrypted data (16 bytes)
+ * Returns: 0 on success, -1 on failure
*/
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
/**
* aes_decrypt_deinit - Deinitialize AES decryption
@@ -135,7 +160,8 @@ void aes_decrypt_deinit(void *ctx);
enum crypto_hash_alg {
CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
- CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
+ CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256,
+ CRYPTO_HASH_ALG_SHA384, CRYPTO_HASH_ALG_SHA512
};
struct crypto_hash;
@@ -391,6 +417,14 @@ int __must_check crypto_public_key_decrypt_pkcs1(
struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len);
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey);
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len);
+
/**
* crypto_global_init - Initialize crypto wrapper
*
@@ -503,6 +537,14 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
u8 *buf, size_t buflen, size_t padlen);
/**
+ * crypto_bignum_rand - Create a random number in range of modulus
+ * @r: Bignum; set to a random value
+ * @m: Bignum; modulus
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m);
+
+/**
* crypto_bignum_add - c = a + b
* @a: Bignum
* @b: Bignum
@@ -584,6 +626,16 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
struct crypto_bignum *d);
/**
+ * crypto_bignum_rshift - r = a >> n
+ * @a: Bignum
+ * @n: Number of bits
+ * @r: Bignum; used to store the result of a >> n
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r);
+
+/**
* crypto_bignum_cmp - Compare two bignums
* @a: Bignum
* @b: Bignum
@@ -614,6 +666,13 @@ int crypto_bignum_is_zero(const struct crypto_bignum *a);
int crypto_bignum_is_one(const struct crypto_bignum *a);
/**
+ * crypto_bignum_is_odd - Is the given bignum odd
+ * @a: Bignum
+ * Returns: 1 if @a is odd or 0 if not
+ */
+int crypto_bignum_is_odd(const struct crypto_bignum *a);
+
+/**
* crypto_bignum_legendre - Compute the Legendre symbol (a/p)
* @a: Bignum
* @p: Bignum
@@ -659,6 +718,13 @@ size_t crypto_ec_prime_len(struct crypto_ec *e);
size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
/**
+ * crypto_ec_order_len - Get length of the order in octets
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the order defining the group
+ */
+size_t crypto_ec_order_len(struct crypto_ec *e);
+
+/**
* crypto_ec_get_prime - Get prime defining an EC group
* @e: EC context from crypto_ec_init()
* Returns: Prime (bignum) defining the group
@@ -695,6 +761,16 @@ struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e);
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
/**
+ * crypto_ec_point_x - Copies the x-ordinate point into big number
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point data
+ * @x: Big number to set to the copy of x-ordinate
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+ struct crypto_bignum *x);
+
+/**
* crypto_ec_point_to_bin - Write EC point value as binary data
* @e: EC context from crypto_ec_init()
* @p: EC point data from crypto_ec_point_init()
@@ -723,7 +799,7 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
const u8 *val);
/**
- * crypto_bignum_add - c = a + b
+ * crypto_ec_point_add - c = a + b
* @e: EC context from crypto_ec_init()
* @a: Bignum
* @b: Bignum
@@ -735,7 +811,7 @@ int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
struct crypto_ec_point *c);
/**
- * crypto_bignum_mul - res = b * p
+ * crypto_ec_point_mul - res = b * p
* @e: EC context from crypto_ec_init()
* @p: EC point
* @b: Bignum
@@ -806,4 +882,12 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
const struct crypto_ec_point *a,
const struct crypto_ec_point *b);
+struct crypto_ecdh;
+
+struct crypto_ecdh * crypto_ecdh_init(int group);
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y);
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+ const u8 *key, size_t len);
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
+
#endif /* CRYPTO_H */
diff --git a/contrib/wpa/src/crypto/crypto_gnutls.c b/contrib/wpa/src/crypto/crypto_gnutls.c
index 0dfd54d..4ef1146 100644
--- a/contrib/wpa/src/crypto/crypto_gnutls.c
+++ b/contrib/wpa/src/crypto/crypto_gnutls.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for libgcrypt
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,27 +10,42 @@
#include <gcrypt.h>
#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "sha512.h"
#include "crypto.h"
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+static int gnutls_digest_vector(int algo, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
- if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
+ if (TEST_FAIL())
+ return -1;
+
+ if (gcry_md_open(&hd, algo, 0) != GPG_ERR_NO_ERROR)
return -1;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
- p = gcry_md_read(hd, GCRY_MD_MD4);
+ p = gcry_md_read(hd, algo);
if (p)
- memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
+ memcpy(mac, p, gcry_md_get_algo_dlen(algo));
gcry_md_close(hd);
return 0;
}
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_MD4, num_elem, addr, len, mac);
+}
+
+
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
gcry_cipher_hd_t hd;
u8 pkey[8], next, tmp;
@@ -49,49 +64,161 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
gcry_err_code(gcry_cipher_setkey(hd, pkey, 8));
gcry_cipher_encrypt(hd, cypher, 8, clear, 8);
gcry_cipher_close(hd);
+ return 0;
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
- gcry_md_hd_t hd;
- unsigned char *p;
- size_t i;
-
- if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
- return -1;
- for (i = 0; i < num_elem; i++)
- gcry_md_write(hd, addr[i], len[i]);
- p = gcry_md_read(hd, GCRY_MD_MD5);
- if (p)
- memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
- gcry_md_close(hd);
- return 0;
+ return gnutls_digest_vector(GCRY_MD_MD5, num_elem, addr, len, mac);
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
+ return gnutls_digest_vector(GCRY_MD_SHA1, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_SHA256, num_elem, addr, len, mac);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_SHA384, num_elem, addr, len, mac);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_SHA512, num_elem, addr, len, mac);
+}
+
+
+static int gnutls_hmac_vector(int algo, const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac)
+{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
- if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
+ if (TEST_FAIL())
+ return -1;
+
+ if (gcry_md_open(&hd, algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR)
+ return -1;
+ if (gcry_md_setkey(hd, key, key_len) != GPG_ERR_NO_ERROR) {
+ gcry_md_close(hd);
return -1;
+ }
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
- p = gcry_md_read(hd, GCRY_MD_SHA1);
+ p = gcry_md_read(hd, algo);
if (p)
- memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
+ memcpy(mac, p, gcry_md_get_algo_dlen(algo));
gcry_md_close(hd);
return 0;
}
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_MD5, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA1, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA256, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA384, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA512, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
void * aes_encrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
+ if (TEST_FAIL())
+ return NULL;
+
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR) {
printf("cipher open failed\n");
@@ -107,10 +234,11 @@ void * aes_encrypt_init(const u8 *key, size_t len)
}
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_encrypt(hd, crypt, 16, plain, 16);
+ return 0;
}
@@ -125,6 +253,9 @@ void * aes_decrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
+ if (TEST_FAIL())
+ return NULL;
+
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR)
return NULL;
@@ -137,10 +268,11 @@ void * aes_decrypt_init(const u8 *key, size_t len)
}
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_decrypt(hd, plain, 16, crypt, 16);
+ return 0;
}
@@ -151,6 +283,81 @@ void aes_decrypt_deinit(void *ctx)
}
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ gcry_mpi_t pub = NULL;
+ int res = -1;
+
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+ os_memcmp(pubkey, prime, prime_len) >= 0))
+ return -1;
+
+ if (gcry_mpi_scan(&pub, GCRYMPI_FMT_USG, pubkey, pubkey_len, NULL) !=
+ GPG_ERR_NO_ERROR ||
+ gcry_mpi_cmp_ui(pub, 1) <= 0)
+ goto fail;
+
+ if (order) {
+ gcry_mpi_t p = NULL, q = NULL, tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ tmp = gcry_mpi_new(prime_len * 8);
+ failed = !tmp ||
+ gcry_mpi_scan(&p, GCRYMPI_FMT_USG, prime, prime_len,
+ NULL) != GPG_ERR_NO_ERROR ||
+ gcry_mpi_scan(&q, GCRYMPI_FMT_USG, order, order_len,
+ NULL) != GPG_ERR_NO_ERROR;
+ if (!failed) {
+ gcry_mpi_powm(tmp, pub, q, p);
+ failed = gcry_mpi_cmp_ui(tmp, 1) != 0;
+ }
+ gcry_mpi_release(p);
+ gcry_mpi_release(q);
+ gcry_mpi_release(tmp);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ gcry_mpi_release(pub);
+ return res;
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
diff --git a/contrib/wpa/src/crypto/crypto_internal-modexp.c b/contrib/wpa/src/crypto/crypto_internal-modexp.c
index 9dcabb9..6819f1a 100644
--- a/contrib/wpa/src/crypto/crypto_internal-modexp.c
+++ b/contrib/wpa/src/crypto/crypto_internal-modexp.c
@@ -13,6 +13,79 @@
#include "crypto.h"
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ struct bignum *pub;
+ int res = -1;
+
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+ os_memcmp(pubkey, prime, prime_len) >= 0))
+ return -1;
+
+ pub = bignum_init();
+ if (!pub || bignum_set_unsigned_bin(pub, pubkey, pubkey_len) < 0 ||
+ bignum_cmp_d(pub, 1) <= 0)
+ goto fail;
+
+ if (order) {
+ struct bignum *p, *q, *tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ p = bignum_init();
+ q = bignum_init();
+ tmp = bignum_init();
+ failed = !p || !q || !tmp ||
+ bignum_set_unsigned_bin(p, prime, prime_len) < 0 ||
+ bignum_set_unsigned_bin(q, order, order_len) < 0 ||
+ bignum_exptmod(pub, q, p, tmp) < 0 ||
+ bignum_cmp_d(tmp, 1) != 0;
+ bignum_deinit(p);
+ bignum_deinit(q);
+ bignum_deinit(tmp);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ bignum_deinit(pub);
+ return res;
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
diff --git a/contrib/wpa/src/crypto/crypto_internal.c b/contrib/wpa/src/crypto/crypto_internal.c
index f3602da..aad40af 100644
--- a/contrib/wpa/src/crypto/crypto_internal.c
+++ b/contrib/wpa/src/crypto/crypto_internal.c
@@ -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"
@@ -22,6 +24,12 @@ struct crypto_hash {
#ifdef CONFIG_SHA256
struct sha256_state sha256;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ struct sha384_state sha384;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ struct sha512_state sha512;
+#endif /* CONFIG_INTERNAL_SHA512 */
} u;
u8 key[64];
size_t key_len;
@@ -54,6 +62,16 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
sha256_init(&ctx->u.sha256);
break;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ case CRYPTO_HASH_ALG_SHA384:
+ sha384_init(&ctx->u.sha384);
+ break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ case CRYPTO_HASH_ALG_SHA512:
+ sha512_init(&ctx->u.sha512);
+ break;
+#endif /* CONFIG_INTERNAL_SHA512 */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (key_len > sizeof(k_pad)) {
MD5Init(&ctx->u.md5);
@@ -142,6 +160,16 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
sha256_process(&ctx->u.sha256, data, len);
break;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ case CRYPTO_HASH_ALG_SHA384:
+ sha384_process(&ctx->u.sha384, data, len);
+ break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ case CRYPTO_HASH_ALG_SHA512:
+ sha512_process(&ctx->u.sha512, data, len);
+ break;
+#endif /* CONFIG_INTERNAL_SHA512 */
default:
break;
}
@@ -191,6 +219,28 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
sha256_done(&ctx->u.sha256, mac);
break;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ case CRYPTO_HASH_ALG_SHA384:
+ if (*len < 48) {
+ *len = 48;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 48;
+ sha384_done(&ctx->u.sha384, mac);
+ break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ case CRYPTO_HASH_ALG_SHA512:
+ if (*len < 64) {
+ *len = 64;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 64;
+ sha512_done(&ctx->u.sha512, mac);
+ break;
+#endif /* CONFIG_INTERNAL_SHA512 */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (*len < 16) {
*len = 16;
@@ -260,6 +310,9 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
os_free(ctx);
+ if (TEST_FAIL())
+ return -1;
+
return 0;
}
diff --git a/contrib/wpa/src/crypto/crypto_libtomcrypt.c b/contrib/wpa/src/crypto/crypto_libtomcrypt.c
index a55edd1..ed30efa 100644
--- a/contrib/wpa/src/crypto/crypto_libtomcrypt.c
+++ b/contrib/wpa/src/crypto/crypto_libtomcrypt.c
@@ -35,7 +35,7 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
}
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
@@ -53,6 +53,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
des_setup(pkey, 8, 0, &skey);
des_ecb_encrypt(clear, cypher, &skey);
des_done(&skey);
+ return 0;
}
@@ -96,10 +97,10 @@ void * aes_encrypt_init(const u8 *key, size_t len)
}
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
symmetric_key *skey = ctx;
- aes_ecb_encrypt(plain, crypt, skey);
+ return aes_ecb_encrypt(plain, crypt, skey) == CRYPT_OK ? 0 : -1;
}
@@ -125,10 +126,10 @@ void * aes_decrypt_init(const u8 *key, size_t len)
}
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
symmetric_key *skey = ctx;
- aes_ecb_encrypt(plain, (u8 *) crypt, skey);
+ return aes_ecb_encrypt(plain, (u8 *) crypt, skey) == CRYPT_OK ? 0 : -1;
}
@@ -277,6 +278,9 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
os_free(ctx);
+ if (TEST_FAIL())
+ return -1;
+
return ret;
}
@@ -297,7 +301,7 @@ struct crypto_cipher {
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
-{
+{
struct crypto_cipher *ctx;
int idx, res, rc4 = 0;
@@ -693,6 +697,44 @@ void crypto_global_deinit(void)
#ifdef CONFIG_MODEXP
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ /* TODO: check pubkey */
+ return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
diff --git a/contrib/wpa/src/crypto/crypto_linux.c b/contrib/wpa/src/crypto/crypto_linux.c
new file mode 100644
index 0000000..1724456
--- /dev/null
+++ b/contrib/wpa/src/crypto/crypto_linux.c
@@ -0,0 +1,1009 @@
+/*
+ * Crypto wrapper for Linux kernel AF_ALG
+ * Copyright (c) 2017, 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 <linux/if_alg.h>
+
+#include "common.h"
+#include "crypto.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "aes.h"
+
+
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif /* SOL_ALG */
+
+
+static int linux_af_alg_socket(const char *type, const char *name)
+{
+ struct sockaddr_alg sa;
+ int s;
+
+ if (TEST_FAIL())
+ return -1;
+
+ s = socket(AF_ALG, SOCK_SEQPACKET, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "%s: Failed to open AF_ALG socket: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&sa, 0, sizeof(sa));
+ sa.salg_family = AF_ALG;
+ os_strlcpy((char *) sa.salg_type, type, sizeof(sa.salg_type));
+ os_strlcpy((char *) sa.salg_name, name, sizeof(sa.salg_type));
+ if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: Failed to bind AF_ALG socket(%s,%s): %s",
+ __func__, type, name, strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+
+static int linux_af_alg_hash_vector(const char *alg, const u8 *key,
+ size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len,
+ u8 *mac, size_t mac_len)
+{
+ int s, t;
+ size_t i;
+ ssize_t res;
+ int ret = -1;
+
+ s = linux_af_alg_socket("hash", alg);
+ if (s < 0)
+ return -1;
+
+ if (key && setsockopt(s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
+ wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s",
+ __func__, strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ t = accept(s, NULL, NULL);
+ if (t < 0) {
+ wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ for (i = 0; i < num_elem; i++) {
+ res = send(t, addr[i], len[i], i + 1 < num_elem ? MSG_MORE : 0);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: send on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if ((size_t) res < len[i]) {
+ wpa_printf(MSG_ERROR,
+ "%s: send on AF_ALG socket did not accept full buffer (%d/%d)",
+ __func__, (int) res, (int) len[i]);
+ goto fail;
+ }
+ }
+
+ res = recv(t, mac, mac_len, 0);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: recv on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if ((size_t) res < mac_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: recv on AF_ALG socket did not return full buffer (%d/%d)",
+ __func__, (int) res, (int) mac_len);
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ close(t);
+ close(s);
+
+ return ret;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("md4", NULL, 0, num_elem, addr, len,
+ mac, 16);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("md5", NULL, 0, num_elem, addr, len,
+ mac, MD5_MAC_LEN);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return linux_af_alg_hash_vector("sha1", NULL, 0, num_elem, addr, len,
+ mac, SHA1_MAC_LEN);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return linux_af_alg_hash_vector("sha256", NULL, 0, num_elem, addr, len,
+ mac, SHA256_MAC_LEN);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return linux_af_alg_hash_vector("sha384", NULL, 0, num_elem, addr, len,
+ mac, SHA384_MAC_LEN);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return linux_af_alg_hash_vector("sha512", NULL, 0, num_elem, addr, len,
+ mac, 64);
+}
+
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("hmac(md5)", key, key_len, num_elem,
+ addr, len, mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("hmac(sha1)", key, key_len, num_elem,
+ addr, len, mac, SHA1_MAC_LEN);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("hmac(sha256)", key, key_len, num_elem,
+ addr, len, mac, SHA256_MAC_LEN);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("hmac(sha384)", key, key_len, num_elem,
+ addr, len, mac, SHA384_MAC_LEN);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+struct crypto_hash {
+ int s;
+ int t;
+ size_t mac_len;
+ int failed;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ctx;
+ const char *name;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ switch (alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ name = "md5";
+ ctx->mac_len = MD5_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ name = "sha1";
+ ctx->mac_len = SHA1_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ name = "hmac(md5)";
+ ctx->mac_len = MD5_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ name = "hmac(sha1)";
+ ctx->mac_len = SHA1_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_SHA256:
+ name = "sha256";
+ ctx->mac_len = SHA256_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ name = "hmac(sha256)";
+ ctx->mac_len = SHA256_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_SHA384:
+ name = "sha384";
+ ctx->mac_len = SHA384_MAC_LEN;
+ break;
+ case CRYPTO_HASH_ALG_SHA512:
+ name = "sha512";
+ ctx->mac_len = 64;
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ ctx->s = linux_af_alg_socket("hash", name);
+ if (ctx->s < 0) {
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (key && key_len &&
+ setsockopt(ctx->s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
+ wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s",
+ __func__, strerror(errno));
+ close(ctx->s);
+ os_free(ctx);
+ return NULL;
+ }
+
+ ctx->t = accept(ctx->s, NULL, NULL);
+ if (ctx->t < 0) {
+ wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ close(ctx->s);
+ os_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ ssize_t res;
+
+ if (!ctx)
+ return;
+
+ res = send(ctx->t, data, len, MSG_MORE);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: send on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ ctx->failed = 1;
+ return;
+ }
+ if ((size_t) res < len) {
+ wpa_printf(MSG_ERROR,
+ "%s: send on AF_ALG socket did not accept full buffer (%d/%d)",
+ __func__, (int) res, (int) len);
+ ctx->failed = 1;
+ return;
+ }
+}
+
+
+static void crypto_hash_deinit(struct crypto_hash *ctx)
+{
+ close(ctx->s);
+ close(ctx->t);
+ os_free(ctx);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ ssize_t res;
+
+ if (!ctx)
+ return -2;
+
+ if (!mac || !len) {
+ crypto_hash_deinit(ctx);
+ return 0;
+ }
+
+ if (ctx->failed) {
+ crypto_hash_deinit(ctx);
+ return -2;
+ }
+
+ if (*len < ctx->mac_len) {
+ crypto_hash_deinit(ctx);
+ *len = ctx->mac_len;
+ return -1;
+ }
+ *len = ctx->mac_len;
+
+ res = recv(ctx->t, mac, ctx->mac_len, 0);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: recv on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ crypto_hash_deinit(ctx);
+ return -2;
+ }
+ if ((size_t) res < ctx->mac_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: recv on AF_ALG socket did not return full buffer (%d/%d)",
+ __func__, (int) res, (int) ctx->mac_len);
+ crypto_hash_deinit(ctx);
+ return -2;
+ }
+
+ crypto_hash_deinit(ctx);
+
+ if (TEST_FAIL())
+ return -1;
+ return 0;
+}
+
+
+struct linux_af_alg_skcipher {
+ int s;
+ int t;
+};
+
+
+static void linux_af_alg_skcipher_deinit(struct linux_af_alg_skcipher *skcipher)
+{
+ if (!skcipher)
+ return;
+ if (skcipher->s >= 0)
+ close(skcipher->s);
+ if (skcipher->t >= 0)
+ close(skcipher->t);
+ os_free(skcipher);
+}
+
+
+static struct linux_af_alg_skcipher *
+linux_af_alg_skcipher(const char *alg, const u8 *key, size_t key_len)
+{
+ struct linux_af_alg_skcipher *skcipher;
+
+ skcipher = os_zalloc(sizeof(*skcipher));
+ if (!skcipher)
+ goto fail;
+ skcipher->t = -1;
+
+ skcipher->s = linux_af_alg_socket("skcipher", alg);
+ if (skcipher->s < 0)
+ goto fail;
+
+ if (setsockopt(skcipher->s, SOL_ALG, ALG_SET_KEY, key, key_len) < 0) {
+ wpa_printf(MSG_ERROR, "%s: setsockopt(ALG_SET_KEY) failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+
+ skcipher->t = accept(skcipher->s, NULL, NULL);
+ if (skcipher->t < 0) {
+ wpa_printf(MSG_ERROR, "%s: accept on AF_ALG socket failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+
+ return skcipher;
+fail:
+ linux_af_alg_skcipher_deinit(skcipher);
+ return NULL;
+}
+
+
+static int linux_af_alg_skcipher_oper(struct linux_af_alg_skcipher *skcipher,
+ int enc, const u8 *in, u8 *out)
+{
+ char buf[CMSG_SPACE(sizeof(u32))];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+
+ io[0].iov_base = (void *) in;
+ io[0].iov_len = AES_BLOCK_SIZE;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = enc ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ ret = read(skcipher->t, out, AES_BLOCK_SIZE);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: read failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ if (ret < AES_BLOCK_SIZE) {
+ wpa_printf(MSG_ERROR,
+ "%s: read did not return full data (%d/%d)",
+ __func__, (int) ret, AES_BLOCK_SIZE);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ return linux_af_alg_skcipher("ecb(aes)", key, len);
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ struct linux_af_alg_skcipher *skcipher = ctx;
+
+ return linux_af_alg_skcipher_oper(skcipher, 1, plain, crypt);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ linux_af_alg_skcipher_deinit(ctx);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ return linux_af_alg_skcipher("ecb(aes)", key, len);
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ struct linux_af_alg_skcipher *skcipher = ctx;
+
+ return linux_af_alg_skcipher_oper(skcipher, 0, crypt, plain);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ linux_af_alg_skcipher_deinit(ctx);
+}
+
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+ u8 *data, size_t data_len)
+{
+ struct linux_af_alg_skcipher *skcipher;
+ u8 *skip_buf;
+ char buf[CMSG_SPACE(sizeof(u32))];
+ struct iovec io[2];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+
+ skip_buf = os_zalloc(skip + 1);
+ if (!skip_buf)
+ return -1;
+ skcipher = linux_af_alg_skcipher("ecb(arc4)", key, keylen);
+ if (!skcipher) {
+ os_free(skip_buf);
+ return -1;
+ }
+
+ io[0].iov_base = skip_buf;
+ io[0].iov_len = skip;
+ io[1].iov_base = data;
+ io[1].iov_len = data_len;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = ALG_OP_ENCRYPT;
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ os_free(skip_buf);
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+ os_free(skip_buf);
+
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ ret = recvmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: recvmsg failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+ linux_af_alg_skcipher_deinit(skcipher);
+
+ if ((size_t) ret < skip + data_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: recvmsg did not return full data (%d/%d)",
+ __func__, (int) ret, (int) (skip + data_len));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ u8 pkey[8], next, tmp;
+ int i;
+ struct linux_af_alg_skcipher *skcipher;
+ char buf[CMSG_SPACE(sizeof(u32))];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+ int res = -1;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ skcipher = linux_af_alg_skcipher("ecb(des)", pkey, sizeof(pkey));
+ if (!skcipher)
+ goto fail;
+
+ io[0].iov_base = (void *) clear;
+ io[0].iov_len = 8;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = ALG_OP_ENCRYPT;
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+
+ ret = read(skcipher->t, cypher, 8);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: read failed: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if (ret < 8) {
+ wpa_printf(MSG_ERROR,
+ "%s: read did not return full data (%d/8)",
+ __func__, (int) ret);
+ goto fail;
+ }
+
+ res = 0;
+fail:
+ linux_af_alg_skcipher_deinit(skcipher);
+ return res;
+}
+
+
+static int aes_128_cbc_oper(const u8 *key, int enc, const u8 *iv,
+ u8 *data, size_t data_len)
+{
+ struct linux_af_alg_skcipher *skcipher;
+ char buf[100];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+ struct af_alg_iv *alg_iv;
+ size_t iv_len = AES_BLOCK_SIZE;
+
+ skcipher = linux_af_alg_skcipher("cbc(aes)", key, 16);
+ if (!skcipher)
+ return -1;
+
+ io[0].iov_base = (void *) data;
+ io[0].iov_len = data_len;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32)) +
+ CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = enc ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
+
+ hdr = CMSG_NXTHDR(&msg, hdr);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_IV;
+ hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
+ alg_iv->ivlen = iv_len;
+ os_memcpy(alg_iv->iv, iv, iv_len);
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+
+ ret = recvmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: recvmsg failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+ if ((size_t) ret < data_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: recvmsg not return full data (%d/%d)",
+ __func__, (int) ret, (int) data_len);
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+
+ linux_af_alg_skcipher_deinit(skcipher);
+ return 0;
+}
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ return aes_128_cbc_oper(key, 1, iv, data, data_len);
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ return aes_128_cbc_oper(key, 0, iv, data, data_len);
+}
+
+
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return linux_af_alg_hash_vector("cmac(aes)", key, key_len, num_elem,
+ addr, len, mac, AES_BLOCK_SIZE);
+}
+
+
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+ u8 *plain)
+{
+ struct linux_af_alg_skcipher *skcipher;
+ char buf[100];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+ struct af_alg_iv *alg_iv;
+ size_t iv_len = 8;
+
+ skcipher = linux_af_alg_skcipher("kw(aes)", kek, kek_len);
+ if (!skcipher)
+ return -1;
+
+ io[0].iov_base = (void *) (cipher + iv_len);
+ io[0].iov_len = n * 8;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32)) +
+ CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = ALG_OP_DECRYPT;
+
+ hdr = CMSG_NXTHDR(&msg, hdr);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_IV;
+ hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
+ alg_iv->ivlen = iv_len;
+ os_memcpy(alg_iv->iv, cipher, iv_len);
+
+ ret = sendmsg(skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ ret = read(skcipher->t, plain, n * 8);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: read failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+ if (ret < n * 8) {
+ wpa_printf(MSG_ERROR,
+ "%s: read not return full data (%d/%d)",
+ __func__, (int) ret, n * 8);
+ linux_af_alg_skcipher_deinit(skcipher);
+ return -1;
+ }
+
+ linux_af_alg_skcipher_deinit(skcipher);
+ return 0;
+}
+
+
+struct crypto_cipher {
+ struct linux_af_alg_skcipher *skcipher;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+ const char *name;
+ struct af_alg_iv *alg_iv;
+ size_t iv_len = 0;
+ char buf[100];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ name = "ecb(arc4)";
+ break;
+ case CRYPTO_CIPHER_ALG_AES:
+ name = "cbc(aes)";
+ iv_len = AES_BLOCK_SIZE;
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ name = "cbc(des3_ede)";
+ iv_len = 8;
+ break;
+ case CRYPTO_CIPHER_ALG_DES:
+ name = "cbc(des)";
+ iv_len = 8;
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ ctx->skcipher = linux_af_alg_skcipher(name, key, key_len);
+ if (!ctx->skcipher) {
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (iv && iv_len) {
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_IV;
+ hdr->cmsg_len = CMSG_SPACE(sizeof(*alg_iv) + iv_len);
+ alg_iv = (struct af_alg_iv *) CMSG_DATA(hdr);
+ alg_iv->ivlen = iv_len;
+ os_memcpy(alg_iv->iv, iv, iv_len);
+
+ ret = sendmsg(ctx->skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ linux_af_alg_skcipher_deinit(ctx->skcipher);
+ os_free(ctx);
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+
+static int crypto_cipher_oper(struct crypto_cipher *ctx, u32 type, const u8 *in,
+ u8 *out, size_t len)
+{
+ char buf[CMSG_SPACE(sizeof(u32))];
+ struct iovec io[1];
+ struct msghdr msg;
+ struct cmsghdr *hdr;
+ ssize_t ret;
+ u32 *op;
+
+ io[0].iov_base = (void *) in;
+ io[0].iov_len = len;
+ os_memset(&msg, 0, sizeof(msg));
+ os_memset(buf, 0, sizeof(buf));
+ msg.msg_control = buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(u32));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 1;
+ hdr = CMSG_FIRSTHDR(&msg);
+ hdr->cmsg_level = SOL_ALG;
+ hdr->cmsg_type = ALG_SET_OP;
+ hdr->cmsg_len = CMSG_LEN(sizeof(u32));
+ op = (u32 *) CMSG_DATA(hdr);
+ *op = type;
+
+ ret = sendmsg(ctx->skcipher->t, &msg, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: sendmsg failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ ret = read(ctx->skcipher->t, out, len);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: read failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ if (ret < (ssize_t) len) {
+ wpa_printf(MSG_ERROR,
+ "%s: read did not return full data (%d/%d)",
+ __func__, (int) ret, (int) len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ return crypto_cipher_oper(ctx, ALG_OP_ENCRYPT, plain, crypt, len);
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ return crypto_cipher_oper(ctx, ALG_OP_DECRYPT, crypt, plain, len);
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ if (ctx) {
+ linux_af_alg_skcipher_deinit(ctx->skcipher);
+ os_free(ctx);
+ }
+}
+
+
+int crypto_global_init(void)
+{
+ return 0;
+}
+
+
+void crypto_global_deinit(void)
+{
+}
diff --git a/contrib/wpa/src/crypto/crypto_module_tests.c b/contrib/wpa/src/crypto/crypto_module_tests.c
index 581005d..1cc73d8 100644
--- a/contrib/wpa/src/crypto/crypto_module_tests.c
+++ b/contrib/wpa/src/crypto/crypto_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
#include "crypto/aes_siv.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes.h"
@@ -16,6 +17,7 @@
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
static int test_siv(void)
@@ -91,7 +93,7 @@ static int test_siv(void)
addr[0] = ad;
len[0] = sizeof(ad);
- if (aes_siv_encrypt(key, plaintext, sizeof(plaintext),
+ if (aes_siv_encrypt(key, sizeof(key), plaintext, sizeof(plaintext),
1, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
return 1;
@@ -102,7 +104,8 @@ static int test_siv(void)
return 1;
}
- if (aes_siv_decrypt(key, iv_c, sizeof(iv_c), 1, addr, len, out)) {
+ if (aes_siv_decrypt(key, sizeof(key), iv_c, sizeof(iv_c),
+ 1, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
return 1;
}
@@ -120,7 +123,8 @@ static int test_siv(void)
addr[2] = nonce_2;
len[2] = sizeof(nonce_2);
- if (aes_siv_encrypt(key_2, plaintext_2, sizeof(plaintext_2),
+ if (aes_siv_encrypt(key_2, sizeof(key_2),
+ plaintext_2, sizeof(plaintext_2),
3, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
return 1;
@@ -131,7 +135,8 @@ static int test_siv(void)
return 1;
}
- if (aes_siv_decrypt(key_2, iv_c_2, sizeof(iv_c_2), 3, addr, len, out)) {
+ if (aes_siv_decrypt(key_2, sizeof(key_2), iv_c_2, sizeof(iv_c_2),
+ 3, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
return 1;
}
@@ -1266,7 +1271,7 @@ static int test_sha1(void)
}
-const struct {
+static const struct {
char *data;
u8 hash[32];
} tests[] = {
@@ -1290,14 +1295,15 @@ const struct {
}
};
-const struct hmac_test {
- u8 key[80];
+static const struct hmac_test {
+ u8 key[150];
size_t key_len;
- u8 data[128];
+ u8 data[160];
size_t data_len;
- u8 hash[32];
+ u8 hash[32]; /* HMAC-SHA-256 */
+ u8 hash384[48]; /* HMAC-SHA-384 */
} hmac_tests[] = {
- /* draft-ietf-ipsec-ciph-sha-256-01.txt */
+ /* draft-ietf-ipsec-ciph-sha-256-01.txt; RFC 4231 */
{
{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
@@ -1312,7 +1318,8 @@ const struct hmac_test {
0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
- }
+ },
+ { }
},
{
{
@@ -1329,7 +1336,8 @@ const struct hmac_test {
0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
- }
+ },
+ { }
},
{
{
@@ -1347,7 +1355,8 @@ const struct hmac_test {
0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
- }
+ },
+ { }
},
{
{
@@ -1364,9 +1373,34 @@ const struct hmac_test {
0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 1 */
+ {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+ },
+ 20,
+ "Hi There",
+ 8,
+ {
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
+ 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
+ 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
+ 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7
+ },
+ {
+ 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62,
+ 0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f,
+ 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+ 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c,
+ 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f,
+ 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6
}
},
- {
+ { /* RFC 4231 - Test Case 2 */
"Jefe",
4,
"what do ya want for nothing?",
@@ -1376,6 +1410,14 @@ const struct hmac_test {
0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+ },
+ {
+ 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31,
+ 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b,
+ 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+ 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e,
+ 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7,
+ 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49
}
},
{
@@ -1401,6 +1443,39 @@ const struct hmac_test {
0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 3 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 20,
+ {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+ },
+ 50,
+ {
+ 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
+ 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
+ 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
+ 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe
+ },
+ {
+ 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a,
+ 0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f,
+ 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+ 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b,
+ 0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9,
+ 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27
}
},
{
@@ -1427,6 +1502,40 @@ const struct hmac_test {
0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 4 */
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19,
+ },
+ 25,
+ {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+ },
+ 50,
+ {
+ 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
+ 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
+ 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
+ 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b
+ },
+ {
+ 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85,
+ 0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7,
+ 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+ 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e,
+ 0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79,
+ 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb
}
},
{
@@ -1444,7 +1553,8 @@ const struct hmac_test {
0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
- }
+ },
+ { }
},
{
{
@@ -1467,6 +1577,45 @@ const struct hmac_test {
0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 6 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa
+ },
+ 131,
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ 54,
+ {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+ 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+ 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+ 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54
+ },
+ {
+ 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90,
+ 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4,
+ 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+ 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6,
+ 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82,
+ 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52
}
},
{
@@ -1491,6 +1640,45 @@ const struct hmac_test {
0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 7 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa
+ },
+ 131,
+ "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ 152,
+ {
+ 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
+ 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
+ 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
+ 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2
+ },
+ {
+ 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d,
+ 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c,
+ 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+ 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5,
+ 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d,
+ 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e
}
}
};
@@ -1503,6 +1691,7 @@ static int test_sha256(void)
const u8 *addr[2];
size_t len[2];
int errors = 0;
+ u8 *key;
for (i = 0; i < ARRAY_SIZE(tests); i++) {
wpa_printf(MSG_INFO, "SHA256 test case %d:", i + 1);
@@ -1573,12 +1762,285 @@ static int test_sha256(void)
hash, sizeof(hash));
/* TODO: add proper test case for this */
+ key = os_malloc(8161);
+ if (key) {
+#ifdef CONFIG_HMAC_SHA256_KDF
+ int res;
+
+ res = hmac_sha256_kdf((u8 *) "secret", 6, "label",
+ (u8 *) "seed", 4, key, 8160);
+ if (res) {
+ wpa_printf(MSG_INFO,
+ "Unexpected hmac_sha256_kdf(outlen=8160) failure");
+ errors++;
+ }
+
+ res = hmac_sha256_kdf((u8 *) "secret", 6, "label",
+ (u8 *) "seed", 4, key, 8161);
+ if (res == 0) {
+ wpa_printf(MSG_INFO,
+ "Unexpected hmac_sha256_kdf(outlen=8161) success");
+ errors++;
+ }
+#endif /* CONFIG_HMAC_SHA256_KDF */
+
+ os_free(key);
+ }
+
if (!errors)
wpa_printf(MSG_INFO, "SHA256 test cases passed");
return errors;
}
+static int test_sha384(void)
+{
+#ifdef CONFIG_SHA384
+ unsigned int i;
+ u8 hash[48];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+ const char *data = "hello";
+ const u8 hash_res[] = {
+ 0x59, 0xe1, 0x74, 0x87, 0x77, 0x44, 0x8c, 0x69,
+ 0xde, 0x6b, 0x80, 0x0d, 0x7a, 0x33, 0xbb, 0xfb,
+ 0x9f, 0xf1, 0xb4, 0x63, 0xe4, 0x43, 0x54, 0xc3,
+ 0x55, 0x3b, 0xcd, 0xb9, 0xc6, 0x66, 0xfa, 0x90,
+ 0x12, 0x5a, 0x3c, 0x79, 0xf9, 0x03, 0x97, 0xbd,
+ 0xf5, 0xf6, 0xa1, 0x3d, 0xe8, 0x28, 0x68, 0x4f
+ };
+
+ addr[0] = (const u8 *) data;
+ len[0] = 5;
+ if (sha384_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, hash_res, 48) != 0) {
+ wpa_printf(MSG_INFO, "SHA384 test case 1: FAIL");
+ errors++;
+ } else {
+ wpa_printf(MSG_INFO, "SHA384 test case 1: OK");
+ }
+
+ addr[0] = (const u8 *) data;
+ len[0] = 4;
+ addr[1] = (const u8 *) data + 4;
+ len[1] = 1;
+ if (sha384_vector(2, addr, len, hash) < 0 ||
+ os_memcmp(hash, hash_res, 48) != 0) {
+ wpa_printf(MSG_INFO, "SHA384 test case 2: FAIL");
+ errors++;
+ } else {
+ wpa_printf(MSG_INFO, "SHA384 test case 2: OK");
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
+ const struct hmac_test *t = &hmac_tests[i];
+
+ if (t->hash384[0] == 0 && t->hash384[1] == 0 &&
+ t->hash384[2] == 0 && t->hash384[3] == 0)
+ continue;
+ wpa_printf(MSG_INFO, "HMAC-SHA384 test case %d:", i + 1);
+
+ if (hmac_sha384(t->key, t->key_len, t->data, t->data_len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ addr[0] = t->data;
+ len[0] = t->data_len;
+ if (hmac_sha384_vector(t->key, t->key_len, 1, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = t->data;
+ len[0] = 1;
+ addr[1] = t->data + 1;
+ len[1] = t->data_len - 1;
+ if (hmac_sha384_vector(t->key, t->key_len, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "SHA384 test cases passed");
+ return errors;
+#else /* CONFIG_SHA384 */
+ return 0;
+#endif /* CONFIG_SHA384 */
+}
+
+
+static int test_fips186_2_prf(void)
+{
+ /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
+ u8 xkey[] = {
+ 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
+ 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
+ 0xeb, 0x5a, 0x38, 0xb6
+ };
+ u8 w[] = {
+ 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
+ 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
+ 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
+ 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
+ 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
+ };
+ u8 buf[40];
+
+ wpa_printf(MSG_INFO,
+ "Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)");
+ if (fips186_2_prf(xkey, sizeof(xkey), buf, sizeof(buf)) < 0 ||
+ os_memcmp(w, buf, sizeof(w)) != 0) {
+ wpa_printf(MSG_INFO, "fips186_2_prf failed");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int test_extract_expand_hkdf(void)
+{
+ u8 prk[SHA256_MAC_LEN];
+ u8 okm[82];
+
+ /* RFC 5869, A.1 */
+ u8 ikm1[22] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+ };
+ u8 salt1[13] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c
+ };
+ u8 info1[10] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9
+ };
+ u8 prk1[32] = {
+ 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
+ 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
+ 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
+ 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5
+ };
+ u8 okm1[42] = {
+ 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
+ 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
+ 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
+ 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
+ 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
+ 0x58, 0x65
+ };
+
+ /* RFC 5869, A.2 */
+ u8 ikm2[80] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+ };
+ u8 salt2[80] = {
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf
+ };
+ u8 info2[80] = {
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ u8 prk2[32] = {
+ 0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a,
+ 0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c,
+ 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01,
+ 0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44
+ };
+ u8 okm2[82] = {
+ 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1,
+ 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34,
+ 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8,
+ 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c,
+ 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72,
+ 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09,
+ 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8,
+ 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71,
+ 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87,
+ 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f,
+ 0x1d, 0x87
+ };
+
+ wpa_printf(MSG_INFO, "Testing Extract-and-Expand HKDF (RFC 5869)");
+
+ wpa_printf(MSG_INFO, "RFC 5869 - Test Case 1");
+ if (hmac_sha256(salt1, sizeof(salt1), ikm1, sizeof(ikm1), prk) < 0)
+ return -1;
+ if (os_memcmp(prk, prk1, SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO, "HKDF-Extract mismatch in PRK");
+ return -1;
+ }
+ if (hmac_sha256_kdf(prk1, sizeof(prk1), NULL, info1, sizeof(info1),
+ okm, sizeof(okm1)) < 0)
+ return -1;
+ if (os_memcmp(okm, okm1, sizeof(okm1)) != 0) {
+ wpa_printf(MSG_INFO, "HKDF-Expand mismatch in OKM");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 5869 - Test Case 2");
+ if (hmac_sha256(salt2, sizeof(salt2), ikm2, sizeof(ikm2), prk) < 0)
+ return -1;
+ if (os_memcmp(prk, prk2, SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO, "HKDF-Extract mismatch in PRK");
+ return -1;
+ }
+ if (hmac_sha256_kdf(prk2, sizeof(prk2), NULL, info2, sizeof(info2),
+ okm, sizeof(okm2)) < 0)
+ return -1;
+ if (os_memcmp(okm, okm2, sizeof(okm2)) != 0) {
+ wpa_printf(MSG_INFO, "HKDF-Expand mismatch in OKM");
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "Extract-and-Expand HKDF test cases passed");
+
+ return 0;
+}
+
+
static int test_ms_funcs(void)
{
#ifndef CONFIG_FIPS
@@ -1695,6 +2157,9 @@ int crypto_module_tests(void)
test_md5() ||
test_sha1() ||
test_sha256() ||
+ test_sha384() ||
+ test_fips186_2_prf() ||
+ test_extract_expand_hkdf() ||
test_ms_funcs())
ret = -1;
diff --git a/contrib/wpa/src/crypto/crypto_nettle.c b/contrib/wpa/src/crypto/crypto_nettle.c
new file mode 100644
index 0000000..f85d365
--- /dev/null
+++ b/contrib/wpa/src/crypto/crypto_nettle.c
@@ -0,0 +1,469 @@
+/*
+ * Wrapper functions for libnettle and libgmp
+ * Copyright (c) 2017, 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 <nettle/nettle-meta.h>
+#include <nettle/des.h>
+#undef des_encrypt
+#include <nettle/hmac.h>
+#include <nettle/aes.h>
+#undef aes_encrypt
+#undef aes_decrypt
+#include <nettle/arcfour.h>
+#include <nettle/bignum.h>
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "sha512.h"
+#include "crypto.h"
+
+
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ struct des_ctx ctx;
+ u8 pkey[8], next, tmp;
+ int i;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ nettle_des_set_key(&ctx, pkey);
+ nettle_des_encrypt(&ctx, DES_BLOCK_SIZE, cypher, clear);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+static int nettle_digest_vector(const struct nettle_hash *alg, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ void *ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ctx = os_malloc(alg->context_size);
+ if (!ctx)
+ return -1;
+ alg->init(ctx);
+ for (i = 0; i < num_elem; i++)
+ alg->update(ctx, len[i], addr[i]);
+ alg->digest(ctx, alg->digest_size, mac);
+ bin_clear_free(ctx, alg->context_size);
+ return 0;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_md4, num_elem, addr, len, mac);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_md5, num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha1, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha256, num_elem, addr, len, mac);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha384, num_elem, addr, len, mac);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha512, num_elem, addr, len, mac);
+}
+
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_md5_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_md5_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_md5_update(&ctx, len[i], addr[i]);
+ hmac_md5_digest(&ctx, MD5_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha1_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha1_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha1_update(&ctx, len[i], addr[i]);
+ hmac_sha1_digest(&ctx, SHA1_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha256_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha256_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha256_update(&ctx, len[i], addr[i]);
+ hmac_sha256_digest(&ctx, SHA256_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha384_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha384_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha384_update(&ctx, len[i], addr[i]);
+ hmac_sha384_digest(&ctx, SHA384_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha512_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha512_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha512_update(&ctx, len[i], addr[i]);
+ hmac_sha512_digest(&ctx, SHA512_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ struct aes_ctx *ctx;
+
+ if (TEST_FAIL())
+ return NULL;
+ ctx = os_malloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ nettle_aes_set_encrypt_key(ctx, len, key);
+
+ return ctx;
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ struct aes_ctx *actx = ctx;
+ nettle_aes_encrypt(actx, AES_BLOCK_SIZE, crypt, plain);
+ return 0;
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ struct aes_ctx *actx = ctx;
+ bin_clear_free(actx, sizeof(*actx));
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ struct aes_ctx *ctx;
+
+ if (TEST_FAIL())
+ return NULL;
+ ctx = os_malloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ nettle_aes_set_decrypt_key(ctx, len, key);
+
+ return ctx;
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ struct aes_ctx *actx = ctx;
+ nettle_aes_decrypt(actx, AES_BLOCK_SIZE, plain, crypt);
+ return 0;
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ struct aes_ctx *actx = ctx;
+ bin_clear_free(actx, sizeof(*actx));
+}
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ mpz_t pub;
+ int res = -1;
+
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+ os_memcmp(pubkey, prime, prime_len) >= 0))
+ return -1;
+
+ mpz_init(pub);
+ mpz_import(pub, pubkey_len, 1, 1, 1, 0, pubkey);
+ if (mpz_cmp_d(pub, 1) <= 0)
+ goto fail;
+
+ if (order) {
+ mpz_t p, q, tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ mpz_inits(p, q, tmp, NULL);
+ mpz_import(p, prime_len, 1, 1, 1, 0, prime);
+ mpz_import(q, order_len, 1, 1, 1, 0, order);
+ mpz_powm(tmp, pub, q, p);
+ failed = mpz_cmp_d(tmp, 1) != 0;
+ mpz_clears(p, q, tmp, NULL);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ mpz_clear(pub);
+ return res;
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+ const u8 *power, size_t power_len,
+ const u8 *modulus, size_t modulus_len,
+ u8 *result, size_t *result_len)
+{
+ mpz_t bn_base, bn_exp, bn_modulus, bn_result;
+ int ret = -1;
+ size_t len;
+
+ mpz_inits(bn_base, bn_exp, bn_modulus, bn_result, NULL);
+ mpz_import(bn_base, base_len, 1, 1, 1, 0, base);
+ mpz_import(bn_exp, power_len, 1, 1, 1, 0, power);
+ mpz_import(bn_modulus, modulus_len, 1, 1, 1, 0, modulus);
+
+ mpz_powm(bn_result, bn_base, bn_exp, bn_modulus);
+ len = mpz_sizeinbase(bn_result, 2);
+ len = (len + 7) / 8;
+ if (*result_len < len)
+ goto error;
+ mpz_export(result, result_len, 1, 1, 1, 0, bn_result);
+ ret = 0;
+
+error:
+ mpz_clears(bn_base, bn_exp, bn_modulus, bn_result, NULL);
+ return ret;
+}
+
+
+struct crypto_cipher {
+ enum crypto_cipher_alg alg;
+ union {
+ struct arcfour_ctx arcfour_ctx;
+ } u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ ctx->alg = alg;
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ nettle_arcfour_set_key(&ctx->u.arcfour_ctx, key_len, key);
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ switch (ctx->alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ nettle_arcfour_crypt(&ctx->u.arcfour_ctx, len, crypt, plain);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ switch (ctx->alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ nettle_arcfour_crypt(&ctx->u.arcfour_ctx, len, plain, crypt);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ bin_clear_free(ctx, sizeof(*ctx));
+}
diff --git a/contrib/wpa/src/crypto/crypto_none.c b/contrib/wpa/src/crypto/crypto_none.c
index 011f3f3..5479194 100644
--- a/contrib/wpa/src/crypto/crypto_none.c
+++ b/contrib/wpa/src/crypto/crypto_none.c
@@ -18,6 +18,7 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
}
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/crypto_openssl.c b/contrib/wpa/src/crypto/crypto_openssl.c
index 6cff75c..1b0c1ec 100644
--- a/contrib/wpa/src/crypto/crypto_openssl.c
+++ b/contrib/wpa/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
* Wrapper functions for OpenSSL libcrypto
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -24,16 +24,72 @@
#endif /* CONFIG_ECC */
#include "common.h"
+#include "utils/const_time.h"
#include "wpabuf.h"
#include "dh_group5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha384.h"
+#include "sha512.h"
+#include "md5.h"
+#include "aes_wrap.h"
#include "crypto.h"
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+/* Compatibility wrappers for older versions. */
+
+static HMAC_CTX * HMAC_CTX_new(void)
+{
+ HMAC_CTX *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx)
+ HMAC_CTX_init(ctx);
+ return ctx;
+}
+
+
+static void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+ if (!ctx)
+ return;
+ HMAC_CTX_cleanup(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+}
+
+
+static EVP_MD_CTX * EVP_MD_CTX_new(void)
+{
+ EVP_MD_CTX *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx)
+ EVP_MD_CTX_init(ctx);
+ return ctx;
+}
+
+
+static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+ if (!ctx)
+ return;
+ EVP_MD_CTX_cleanup(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+}
+
+#endif /* OpenSSL version < 1.1.0 */
+
static BIGNUM * get_group5_prime(void)
{
-#ifdef OPENSSL_IS_BORINGSSL
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !(defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+ return BN_get_rfc3526_prime_1536(NULL);
+#elif !defined(OPENSSL_IS_BORINGSSL)
+ return get_rfc3526_prime_1536(NULL);
+#else
static const unsigned char RFC3526_PRIME_1536[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
@@ -53,41 +109,76 @@ static BIGNUM * get_group5_prime(void)
0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
-#else /* OPENSSL_IS_BORINGSSL */
- return get_rfc3526_prime_1536(NULL);
-#endif /* OPENSSL_IS_BORINGSSL */
+#endif
+}
+
+
+static BIGNUM * get_group5_order(void)
+{
+ static const unsigned char RFC3526_ORDER_1536[] = {
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE4,0x87,0xED,0x51,
+ 0x10,0xB4,0x61,0x1A,0x62,0x63,0x31,0x45,0xC0,0x6E,0x0E,0x68,
+ 0x94,0x81,0x27,0x04,0x45,0x33,0xE6,0x3A,0x01,0x05,0xDF,0x53,
+ 0x1D,0x89,0xCD,0x91,0x28,0xA5,0x04,0x3C,0xC7,0x1A,0x02,0x6E,
+ 0xF7,0xCA,0x8C,0xD9,0xE6,0x9D,0x21,0x8D,0x98,0x15,0x85,0x36,
+ 0xF9,0x2F,0x8A,0x1B,0xA7,0xF0,0x9A,0xB6,0xB6,0xA8,0xE1,0x22,
+ 0xF2,0x42,0xDA,0xBB,0x31,0x2F,0x3F,0x63,0x7A,0x26,0x21,0x74,
+ 0xD3,0x1B,0xF6,0xB5,0x85,0xFF,0xAE,0x5B,0x7A,0x03,0x5B,0xF6,
+ 0xF7,0x1C,0x35,0xFD,0xAD,0x44,0xCF,0xD2,0xD7,0x4F,0x92,0x08,
+ 0xBE,0x25,0x8F,0xF3,0x24,0x94,0x33,0x28,0xF6,0x72,0x2D,0x9E,
+ 0xE1,0x00,0x3E,0x5C,0x50,0xB1,0xDF,0x82,0xCC,0x6D,0x24,0x1B,
+ 0x0E,0x2A,0xE9,0xCD,0x34,0x8B,0x1F,0xD4,0x7E,0x92,0x67,0xAF,
+ 0xC1,0xB2,0xAE,0x91,0xEE,0x51,0xD6,0xCB,0x0E,0x31,0x79,0xAB,
+ 0x10,0x42,0xA9,0x5D,0xCF,0x6A,0x94,0x83,0xB8,0x4B,0x4B,0x36,
+ 0xB3,0x86,0x1A,0xA7,0x25,0x5E,0x4C,0x02,0x78,0xBA,0x36,0x04,
+ 0x65,0x11,0xB9,0x93,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+ };
+ return BN_bin2bn(RFC3526_ORDER_1536, sizeof(RFC3526_ORDER_1536), NULL);
}
+
#ifdef OPENSSL_NO_SHA256
#define NO_SHA256_WRAPPER
#endif
+#ifdef OPENSSL_NO_SHA512
+#define NO_SHA384_WRAPPER
+#endif
static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
- EVP_MD_CTX ctx;
+ EVP_MD_CTX *ctx;
size_t i;
unsigned int mac_len;
- EVP_MD_CTX_init(&ctx);
- if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
+ if (TEST_FAIL())
+ return -1;
+
+ ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ return -1;
+ if (!EVP_DigestInit_ex(ctx, type, NULL)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
return -1;
}
for (i = 0; i < num_elem; i++) {
- if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
+ if (!EVP_DigestUpdate(ctx, addr[i], len[i])) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
"failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
return -1;
}
}
- if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
+ if (!EVP_DigestFinal(ctx, mac, &mac_len)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
return -1;
}
+ EVP_MD_CTX_free(ctx);
return 0;
}
@@ -101,7 +192,7 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
#endif /* CONFIG_FIPS */
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
@@ -119,6 +210,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
DES_set_key((DES_cblock *) &pkey, &ks);
DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
DES_ENCRYPT);
+ return 0;
}
@@ -129,32 +221,34 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip,
#ifdef OPENSSL_NO_RC4
return -1;
#else /* OPENSSL_NO_RC4 */
- EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX *ctx;
int outl;
int res = -1;
unsigned char skip_buf[16];
- EVP_CIPHER_CTX_init(&ctx);
- if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
- !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
- !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
- !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx ||
+ !EVP_CIPHER_CTX_set_padding(ctx, 0) ||
+ !EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
+ !EVP_CIPHER_CTX_set_key_length(ctx, keylen) ||
+ !EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, 1))
goto out;
while (skip >= sizeof(skip_buf)) {
size_t len = skip;
if (len > sizeof(skip_buf))
len = sizeof(skip_buf);
- if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
+ if (!EVP_CipherUpdate(ctx, skip_buf, &outl, skip_buf, len))
goto out;
skip -= len;
}
- if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
+ if (EVP_CipherUpdate(ctx, data, &outl, data, data_len))
res = 0;
out:
- EVP_CIPHER_CTX_cleanup(&ctx);
+ if (ctx)
+ EVP_CIPHER_CTX_free(ctx);
return res;
#endif /* OPENSSL_NO_RC4 */
}
@@ -184,15 +278,31 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
#endif /* NO_SHA256_WRAPPER */
+#ifndef NO_SHA384_WRAPPER
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return openssl_digest_vector(EVP_sha384(), num_elem, addr, len, mac);
+}
+#endif /* NO_SHA384_WRAPPER */
+
+
+#ifndef NO_SHA512_WRAPPER
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return openssl_digest_vector(EVP_sha512(), num_elem, addr, len, mac);
+}
+#endif /* NO_SHA512_WRAPPER */
+
+
static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
{
switch (keylen) {
case 16:
return EVP_aes_128_ecb();
-#ifndef OPENSSL_IS_BORINGSSL
case 24:
return EVP_aes_192_ecb();
-#endif /* OPENSSL_IS_BORINGSSL */
case 32:
return EVP_aes_256_ecb();
}
@@ -206,14 +316,19 @@ void * aes_encrypt_init(const u8 *key, size_t len)
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *type;
+ if (TEST_FAIL())
+ return NULL;
+
type = aes_get_evp_cipher(len);
- if (type == NULL)
+ if (!type) {
+ wpa_printf(MSG_INFO, "%s: Unsupported len=%u",
+ __func__, (unsigned int) len);
return NULL;
+ }
- ctx = os_malloc(sizeof(*ctx));
+ ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
return NULL;
- EVP_CIPHER_CTX_init(ctx);
if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
os_free(ctx);
return NULL;
@@ -223,14 +338,16 @@ void * aes_encrypt_init(const u8 *key, size_t len)
}
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
EVP_CIPHER_CTX *c = ctx;
int clen = 16;
if (EVP_EncryptUpdate(c, crypt, &clen, plain, 16) != 1) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptUpdate failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ return -1;
}
+ return 0;
}
@@ -247,8 +364,7 @@ void aes_encrypt_deinit(void *ctx)
wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
"in AES encrypt", len);
}
- EVP_CIPHER_CTX_cleanup(c);
- bin_clear_free(c, sizeof(*c));
+ EVP_CIPHER_CTX_free(c);
}
@@ -257,16 +373,21 @@ void * aes_decrypt_init(const u8 *key, size_t len)
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *type;
+ if (TEST_FAIL())
+ return NULL;
+
type = aes_get_evp_cipher(len);
- if (type == NULL)
+ if (!type) {
+ wpa_printf(MSG_INFO, "%s: Unsupported len=%u",
+ __func__, (unsigned int) len);
return NULL;
+ }
- ctx = os_malloc(sizeof(*ctx));
+ ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
return NULL;
- EVP_CIPHER_CTX_init(ctx);
if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
- os_free(ctx);
+ EVP_CIPHER_CTX_free(ctx);
return NULL;
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
@@ -274,14 +395,16 @@ void * aes_decrypt_init(const u8 *key, size_t len)
}
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
EVP_CIPHER_CTX *c = ctx;
int plen = 16;
if (EVP_DecryptUpdate(c, plain, &plen, crypt, 16) != 1) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptUpdate failed: %s",
ERR_error_string(ERR_get_error(), NULL));
+ return -1;
}
+ return 0;
}
@@ -298,8 +421,7 @@ void aes_decrypt_deinit(void *ctx)
wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
"in AES decrypt", len);
}
- EVP_CIPHER_CTX_cleanup(c);
- bin_clear_free(c, sizeof(*c));
+ EVP_CIPHER_CTX_free(c);
}
@@ -311,6 +433,8 @@ int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
AES_KEY actx;
int res;
+ if (TEST_FAIL())
+ return -1;
if (AES_set_encrypt_key(kek, kek_len << 3, &actx))
return -1;
res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
@@ -325,6 +449,8 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
AES_KEY actx;
int res;
+ if (TEST_FAIL())
+ return -1;
if (AES_set_decrypt_key(kek, kek_len << 3, &actx))
return -1;
res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
@@ -338,54 +464,128 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
- EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX *ctx;
int clen, len;
u8 buf[16];
+ int res = -1;
- EVP_CIPHER_CTX_init(&ctx);
- if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ if (TEST_FAIL())
return -1;
- EVP_CIPHER_CTX_set_padding(&ctx, 0);
- clen = data_len;
- if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 ||
- clen != (int) data_len)
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
return -1;
-
+ clen = data_len;
len = sizeof(buf);
- if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
- return -1;
- EVP_CIPHER_CTX_cleanup(&ctx);
+ if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_EncryptUpdate(ctx, data, &clen, data, data_len) == 1 &&
+ clen == (int) data_len &&
+ EVP_EncryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+ res = 0;
+ EVP_CIPHER_CTX_free(ctx);
- return 0;
+ return res;
}
int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
- EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX *ctx;
int plen, len;
u8 buf[16];
+ int res = -1;
- EVP_CIPHER_CTX_init(&ctx);
- if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ if (TEST_FAIL())
return -1;
- EVP_CIPHER_CTX_set_padding(&ctx, 0);
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ return -1;
plen = data_len;
- if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 ||
- plen != (int) data_len)
+ len = sizeof(buf);
+ if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_DecryptUpdate(ctx, data, &plen, data, data_len) == 1 &&
+ plen == (int) data_len &&
+ EVP_DecryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+ res = 0;
+ EVP_CIPHER_CTX_free(ctx);
+
+ return res;
+
+}
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
- len = sizeof(buf);
- if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
return -1;
- EVP_CIPHER_CTX_cleanup(&ctx);
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
return 0;
}
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ BIGNUM *pub, *p;
+ int res = -1;
+
+ pub = BN_bin2bn(pubkey, pubkey_len, NULL);
+ p = BN_bin2bn(prime, prime_len, NULL);
+ if (!pub || !p || BN_is_zero(pub) || BN_is_one(pub) ||
+ BN_cmp(pub, p) >= 0)
+ goto fail;
+
+ if (order) {
+ BN_CTX *ctx;
+ BIGNUM *q, *tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ q = BN_bin2bn(order, order_len, NULL);
+ ctx = BN_CTX_new();
+ tmp = BN_new();
+ failed = !q || !ctx || !tmp ||
+ !BN_mod_exp(tmp, pub, q, p, ctx) ||
+ !BN_is_one(tmp);
+ BN_clear(q);
+ BN_clear(tmp);
+ BN_CTX_free(ctx);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ BN_clear(pub);
+ BN_clear(p);
+ return res;
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
@@ -408,7 +608,8 @@ int crypto_mod_exp(const u8 *base, size_t base_len,
bn_result == NULL)
goto error;
- if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
+ if (BN_mod_exp_mont_consttime(bn_result, bn_base, bn_exp, bn_modulus,
+ ctx, NULL) != 1)
goto error;
*result_len = BN_bn2bin(bn_result, result);
@@ -425,8 +626,8 @@ error:
struct crypto_cipher {
- EVP_CIPHER_CTX enc;
- EVP_CIPHER_CTX dec;
+ EVP_CIPHER_CTX *enc;
+ EVP_CIPHER_CTX *dec;
};
@@ -487,23 +688,25 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
return NULL;
}
- EVP_CIPHER_CTX_init(&ctx->enc);
- EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
- if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
- !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
- !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
- EVP_CIPHER_CTX_cleanup(&ctx->enc);
+ if (!(ctx->enc = EVP_CIPHER_CTX_new()) ||
+ !EVP_CIPHER_CTX_set_padding(ctx->enc, 0) ||
+ !EVP_EncryptInit_ex(ctx->enc, cipher, NULL, NULL, NULL) ||
+ !EVP_CIPHER_CTX_set_key_length(ctx->enc, key_len) ||
+ !EVP_EncryptInit_ex(ctx->enc, NULL, NULL, key, iv)) {
+ if (ctx->enc)
+ EVP_CIPHER_CTX_free(ctx->enc);
os_free(ctx);
return NULL;
}
- EVP_CIPHER_CTX_init(&ctx->dec);
- EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
- if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
- !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
- !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
- EVP_CIPHER_CTX_cleanup(&ctx->enc);
- EVP_CIPHER_CTX_cleanup(&ctx->dec);
+ if (!(ctx->dec = EVP_CIPHER_CTX_new()) ||
+ !EVP_CIPHER_CTX_set_padding(ctx->dec, 0) ||
+ !EVP_DecryptInit_ex(ctx->dec, cipher, NULL, NULL, NULL) ||
+ !EVP_CIPHER_CTX_set_key_length(ctx->dec, key_len) ||
+ !EVP_DecryptInit_ex(ctx->dec, NULL, NULL, key, iv)) {
+ EVP_CIPHER_CTX_free(ctx->enc);
+ if (ctx->dec)
+ EVP_CIPHER_CTX_free(ctx->dec);
os_free(ctx);
return NULL;
}
@@ -516,7 +719,7 @@ int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
int outl;
- if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
+ if (!EVP_EncryptUpdate(ctx->enc, crypt, &outl, plain, len))
return -1;
return 0;
}
@@ -527,7 +730,7 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
{
int outl;
outl = len;
- if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
+ if (!EVP_DecryptUpdate(ctx->dec, plain, &outl, crypt, len))
return -1;
return 0;
}
@@ -535,19 +738,23 @@ int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
- EVP_CIPHER_CTX_cleanup(&ctx->enc);
- EVP_CIPHER_CTX_cleanup(&ctx->dec);
+ EVP_CIPHER_CTX_free(ctx->enc);
+ EVP_CIPHER_CTX_free(ctx->dec);
os_free(ctx);
}
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
size_t publen, privlen;
*priv = NULL;
+ wpabuf_free(*publ);
*publ = NULL;
dh = DH_new();
@@ -562,6 +769,10 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
if (dh->p == NULL)
goto err;
+ dh->q = get_group5_order();
+ if (!dh->q)
+ goto err;
+
if (DH_generate_key(dh) != 1)
goto err;
@@ -586,11 +797,68 @@ err:
wpabuf_clear_free(privkey);
DH_free(dh);
return NULL;
+#else
+ DH *dh;
+ struct wpabuf *pubkey = NULL, *privkey = NULL;
+ size_t publen, privlen;
+ BIGNUM *p, *g, *q;
+ const BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+ *priv = NULL;
+ wpabuf_free(*publ);
+ *publ = NULL;
+
+ dh = DH_new();
+ if (dh == NULL)
+ return NULL;
+
+ g = BN_new();
+ p = get_group5_prime();
+ q = get_group5_order();
+ if (!g || BN_set_word(g, 2) != 1 || !p || !q ||
+ DH_set0_pqg(dh, p, q, g) != 1)
+ goto err;
+ p = NULL;
+ q = NULL;
+ g = NULL;
+
+ if (DH_generate_key(dh) != 1)
+ goto err;
+
+ DH_get0_key(dh, &pub_key, &priv_key);
+ publen = BN_num_bytes(pub_key);
+ pubkey = wpabuf_alloc(publen);
+ if (!pubkey)
+ goto err;
+ privlen = BN_num_bytes(priv_key);
+ privkey = wpabuf_alloc(privlen);
+ if (!privkey)
+ goto err;
+
+ BN_bn2bin(pub_key, wpabuf_put(pubkey, publen));
+ BN_bn2bin(priv_key, wpabuf_put(privkey, privlen));
+
+ *priv = privkey;
+ *publ = pubkey;
+ return dh;
+
+err:
+ BN_free(p);
+ BN_free(q);
+ BN_free(g);
+ wpabuf_clear_free(pubkey);
+ wpabuf_clear_free(privkey);
+ DH_free(dh);
+ return NULL;
+#endif
}
void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
DH *dh;
dh = DH_new();
@@ -621,6 +889,42 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
err:
DH_free(dh);
return NULL;
+#else
+ DH *dh;
+ BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL;
+
+ dh = DH_new();
+ if (dh == NULL)
+ return NULL;
+
+ g = BN_new();
+ p = get_group5_prime();
+ if (!g || BN_set_word(g, 2) != 1 || !p ||
+ DH_set0_pqg(dh, p, NULL, g) != 1)
+ goto err;
+ p = NULL;
+ g = NULL;
+
+ priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+ pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+ if (!priv_key || !pub_key || DH_set0_key(dh, pub_key, priv_key) != 1)
+ goto err;
+ pub_key = NULL;
+ priv_key = NULL;
+
+ if (DH_generate_key(dh) != 1)
+ goto err;
+
+ return dh;
+
+err:
+ BN_free(p);
+ BN_free(g);
+ BN_free(pub_key);
+ BN_clear_free(priv_key);
+ DH_free(dh);
+ return NULL;
+#endif
}
@@ -672,7 +976,7 @@ void dh5_free(void *ctx)
struct crypto_hash {
- HMAC_CTX ctx;
+ HMAC_CTX *ctx;
};
@@ -707,16 +1011,17 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
- HMAC_CTX_init(&ctx->ctx);
+ ctx->ctx = HMAC_CTX_new();
+ if (!ctx->ctx) {
+ os_free(ctx);
+ return NULL;
+ }
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
-#else /* openssl < 0.9.9 */
- if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
+ if (HMAC_Init_ex(ctx->ctx, key, key_len, md, NULL) != 1) {
+ HMAC_CTX_free(ctx->ctx);
bin_clear_free(ctx, sizeof(*ctx));
return NULL;
}
-#endif /* openssl < 0.9.9 */
return ctx;
}
@@ -726,7 +1031,7 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
{
if (ctx == NULL)
return;
- HMAC_Update(&ctx->ctx, data, len);
+ HMAC_Update(ctx->ctx, data, len);
}
@@ -739,20 +1044,19 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
return -2;
if (mac == NULL || len == NULL) {
+ HMAC_CTX_free(ctx->ctx);
bin_clear_free(ctx, sizeof(*ctx));
return 0;
}
mdlen = *len;
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Final(&ctx->ctx, mac, &mdlen);
- res = 1;
-#else /* openssl < 0.9.9 */
- res = HMAC_Final(&ctx->ctx, mac, &mdlen);
-#endif /* openssl < 0.9.9 */
- HMAC_CTX_cleanup(&ctx->ctx);
+ res = HMAC_Final(ctx->ctx, mac, &mdlen);
+ HMAC_CTX_free(ctx->ctx);
bin_clear_free(ctx, sizeof(*ctx));
+ if (TEST_FAIL())
+ return -1;
+
if (res == 1) {
*len = mdlen;
return 0;
@@ -767,28 +1071,26 @@ static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
const u8 *addr[], const size_t *len, u8 *mac,
unsigned int mdlen)
{
- HMAC_CTX ctx;
+ HMAC_CTX *ctx;
size_t i;
int res;
- HMAC_CTX_init(&ctx);
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Init_ex(&ctx, key, key_len, type, NULL);
-#else /* openssl < 0.9.9 */
- if (HMAC_Init_ex(&ctx, key, key_len, type, NULL) != 1)
+ if (TEST_FAIL())
+ return -1;
+
+ ctx = HMAC_CTX_new();
+ if (!ctx)
return -1;
-#endif /* openssl < 0.9.9 */
+ res = HMAC_Init_ex(ctx, key, key_len, type, NULL);
+ if (res != 1)
+ goto done;
for (i = 0; i < num_elem; i++)
- HMAC_Update(&ctx, addr[i], len[i]);
+ HMAC_Update(ctx, addr[i], len[i]);
-#if OPENSSL_VERSION_NUMBER < 0x00909000
- HMAC_Final(&ctx, mac, &mdlen);
- res = 1;
-#else /* openssl < 0.9.9 */
- res = HMAC_Final(&ctx, mac, &mdlen);
-#endif /* openssl < 0.9.9 */
- HMAC_CTX_cleanup(&ctx);
+ res = HMAC_Final(ctx, mac, &mdlen);
+done:
+ HMAC_CTX_free(ctx);
return res == 1 ? 0 : -1;
}
@@ -863,7 +1165,7 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_hmac_vector(EVP_sha384(), key, key_len, num_elem, addr,
- len, mac, 32);
+ len, mac, 48);
}
@@ -876,6 +1178,25 @@ int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector(EVP_sha512(), key, key_len, num_elem, addr,
+ len, mac, 64);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
int crypto_get_random(void *buf, size_t len)
{
if (RAND_bytes(buf, len) != 1)
@@ -892,6 +1213,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
int ret = -1;
size_t outlen, i;
+ if (TEST_FAIL())
+ return -1;
+
ctx = CMAC_CTX_new();
if (ctx == NULL)
return -1;
@@ -941,13 +1265,20 @@ int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
struct crypto_bignum * crypto_bignum_init(void)
{
+ if (TEST_FAIL())
+ return NULL;
return (struct crypto_bignum *) BN_new();
}
struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
{
- BIGNUM *bn = BN_bin2bn(buf, len, NULL);
+ BIGNUM *bn;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ bn = BN_bin2bn(buf, len, NULL);
return (struct crypto_bignum *) bn;
}
@@ -966,6 +1297,9 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
{
int num_bytes, offset;
+ if (TEST_FAIL())
+ return -1;
+
if (padlen > buflen)
return -1;
@@ -984,6 +1318,14 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
}
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+ if (TEST_FAIL())
+ return -1;
+ return BN_rand_range((BIGNUM *) r, (const BIGNUM *) m) == 1 ? 0 : -1;
+}
+
+
int crypto_bignum_add(const struct crypto_bignum *a,
const struct crypto_bignum *b,
struct crypto_bignum *c)
@@ -1019,11 +1361,15 @@ int crypto_bignum_exptmod(const struct crypto_bignum *a,
int res;
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
- res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
- (const BIGNUM *) c, bnctx);
+ res = BN_mod_exp_mont_consttime((BIGNUM *) d, (const BIGNUM *) a,
+ (const BIGNUM *) b, (const BIGNUM *) c,
+ bnctx, NULL);
BN_CTX_free(bnctx);
return res ? 0 : -1;
@@ -1037,9 +1383,16 @@ int crypto_bignum_inverse(const struct crypto_bignum *a,
BIGNUM *res;
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
+#ifdef OPENSSL_IS_BORINGSSL
+ /* TODO: use BN_mod_inverse_blinded() ? */
+#else /* OPENSSL_IS_BORINGSSL */
+ BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
+#endif /* OPENSSL_IS_BORINGSSL */
res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a,
(const BIGNUM *) b, bnctx);
BN_CTX_free(bnctx);
@@ -1052,6 +1405,8 @@ int crypto_bignum_sub(const struct crypto_bignum *a,
const struct crypto_bignum *b,
struct crypto_bignum *c)
{
+ if (TEST_FAIL())
+ return -1;
return BN_sub((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
0 : -1;
}
@@ -1065,9 +1420,15 @@ int crypto_bignum_div(const struct crypto_bignum *a,
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
+#ifndef OPENSSL_IS_BORINGSSL
+ BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
+#endif /* OPENSSL_IS_BORINGSSL */
res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a,
(const BIGNUM *) b, bnctx);
BN_CTX_free(bnctx);
@@ -1085,6 +1446,9 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
BN_CTX *bnctx;
+ if (TEST_FAIL())
+ return -1;
+
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
@@ -1096,6 +1460,15 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
}
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r)
+{
+ /* Note: BN_rshift() does not modify the first argument even though it
+ * has not been marked const. */
+ return BN_rshift((BIGNUM *) a, (BIGNUM *) r, n) == 1 ? 0 : -1;
+}
+
+
int crypto_bignum_cmp(const struct crypto_bignum *a,
const struct crypto_bignum *b)
{
@@ -1121,12 +1494,22 @@ int crypto_bignum_is_one(const struct crypto_bignum *a)
}
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+ return BN_is_odd((const BIGNUM *) a);
+}
+
+
int crypto_bignum_legendre(const struct crypto_bignum *a,
const struct crypto_bignum *p)
{
BN_CTX *bnctx;
BIGNUM *exp = NULL, *tmp = NULL;
int res = -2;
+ unsigned int mask;
+
+ if (TEST_FAIL())
+ return -2;
bnctx = BN_CTX_new();
if (bnctx == NULL)
@@ -1138,16 +1521,17 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
/* exp = (p-1) / 2 */
!BN_sub(exp, (const BIGNUM *) p, BN_value_one()) ||
!BN_rshift1(exp, exp) ||
- !BN_mod_exp(tmp, (const BIGNUM *) a, exp, (const BIGNUM *) p,
- bnctx))
+ !BN_mod_exp_mont_consttime(tmp, (const BIGNUM *) a, exp,
+ (const BIGNUM *) p, bnctx, NULL))
goto fail;
- if (BN_is_word(tmp, 1))
- res = 1;
- else if (BN_is_zero(tmp))
- res = 0;
- else
- res = -1;
+ /* Return 1 if tmp == 1, 0 if tmp == 0, or -1 otherwise. Need to use
+ * constant time selection to avoid branches here. */
+ res = -1;
+ mask = const_time_eq(BN_is_word(tmp, 1), 1);
+ res = const_time_select_int(mask, 1, res);
+ mask = const_time_eq(BN_is_zero(tmp), 1);
+ res = const_time_select_int(mask, 0, res);
fail:
BN_clear_free(tmp);
@@ -1161,6 +1545,7 @@ fail:
struct crypto_ec {
EC_GROUP *group;
+ int nid;
BN_CTX *bnctx;
BIGNUM *prime;
BIGNUM *order;
@@ -1218,6 +1603,7 @@ struct crypto_ec * crypto_ec_init(int group)
if (e == NULL)
return NULL;
+ e->nid = nid;
e->bnctx = BN_CTX_new();
e->group = EC_GROUP_new_by_curve_name(nid);
e->prime = BN_new();
@@ -1252,6 +1638,8 @@ void crypto_ec_deinit(struct crypto_ec *e)
struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
{
+ if (TEST_FAIL())
+ return NULL;
if (e == NULL)
return NULL;
return (struct crypto_ec_point *) EC_POINT_new(e->group);
@@ -1270,6 +1658,12 @@ size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
}
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+ return BN_num_bytes(e->order);
+}
+
+
const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
{
return (const struct crypto_bignum *) e->prime;
@@ -1291,6 +1685,16 @@ void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
}
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+ struct crypto_bignum *x)
+{
+ return EC_POINT_get_affine_coordinates_GFp(e->group,
+ (const EC_POINT *) p,
+ (BIGNUM *) x, NULL,
+ e->bnctx) == 1 ? 0 : -1;
+}
+
+
int crypto_ec_point_to_bin(struct crypto_ec *e,
const struct crypto_ec_point *point, u8 *x, u8 *y)
{
@@ -1298,6 +1702,9 @@ int crypto_ec_point_to_bin(struct crypto_ec *e,
int ret = -1;
int len = BN_num_bytes(e->prime);
+ if (TEST_FAIL())
+ return -1;
+
x_bn = BN_new();
y_bn = BN_new();
@@ -1328,6 +1735,9 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
EC_POINT *elem;
int len = BN_num_bytes(e->prime);
+ if (TEST_FAIL())
+ return NULL;
+
x = BN_bin2bn(val, len, NULL);
y = BN_bin2bn(val + len, len, NULL);
elem = EC_POINT_new(e->group);
@@ -1355,6 +1765,8 @@ int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
const struct crypto_ec_point *b,
struct crypto_ec_point *c)
{
+ if (TEST_FAIL())
+ return -1;
return EC_POINT_add(e->group, (EC_POINT *) c, (const EC_POINT *) a,
(const EC_POINT *) b, e->bnctx) ? 0 : -1;
}
@@ -1364,6 +1776,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
const struct crypto_bignum *b,
struct crypto_ec_point *res)
{
+ if (TEST_FAIL())
+ return -1;
return EC_POINT_mul(e->group, (EC_POINT *) res, NULL,
(const EC_POINT *) p, (const BIGNUM *) b, e->bnctx)
? 0 : -1;
@@ -1372,6 +1786,8 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
{
+ if (TEST_FAIL())
+ return -1;
return EC_POINT_invert(e->group, (EC_POINT *) p, e->bnctx) ? 0 : -1;
}
@@ -1380,6 +1796,8 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
struct crypto_ec_point *p,
const struct crypto_bignum *x, int y_bit)
{
+ if (TEST_FAIL())
+ return -1;
if (!EC_POINT_set_compressed_coordinates_GFp(e->group, (EC_POINT *) p,
(const BIGNUM *) x, y_bit,
e->bnctx) ||
@@ -1395,6 +1813,9 @@ crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
{
BIGNUM *tmp, *tmp2, *y_sqr = NULL;
+ if (TEST_FAIL())
+ return NULL;
+
tmp = BN_new();
tmp2 = BN_new();
@@ -1439,4 +1860,228 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
(const EC_POINT *) b, e->bnctx);
}
+
+struct crypto_ecdh {
+ struct crypto_ec *ec;
+ EVP_PKEY *pkey;
+};
+
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+ struct crypto_ecdh *ecdh;
+ EVP_PKEY *params = NULL;
+ EC_KEY *ec_params;
+ EVP_PKEY_CTX *kctx = NULL;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ ec_params = EC_KEY_new_by_curve_name(ecdh->ec->nid);
+ if (!ec_params) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to generate EC_KEY parameters");
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
+ params = EVP_PKEY_new();
+ if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to generate EVP_PKEY parameters");
+ goto fail;
+ }
+
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+ if (!kctx)
+ goto fail;
+
+ if (EVP_PKEY_keygen_init(kctx) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EVP_PKEY_keygen_init failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_keygen(kctx, &ecdh->pkey) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_PKEY_keygen failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+done:
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ ecdh = NULL;
+ goto done;
+}
+
+
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
+{
+ struct wpabuf *buf = NULL;
+ EC_KEY *eckey;
+ const EC_POINT *pubkey;
+ BIGNUM *x, *y = NULL;
+ int len = BN_num_bytes(ecdh->ec->prime);
+ int res;
+
+ eckey = EVP_PKEY_get1_EC_KEY(ecdh->pkey);
+ if (!eckey)
+ return NULL;
+
+ pubkey = EC_KEY_get0_public_key(eckey);
+ if (!pubkey)
+ return NULL;
+
+ x = BN_new();
+ if (inc_y) {
+ y = BN_new();
+ if (!y)
+ goto fail;
+ }
+ buf = wpabuf_alloc(inc_y ? 2 * len : len);
+ if (!x || !buf)
+ goto fail;
+
+ if (EC_POINT_get_affine_coordinates_GFp(ecdh->ec->group, pubkey,
+ x, y, ecdh->ec->bnctx) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EC_POINT_get_affine_coordinates_GFp failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ res = crypto_bignum_to_bin((struct crypto_bignum *) x,
+ wpabuf_put(buf, len), len, len);
+ if (res < 0)
+ goto fail;
+
+ if (inc_y) {
+ res = crypto_bignum_to_bin((struct crypto_bignum *) y,
+ wpabuf_put(buf, len), len, len);
+ if (res < 0)
+ goto fail;
+ }
+
+done:
+ BN_clear_free(x);
+ BN_clear_free(y);
+ EC_KEY_free(eckey);
+
+ return buf;
+fail:
+ wpabuf_free(buf);
+ buf = NULL;
+ goto done;
+}
+
+
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+ const u8 *key, size_t len)
+{
+ BIGNUM *x, *y = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *peerkey = NULL;
+ struct wpabuf *secret = NULL;
+ size_t secret_len;
+ EC_POINT *pub;
+ EC_KEY *eckey = NULL;
+
+ x = BN_bin2bn(key, inc_y ? len / 2 : len, NULL);
+ pub = EC_POINT_new(ecdh->ec->group);
+ if (!x || !pub)
+ goto fail;
+
+ if (inc_y) {
+ y = BN_bin2bn(key + len / 2, len / 2, NULL);
+ if (!y)
+ goto fail;
+ if (!EC_POINT_set_affine_coordinates_GFp(ecdh->ec->group, pub,
+ x, y,
+ ecdh->ec->bnctx)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ } else if (!EC_POINT_set_compressed_coordinates_GFp(ecdh->ec->group,
+ pub, x, 0,
+ ecdh->ec->bnctx)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EC_POINT_set_compressed_coordinates_GFp failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (!EC_POINT_is_on_curve(ecdh->ec->group, pub, ecdh->ec->bnctx)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: ECDH peer public key is not on curve");
+ goto fail;
+ }
+
+ eckey = EC_KEY_new_by_curve_name(ecdh->ec->nid);
+ if (!eckey || EC_KEY_set_public_key(eckey, pub) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EC_KEY_set_public_key failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ peerkey = EVP_PKEY_new();
+ if (!peerkey || EVP_PKEY_set1_EC_KEY(peerkey, eckey) != 1)
+ goto fail;
+
+ ctx = EVP_PKEY_CTX_new(ecdh->pkey, NULL);
+ if (!ctx || EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, peerkey) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &secret_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EVP_PKEY_derive(1) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ secret = wpabuf_alloc(secret_len);
+ if (!secret)
+ goto fail;
+ if (EVP_PKEY_derive(ctx, wpabuf_put(secret, secret_len),
+ &secret_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EVP_PKEY_derive(2) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+done:
+ BN_free(x);
+ BN_free(y);
+ EC_KEY_free(eckey);
+ EC_POINT_free(pub);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return secret;
+fail:
+ wpabuf_free(secret);
+ secret = NULL;
+ goto done;
+}
+
+
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
+{
+ if (ecdh) {
+ crypto_ec_deinit(ecdh->ec);
+ EVP_PKEY_free(ecdh->pkey);
+ os_free(ecdh);
+ }
+}
+
#endif /* CONFIG_ECC */
diff --git a/contrib/wpa/src/crypto/crypto_wolfssl.c b/contrib/wpa/src/crypto/crypto_wolfssl.c
new file mode 100644
index 0000000..976a008
--- /dev/null
+++ b/contrib/wpa/src/crypto/crypto_wolfssl.c
@@ -0,0 +1,1786 @@
+/*
+ * Wrapper functions for libwolfssl
+ * Copyright (c) 2004-2017, 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.h"
+
+/* wolfSSL headers */
+#include <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/md4.h>
+#include <wolfssl/wolfcrypt/md5.h>
+#include <wolfssl/wolfcrypt/sha.h>
+#include <wolfssl/wolfcrypt/sha256.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+#include <wolfssl/wolfcrypt/hmac.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/arc4.h>
+#include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/dh.h>
+#include <wolfssl/wolfcrypt/cmac.h>
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/openssl/bn.h>
+
+
+#ifndef CONFIG_FIPS
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ Md4 md4;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitMd4(&md4);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Md4Update(&md4, addr[i], len[i]);
+
+ wc_Md4Final(&md4, mac);
+
+ return 0;
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ wc_Md5 md5;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitMd5(&md5);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Md5Update(&md5, addr[i], len[i]);
+
+ wc_Md5Final(&md5, mac);
+
+ return 0;
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ wc_Sha sha;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha(&sha);
+
+ for (i = 0; i < num_elem; i++)
+ wc_ShaUpdate(&sha, addr[i], len[i]);
+
+ wc_ShaFinal(&sha, mac);
+
+ return 0;
+}
+
+
+#ifndef NO_SHA256_WRAPPER
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ wc_Sha256 sha256;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha256(&sha256);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Sha256Update(&sha256, addr[i], len[i]);
+
+ wc_Sha256Final(&sha256, mac);
+
+ return 0;
+}
+#endif /* NO_SHA256_WRAPPER */
+
+
+#ifdef CONFIG_SHA384
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ wc_Sha384 sha384;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha384(&sha384);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Sha384Update(&sha384, addr[i], len[i]);
+
+ wc_Sha384Final(&sha384, mac);
+
+ return 0;
+}
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ wc_Sha512 sha512;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha512(&sha512);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Sha512Update(&sha512, addr[i], len[i]);
+
+ wc_Sha512Final(&sha512, mac);
+
+ return 0;
+}
+#endif /* CONFIG_SHA512 */
+
+
+static int wolfssl_hmac_vector(int type, const u8 *key,
+ size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac,
+ unsigned int mdlen)
+{
+ Hmac hmac;
+ size_t i;
+
+ (void) mdlen;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
+ return -1;
+ for (i = 0; i < num_elem; i++)
+ if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0)
+ return -1;
+ if (wc_HmacFinal(&hmac, mac) != 0)
+ return -1;
+ return 0;
+}
+
+
+#ifndef CONFIG_FIPS
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_MD5, key, key_len, num_elem, addr, len,
+ mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA, key, key_len, num_elem, addr, len,
+ mac, 20);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA256, key, key_len, num_elem, addr, len,
+ mac, 32);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA384, key, key_len, num_elem, addr, len,
+ mac, 48);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA512, key, key_len, num_elem, addr, len,
+ mac, 64);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+ int iterations, u8 *buf, size_t buflen)
+{
+ if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
+ ssid_len, iterations, buflen, WC_SHA) != 0)
+ return -1;
+ return 0;
+}
+
+
+#ifdef CONFIG_DES
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ Des des;
+ u8 pkey[8], next, tmp;
+ int i;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ wc_Des_SetKey(&des, pkey, NULL, DES_ENCRYPTION);
+ wc_Des_EcbEncrypt(&des, cypher, clear, DES_BLOCK_SIZE);
+
+ return 0;
+}
+#endif /* CONFIG_DES */
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ Aes *aes;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ aes = os_malloc(sizeof(Aes));
+ if (!aes)
+ return NULL;
+
+ if (wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION) < 0) {
+ os_free(aes);
+ return NULL;
+ }
+
+ return aes;
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ wc_AesEncryptDirect(ctx, crypt, plain);
+ return 0;
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ os_free(ctx);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ Aes *aes;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ aes = os_malloc(sizeof(Aes));
+ if (!aes)
+ return NULL;
+
+ if (wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION) < 0) {
+ os_free(aes);
+ return NULL;
+ }
+
+ return aes;
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ wc_AesDecryptDirect(ctx, plain, crypt);
+ return 0;
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ os_free(ctx);
+}
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ Aes aes;
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesSetKey(&aes, key, 16, iv, AES_ENCRYPTION);
+ if (ret != 0)
+ return -1;
+
+ ret = wc_AesCbcEncrypt(&aes, data, data, data_len);
+ if (ret != 0)
+ return -1;
+ return 0;
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ Aes aes;
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesSetKey(&aes, key, 16, iv, AES_DECRYPTION);
+ if (ret != 0)
+ return -1;
+
+ ret = wc_AesCbcDecrypt(&aes, data, data, data_len);
+ if (ret != 0)
+ return -1;
+ return 0;
+}
+
+
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
+ NULL);
+ return ret != (n + 1) * 8 ? -1 : 0;
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+ u8 *plain)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
+ NULL);
+ return ret != n * 8 ? -1 : 0;
+}
+
+
+#ifndef CONFIG_NO_RC4
+int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data,
+ size_t data_len)
+{
+#ifndef NO_RC4
+ Arc4 arc4;
+ unsigned char skip_buf[16];
+
+ wc_Arc4SetKey(&arc4, key, keylen);
+
+ while (skip >= sizeof(skip_buf)) {
+ size_t len = skip;
+
+ if (len > sizeof(skip_buf))
+ len = sizeof(skip_buf);
+ wc_Arc4Process(&arc4, skip_buf, skip_buf, len);
+ skip -= len;
+ }
+
+ wc_Arc4Process(&arc4, data, data, data_len);
+
+ return 0;
+#else /* NO_RC4 */
+ return -1;
+#endif /* NO_RC4 */
+}
+#endif /* CONFIG_NO_RC4 */
+
+
+#if defined(EAP_IKEV2) || defined(EAP_IKEV2_DYNAMIC) \
+ || defined(EAP_SERVER_IKEV2)
+union wolfssl_cipher {
+ Aes aes;
+ Des3 des3;
+ Arc4 arc4;
+};
+
+struct crypto_cipher {
+ enum crypto_cipher_alg alg;
+ union wolfssl_cipher enc;
+ union wolfssl_cipher dec;
+};
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ switch (alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+ case CRYPTO_CIPHER_ALG_RC4:
+ wc_Arc4SetKey(&ctx->enc.arc4, key, key_len);
+ wc_Arc4SetKey(&ctx->dec.arc4, key, key_len);
+ break;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+ case CRYPTO_CIPHER_ALG_AES:
+ switch (key_len) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+ if (wc_AesSetKey(&ctx->enc.aes, key, key_len, iv,
+ AES_ENCRYPTION) ||
+ wc_AesSetKey(&ctx->dec.aes, key, key_len, iv,
+ AES_DECRYPTION)) {
+ os_free(ctx);
+ return NULL;
+ }
+ break;
+#endif /* NO_AES */
+#ifndef NO_DES3
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (key_len != DES3_KEYLEN ||
+ wc_Des3_SetKey(&ctx->enc.des3, key, iv, DES_ENCRYPTION) ||
+ wc_Des3_SetKey(&ctx->dec.des3, key, iv, DES_DECRYPTION)) {
+ os_free(ctx);
+ return NULL;
+ }
+ break;
+#endif /* NO_DES3 */
+ case CRYPTO_CIPHER_ALG_RC2:
+ case CRYPTO_CIPHER_ALG_DES:
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ ctx->alg = alg;
+
+ return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+ case CRYPTO_CIPHER_ALG_RC4:
+ wc_Arc4Process(&ctx->enc.arc4, crypt, plain, len);
+ return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+ case CRYPTO_CIPHER_ALG_AES:
+ if (wc_AesCbcEncrypt(&ctx->enc.aes, crypt, plain, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (wc_Des3_CbcEncrypt(&ctx->enc.des3, crypt, plain, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_DES3 */
+ default:
+ return -1;
+ }
+ return -1;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+ case CRYPTO_CIPHER_ALG_RC4:
+ wc_Arc4Process(&ctx->dec.arc4, plain, crypt, len);
+ return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+ case CRYPTO_CIPHER_ALG_AES:
+ if (wc_AesCbcDecrypt(&ctx->dec.aes, plain, crypt, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (wc_Des3_CbcDecrypt(&ctx->dec.des3, plain, crypt, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_DES3 */
+ default:
+ return -1;
+ }
+ return -1;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ os_free(ctx);
+}
+
+#endif
+
+
+#ifdef CONFIG_WPS_NFC
+
+static const unsigned char RFC3526_PRIME_1536[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+ 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
+ 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
+ 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
+ 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
+ 0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static const unsigned char RFC3526_GENERATOR_1536[] = {
+ 0x02
+};
+
+#define RFC3526_LEN sizeof(RFC3526_PRIME_1536)
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+ WC_RNG rng;
+ DhKey *ret = NULL;
+ DhKey *dh = NULL;
+ struct wpabuf *privkey = NULL;
+ struct wpabuf *pubkey = NULL;
+ word32 priv_sz, pub_sz;
+
+ *priv = NULL;
+ wpabuf_free(*publ);
+ *publ = NULL;
+
+ dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (!dh)
+ return NULL;
+ wc_InitDhKey(dh);
+
+ if (wc_InitRng(&rng) != 0) {
+ XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ return NULL;
+ }
+
+ privkey = wpabuf_alloc(RFC3526_LEN);
+ pubkey = wpabuf_alloc(RFC3526_LEN);
+ if (!privkey || !pubkey)
+ goto done;
+
+ if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+ RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+ != 0)
+ goto done;
+
+ if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &priv_sz,
+ wpabuf_mhead(pubkey), &pub_sz) != 0)
+ goto done;
+
+ wpabuf_put(privkey, priv_sz);
+ wpabuf_put(pubkey, pub_sz);
+
+ ret = dh;
+ *priv = privkey;
+ *publ = pubkey;
+ dh = NULL;
+ privkey = NULL;
+ pubkey = NULL;
+done:
+ wpabuf_clear_free(pubkey);
+ wpabuf_clear_free(privkey);
+ if (dh) {
+ wc_FreeDhKey(dh);
+ XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ }
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+ DhKey *ret = NULL;
+ DhKey *dh;
+ byte *secret;
+ word32 secret_sz;
+
+ dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (!dh)
+ return NULL;
+ wc_InitDhKey(dh);
+
+ secret = XMALLOC(RFC3526_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (!secret)
+ goto done;
+
+ if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+ RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+ != 0)
+ goto done;
+
+ if (wc_DhAgree(dh, secret, &secret_sz, wpabuf_head(priv),
+ wpabuf_len(priv), RFC3526_GENERATOR_1536,
+ sizeof(RFC3526_GENERATOR_1536)) != 0)
+ goto done;
+
+ if (secret_sz != wpabuf_len(publ) ||
+ os_memcmp(secret, wpabuf_head(publ), secret_sz) != 0)
+ goto done;
+
+ ret = dh;
+ dh = NULL;
+done:
+ if (dh) {
+ wc_FreeDhKey(dh);
+ XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ }
+ XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ return ret;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+ const struct wpabuf *own_private)
+{
+ struct wpabuf *ret = NULL;
+ struct wpabuf *secret;
+ word32 secret_sz;
+
+ secret = wpabuf_alloc(RFC3526_LEN);
+ if (!secret)
+ goto done;
+
+ if (wc_DhAgree(ctx, wpabuf_mhead(secret), &secret_sz,
+ wpabuf_head(own_private), wpabuf_len(own_private),
+ wpabuf_head(peer_public), wpabuf_len(peer_public)) != 0)
+ goto done;
+
+ wpabuf_put(secret, secret_sz);
+
+ ret = secret;
+ secret = NULL;
+done:
+ wpabuf_clear_free(secret);
+ return ret;
+}
+
+
+void dh5_free(void *ctx)
+{
+ if (!ctx)
+ return;
+
+ wc_FreeDhKey(ctx);
+ XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ int ret = -1;
+ WC_RNG rng;
+ DhKey *dh = NULL;
+ word32 priv_sz, pub_sz;
+
+ if (TEST_FAIL())
+ return -1;
+
+ dh = os_malloc(sizeof(DhKey));
+ if (!dh)
+ return -1;
+ wc_InitDhKey(dh);
+
+ if (wc_InitRng(&rng) != 0) {
+ os_free(dh);
+ return -1;
+ }
+
+ if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+ goto done;
+
+ if (wc_DhGenerateKeyPair(dh, &rng, privkey, &priv_sz, pubkey, &pub_sz)
+ != 0)
+ goto done;
+
+ if (priv_sz < prime_len) {
+ size_t pad_sz = prime_len - priv_sz;
+
+ os_memmove(privkey + pad_sz, privkey, priv_sz);
+ os_memset(privkey, 0, pad_sz);
+ }
+
+ if (pub_sz < prime_len) {
+ size_t pad_sz = prime_len - pub_sz;
+
+ os_memmove(pubkey + pad_sz, pubkey, pub_sz);
+ os_memset(pubkey, 0, pad_sz);
+ }
+ ret = 0;
+done:
+ wc_FreeDhKey(dh);
+ os_free(dh);
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ int ret = -1;
+ DhKey *dh;
+ word32 secret_sz;
+
+ dh = os_malloc(sizeof(DhKey));
+ if (!dh)
+ return -1;
+ wc_InitDhKey(dh);
+
+ if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+ goto done;
+
+ if (wc_DhAgree(dh, secret, &secret_sz, privkey, privkey_len, pubkey,
+ pubkey_len) != 0)
+ goto done;
+
+ *len = secret_sz;
+ ret = 0;
+done:
+ wc_FreeDhKey(dh);
+ os_free(dh);
+ return ret;
+}
+
+
+#ifdef CONFIG_FIPS
+int crypto_get_random(void *buf, size_t len)
+{
+ int ret = 0;
+ WC_RNG rng;
+
+ if (wc_InitRng(&rng) != 0)
+ return -1;
+ if (wc_RNG_GenerateBlock(&rng, buf, len) != 0)
+ ret = -1;
+ wc_FreeRng(&rng);
+ return ret;
+}
+#endif /* CONFIG_FIPS */
+
+
+#if defined(EAP_PWD) || defined(EAP_SERVER_PWD)
+struct crypto_hash {
+ Hmac hmac;
+ int size;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ret = NULL;
+ struct crypto_hash *hash;
+ int type;
+
+ hash = os_zalloc(sizeof(*hash));
+ if (!hash)
+ goto done;
+
+ switch (alg) {
+#ifndef NO_MD5
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ hash->size = 16;
+ type = WC_MD5;
+ break;
+#endif /* NO_MD5 */
+#ifndef NO_SHA
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ type = WC_SHA;
+ hash->size = 20;
+ break;
+#endif /* NO_SHA */
+#ifdef CONFIG_SHA256
+#ifndef NO_SHA256
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ type = WC_SHA256;
+ hash->size = 32;
+ break;
+#endif /* NO_SHA256 */
+#endif /* CONFIG_SHA256 */
+ default:
+ goto done;
+ }
+
+ if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
+ goto done;
+
+ ret = hash;
+ hash = NULL;
+done:
+ os_free(hash);
+ return ret;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ if (!ctx)
+ return;
+ wc_HmacUpdate(&ctx->hmac, data, len);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ int ret = 0;
+
+ if (!ctx)
+ return -2;
+
+ if (!mac || !len)
+ goto done;
+
+ if (wc_HmacFinal(&ctx->hmac, mac) != 0) {
+ ret = -1;
+ goto done;
+ }
+
+ *len = ctx->size;
+ ret = 0;
+done:
+ bin_clear_free(ctx, sizeof(*ctx));
+ if (TEST_FAIL())
+ return -1;
+ return ret;
+}
+
+#endif
+
+
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ Cmac cmac;
+ size_t i;
+ word32 sz;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (wc_InitCmac(&cmac, key, key_len, WC_CMAC_AES, NULL) != 0)
+ return -1;
+
+ for (i = 0; i < num_elem; i++)
+ if (wc_CmacUpdate(&cmac, addr[i], len[i]) != 0)
+ return -1;
+
+ sz = AES_BLOCK_SIZE;
+ if (wc_CmacFinal(&cmac, mac, &sz) != 0 || sz != AES_BLOCK_SIZE)
+ return -1;
+
+ return 0;
+}
+
+
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
+
+
+struct crypto_bignum * crypto_bignum_init(void)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = os_malloc(sizeof(*a));
+ if (!a || mp_init(a) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = (mp_int *) crypto_bignum_init();
+ if (!a)
+ return NULL;
+
+ if (mp_read_unsigned_bin(a, buf, len) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+{
+ if (!n)
+ return;
+
+ if (clear)
+ mp_forcezero((mp_int *) n);
+ mp_clear((mp_int *) n);
+ os_free((mp_int *) n);
+}
+
+
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ u8 *buf, size_t buflen, size_t padlen)
+{
+ int num_bytes, offset;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (padlen > buflen)
+ return -1;
+
+ num_bytes = (mp_count_bits((mp_int *) a) + 7) / 8;
+ if ((size_t) num_bytes > buflen)
+ return -1;
+ if (padlen > (size_t) num_bytes)
+ offset = padlen - num_bytes;
+ else
+ offset = 0;
+
+ os_memset(buf, 0, offset);
+ mp_to_unsigned_bin((mp_int *) a, buf + offset);
+
+ return num_bytes + offset;
+}
+
+
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+ int ret = 0;
+ WC_RNG rng;
+
+ if (TEST_FAIL())
+ return -1;
+ if (wc_InitRng(&rng) != 0)
+ return -1;
+ if (mp_rand_prime((mp_int *) r,
+ (mp_count_bits((mp_int *) m) + 7) / 8 * 2,
+ &rng, NULL) != 0)
+ ret = -1;
+ if (ret == 0 &&
+ mp_mod((mp_int *) r, (mp_int *) m, (mp_int *) r) != 0)
+ ret = -1;
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+
+int crypto_bignum_add(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *r)
+{
+ return mp_add((mp_int *) a, (mp_int *) b,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mod(const struct crypto_bignum *a,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *r)
+{
+ return mp_mod((mp_int *) a, (mp_int *) m,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_exptmod(const struct crypto_bignum *b,
+ const struct crypto_bignum *e,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *r)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_exptmod((mp_int *) b, (mp_int *) e, (mp_int *) m,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *r)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_invmod((mp_int *) a, (mp_int *) m,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_sub(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *r)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_add((mp_int *) a, (mp_int *) b,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_div(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_div((mp_int *) a, (mp_int *) b, (mp_int *) d,
+ NULL) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) m,
+ (mp_int *) d) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r)
+{
+ if (mp_copy((mp_int *) a, (mp_int *) r) != MP_OKAY)
+ return -1;
+ mp_rshb((mp_int *) r, n);
+ return 0;
+}
+
+
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+ const struct crypto_bignum *b)
+{
+ return mp_cmp((mp_int *) a, (mp_int *) b);
+}
+
+
+int crypto_bignum_bits(const struct crypto_bignum *a)
+{
+ return mp_count_bits((mp_int *) a);
+}
+
+
+int crypto_bignum_is_zero(const struct crypto_bignum *a)
+{
+ return mp_iszero((mp_int *) a);
+}
+
+
+int crypto_bignum_is_one(const struct crypto_bignum *a)
+{
+ return mp_isone((const mp_int *) a);
+}
+
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+ return mp_isodd((mp_int *) a);
+}
+
+
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+ const struct crypto_bignum *p)
+{
+ mp_int t;
+ int ret;
+ int res = -2;
+
+ if (TEST_FAIL())
+ return -2;
+
+ if (mp_init(&t) != MP_OKAY)
+ return -2;
+
+ /* t = (p-1) / 2 */
+ ret = mp_sub_d((mp_int *) p, 1, &t);
+ if (ret == MP_OKAY)
+ mp_rshb(&t, 1);
+ if (ret == MP_OKAY)
+ ret = mp_exptmod((mp_int *) a, &t, (mp_int *) p, &t);
+ if (ret == MP_OKAY) {
+ if (mp_isone(&t))
+ res = 1;
+ else if (mp_iszero(&t))
+ res = 0;
+ else
+ res = -1;
+ }
+
+ mp_clear(&t);
+ return res;
+}
+
+
+#ifdef CONFIG_ECC
+
+int ecc_map(ecc_point *, mp_int *, mp_digit);
+int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R,
+ mp_int *a, mp_int *modulus, mp_digit mp);
+
+struct crypto_ec {
+ ecc_key key;
+ mp_int a;
+ mp_int prime;
+ mp_int order;
+ mp_digit mont_b;
+ mp_int b;
+};
+
+
+struct crypto_ec * crypto_ec_init(int group)
+{
+ int built = 0;
+ struct crypto_ec *e;
+ int curve_id;
+
+ /* Map from IANA registry for IKE D-H groups to OpenSSL NID */
+ switch (group) {
+ case 19:
+ curve_id = ECC_SECP256R1;
+ break;
+ case 20:
+ curve_id = ECC_SECP384R1;
+ break;
+ case 21:
+ curve_id = ECC_SECP521R1;
+ break;
+ case 25:
+ curve_id = ECC_SECP192R1;
+ break;
+ case 26:
+ curve_id = ECC_SECP224R1;
+ break;
+#ifdef HAVE_ECC_BRAINPOOL
+ case 27:
+ curve_id = ECC_BRAINPOOLP224R1;
+ break;
+ case 28:
+ curve_id = ECC_BRAINPOOLP256R1;
+ break;
+ case 29:
+ curve_id = ECC_BRAINPOOLP384R1;
+ break;
+ case 30:
+ curve_id = ECC_BRAINPOOLP512R1;
+ break;
+#endif /* HAVE_ECC_BRAINPOOL */
+ default:
+ return NULL;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (!e)
+ return NULL;
+
+ if (wc_ecc_init(&e->key) != 0 ||
+ wc_ecc_set_curve(&e->key, 0, curve_id) != 0 ||
+ mp_init(&e->a) != MP_OKAY ||
+ mp_init(&e->prime) != MP_OKAY ||
+ mp_init(&e->order) != MP_OKAY ||
+ mp_init(&e->b) != MP_OKAY ||
+ mp_read_radix(&e->a, e->key.dp->Af, 16) != MP_OKAY ||
+ mp_read_radix(&e->b, e->key.dp->Bf, 16) != MP_OKAY ||
+ mp_read_radix(&e->prime, e->key.dp->prime, 16) != MP_OKAY ||
+ mp_read_radix(&e->order, e->key.dp->order, 16) != MP_OKAY ||
+ mp_montgomery_setup(&e->prime, &e->mont_b) != MP_OKAY)
+ goto done;
+
+ built = 1;
+done:
+ if (!built) {
+ crypto_ec_deinit(e);
+ e = NULL;
+ }
+ return e;
+}
+
+
+void crypto_ec_deinit(struct crypto_ec* e)
+{
+ if (!e)
+ return;
+
+ mp_clear(&e->b);
+ mp_clear(&e->order);
+ mp_clear(&e->prime);
+ mp_clear(&e->a);
+ wc_ecc_free(&e->key);
+ os_free(e);
+}
+
+
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
+{
+ if (TEST_FAIL())
+ return NULL;
+ if (!e)
+ return NULL;
+ return (struct crypto_ec_point *) wc_ecc_new_point();
+}
+
+
+size_t crypto_ec_prime_len(struct crypto_ec *e)
+{
+ return (mp_count_bits(&e->prime) + 7) / 8;
+}
+
+
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
+{
+ return mp_count_bits(&e->prime);
+}
+
+
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+ return (mp_count_bits(&e->order) + 7) / 8;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->prime;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->order;
+}
+
+
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+ ecc_point *point = (ecc_point *) p;
+
+ if (!p)
+ return;
+
+ if (clear) {
+ mp_forcezero(point->x);
+ mp_forcezero(point->y);
+ mp_forcezero(point->z);
+ }
+ wc_ecc_del_point(point);
+}
+
+
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+ struct crypto_bignum *x)
+{
+ return mp_copy(((ecc_point *) p)->x, (mp_int *) x) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+ const struct crypto_ec_point *point, u8 *x, u8 *y)
+{
+ ecc_point *p = (ecc_point *) point;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (!mp_isone(p->z)) {
+ if (ecc_map(p, &e->prime, e->mont_b) != MP_OKAY)
+ return -1;
+ }
+
+ if (x) {
+ if (crypto_bignum_to_bin((struct crypto_bignum *)p->x, x,
+ e->key.dp->size,
+ e->key.dp->size) <= 0)
+ return -1;
+ }
+
+ if (y) {
+ if (crypto_bignum_to_bin((struct crypto_bignum *) p->y, y,
+ e->key.dp->size,
+ e->key.dp->size) <= 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+ const u8 *val)
+{
+ ecc_point *point = NULL;
+ int loaded = 0;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ point = wc_ecc_new_point();
+ if (!point)
+ goto done;
+
+ if (mp_read_unsigned_bin(point->x, val, e->key.dp->size) != MP_OKAY)
+ goto done;
+ val += e->key.dp->size;
+ if (mp_read_unsigned_bin(point->y, val, e->key.dp->size) != MP_OKAY)
+ goto done;
+ mp_set(point->z, 1);
+
+ loaded = 1;
+done:
+ if (!loaded) {
+ wc_ecc_del_point(point);
+ point = NULL;
+ }
+ return (struct crypto_ec_point *) point;
+}
+
+
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b,
+ struct crypto_ec_point *c)
+{
+ mp_int mu;
+ ecc_point *ta = NULL, *tb = NULL;
+ ecc_point *pa = (ecc_point *) a, *pb = (ecc_point *) b;
+ mp_int *modulus = &e->prime;
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = mp_init(&mu);
+ if (ret != MP_OKAY)
+ return -1;
+
+ ret = mp_montgomery_calc_normalization(&mu, modulus);
+ if (ret != MP_OKAY) {
+ mp_clear(&mu);
+ return -1;
+ }
+
+ if (!mp_isone(&mu)) {
+ ta = wc_ecc_new_point();
+ if (!ta) {
+ mp_clear(&mu);
+ return -1;
+ }
+ tb = wc_ecc_new_point();
+ if (!tb) {
+ wc_ecc_del_point(ta);
+ mp_clear(&mu);
+ return -1;
+ }
+
+ if (mp_mulmod(pa->x, &mu, modulus, ta->x) != MP_OKAY ||
+ mp_mulmod(pa->y, &mu, modulus, ta->y) != MP_OKAY ||
+ mp_mulmod(pa->z, &mu, modulus, ta->z) != MP_OKAY ||
+ mp_mulmod(pb->x, &mu, modulus, tb->x) != MP_OKAY ||
+ mp_mulmod(pb->y, &mu, modulus, tb->y) != MP_OKAY ||
+ mp_mulmod(pb->z, &mu, modulus, tb->z) != MP_OKAY) {
+ ret = -1;
+ goto end;
+ }
+ pa = ta;
+ pb = tb;
+ }
+
+ ret = ecc_projective_add_point(pa, pb, (ecc_point *) c, &e->a,
+ &e->prime, e->mont_b);
+ if (ret != 0) {
+ ret = -1;
+ goto end;
+ }
+
+ if (ecc_map((ecc_point *) c, &e->prime, e->mont_b) != MP_OKAY)
+ ret = -1;
+ else
+ ret = 0;
+end:
+ wc_ecc_del_point(tb);
+ wc_ecc_del_point(ta);
+ mp_clear(&mu);
+ return ret;
+}
+
+
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+ const struct crypto_bignum *b,
+ struct crypto_ec_point *res)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_ecc_mulmod((mp_int *) b, (ecc_point *) p, (ecc_point *) res,
+ &e->a, &e->prime, 1);
+ return ret == 0 ? 0 : -1;
+}
+
+
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+{
+ ecc_point *point = (ecc_point *) p;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (mp_sub(&e->prime, point->y, point->y) != MP_OKAY)
+ return -1;
+
+ return 0;
+}
+
+
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+ struct crypto_ec_point *p,
+ const struct crypto_bignum *x, int y_bit)
+{
+ byte buf[1 + 2 * MAX_ECC_BYTES];
+ int ret;
+ int prime_len = crypto_ec_prime_len(e);
+
+ if (TEST_FAIL())
+ return -1;
+
+ buf[0] = y_bit ? ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN;
+ ret = crypto_bignum_to_bin(x, buf + 1, prime_len, prime_len);
+ if (ret <= 0)
+ return -1;
+ ret = wc_ecc_import_point_der(buf, 1 + 2 * ret, e->key.idx,
+ (ecc_point *) p);
+ if (ret != 0)
+ return -1;
+
+ return 0;
+}
+
+
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+ const struct crypto_bignum *x)
+{
+ mp_int *y2 = NULL;
+ mp_int t;
+ int calced = 0;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ if (mp_init(&t) != MP_OKAY)
+ return NULL;
+
+ y2 = (mp_int *) crypto_bignum_init();
+ if (!y2)
+ goto done;
+
+ if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+ mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 ||
+ mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 ||
+ mp_addmod(y2, &t, &e->prime, y2) != 0 ||
+ mp_addmod(y2, &e->b, &e->prime, y2) != 0)
+ goto done;
+
+ calced = 1;
+done:
+ if (!calced) {
+ if (y2) {
+ mp_clear(y2);
+ os_free(y2);
+ }
+ mp_clear(&t);
+ }
+
+ return (struct crypto_bignum *) y2;
+}
+
+
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return wc_ecc_point_is_at_infinity((ecc_point *) p);
+}
+
+
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return wc_ecc_is_point((ecc_point *) p, &e->a, &e->b, &e->prime) ==
+ MP_OKAY;
+}
+
+
+int crypto_ec_point_cmp(const struct crypto_ec *e,
+ const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b)
+{
+ return wc_ecc_cmp_point((ecc_point *) a, (ecc_point *) b);
+}
+
+
+struct crypto_ecdh {
+ struct crypto_ec *ec;
+};
+
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+ struct crypto_ecdh *ecdh = NULL;
+ WC_RNG rng;
+ int ret;
+
+ if (wc_InitRng(&rng) != 0)
+ goto fail;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key,
+ ecdh->ec->key.dp->id);
+ if (ret < 0)
+ goto fail;
+
+done:
+ wc_FreeRng(&rng);
+
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ ecdh = NULL;
+ goto done;
+}
+
+
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
+{
+ if (ecdh) {
+ crypto_ec_deinit(ecdh->ec);
+ os_free(ecdh);
+ }
+}
+
+
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
+{
+ struct wpabuf *buf = NULL;
+ int ret;
+ int len = ecdh->ec->key.dp->size;
+
+ buf = wpabuf_alloc(inc_y ? 2 * len : len);
+ if (!buf)
+ goto fail;
+
+ ret = crypto_bignum_to_bin((struct crypto_bignum *)
+ ecdh->ec->key.pubkey.x, wpabuf_put(buf, len),
+ len, len);
+ if (ret < 0)
+ goto fail;
+ if (inc_y) {
+ ret = crypto_bignum_to_bin((struct crypto_bignum *)
+ ecdh->ec->key.pubkey.y,
+ wpabuf_put(buf, len), len, len);
+ if (ret < 0)
+ goto fail;
+ }
+
+done:
+ return buf;
+fail:
+ wpabuf_free(buf);
+ buf = NULL;
+ goto done;
+}
+
+
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+ const u8 *key, size_t len)
+{
+ int ret;
+ struct wpabuf *pubkey = NULL;
+ struct wpabuf *secret = NULL;
+ word32 key_len = ecdh->ec->key.dp->size;
+ ecc_point *point = NULL;
+ size_t need_key_len = inc_y ? 2 * key_len : key_len;
+
+ if (len < need_key_len)
+ goto fail;
+ pubkey = wpabuf_alloc(1 + 2 * key_len);
+ if (!pubkey)
+ goto fail;
+ wpabuf_put_u8(pubkey, inc_y ? ECC_POINT_UNCOMP : ECC_POINT_COMP_EVEN);
+ wpabuf_put_data(pubkey, key, need_key_len);
+
+ point = wc_ecc_new_point();
+ if (!point)
+ goto fail;
+
+ ret = wc_ecc_import_point_der(wpabuf_mhead(pubkey), 1 + 2 * key_len,
+ ecdh->ec->key.idx, point);
+ if (ret != MP_OKAY)
+ goto fail;
+
+ secret = wpabuf_alloc(key_len);
+ if (!secret)
+ goto fail;
+
+ ret = wc_ecc_shared_secret_ex(&ecdh->ec->key, point,
+ wpabuf_put(secret, key_len), &key_len);
+ if (ret != MP_OKAY)
+ goto fail;
+
+done:
+ wc_ecc_del_point(point);
+ wpabuf_free(pubkey);
+ return secret;
+fail:
+ wpabuf_free(secret);
+ secret = NULL;
+ goto done;
+}
+
+#endif /* CONFIG_ECC */
diff --git a/contrib/wpa/src/crypto/des-internal.c b/contrib/wpa/src/crypto/des-internal.c
index dec39ef..4ed6957 100644
--- a/contrib/wpa/src/crypto/des-internal.c
+++ b/contrib/wpa/src/crypto/des-internal.c
@@ -48,7 +48,7 @@
static const u32 bytebit[8] =
{
- 0200, 0100, 040, 020, 010, 04, 02, 01
+ 0200, 0100, 040, 020, 010, 04, 02, 01
};
static const u32 bigbyte[24] =
@@ -58,22 +58,22 @@ static const u32 bigbyte[24] =
0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL,
0x800UL, 0x400UL, 0x200UL, 0x100UL,
0x80UL, 0x40UL, 0x20UL, 0x10UL,
- 0x8UL, 0x4UL, 0x2UL, 0x1L
+ 0x8UL, 0x4UL, 0x2UL, 0x1L
};
/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
static const u8 pc1[56] = {
- 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
- 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
- 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
};
static const u8 totrot[16] = {
1, 2, 4, 6,
- 8, 10, 12, 14,
- 15, 17, 19, 21,
+ 8, 10, 12, 14,
+ 15, 17, 19, 21,
23, 25, 27, 28
};
@@ -396,7 +396,7 @@ static void desfunc(u32 *block, const u32 *keys)
/* wpa_supplicant/hostapd specific wrapper */
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
@@ -421,6 +421,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
os_memset(pkey, 0, sizeof(pkey));
os_memset(ek, 0, sizeof(ek));
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/dh_group5.c b/contrib/wpa/src/crypto/dh_group5.c
index ccdbfc8..425c848 100644
--- a/contrib/wpa/src/crypto/dh_group5.c
+++ b/contrib/wpa/src/crypto/dh_group5.c
@@ -15,6 +15,7 @@
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
+ wpabuf_free(*publ);
*publ = dh_init(dh_groups_get(5), priv);
if (*publ == NULL)
return NULL;
diff --git a/contrib/wpa/src/crypto/dh_groups.c b/contrib/wpa/src/crypto/dh_groups.c
index 3aeb2bb..5e421b2 100644
--- a/contrib/wpa/src/crypto/dh_groups.c
+++ b/contrib/wpa/src/crypto/dh_groups.c
@@ -1151,7 +1151,7 @@ static const u8 dh_group24_order[] = {
{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
-
+
static const struct dh_group dh_groups[] = {
DH_GROUP(5, 1),
@@ -1203,32 +1203,24 @@ struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
if (*priv == NULL)
return NULL;
- if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
- {
+ pv_len = dh->prime_len;
+ pv = wpabuf_alloc(pv_len);
+ if (pv == NULL) {
wpabuf_clear_free(*priv);
*priv = NULL;
return NULL;
}
-
- if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) {
- /* Make sure private value is smaller than prime */
- *(wpabuf_mhead_u8(*priv)) = 0;
- }
- wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
-
- pv_len = dh->prime_len;
- pv = wpabuf_alloc(pv_len);
- if (pv == NULL)
- return NULL;
- if (crypto_mod_exp(dh->generator, dh->generator_len,
- wpabuf_head(*priv), wpabuf_len(*priv),
- dh->prime, dh->prime_len, wpabuf_mhead(pv),
- &pv_len) < 0) {
+ if (crypto_dh_init(*dh->generator, dh->prime, dh->prime_len,
+ wpabuf_mhead(*priv), wpabuf_mhead(pv)) < 0) {
wpabuf_clear_free(pv);
- wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+ wpa_printf(MSG_INFO, "DH: crypto_dh_init failed");
+ wpabuf_clear_free(*priv);
+ *priv = NULL;
return NULL;
}
- wpabuf_put(pv, pv_len);
+ wpabuf_put(*priv, dh->prime_len);
+ wpabuf_put(pv, dh->prime_len);
+ wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
return pv;
@@ -1256,12 +1248,15 @@ struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
shared = wpabuf_alloc(shared_len);
if (shared == NULL)
return NULL;
- if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
- wpabuf_head(own_private), wpabuf_len(own_private),
- dh->prime, dh->prime_len,
- wpabuf_mhead(shared), &shared_len) < 0) {
+ if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
+ dh->order, dh->order_len,
+ wpabuf_head(own_private),
+ wpabuf_len(own_private),
+ wpabuf_head(peer_public),
+ wpabuf_len(peer_public),
+ wpabuf_mhead(shared), &shared_len) < 0) {
wpabuf_clear_free(shared);
- wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+ wpa_printf(MSG_INFO, "DH: crypto_dh_derive_secret failed");
return NULL;
}
wpabuf_put(shared, shared_len);
diff --git a/contrib/wpa/src/crypto/fips_prf_openssl.c b/contrib/wpa/src/crypto/fips_prf_openssl.c
index fb03efc..4697e04 100644
--- a/contrib/wpa/src/crypto/fips_prf_openssl.c
+++ b/contrib/wpa/src/crypto/fips_prf_openssl.c
@@ -17,6 +17,19 @@ static void sha1_transform(u32 *state, const u8 data[64])
{
SHA_CTX context;
os_memset(&context, 0, sizeof(context));
+#if defined(OPENSSL_IS_BORINGSSL) && !defined(ANDROID)
+ context.h[0] = state[0];
+ context.h[1] = state[1];
+ context.h[2] = state[2];
+ context.h[3] = state[3];
+ context.h[4] = state[4];
+ SHA1_Transform(&context, data);
+ state[0] = context.h[0];
+ state[1] = context.h[1];
+ state[2] = context.h[2];
+ state[3] = context.h[3];
+ state[4] = context.h[4];
+#else
context.h0 = state[0];
context.h1 = state[1];
context.h2 = state[2];
@@ -28,6 +41,7 @@ static void sha1_transform(u32 *state, const u8 data[64])
state[2] = context.h2;
state[3] = context.h3;
state[4] = context.h4;
+#endif
}
@@ -62,12 +76,11 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
/* w_i = G(t, XVAL) */
os_memcpy(_t, t, 20);
sha1_transform(_t, xkey);
- _t[0] = host_to_be32(_t[0]);
- _t[1] = host_to_be32(_t[1]);
- _t[2] = host_to_be32(_t[2]);
- _t[3] = host_to_be32(_t[3]);
- _t[4] = host_to_be32(_t[4]);
- os_memcpy(xpos, _t, 20);
+ WPA_PUT_BE32(xpos, _t[0]);
+ WPA_PUT_BE32(xpos + 4, _t[1]);
+ WPA_PUT_BE32(xpos + 8, _t[2]);
+ WPA_PUT_BE32(xpos + 12, _t[3]);
+ WPA_PUT_BE32(xpos + 16, _t[4]);
/* XKEY = (1 + XKEY + w_i) mod 2^b */
carry = 1;
diff --git a/contrib/wpa/src/crypto/fips_prf_wolfssl.c b/contrib/wpa/src/crypto/fips_prf_wolfssl.c
new file mode 100644
index 0000000..feb39db
--- /dev/null
+++ b/contrib/wpa/src/crypto/fips_prf_wolfssl.c
@@ -0,0 +1,87 @@
+/*
+ * FIPS 186-2 PRF for libcrypto
+ * Copyright (c) 2004-2017, 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 <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static void sha1_transform(u32 *state, const u8 data[64])
+{
+ wc_Sha sha;
+
+ os_memset(&sha, 0, sizeof(sha));
+ sha.digest[0] = state[0];
+ sha.digest[1] = state[1];
+ sha.digest[2] = state[2];
+ sha.digest[3] = state[3];
+ sha.digest[4] = state[4];
+ wc_ShaUpdate(&sha, data, 64);
+ state[0] = sha.digest[0];
+ state[1] = sha.digest[1];
+ state[2] = sha.digest[2];
+ state[3] = sha.digest[3];
+ state[4] = sha.digest[4];
+}
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+ u8 xkey[64];
+ u32 t[5], _t[5];
+ int i, j, m, k;
+ u8 *xpos = x;
+ u32 carry;
+
+ if (seed_len < sizeof(xkey))
+ os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+ else
+ seed_len = sizeof(xkey);
+
+ /* FIPS 186-2 + change notice 1 */
+
+ os_memcpy(xkey, seed, seed_len);
+ t[0] = 0x67452301;
+ t[1] = 0xEFCDAB89;
+ t[2] = 0x98BADCFE;
+ t[3] = 0x10325476;
+ t[4] = 0xC3D2E1F0;
+
+ m = xlen / 40;
+ for (j = 0; j < m; j++) {
+ /* XSEED_j = 0 */
+ for (i = 0; i < 2; i++) {
+ /* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+ /* w_i = G(t, XVAL) */
+ os_memcpy(_t, t, 20);
+ sha1_transform(_t, xkey);
+ WPA_PUT_BE32(xpos, _t[0]);
+ WPA_PUT_BE32(xpos + 4, _t[1]);
+ WPA_PUT_BE32(xpos + 8, _t[2]);
+ WPA_PUT_BE32(xpos + 12, _t[3]);
+ WPA_PUT_BE32(xpos + 16, _t[4]);
+
+ /* XKEY = (1 + XKEY + w_i) mod 2^b */
+ carry = 1;
+ for (k = 19; k >= 0; k--) {
+ carry += xkey[k] + xpos[k];
+ xkey[k] = carry & 0xff;
+ carry >>= 8;
+ }
+
+ xpos += 20;
+ }
+ /* x_j = w_0|w_1 */
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/md4-internal.c b/contrib/wpa/src/crypto/md4-internal.c
index cd5e6ca..cf408e8 100644
--- a/contrib/wpa/src/crypto/md4-internal.c
+++ b/contrib/wpa/src/crypto/md4-internal.c
@@ -31,6 +31,9 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
MD4_CTX ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
MD4Init(&ctx);
for (i = 0; i < num_elem; i++)
MD4Update(&ctx, addr[i], len[i]);
@@ -82,7 +85,7 @@ MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
(cp)[1] = (value) >> 8; \
(cp)[0] = (value); } while (0)
-static u8 PADDING[MD4_BLOCK_LENGTH] = {
+static const u8 PADDING[MD4_BLOCK_LENGTH] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
diff --git a/contrib/wpa/src/crypto/md5-internal.c b/contrib/wpa/src/crypto/md5-internal.c
index f0a2a5d..944698a 100644
--- a/contrib/wpa/src/crypto/md5-internal.c
+++ b/contrib/wpa/src/crypto/md5-internal.c
@@ -33,6 +33,9 @@ int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
MD5_CTX ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
MD5Init(&ctx);
for (i = 0; i < num_elem; i++)
MD5Update(&ctx, addr[i], len[i]);
diff --git a/contrib/wpa/src/crypto/ms_funcs.c b/contrib/wpa/src/crypto/ms_funcs.c
index 053d203..aff7d33 100644
--- a/contrib/wpa/src/crypto/ms_funcs.c
+++ b/contrib/wpa/src/crypto/ms_funcs.c
@@ -48,7 +48,7 @@ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
WPA_PUT_LE16(ucs2_buffer + j,
((c & 0x1F) << 6) | (c2 & 0x3F));
j += 2;
- } else if (i == utf8_string_len ||
+ } else if (i == utf8_string_len - 1 ||
j >= ucs2_buffer_size - 1) {
/* incomplete surrogate */
return -1;
@@ -140,17 +140,20 @@ int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
* @challenge: 8-octet Challenge (IN)
* @password_hash: 16-octet PasswordHash (IN)
* @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
*/
-void challenge_response(const u8 *challenge, const u8 *password_hash,
- u8 *response)
+int challenge_response(const u8 *challenge, const u8 *password_hash,
+ u8 *response)
{
u8 zpwd[7];
- des_encrypt(challenge, password_hash, response);
- des_encrypt(challenge, password_hash + 7, response + 8);
+
+ if (des_encrypt(challenge, password_hash, response) < 0 ||
+ des_encrypt(challenge, password_hash + 7, response + 8) < 0)
+ return -1;
zpwd[0] = password_hash[14];
zpwd[1] = password_hash[15];
os_memset(zpwd + 2, 0, 5);
- des_encrypt(challenge, zpwd, response + 16);
+ return des_encrypt(challenge, zpwd, response + 16);
}
@@ -175,9 +178,9 @@ int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
if (challenge_hash(peer_challenge, auth_challenge, username,
username_len, challenge) ||
- nt_password_hash(password, password_len, password_hash))
+ nt_password_hash(password, password_len, password_hash) ||
+ challenge_response(challenge, password_hash, response))
return -1;
- challenge_response(challenge, password_hash, response);
return 0;
}
@@ -202,9 +205,9 @@ int generate_nt_response_pwhash(const u8 *auth_challenge,
if (challenge_hash(peer_challenge, auth_challenge,
username, username_len,
- challenge))
+ challenge) ||
+ challenge_response(challenge, password_hash, response))
return -1;
- challenge_response(challenge, password_hash, response);
return 0;
}
@@ -304,9 +307,10 @@ int nt_challenge_response(const u8 *challenge, const u8 *password,
size_t password_len, u8 *response)
{
u8 password_hash[16];
- if (nt_password_hash(password, password_len, password_hash))
+
+ if (nt_password_hash(password, password_len, password_hash) ||
+ challenge_response(challenge, password_hash, response))
return -1;
- challenge_response(challenge, password_hash, response);
return 0;
}
@@ -487,12 +491,15 @@ int new_password_encrypted_with_old_nt_password_hash(
* @password_hash: 16-octer PasswordHash (IN)
* @block: 16-octet Block (IN)
* @cypher: 16-octer Cypher (OUT)
+ * Returns: 0 on success, -1 on failure
*/
-void nt_password_hash_encrypted_with_block(const u8 *password_hash,
- const u8 *block, u8 *cypher)
+int nt_password_hash_encrypted_with_block(const u8 *password_hash,
+ const u8 *block, u8 *cypher)
{
- des_encrypt(password_hash, block, cypher);
- des_encrypt(password_hash + 8, block + 7, cypher + 8);
+ if (des_encrypt(password_hash, block, cypher) < 0 ||
+ des_encrypt(password_hash + 8, block + 7, cypher + 8) < 0)
+ return -1;
+ return 0;
}
@@ -515,10 +522,10 @@ int old_nt_password_hash_encrypted_with_new_nt_password_hash(
if (nt_password_hash(old_password, old_password_len,
old_password_hash) ||
nt_password_hash(new_password, new_password_len,
- new_password_hash))
+ new_password_hash) ||
+ nt_password_hash_encrypted_with_block(old_password_hash,
+ new_password_hash,
+ encrypted_password_hash))
return -1;
- nt_password_hash_encrypted_with_block(old_password_hash,
- new_password_hash,
- encrypted_password_hash);
return 0;
}
diff --git a/contrib/wpa/src/crypto/ms_funcs.h b/contrib/wpa/src/crypto/ms_funcs.h
index b5b5918..b8d55f0 100644
--- a/contrib/wpa/src/crypto/ms_funcs.h
+++ b/contrib/wpa/src/crypto/ms_funcs.h
@@ -31,8 +31,8 @@ int generate_authenticator_response_pwhash(
int nt_challenge_response(const u8 *challenge, const u8 *password,
size_t password_len, u8 *response);
-void challenge_response(const u8 *challenge, const u8 *password_hash,
- u8 *response);
+int challenge_response(const u8 *challenge, const u8 *password_hash,
+ u8 *response);
int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
const u8 *username, size_t username_len, u8 *challenge);
int nt_password_hash(const u8 *password, size_t password_len,
@@ -50,8 +50,8 @@ int __must_check new_password_encrypted_with_old_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_pw_block);
-void nt_password_hash_encrypted_with_block(const u8 *password_hash,
- const u8 *block, u8 *cypher);
+int nt_password_hash_encrypted_with_block(const u8 *password_hash,
+ const u8 *block, u8 *cypher);
int old_nt_password_hash_encrypted_with_new_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
diff --git a/contrib/wpa/src/crypto/random.c b/contrib/wpa/src/crypto/random.c
index 3a86a93..1cabf3f 100644
--- a/contrib/wpa/src/crypto/random.c
+++ b/contrib/wpa/src/crypto/random.c
@@ -25,6 +25,9 @@
#include "utils/includes.h"
#ifdef __linux__
#include <fcntl.h>
+#ifdef CONFIG_GETRANDOM
+#include <sys/random.h>
+#endif /* CONFIG_GETRANDOM */
#endif /* __linux__ */
#include "utils/common.h"
@@ -54,7 +57,6 @@ static int random_fd = -1;
static unsigned int own_pool_ready = 0;
#define RANDOM_ENTROPY_SIZE 20
static char *random_entropy_file = NULL;
-static int random_entropy_file_read = 0;
#define MIN_COLLECT_ENTROPY 1000
static unsigned int entropy = 0;
@@ -66,6 +68,9 @@ static void random_write_entropy(void);
static u32 __ROL32(u32 x, u32 y)
{
+ if (y == 0)
+ return x;
+
return (x << (y & 31)) | (x >> (32 - (y & 31)));
}
@@ -226,30 +231,52 @@ int random_pool_ready(void)
return 1; /* Already initialized - good to continue */
/*
- * Try to fetch some more data from the kernel high quality
- * /dev/random. There may not be enough data available at this point,
+ * Try to fetch some more data from the kernel high quality RNG.
+ * There may not be enough data available at this point,
* so use non-blocking read to avoid blocking the application
* completely.
*/
- fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(errno));
- return -1;
- }
- res = read(fd, dummy_key + dummy_key_avail,
- sizeof(dummy_key) - dummy_key_avail);
+#ifdef CONFIG_GETRANDOM
+ res = getrandom(dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK);
if (res < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
- "%s", strerror(errno));
- res = 0;
+ if (errno == ENOSYS) {
+ wpa_printf(MSG_DEBUG,
+ "random: getrandom() not supported, falling back to /dev/random");
+ } else {
+ wpa_printf(MSG_INFO,
+ "random: no data from getrandom(): %s",
+ strerror(errno));
+ res = 0;
+ }
}
- wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
- "/dev/random", (unsigned) res,
+#else /* CONFIG_GETRANDOM */
+ res = -1;
+#endif /* CONFIG_GETRANDOM */
+ if (res < 0) {
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ wpa_printf(MSG_ERROR,
+ "random: Cannot open /dev/random: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ res = read(fd, dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "random: Cannot read from /dev/random: %s",
+ strerror(errno));
+ res = 0;
+ }
+ close(fd);
+ }
+
+ wpa_printf(MSG_DEBUG, "random: Got %u/%u random bytes", (unsigned) res,
(unsigned) (sizeof(dummy_key) - dummy_key_avail));
dummy_key_avail += res;
- close(fd);
if (dummy_key_avail == sizeof(dummy_key)) {
if (own_pool_ready < MIN_READY_MARK)
@@ -259,7 +286,7 @@ int random_pool_ready(void)
}
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
- "random data available from /dev/random",
+ "random data available",
(unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
if (own_pool_ready >= MIN_READY_MARK ||
@@ -354,7 +381,6 @@ static void random_read_entropy(void)
own_pool_ready = (u8) buf[0];
random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
- random_entropy_file_read = 1;
os_free(buf);
wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
"(own_pool_ready=%u)",
@@ -412,6 +438,19 @@ void random_init(const char *entropy_file)
if (random_fd >= 0)
return;
+#ifdef CONFIG_GETRANDOM
+ {
+ u8 dummy;
+
+ if (getrandom(&dummy, 0, GRND_NONBLOCK) == 0 ||
+ errno != ENOSYS) {
+ wpa_printf(MSG_DEBUG,
+ "random: getrandom() support available");
+ return;
+ }
+ }
+#endif /* CONFIG_GETRANDOM */
+
random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (random_fd < 0) {
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
diff --git a/contrib/wpa/src/crypto/sha1-internal.c b/contrib/wpa/src/crypto/sha1-internal.c
index 24bc3ff..a491707 100644
--- a/contrib/wpa/src/crypto/sha1-internal.c
+++ b/contrib/wpa/src/crypto/sha1-internal.c
@@ -33,6 +33,9 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
SHA1_CTX ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
SHA1Init(&ctx);
for (i = 0; i < num_elem; i++)
SHA1Update(&ctx, addr[i], len[i]);
@@ -50,7 +53,7 @@ By Steve Reid <sreid@sea-to-sky.net>
100% Public Domain
-----------------
-Modified 7/98
+Modified 7/98
By James H. Brown <jbrown@burgoyne.com>
Still 100% Public Domain
@@ -72,7 +75,7 @@ Since the file IO in main() reads 16K at a time, any file 8K or larger would
be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
"a"s).
-I also changed the declaration of variables i & j in SHA1Update to
+I also changed the declaration of variables i & j in SHA1Update to
unsigned long from unsigned int for the same reason.
These changes should make no difference to any 32 bit implementations since
@@ -99,7 +102,7 @@ Still 100% public domain
Modified 4/01
By Saul Kravitz <Saul.Kravitz@celera.com>
Still 100% PD
-Modified to run on Compaq Alpha hardware.
+Modified to run on Compaq Alpha hardware.
-----------------
Modified 4/01
@@ -159,7 +162,7 @@ void SHAPrintContext(SHA1_CTX *context, char *msg)
{
printf("%s (%d,%d) %x %x %x %x %x\n",
msg,
- context->count[0], context->count[1],
+ context->count[0], context->count[1],
context->state[0],
context->state[1],
context->state[2],
@@ -294,7 +297,6 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
255);
}
/* Wipe variables */
- i = 0;
os_memset(context->buffer, 0, 64);
os_memset(context->state, 0, 20);
os_memset(context->count, 0, 8);
diff --git a/contrib/wpa/src/crypto/sha1-tlsprf.c b/contrib/wpa/src/crypto/sha1-tlsprf.c
index f9bc0eb..a11649a 100644
--- a/contrib/wpa/src/crypto/sha1-tlsprf.c
+++ b/contrib/wpa/src/crypto/sha1-tlsprf.c
@@ -40,9 +40,6 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
const unsigned char *SHA1_addr[3];
size_t SHA1_len[3];
- if (secret_len & 1)
- return -1;
-
MD5_addr[0] = A_MD5;
MD5_len[0] = MD5_MAC_LEN;
MD5_addr[1] = (unsigned char *) label;
diff --git a/contrib/wpa/src/crypto/sha256-internal.c b/contrib/wpa/src/crypto/sha256-internal.c
index 35299b0..ff1e2ba1 100644
--- a/contrib/wpa/src/crypto/sha256-internal.c
+++ b/contrib/wpa/src/crypto/sha256-internal.c
@@ -28,6 +28,9 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
struct sha256_state ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
sha256_init(&ctx);
for (i = 0; i < num_elem; i++)
if (sha256_process(&ctx, addr[i], len[i]))
@@ -66,7 +69,7 @@ static const unsigned long K[64] = {
( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
-#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x), (n))
#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
@@ -97,7 +100,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf)
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
W[i - 16];
- }
+ }
/* Compress */
#define RND(a,b,c,d,e,f,g,h,i) \
@@ -108,7 +111,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf)
for (i = 0; i < 64; ++i) {
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
- t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
}
diff --git a/contrib/wpa/src/crypto/sha256-kdf.c b/contrib/wpa/src/crypto/sha256-kdf.c
index e7509ce..af7d954 100644
--- a/contrib/wpa/src/crypto/sha256-kdf.c
+++ b/contrib/wpa/src/crypto/sha256-kdf.c
@@ -1,6 +1,6 @@
/*
- * HMAC-SHA256 KDF (RFC 5295)
- * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ * HMAC-SHA256 KDF (RFC 5295) and HKDF-Expand(SHA256) (RFC 5869)
+ * Copyright (c) 2014-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -16,7 +16,8 @@
* hmac_sha256_kdf - HMAC-SHA256 based KDF (RFC 5295)
* @secret: Key for KDF
* @secret_len: Length of the key in bytes
- * @label: A unique label for each purpose of the KDF
+ * @label: A unique label for each purpose of the KDF or %NULL to select
+ * RFC 5869 HKDF-Expand() with arbitrary seed (= info)
* @seed: Seed value to bind into the key
* @seed_len: Length of the seed
* @out: Buffer for the generated pseudo-random key
@@ -24,7 +25,9 @@
* Returns: 0 on success, -1 on failure.
*
* This function is used to derive new, cryptographically separate keys from a
- * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2.
+ * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used
+ * with label = NULL and seed = info, this matches HKDF-Expand() defined in
+ * RFC 5869, Chapter 2.3.
*/
int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
@@ -38,8 +41,13 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
addr[0] = T;
len[0] = SHA256_MAC_LEN;
- addr[1] = (const unsigned char *) label;
- len[1] = os_strlen(label) + 1;
+ if (label) {
+ addr[1] = (const unsigned char *) label;
+ len[1] = os_strlen(label) + 1;
+ } else {
+ addr[1] = (const u8 *) "";
+ len[1] = 0;
+ }
addr[2] = seed;
len[2] = seed_len;
addr[3] = &iter;
diff --git a/contrib/wpa/src/crypto/sha256-prf.c b/contrib/wpa/src/crypto/sha256-prf.c
index 79791c0..722cad6 100644
--- a/contrib/wpa/src/crypto/sha256-prf.c
+++ b/contrib/wpa/src/crypto/sha256-prf.c
@@ -1,6 +1,6 @@
/*
* SHA256-based PRF (IEEE 802.11r)
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,14 +22,16 @@
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key.
*/
-void sha256_prf(const u8 *key, size_t key_len, const char *label,
+int sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
- sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+ return sha256_prf_bits(key, key_len, label, data, data_len, buf,
+ buf_len * 8);
}
@@ -42,15 +44,16 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label,
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bits of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key. If the requested buf_len is not divisible by eight, the least
* significant 1-7 bits of the last octet in the output are not part of the
* requested output.
*/
-void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits)
+int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
{
u16 counter = 1;
size_t pos, plen;
@@ -75,11 +78,14 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
plen = buf_len - pos;
WPA_PUT_LE16(counter_le, counter);
if (plen >= SHA256_MAC_LEN) {
- hmac_sha256_vector(key, key_len, 4, addr, len,
- &buf[pos]);
+ if (hmac_sha256_vector(key, key_len, 4, addr, len,
+ &buf[pos]) < 0)
+ return -1;
pos += SHA256_MAC_LEN;
} else {
- hmac_sha256_vector(key, key_len, 4, addr, len, hash);
+ if (hmac_sha256_vector(key, key_len, 4, addr, len,
+ hash) < 0)
+ return -1;
os_memcpy(&buf[pos], hash, plen);
pos += plen;
break;
@@ -97,4 +103,6 @@ void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
}
os_memset(hash, 0, sizeof(hash));
+
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/sha256.h b/contrib/wpa/src/crypto/sha256.h
index b15f511..5219022 100644
--- a/contrib/wpa/src/crypto/sha256.h
+++ b/contrib/wpa/src/crypto/sha256.h
@@ -1,6 +1,6 @@
/*
* SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,11 +15,11 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
-void sha256_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
-void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits);
+int sha256_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
void tls_prf_sha256(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
diff --git a/contrib/wpa/src/crypto/sha384-internal.c b/contrib/wpa/src/crypto/sha384-internal.c
new file mode 100644
index 0000000..646f729
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384-internal.c
@@ -0,0 +1,92 @@
+/*
+ * SHA-384 hash implementation and interface functions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384_i.h"
+#include "crypto.h"
+
+
+/**
+ * sha384_vector - SHA384 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ struct sha384_state ctx;
+ size_t i;
+
+ sha384_init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ if (sha384_process(&ctx, addr[i], len[i]))
+ return -1;
+ if (sha384_done(&ctx, mac))
+ return -1;
+ return 0;
+}
+
+
+/* ===== start - public domain SHA384 implementation ===== */
+
+/* This is based on SHA384 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define CONST64(n) n ## ULL
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+void sha384_init(struct sha384_state *md)
+{
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = CONST64(0xcbbb9d5dc1059ed8);
+ md->state[1] = CONST64(0x629a292a367cd507);
+ md->state[2] = CONST64(0x9159015a3070dd17);
+ md->state[3] = CONST64(0x152fecd8f70e5939);
+ md->state[4] = CONST64(0x67332667ffc00b31);
+ md->state[5] = CONST64(0x8eb44a8768581511);
+ md->state[6] = CONST64(0xdb0c2e0d64f98fa7);
+ md->state[7] = CONST64(0x47b5481dbefa4fa4);
+}
+
+int sha384_process(struct sha384_state *md, const unsigned char *in,
+ unsigned long inlen)
+{
+ return sha512_process(md, in, inlen);
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (48 bytes)
+ @return CRYPT_OK if successful
+*/
+int sha384_done(struct sha384_state *md, unsigned char *out)
+{
+ unsigned char buf[64];
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ if (sha512_done(md, buf) != 0)
+ return -1;
+
+ os_memcpy(out, buf, 48);
+ return 0;
+}
+
+/* ===== end - public domain SHA384 implementation ===== */
diff --git a/contrib/wpa/src/crypto/sha384-kdf.c b/contrib/wpa/src/crypto/sha384-kdf.c
new file mode 100644
index 0000000..1d19627
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384-kdf.c
@@ -0,0 +1,87 @@
+/*
+ * HMAC-SHA384 KDF (RFC 5295) and HKDF-Expand(SHA384) (RFC 5869)
+ * Copyright (c) 2014-2017, 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 "sha384.h"
+
+
+/**
+ * hmac_sha384_kdf - HMAC-SHA384 based KDF (RFC 5295)
+ * @secret: Key for KDF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF or %NULL to select
+ * RFC 5869 HKDF-Expand() with arbitrary seed (= info)
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used
+ * with label = NULL and seed = info, this matches HKDF-Expand() defined in
+ * RFC 5869, Chapter 2.3.
+ */
+int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen)
+{
+ u8 T[SHA384_MAC_LEN];
+ u8 iter = 1;
+ const unsigned char *addr[4];
+ size_t len[4];
+ size_t pos, clen;
+
+ addr[0] = T;
+ len[0] = SHA384_MAC_LEN;
+ if (label) {
+ addr[1] = (const unsigned char *) label;
+ len[1] = os_strlen(label) + 1;
+ } else {
+ addr[1] = (const u8 *) "";
+ len[1] = 0;
+ }
+ addr[2] = seed;
+ len[2] = seed_len;
+ addr[3] = &iter;
+ len[3] = 1;
+
+ if (hmac_sha384_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
+ return -1;
+
+ pos = 0;
+ for (;;) {
+ clen = outlen - pos;
+ if (clen > SHA384_MAC_LEN)
+ clen = SHA384_MAC_LEN;
+ os_memcpy(out + pos, T, clen);
+ pos += clen;
+
+ if (pos == outlen)
+ break;
+
+ if (iter == 255) {
+ os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA384_MAC_LEN);
+ return -1;
+ }
+ iter++;
+
+ if (hmac_sha384_vector(secret, secret_len, 4, addr, len, T) < 0)
+ {
+ os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA384_MAC_LEN);
+ return -1;
+ }
+ }
+
+ os_memset(T, 0, SHA384_MAC_LEN);
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/sha384-prf.c b/contrib/wpa/src/crypto/sha384-prf.c
index 653920b..03e3cb3 100644
--- a/contrib/wpa/src/crypto/sha384-prf.c
+++ b/contrib/wpa/src/crypto/sha384-prf.c
@@ -1,6 +1,6 @@
/*
* SHA384-based KDF (IEEE 802.11ac)
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,14 +22,16 @@
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key.
*/
-void sha384_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+int sha384_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
- sha384_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+ return sha384_prf_bits(key, key_len, label, data, data_len, buf,
+ buf_len * 8);
}
@@ -42,15 +44,16 @@ void sha384_prf(const u8 *key, size_t key_len, const char *label,
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bits of key to generate
+ * Returns: 0 on success, -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key. If the requested buf_len is not divisible by eight, the least
* significant 1-7 bits of the last octet in the output are not part of the
* requested output.
*/
-void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits)
+int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
{
u16 counter = 1;
size_t pos, plen;
@@ -75,11 +78,14 @@ void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
plen = buf_len - pos;
WPA_PUT_LE16(counter_le, counter);
if (plen >= SHA384_MAC_LEN) {
- hmac_sha384_vector(key, key_len, 4, addr, len,
- &buf[pos]);
+ if (hmac_sha384_vector(key, key_len, 4, addr, len,
+ &buf[pos]) < 0)
+ return -1;
pos += SHA384_MAC_LEN;
} else {
- hmac_sha384_vector(key, key_len, 4, addr, len, hash);
+ if (hmac_sha384_vector(key, key_len, 4, addr, len,
+ hash) < 0)
+ return -1;
os_memcpy(&buf[pos], hash, plen);
pos += plen;
break;
@@ -97,4 +103,6 @@ void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
}
os_memset(hash, 0, sizeof(hash));
+
+ return 0;
}
diff --git a/contrib/wpa/src/crypto/sha384.c b/contrib/wpa/src/crypto/sha384.c
new file mode 100644
index 0000000..ee136ce
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-384 hash implementation and interface functions
+ * Copyright (c) 2003-2017, 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 "sha384.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha384_vector - HMAC-SHA384 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
+ unsigned char tk[48];
+ const u8 *_addr[6];
+ size_t _len[6], i;
+
+ if (num_elem > 5) {
+ /*
+ * Fixed limit on the number of fragments to avoid having to
+ * allocate memory (which could fail).
+ */
+ return -1;
+ }
+
+ /* if key is longer than 128 bytes reset it to key = SHA384(key) */
+ if (key_len > 128) {
+ if (sha384_vector(1, &key, &key_len, tk) < 0)
+ return -1;
+ key = tk;
+ key_len = 48;
+ }
+
+ /* the HMAC_SHA384 transform looks like:
+ *
+ * SHA384(K XOR opad, SHA384(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 128 times
+ * opad is the byte 0x5c repeated 128 times
+ * and text is the data being protected */
+
+ /* start out by storing key in ipad */
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with ipad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x36;
+
+ /* perform inner SHA384 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ for (i = 0; i < num_elem; i++) {
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
+ }
+ if (sha384_vector(1 + num_elem, _addr, _len, mac) < 0)
+ return -1;
+
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with opad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x5c;
+
+ /* perform outer SHA384 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ _addr[1] = mac;
+ _len[1] = SHA384_MAC_LEN;
+ return sha384_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha384 - HMAC-SHA384 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/contrib/wpa/src/crypto/sha384.h b/contrib/wpa/src/crypto/sha384.h
index 3deafa5..2241425 100644
--- a/contrib/wpa/src/crypto/sha384.h
+++ b/contrib/wpa/src/crypto/sha384.h
@@ -1,6 +1,6 @@
/*
* SHA384 hash implementation and interface functions
- * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,10 +15,13 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
-void sha384_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
-void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf,
- size_t buf_len_bits);
+int sha384_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
+int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
#endif /* SHA384_H */
diff --git a/contrib/wpa/src/crypto/sha384_i.h b/contrib/wpa/src/crypto/sha384_i.h
new file mode 100644
index 0000000..a00253f
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha384_i.h
@@ -0,0 +1,23 @@
+/*
+ * SHA-384 internal definitions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA384_I_H
+#define SHA384_I_H
+
+#include "sha512_i.h"
+
+#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE
+
+#define sha384_state sha512_state
+
+void sha384_init(struct sha384_state *md);
+int sha384_process(struct sha384_state *md, const unsigned char *in,
+ unsigned long inlen);
+int sha384_done(struct sha384_state *md, unsigned char *out);
+
+#endif /* SHA384_I_H */
diff --git a/contrib/wpa/src/crypto/sha512-internal.c b/contrib/wpa/src/crypto/sha512-internal.c
new file mode 100644
index 0000000..c026394
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512-internal.c
@@ -0,0 +1,270 @@
+/*
+ * SHA-512 hash implementation and interface functions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha512_i.h"
+#include "crypto.h"
+
+
+/**
+ * sha512_vector - SHA512 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ struct sha512_state ctx;
+ size_t i;
+
+ sha512_init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ if (sha512_process(&ctx, addr[i], len[i]))
+ return -1;
+ if (sha512_done(&ctx, mac))
+ return -1;
+ return 0;
+}
+
+
+/* ===== start - public domain SHA512 implementation ===== */
+
+/* This is based on SHA512 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define CONST64(n) n ## ULL
+
+/* the K array */
+static const u64 K[80] = {
+ CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
+ CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
+ CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
+ CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
+ CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
+ CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
+ CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
+ CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
+ CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
+ CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
+ CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
+ CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
+ CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
+ CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
+ CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
+ CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
+ CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
+ CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
+ CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
+ CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
+ CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
+ CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
+ CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
+ CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
+ CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
+ CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
+ CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
+ CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
+ CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
+ CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
+ CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
+ CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
+ CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
+ CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
+ CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
+ CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
+ CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
+ CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
+ CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
+ CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)
+};
+
+/* Various logical functions */
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) ROR64c(x, n)
+#define R(x, n) (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) n))
+#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
+#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
+#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
+#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+#define ROR64c(x, y) \
+ ( ((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) (y) & CONST64(63))) | \
+ ((x) << ((u64) (64 - ((y) & CONST64(63)))))) & \
+ CONST64(0xFFFFFFFFFFFFFFFF))
+
+/* compress 1024-bits */
+static int sha512_compress(struct sha512_state *md, unsigned char *buf)
+{
+ u64 S[8], t0, t1;
+ u64 *W;
+ int i;
+
+ W = os_malloc(80 * sizeof(u64));
+ if (!W)
+ return -1;
+
+ /* copy state into S */
+ for (i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+
+ /* copy the state into 1024-bits into W[0..15] */
+ for (i = 0; i < 16; i++)
+ W[i] = WPA_GET_BE64(buf + (8 * i));
+
+ /* fill W[16..79] */
+ for (i = 16; i < 80; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+ W[i - 16];
+ }
+
+ /* Compress */
+ for (i = 0; i < 80; i++) {
+ t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i];
+ t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]);
+ S[7] = S[6];
+ S[6] = S[5];
+ S[5] = S[4];
+ S[4] = S[3] + t0;
+ S[3] = S[2];
+ S[2] = S[1];
+ S[1] = S[0];
+ S[0] = t0 + t1;
+ }
+
+ /* feedback */
+ for (i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+
+ os_free(W);
+ return 0;
+}
+
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+void sha512_init(struct sha512_state *md)
+{
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = CONST64(0x6a09e667f3bcc908);
+ md->state[1] = CONST64(0xbb67ae8584caa73b);
+ md->state[2] = CONST64(0x3c6ef372fe94f82b);
+ md->state[3] = CONST64(0xa54ff53a5f1d36f1);
+ md->state[4] = CONST64(0x510e527fade682d1);
+ md->state[5] = CONST64(0x9b05688c2b3e6c1f);
+ md->state[6] = CONST64(0x1f83d9abfb41bd6b);
+ md->state[7] = CONST64(0x5be0cd19137e2179);
+}
+
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+int sha512_process(struct sha512_state *md, const unsigned char *in,
+ unsigned long inlen)
+{
+ unsigned long n;
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= SHA512_BLOCK_SIZE) {
+ if (sha512_compress(md, (unsigned char *) in) < 0)
+ return -1;
+ md->length += SHA512_BLOCK_SIZE * 8;
+ in += SHA512_BLOCK_SIZE;
+ inlen -= SHA512_BLOCK_SIZE;
+ } else {
+ n = MIN(inlen, (SHA512_BLOCK_SIZE - md->curlen));
+ os_memcpy(md->buf + md->curlen, in, n);
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == SHA512_BLOCK_SIZE) {
+ if (sha512_compress(md, md->buf) < 0)
+ return -1;
+ md->length += 8 * SHA512_BLOCK_SIZE;
+ md->curlen = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (64 bytes)
+ @return CRYPT_OK if successful
+*/
+int sha512_done(struct sha512_state *md, unsigned char *out)
+{
+ int i;
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ /* increase the length of the message */
+ md->length += md->curlen * CONST64(8);
+
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char) 0x80;
+
+ /* if the length is currently above 112 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 112) {
+ while (md->curlen < 128) {
+ md->buf[md->curlen++] = (unsigned char) 0;
+ }
+ sha512_compress(md, md->buf);
+ md->curlen = 0;
+ }
+
+ /* pad up to 120 bytes of zeroes
+ * note: that from 112 to 120 is the 64 MSB of the length. We assume
+ * that you won't hash > 2^64 bits of data... :-)
+ */
+ while (md->curlen < 120) {
+ md->buf[md->curlen++] = (unsigned char) 0;
+ }
+
+ /* store length */
+ WPA_PUT_BE64(md->buf + 120, md->length);
+ sha512_compress(md, md->buf);
+
+ /* copy output */
+ for (i = 0; i < 8; i++)
+ WPA_PUT_BE64(out + (8 * i), md->state[i]);
+
+ return 0;
+}
+
+/* ===== end - public domain SHA512 implementation ===== */
diff --git a/contrib/wpa/src/crypto/sha512-kdf.c b/contrib/wpa/src/crypto/sha512-kdf.c
new file mode 100644
index 0000000..8b71f9b
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512-kdf.c
@@ -0,0 +1,87 @@
+/*
+ * HMAC-SHA512 KDF (RFC 5295) and HKDF-Expand(SHA512) (RFC 5869)
+ * Copyright (c) 2014-2017, 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 "sha512.h"
+
+
+/**
+ * hmac_sha512_kdf - HMAC-SHA512 based KDF (RFC 5295)
+ * @secret: Key for KDF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF or %NULL to select
+ * RFC 5869 HKDF-Expand() with arbitrary seed (= info)
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used
+ * with label = NULL and seed = info, this matches HKDF-Expand() defined in
+ * RFC 5869, Chapter 2.3.
+ */
+int hmac_sha512_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen)
+{
+ u8 T[SHA512_MAC_LEN];
+ u8 iter = 1;
+ const unsigned char *addr[4];
+ size_t len[4];
+ size_t pos, clen;
+
+ addr[0] = T;
+ len[0] = SHA512_MAC_LEN;
+ if (label) {
+ addr[1] = (const unsigned char *) label;
+ len[1] = os_strlen(label) + 1;
+ } else {
+ addr[1] = (const u8 *) "";
+ len[1] = 0;
+ }
+ addr[2] = seed;
+ len[2] = seed_len;
+ addr[3] = &iter;
+ len[3] = 1;
+
+ if (hmac_sha512_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
+ return -1;
+
+ pos = 0;
+ for (;;) {
+ clen = outlen - pos;
+ if (clen > SHA512_MAC_LEN)
+ clen = SHA512_MAC_LEN;
+ os_memcpy(out + pos, T, clen);
+ pos += clen;
+
+ if (pos == outlen)
+ break;
+
+ if (iter == 255) {
+ os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA512_MAC_LEN);
+ return -1;
+ }
+ iter++;
+
+ if (hmac_sha512_vector(secret, secret_len, 4, addr, len, T) < 0)
+ {
+ os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA512_MAC_LEN);
+ return -1;
+ }
+ }
+
+ os_memset(T, 0, SHA512_MAC_LEN);
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/sha512-prf.c b/contrib/wpa/src/crypto/sha512-prf.c
new file mode 100644
index 0000000..3b2ad88
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512-prf.c
@@ -0,0 +1,108 @@
+/*
+ * SHA512-based KDF (IEEE 802.11ac)
+ * Copyright (c) 2003-2017, 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 "sha512.h"
+#include "crypto.h"
+
+
+/**
+ * sha512_prf - SHA512-based Key derivation function (IEEE 802.11ac, 11.6.1.7.2)
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key.
+ */
+int sha512_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+ return sha512_prf_bits(key, key_len, label, data, data_len, buf,
+ buf_len * 8);
+}
+
+
+/**
+ * sha512_prf_bits - IEEE Std 802.11ac-2013, 11.6.1.7.2 Key derivation function
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bits of key to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key. If the requested buf_len is not divisible by eight, the least
+ * significant 1-7 bits of the last octet in the output are not part of the
+ * requested output.
+ */
+int sha512_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
+{
+ u16 counter = 1;
+ size_t pos, plen;
+ u8 hash[SHA512_MAC_LEN];
+ const u8 *addr[4];
+ size_t len[4];
+ u8 counter_le[2], length_le[2];
+ size_t buf_len = (buf_len_bits + 7) / 8;
+
+ addr[0] = counter_le;
+ len[0] = 2;
+ addr[1] = (u8 *) label;
+ len[1] = os_strlen(label);
+ addr[2] = data;
+ len[2] = data_len;
+ addr[3] = length_le;
+ len[3] = sizeof(length_le);
+
+ WPA_PUT_LE16(length_le, buf_len_bits);
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ WPA_PUT_LE16(counter_le, counter);
+ if (plen >= SHA512_MAC_LEN) {
+ if (hmac_sha512_vector(key, key_len, 4, addr, len,
+ &buf[pos]) < 0)
+ return -1;
+ pos += SHA512_MAC_LEN;
+ } else {
+ if (hmac_sha512_vector(key, key_len, 4, addr, len,
+ hash) < 0)
+ return -1;
+ os_memcpy(&buf[pos], hash, plen);
+ pos += plen;
+ break;
+ }
+ counter++;
+ }
+
+ /*
+ * Mask out unused bits in the last octet if it does not use all the
+ * bits.
+ */
+ if (buf_len_bits % 8) {
+ u8 mask = 0xff << (8 - buf_len_bits % 8);
+ buf[pos - 1] &= mask;
+ }
+
+ os_memset(hash, 0, sizeof(hash));
+
+ return 0;
+}
diff --git a/contrib/wpa/src/crypto/sha512.c b/contrib/wpa/src/crypto/sha512.c
new file mode 100644
index 0000000..66311c3
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-512 hash implementation and interface functions
+ * Copyright (c) 2003-2018, 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 "sha512.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha512_vector - HMAC-SHA512 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (64 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
+ unsigned char tk[64];
+ const u8 *_addr[6];
+ size_t _len[6], i;
+
+ if (num_elem > 5) {
+ /*
+ * Fixed limit on the number of fragments to avoid having to
+ * allocate memory (which could fail).
+ */
+ return -1;
+ }
+
+ /* if key is longer than 128 bytes reset it to key = SHA512(key) */
+ if (key_len > 128) {
+ if (sha512_vector(1, &key, &key_len, tk) < 0)
+ return -1;
+ key = tk;
+ key_len = 64;
+ }
+
+ /* the HMAC_SHA512 transform looks like:
+ *
+ * SHA512(K XOR opad, SHA512(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 128 times
+ * opad is the byte 0x5c repeated 128 times
+ * and text is the data being protected */
+
+ /* start out by storing key in ipad */
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with ipad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x36;
+
+ /* perform inner SHA512 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ for (i = 0; i < num_elem; i++) {
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
+ }
+ if (sha512_vector(1 + num_elem, _addr, _len, mac) < 0)
+ return -1;
+
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with opad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x5c;
+
+ /* perform outer SHA512 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ _addr[1] = mac;
+ _len[1] = SHA512_MAC_LEN;
+ return sha512_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha512 - HMAC-SHA512 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (64 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/contrib/wpa/src/crypto/sha512.h b/contrib/wpa/src/crypto/sha512.h
new file mode 100644
index 0000000..8e64c8b
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512.h
@@ -0,0 +1,27 @@
+/*
+ * SHA512 hash implementation and interface functions
+ * Copyright (c) 2015-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA512_H
+#define SHA512_H
+
+#define SHA512_MAC_LEN 64
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac);
+int sha512_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha512_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
+int hmac_sha512_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
+
+#endif /* SHA512_H */
diff --git a/contrib/wpa/src/crypto/sha512_i.h b/contrib/wpa/src/crypto/sha512_i.h
new file mode 100644
index 0000000..1089589
--- /dev/null
+++ b/contrib/wpa/src/crypto/sha512_i.h
@@ -0,0 +1,25 @@
+/*
+ * SHA-512 internal definitions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA512_I_H
+#define SHA512_I_H
+
+#define SHA512_BLOCK_SIZE 128
+
+struct sha512_state {
+ u64 length, state[8];
+ u32 curlen;
+ u8 buf[SHA512_BLOCK_SIZE];
+};
+
+void sha512_init(struct sha512_state *md);
+int sha512_process(struct sha512_state *md, const unsigned char *in,
+ unsigned long inlen);
+int sha512_done(struct sha512_state *md, unsigned char *out);
+
+#endif /* SHA512_I_H */
diff --git a/contrib/wpa/src/crypto/tls.h b/contrib/wpa/src/crypto/tls.h
index 2e56233..8bdb91f 100644
--- a/contrib/wpa/src/crypto/tls.h
+++ b/contrib/wpa/src/crypto/tls.h
@@ -41,6 +41,8 @@ enum tls_fail_reason {
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,
};
@@ -63,6 +65,7 @@ union tls_event_data {
size_t hash_len;
const char *altsubject[TLS_MAX_ALT_SUBJECT];
int num_altsubject;
+ const char *serial_num;
} peer_cert;
struct {
@@ -80,6 +83,8 @@ struct tls_config {
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);
@@ -95,6 +100,14 @@ struct tls_config {
#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)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -107,12 +120,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: String to suffix match in the dNSName or CN of the peer
- * certificate or %NULL to allow all domain names. This may allow subdomains an
- * wildcard certificates. Each domain name label must have a full match.
+ * @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
@@ -136,9 +156,15 @@ struct tls_config {
* @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().
@@ -176,9 +202,12 @@ struct tls_connection_params {
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;
};
@@ -242,6 +271,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()
* @conn: Connection context data from tls_connection_init()
@@ -297,9 +338,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
@@ -330,29 +373,42 @@ int __must_check tls_connection_get_random(void *tls_ctx,
struct tls_random *data);
/**
- * tls_connection_prf - Use TLS-PRF to derive keying material
+ * tls_connection_export_key - Derive keying material from a TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @label: Label (e.g., description of the key) for PRF
- * @server_random_first: seed is 0 = client_random|server_random,
- * 1 = server_random|client_random
- * @skip_keyblock: Skip TLS key block from the beginning of PRF output
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * Exports keying material using the mechanism described in RFC 5705. If
+ * context is %NULL, context is not provided; otherwise, context is provided
+ * (including the case of empty context with context_len == 0).
+ */
+int __must_check tls_connection_export_key(void *tls_ctx,
+ struct tls_connection *conn,
+ const char *label,
+ const u8 *context,
+ size_t context_len,
+ u8 *out, size_t out_len);
+
+/**
+ * tls_connection_get_eap_fast_key - Derive key material for EAP-FAST
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*
- * tls_connection_prf() is required so that further keying material can be
- * derived from the master secret. Example implementation of this function is in
- * tls_prf_sha1_md5() when it is called with seed set to
- * client_random|server_random (or server_random|client_random). For TLSv1.2 and
- * newer, a different PRF is needed, though.
+ * Exports key material after the normal TLS key block for use with
+ * EAP-FAST. Most callers will want tls_connection_export_key(), but EAP-FAST
+ * uses a different legacy mechanism.
*/
-int __must_check tls_connection_prf(void *tls_ctx,
- struct tls_connection *conn,
- const char *label,
- int server_random_first,
- int skip_keyblock,
- u8 *out, size_t out_len);
+int __must_check tls_connection_get_eap_fast_key(void *tls_ctx,
+ struct tls_connection *conn,
+ u8 *out, size_t out_len);
/**
* tls_connection_handshake - Process TLS handshake (client side)
@@ -455,7 +511,9 @@ enum {
TLS_CIPHER_RC4_SHA /* 0x0005 */,
TLS_CIPHER_AES128_SHA /* 0x002f */,
TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
- TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
+ TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */,
+ TLS_CIPHER_RSA_DHE_AES256_SHA /* 0x0039 */,
+ TLS_CIPHER_AES256_SHA /* 0x0035 */,
};
/**
diff --git a/contrib/wpa/src/crypto/tls_gnutls.c b/contrib/wpa/src/crypto/tls_gnutls.c
index f994379..daa01d9 100644
--- a/contrib/wpa/src/crypto/tls_gnutls.c
+++ b/contrib/wpa/src/crypto/tls_gnutls.c
@@ -1,6 +1,6 @@
/*
* SSL/TLS interface functions for GnuTLS
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -37,6 +37,8 @@ struct tls_global {
union tls_event_data *data);
void *cb_ctx;
int cert_in_cb;
+
+ char *ocsp_stapling_response;
};
struct tls_connection {
@@ -133,6 +135,7 @@ void tls_deinit(void *ssl_ctx)
if (global->params_set)
gnutls_certificate_free_credentials(global->xcred);
os_free(global->session_data);
+ os_free(global->ocsp_stapling_response);
os_free(global);
}
@@ -292,6 +295,14 @@ int tls_connection_established(void *ssl_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 *ssl_ctx, struct tls_connection *conn)
{
struct tls_global *global = ssl_ctx;
@@ -343,10 +354,25 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
int ret;
+ const char *err;
+ char prio_buf[100];
+ const char *prio = NULL;
if (conn == NULL || params == NULL)
return -1;
+ if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: ocsp=3 not supported");
+ return -1;
+ }
+
+ if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: tls_ext_cert_check=1 not supported");
+ return -1;
+ }
+
if (params->subject_match) {
wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
return -1;
@@ -382,12 +408,66 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
conn->flags = params->flags;
+ if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
+ TLS_CONN_DISABLE_TLSv1_1 |
+ TLS_CONN_DISABLE_TLSv1_2)) {
+ os_snprintf(prio_buf, sizeof(prio_buf),
+ "NORMAL:-VERS-SSL3.0%s%s%s",
+ params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
+ ":-VERS-TLS1.0" : "",
+ params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
+ ":-VERS-TLS1.1" : "",
+ params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
+ ":-VERS-TLS1.2" : "");
+ prio = prio_buf;
+ }
+
if (params->openssl_ciphers) {
- wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
+ prio = "SUITEB128";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "SUITEB192") == 0) {
+ prio = "SUITEB192";
+ } else if ((params->flags & TLS_CONN_SUITEB) &&
+ os_strcmp(params->openssl_ciphers,
+ "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "DHE-RSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+ } else {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: openssl_ciphers not supported");
+ return -1;
+ }
+ } else if (params->flags & TLS_CONN_SUITEB) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
+ }
+
+ if (prio) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
+ ret = gnutls_priority_set_direct(conn->session, prio, &err);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "GnuTLS: Priority string failure at '%s'",
+ err);
+ return -1;
+ }
+ }
+
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: openssl_ecdh_curves not supported");
return -1;
}
- /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
+ /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
* to force peer validation(?) */
if (params->ca_cert) {
@@ -410,6 +490,13 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
gnutls_strerror(ret));
return -1;
}
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read CA cert '%s' in PEM format",
+ params->ca_cert);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read CA cert '%s' in DER format",
+ params->ca_cert);
}
} else if (params->ca_cert_blob) {
gnutls_datum_t ca;
@@ -457,6 +544,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
if (params->client_cert && params->private_key) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
+ params->client_cert, params->private_key);
#if GNUTLS_VERSION_NUMBER >= 0x03010b
ret = gnutls_certificate_set_x509_key_file2(
conn->xcred, params->client_cert, params->private_key,
@@ -468,8 +558,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
GNUTLS_X509_FMT_DER);
#endif
if (ret < 0) {
- wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
- "in DER format: %s", gnutls_strerror(ret));
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
+ gnutls_strerror(ret));
#if GNUTLS_VERSION_NUMBER >= 0x03010b
ret = gnutls_certificate_set_x509_key_file2(
conn->xcred, params->client_cert,
@@ -486,11 +577,19 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
gnutls_strerror(ret));
return ret;
}
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read client cert/key in PEM format");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read client cert/key in DER format");
}
} else if (params->private_key) {
int pkcs12_ok = 0;
#ifdef PKCS12_FUNCS
/* Try to load in PKCS#12 format */
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
+ params->private_key);
ret = gnutls_certificate_set_x509_simple_pkcs12_file(
conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
params->private_key_passwd);
@@ -596,12 +695,53 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
+ gnutls_datum_t *resp)
+{
+ struct tls_global *global = ptr;
+ char *cached;
+ size_t len;
+
+ if (!global->ocsp_stapling_response) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
+ return GNUTLS_E_NO_CERTIFICATE_STATUS;
+ }
+
+ cached = os_readfile(global->ocsp_stapling_response, &len);
+ if (!cached) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP status callback - could not read response file (%s)",
+ global->ocsp_stapling_response);
+ return GNUTLS_E_NO_CERTIFICATE_STATUS;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP status callback - send cached response");
+ resp->data = gnutls_malloc(len);
+ if (!resp->data) {
+ os_free(resp);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ os_memcpy(resp->data, cached, len);
+ resp->size = len;
+ os_free(cached);
+
+ return GNUTLS_E_SUCCESS;
+}
+#endif /* 3.1.3 */
+
+
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
struct tls_global *global = tls_ctx;
int ret;
+ if (params->check_cert_subject)
+ return -1; /* not yet supported */
+
/* Currently, global parameters are only set when running in server
* mode. */
global->server = 1;
@@ -690,6 +830,17 @@ int tls_global_set_params(void *tls_ctx,
}
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+ os_free(global->ocsp_stapling_response);
+ if (params->ocsp_stapling_response)
+ global->ocsp_stapling_response =
+ os_strdup(params->ocsp_stapling_response);
+ else
+ global->ocsp_stapling_response = NULL;
+ gnutls_certificate_set_ocsp_status_request_function(
+ global->xcred, server_ocsp_status_req, global);
+#endif /* 3.1.3 */
+
global->params_set = 1;
return 0;
@@ -700,7 +851,7 @@ fail:
}
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
{
/* TODO */
return 0;
@@ -746,15 +897,31 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
}
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
{
- if (conn == NULL || conn->session == NULL || skip_keyblock)
+ if (conn == NULL || conn->session == NULL)
return -1;
+#if GNUTLS_VERSION_NUMBER >= 0x030404
+ return gnutls_prf_rfc5705(conn->session, os_strlen(label), label,
+ context_len, (const char *) context,
+ out_len, (char *) out);
+#else /* 3.4.4 */
+ if (context)
+ return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
- server_random_first, 0, NULL, out_len, (char *) out);
+ 0 /* client_random first */, 0, NULL, out_len,
+ (char *) out);
+#endif /* 3.4.4 */
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+ return -1;
}
@@ -919,6 +1086,52 @@ ocsp_error:
}
+static int tls_match_suffix_helper(gnutls_x509_crt_t cert, const char *match,
+ int full)
+{
+ int res = -1;
+
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ if (full)
+ res = gnutls_x509_crt_check_hostname2(
+ cert, match,
+ GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
+#endif /* >= 3.3.0 */
+ if (res == -1)
+ res = gnutls_x509_crt_check_hostname(cert, match);
+
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s --> res=%d",
+ full ? "": "suffix ", match, res);
+ return res;
+}
+
+
+static int tls_match_suffix(gnutls_x509_crt_t cert, const char *match,
+ int full)
+{
+ char *values, *token, *context = NULL;
+ int ret = 0;
+
+ if (!os_strchr(match, ';'))
+ return tls_match_suffix_helper(cert, match, full);
+
+ values = os_strdup(match);
+ if (!values)
+ return 0;
+
+ /* Process each match alternative separately until a match is found */
+ while ((token = str_token(values, ";", &context))) {
+ if (tls_match_suffix_helper(cert, token, full)) {
+ ret = 1;
+ break;
+ }
+ }
+
+ os_free(values);
+ return ret;
+}
+
+
static int tls_connection_verify_peer(gnutls_session_t session)
{
struct tls_connection *conn;
@@ -1114,8 +1327,7 @@ static int tls_connection_verify_peer(gnutls_session_t session)
if (i == 0) {
if (conn->suffix_match &&
- !gnutls_x509_crt_check_hostname(
- cert, conn->suffix_match)) {
+ !tls_match_suffix(cert, conn->suffix_match, 0)) {
wpa_printf(MSG_WARNING,
"TLS: Domain suffix match '%s' not found",
conn->suffix_match);
@@ -1131,9 +1343,7 @@ static int tls_connection_verify_peer(gnutls_session_t session)
#if GNUTLS_VERSION_NUMBER >= 0x030300
if (conn->domain_match &&
- !gnutls_x509_crt_check_hostname2(
- cert, conn->domain_match,
- GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
+ !tls_match_suffix(cert, conn->domain_match, 1)) {
wpa_printf(MSG_WARNING,
"TLS: Domain match '%s' not found",
conn->domain_match);
@@ -1262,6 +1472,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
ret = gnutls_handshake(conn->session);
if (ret < 0) {
gnutls_alert_description_t alert;
+ union tls_event_data ev;
switch (ret) {
case GNUTLS_E_AGAIN:
@@ -1272,14 +1483,29 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
conn->push_buf = wpabuf_alloc(0);
}
break;
+ case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
+ wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
+ if (conn->global->event_cb) {
+ os_memset(&ev, 0, sizeof(ev));
+ ev.alert.is_local = 1;
+ ev.alert.type = "fatal";
+ ev.alert.description = "insufficient security";
+ conn->global->event_cb(conn->global->cb_ctx,
+ TLS_ALERT, &ev);
+ }
+ /*
+ * Could send a TLS Alert to the server, but for now,
+ * simply terminate handshake.
+ */
+ conn->failed++;
+ conn->write_alerts++;
+ break;
case GNUTLS_E_FATAL_ALERT_RECEIVED:
alert = gnutls_alert_get(conn->session);
wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
__func__, gnutls_alert_get_name(alert));
conn->read_alerts++;
if (conn->global->event_cb != NULL) {
- union tls_event_data ev;
-
os_memset(&ev, 0, sizeof(ev));
ev.alert.is_local = 0;
ev.alert.type = gnutls_alert_get_name(alert);
@@ -1430,16 +1656,53 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- /* TODO */
- return -1;
+ gnutls_protocol_t ver;
+
+ ver = gnutls_protocol_get_version(conn->session);
+ if (ver == GNUTLS_TLS1_0)
+ os_strlcpy(buf, "TLSv1", buflen);
+ else if (ver == GNUTLS_TLS1_1)
+ os_strlcpy(buf, "TLSv1.1", buflen);
+ else if (ver == GNUTLS_TLS1_2)
+ os_strlcpy(buf, "TLSv1.2", buflen);
+ else
+ return -1;
+ return 0;
}
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- /* TODO */
- buf[0] = '\0';
+ gnutls_cipher_algorithm_t cipher;
+ gnutls_kx_algorithm_t kx;
+ gnutls_mac_algorithm_t mac;
+ const char *kx_str, *cipher_str, *mac_str;
+ int res;
+
+ cipher = gnutls_cipher_get(conn->session);
+ cipher_str = gnutls_cipher_get_name(cipher);
+ if (!cipher_str)
+ cipher_str = "";
+
+ kx = gnutls_kx_get(conn->session);
+ kx_str = gnutls_kx_get_name(kx);
+ if (!kx_str)
+ kx_str = "";
+
+ mac = gnutls_mac_get(conn->session);
+ mac_str = gnutls_mac_get_name(mac);
+ if (!mac_str)
+ mac_str = "";
+
+ if (kx == GNUTLS_KX_RSA)
+ res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
+ else
+ res = os_snprintf(buf, buflen, "%s-%s-%s",
+ kx_str, cipher_str, mac_str);
+ if (os_snprintf_error(buflen, res))
+ return -1;
+
return 0;
}
diff --git a/contrib/wpa/src/crypto/tls_internal.c b/contrib/wpa/src/crypto/tls_internal.c
index 704751d..8095b43 100644
--- a/contrib/wpa/src/crypto/tls_internal.c
+++ b/contrib/wpa/src/crypto/tls_internal.c
@@ -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.
@@ -23,6 +23,11 @@ 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 {
@@ -51,6 +56,11 @@ void * tls_init(const struct tls_config *conf)
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);
}
@@ -95,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
@@ -163,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
@@ -186,6 +208,12 @@ 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;
@@ -220,6 +248,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
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)) {
@@ -259,8 +293,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
- tlsv1_client_set_time_checks(
- conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
+ tlsv1_client_set_flags(conn->client, params->flags);
return 0;
#else /* CONFIG_TLS_INTERNAL_CLIENT */
@@ -276,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;
@@ -312,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;
@@ -319,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;
@@ -368,9 +411,10 @@ static int tls_get_keyblock_size(struct tls_connection *conn)
}
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, int server_random_first,
+ int skip_keyblock, u8 *out, size_t out_len)
{
int ret = -1, skip = 0;
u8 *tmp_out = NULL;
@@ -388,16 +432,16 @@ 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,
- _out, out_len);
+ 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,
- _out, out_len);
+ ret = tlsv1_server_prf(conn->server, label, context,
+ context_len, server_random_first,
+ _out, skip + out_len);
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
if (ret == 0 && skip_keyblock)
@@ -408,6 +452,23 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
}
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
+{
+ return tls_connection_prf(tls_ctx, conn, label, context, context_len,
+ 0, 0, out, out_len);
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+ return tls_connection_prf(tls_ctx, conn, "key expansion", NULL, 0,
+ 1, 1, out, out_len);
+}
+
+
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
@@ -621,7 +682,12 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- /* TODO */
+ 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;
}
@@ -666,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;
}
@@ -679,6 +753,10 @@ 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;
}
diff --git a/contrib/wpa/src/crypto/tls_none.c b/contrib/wpa/src/crypto/tls_none.c
index ae392ad..6d6fb0c 100644
--- a/contrib/wpa/src/crypto/tls_none.c
+++ b/contrib/wpa/src/crypto/tls_none.c
@@ -45,6 +45,13 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ return NULL;
+}
+
+
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{
return -1;
@@ -65,7 +72,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)
{
return -1;
}
@@ -86,9 +93,16 @@ int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
}
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
+{
+ return -1;
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
{
return -1;
}
diff --git a/contrib/wpa/src/crypto/tls_openssl.c b/contrib/wpa/src/crypto/tls_openssl.c
index 8b7b47b..b0c23ae 100644
--- a/contrib/wpa/src/crypto/tls_openssl.c
+++ b/contrib/wpa/src/crypto/tls_openssl.c
@@ -18,6 +18,7 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
+#include <openssl/opensslv.h>
#include <openssl/pkcs12.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_NO_ENGINE
@@ -35,12 +36,12 @@
#include "sha1.h"
#include "sha256.h"
#include "tls.h"
+#include "tls_openssl.h"
-#if OPENSSL_VERSION_NUMBER < 0x10000000L
-/* ERR_remove_thread_state replaces ERR_remove_state and the latter is
- * deprecated. However, OpenSSL 0.9.8 doesn't include
- * ERR_remove_thread_state. */
-#define ERR_remove_thread_state(tid) ERR_remove_state(0)
+#if !defined(CONFIG_FIPS) && \
+ (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
+ defined(EAP_SERVER_FAST))
+#define OPENSSL_NEED_EAP_FAST_PRF
#endif
#if defined(OPENSSL_IS_BORINGSSL)
@@ -57,6 +58,69 @@ typedef int stack_index_t;
#endif /* OPENSSL_NO_TLSEXT */
#endif /* SSL_set_tlsext_status_type */
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \
+ !defined(BORINGSSL_API_VERSION)
+/*
+ * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
+ * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
+ * older versions.
+ */
+
+static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
+ size_t outlen)
+{
+ if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+ return 0;
+ os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+ return SSL3_RANDOM_SIZE;
+}
+
+
+static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
+ size_t outlen)
+{
+ if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
+ return 0;
+ os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
+ return SSL3_RANDOM_SIZE;
+}
+
+
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
+static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
+ unsigned char *out, size_t outlen)
+{
+ if (!session || session->master_key_length < 0 ||
+ (size_t) session->master_key_length > outlen)
+ return 0;
+ if ((size_t) session->master_key_length < outlen)
+ outlen = session->master_key_length;
+ os_memcpy(out, session->master_key, outlen);
+ return outlen;
+}
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
+
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#ifdef CONFIG_SUITEB
+static int RSA_bits(const RSA *r)
+{
+ return BN_num_bits(r->n);
+}
+#endif /* CONFIG_SUITEB */
+
+
+static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+ return ASN1_STRING_data((ASN1_STRING *) x);
+}
+#endif
+
#ifdef ANDROID
#include <openssl/pem.h>
#include <keystore/keystore_get.h>
@@ -71,6 +135,66 @@ static BIO * BIO_from_keystore(const char *key)
free(value);
return bio;
}
+
+
+static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
+{
+ BIO *bio = BIO_from_keystore(key_alias);
+ STACK_OF(X509_INFO) *stack = NULL;
+ stack_index_t i;
+
+ if (bio) {
+ stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ }
+
+ if (!stack) {
+ wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
+ key_alias);
+ return -1;
+ }
+
+ for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+ X509_INFO *info = sk_X509_INFO_value(stack, i);
+
+ if (info->x509)
+ X509_STORE_add_cert(ctx, info->x509);
+ if (info->crl)
+ X509_STORE_add_crl(ctx, info->crl);
+ }
+
+ sk_X509_INFO_pop_free(stack, X509_INFO_free);
+
+ return 0;
+}
+
+
+static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
+ const char *encoded_key_alias)
+{
+ int rc = -1;
+ int len = os_strlen(encoded_key_alias);
+ unsigned char *decoded_alias;
+
+ if (len & 1) {
+ wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
+ encoded_key_alias);
+ return rc;
+ }
+
+ decoded_alias = os_malloc(len / 2 + 1);
+ if (decoded_alias) {
+ if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
+ decoded_alias[len / 2] = '\0';
+ rc = tls_add_ca_from_keystore(
+ ctx, (const char *) decoded_alias);
+ }
+ os_free(decoded_alias);
+ }
+
+ return rc;
+}
+
#endif /* ANDROID */
static int tls_openssl_ref_count = 0;
@@ -90,18 +214,26 @@ static struct tls_context *tls_global = NULL;
struct tls_data {
SSL_CTX *ssl;
unsigned int tls_session_lifetime;
+ int check_crl;
+ int check_crl_strict;
+ char *ca_cert;
+ unsigned int crl_reload_interval;
+ struct os_reltime crl_last_reload;
+ char *check_cert_subject;
};
struct tls_connection {
struct tls_context *context;
+ struct tls_data *data;
SSL_CTX *ssl_ctx;
SSL *ssl;
BIO *ssl_in, *ssl_out;
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
ENGINE *engine; /* functional reference to the engine */
EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
char *subject_match, *altsubject_match, *suffix_match, *domain_match;
+ char *check_cert_subject;
int read_alerts, write_alerts, failed;
tls_session_ticket_cb session_ticket_cb;
@@ -116,6 +248,8 @@ struct tls_connection {
unsigned int server_cert_only:1;
unsigned int invalid_hb_used:1;
unsigned int success_data:1;
+ unsigned int client_hello_generated:1;
+ unsigned int server:1;
u8 srv_cert_hash[32];
@@ -125,10 +259,11 @@ struct tls_connection {
X509 *peer_issuer;
X509 *peer_issuer_issuer;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
unsigned char client_random[SSL3_RANDOM_SIZE];
unsigned char server_random[SSL3_RANDOM_SIZE];
-#endif
+
+ u16 cipher_suite;
+ int server_dh_prime_len;
};
@@ -176,6 +311,36 @@ static void tls_show_errors(int level, const char *func, const char *txt)
#endif /* CONFIG_NO_STDOUT_DEBUG */
+static X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
+{
+ int flags;
+ X509_STORE *store;
+
+ store = X509_STORE_new();
+ if (!store) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: %s - failed to allocate new certificate store",
+ __func__);
+ return NULL;
+ }
+
+ if (ca_cert && X509_STORE_load_locations(store, ca_cert, NULL) != 1) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to load root certificates");
+ X509_STORE_free(store);
+ return NULL;
+ }
+
+ flags = check_crl ? X509_V_FLAG_CRL_CHECK : 0;
+ if (check_crl == 2)
+ flags |= X509_V_FLAG_CRL_CHECK_ALL;
+
+ X509_STORE_set_flags(store, flags);
+
+ return store;
+}
+
+
#ifdef CONFIG_NATIVE_WINDOWS
/* Windows CryptoAPI and access to certificate stores */
@@ -526,7 +691,8 @@ static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
"system certificate store: subject='%s'", buf);
- if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
+ cert)) {
tls_show_errors(MSG_WARNING, __func__,
"Failed to add ca_cert to OpenSSL "
"certificate store");
@@ -624,10 +790,16 @@ static int tls_engine_load_dynamic_generic(const char *pre[],
engine = ENGINE_by_id(id);
if (engine) {
- ENGINE_free(engine);
wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
"available", id);
- return 0;
+ /*
+ * If it was auto-loaded by ENGINE_by_id() we might still
+ * need to tell it which PKCS#11 module to use in legacy
+ * (non-p11-kit) environments. Do so now; even if it was
+ * properly initialised before, setting it again will be
+ * harmless.
+ */
+ goto found;
}
ERR_clear_error();
@@ -664,7 +836,7 @@ static int tls_engine_load_dynamic_generic(const char *pre[],
id, ERR_error_string(ERR_get_error(), NULL));
return -1;
}
-
+ found:
while (post && post[0]) {
wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
@@ -808,6 +980,9 @@ void * tls_init(const struct tls_config *conf)
}
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
SSL_load_error_strings();
SSL_library_init();
#ifndef OPENSSL_NO_SHA256
@@ -829,6 +1004,7 @@ void * tls_init(const struct tls_config *conf)
#endif /* OPENSSL_NO_RC2 */
PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
+#endif /* < 1.1.0 */
} else {
context = tls_context_new(conf);
if (context == NULL)
@@ -849,15 +1025,26 @@ void * tls_init(const struct tls_config *conf)
os_free(tls_global);
tls_global = NULL;
}
+ os_free(data);
return NULL;
}
data->ssl = ssl;
- if (conf)
+ if (conf) {
data->tls_session_lifetime = conf->tls_session_lifetime;
+ data->crl_reload_interval = conf->crl_reload_interval;
+ }
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+#ifdef SSL_MODE_NO_AUTO_CHAIN
+ /* Number of deployed use cases assume the default OpenSSL behavior of
+ * auto chaining the local certificate is in use. BoringSSL removed this
+ * functionality by default, so we need to restore it here to avoid
+ * breaking existing use cases. */
+ SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
+#endif /* SSL_MODE_NO_AUTO_CHAIN */
+
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
SSL_CTX_set_app_data(ssl, context);
if (data->tls_session_lifetime > 0) {
@@ -885,8 +1072,10 @@ void * tls_init(const struct tls_config *conf)
#ifndef OPENSSL_NO_ENGINE
wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_load_ENGINE_strings();
ENGINE_load_dynamic();
+#endif /* OPENSSL_VERSION_NUMBER */
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
@@ -903,7 +1092,7 @@ void * tls_init(const struct tls_config *conf)
if (conf && conf->openssl_ciphers)
ciphers = conf->openssl_ciphers;
else
- ciphers = "DEFAULT:!EXP:!LOW";
+ ciphers = TLS_DEFAULT_CIPHERS;
if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
wpa_printf(MSG_ERROR,
"OpenSSL: Failed to set cipher string '%s'",
@@ -925,10 +1114,14 @@ void tls_deinit(void *ssl_ctx)
os_free(context);
if (data->tls_session_lifetime > 0)
SSL_CTX_flush_sessions(ssl, 0);
+ os_free(data->ca_cert);
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
if (tls_openssl_ref_count == 0) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
@@ -936,12 +1129,14 @@ void tls_deinit(void *ssl_ctx)
ERR_remove_thread_state(NULL);
ERR_free_strings();
EVP_cleanup();
+#endif /* < 1.1.0 */
os_free(tls_global->ocsp_stapling_response);
tls_global->ocsp_stapling_response = NULL;
os_free(tls_global);
tls_global = NULL;
}
+ os_free(data->check_cert_subject);
os_free(data);
}
@@ -967,10 +1162,32 @@ static int tls_is_pin_error(unsigned int err)
#endif /* OPENSSL_NO_ENGINE */
+#ifdef ANDROID
+/* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
+EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
+#endif /* ANDROID */
+
static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
const char *pin, const char *key_id,
const char *cert_id, const char *ca_cert_id)
{
+#if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
+#if !defined(OPENSSL_NO_ENGINE)
+#error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
+#endif
+ if (!key_id)
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ conn->engine = NULL;
+ conn->private_key = EVP_PKEY_from_keystore(key_id);
+ if (!conn->private_key) {
+ wpa_printf(MSG_ERROR,
+ "ENGINE: cannot load private key with id '%s' [%s]",
+ key_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ }
+#endif /* ANDROID && OPENSSL_IS_BORINGSSL */
+
#ifndef OPENSSL_NO_ENGINE
int ret = -1;
if (engine_id == NULL) {
@@ -1068,17 +1285,19 @@ err:
static void tls_engine_deinit(struct tls_connection *conn)
{
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
if (conn->private_key) {
EVP_PKEY_free(conn->private_key);
conn->private_key = NULL;
}
if (conn->engine) {
+#if !defined(OPENSSL_IS_BORINGSSL)
ENGINE_finish(conn->engine);
+#endif /* !OPENSSL_IS_BORINGSSL */
conn->engine = NULL;
}
-#endif /* OPENSSL_NO_ENGINE */
+#endif /* ANDROID || !OPENSSL_NO_ENGINE */
}
@@ -1097,14 +1316,186 @@ int tls_get_errors(void *ssl_ctx)
}
+static const char * openssl_content_type(int content_type)
+{
+ switch (content_type) {
+ case 20:
+ return "change cipher spec";
+ case 21:
+ return "alert";
+ case 22:
+ return "handshake";
+ case 23:
+ return "application data";
+ case 24:
+ return "heartbeat";
+ case 256:
+ return "TLS header info"; /* pseudo content type */
+ default:
+ return "?";
+ }
+}
+
+
+static const char * openssl_handshake_type(int content_type, const u8 *buf,
+ size_t len)
+{
+ if (content_type != 22 || !buf || len == 0)
+ return "";
+ switch (buf[0]) {
+ case 0:
+ return "hello request";
+ case 1:
+ return "client hello";
+ case 2:
+ return "server hello";
+ case 3:
+ return "hello verify request";
+ case 4:
+ return "new session ticket";
+ case 5:
+ return "end of early data";
+ case 6:
+ return "hello retry request";
+ case 8:
+ return "encrypted extensions";
+ case 11:
+ return "certificate";
+ case 12:
+ return "server key exchange";
+ case 13:
+ return "certificate request";
+ case 14:
+ return "server hello done";
+ case 15:
+ return "certificate verify";
+ case 16:
+ return "client key exchange";
+ case 20:
+ return "finished";
+ case 21:
+ return "certificate url";
+ case 22:
+ return "certificate status";
+ case 23:
+ return "supplemental data";
+ case 24:
+ return "key update";
+ case 254:
+ return "message hash";
+ default:
+ return "?";
+ }
+}
+
+
+#ifdef CONFIG_SUITEB
+
+static void check_server_hello(struct tls_connection *conn,
+ const u8 *pos, const u8 *end)
+{
+ size_t payload_len, id_len;
+
+ /*
+ * Parse ServerHello to get the selected cipher suite since OpenSSL does
+ * not make it cleanly available during handshake and we need to know
+ * whether DHE was selected.
+ */
+
+ if (end - pos < 3)
+ return;
+ payload_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) < payload_len)
+ return;
+ end = pos + payload_len;
+
+ /* Skip Version and Random */
+ if (end - pos < 2 + SSL3_RANDOM_SIZE)
+ return;
+ pos += 2 + SSL3_RANDOM_SIZE;
+
+ /* Skip Session ID */
+ if (end - pos < 1)
+ return;
+ id_len = *pos++;
+ if ((size_t) (end - pos) < id_len)
+ return;
+ pos += id_len;
+
+ if (end - pos < 2)
+ return;
+ conn->cipher_suite = WPA_GET_BE16(pos);
+ wpa_printf(MSG_DEBUG, "OpenSSL: Server selected cipher suite 0x%x",
+ conn->cipher_suite);
+}
+
+
+static void check_server_key_exchange(SSL *ssl, struct tls_connection *conn,
+ const u8 *pos, const u8 *end)
+{
+ size_t payload_len;
+ u16 dh_len;
+ BIGNUM *p;
+ int bits;
+
+ if (!(conn->flags & TLS_CONN_SUITEB))
+ return;
+
+ /* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
+ if (conn->cipher_suite != 0x9f)
+ return;
+
+ if (end - pos < 3)
+ return;
+ payload_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) < payload_len)
+ return;
+ end = pos + payload_len;
+
+ if (end - pos < 2)
+ return;
+ dh_len = WPA_GET_BE16(pos);
+ pos += 2;
+
+ if ((size_t) (end - pos) < dh_len)
+ return;
+ p = BN_bin2bn(pos, dh_len, NULL);
+ if (!p)
+ return;
+
+ bits = BN_num_bits(p);
+ BN_free(p);
+
+ conn->server_dh_prime_len = bits;
+ wpa_printf(MSG_DEBUG, "OpenSSL: Server DH prime length: %d bits",
+ conn->server_dh_prime_len);
+}
+
+#endif /* CONFIG_SUITEB */
+
+
static void tls_msg_cb(int write_p, int version, int content_type,
const void *buf, size_t len, SSL *ssl, void *arg)
{
struct tls_connection *conn = arg;
const u8 *pos = buf;
- wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d",
- write_p ? "TX" : "RX", version, content_type);
+ if (write_p == 2) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: session ver=0x%x content_type=%d",
+ version, content_type);
+ wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
+ write_p ? "TX" : "RX", version, content_type,
+ openssl_content_type(content_type),
+ openssl_handshake_type(content_type, buf, len));
wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
if (content_type == 24 && len >= 3 && pos[0] == 1) {
size_t payload_len = WPA_GET_BE16(pos + 1);
@@ -1113,6 +1504,18 @@ static void tls_msg_cb(int write_p, int version, int content_type,
conn->invalid_hb_used = 1;
}
}
+
+#ifdef CONFIG_SUITEB
+ /*
+ * Need to parse these handshake messages to be able to check DH prime
+ * length since OpenSSL does not expose the new cipher suite and DH
+ * parameters during handshake (e.g., for cert_cb() callback).
+ */
+ if (content_type == 22 && pos && len > 0 && pos[0] == 2)
+ check_server_hello(conn, pos + 1, pos + len);
+ if (content_type == 22 && pos && len > 0 && pos[0] == 12)
+ check_server_key_exchange(ssl, conn, pos + 1, pos + len);
+#endif /* CONFIG_SUITEB */
}
@@ -1122,11 +1525,32 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
SSL_CTX *ssl = data->ssl;
struct tls_connection *conn;
long options;
+ X509_STORE *new_cert_store;
+ struct os_reltime now;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
+ /* Replace X509 store if it is time to update CRL. */
+ if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
+ os_reltime_expired(&now, &data->crl_last_reload,
+ data->crl_reload_interval)) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Flushing X509 store with ca_cert file");
+ new_cert_store = tls_crl_cert_reload(data->ca_cert,
+ data->check_crl);
+ if (!new_cert_store) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Error replacing X509 store with ca_cert file");
+ } else {
+ /* Replace old store */
+ SSL_CTX_set_cert_store(ssl, new_cert_store);
+ data->crl_last_reload = now;
+ }
+ }
+
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
+ conn->data = data;
conn->ssl_ctx = ssl;
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
@@ -1190,6 +1614,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
os_free(conn->altsubject_match);
os_free(conn->suffix_match);
os_free(conn->domain_match);
+ os_free(conn->check_cert_subject);
os_free(conn->session_ticket);
os_free(conn);
}
@@ -1201,6 +1626,31 @@ int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ ASN1_INTEGER *ser;
+ char *serial_num;
+ size_t len;
+
+ if (!conn->peer_cert)
+ return NULL;
+
+ ser = X509_get_serialNumber(conn->peer_cert);
+ if (!ser)
+ return NULL;
+
+ len = ASN1_STRING_length(ser) * 2 + 1;
+ serial_num = os_malloc(len);
+ if (!serial_num)
+ return NULL;
+ wpa_snprintf_hex_uppercase(serial_num, len,
+ ASN1_STRING_get0_data(ser),
+ ASN1_STRING_length(ser));
+ return serial_num;
+}
+
+
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
@@ -1234,6 +1684,8 @@ static int tls_match_altsubject_component(X509 *cert, int type,
found++;
}
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
+
return found;
}
@@ -1283,9 +1735,9 @@ static int tls_match_altsubject(X509 *cert, const char *match)
#ifndef CONFIG_NATIVE_WINDOWS
static int domain_suffix_match(const u8 *val, size_t len, const char *match,
- int full)
+ size_t match_len, int full)
{
- size_t i, match_len;
+ size_t i;
/* Check for embedded nuls that could mess up suffix matching */
for (i = 0; i < len; i++) {
@@ -1295,7 +1747,6 @@ static int domain_suffix_match(const u8 *val, size_t len, const char *match,
}
}
- match_len = os_strlen(match);
if (match_len > len || (full && match_len != len))
return 0;
@@ -1315,12 +1766,223 @@ static int domain_suffix_match(const u8 *val, size_t len, const char *match,
#endif /* CONFIG_NATIVE_WINDOWS */
-static int tls_match_suffix(X509 *cert, const char *match, int full)
+struct tls_dn_field_order_cnt {
+ u8 cn;
+ u8 c;
+ u8 l;
+ u8 st;
+ u8 o;
+ u8 ou;
+ u8 email;
+};
+
+
+static int get_dn_field_index(const struct tls_dn_field_order_cnt *dn_cnt,
+ int nid)
+{
+ switch (nid) {
+ case NID_commonName:
+ return dn_cnt->cn;
+ case NID_countryName:
+ return dn_cnt->c;
+ case NID_localityName:
+ return dn_cnt->l;
+ case NID_stateOrProvinceName:
+ return dn_cnt->st;
+ case NID_organizationName:
+ return dn_cnt->o;
+ case NID_organizationalUnitName:
+ return dn_cnt->ou;
+ case NID_pkcs9_emailAddress:
+ return dn_cnt->email;
+ default:
+ wpa_printf(MSG_ERROR,
+ "TLS: Unknown NID '%d' in check_cert_subject",
+ nid);
+ return -1;
+ }
+}
+
+
+/**
+ * match_dn_field - Match configuration DN field against Certificate DN field
+ * @cert: Certificate
+ * @nid: NID of DN field
+ * @field: Field name
+ * @value DN field value which is passed from configuration
+ * e.g., if configuration have C=US and this argument will point to US.
+ * @dn_cnt: DN matching context
+ * Returns: 1 on success and 0 on failure
+ */
+static int match_dn_field(const X509 *cert, int nid, const char *field,
+ const char *value,
+ const struct tls_dn_field_order_cnt *dn_cnt)
+{
+ int i, ret = 0, len, config_dn_field_index, match_index = 0;
+ X509_NAME *name;
+
+ len = os_strlen(value);
+ name = X509_get_subject_name((X509 *) cert);
+
+ /* Assign incremented cnt for every field of DN to check DN field in
+ * right order */
+ config_dn_field_index = get_dn_field_index(dn_cnt, nid);
+ if (config_dn_field_index < 0)
+ return 0;
+
+ /* Fetch value based on NID */
+ for (i = -1; (i = X509_NAME_get_index_by_NID(name, nid, i)) > -1;) {
+ X509_NAME_ENTRY *e;
+ ASN1_STRING *cn;
+
+ e = X509_NAME_get_entry(name, i);
+ if (!e)
+ continue;
+
+ cn = X509_NAME_ENTRY_get_data(e);
+ if (!cn)
+ continue;
+
+ match_index++;
+
+ /* check for more than one DN field with same name */
+ if (match_index != config_dn_field_index)
+ continue;
+
+ /* Check wildcard at the right end side */
+ /* E.g., if OU=develop* mentioned in configuration, allow 'OU'
+ * of the subject in the client certificate to start with
+ * 'develop' */
+ if (len > 0 && value[len - 1] == '*') {
+ /* Compare actual certificate DN field value with
+ * configuration DN field value up to the specified
+ * length. */
+ ret = ASN1_STRING_length(cn) >= len - 1 &&
+ os_memcmp(ASN1_STRING_get0_data(cn), value,
+ len - 1) == 0;
+ } else {
+ /* Compare actual certificate DN field value with
+ * configuration DN field value */
+ ret = ASN1_STRING_length(cn) == len &&
+ os_memcmp(ASN1_STRING_get0_data(cn), value,
+ len) == 0;
+ }
+ if (!ret) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to match %s '%s' with certificate DN field value '%s'",
+ field, value, ASN1_STRING_get0_data(cn));
+ }
+ break;
+ }
+
+ return ret;
+}
+
+
+/**
+ * get_value_from_field - Get value from DN field
+ * @cert: Certificate
+ * @field_str: DN field string which is passed from configuration file (e.g.,
+ * C=US)
+ * @dn_cnt: DN matching context
+ * Returns: 1 on success and 0 on failure
+ */
+static int get_value_from_field(const X509 *cert, char *field_str,
+ struct tls_dn_field_order_cnt *dn_cnt)
+{
+ int nid;
+ char *context = NULL, *name, *value;
+
+ if (os_strcmp(field_str, "*") == 0)
+ return 1; /* wildcard matches everything */
+
+ name = str_token(field_str, "=", &context);
+ if (!name)
+ return 0;
+
+ /* Compare all configured DN fields and assign nid based on that to
+ * fetch correct value from certificate subject */
+ if (os_strcmp(name, "CN") == 0) {
+ nid = NID_commonName;
+ dn_cnt->cn++;
+ } else if(os_strcmp(name, "C") == 0) {
+ nid = NID_countryName;
+ dn_cnt->c++;
+ } else if (os_strcmp(name, "L") == 0) {
+ nid = NID_localityName;
+ dn_cnt->l++;
+ } else if (os_strcmp(name, "ST") == 0) {
+ nid = NID_stateOrProvinceName;
+ dn_cnt->st++;
+ } else if (os_strcmp(name, "O") == 0) {
+ nid = NID_organizationName;
+ dn_cnt->o++;
+ } else if (os_strcmp(name, "OU") == 0) {
+ nid = NID_organizationalUnitName;
+ dn_cnt->ou++;
+ } else if (os_strcmp(name, "emailAddress") == 0) {
+ nid = NID_pkcs9_emailAddress;
+ dn_cnt->email++;
+ } else {
+ wpa_printf(MSG_ERROR,
+ "TLS: Unknown field '%s' in check_cert_subject", name);
+ return 0;
+ }
+
+ value = str_token(field_str, "=", &context);
+ if (!value) {
+ wpa_printf(MSG_ERROR,
+ "TLS: Distinguished Name field '%s' value is not defined in check_cert_subject",
+ name);
+ return 0;
+ }
+
+ return match_dn_field(cert, nid, name, value, dn_cnt);
+}
+
+
+/**
+ * tls_match_dn_field - Match subject DN field with check_cert_subject
+ * @cert: Certificate
+ * @match: check_cert_subject string
+ * Returns: Return 1 on success and 0 on failure
+*/
+static int tls_match_dn_field(X509 *cert, const char *match)
+{
+ const char *token, *last = NULL;
+ char field[256];
+ struct tls_dn_field_order_cnt dn_cnt;
+
+ os_memset(&dn_cnt, 0, sizeof(dn_cnt));
+
+ /* Maximum length of each DN field is 255 characters */
+
+ /* Process each '/' delimited field */
+ while ((token = cstr_token(match, "/", &last))) {
+ if (last - token >= (int) sizeof(field)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Too long DN matching field value in '%s'",
+ match);
+ return 0;
+ }
+ os_memcpy(field, token, last - token);
+ field[last - token] = '\0';
+
+ if (!get_value_from_field(cert, field, &dn_cnt)) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No match for DN '%s'",
+ field);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static int tls_match_suffix_helper(X509 *cert, const char *match,
+ size_t match_len, int full)
{
-#ifdef CONFIG_NATIVE_WINDOWS
- /* wincrypt.h has conflicting X509_NAME definition */
- return -1;
-#else /* CONFIG_NATIVE_WINDOWS */
GENERAL_NAME *gen;
void *ext;
int i;
@@ -1342,13 +2004,15 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
gen->d.dNSName->data,
gen->d.dNSName->length);
if (domain_suffix_match(gen->d.dNSName->data,
- gen->d.dNSName->length, match, full) ==
- 1) {
+ gen->d.dNSName->length,
+ match, match_len, full) == 1) {
wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
full ? "Match" : "Suffix match");
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
return 1;
}
}
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
if (dns_name) {
wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
@@ -1372,8 +2036,8 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
continue;
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
cn->data, cn->length);
- if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
- {
+ if (domain_suffix_match(cn->data, cn->length,
+ match, match_len, full) == 1) {
wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
full ? "Match" : "Suffix match");
return 1;
@@ -1383,6 +2047,25 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
full ? "": "suffix ");
return 0;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int tls_match_suffix(X509 *cert, const char *match, int full)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ /* wincrypt.h has conflicting X509_NAME definition */
+ return -1;
+#else /* CONFIG_NATIVE_WINDOWS */
+ const char *token, *last = NULL;
+
+ /* Process each match alternative separately until a match is found */
+ while ((token = cstr_token(match, ";", &last))) {
+ if (tls_match_suffix_helper(cert, token, last - token, full))
+ return 1;
+ }
+
+ return 0;
#endif /* CONFIG_NATIVE_WINDOWS */
}
@@ -1481,6 +2164,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
GENERAL_NAME *gen;
void *ext;
stack_index_t i;
+ ASN1_INTEGER *ser;
+ char serial_num[128];
#ifdef CONFIG_SHA256
u8 hash[32];
#endif /* CONFIG_SHA256 */
@@ -1489,7 +2174,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cert_probe || context->cert_in_cb) {
+ if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+ context->cert_in_cb) {
cert = get_x509_cert(err_cert);
ev.peer_cert.cert = cert;
}
@@ -1508,6 +2194,14 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
ev.peer_cert.depth = depth;
ev.peer_cert.subject = subject;
+ ser = X509_get_serialNumber(err_cert);
+ if (ser) {
+ wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
+ ASN1_STRING_get0_data(ser),
+ ASN1_STRING_length(ser));
+ ev.peer_cert.serial_num = serial_num;
+ }
+
ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
char *pos;
@@ -1544,6 +2238,7 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
pos += gen->d.ia5->length;
*pos = '\0';
}
+ sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
for (alt = 0; alt < num_altsubject; alt++)
ev.peer_cert.altsubject[alt] = altsubject[alt];
@@ -1565,6 +2260,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
struct tls_connection *conn;
struct tls_context *context;
char *match, *altmatch, *suffix_match, *domain_match;
+ const char *check_cert_subject;
const char *err_str;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
@@ -1605,6 +2301,13 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
"time mismatch");
preverify_ok = 1;
}
+ if (!preverify_ok && !conn->data->check_crl_strict &&
+ (err == X509_V_ERR_CRL_HAS_EXPIRED ||
+ err == X509_V_ERR_CRL_NOT_YET_VALID)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Ignore certificate validity CRL time mismatch");
+ preverify_ok = 1;
+ }
err_str = X509_verify_cert_error_string(err);
@@ -1658,6 +2361,18 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
"err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
preverify_ok, err, err_str,
conn->ca_cert_verify, depth, buf);
+ check_cert_subject = conn->check_cert_subject;
+ if (!check_cert_subject)
+ check_cert_subject = conn->data->check_cert_subject;
+ if (check_cert_subject) {
+ if (depth == 0 &&
+ !tls_match_dn_field(err_cert, check_cert_subject)) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Distinguished Name",
+ TLS_FAIL_DN_MISMATCH);
+ }
+ }
if (depth == 0 && match && os_strstr(buf, match) == NULL) {
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
"match with '%s'", buf, match);
@@ -1701,7 +2416,64 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
TLS_FAIL_SERVER_CHAIN_PROBE);
}
- if (preverify_ok && context->event_cb != NULL)
+#ifdef CONFIG_SUITEB
+ if (conn->flags & TLS_CONN_SUITEB) {
+ EVP_PKEY *pk;
+ RSA *rsa;
+ int len = -1;
+
+ pk = X509_get_pubkey(err_cert);
+ if (pk) {
+ rsa = EVP_PKEY_get1_RSA(pk);
+ if (rsa) {
+ len = RSA_bits(rsa);
+ RSA_free(rsa);
+ }
+ EVP_PKEY_free(pk);
+ }
+
+ if (len >= 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: RSA modulus size: %d bits", len);
+ if (len < 3072) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(
+ conn, err_cert, err,
+ depth, buf,
+ "Insufficient RSA modulus size",
+ TLS_FAIL_INSUFFICIENT_KEY_LEN);
+ }
+ }
+ }
+#endif /* CONFIG_SUITEB */
+
+#ifdef OPENSSL_IS_BORINGSSL
+ if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ preverify_ok) {
+ enum ocsp_result res;
+
+ res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+ conn->peer_issuer,
+ conn->peer_issuer_issuer);
+ if (res == OCSP_REVOKED) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "certificate revoked",
+ TLS_FAIL_REVOKED);
+ if (err == X509_V_OK)
+ X509_STORE_CTX_set_error(
+ x509_ctx, X509_V_ERR_CERT_REVOKED);
+ } else if (res != OCSP_GOOD &&
+ (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "bad certificate status response",
+ TLS_FAIL_UNSPECIFIED);
+ }
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+ if (depth == 0 && preverify_ok && context->event_cb != NULL)
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
@@ -1837,30 +2609,40 @@ static int tls_connection_ca_cert(struct tls_data *data,
}
#ifdef ANDROID
+ /* Single alias */
if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
- BIO *bio = BIO_from_keystore(&ca_cert[11]);
- STACK_OF(X509_INFO) *stack = NULL;
- stack_index_t i;
-
- if (bio) {
- stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
- BIO_free(bio);
- }
- if (!stack)
+ if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
+ &ca_cert[11]) < 0)
return -1;
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ return 0;
+ }
- for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
- X509_INFO *info = sk_X509_INFO_value(stack, i);
- if (info->x509) {
- X509_STORE_add_cert(ssl_ctx->cert_store,
- info->x509);
- }
- if (info->crl) {
- X509_STORE_add_crl(ssl_ctx->cert_store,
- info->crl);
+ /* Multiple aliases separated by space */
+ if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
+ char *aliases = os_strdup(&ca_cert[12]);
+ const char *delim = " ";
+ int rc = 0;
+ char *savedptr;
+ char *alias;
+
+ if (!aliases)
+ return -1;
+ alias = strtok_r(aliases, delim, &savedptr);
+ for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
+ if (tls_add_ca_from_keystore_encoded(
+ SSL_CTX_get_cert_store(ssl_ctx), alias)) {
+ wpa_printf(MSG_WARNING,
+ "OpenSSL: %s - Failed to add ca_cert %s from keystore",
+ __func__, alias);
+ rc = -1;
+ break;
}
}
- sk_X509_INFO_pop_free(stack, X509_INFO_free);
+ os_free(aliases);
+ if (rc)
+ return rc;
+
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
return 0;
}
@@ -1928,13 +2710,16 @@ static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
SSL_CTX_set_client_CA_list(ssl_ctx,
SSL_load_client_CA_file(ca_cert));
#endif /* OPENSSL_NO_STDIO */
+
+ os_free(data->ca_cert);
+ data->ca_cert = os_strdup(ca_cert);
}
return 0;
}
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
{
int flags;
@@ -1951,6 +2736,10 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
if (check_crl == 2)
flags |= X509_V_FLAG_CRL_CHECK_ALL;
X509_STORE_set_flags(cs, flags);
+
+ data->check_crl = check_crl;
+ data->check_crl_strict = strict;
+ os_get_reltime(&data->crl_last_reload);
}
return 0;
}
@@ -1960,7 +2749,8 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
const char *subject_match,
const char *altsubject_match,
const char *suffix_match,
- const char *domain_match)
+ const char *domain_match,
+ const char *check_cert_subject)
{
os_free(conn->subject_match);
conn->subject_match = NULL;
@@ -1994,19 +2784,60 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
return -1;
}
+ os_free(conn->check_cert_subject);
+ conn->check_cert_subject = NULL;
+ if (check_cert_subject) {
+ conn->check_cert_subject = os_strdup(check_cert_subject);
+ if (!conn->check_cert_subject)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_SUITEB
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+static int suiteb_cert_cb(SSL *ssl, void *arg)
+{
+ struct tls_connection *conn = arg;
+
+ /*
+ * This cert_cb() is not really the best location for doing a
+ * constraint check for the ServerKeyExchange message, but this seems to
+ * be the only place where the current OpenSSL sequence can be
+ * terminated cleanly with an TLS alert going out to the server.
+ */
+
+ if (!(conn->flags & TLS_CONN_SUITEB))
+ return 1;
+
+ /* DHE is enabled only with DHE-RSA-AES256-GCM-SHA384 */
+ if (conn->cipher_suite != 0x9f)
+ return 1;
+
+ if (conn->server_dh_prime_len >= 3072)
+ return 1;
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Server DH prime length (%d bits) not sufficient for Suite B RSA - reject handshake",
+ conn->server_dh_prime_len);
return 0;
}
+#endif /* OPENSSL_VERSION_NUMBER */
+#endif /* CONFIG_SUITEB */
-static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
+static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
+ const char *openssl_ciphers)
{
+ SSL *ssl = conn->ssl;
+
#ifdef SSL_OP_NO_TICKET
if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_set_options(ssl, SSL_OP_NO_TICKET);
-#ifdef SSL_clear_options
else
SSL_clear_options(ssl, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
#endif /* SSL_OP_NO_TICKET */
#ifdef SSL_OP_NO_TLSv1
@@ -2027,6 +2858,165 @@ static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
else
SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
#endif /* SSL_OP_NO_TLSv1_2 */
+#ifdef SSL_OP_NO_TLSv1_3
+ if (flags & TLS_CONN_DISABLE_TLSv1_3)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
+#endif /* SSL_OP_NO_TLSv1_3 */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ if (flags & (TLS_CONN_ENABLE_TLSv1_0 |
+ TLS_CONN_ENABLE_TLSv1_1 |
+ TLS_CONN_ENABLE_TLSv1_2)) {
+ int version = 0;
+
+ /* Explicit request to enable TLS versions even if needing to
+ * override systemwide policies. */
+ if (flags & TLS_CONN_ENABLE_TLSv1_0) {
+ version = TLS1_VERSION;
+ } else if (flags & TLS_CONN_ENABLE_TLSv1_1) {
+ if (!(flags & TLS_CONN_DISABLE_TLSv1_0))
+ version = TLS1_1_VERSION;
+ } else if (flags & TLS_CONN_ENABLE_TLSv1_2) {
+ if (!(flags & (TLS_CONN_DISABLE_TLSv1_0 |
+ TLS_CONN_DISABLE_TLSv1_1)))
+ version = TLS1_2_VERSION;
+ }
+ if (!version) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid TLS version configuration");
+ return -1;
+ }
+
+ if (SSL_set_min_proto_version(ssl, version) != 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Failed to set minimum TLS version");
+ return -1;
+ }
+ }
+#endif /* >= 1.1.0 */
+
+#ifdef CONFIG_SUITEB
+#ifdef OPENSSL_IS_BORINGSSL
+ /* Start with defaults from BoringSSL */
+ SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, NULL, 0);
+#endif /* OPENSSL_IS_BORINGSSL */
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ if (flags & TLS_CONN_SUITEB_NO_ECDH) {
+ const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
+
+ if (openssl_ciphers) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Override ciphers for Suite B (no ECDH): %s",
+ openssl_ciphers);
+ ciphers = openssl_ciphers;
+ }
+ if (SSL_set_cipher_list(ssl, ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B ciphers");
+ return -1;
+ }
+ } else if (flags & TLS_CONN_SUITEB) {
+ EC_KEY *ecdh;
+ const char *ciphers =
+ "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
+ int nid[1] = { NID_secp384r1 };
+
+ if (openssl_ciphers) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Override ciphers for Suite B: %s",
+ openssl_ciphers);
+ ciphers = openssl_ciphers;
+ }
+ if (SSL_set_cipher_list(ssl, ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B ciphers");
+ return -1;
+ }
+
+ if (SSL_set1_curves(ssl, nid, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B curves");
+ return -1;
+ }
+
+ ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
+ if (!ecdh || SSL_set_tmp_ecdh(ssl, ecdh) != 1) {
+ EC_KEY_free(ecdh);
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH parameter");
+ return -1;
+ }
+ EC_KEY_free(ecdh);
+ }
+ if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
+#ifdef OPENSSL_IS_BORINGSSL
+ uint16_t sigalgs[1] = { SSL_SIGN_RSA_PKCS1_SHA384 };
+
+ if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
+ 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B sigalgs");
+ return -1;
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+ /* ECDSA+SHA384 if need to add EC support here */
+ if (SSL_set1_sigalgs_list(ssl, "RSA+SHA384") != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B sigalgs");
+ return -1;
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1);
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+ SSL_set_cert_cb(ssl, suiteb_cert_cb, conn);
+ }
+#else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+ if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Suite B RSA case not supported with this OpenSSL version");
+ return -1;
+ }
+#endif /* OPENSSL_VERSION_NUMBER */
+
+#ifdef OPENSSL_IS_BORINGSSL
+ if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
+ uint16_t sigalgs[1] = { SSL_SIGN_ECDSA_SECP384R1_SHA384 };
+ int nid[1] = { NID_secp384r1 };
+
+ if (SSL_set1_curves(ssl, nid, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B curves");
+ return -1;
+ }
+
+ if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
+ 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B sigalgs");
+ return -1;
+ }
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+ if (!(flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) &&
+ openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set openssl_ciphers '%s'",
+ openssl_ciphers);
+ return -1;
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+#else /* CONFIG_SUITEB */
+ if (openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set openssl_ciphers '%s'",
+ openssl_ciphers);
+ return -1;
+ }
+#endif /* CONFIG_SUITEB */
+
+ return 0;
}
@@ -2050,7 +3040,8 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
}
- tls_set_conn_flags(conn->ssl, flags);
+ if (tls_set_conn_flags(conn, flags, NULL) < 0)
+ return -1;
conn->flags = flags;
SSL_set_accept_state(conn->ssl);
@@ -2082,6 +3073,17 @@ static int tls_connection_client_cert(struct tls_connection *conn,
if (client_cert == NULL && client_cert_blob == NULL)
return 0;
+#ifdef PKCS12_FUNCS
+#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
+ /*
+ * Clear previously set extra chain certificates, if any, from PKCS#12
+ * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
+ * chain properly.
+ */
+ SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
+#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+#endif /* PKCS12_FUNCS */
+
if (client_cert_blob &&
SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
client_cert_blob_len) == 1) {
@@ -2103,13 +3105,24 @@ static int tls_connection_client_cert(struct tls_connection *conn,
int ret = -1;
if (bio) {
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
- BIO_free(bio);
}
if (x509) {
if (SSL_use_certificate(conn->ssl, x509) == 1)
ret = 0;
X509_free(x509);
}
+
+ /* Read additional certificates into the chain. */
+ while (bio) {
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (x509) {
+ /* Takes ownership of x509 */
+ SSL_add0_chain_cert(conn->ssl, x509);
+ } else {
+ BIO_free(bio);
+ bio = NULL;
+ }
+ }
return ret;
}
#endif /* ANDROID */
@@ -2122,6 +3135,15 @@ static int tls_connection_client_cert(struct tls_connection *conn,
return 0;
}
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
+ if (SSL_use_certificate_chain_file(conn->ssl, client_cert) == 1) {
+ ERR_clear_error();
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_chain_file"
+ " --> OK");
+ return 0;
+ }
+#else
if (SSL_use_certificate_file(conn->ssl, client_cert,
SSL_FILETYPE_PEM) == 1) {
ERR_clear_error();
@@ -2129,6 +3151,7 @@ static int tls_connection_client_cert(struct tls_connection *conn,
" --> OK");
return 0;
}
+#endif
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_file failed");
@@ -2168,16 +3191,6 @@ static int tls_global_client_cert(struct tls_data *data,
}
-static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
-{
- if (password == NULL) {
- return 0;
- }
- os_strlcpy(buf, (char *) password, size);
- return os_strlen(buf);
-}
-
-
#ifdef PKCS12_FUNCS
static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
const char *passwd)
@@ -2229,28 +3242,42 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
}
if (certs) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
- SSL_clear_chain_certs(ssl);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
+ if (ssl)
+ SSL_clear_chain_certs(ssl);
+ else
+ SSL_CTX_clear_chain_certs(data->ssl);
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
wpa_printf(MSG_DEBUG, "TLS: additional certificate"
" from PKCS12: subject='%s'", buf);
- if (SSL_add1_chain_cert(ssl, cert) != 1) {
+ if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
+ (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
+ cert) != 1)) {
tls_show_errors(MSG_DEBUG, __func__,
"Failed to add additional certificate");
res = -1;
+ X509_free(cert);
break;
}
+ X509_free(cert);
}
if (!res) {
/* Try to continue anyway */
}
- sk_X509_free(certs);
+ sk_X509_pop_free(certs, X509_free);
#ifndef OPENSSL_IS_BORINGSSL
- res = SSL_build_cert_chain(ssl,
- SSL_BUILD_CHAIN_FLAG_CHECK |
- SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+ if (ssl)
+ res = SSL_build_cert_chain(
+ ssl,
+ SSL_BUILD_CHAIN_FLAG_CHECK |
+ SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+ else
+ res = SSL_CTX_build_cert_chain(
+ data->ssl,
+ SSL_BUILD_CHAIN_FLAG_CHECK |
+ SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
if (!res) {
tls_show_errors(MSG_DEBUG, __func__,
"Failed to build certificate chain");
@@ -2265,9 +3292,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
*/
res = 0;
#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
SSL_CTX_clear_extra_chain_certs(data->ssl);
-#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
@@ -2279,11 +3304,12 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
*/
if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
{
+ X509_free(cert);
res = -1;
break;
}
}
- sk_X509_free(certs);
+ sk_X509_pop_free(certs, X509_free);
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
}
@@ -2463,7 +3489,7 @@ static int tls_connection_engine_ca_cert(struct tls_data *data,
static int tls_connection_engine_private_key(struct tls_connection *conn)
{
-#ifndef OPENSSL_NO_ENGINE
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
tls_show_errors(MSG_ERROR, __func__,
"ENGINE: cannot use private key for TLS");
@@ -2483,6 +3509,64 @@ static int tls_connection_engine_private_key(struct tls_connection *conn)
}
+#ifndef OPENSSL_NO_STDIO
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
+{
+ if (!password)
+ return 0;
+ os_strlcpy(buf, (const char *) password, size);
+ return os_strlen(buf);
+}
+#endif /* OPENSSL_NO_STDIO */
+
+
+static int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
+ const char *private_key,
+ const char *private_key_passwd)
+{
+#ifndef OPENSSL_NO_STDIO
+ BIO *bio;
+ EVP_PKEY *pkey;
+ int ret;
+
+ /* First try ASN.1 (DER). */
+ bio = BIO_new_file(private_key, "r");
+ if (!bio)
+ return -1;
+ pkey = d2i_PrivateKey_bio(bio, NULL);
+ BIO_free(bio);
+
+ if (pkey) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s (DER) --> loaded", __func__);
+ } else {
+ /* Try PEM with the provided password. */
+ bio = BIO_new_file(private_key, "r");
+ if (!bio)
+ return -1;
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
+ (void *) private_key_passwd);
+ BIO_free(bio);
+ if (!pkey)
+ return -1;
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s (PEM) --> loaded", __func__);
+ /* Clear errors from the previous failed load. */
+ ERR_clear_error();
+ }
+
+ if (ssl)
+ ret = SSL_use_PrivateKey(ssl, pkey);
+ else
+ ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
+
+ EVP_PKEY_free(pkey);
+ return ret == 1 ? 0 : -1;
+#else /* OPENSSL_NO_STDIO */
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+ return -1;
+#endif /* OPENSSL_NO_STDIO */
+}
+
+
static int tls_connection_private_key(struct tls_data *data,
struct tls_connection *conn,
const char *private_key,
@@ -2490,23 +3574,11 @@ static int tls_connection_private_key(struct tls_data *data,
const u8 *private_key_blob,
size_t private_key_blob_len)
{
- SSL_CTX *ssl_ctx = data->ssl;
- char *passwd;
int ok;
if (private_key == NULL && private_key_blob == NULL)
return 0;
- if (private_key_passwd) {
- passwd = os_strdup(private_key_passwd);
- if (passwd == NULL)
- return -1;
- } else
- passwd = NULL;
-
- SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
- SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
-
ok = 0;
while (private_key_blob) {
if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
@@ -2537,7 +3609,8 @@ static int tls_connection_private_key(struct tls_data *data,
}
if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
- private_key_blob_len, passwd) == 0) {
+ private_key_blob_len,
+ private_key_passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
"OK");
ok = 1;
@@ -2548,29 +3621,14 @@ static int tls_connection_private_key(struct tls_data *data,
}
while (!ok && private_key) {
-#ifndef OPENSSL_NO_STDIO
- if (SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_ASN1) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: "
- "SSL_use_PrivateKey_File (DER) --> OK");
- ok = 1;
- break;
- }
-
- if (SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: "
- "SSL_use_PrivateKey_File (PEM) --> OK");
+ if (tls_use_private_key_file(data, conn->ssl, private_key,
+ private_key_passwd) == 0) {
ok = 1;
break;
}
-#else /* OPENSSL_NO_STDIO */
- wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
- __func__);
-#endif /* OPENSSL_NO_STDIO */
- if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
- == 0) {
+ if (tls_read_pkcs12(data, conn->ssl, private_key,
+ private_key_passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
"--> OK");
ok = 1;
@@ -2590,12 +3648,9 @@ static int tls_connection_private_key(struct tls_data *data,
if (!ok) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
- os_free(passwd);
return -1;
}
ERR_clear_error();
- SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
- os_free(passwd);
if (!SSL_check_private_key(conn->ssl)) {
tls_show_errors(MSG_INFO, __func__, "Private key failed "
@@ -2613,37 +3668,19 @@ static int tls_global_private_key(struct tls_data *data,
const char *private_key_passwd)
{
SSL_CTX *ssl_ctx = data->ssl;
- char *passwd;
if (private_key == NULL)
return 0;
- if (private_key_passwd) {
- passwd = os_strdup(private_key_passwd);
- if (passwd == NULL)
- return -1;
- } else
- passwd = NULL;
-
- SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
- SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
- if (
-#ifndef OPENSSL_NO_STDIO
- SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
- SSL_FILETYPE_ASN1) != 1 &&
- SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
- SSL_FILETYPE_PEM) != 1 &&
-#endif /* OPENSSL_NO_STDIO */
- tls_read_pkcs12(data, NULL, private_key, passwd)) {
+ if (tls_use_private_key_file(data, NULL, private_key,
+ private_key_passwd) &&
+ tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
- os_free(passwd);
ERR_clear_error();
return -1;
}
- os_free(passwd);
ERR_clear_error();
- SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
if (!SSL_CTX_check_private_key(ssl_ctx)) {
tls_show_errors(MSG_INFO, __func__,
@@ -2812,16 +3849,6 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
if (conn == NULL || keys == NULL)
return -1;
ssl = conn->ssl;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
- return -1;
-
- os_memset(keys, 0, sizeof(*keys));
- keys->client_random = ssl->s3->client_random;
- keys->client_random_len = SSL3_RANDOM_SIZE;
- keys->server_random = ssl->s3->server_random;
- keys->server_random_len = SSL3_RANDOM_SIZE;
-#else
if (ssl == NULL)
return -1;
@@ -2832,16 +3859,17 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
keys->server_random = conn->server_random;
keys->server_random_len = SSL_get_server_random(
ssl, conn->server_random, sizeof(conn->server_random));
-#endif
return 0;
}
-#ifndef CONFIG_FIPS
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
static int openssl_get_keyblock_size(SSL *ssl)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
const EVP_CIPHER *c;
const EVP_MD *h;
int md_size;
@@ -2851,17 +3879,11 @@ static int openssl_get_keyblock_size(SSL *ssl)
return -1;
c = ssl->enc_read_ctx->cipher;
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
h = EVP_MD_CTX_md(ssl->read_hash);
-#else
- h = ssl->read_hash;
-#endif
if (h)
md_size = EVP_MD_size(h);
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
else if (ssl->s3)
md_size = ssl->s3->tmp.new_mac_secret_size;
-#endif
else
return -1;
@@ -2899,86 +3921,26 @@ static int openssl_get_keyblock_size(SSL *ssl)
EVP_CIPHER_iv_length(c));
#endif
}
-#endif /* CONFIG_FIPS */
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
-static int openssl_tls_prf(struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
{
-#ifdef CONFIG_FIPS
- wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
- "mode");
- return -1;
-#else /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- SSL *ssl;
- u8 *rnd;
- int ret = -1;
- int skip = 0;
- u8 *tmp_out = NULL;
- u8 *_out = out;
- const char *ver;
-
- /*
- * TLS library did not support key generation, so get the needed TLS
- * session parameters and use an internal implementation of TLS PRF to
- * derive the key.
- */
-
- if (conn == NULL)
- return -1;
- ssl = conn->ssl;
- if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL ||
- ssl->session->master_key_length <= 0)
- return -1;
- ver = SSL_get_version(ssl);
-
- if (skip_keyblock) {
- skip = openssl_get_keyblock_size(ssl);
- if (skip < 0)
- return -1;
- tmp_out = os_malloc(skip + out_len);
- if (!tmp_out)
- return -1;
- _out = tmp_out;
- }
-
- rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
- if (!rnd) {
- os_free(tmp_out);
+ if (!conn ||
+ SSL_export_keying_material(conn->ssl, out, out_len, label,
+ os_strlen(label), context, context_len,
+ context != NULL) != 1)
return -1;
- }
-
- if (server_random_first) {
- os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
- SSL3_RANDOM_SIZE);
- } else {
- os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random,
- SSL3_RANDOM_SIZE);
- }
+ return 0;
+}
- if (os_strcmp(ver, "TLSv1.2") == 0) {
- tls_prf_sha256(ssl->session->master_key,
- ssl->session->master_key_length,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
- _out, skip + out_len);
- ret = 0;
- } else if (tls_prf_sha1_md5(ssl->session->master_key,
- ssl->session->master_key_length,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
- _out, skip + out_len) == 0) {
- ret = 0;
- }
- os_free(rnd);
- if (ret == 0 && skip_keyblock)
- os_memcpy(out, _out + skip, out_len);
- bin_clear_free(tmp_out, skip);
- return ret;
-#else
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
SSL *ssl;
SSL_SESSION *sess;
u8 *rnd;
@@ -2993,9 +3955,9 @@ static int openssl_tls_prf(struct tls_connection *conn,
const char *ver;
/*
- * TLS library did not support key generation, so get the needed TLS
- * session parameters and use an internal implementation of TLS PRF to
- * derive the key.
+ * TLS library did not support EAP-FAST key generation, so get the
+ * needed TLS session parameters and use an internal implementation of
+ * TLS PRF to derive the key.
*/
if (conn == NULL)
@@ -3008,15 +3970,13 @@ static int openssl_tls_prf(struct tls_connection *conn,
if (!ver || !sess)
return -1;
- if (skip_keyblock) {
- skip = openssl_get_keyblock_size(ssl);
- if (skip < 0)
- return -1;
- tmp_out = os_malloc(skip + out_len);
- if (!tmp_out)
- return -1;
- _out = tmp_out;
- }
+ skip = openssl_get_keyblock_size(ssl);
+ if (skip < 0)
+ return -1;
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
if (!rnd) {
@@ -3029,65 +3989,36 @@ static int openssl_tls_prf(struct tls_connection *conn,
master_key_len = SSL_SESSION_get_master_key(sess, master_key,
sizeof(master_key));
- if (server_random_first) {
- os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random,
- SSL3_RANDOM_SIZE);
- } else {
- os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random,
- SSL3_RANDOM_SIZE);
- }
+ os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
+ os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
if (os_strcmp(ver, "TLSv1.2") == 0) {
tls_prf_sha256(master_key, master_key_len,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
+ "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
_out, skip + out_len);
ret = 0;
} else if (tls_prf_sha1_md5(master_key, master_key_len,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
+ "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
_out, skip + out_len) == 0) {
ret = 0;
}
os_memset(master_key, 0, sizeof(master_key));
os_free(rnd);
- if (ret == 0 && skip_keyblock)
+ if (ret == 0)
os_memcpy(out, _out + skip, out_len);
bin_clear_free(tmp_out, skip);
return ret;
-#endif
-#endif /* CONFIG_FIPS */
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
-{
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- SSL *ssl;
- if (conn == NULL)
- return -1;
- if (server_random_first || skip_keyblock)
- return openssl_tls_prf(conn, label,
- server_random_first, skip_keyblock,
- out, out_len);
- ssl = conn->ssl;
- if (SSL_export_keying_material(ssl, out, out_len, label,
- os_strlen(label), NULL, 0, 0) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
- return 0;
- }
-#endif
- return openssl_tls_prf(conn, label, server_random_first,
- skip_keyblock, out, out_len);
+#else /* OPENSSL_NEED_EAP_FAST_PRF */
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
+ return -1;
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
}
static struct wpabuf *
-openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
- int server)
+openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
{
int res;
struct wpabuf *out_data;
@@ -3105,7 +4036,7 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
}
/* Initiate TLS handshake or continue the existing handshake */
- if (server)
+ if (conn->server)
res = SSL_accept(conn->ssl);
else
res = SSL_connect(conn->ssl);
@@ -3120,9 +4051,58 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
else {
tls_show_errors(MSG_INFO, __func__, "SSL_connect");
conn->failed++;
+ if (!conn->server && !conn->client_hello_generated) {
+ /* The server would not understand TLS Alert
+ * before ClientHello, so simply terminate
+ * handshake on this type of error case caused
+ * by a likely internal error like no ciphers
+ * available. */
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not generate ClientHello");
+ conn->write_alerts++;
+ return NULL;
+ }
}
}
+ if (!conn->server && !conn->failed)
+ conn->client_hello_generated = 1;
+
+#ifdef CONFIG_SUITEB
+ if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
+ os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
+ conn->server_dh_prime_len < 3072) {
+ struct tls_context *context = conn->context;
+
+ /*
+ * This should not be reached since earlier cert_cb should have
+ * terminated the handshake. Keep this check here for extra
+ * protection if anything goes wrong with the more low-level
+ * checks based on having to parse the TLS handshake messages.
+ */
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Server DH prime length: %d bits",
+ conn->server_dh_prime_len);
+
+ if (context->event_cb) {
+ union tls_event_data ev;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.alert.is_local = 1;
+ ev.alert.type = "fatal";
+ ev.alert.description = "insufficient security";
+ context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
+ }
+ /*
+ * Could send a TLS Alert to the server, but for now, simply
+ * terminate handshake.
+ */
+ conn->failed++;
+ conn->write_alerts++;
+ return NULL;
+ }
+#endif /* CONFIG_SUITEB */
+
/* Get the TLS handshake data to be sent to the server */
res = BIO_ctrl_pending(conn->ssl_out);
wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
@@ -3192,14 +4172,14 @@ openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
static struct wpabuf *
openssl_connection_handshake(struct tls_connection *conn,
const struct wpabuf *in_data,
- struct wpabuf **appl_data, int server)
+ struct wpabuf **appl_data)
{
struct wpabuf *out_data;
if (appl_data)
*appl_data = NULL;
- out_data = openssl_handshake(conn, in_data, server);
+ out_data = openssl_handshake(conn, in_data);
if (out_data == NULL)
return NULL;
if (conn->invalid_hb_used) {
@@ -3236,7 +4216,7 @@ tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
- return openssl_connection_handshake(conn, in_data, appl_data, 0);
+ return openssl_connection_handshake(conn, in_data, appl_data);
}
@@ -3245,7 +4225,8 @@ struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
- return openssl_connection_handshake(conn, in_data, appl_data, 1);
+ conn->server = 1;
+ return openssl_connection_handshake(conn, in_data, appl_data);
}
@@ -3340,18 +4321,14 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
{
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- return conn ? SSL_cache_hit(conn->ssl) : 0;
-#else
- return conn ? conn->ssl->hit : 0;
-#endif
+ return conn ? SSL_session_reused(conn->ssl) : 0;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
- char buf[100], *pos, *end;
+ char buf[500], *pos, *end;
u8 *c;
int ret;
@@ -3379,6 +4356,12 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
case TLS_CIPHER_ANON_DH_AES128_SHA:
suite = "ADH-AES128-SHA";
break;
+ case TLS_CIPHER_RSA_DHE_AES256_SHA:
+ suite = "DHE-RSA-AES256-SHA";
+ break;
+ case TLS_CIPHER_AES256_SHA:
+ suite = "AES256-SHA";
+ break;
default:
wpa_printf(MSG_DEBUG, "TLS: Unsupported "
"cipher selection: %d", *c);
@@ -3394,7 +4377,7 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
if (os_strstr(buf, ":ADH-")) {
/*
@@ -3579,7 +4562,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
{
struct tls_connection *conn = arg;
const unsigned char *p;
- int len, status, reason;
+ int len, status, reason, res;
OCSP_RESPONSE *rsp;
OCSP_BASICRESP *basic;
OCSP_CERTID *id;
@@ -3674,23 +4657,42 @@ static int ocsp_resp_cb(SSL *s, void *arg)
return 0;
}
- id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
+ id = OCSP_cert_to_id(EVP_sha256(), conn->peer_cert, conn->peer_issuer);
if (!id) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not create OCSP certificate identifier (SHA256)");
OCSP_BASICRESP_free(basic);
OCSP_RESPONSE_free(rsp);
return 0;
}
- if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
- &this_update, &next_update)) {
+ res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
+ &this_update, &next_update);
+ if (!res) {
+ id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
+ if (!id) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not create OCSP certificate identifier (SHA1)");
+ OCSP_BASICRESP_free(basic);
+ OCSP_RESPONSE_free(rsp);
+ return 0;
+ }
+
+ res = OCSP_resp_find_status(basic, id, &status, &reason,
+ &produced_at, &this_update,
+ &next_update);
+ }
+
+ if (!res) {
wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
(conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
" (OCSP not required)");
+ OCSP_CERTID_free(id);
OCSP_BASICRESP_free(basic);
OCSP_RESPONSE_free(rsp);
return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
}
+ OCSP_CERTID_free(id);
if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
tls_show_errors(MSG_INFO, __func__,
@@ -3765,10 +4767,17 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const char *cert_id = params->cert_id;
const char *ca_cert_id = params->ca_cert_id;
const char *engine_id = params->engine ? params->engine_id : NULL;
+ const char *ciphers;
if (conn == NULL)
return -1;
+ if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ocsp=3 not supported");
+ return -1;
+ }
+
/*
* If the engine isn't explicitly configured, and any of the
* cert/key fields are actually PKCS#11 URIs, then automatically
@@ -3800,7 +4809,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
engine_id = "pkcs11";
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (params->flags & TLS_CONN_EAP_FAST) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Use TLSv1_method() for EAP-FAST");
@@ -3811,6 +4820,17 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
}
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+#ifdef SSL_OP_NO_TLSv1_3
+ if (params->flags & TLS_CONN_EAP_FAST) {
+ /* Need to disable TLS v1.3 at least for now since OpenSSL 1.1.1
+ * refuses to start the handshake with the modified ciphersuite
+ * list (no TLS v1.3 ciphersuites included) for EAP-FAST. */
+ wpa_printf(MSG_DEBUG, "OpenSSL: Disable TLSv1.3 for EAP-FAST");
+ SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_3);
+ }
+#endif /* SSL_OP_NO_TLSv1_3 */
+#endif
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
while ((err = ERR_get_error())) {
@@ -3829,7 +4849,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
params->subject_match,
params->altsubject_match,
params->suffix_match,
- params->domain_match))
+ params->domain_match,
+ params->check_cert_subject))
return -1;
if (engine_id && ca_cert_id) {
@@ -3869,16 +4890,67 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
- if (params->openssl_ciphers &&
- SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+ ciphers = params->openssl_ciphers;
+#ifdef CONFIG_SUITEB
+#ifdef OPENSSL_IS_BORINGSSL
+ if (ciphers && os_strcmp(ciphers, "SUITEB192") == 0) {
+ /* BoringSSL removed support for SUITEB192, so need to handle
+ * this with hardcoded ciphersuite and additional checks for
+ * other parameters. */
+ ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384";
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+#endif /* CONFIG_SUITEB */
+ if (ciphers && SSL_set_cipher_list(conn->ssl, ciphers) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set cipher string '%s'",
- params->openssl_ciphers);
+ ciphers);
return -1;
}
- tls_set_conn_flags(conn->ssl, params->flags);
+ if (!params->openssl_ecdh_curves) {
+#ifndef OPENSSL_IS_BORINGSSL
+#ifndef OPENSSL_NO_EC
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
+ (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves to auto");
+ return -1;
+ }
+#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ } else if (params->openssl_ecdh_curves[0]) {
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ECDH configuration nnot supported");
+ return -1;
+#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#ifndef OPENSSL_NO_EC
+ if (SSL_set1_curves_list(conn->ssl,
+ params->openssl_ecdh_curves) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
+ return -1;
+ }
+#else /* OPENSSL_NO_EC */
+ wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
+ return -1;
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ }
+
+ if (tls_set_conn_flags(conn, params->flags,
+ params->openssl_ciphers) < 0)
+ return -1;
+#ifdef OPENSSL_IS_BORINGSSL
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ SSL_enable_ocsp_stapling(conn->ssl);
+ }
+#else /* OPENSSL_IS_BORINGSSL */
#ifdef HAVE_OCSP
if (params->flags & TLS_CONN_REQUEST_OCSP) {
SSL_CTX *ssl_ctx = data->ssl;
@@ -3897,6 +4969,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
"OpenSSL: No OCSP support included - allow optional OCSP case to continue");
}
#endif /* HAVE_OCSP */
+#endif /* OPENSSL_IS_BORINGSSL */
conn->flags = params->flags;
@@ -3918,6 +4991,15 @@ int tls_global_set_params(void *tls_ctx,
__func__, ERR_error_string(err, NULL));
}
+ os_free(data->check_cert_subject);
+ data->check_cert_subject = NULL;
+ if (params->check_cert_subject) {
+ data->check_cert_subject =
+ os_strdup(params->check_cert_subject);
+ if (!data->check_cert_subject)
+ return -1;
+ }
+
if (tls_global_ca_cert(data, params->ca_cert) ||
tls_global_client_cert(data, params->client_cert) ||
tls_global_private_key(data, params->private_key,
@@ -3935,13 +5017,49 @@ int tls_global_set_params(void *tls_ctx,
return -1;
}
+ if (!params->openssl_ecdh_curves) {
+#ifndef OPENSSL_IS_BORINGSSL
+#ifndef OPENSSL_NO_EC
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
+ (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves to auto");
+ return -1;
+ }
+#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ } else if (params->openssl_ecdh_curves[0]) {
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ECDH configuration nnot supported");
+ return -1;
+#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#ifndef OPENSSL_NO_EC
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
+#endif
+ if (SSL_CTX_set1_curves_list(ssl_ctx,
+ params->openssl_ecdh_curves) !=
+ 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
+ return -1;
+ }
+#else /* OPENSSL_NO_EC */
+ wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
+ return -1;
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
-#ifdef SSL_CTX_clear_options
else
SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
#endif /* SSL_OP_NO_TICKET */
#ifdef HAVE_OCSP
@@ -3964,7 +5082,7 @@ int tls_global_set_params(void *tls_ctx,
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
-#ifdef OPENSSL_IS_BORINGSSL
+#if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
STACK_OF(SSL_CIPHER) *peer_ciphers,
const SSL_CIPHER **cipher, void *arg)
@@ -3977,7 +5095,9 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
struct tls_connection *conn = arg;
int ret;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
@@ -4030,11 +5150,10 @@ static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
"extension", data, len);
- conn->session_ticket = os_malloc(len);
+ conn->session_ticket = os_memdup(data, len);
if (conn->session_ticket == NULL)
return 0;
- os_memcpy(conn->session_ticket, data, len);
conn->session_ticket_len = len;
return 1;
@@ -4072,9 +5191,15 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
int tls_get_library_version(char *buf, size_t buf_len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
+ OPENSSL_VERSION_TEXT,
+ OpenSSL_version(OPENSSL_VERSION));
+#else
return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
OPENSSL_VERSION_TEXT,
SSLeay_version(SSLEAY_VERSION));
+#endif
}
diff --git a/contrib/wpa/src/crypto/tls_openssl.h b/contrib/wpa/src/crypto/tls_openssl.h
new file mode 100644
index 0000000..2a62d5c
--- /dev/null
+++ b/contrib/wpa/src/crypto/tls_openssl.h
@@ -0,0 +1,19 @@
+/*
+ * SSL/TLS interface functions for OpenSSL
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLS_OPENSSL_H
+#define TLS_OPENSSL_H
+
+enum ocsp_result {
+ OCSP_GOOD, OCSP_REVOKED, OCSP_NO_RESPONSE, OCSP_INVALID
+};
+
+enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert,
+ X509 *issuer, X509 *issuer_issuer);
+
+#endif /* TLS_OPENSSL_H */
diff --git a/contrib/wpa/src/crypto/tls_openssl_ocsp.c b/contrib/wpa/src/crypto/tls_openssl_ocsp.c
new file mode 100644
index 0000000..8b37b34
--- /dev/null
+++ b/contrib/wpa/src/crypto/tls_openssl_ocsp.c
@@ -0,0 +1,846 @@
+/*
+ * SSL/TLS interface functions for OpenSSL - BoringSSL OCSP
+ * Copyright (c) 2004-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 <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#endif /* OPENSSL_IS_BORINGSSL */
+
+#include "common.h"
+#include "tls_openssl.h"
+
+
+#ifdef OPENSSL_IS_BORINGSSL
+
+static void tls_show_errors(int level, const char *func, const char *txt)
+{
+ unsigned long err;
+
+ wpa_printf(level, "OpenSSL: %s - %s %s",
+ func, txt, ERR_error_string(ERR_get_error(), NULL));
+
+ while ((err = ERR_get_error())) {
+ wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
+ ERR_error_string(err, NULL));
+ }
+}
+
+
+/*
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuer's public key
+ * serialNumber CertificateSerialNumber }
+ */
+typedef struct {
+ X509_ALGOR *hashAlgorithm;
+ ASN1_OCTET_STRING *issuerNameHash;
+ ASN1_OCTET_STRING *issuerKeyHash;
+ ASN1_INTEGER *serialNumber;
+} CertID;
+
+/*
+ * ResponseBytes ::= SEQUENCE {
+ * responseType OBJECT IDENTIFIER,
+ * response OCTET STRING }
+ */
+typedef struct {
+ ASN1_OBJECT *responseType;
+ ASN1_OCTET_STRING *response;
+} ResponseBytes;
+
+/*
+ * OCSPResponse ::= SEQUENCE {
+ * responseStatus OCSPResponseStatus,
+ * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+ */
+typedef struct {
+ ASN1_ENUMERATED *responseStatus;
+ ResponseBytes *responseBytes;
+} OCSPResponse;
+
+ASN1_SEQUENCE(ResponseBytes) = {
+ ASN1_SIMPLE(ResponseBytes, responseType, ASN1_OBJECT),
+ ASN1_SIMPLE(ResponseBytes, response, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(ResponseBytes);
+
+ASN1_SEQUENCE(OCSPResponse) = {
+ ASN1_SIMPLE(OCSPResponse, responseStatus, ASN1_ENUMERATED),
+ ASN1_EXP_OPT(OCSPResponse, responseBytes, ResponseBytes, 0)
+} ASN1_SEQUENCE_END(OCSPResponse);
+
+IMPLEMENT_ASN1_FUNCTIONS(OCSPResponse);
+
+/*
+ * ResponderID ::= CHOICE {
+ * byName [1] Name,
+ * byKey [2] KeyHash }
+ */
+typedef struct {
+ int type;
+ union {
+ X509_NAME *byName;
+ ASN1_OCTET_STRING *byKey;
+ } value;
+} ResponderID;
+
+/*
+ * RevokedInfo ::= SEQUENCE {
+ * revocationTime GeneralizedTime,
+ * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
+ */
+typedef struct {
+ ASN1_GENERALIZEDTIME *revocationTime;
+ ASN1_ENUMERATED *revocationReason;
+} RevokedInfo;
+
+/*
+ * CertStatus ::= CHOICE {
+ * good [0] IMPLICIT NULL,
+ * revoked [1] IMPLICIT RevokedInfo,
+ * unknown [2] IMPLICIT UnknownInfo }
+ */
+typedef struct {
+ int type;
+ union {
+ ASN1_NULL *good;
+ RevokedInfo *revoked;
+ ASN1_NULL *unknown;
+ } value;
+} CertStatus;
+
+/*
+ * SingleResponse ::= SEQUENCE {
+ * certID CertID,
+ * certStatus CertStatus,
+ * thisUpdate GeneralizedTime,
+ * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct {
+ CertID *certID;
+ CertStatus *certStatus;
+ ASN1_GENERALIZEDTIME *thisUpdate;
+ ASN1_GENERALIZEDTIME *nextUpdate;
+ STACK_OF(X509_EXTENSION) *singleExtensions;
+} SingleResponse;
+
+/*
+ * ResponseData ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * responderID ResponderID,
+ * producedAt GeneralizedTime,
+ * responses SEQUENCE OF SingleResponse,
+ * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct {
+ ASN1_INTEGER *version;
+ ResponderID *responderID;
+ ASN1_GENERALIZEDTIME *producedAt;
+ STACK_OF(SingleResponse) *responses;
+ STACK_OF(X509_EXTENSION) *responseExtensions;
+} ResponseData;
+
+/*
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+typedef struct {
+ ResponseData *tbsResponseData;
+ X509_ALGOR *signatureAlgorithm;
+ ASN1_BIT_STRING *signature;
+ STACK_OF(X509) *certs;
+} BasicOCSPResponse;
+
+ASN1_SEQUENCE(CertID) = {
+ ASN1_SIMPLE(CertID, hashAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE(CertID, issuerNameHash, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(CertID, issuerKeyHash, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(CertID, serialNumber, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(CertID);
+
+ASN1_CHOICE(ResponderID) = {
+ ASN1_EXP(ResponderID, value.byName, X509_NAME, 1),
+ ASN1_EXP(ResponderID, value.byKey, ASN1_OCTET_STRING, 2)
+} ASN1_CHOICE_END(ResponderID);
+
+ASN1_SEQUENCE(RevokedInfo) = {
+ ASN1_SIMPLE(RevokedInfo, revocationTime, ASN1_GENERALIZEDTIME),
+ ASN1_EXP_OPT(RevokedInfo, revocationReason, ASN1_ENUMERATED, 0)
+} ASN1_SEQUENCE_END(RevokedInfo);
+
+ASN1_CHOICE(CertStatus) = {
+ ASN1_IMP(CertStatus, value.good, ASN1_NULL, 0),
+ ASN1_IMP(CertStatus, value.revoked, RevokedInfo, 1),
+ ASN1_IMP(CertStatus, value.unknown, ASN1_NULL, 2)
+} ASN1_CHOICE_END(CertStatus);
+
+ASN1_SEQUENCE(SingleResponse) = {
+ ASN1_SIMPLE(SingleResponse, certID, CertID),
+ ASN1_SIMPLE(SingleResponse, certStatus, CertStatus),
+ ASN1_SIMPLE(SingleResponse, thisUpdate, ASN1_GENERALIZEDTIME),
+ ASN1_EXP_OPT(SingleResponse, nextUpdate, ASN1_GENERALIZEDTIME, 0),
+ ASN1_EXP_SEQUENCE_OF_OPT(SingleResponse, singleExtensions,
+ X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(SingleResponse);
+
+ASN1_SEQUENCE(ResponseData) = {
+ ASN1_EXP_OPT(ResponseData, version, ASN1_INTEGER, 0),
+ ASN1_SIMPLE(ResponseData, responderID, ResponderID),
+ ASN1_SIMPLE(ResponseData, producedAt, ASN1_GENERALIZEDTIME),
+ ASN1_SEQUENCE_OF(ResponseData, responses, SingleResponse),
+ ASN1_EXP_SEQUENCE_OF_OPT(ResponseData, responseExtensions,
+ X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(ResponseData);
+
+ASN1_SEQUENCE(BasicOCSPResponse) = {
+ ASN1_SIMPLE(BasicOCSPResponse, tbsResponseData, ResponseData),
+ ASN1_SIMPLE(BasicOCSPResponse, signatureAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE(BasicOCSPResponse, signature, ASN1_BIT_STRING),
+ ASN1_EXP_SEQUENCE_OF_OPT(BasicOCSPResponse, certs, X509, 0)
+} ASN1_SEQUENCE_END(BasicOCSPResponse);
+
+IMPLEMENT_ASN1_FUNCTIONS(BasicOCSPResponse);
+
+#define sk_SingleResponse_num(sk) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk))
+
+#define sk_SingleResponse_value(sk, i) \
+ ((SingleResponse *) \
+ sk_value(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk), (i)))
+
+
+static char * mem_bio_to_str(BIO *out)
+{
+ char *txt;
+ size_t rlen;
+ int res;
+
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (!txt) {
+ BIO_free(out);
+ return NULL;
+ }
+
+ res = BIO_read(out, txt, rlen);
+ BIO_free(out);
+ if (res < 0) {
+ os_free(txt);
+ return NULL;
+ }
+
+ txt[res] = '\0';
+ return txt;
+}
+
+
+static char * generalizedtime_str(ASN1_GENERALIZEDTIME *t)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ if (!ASN1_GENERALIZEDTIME_print(out, t)) {
+ BIO_free(out);
+ return NULL;
+ }
+
+ return mem_bio_to_str(out);
+}
+
+
+static char * responderid_str(ResponderID *rid)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ switch (rid->type) {
+ case 0:
+ X509_NAME_print_ex(out, rid->value.byName, 0, XN_FLAG_ONELINE);
+ break;
+ case 1:
+ i2a_ASN1_STRING(out, rid->value.byKey, V_ASN1_OCTET_STRING);
+ break;
+ default:
+ BIO_free(out);
+ return NULL;
+ }
+
+ return mem_bio_to_str(out);
+}
+
+
+static char * octet_string_str(ASN1_OCTET_STRING *o)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ i2a_ASN1_STRING(out, o, V_ASN1_OCTET_STRING);
+ return mem_bio_to_str(out);
+}
+
+
+static char * integer_str(ASN1_INTEGER *i)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ i2a_ASN1_INTEGER(out, i);
+ return mem_bio_to_str(out);
+}
+
+
+static char * algor_str(X509_ALGOR *alg)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ i2a_ASN1_OBJECT(out, alg->algorithm);
+ return mem_bio_to_str(out);
+}
+
+
+static char * extensions_str(const char *title, STACK_OF(X509_EXTENSION) *ext)
+{
+ BIO *out;
+
+ if (!ext)
+ return NULL;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ if (!X509V3_extensions_print(out, title, ext, 0, 0)) {
+ BIO_free(out);
+ return NULL;
+ }
+ return mem_bio_to_str(out);
+}
+
+
+static int ocsp_resp_valid(ASN1_GENERALIZEDTIME *thisupd,
+ ASN1_GENERALIZEDTIME *nextupd)
+{
+ time_t now, tmp;
+
+ if (!ASN1_GENERALIZEDTIME_check(thisupd)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid OCSP response thisUpdate");
+ return 0;
+ }
+
+ time(&now);
+ tmp = now + 5 * 60; /* allow five minute clock difference */
+ if (X509_cmp_time(thisupd, &tmp) > 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response not yet valid");
+ return 0;
+ }
+
+ if (!nextupd)
+ return 1; /* OK - no limit on response age */
+
+ if (!ASN1_GENERALIZEDTIME_check(nextupd)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid OCSP response nextUpdate");
+ return 0;
+ }
+
+ tmp = now - 5 * 60; /* allow five minute clock difference */
+ if (X509_cmp_time(nextupd, &tmp) < 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response expired");
+ return 0;
+ }
+
+ if (ASN1_STRING_cmp(nextupd, thisupd) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response nextUpdate before thisUpdate");
+ return 0;
+ }
+
+ /* Both thisUpdate and nextUpdate are valid */
+ return -1;
+}
+
+
+static int issuer_match(X509 *cert, X509 *issuer, CertID *certid)
+{
+ X509_NAME *iname;
+ ASN1_BIT_STRING *ikey;
+ const EVP_MD *dgst;
+ unsigned int len;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ ASN1_OCTET_STRING *hash;
+ char *txt;
+
+ dgst = EVP_get_digestbyobj(certid->hashAlgorithm->algorithm);
+ if (!dgst) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not find matching hash algorithm for OCSP");
+ return -1;
+ }
+
+ iname = X509_get_issuer_name(cert);
+ if (!X509_NAME_digest(iname, dgst, md, &len))
+ return -1;
+ hash = ASN1_OCTET_STRING_new();
+ if (!hash)
+ return -1;
+ if (!ASN1_OCTET_STRING_set(hash, md, len)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ txt = octet_string_str(hash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerNameHash: %s",
+ txt);
+ os_free(txt);
+ }
+
+ if (ASN1_OCTET_STRING_cmp(certid->issuerNameHash, hash)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ ikey = X509_get0_pubkey_bitstr(issuer);
+ if (!ikey ||
+ !EVP_Digest(ikey->data, ikey->length, md, &len, dgst, NULL) ||
+ !ASN1_OCTET_STRING_set(hash, md, len)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ txt = octet_string_str(hash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerKeyHash: %s",
+ txt);
+ os_free(txt);
+ }
+
+ if (ASN1_OCTET_STRING_cmp(certid->issuerKeyHash, hash)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ ASN1_OCTET_STRING_free(hash);
+ return 0;
+}
+
+
+static X509 * ocsp_find_signer(STACK_OF(X509) *certs, ResponderID *rid)
+{
+ unsigned int i;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (rid->type == 0) {
+ /* byName */
+ return X509_find_by_subject(certs, rid->value.byName);
+ }
+
+ /* byKey */
+ if (rid->value.byKey->length != SHA_DIGEST_LENGTH)
+ return NULL;
+ for (i = 0; i < sk_X509_num(certs); i++) {
+ X509 *x = sk_X509_value(certs, i);
+
+ X509_pubkey_digest(x, EVP_sha1(), hash, NULL);
+ if (os_memcmp(rid->value.byKey->data, hash,
+ SHA_DIGEST_LENGTH) == 0)
+ return x;
+ }
+
+ return NULL;
+}
+
+
+enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert,
+ X509 *issuer, X509 *issuer_issuer)
+{
+ const uint8_t *resp_data;
+ size_t resp_len;
+ OCSPResponse *resp;
+ int status;
+ ResponseBytes *bytes;
+ const u8 *basic_data;
+ size_t basic_len;
+ BasicOCSPResponse *basic;
+ ResponseData *rd;
+ char *txt;
+ int i, num;
+ unsigned int j, num_resp;
+ SingleResponse *matching_resp = NULL, *cmp_sresp;
+ enum ocsp_result result = OCSP_INVALID;
+ X509_STORE *store;
+ STACK_OF(X509) *untrusted = NULL, *certs = NULL, *chain = NULL;
+ X509_STORE_CTX ctx;
+ X509 *signer, *tmp_cert;
+ int signer_trusted = 0;
+ EVP_PKEY *skey;
+ int ret;
+ char buf[256];
+
+ txt = integer_str(X509_get_serialNumber(cert));
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Searching OCSP response for peer certificate serialNumber: %s", txt);
+ os_free(txt);
+ }
+
+ SSL_get0_ocsp_response(ssl, &resp_data, &resp_len);
+ if (resp_data == NULL || resp_len == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+ return OCSP_NO_RESPONSE;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", resp_data, resp_len);
+
+ resp = d2i_OCSPResponse(NULL, &resp_data, resp_len);
+ if (!resp) {
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSPResponse");
+ return OCSP_INVALID;
+ }
+
+ status = ASN1_ENUMERATED_get(resp->responseStatus);
+ if (status != 0) {
+ wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d",
+ status);
+ return OCSP_INVALID;
+ }
+
+ bytes = resp->responseBytes;
+
+ if (!bytes ||
+ OBJ_obj2nid(bytes->responseType) != NID_id_pkix_OCSP_basic) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Could not find BasicOCSPResponse");
+ return OCSP_INVALID;
+ }
+
+ basic_data = ASN1_STRING_data(bytes->response);
+ basic_len = ASN1_STRING_length(bytes->response);
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: BasicOCSPResponse",
+ basic_data, basic_len);
+
+ basic = d2i_BasicOCSPResponse(NULL, &basic_data, basic_len);
+ if (!basic) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Could not parse BasicOCSPResponse");
+ OCSPResponse_free(resp);
+ return OCSP_INVALID;
+ }
+
+ rd = basic->tbsResponseData;
+
+ if (basic->certs) {
+ untrusted = sk_X509_dup(basic->certs);
+ if (!untrusted)
+ goto fail;
+
+ num = sk_X509_num(basic->certs);
+ for (i = 0; i < num; i++) {
+ X509 *extra_cert;
+
+ extra_cert = sk_X509_value(basic->certs, i);
+ X509_NAME_oneline(X509_get_subject_name(extra_cert),
+ buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: BasicOCSPResponse cert %s", buf);
+
+ if (!sk_X509_push(untrusted, extra_cert)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not add certificate to the untrusted stack");
+ }
+ }
+ }
+
+ store = SSL_CTX_get_cert_store(ssl_ctx);
+ if (issuer) {
+ if (X509_STORE_add_cert(store, issuer) != 1) {
+ tls_show_errors(MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer to certificate store");
+ }
+ certs = sk_X509_new_null();
+ if (certs) {
+ tmp_cert = X509_dup(issuer);
+ if (tmp_cert && !sk_X509_push(certs, tmp_cert)) {
+ tls_show_errors(
+ MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer to OCSP responder trust store");
+ X509_free(tmp_cert);
+ sk_X509_free(certs);
+ certs = NULL;
+ }
+ if (certs && issuer_issuer) {
+ tmp_cert = X509_dup(issuer_issuer);
+ if (tmp_cert &&
+ !sk_X509_push(certs, tmp_cert)) {
+ tls_show_errors(
+ MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
+ X509_free(tmp_cert);
+ }
+ }
+ }
+ }
+
+ signer = ocsp_find_signer(certs, rd->responderID);
+ if (!signer)
+ signer = ocsp_find_signer(untrusted, rd->responderID);
+ else
+ signer_trusted = 1;
+ if (!signer) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not find OCSP signer certificate");
+ goto fail;
+ }
+
+ skey = X509_get_pubkey(signer);
+ if (!skey) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not get OCSP signer public key");
+ goto fail;
+ }
+ if (ASN1_item_verify(ASN1_ITEM_rptr(ResponseData),
+ basic->signatureAlgorithm, basic->signature,
+ basic->tbsResponseData, skey) <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: BasicOCSPResponse signature is invalid");
+ goto fail;
+ }
+
+ X509_NAME_oneline(X509_get_subject_name(signer), buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Found OCSP signer certificate %s and verified BasicOCSPResponse signature",
+ buf);
+
+ if (!X509_STORE_CTX_init(&ctx, store, signer, untrusted))
+ goto fail;
+ X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER);
+ ret = X509_verify_cert(&ctx);
+ chain = X509_STORE_CTX_get1_chain(&ctx);
+ X509_STORE_CTX_cleanup(&ctx);
+ if (ret <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not validate OCSP signer certificate");
+ goto fail;
+ }
+
+ if (!chain || sk_X509_num(chain) <= 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP signer chain found");
+ goto fail;
+ }
+
+ if (!signer_trusted) {
+ X509_check_purpose(signer, -1, 0);
+ if ((signer->ex_flags & EXFLAG_XKUSAGE) &&
+ (signer->ex_xkusage & XKU_OCSP_SIGN)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP signer certificate delegation OK");
+ } else {
+ tmp_cert = sk_X509_value(chain, sk_X509_num(chain) - 1);
+ if (X509_check_trust(tmp_cert, NID_OCSP_sign, 0) !=
+ X509_TRUST_TRUSTED) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP signer certificate not trusted");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP version: %lu",
+ ASN1_INTEGER_get(rd->version));
+
+ txt = responderid_str(rd->responderID);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP responderID: %s",
+ txt);
+ os_free(txt);
+ }
+
+ txt = generalizedtime_str(rd->producedAt);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP producedAt: %s",
+ txt);
+ os_free(txt);
+ }
+
+ num_resp = sk_SingleResponse_num(rd->responses);
+ if (num_resp == 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: No OCSP SingleResponse within BasicOCSPResponse");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+ cmp_sresp = sk_SingleResponse_value(rd->responses, 0);
+ for (j = 0; j < num_resp; j++) {
+ SingleResponse *sresp;
+ CertID *cid1, *cid2;
+
+ sresp = sk_SingleResponse_value(rd->responses, j);
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP SingleResponse %u/%u",
+ j + 1, num_resp);
+
+ txt = algor_str(sresp->certID->hashAlgorithm);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID hashAlgorithm: %s", txt);
+ os_free(txt);
+ }
+
+ txt = octet_string_str(sresp->certID->issuerNameHash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID issuerNameHash: %s", txt);
+ os_free(txt);
+ }
+
+ txt = octet_string_str(sresp->certID->issuerKeyHash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID issuerKeyHash: %s", txt);
+ os_free(txt);
+ }
+
+ txt = integer_str(sresp->certID->serialNumber);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID serialNumber: %s", txt);
+ os_free(txt);
+ }
+
+ switch (sresp->certStatus->type) {
+ case 0:
+ wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: good");
+ break;
+ case 1:
+ wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: revoked");
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: unknown");
+ break;
+ }
+
+ txt = generalizedtime_str(sresp->thisUpdate);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: thisUpdate: %s", txt);
+ os_free(txt);
+ }
+
+ if (sresp->nextUpdate) {
+ txt = generalizedtime_str(sresp->nextUpdate);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: nextUpdate: %s",
+ txt);
+ os_free(txt);
+ }
+ }
+
+ txt = extensions_str("singleExtensions",
+ sresp->singleExtensions);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
+ os_free(txt);
+ }
+
+ cid1 = cmp_sresp->certID;
+ cid2 = sresp->certID;
+ if (j > 0 &&
+ (OBJ_cmp(cid1->hashAlgorithm->algorithm,
+ cid2->hashAlgorithm->algorithm) != 0 ||
+ ASN1_OCTET_STRING_cmp(cid1->issuerNameHash,
+ cid2->issuerNameHash) != 0 ||
+ ASN1_OCTET_STRING_cmp(cid1->issuerKeyHash,
+ cid2->issuerKeyHash) != 0)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Different OCSP response issuer information between SingleResponse values within BasicOCSPResponse");
+ goto fail;
+ }
+
+ if (!matching_resp && issuer &&
+ ASN1_INTEGER_cmp(sresp->certID->serialNumber,
+ X509_get_serialNumber(cert)) == 0 &&
+ issuer_match(cert, issuer, sresp->certID) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: This response matches peer certificate");
+ matching_resp = sresp;
+ }
+ }
+
+ txt = extensions_str("responseExtensions", rd->responseExtensions);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
+ os_free(txt);
+ }
+
+ if (!matching_resp) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not find OCSP response that matches the peer certificate");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+
+ if (!ocsp_resp_valid(matching_resp->thisUpdate,
+ matching_resp->nextUpdate)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response not valid at this time");
+ goto fail;
+ }
+
+ if (matching_resp->certStatus->type == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response indicated that the peer certificate has been revoked");
+ result = OCSP_REVOKED;
+ goto fail;
+ }
+
+ if (matching_resp->certStatus->type != 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response did not indicate good status");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+
+ /* OCSP response indicated the certificate is good. */
+ result = OCSP_GOOD;
+fail:
+ sk_X509_pop_free(chain, X509_free);
+ sk_X509_free(untrusted);
+ sk_X509_pop_free(certs, X509_free);
+ BasicOCSPResponse_free(basic);
+ OCSPResponse_free(resp);
+
+ return result;
+}
+
+#endif /* OPENSSL_IS_BORINGSSL */
diff --git a/contrib/wpa/src/crypto/tls_wolfssl.c b/contrib/wpa/src/crypto/tls_wolfssl.c
new file mode 100644
index 0000000..e9cb425
--- /dev/null
+++ b/contrib/wpa/src/crypto/tls_wolfssl.c
@@ -0,0 +1,2201 @@
+/*
+ * SSL/TLS interface functions for wolfSSL TLS case
+ * Copyright (c) 2004-2017, 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.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "tls.h"
+
+/* wolfSSL includes */
+#include <wolfssl/options.h>
+#include <wolfssl/ssl.h>
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/wolfcrypt/asn.h>
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#define HAVE_AESGCM
+#include <wolfssl/wolfcrypt/aes.h>
+#endif
+
+#if !defined(CONFIG_FIPS) && \
+ (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
+ defined(EAP_SERVER_FAST))
+#define WOLFSSL_NEED_EAP_FAST_PRF
+#endif
+
+#define SECRET_LEN 48
+#define RAN_LEN 32
+#define SESSION_TICKET_LEN 256
+
+static int tls_ref_count = 0;
+
+static int tls_ex_idx_session = 0;
+
+
+/* tls input data for wolfSSL Read Callback */
+struct tls_in_data {
+ const struct wpabuf *in_data;
+ size_t consumed; /* how many bytes have we used already */
+};
+
+/* tls output data for wolfSSL Write Callback */
+struct tls_out_data {
+ struct wpabuf *out_data;
+};
+
+struct tls_context {
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data);
+ void *cb_ctx;
+ int cert_in_cb;
+ char *ocsp_stapling_response;
+};
+
+static struct tls_context *tls_global = NULL;
+
+/* wolfssl tls_connection */
+struct tls_connection {
+ struct tls_context *context;
+ WOLFSSL *ssl;
+ int read_alerts;
+ int write_alerts;
+ int failed;
+ struct tls_in_data input;
+ struct tls_out_data output;
+ char *subject_match;
+ char *alt_subject_match;
+ char *suffix_match;
+ char *domain_match;
+
+ u8 srv_cert_hash[32];
+
+ unsigned char client_random[RAN_LEN];
+ unsigned char server_random[RAN_LEN];
+ unsigned int flags;
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+ tls_session_ticket_cb session_ticket_cb;
+ void *session_ticket_cb_ctx;
+ byte session_ticket[SESSION_TICKET_LEN];
+#endif
+ unsigned int ca_cert_verify:1;
+ unsigned int cert_probe:1;
+ unsigned int server_cert_only:1;
+ unsigned int success_data:1;
+
+ WOLFSSL_X509 *peer_cert;
+ WOLFSSL_X509 *peer_issuer;
+ WOLFSSL_X509 *peer_issuer_issuer;
+};
+
+
+static struct tls_context * tls_context_new(const struct tls_config *conf)
+{
+ struct tls_context *context = os_zalloc(sizeof(*context));
+
+ if (!context)
+ return NULL;
+
+ if (conf) {
+ context->event_cb = conf->event_cb;
+ context->cb_ctx = conf->cb_ctx;
+ context->cert_in_cb = conf->cert_in_cb;
+ }
+
+ return context;
+}
+
+
+static void wolfssl_reset_in_data(struct tls_in_data *in,
+ const struct wpabuf *buf)
+{
+ /* old one not owned by us so don't free */
+ in->in_data = buf;
+ in->consumed = 0;
+}
+
+
+static void wolfssl_reset_out_data(struct tls_out_data *out)
+{
+ /* old one not owned by us so don't free */
+ out->out_data = wpabuf_alloc_copy("", 0);
+}
+
+
+/* wolfSSL I/O Receive CallBack */
+static int wolfssl_receive_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+ size_t get = sz;
+ struct tls_in_data *data = ctx;
+
+ if (!data)
+ return -1;
+
+ if (get > (wpabuf_len(data->in_data) - data->consumed))
+ get = wpabuf_len(data->in_data) - data->consumed;
+
+ os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get);
+ data->consumed += get;
+
+ if (get == 0)
+ return -2; /* WANT_READ */
+
+ return (int) get;
+}
+
+
+/* wolfSSL I/O Send CallBack */
+static int wolfssl_send_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+ struct wpabuf *tmp;
+ struct tls_out_data *data = ctx;
+
+ if (!data)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "SSL: adding %d bytes", sz);
+
+ tmp = wpabuf_alloc_copy(buf, sz);
+ if (!tmp)
+ return -1;
+ data->out_data = wpabuf_concat(data->out_data, tmp);
+ if (!data->out_data)
+ return -1;
+
+ return sz;
+}
+
+
+static void remove_session_cb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
+{
+ struct wpabuf *buf;
+
+ buf = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (!buf)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Free application session data %p (sess %p)",
+ buf, sess);
+ wpabuf_free(buf);
+
+ wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+ WOLFSSL_CTX *ssl_ctx;
+ struct tls_context *context;
+ const char *ciphers;
+
+#ifdef DEBUG_WOLFSSL
+ wolfSSL_Debugging_ON();
+#endif /* DEBUG_WOLFSSL */
+
+ context = tls_context_new(conf);
+ if (!context)
+ return NULL;
+
+ if (tls_ref_count == 0) {
+ tls_global = context;
+
+ if (wolfSSL_Init() < 0)
+ return NULL;
+ /* wolfSSL_Debugging_ON(); */
+ }
+
+ tls_ref_count++;
+
+ /* start as client */
+ ssl_ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
+ if (!ssl_ctx) {
+ tls_ref_count--;
+ if (context != tls_global)
+ os_free(context);
+ if (tls_ref_count == 0) {
+ os_free(tls_global);
+ tls_global = NULL;
+ }
+ }
+ wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb);
+ wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb);
+ wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context);
+
+ if (conf->tls_session_lifetime > 0) {
+ wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1);
+ wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
+ SSL_SESS_CACHE_SERVER);
+ wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime);
+ wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb);
+ } else {
+ wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
+ SSL_SESS_CACHE_CLIENT);
+ }
+
+ if (conf && conf->openssl_ciphers)
+ ciphers = conf->openssl_ciphers;
+ else
+ ciphers = "ALL";
+ if (wolfSSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Failed to set cipher string '%s'",
+ ciphers);
+ tls_deinit(ssl_ctx);
+ return NULL;
+ }
+
+ return ssl_ctx;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+ struct tls_context *context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+
+ if (context != tls_global)
+ os_free(context);
+
+ wolfSSL_CTX_free((WOLFSSL_CTX *) ssl_ctx);
+
+ tls_ref_count--;
+ if (tls_ref_count == 0) {
+ wolfSSL_Cleanup();
+ os_free(tls_global);
+ tls_global = NULL;
+ }
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+#ifdef DEBUG_WOLFSSL
+#if 0
+ unsigned long err;
+
+ err = wolfSSL_ERR_peek_last_error_line(NULL, NULL);
+ if (err != 0) {
+ wpa_printf(MSG_INFO, "TLS - SSL error: %s",
+ wolfSSL_ERR_error_string(err, NULL));
+ return 1;
+ }
+#endif
+#endif /* DEBUG_WOLFSSL */
+ return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+ WOLFSSL_CTX *ssl_ctx = tls_ctx;
+ struct tls_connection *conn;
+
+ wpa_printf(MSG_DEBUG, "SSL: connection init");
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn)
+ return NULL;
+ conn->ssl = wolfSSL_new(ssl_ctx);
+ if (!conn->ssl) {
+ os_free(conn);
+ return NULL;
+ }
+
+ wolfSSL_SetIOReadCtx(conn->ssl, &conn->input);
+ wolfSSL_SetIOWriteCtx(conn->ssl, &conn->output);
+ wolfSSL_set_ex_data(conn->ssl, 0, conn);
+ conn->context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+
+ /* Need randoms post-hanshake for EAP-FAST, export key and deriving
+ * session ID in EAP methods. */
+ wolfSSL_KeepArrays(conn->ssl);
+ wolfSSL_KeepHandshakeResources(conn->ssl);
+ wolfSSL_UseClientSuites(conn->ssl);
+
+ return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+ if (!conn)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SSL: connection deinit");
+
+ /* parts */
+ wolfSSL_free(conn->ssl);
+ os_free(conn->subject_match);
+ os_free(conn->alt_subject_match);
+ os_free(conn->suffix_match);
+ os_free(conn->domain_match);
+
+ /* self */
+ os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+ return conn ? wolfSSL_is_init_finished(conn->ssl) : 0;
+}
+
+
+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)
+{
+ WOLFSSL_SESSION *session;
+
+ if (!conn)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "SSL: connection shutdown");
+
+ /* Set quiet as OpenSSL does */
+ wolfSSL_set_quiet_shutdown(conn->ssl, 1);
+ wolfSSL_shutdown(conn->ssl);
+
+ session = wolfSSL_get_session(conn->ssl);
+ if (wolfSSL_clear(conn->ssl) != 1)
+ return -1;
+ wolfSSL_set_session(conn->ssl, session);
+
+ return 0;
+}
+
+
+static int tls_connection_set_subject_match(struct tls_connection *conn,
+ const char *subject_match,
+ const char *alt_subject_match,
+ const char *suffix_match,
+ const char *domain_match)
+{
+ os_free(conn->subject_match);
+ conn->subject_match = NULL;
+ if (subject_match) {
+ conn->subject_match = os_strdup(subject_match);
+ if (!conn->subject_match)
+ return -1;
+ }
+
+ os_free(conn->alt_subject_match);
+ conn->alt_subject_match = NULL;
+ if (alt_subject_match) {
+ conn->alt_subject_match = os_strdup(alt_subject_match);
+ if (!conn->alt_subject_match)
+ return -1;
+ }
+
+ os_free(conn->suffix_match);
+ conn->suffix_match = NULL;
+ if (suffix_match) {
+ conn->suffix_match = os_strdup(suffix_match);
+ if (!conn->suffix_match)
+ return -1;
+ }
+
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (domain_match) {
+ conn->domain_match = os_strdup(domain_match);
+ if (!conn->domain_match)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int tls_connection_dh(struct tls_connection *conn, const char *dh_file,
+ const u8 *dh_blob, size_t blob_len)
+{
+ if (!dh_file && !dh_blob)
+ return 0;
+
+ wolfSSL_set_accept_state(conn->ssl);
+
+ if (dh_blob) {
+ if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO, "SSL: use DH DER blob failed");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use DH blob OK");
+ return 0;
+ }
+
+ if (dh_file) {
+ wpa_printf(MSG_INFO, "SSL: use DH PEM file: %s", dh_file);
+ if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
+ SSL_FILETYPE_PEM) < 0) {
+ wpa_printf(MSG_INFO, "SSL: use DH PEM file failed");
+ if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use DH DER file failed");
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use DH file OK");
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static int tls_connection_client_cert(struct tls_connection *conn,
+ const char *client_cert,
+ const u8 *client_cert_blob,
+ size_t blob_len)
+{
+ if (!client_cert && !client_cert_blob)
+ return 0;
+
+ if (client_cert_blob) {
+ if (wolfSSL_use_certificate_chain_buffer_format(
+ conn->ssl, client_cert_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert DER blob failed");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK");
+ return 0;
+ }
+
+ if (client_cert) {
+ if (wolfSSL_use_certificate_chain_file(conn->ssl,
+ client_cert) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert PEM file failed");
+ if (wolfSSL_use_certificate_chain_file_format(
+ conn->ssl, client_cert,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert DER file failed");
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use client cert file OK");
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
+{
+ if (!password)
+ return 0;
+ os_strlcpy(buf, (char *) password, size);
+ return os_strlen(buf);
+}
+
+
+static int tls_connection_private_key(void *tls_ctx,
+ struct tls_connection *conn,
+ const char *private_key,
+ const char *private_key_passwd,
+ const u8 *private_key_blob,
+ size_t blob_len)
+{
+ WOLFSSL_CTX *ctx = tls_ctx;
+ char *passwd = NULL;
+ int ok = 0;
+
+ if (!private_key && !private_key_blob)
+ return 0;
+
+ if (private_key_passwd) {
+ passwd = os_strdup(private_key_passwd);
+ if (!passwd)
+ return -1;
+ }
+
+ wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+ wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+ if (private_key_blob) {
+ if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
+ private_key_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use private DER blob failed");
+ } else {
+ wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
+ ok = 1;
+ }
+ }
+
+ if (!ok && private_key) {
+ if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_PEM) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use private key PEM file failed");
+ if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_ASN1) < 0)
+ {
+ wpa_printf(MSG_INFO,
+ "SSL: use private key DER file failed");
+ } else {
+ ok = 1;
+ }
+ } else {
+ ok = 1;
+ }
+
+ if (ok)
+ wpa_printf(MSG_DEBUG, "SSL: use private key file OK");
+ }
+
+ wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+ os_free(passwd);
+
+ if (!ok)
+ return -1;
+
+ return 0;
+}
+
+
+static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
+ const char *value, size_t len)
+{
+ WOLFSSL_ASN1_OBJECT *gen;
+ void *ext;
+ int found = 0;
+ int i;
+
+ ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+ for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
+ gen = wolfSSL_sk_value(ext, i);
+ if (gen->type != type)
+ continue;
+ if (os_strlen((char *) gen->obj) == len &&
+ os_memcmp(value, gen->obj, len) == 0)
+ found++;
+ }
+
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+ return found;
+}
+
+
+static int tls_match_alt_subject(WOLFSSL_X509 *cert, const char *match)
+{
+ int type;
+ const char *pos, *end;
+ size_t len;
+
+ pos = match;
+ do {
+ if (os_strncmp(pos, "EMAIL:", 6) == 0) {
+ type = GEN_EMAIL;
+ pos += 6;
+ } else if (os_strncmp(pos, "DNS:", 4) == 0) {
+ type = GEN_DNS;
+ pos += 4;
+ } else if (os_strncmp(pos, "URI:", 4) == 0) {
+ type = GEN_URI;
+ pos += 4;
+ } else {
+ wpa_printf(MSG_INFO,
+ "TLS: Invalid altSubjectName match '%s'",
+ pos);
+ return 0;
+ }
+ end = os_strchr(pos, ';');
+ while (end) {
+ if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
+ os_strncmp(end + 1, "DNS:", 4) == 0 ||
+ os_strncmp(end + 1, "URI:", 4) == 0)
+ break;
+ end = os_strchr(end + 1, ';');
+ }
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (tls_match_alt_subject_component(cert, type, pos, len) > 0)
+ return 1;
+ pos = end + 1;
+ } while (end);
+
+ return 0;
+}
+
+
+static int domain_suffix_match(const char *val, size_t len, const char *match,
+ size_t match_len, int full)
+{
+ size_t i;
+
+ /* Check for embedded nuls that could mess up suffix matching */
+ for (i = 0; i < len; i++) {
+ if (val[i] == '\0') {
+ wpa_printf(MSG_DEBUG,
+ "TLS: Embedded null in a string - reject");
+ return 0;
+ }
+ }
+
+ if (match_len > len || (full && match_len != len))
+ return 0;
+
+ if (os_strncasecmp(val + len - match_len, match, match_len) != 0)
+ return 0; /* no match */
+
+ if (match_len == len)
+ return 1; /* exact match */
+
+ if (val[len - match_len - 1] == '.')
+ return 1; /* full label match completes suffix match */
+
+ wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
+ return 0;
+}
+
+
+static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
+ size_t match_len, int full)
+{
+ WOLFSSL_ASN1_OBJECT *gen;
+ void *ext;
+ int i;
+ int j;
+ int dns_name = 0;
+ WOLFSSL_X509_NAME *name;
+
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+ full ? "" : "suffix ", match);
+
+ ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+ for (j = 0; ext && j < wolfSSL_sk_num(ext); j++) {
+ gen = wolfSSL_sk_value(ext, j);
+ if (gen->type != ASN_DNS_TYPE)
+ continue;
+ dns_name++;
+ wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
+ gen->obj, os_strlen((char *)gen->obj));
+ if (domain_suffix_match((const char *) gen->obj,
+ os_strlen((char *) gen->obj), match,
+ match_len, full) == 1) {
+ wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
+ full ? "Match" : "Suffix match");
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+ return 1;
+ }
+ }
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+ if (dns_name) {
+ wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
+ return 0;
+ }
+
+ name = wolfSSL_X509_get_subject_name(cert);
+ i = -1;
+ for (;;) {
+ WOLFSSL_X509_NAME_ENTRY *e;
+ WOLFSSL_ASN1_STRING *cn;
+
+ i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME,
+ i);
+ if (i == -1)
+ break;
+ e = wolfSSL_X509_NAME_get_entry(name, i);
+ if (!e)
+ continue;
+ cn = wolfSSL_X509_NAME_ENTRY_get_data(e);
+ if (!cn)
+ continue;
+ wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
+ cn->data, cn->length);
+ if (domain_suffix_match(cn->data, cn->length,
+ match, match_len, full) == 1) {
+ wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
+ full ? "Match" : "Suffix match");
+ return 1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
+ full ? "" : "suffix ");
+ return 0;
+}
+
+
+static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
+{
+ const char *token, *last = NULL;
+
+ /* Process each match alternative separately until a match is found */
+ while ((token = cstr_token(match, ";", &last))) {
+ if (tls_match_suffix_helper(cert, token, last - token, full))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static enum tls_fail_reason wolfssl_tls_fail_reason(int err)
+{
+ switch (err) {
+ case X509_V_ERR_CERT_REVOKED:
+ return TLS_FAIL_REVOKED;
+ case ASN_BEFORE_DATE_E:
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ return TLS_FAIL_NOT_YET_VALID;
+ case ASN_AFTER_DATE_E:
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ return TLS_FAIL_EXPIRED;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ case X509_V_ERR_INVALID_CA:
+ return TLS_FAIL_UNTRUSTED;
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ case X509_V_ERR_CERT_UNTRUSTED:
+ case X509_V_ERR_CERT_REJECTED:
+ return TLS_FAIL_BAD_CERTIFICATE;
+ default:
+ return TLS_FAIL_UNSPECIFIED;
+ }
+}
+
+
+static const char * wolfssl_tls_err_string(int err, const char *err_str)
+{
+ switch (err) {
+ case ASN_BEFORE_DATE_E:
+ return "certificate is not yet valid";
+ case ASN_AFTER_DATE_E:
+ return "certificate has expired";
+ default:
+ return err_str;
+ }
+}
+
+
+static struct wpabuf * get_x509_cert(WOLFSSL_X509 *cert)
+{
+ struct wpabuf *buf = NULL;
+ const u8 *data;
+ int cert_len;
+
+ data = wolfSSL_X509_get_der(cert, &cert_len);
+ if (!data)
+ buf = wpabuf_alloc_copy(data, cert_len);
+
+ return buf;
+}
+
+
+static void wolfssl_tls_fail_event(struct tls_connection *conn,
+ WOLFSSL_X509 *err_cert, int err, int depth,
+ const char *subject, const char *err_str,
+ enum tls_fail_reason reason)
+{
+ union tls_event_data ev;
+ struct wpabuf *cert = NULL;
+ struct tls_context *context = conn->context;
+
+ if (!context->event_cb)
+ return;
+
+ cert = get_x509_cert(err_cert);
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
+ reason : wolfssl_tls_fail_reason(err);
+ ev.cert_fail.depth = depth;
+ ev.cert_fail.subject = subject;
+ ev.cert_fail.reason_txt = wolfssl_tls_err_string(err, err_str);
+ ev.cert_fail.cert = cert;
+ context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+ wpabuf_free(cert);
+}
+
+
+static void wolfssl_tls_cert_event(struct tls_connection *conn,
+ WOLFSSL_X509 *err_cert, int depth,
+ const char *subject)
+{
+ struct wpabuf *cert = NULL;
+ union tls_event_data ev;
+ struct tls_context *context = conn->context;
+ char *alt_subject[TLS_MAX_ALT_SUBJECT];
+ int alt, num_alt_subject = 0;
+ WOLFSSL_ASN1_OBJECT *gen;
+ void *ext;
+ int i;
+#ifdef CONFIG_SHA256
+ u8 hash[32];
+#endif /* CONFIG_SHA256 */
+
+ if (!context->event_cb)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+ context->cert_in_cb) {
+ cert = get_x509_cert(err_cert);
+ ev.peer_cert.cert = cert;
+ }
+
+#ifdef CONFIG_SHA256
+ if (cert) {
+ const u8 *addr[1];
+ size_t len[1];
+
+ addr[0] = wpabuf_head(cert);
+ len[0] = wpabuf_len(cert);
+ 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;
+ ev.peer_cert.subject = subject;
+
+ ext = wolfSSL_X509_get_ext_d2i(err_cert, ALT_NAMES_OID, NULL, NULL);
+ for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
+ char *pos;
+
+ if (num_alt_subject == TLS_MAX_ALT_SUBJECT)
+ break;
+ gen = wolfSSL_sk_value((void *) ext, i);
+ if (gen->type != GEN_EMAIL &&
+ gen->type != GEN_DNS &&
+ gen->type != GEN_URI)
+ continue;
+
+ pos = os_malloc(10 + os_strlen((char *) gen->obj) + 1);
+ if (!pos)
+ break;
+ alt_subject[num_alt_subject++] = pos;
+
+ switch (gen->type) {
+ case GEN_EMAIL:
+ os_memcpy(pos, "EMAIL:", 6);
+ pos += 6;
+ break;
+ case GEN_DNS:
+ os_memcpy(pos, "DNS:", 4);
+ pos += 4;
+ break;
+ case GEN_URI:
+ os_memcpy(pos, "URI:", 4);
+ pos += 4;
+ break;
+ }
+
+ os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
+ pos += os_strlen((char *)gen->obj);
+ *pos = '\0';
+ }
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+ for (alt = 0; alt < num_alt_subject; alt++)
+ ev.peer_cert.altsubject[alt] = alt_subject[alt];
+ ev.peer_cert.num_altsubject = num_alt_subject;
+
+ context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+ wpabuf_free(cert);
+ for (alt = 0; alt < num_alt_subject; alt++)
+ os_free(alt_subject[alt]);
+}
+
+
+static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
+{
+ char buf[256];
+ WOLFSSL_X509 *err_cert;
+ int err, depth;
+ WOLFSSL *ssl;
+ struct tls_connection *conn;
+ struct tls_context *context;
+ char *match, *altmatch, *suffix_match, *domain_match;
+ const char *err_str;
+
+ err_cert = wolfSSL_X509_STORE_CTX_get_current_cert(x509_ctx);
+ if (!err_cert) {
+ wpa_printf(MSG_DEBUG, "wolfSSL: No Cert");
+ return 0;
+ }
+
+ err = wolfSSL_X509_STORE_CTX_get_error(x509_ctx);
+ depth = wolfSSL_X509_STORE_CTX_get_error_depth(x509_ctx);
+ ssl = wolfSSL_X509_STORE_CTX_get_ex_data(
+ x509_ctx, wolfSSL_get_ex_data_X509_STORE_CTX_idx());
+ wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(err_cert), buf,
+ sizeof(buf));
+
+ conn = wolfSSL_get_ex_data(ssl, 0);
+ if (!conn) {
+ wpa_printf(MSG_DEBUG, "wolfSSL: No ex_data");
+ return 0;
+ }
+
+ if (depth == 0)
+ conn->peer_cert = err_cert;
+ else if (depth == 1)
+ conn->peer_issuer = err_cert;
+ else if (depth == 2)
+ conn->peer_issuer_issuer = err_cert;
+
+ context = conn->context;
+ match = conn->subject_match;
+ altmatch = conn->alt_subject_match;
+ suffix_match = conn->suffix_match;
+ domain_match = conn->domain_match;
+
+ if (!preverify_ok && !conn->ca_cert_verify)
+ preverify_ok = 1;
+ if (!preverify_ok && depth > 0 && conn->server_cert_only)
+ preverify_ok = 1;
+ if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
+ (err == X509_V_ERR_CERT_HAS_EXPIRED ||
+ err == ASN_AFTER_DATE_E || err == ASN_BEFORE_DATE_E ||
+ err == X509_V_ERR_CERT_NOT_YET_VALID)) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Ignore certificate validity time mismatch");
+ preverify_ok = 1;
+ }
+
+ err_str = wolfSSL_X509_verify_cert_error_string(err);
+
+#ifdef CONFIG_SHA256
+ /*
+ * Do not require preverify_ok so we can explicity allow otherwise
+ * invalid pinned server certificates.
+ */
+ if (depth == 0 && conn->server_cert_only) {
+ struct wpabuf *cert;
+
+ cert = get_x509_cert(err_cert);
+ if (!cert) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Could not fetch server certificate data");
+ preverify_ok = 0;
+ } else {
+ u8 hash[32];
+ const u8 *addr[1];
+ size_t len[1];
+
+ addr[0] = wpabuf_head(cert);
+ len[0] = wpabuf_len(cert);
+ if (sha256_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
+ err_str = "Server certificate mismatch";
+ err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+ preverify_ok = 0;
+ } else if (!preverify_ok) {
+ /*
+ * Certificate matches pinned certificate, allow
+ * regardless of other problems.
+ */
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Ignore validation issues for a pinned server certificate");
+ preverify_ok = 1;
+ }
+ wpabuf_free(cert);
+ }
+ }
+#endif /* CONFIG_SHA256 */
+
+ if (!preverify_ok) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Certificate verification failed, error %d (%s) depth %d for '%s'",
+ err, err_str, depth, buf);
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ err_str, TLS_FAIL_UNSPECIFIED);
+ return preverify_ok;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TLS: %s - preverify_ok=%d err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
+ __func__, preverify_ok, err, err_str,
+ conn->ca_cert_verify, depth, buf);
+ if (depth == 0 && match && os_strstr(buf, match) == NULL) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Subject '%s' did not match with '%s'",
+ buf, match);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Subject mismatch",
+ TLS_FAIL_SUBJECT_MISMATCH);
+ } else if (depth == 0 && altmatch &&
+ !tls_match_alt_subject(err_cert, altmatch)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: altSubjectName match '%s' not found",
+ altmatch);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "AltSubject mismatch",
+ TLS_FAIL_ALTSUBJECT_MISMATCH);
+ } else if (depth == 0 && suffix_match &&
+ !tls_match_suffix(err_cert, suffix_match, 0)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Domain suffix match '%s' not found",
+ suffix_match);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain suffix mismatch",
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+ } else if (depth == 0 && domain_match &&
+ !tls_match_suffix(err_cert, domain_match, 1)) {
+ wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+ domain_match);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
+ } else {
+ wolfssl_tls_cert_event(conn, err_cert, depth, buf);
+ }
+
+ if (conn->cert_probe && preverify_ok && depth == 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Reject server certificate on probe-only run");
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Server certificate chain probe",
+ TLS_FAIL_SERVER_CHAIN_PROBE);
+ }
+
+#ifdef HAVE_OCSP_WOLFSSL
+ if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ preverify_ok) {
+ enum ocsp_result res;
+
+ res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+ conn->peer_issuer,
+ conn->peer_issuer_issuer);
+ if (res == OCSP_REVOKED) {
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "certificate revoked",
+ TLS_FAIL_REVOKED);
+ if (err == X509_V_OK)
+ X509_STORE_CTX_set_error(
+ x509_ctx, X509_V_ERR_CERT_REVOKED);
+ } else if (res != OCSP_GOOD &&
+ (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "bad certificate status response",
+ TLS_FAIL_UNSPECIFIED);
+ }
+ }
+#endif /* HAVE_OCSP_WOLFSSL */
+ if (depth == 0 && preverify_ok && context->event_cb != NULL)
+ context->event_cb(context->cb_ctx,
+ TLS_CERT_CHAIN_SUCCESS, NULL);
+
+ return preverify_ok;
+}
+
+
+static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
+ const char *ca_cert,
+ const u8 *ca_cert_blob, size_t blob_len,
+ const char *ca_path)
+{
+ WOLFSSL_CTX *ctx = tls_ctx;
+
+ wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ conn->ca_cert_verify = 1;
+
+ if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Probe for server certificate chain");
+ conn->cert_probe = 1;
+ conn->ca_cert_verify = 0;
+ return 0;
+ }
+
+ if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
+#ifdef CONFIG_SHA256
+ const char *pos = ca_cert + 7;
+
+ if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Unsupported ca_cert hash value '%s'",
+ ca_cert);
+ return -1;
+ }
+ pos += 14;
+ if (os_strlen(pos) != 32 * 2) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Unexpected SHA256 hash length in ca_cert '%s'",
+ ca_cert);
+ return -1;
+ }
+ if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Invalid SHA256 hash value in ca_cert '%s'",
+ ca_cert);
+ return -1;
+ }
+ conn->server_cert_only = 1;
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Checking only server certificate match");
+ return 0;
+#else /* CONFIG_SHA256 */
+ wpa_printf(MSG_INFO,
+ "No SHA256 included in the build - cannot validate server certificate hash");
+ return -1;
+#endif /* CONFIG_SHA256 */
+ }
+
+ if (ca_cert_blob) {
+ if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len,
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO, "SSL: failed to load CA blob");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK");
+ return 0;
+ }
+
+ if (ca_cert || ca_path) {
+ WOLFSSL_X509_STORE *cm = wolfSSL_X509_STORE_new();
+
+ if (!cm) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to create certificate store");
+ return -1;
+ }
+ wolfSSL_CTX_set_cert_store(ctx, cm);
+
+ if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to load ca_cert as PEM");
+
+ if (!ca_cert)
+ return -1;
+
+ if (wolfSSL_CTX_der_load_verify_locations(
+ ctx, ca_cert, SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to load ca_cert as DER");
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ conn->ca_cert_verify = 0;
+ return 0;
+}
+
+
+static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
+{
+#ifdef HAVE_SESSION_TICKET
+#if 0
+ if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
+ wolfSSL_UseSessionTicket(ssl);
+#endif
+#endif /* HAVE_SESSION_TICKET */
+
+ if (flags & TLS_CONN_DISABLE_TLSv1_0)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1);
+ if (flags & TLS_CONN_DISABLE_TLSv1_1)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+ if (flags & TLS_CONN_DISABLE_TLSv1_2)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+ const struct tls_connection_params *params)
+{
+ wpa_printf(MSG_DEBUG, "SSL: set params");
+
+ if (tls_connection_set_subject_match(conn, params->subject_match,
+ params->altsubject_match,
+ params->suffix_match,
+ params->domain_match) < 0) {
+ wpa_printf(MSG_INFO, "Error setting subject match");
+ return -1;
+ }
+
+ if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ params->ca_cert_blob,
+ params->ca_cert_blob_len,
+ params->ca_path) < 0) {
+ wpa_printf(MSG_INFO, "Error setting CA cert");
+ return -1;
+ }
+
+ if (tls_connection_client_cert(conn, params->client_cert,
+ params->client_cert_blob,
+ params->client_cert_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "Error setting client cert");
+ return -1;
+ }
+
+ if (tls_connection_private_key(tls_ctx, conn, params->private_key,
+ params->private_key_passwd,
+ params->private_key_blob,
+ params->private_key_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "Error setting private key");
+ return -1;
+ }
+
+ if (tls_connection_dh(conn, params->dh_file, params->dh_blob,
+ params->dh_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "Error setting DH");
+ return -1;
+ }
+
+ if (params->openssl_ciphers &&
+ wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
+ tls_set_conn_flags(conn->ssl, params->flags);
+
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ if (wolfSSL_UseOCSPStapling(conn->ssl, WOLFSSL_CSR_OCSP,
+ WOLFSSL_CSR_OCSP_USE_NONCE) !=
+ SSL_SUCCESS)
+ return -1;
+ wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ }
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ if (wolfSSL_UseOCSPStaplingV2(conn->ssl,
+ WOLFSSL_CSR2_OCSP_MULTI, 0) !=
+ SSL_SUCCESS)
+ return -1;
+ wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ }
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
+ !defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+#ifdef HAVE_OCSP
+ if (params->flags & TLS_CONN_REQUEST_OCSP)
+ wolfSSL_CTX_EnableOCSP(ctx, 0);
+#else /* HAVE_OCSP */
+ if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: No OCSP support included - reject configuration");
+ return -1;
+ }
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: No OCSP support included - allow optional OCSP case to continue");
+ }
+#endif /* HAVE_OCSP */
+#endif /* !HAVE_CERTIFICATE_STATUS_REQUEST &&
+ * !HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+
+ conn->flags = params->flags;
+
+ return 0;
+}
+
+
+static int tls_global_ca_cert(void *ssl_ctx, const char *ca_cert)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+
+ if (ca_cert) {
+ if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, NULL) != 1)
+ {
+ wpa_printf(MSG_WARNING,
+ "Failed to load root certificates");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TLS: Trusted root certificate(s) loaded");
+ }
+
+ return 0;
+}
+
+
+static int tls_global_client_cert(void *ssl_ctx, const char *client_cert)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+
+ if (!client_cert)
+ return 0;
+
+ if (wolfSSL_CTX_use_certificate_chain_file_format(ctx, client_cert,
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS &&
+ wolfSSL_CTX_use_certificate_chain_file(ctx, client_cert) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO, "Failed to load client certificate");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SSL: Loaded global client certificate: %s",
+ client_cert);
+
+ return 0;
+}
+
+
+static int tls_global_private_key(void *ssl_ctx, const char *private_key,
+ const char *private_key_passwd)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+ char *passwd = NULL;
+ int ret = 0;
+
+ if (!private_key)
+ return 0;
+
+ if (private_key_passwd) {
+ passwd = os_strdup(private_key_passwd);
+ if (!passwd)
+ return -1;
+ }
+
+ wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+ wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+ if (wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+ SSL_FILETYPE_ASN1) != 1 &&
+ wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+ SSL_FILETYPE_PEM) != 1) {
+ wpa_printf(MSG_INFO, "Failed to load private key");
+ ret = -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SSL: Loaded global private key");
+
+ os_free(passwd);
+ wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+
+ return ret;
+}
+
+
+static int tls_global_dh(void *ssl_ctx, const char *dh_file,
+ const u8 *dh_blob, size_t blob_len)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+
+ if (!dh_file && !dh_blob)
+ return 0;
+
+ if (dh_blob) {
+ if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: global use DH DER blob failed");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: global use DH blob OK");
+ return 0;
+ }
+
+ if (dh_file) {
+ if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) <
+ 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: global use DH PEM file failed");
+ if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: global use DH DER file failed");
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "SSL: global use DH file OK");
+ return 0;
+ }
+
+ return 0;
+}
+
+
+#ifdef HAVE_OCSP
+
+int ocsp_status_cb(void *unused, const char *url, int url_sz,
+ unsigned char *request, int request_sz,
+ unsigned char **response)
+{
+ size_t len;
+
+ (void) unused;
+
+ if (!url) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: OCSP status callback - no response configured");
+ *response = NULL;
+ return 0;
+ }
+
+ *response = (unsigned char *) os_readfile(url, &len);
+ if (!*response) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: OCSP status callback - could not read response file");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: OCSP status callback - send cached response");
+ return len;
+}
+
+
+void ocsp_resp_free_cb(void *ocsp_stapling_response, unsigned char *response)
+{
+ os_free(response);
+}
+
+#endif /* HAVE_OCSP */
+
+
+int tls_global_set_params(void *tls_ctx,
+ const struct tls_connection_params *params)
+{
+ wpa_printf(MSG_DEBUG, "SSL: global set params");
+
+ if (params->check_cert_subject)
+ return -1; /* not yet supported */
+
+ if (tls_global_ca_cert(tls_ctx, params->ca_cert) < 0) {
+ wpa_printf(MSG_INFO, "SSL: Failed to load ca cert file '%s'",
+ params->ca_cert);
+ return -1;
+ }
+
+ if (tls_global_client_cert(tls_ctx, params->client_cert) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: Failed to load client cert file '%s'",
+ params->client_cert);
+ return -1;
+ }
+
+ if (tls_global_private_key(tls_ctx, params->private_key,
+ params->private_key_passwd) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: Failed to load private key file '%s'",
+ params->private_key);
+ return -1;
+ }
+
+ if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob,
+ params->dh_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'",
+ params->dh_file);
+ return -1;
+ }
+
+ if (params->openssl_ciphers &&
+ wolfSSL_CTX_set_cipher_list(tls_ctx,
+ params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: openssl_ecdh_curves not supported");
+ return -1;
+ }
+
+#ifdef HAVE_SESSION_TICKET
+ /* Session ticket is off by default - can't disable once on. */
+ if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET))
+ wolfSSL_CTX_UseSessionTicket(tls_ctx);
+#endif /* HAVE_SESSION_TICKET */
+
+#ifdef HAVE_OCSP
+ if (params->ocsp_stapling_response) {
+ wolfSSL_CTX_SetOCSP_OverrideURL(tls_ctx,
+ params->ocsp_stapling_response);
+ wolfSSL_CTX_SetOCSP_Cb(tls_ctx, ocsp_status_cb,
+ ocsp_resp_free_cb, NULL);
+ }
+#endif /* HAVE_OCSP */
+
+ return 0;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
+{
+ wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl);
+
+ if (check_crl) {
+ /* Hack to Enable CRLs. */
+ wolfSSL_CTX_LoadCRLBuffer(tls_ctx, NULL, 0, SSL_FILETYPE_PEM);
+ }
+
+ return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
+{
+ if (!conn)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "SSL: set verify: %d", verify_peer);
+
+ if (verify_peer) {
+ conn->ca_cert_verify = 1;
+ wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ tls_verify_cb);
+ } else {
+ conn->ca_cert_verify = 0;
+ wolfSSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
+ }
+
+ wolfSSL_set_accept_state(conn->ssl);
+
+ /* TODO: do we need to fake a session like OpenSSL does here? */
+
+ return 0;
+}
+
+
+static struct wpabuf * wolfssl_handshake(struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ int server)
+{
+ int res;
+
+ wolfssl_reset_out_data(&conn->output);
+
+ /* Initiate TLS handshake or continue the existing handshake */
+ if (server) {
+ wolfSSL_set_accept_state(conn->ssl);
+ res = wolfSSL_accept(conn->ssl);
+ wpa_printf(MSG_DEBUG, "SSL: wolfSSL_accept: %d", res);
+ } else {
+ wolfSSL_set_connect_state(conn->ssl);
+ res = wolfSSL_connect(conn->ssl);
+ wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect: %d", res);
+ }
+
+ if (res != 1) {
+ int err = wolfSSL_get_error(conn->ssl, res);
+
+ if (err == SSL_ERROR_WANT_READ) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: wolfSSL_connect - want more data");
+ } else if (err == SSL_ERROR_WANT_WRITE) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: wolfSSL_connect - want to write");
+ } else {
+ char msg[80];
+
+ wpa_printf(MSG_DEBUG,
+ "SSL: wolfSSL_connect - failed %s",
+ wolfSSL_ERR_error_string(err, msg));
+ conn->failed++;
+ }
+ }
+
+ return conn->output.out_data;
+}
+
+
+static struct wpabuf * wolfssl_get_appl_data(struct tls_connection *conn,
+ size_t max_len)
+{
+ int res;
+ struct wpabuf *appl_data = wpabuf_alloc(max_len + 100);
+
+ if (!appl_data)
+ return NULL;
+
+ res = wolfSSL_read(conn->ssl, wpabuf_mhead(appl_data),
+ wpabuf_size(appl_data));
+ if (res < 0) {
+ int err = wolfSSL_get_error(conn->ssl, res);
+
+ if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: No Application Data included");
+ } else {
+ char msg[80];
+
+ wpa_printf(MSG_DEBUG,
+ "Failed to read possible Application Data %s",
+ wolfSSL_ERR_error_string(err, msg));
+ }
+
+ wpabuf_free(appl_data);
+ return NULL;
+ }
+
+ wpabuf_put(appl_data, res);
+ wpa_hexdump_buf_key(MSG_MSGDUMP,
+ "SSL: Application Data in Finished message",
+ appl_data);
+ return appl_data;
+}
+
+
+static struct wpabuf *
+wolfssl_connection_handshake(struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data, int server)
+{
+ struct wpabuf *out_data;
+
+ wolfssl_reset_in_data(&conn->input, in_data);
+
+ if (appl_data)
+ *appl_data = NULL;
+
+ out_data = wolfssl_handshake(conn, in_data, server);
+ if (!out_data)
+ return NULL;
+
+ if (wolfSSL_is_init_finished(conn->ssl)) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Handshake finished - resumed=%d",
+ tls_connection_resumed(NULL, conn));
+ if (appl_data && in_data)
+ *appl_data = wolfssl_get_appl_data(conn,
+ wpabuf_len(in_data));
+ }
+
+ return out_data;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data)
+{
+ return wolfssl_connection_handshake(conn, in_data, appl_data, 0);
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data)
+{
+ return wolfssl_connection_handshake(conn, in_data, appl_data, 1);
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data)
+{
+ int res;
+
+ if (!conn)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "SSL: encrypt: %ld bytes", wpabuf_len(in_data));
+
+ wolfssl_reset_out_data(&conn->output);
+
+ res = wolfSSL_write(conn->ssl, wpabuf_head(in_data),
+ wpabuf_len(in_data));
+ if (res < 0) {
+ int err = wolfSSL_get_error(conn->ssl, res);
+ char msg[80];
+
+ wpa_printf(MSG_INFO, "Encryption failed - SSL_write: %s",
+ wolfSSL_ERR_error_string(err, msg));
+ return NULL;
+ }
+
+ return conn->output.out_data;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data)
+{
+ int res;
+ struct wpabuf *buf;
+
+ if (!conn)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "SSL: decrypt");
+
+ wolfssl_reset_in_data(&conn->input, in_data);
+
+ /* Read decrypted data for further processing */
+ /*
+ * Even though we try to disable TLS compression, it is possible that
+ * this cannot be done with all TLS libraries. Add extra buffer space
+ * to handle the possibility of the decrypted data being longer than
+ * input data.
+ */
+ buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+ if (!buf)
+ return NULL;
+ res = wolfSSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "Decryption failed - SSL_read");
+ wpabuf_free(buf);
+ return NULL;
+ }
+ wpabuf_put(buf, res);
+
+ wpa_printf(MSG_DEBUG, "SSL: decrypt: %ld bytes", wpabuf_len(buf));
+
+ return buf;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+ return conn ? wolfSSL_session_reused(conn->ssl) : 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+ u8 *ciphers)
+{
+ char buf[128], *pos, *end;
+ u8 *c;
+ int ret;
+
+ if (!conn || !conn->ssl || !ciphers)
+ return -1;
+
+ buf[0] = '\0';
+ pos = buf;
+ end = pos + sizeof(buf);
+
+ c = ciphers;
+ while (*c != TLS_CIPHER_NONE) {
+ const char *suite;
+
+ switch (*c) {
+ case TLS_CIPHER_RC4_SHA:
+ suite = "RC4-SHA";
+ break;
+ case TLS_CIPHER_AES128_SHA:
+ suite = "AES128-SHA";
+ break;
+ case TLS_CIPHER_RSA_DHE_AES128_SHA:
+ suite = "DHE-RSA-AES128-SHA";
+ break;
+ case TLS_CIPHER_ANON_DH_AES128_SHA:
+ suite = "ADH-AES128-SHA";
+ break;
+ case TLS_CIPHER_RSA_DHE_AES256_SHA:
+ suite = "DHE-RSA-AES256-SHA";
+ break;
+ case TLS_CIPHER_AES256_SHA:
+ suite = "AES256-SHA";
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "TLS: Unsupported cipher selection: %d", *c);
+ return -1;
+ }
+ ret = os_snprintf(pos, end - pos, ":%s", suite);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+
+ c++;
+ }
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", buf + 1);
+
+ if (wolfSSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
+ wpa_printf(MSG_DEBUG, "Cipher suite configuration failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ WOLFSSL_CIPHER *cipher;
+ const char *name;
+
+ if (!conn || !conn->ssl)
+ return -1;
+
+ cipher = wolfSSL_get_current_cipher(conn->ssl);
+ if (!cipher)
+ return -1;
+
+ name = wolfSSL_CIPHER_get_name(cipher);
+ if (!name)
+ return -1;
+
+ if (os_strcmp(name, "SSL_RSA_WITH_RC4_128_SHA") == 0)
+ os_strlcpy(buf, "RC4-SHA", buflen);
+ else if (os_strcmp(name, "TLS_RSA_WITH_AES_128_CBC_SHA") == 0)
+ os_strlcpy(buf, "AES128-SHA", buflen);
+ else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA") == 0)
+ os_strlcpy(buf, "DHE-RSA-AES128-SHA", buflen);
+ else if (os_strcmp(name, "TLS_DH_anon_WITH_AES_128_CBC_SHA") == 0)
+ os_strlcpy(buf, "ADH-AES128-SHA", buflen);
+ else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA") == 0)
+ os_strlcpy(buf, "DHE-RSA-AES256-SHA", buflen);
+ else if (os_strcmp(name, "TLS_RSA_WITH_AES_256_CBC_SHA") == 0)
+ os_strlcpy(buf, "AES256-SHA", buflen);
+ else
+ os_strlcpy(buf, name, buflen);
+
+ return 0;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* no empty fragments in wolfSSL for now */
+ return 0;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+ if (!conn)
+ return -1;
+
+ return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+ if (!conn)
+ return -1;
+
+ /* TODO: this is not incremented anywhere */
+ return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ if (!conn)
+ return -1;
+
+ /* TODO: this is not incremented anywhere */
+ return conn->write_alerts;
+}
+
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "wolfSSL build=%s run=%s",
+ WOLFSSL_VERSION, wolfSSL_lib_version());
+}
+
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ const char *name;
+
+ if (!conn || !conn->ssl)
+ return -1;
+
+ name = wolfSSL_get_version(conn->ssl);
+ if (!name)
+ return -1;
+
+ os_strlcpy(buf, name, buflen);
+ return 0;
+}
+
+
+int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_random *keys)
+{
+ WOLFSSL *ssl;
+
+ if (!conn || !keys)
+ return -1;
+ ssl = conn->ssl;
+ if (!ssl)
+ return -1;
+
+ os_memset(keys, 0, sizeof(*keys));
+ keys->client_random = conn->client_random;
+ keys->client_random_len = wolfSSL_get_client_random(
+ ssl, conn->client_random, sizeof(conn->client_random));
+ keys->server_random = conn->server_random;
+ keys->server_random_len = wolfSSL_get_server_random(
+ ssl, conn->server_random, sizeof(conn->server_random));
+
+ return 0;
+}
+
+
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
+{
+ if (context)
+ return -1;
+ if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+ return -1;
+ return 0;
+}
+
+
+#define SEED_LEN (RAN_LEN + RAN_LEN)
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+ byte seed[SEED_LEN];
+ int ret = -1;
+ WOLFSSL *ssl;
+ byte *tmp_out;
+ byte *_out;
+ int skip = 0;
+ byte *master_key;
+ unsigned int master_key_len;
+ byte *server_random;
+ unsigned int server_len;
+ byte *client_random;
+ unsigned int client_len;
+
+ if (!conn || !conn->ssl)
+ return -1;
+ ssl = conn->ssl;
+
+ skip = 2 * (wolfSSL_GetKeySize(ssl) + wolfSSL_GetHmacSize(ssl) +
+ wolfSSL_GetIVSize(ssl));
+
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
+
+ wolfSSL_get_keys(ssl, &master_key, &master_key_len, &server_random,
+ &server_len, &client_random, &client_len);
+ os_memcpy(seed, server_random, RAN_LEN);
+ os_memcpy(seed + RAN_LEN, client_random, RAN_LEN);
+
+ if (wolfSSL_GetVersion(ssl) == WOLFSSL_TLSV1_2) {
+ tls_prf_sha256(master_key, master_key_len,
+ "key expansion", seed, sizeof(seed),
+ _out, skip + out_len);
+ ret = 0;
+ } else {
+ ret = tls_prf_sha1_md5(master_key, master_key_len,
+ "key expansion", seed, sizeof(seed),
+ _out, skip + out_len);
+ }
+
+ os_memset(master_key, 0, master_key_len);
+ if (ret == 0)
+ os_memcpy(out, _out + skip, out_len);
+ bin_clear_free(tmp_out, skip + out_len);
+
+ return ret;
+}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+ int ext_type, const u8 *data,
+ size_t data_len)
+{
+ (void) ssl_ctx;
+
+ if (!conn || !conn->ssl || ext_type != 35)
+ return -1;
+
+ if (wolfSSL_set_SessionTicket(conn->ssl, data,
+ (unsigned int) data_len) != 1)
+ return -1;
+
+ return 0;
+}
+
+
+static int tls_sess_sec_cb(WOLFSSL *s, void *secret, int *secret_len, void *arg)
+{
+ struct tls_connection *conn = arg;
+ int ret;
+ unsigned char client_random[RAN_LEN];
+ unsigned char server_random[RAN_LEN];
+ word32 ticket_len = sizeof(conn->session_ticket);
+
+ if (!conn || !conn->session_ticket_cb)
+ return 1;
+
+ if (wolfSSL_get_client_random(s, client_random,
+ sizeof(client_random)) == 0 ||
+ wolfSSL_get_server_random(s, server_random,
+ sizeof(server_random)) == 0 ||
+ wolfSSL_get_SessionTicket(s, conn->session_ticket,
+ &ticket_len) != 1)
+ return 1;
+
+ if (ticket_len == 0)
+ return 0;
+
+ ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+ conn->session_ticket, ticket_len,
+ client_random, server_random, secret);
+ if (ret <= 0)
+ return 1;
+
+ *secret_len = SECRET_LEN;
+ return 0;
+}
+
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+ struct tls_connection *conn,
+ tls_session_ticket_cb cb,
+ void *ctx)
+{
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+ conn->session_ticket_cb = cb;
+ conn->session_ticket_cb_ctx = ctx;
+
+ if (cb) {
+ if (wolfSSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+ conn) != 1)
+ return -1;
+ } else {
+ if (wolfSSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+ return -1;
+ }
+
+ return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+ return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Success data accepted for resumed session");
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+ WOLFSSL_SESSION *sess;
+
+ sess = wolfSSL_get_session(conn->ssl);
+ if (!sess)
+ return;
+
+ wolfSSL_SSL_SESSION_set_timeout(sess, 0);
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Removed cached session to disable session resumption");
+}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
+{
+ WOLFSSL_SESSION *sess;
+ struct wpabuf *old;
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: Set success data");
+
+ sess = wolfSSL_get_session(conn->ssl);
+ if (!sess) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: No session found for success data");
+ goto fail;
+ }
+
+ old = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (old) {
+ wpa_printf(MSG_DEBUG, "wolfSSL: Replacing old success data %p",
+ old);
+ wpabuf_free(old);
+ }
+ if (wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: Stored success data %p", data);
+ conn->success_data = 1;
+ return;
+
+fail:
+ wpa_printf(MSG_INFO, "wolfSSL: Failed to store success data");
+ wpabuf_free(data);
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ WOLFSSL_SESSION *sess;
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: Get success data");
+
+ sess = wolfSSL_get_session(conn->ssl);
+ if (!sess)
+ return NULL;
+ return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+}
OpenPOWER on IntegriCloud