aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/crypto.h30
-rw-r--r--src/crypto/crypto_cryptoapi.c783
-rw-r--r--src/crypto/crypto_module_tests.c59
-rw-r--r--src/crypto/crypto_openssl.c169
-rw-r--r--src/crypto/dh_groups.c2
-rw-r--r--src/crypto/fips_prf_openssl.c16
-rw-r--r--src/crypto/ms_funcs.c29
-rw-r--r--src/crypto/ms_funcs.h2
-rw-r--r--src/crypto/random.c1
-rw-r--r--src/crypto/sha1-tlsprf.c5
-rw-r--r--src/crypto/sha1-tprf.c2
-rw-r--r--src/crypto/sha256-kdf.c3
-rw-r--r--src/crypto/sha384-prf.c100
-rw-r--r--src/crypto/sha384.h5
-rw-r--r--src/crypto/tls.h94
-rw-r--r--src/crypto/tls_gnutls.c52
-rw-r--r--src/crypto/tls_internal.c118
-rw-r--r--src/crypto/tls_none.c40
-rw-r--r--src/crypto/tls_openssl.c835
-rw-r--r--src/crypto/tls_schannel.c763
20 files changed, 1244 insertions, 1864 deletions
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index f2d5662ff01e2..534c4bd786543 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -614,6 +614,15 @@ int crypto_bignum_is_zero(const struct crypto_bignum *a);
int crypto_bignum_is_one(const struct crypto_bignum *a);
/**
+ * crypto_bignum_legendre - Compute the Legendre symbol (a/p)
+ * @a: Bignum
+ * @p: Bignum
+ * Returns: Legendre symbol -1,0,1 on success; -2 on calculation failure
+ */
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+ const struct crypto_bignum *p);
+
+/**
* struct crypto_ec - Elliptic curve context
*
* Internal data structure for EC implementation. The contents is specific
@@ -758,6 +767,16 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
const struct crypto_bignum *x, int y_bit);
/**
+ * crypto_ec_point_compute_y_sqr - Compute y^2 = x^3 + ax + b
+ * @e: EC context from crypto_ec_init()
+ * @x: x coordinate
+ * Returns: y^2 on success, %NULL failure
+ */
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+ const struct crypto_bignum *x);
+
+/**
* crypto_ec_point_is_at_infinity - Check whether EC point is neutral element
* @e: EC context from crypto_ec_init()
* @p: EC point
@@ -776,4 +795,15 @@ int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
const struct crypto_ec_point *p);
+/**
+ * crypto_ec_point_cmp - Compare two EC points
+ * @e: EC context from crypto_ec_init()
+ * @a: EC point
+ * @b: EC point
+ * Returns: 0 on equal, non-zero otherwise
+ */
+int crypto_ec_point_cmp(const struct crypto_ec *e,
+ const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b);
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_cryptoapi.c b/src/crypto/crypto_cryptoapi.c
deleted file mode 100644
index 55a069b0d036e..0000000000000
--- a/src/crypto/crypto_cryptoapi.c
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * Crypto wrapper for Microsoft CryptoAPI
- * Copyright (c) 2005-2009, 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 <windows.h>
-#include <wincrypt.h>
-
-#include "common.h"
-#include "crypto.h"
-
-#ifndef MS_ENH_RSA_AES_PROV
-#ifdef UNICODE
-#define MS_ENH_RSA_AES_PROV \
-L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#else
-#define MS_ENH_RSA_AES_PROV \
-"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#endif
-#endif /* MS_ENH_RSA_AES_PROV */
-
-#ifndef CALG_HMAC
-#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
-#endif
-
-#ifdef __MINGW32_VERSION
-/*
- * MinGW does not yet include all the needed definitions for CryptoAPI, so
- * define here whatever extra is needed.
- */
-
-static BOOL WINAPI
-(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
- PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
-= NULL; /* to be loaded from crypt32.dll */
-
-
-static int mingw_load_crypto_func(void)
-{
- HINSTANCE dll;
-
- /* MinGW does not yet have full CryptoAPI support, so load the needed
- * function here. */
-
- if (CryptImportPublicKeyInfo)
- return 0;
-
- dll = LoadLibrary("crypt32");
- if (dll == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
- "library");
- return -1;
- }
-
- CryptImportPublicKeyInfo = GetProcAddress(
- dll, "CryptImportPublicKeyInfo");
- if (CryptImportPublicKeyInfo == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
- "CryptImportPublicKeyInfo() address from "
- "crypt32 library");
- return -1;
- }
-
- return 0;
-}
-
-#else /* __MINGW32_VERSION */
-
-static int mingw_load_crypto_func(void)
-{
- return 0;
-}
-
-#endif /* __MINGW32_VERSION */
-
-
-static void cryptoapi_report_error(const char *msg)
-{
- char *s, *pos;
- DWORD err = GetLastError();
-
- if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
- }
-
- pos = s;
- while (*pos) {
- if (*pos == '\n' || *pos == '\r') {
- *pos = '\0';
- break;
- }
- pos++;
- }
-
- wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
- LocalFree(s);
-}
-
-
-int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
-{
- HCRYPTPROV prov;
- HCRYPTHASH hash;
- size_t i;
- DWORD hlen;
- int ret = 0;
-
- if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
- cryptoapi_report_error("CryptAcquireContext");
- return -1;
- }
-
- if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
- cryptoapi_report_error("CryptCreateHash");
- CryptReleaseContext(prov, 0);
- return -1;
- }
-
- for (i = 0; i < num_elem; i++) {
- if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
- cryptoapi_report_error("CryptHashData");
- CryptDestroyHash(hash);
- CryptReleaseContext(prov, 0);
- }
- }
-
- hlen = hash_len;
- if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
- cryptoapi_report_error("CryptGetHashParam");
- ret = -1;
- }
-
- CryptDestroyHash(hash);
- CryptReleaseContext(prov, 0);
-
- return ret;
-}
-
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
- u8 next, tmp;
- int i;
- HCRYPTPROV prov;
- HCRYPTKEY ckey;
- DWORD dlen;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[8];
- } key_blob;
- DWORD mode = CRYPT_MODE_ECB;
-
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- key_blob.hdr.aiKeyAlg = CALG_DES;
- key_blob.len = 8;
-
- /* Add parity bits to the key */
- next = 0;
- for (i = 0; i < 7; i++) {
- tmp = key[i];
- key_blob.key[i] = (tmp >> i) | next | 1;
- next = tmp << (7 - i);
- }
- key_blob.key[i] = next | 1;
-
- if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
- "%d", (int) GetLastError());
- return;
- }
-
- if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
- &ckey)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
- (int) GetLastError());
- CryptReleaseContext(prov, 0);
- return;
- }
-
- if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
- "failed: %d", (int) GetLastError());
- CryptDestroyKey(ckey);
- CryptReleaseContext(prov, 0);
- return;
- }
-
- os_memcpy(cypher, clear, 8);
- dlen = 8;
- if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
- (int) GetLastError());
- os_memset(cypher, 0, 8);
- }
-
- CryptDestroyKey(ckey);
- CryptReleaseContext(prov, 0);
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
-}
-
-
-struct aes_context {
- HCRYPTPROV prov;
- HCRYPTKEY ckey;
-};
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
- struct aes_context *akey;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[16];
- } key_blob;
- DWORD mode = CRYPT_MODE_ECB;
-
- if (len != 16)
- return NULL;
-
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- key_blob.hdr.aiKeyAlg = CALG_AES_128;
- key_blob.len = len;
- os_memcpy(key_blob.key, key, len);
-
- akey = os_zalloc(sizeof(*akey));
- if (akey == NULL)
- return NULL;
-
- if (!CryptAcquireContext(&akey->prov, NULL,
- MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
- CRYPT_VERIFYCONTEXT)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
- "%d", (int) GetLastError());
- os_free(akey);
- return NULL;
- }
-
- if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
- 0, 0, &akey->ckey)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
- (int) GetLastError());
- CryptReleaseContext(akey->prov, 0);
- os_free(akey);
- return NULL;
- }
-
- if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
- "failed: %d", (int) GetLastError());
- CryptDestroyKey(akey->ckey);
- CryptReleaseContext(akey->prov, 0);
- os_free(akey);
- return NULL;
- }
-
- return akey;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
- struct aes_context *akey = ctx;
- DWORD dlen;
-
- os_memcpy(crypt, plain, 16);
- dlen = 16;
- if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
- (int) GetLastError());
- os_memset(crypt, 0, 16);
- }
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
- struct aes_context *akey = ctx;
- if (akey) {
- CryptDestroyKey(akey->ckey);
- CryptReleaseContext(akey->prov, 0);
- os_free(akey);
- }
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
- return aes_encrypt_init(key, len);
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
- struct aes_context *akey = ctx;
- DWORD dlen;
-
- os_memcpy(plain, crypt, 16);
- dlen = 16;
-
- if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
- (int) GetLastError());
- }
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
- aes_encrypt_deinit(ctx);
-}
-
-
-struct crypto_hash {
- enum crypto_hash_alg alg;
- int error;
- HCRYPTPROV prov;
- HCRYPTHASH hash;
- HCRYPTKEY key;
-};
-
-struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
- size_t key_len)
-{
- struct crypto_hash *ctx;
- ALG_ID calg;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[32];
- } key_blob;
-
- os_memset(&key_blob, 0, sizeof(key_blob));
- switch (alg) {
- case CRYPTO_HASH_ALG_MD5:
- calg = CALG_MD5;
- break;
- case CRYPTO_HASH_ALG_SHA1:
- calg = CALG_SHA;
- break;
- case CRYPTO_HASH_ALG_HMAC_MD5:
- case CRYPTO_HASH_ALG_HMAC_SHA1:
- calg = CALG_HMAC;
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- /*
- * Note: RC2 is not really used, but that can be used to
- * import HMAC keys of up to 16 byte long.
- * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
- * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
- */
- key_blob.hdr.aiKeyAlg = CALG_RC2;
- key_blob.len = key_len;
- if (key_len > sizeof(key_blob.key))
- return NULL;
- os_memcpy(key_blob.key, key, key_len);
- break;
- default:
- return NULL;
- }
-
- ctx = os_zalloc(sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- ctx->alg = alg;
-
- if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
- cryptoapi_report_error("CryptAcquireContext");
- os_free(ctx);
- return NULL;
- }
-
- if (calg == CALG_HMAC) {
-#ifndef CRYPT_IPSEC_HMAC_KEY
-#define CRYPT_IPSEC_HMAC_KEY 0x00000100
-#endif
- if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
- sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
- &ctx->key)) {
- cryptoapi_report_error("CryptImportKey");
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
- return NULL;
- }
- }
-
- if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
- cryptoapi_report_error("CryptCreateHash");
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
- return NULL;
- }
-
- if (calg == CALG_HMAC) {
- HMAC_INFO info;
- os_memset(&info, 0, sizeof(info));
- switch (alg) {
- case CRYPTO_HASH_ALG_HMAC_MD5:
- info.HashAlgid = CALG_MD5;
- break;
- case CRYPTO_HASH_ALG_HMAC_SHA1:
- info.HashAlgid = CALG_SHA;
- break;
- default:
- /* unreachable */
- break;
- }
-
- if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
- 0)) {
- cryptoapi_report_error("CryptSetHashParam");
- CryptDestroyHash(ctx->hash);
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
- return NULL;
- }
- }
-
- return ctx;
-}
-
-
-void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
-{
- if (ctx == NULL || ctx->error)
- return;
-
- if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
- cryptoapi_report_error("CryptHashData");
- ctx->error = 1;
- }
-}
-
-
-int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
-{
- int ret = 0;
- DWORD hlen;
-
- if (ctx == NULL)
- return -2;
-
- if (mac == NULL || len == NULL)
- goto done;
-
- if (ctx->error) {
- ret = -2;
- goto done;
- }
-
- hlen = *len;
- if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
- cryptoapi_report_error("CryptGetHashParam");
- ret = -2;
- }
- *len = hlen;
-
-done:
- if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
- ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
- CryptDestroyKey(ctx->key);
-
- os_free(ctx);
-
- return ret;
-}
-
-
-struct crypto_cipher {
- HCRYPTPROV prov;
- HCRYPTKEY key;
-};
-
-
-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;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[32];
- } key_blob;
- DWORD mode = CRYPT_MODE_CBC;
-
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- key_blob.len = key_len;
- if (key_len > sizeof(key_blob.key))
- return NULL;
- os_memcpy(key_blob.key, key, key_len);
-
- switch (alg) {
- case CRYPTO_CIPHER_ALG_AES:
- if (key_len == 32)
- key_blob.hdr.aiKeyAlg = CALG_AES_256;
- else if (key_len == 24)
- key_blob.hdr.aiKeyAlg = CALG_AES_192;
- else
- key_blob.hdr.aiKeyAlg = CALG_AES_128;
- break;
- case CRYPTO_CIPHER_ALG_3DES:
- key_blob.hdr.aiKeyAlg = CALG_3DES;
- break;
- case CRYPTO_CIPHER_ALG_DES:
- key_blob.hdr.aiKeyAlg = CALG_DES;
- break;
- case CRYPTO_CIPHER_ALG_RC2:
- key_blob.hdr.aiKeyAlg = CALG_RC2;
- break;
- case CRYPTO_CIPHER_ALG_RC4:
- key_blob.hdr.aiKeyAlg = CALG_RC4;
- break;
- default:
- return NULL;
- }
-
- ctx = os_zalloc(sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
- PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
- cryptoapi_report_error("CryptAcquireContext");
- goto fail1;
- }
-
- if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
- sizeof(key_blob), 0, 0, &ctx->key)) {
- cryptoapi_report_error("CryptImportKey");
- goto fail2;
- }
-
- if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
- cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
- goto fail3;
- }
-
- if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
- cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
- goto fail3;
- }
-
- return ctx;
-
-fail3:
- CryptDestroyKey(ctx->key);
-fail2:
- CryptReleaseContext(ctx->prov, 0);
-fail1:
- os_free(ctx);
- return NULL;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
- u8 *crypt, size_t len)
-{
- DWORD dlen;
-
- os_memcpy(crypt, plain, len);
- dlen = len;
- if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
- cryptoapi_report_error("CryptEncrypt");
- os_memset(crypt, 0, len);
- return -1;
- }
-
- return 0;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
- u8 *plain, size_t len)
-{
- DWORD dlen;
-
- os_memcpy(plain, crypt, len);
- dlen = len;
- if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
- cryptoapi_report_error("CryptDecrypt");
- return -1;
- }
-
- return 0;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
- CryptDestroyKey(ctx->key);
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
-}
-
-
-struct crypto_public_key {
- HCRYPTPROV prov;
- HCRYPTKEY rsa;
-};
-
-struct crypto_private_key {
- HCRYPTPROV prov;
- HCRYPTKEY rsa;
-};
-
-
-struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
-{
- /* Use crypto_public_key_from_cert() instead. */
- return NULL;
-}
-
-
-struct crypto_private_key * crypto_private_key_import(const u8 *key,
- size_t len,
- const char *passwd)
-{
- /* TODO */
- return NULL;
-}
-
-
-struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
- size_t len)
-{
- struct crypto_public_key *pk;
- PCCERT_CONTEXT cc;
-
- pk = os_zalloc(sizeof(*pk));
- if (pk == NULL)
- return NULL;
-
- cc = CertCreateCertificateContext(X509_ASN_ENCODING |
- PKCS_7_ASN_ENCODING, buf, len);
- if (!cc) {
- cryptoapi_report_error("CryptCreateCertificateContext");
- os_free(pk);
- return NULL;
- }
-
- if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
- 0)) {
- cryptoapi_report_error("CryptAcquireContext");
- os_free(pk);
- CertFreeCertificateContext(cc);
- return NULL;
- }
-
- if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
- PKCS_7_ASN_ENCODING,
- &cc->pCertInfo->SubjectPublicKeyInfo,
- &pk->rsa)) {
- cryptoapi_report_error("CryptImportPublicKeyInfo");
- CryptReleaseContext(pk->prov, 0);
- os_free(pk);
- CertFreeCertificateContext(cc);
- return NULL;
- }
-
- CertFreeCertificateContext(cc);
-
- return pk;
-}
-
-
-int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
- const u8 *in, size_t inlen,
- u8 *out, size_t *outlen)
-{
- DWORD clen;
- u8 *tmp;
- size_t i;
-
- if (*outlen < inlen)
- return -1;
- tmp = malloc(*outlen);
- if (tmp == NULL)
- return -1;
-
- os_memcpy(tmp, in, inlen);
- clen = inlen;
- if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
- "public key: %d", (int) GetLastError());
- os_free(tmp);
- return -1;
- }
-
- *outlen = clen;
-
- /* Reverse the output */
- for (i = 0; i < *outlen; i++)
- out[i] = tmp[*outlen - 1 - i];
-
- os_free(tmp);
-
- return 0;
-}
-
-
-int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
- const u8 *in, size_t inlen,
- u8 *out, size_t *outlen)
-{
- /* TODO */
- return -1;
-}
-
-
-void crypto_public_key_free(struct crypto_public_key *key)
-{
- if (key) {
- CryptDestroyKey(key->rsa);
- CryptReleaseContext(key->prov, 0);
- os_free(key);
- }
-}
-
-
-void crypto_private_key_free(struct crypto_private_key *key)
-{
- if (key) {
- CryptDestroyKey(key->rsa);
- CryptReleaseContext(key->prov, 0);
- os_free(key);
- }
-}
-
-
-int crypto_global_init(void)
-{
- return mingw_load_crypto_func();
-}
-
-
-void crypto_global_deinit(void)
-{
-}
-
-
-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)
-{
- /* TODO */
- return -1;
-}
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
index 7137c27d0e8c5..581005df3e39e 100644
--- a/src/crypto/crypto_module_tests.c
+++ b/src/crypto/crypto_module_tests.c
@@ -161,7 +161,7 @@ struct omac1_test_vector {
u8 tag[16];
};
-static struct omac1_test_vector omac1_test_vectors[] =
+static const struct omac1_test_vector omac1_test_vectors[] =
{
{
{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
@@ -210,7 +210,8 @@ static struct omac1_test_vector omac1_test_vectors[] =
};
-static int test_omac1_vector(struct omac1_test_vector *tv, unsigned int i)
+static int test_omac1_vector(const struct omac1_test_vector *tv,
+ unsigned int i)
{
u8 key[] = {
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
@@ -515,6 +516,7 @@ static int test_key_wrap(void)
0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
};
+#ifndef CONFIG_BORINGSSL
/* RFC 3394 - Test vector 4.2 */
u8 kek42[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -530,6 +532,7 @@ static int test_key_wrap(void)
0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2,
0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D
};
+#endif /* CONFIG_BORINGSSL */
/* RFC 3394 - Test vector 4.3 */
u8 kek43[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -546,6 +549,7 @@ static int test_key_wrap(void)
0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A,
0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7,
};
+#ifndef CONFIG_BORINGSSL
/* RFC 3394 - Test vector 4.4 */
u8 kek44[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -563,6 +567,7 @@ static int test_key_wrap(void)
0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93,
0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2
};
+#endif /* CONFIG_BORINGSSL */
/* RFC 3394 - Test vector 4.5 */
u8 kek45[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -623,6 +628,7 @@ static int test_key_wrap(void)
ret++;
}
+#ifndef CONFIG_BORINGSSL
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.2");
if (aes_wrap(kek42, sizeof(kek42), sizeof(plain42) / 8, plain42,
result)) {
@@ -642,6 +648,7 @@ static int test_key_wrap(void)
wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
ret++;
}
+#endif /* CONFIG_BORINGSSL */
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.3");
if (aes_wrap(kek43, sizeof(kek43), sizeof(plain43) / 8, plain43,
@@ -663,6 +670,7 @@ static int test_key_wrap(void)
ret++;
}
+#ifndef CONFIG_BORINGSSL
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.4");
if (aes_wrap(kek44, sizeof(kek44), sizeof(plain44) / 8, plain44,
result)) {
@@ -682,6 +690,7 @@ static int test_key_wrap(void)
wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
ret++;
}
+#endif /* CONFIG_BORINGSSL */
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.5");
if (aes_wrap(kek45, sizeof(kek45), sizeof(plain45) / 8, plain45,
@@ -732,6 +741,7 @@ static int test_key_wrap(void)
static int test_md5(void)
{
+#ifndef CONFIG_FIPS
struct {
char *data;
char *hash;
@@ -810,6 +820,10 @@ static int test_md5(void)
wpa_printf(MSG_INFO, "MD5 test cases passed");
return errors;
+#else /* CONFIG_FIPS */
+ wpa_printf(MSG_INFO, "MD5 test cases skipped due to CONFIG_FIPS");
+ return 0;
+#endif /* CONFIG_FIPS */
}
@@ -841,6 +855,7 @@ static int test_eap_fast(void)
0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2
};
+#ifndef CONFIG_FIPS
const u8 key_block[] = {
0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
@@ -857,6 +872,7 @@ static int test_eap_fast(void)
0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
};
+#endif /* CONFIG_FIPS */
const u8 sks[] = {
0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
@@ -931,6 +947,7 @@ static int test_eap_fast(void)
errors++;
}
+#ifndef CONFIG_FIPS
wpa_printf(MSG_INFO, "- PRF (TLS, SHA1/MD5) test case / key_block");
if (tls_prf_sha1_md5(master_secret, sizeof(master_secret),
"key expansion", seed, sizeof(seed),
@@ -939,6 +956,7 @@ static int test_eap_fast(void)
wpa_printf(MSG_INFO, "PRF test - FAILED!");
errors++;
}
+#endif /* CONFIG_FIPS */
wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / IMCK");
if (sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
@@ -983,14 +1001,14 @@ static int test_eap_fast(void)
}
-static u8 key0[] =
+static const u8 key0[] =
{
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b
};
-static u8 data0[] = "Hi There";
-static u8 prf0[] =
+static const u8 data0[] = "Hi There";
+static const u8 prf0[] =
{
0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
@@ -1002,9 +1020,9 @@ static u8 prf0[] =
0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
};
-static u8 key1[] = "Jefe";
-static u8 data1[] = "what do ya want for nothing?";
-static u8 prf1[] =
+static const u8 key1[] = "Jefe";
+static const u8 data1[] = "what do ya want for nothing?";
+static const u8 prf1[] =
{
0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
@@ -1017,13 +1035,13 @@ static u8 prf1[] =
};
-static u8 key2[] =
+static const u8 key2[] =
{
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa
};
-static u8 data2[] =
+static const u8 data2[] =
{
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
@@ -1033,7 +1051,7 @@ static u8 data2[] =
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd
};
-static u8 prf2[] =
+static const u8 prf2[] =
{
0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
@@ -1052,7 +1070,7 @@ struct passphrase_test {
char psk[32];
};
-static struct passphrase_test passphrase_tests[] =
+static const struct passphrase_test passphrase_tests[] =
{
{
"password",
@@ -1097,7 +1115,7 @@ struct rfc6070_test {
size_t dk_len;
};
-static struct rfc6070_test rfc6070_tests[] =
+static const struct rfc6070_test rfc6070_tests[] =
{
{
"password",
@@ -1214,7 +1232,7 @@ static int test_sha1(void)
wpa_printf(MSG_INFO, "PBKDF2-SHA1 Passphrase test cases:");
for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
u8 psk[32];
- struct passphrase_test *test = &passphrase_tests[i];
+ const struct passphrase_test *test = &passphrase_tests[i];
if (pbkdf2_sha1(test->passphrase,
(const u8 *) test->ssid, strlen(test->ssid),
@@ -1230,7 +1248,7 @@ static int test_sha1(void)
wpa_printf(MSG_INFO, "PBKDF2-SHA1 test cases (RFC 6070):");
for (i = 0; i < NUM_RFC6070_TESTS; i++) {
u8 dk[25];
- struct rfc6070_test *test = &rfc6070_tests[i];
+ const struct rfc6070_test *test = &rfc6070_tests[i];
if (pbkdf2_sha1(test->p, (const u8 *) test->s, strlen(test->s),
test->c, dk, test->dk_len) == 0 &&
@@ -1248,7 +1266,7 @@ static int test_sha1(void)
}
-struct {
+const struct {
char *data;
u8 hash[32];
} tests[] = {
@@ -1272,7 +1290,7 @@ struct {
}
};
-struct hmac_test {
+const struct hmac_test {
u8 key[80];
size_t key_len;
u8 data[128];
@@ -1513,7 +1531,7 @@ static int test_sha256(void)
}
for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
- struct hmac_test *t = &hmac_tests[i];
+ const struct hmac_test *t = &hmac_tests[i];
wpa_printf(MSG_INFO, "HMAC-SHA256 test case %d:", i + 1);
@@ -1563,6 +1581,7 @@ static int test_sha256(void)
static int test_ms_funcs(void)
{
+#ifndef CONFIG_FIPS
/* Test vector from RFC2759 example */
char *username = "User";
char *password = "clientPass";
@@ -1655,6 +1674,10 @@ static int test_ms_funcs(void)
wpa_printf(MSG_INFO, "ms_funcs test cases passed");
return errors;
+#else /* CONFIG_FIPS */
+ wpa_printf(MSG_INFO, "ms_funcs test cases skipped due to CONFIG_FIPS");
+ return 0;
+#endif /* CONFIG_FIPS */
}
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index f158ef43a645c..6cff75c64ae5a 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -93,10 +93,12 @@ static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
}
+#ifndef CONFIG_FIPS
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
}
+#endif /* CONFIG_FIPS */
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
@@ -120,6 +122,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
}
+#ifndef CONFIG_NO_RC4
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len)
{
@@ -155,12 +158,15 @@ out:
return res;
#endif /* OPENSSL_NO_RC4 */
}
+#endif /* CONFIG_NO_RC4 */
+#ifndef CONFIG_FIPS
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
}
+#endif /* CONFIG_FIPS */
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
@@ -297,6 +303,9 @@ void aes_decrypt_deinit(void *ctx)
}
+#ifndef CONFIG_FIPS
+#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
+
int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
{
AES_KEY actx;
@@ -323,6 +332,59 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
return res <= 0 ? -1 : 0;
}
+#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
+#endif /* CONFIG_FIPS */
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ EVP_CIPHER_CTX ctx;
+ int clen, len;
+ u8 buf[16];
+
+ EVP_CIPHER_CTX_init(&ctx);
+ if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ 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)
+ return -1;
+
+ len = sizeof(buf);
+ if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+ return -1;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ return 0;
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ EVP_CIPHER_CTX ctx;
+ int plen, len;
+ u8 buf[16];
+
+ EVP_CIPHER_CTX_init(&ctx);
+ if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ return -1;
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ plen = data_len;
+ if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 ||
+ plen != (int) data_len)
+ return -1;
+
+ len = sizeof(buf);
+ if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+ return -1;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ return 0;
+}
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
@@ -380,11 +442,13 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
return NULL;
switch (alg) {
+#ifndef CONFIG_NO_RC4
#ifndef OPENSSL_NO_RC4
case CRYPTO_CIPHER_ALG_RC4:
cipher = EVP_rc4();
break;
#endif /* OPENSSL_NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
#ifndef OPENSSL_NO_AES
case CRYPTO_CIPHER_ALG_AES:
switch (key_len) {
@@ -1057,6 +1121,42 @@ int crypto_bignum_is_one(const struct crypto_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;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -2;
+
+ exp = BN_new();
+ tmp = BN_new();
+ if (!exp || !tmp ||
+ /* 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))
+ goto fail;
+
+ if (BN_is_word(tmp, 1))
+ res = 1;
+ else if (BN_is_zero(tmp))
+ res = 0;
+ else
+ res = -1;
+
+fail:
+ BN_clear_free(tmp);
+ BN_clear_free(exp);
+ BN_CTX_free(bnctx);
+ return res;
+}
+
+
#ifdef CONFIG_ECC
struct crypto_ec {
@@ -1064,6 +1164,8 @@ struct crypto_ec {
BN_CTX *bnctx;
BIGNUM *prime;
BIGNUM *order;
+ BIGNUM *a;
+ BIGNUM *b;
};
struct crypto_ec * crypto_ec_init(int group)
@@ -1088,6 +1190,26 @@ struct crypto_ec * crypto_ec_init(int group)
case 26:
nid = NID_secp224r1;
break;
+#ifdef NID_brainpoolP224r1
+ case 27:
+ nid = NID_brainpoolP224r1;
+ break;
+#endif /* NID_brainpoolP224r1 */
+#ifdef NID_brainpoolP256r1
+ case 28:
+ nid = NID_brainpoolP256r1;
+ break;
+#endif /* NID_brainpoolP256r1 */
+#ifdef NID_brainpoolP384r1
+ case 29:
+ nid = NID_brainpoolP384r1;
+ break;
+#endif /* NID_brainpoolP384r1 */
+#ifdef NID_brainpoolP512r1
+ case 30:
+ nid = NID_brainpoolP512r1;
+ break;
+#endif /* NID_brainpoolP512r1 */
default:
return NULL;
}
@@ -1100,9 +1222,11 @@ struct crypto_ec * crypto_ec_init(int group)
e->group = EC_GROUP_new_by_curve_name(nid);
e->prime = BN_new();
e->order = BN_new();
+ e->a = BN_new();
+ e->b = BN_new();
if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
- e->order == NULL ||
- !EC_GROUP_get_curve_GFp(e->group, e->prime, NULL, NULL, e->bnctx) ||
+ e->order == NULL || e->a == NULL || e->b == NULL ||
+ !EC_GROUP_get_curve_GFp(e->group, e->prime, e->a, e->b, e->bnctx) ||
!EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
crypto_ec_deinit(e);
e = NULL;
@@ -1116,6 +1240,8 @@ void crypto_ec_deinit(struct crypto_ec *e)
{
if (e == NULL)
return;
+ BN_clear_free(e->b);
+ BN_clear_free(e->a);
BN_clear_free(e->order);
BN_clear_free(e->prime);
EC_GROUP_free(e->group);
@@ -1263,6 +1389,33 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
}
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+ const struct crypto_bignum *x)
+{
+ BIGNUM *tmp, *tmp2, *y_sqr = NULL;
+
+ tmp = BN_new();
+ tmp2 = BN_new();
+
+ /* y^2 = x^3 + ax + b */
+ if (tmp && tmp2 &&
+ BN_mod_sqr(tmp, (const BIGNUM *) x, e->prime, e->bnctx) &&
+ BN_mod_mul(tmp, tmp, (const BIGNUM *) x, e->prime, e->bnctx) &&
+ BN_mod_mul(tmp2, e->a, (const BIGNUM *) x, e->prime, e->bnctx) &&
+ BN_mod_add_quick(tmp2, tmp2, tmp, e->prime) &&
+ BN_mod_add_quick(tmp2, tmp2, e->b, e->prime)) {
+ y_sqr = tmp2;
+ tmp2 = NULL;
+ }
+
+ BN_clear_free(tmp);
+ BN_clear_free(tmp2);
+
+ return (struct crypto_bignum *) y_sqr;
+}
+
+
int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
const struct crypto_ec_point *p)
{
@@ -1273,7 +1426,17 @@ int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
const struct crypto_ec_point *p)
{
- return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p, e->bnctx);
+ return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p,
+ e->bnctx) == 1;
+}
+
+
+int crypto_ec_point_cmp(const struct crypto_ec *e,
+ const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b)
+{
+ return EC_POINT_cmp(e->group, (const EC_POINT *) a,
+ (const EC_POINT *) b, e->bnctx);
}
#endif /* CONFIG_ECC */
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index d3b263196e2d1..3aeb2bbc60af3 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1153,7 +1153,7 @@ dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
-static struct dh_group dh_groups[] = {
+static const struct dh_group dh_groups[] = {
DH_GROUP(5, 1),
#ifdef ALL_DH_GROUPS
DH_GROUP(1, 1),
diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c
index d69eceabff1c5..fb03efcd4ffc2 100644
--- a/src/crypto/fips_prf_openssl.c
+++ b/src/crypto/fips_prf_openssl.c
@@ -13,13 +13,21 @@
#include "crypto.h"
-static void sha1_transform(u8 *state, const u8 data[64])
+static void sha1_transform(u32 *state, const u8 data[64])
{
SHA_CTX context;
os_memset(&context, 0, sizeof(context));
- os_memcpy(&context.h0, state, 5 * 4);
+ context.h0 = state[0];
+ context.h1 = state[1];
+ context.h2 = state[2];
+ context.h3 = state[3];
+ context.h4 = state[4];
SHA1_Transform(&context, data);
- os_memcpy(state, &context.h0, 5 * 4);
+ state[0] = context.h0;
+ state[1] = context.h1;
+ state[2] = context.h2;
+ state[3] = context.h3;
+ state[4] = context.h4;
}
@@ -53,7 +61,7 @@ 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((u8 *) _t, xkey);
+ 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]);
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index 49a5c1c245d67..053d203cb65bb 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -78,9 +78,8 @@ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
* @challenge: 8-octet Challenge (OUT)
* Returns: 0 on success, -1 on failure
*/
-static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
- const u8 *username, size_t username_len,
- u8 *challenge)
+int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
+ const u8 *username, size_t username_len, u8 *challenge)
{
u8 hash[SHA1_MAC_LEN];
const unsigned char *addr[3];
@@ -175,9 +174,8 @@ int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
u8 password_hash[16];
if (challenge_hash(peer_challenge, auth_challenge, username,
- username_len, challenge))
- return -1;
- if (nt_password_hash(password, password_len, password_hash))
+ username_len, challenge) ||
+ nt_password_hash(password, password_len, password_hash))
return -1;
challenge_response(challenge, password_hash, response);
return 0;
@@ -257,12 +255,9 @@ int generate_authenticator_response_pwhash(
addr2[1] = challenge;
addr2[2] = magic2;
- if (hash_nt_password_hash(password_hash, password_hash_hash))
- return -1;
- if (sha1_vector(3, addr1, len1, response))
- return -1;
-
- if (challenge_hash(peer_challenge, auth_challenge, username,
+ if (hash_nt_password_hash(password_hash, password_hash_hash) ||
+ sha1_vector(3, addr1, len1, response) ||
+ challenge_hash(peer_challenge, auth_challenge, username,
username_len, challenge))
return -1;
return sha1_vector(3, addr2, len2, response);
@@ -417,6 +412,8 @@ int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
}
+#ifndef CONFIG_NO_RC4
+
#define PWBLOCK_LEN 516
/**
@@ -436,10 +433,8 @@ int encrypt_pw_block_with_password_hash(
os_memset(pw_block, 0, PWBLOCK_LEN);
- if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
- return -1;
-
- if (ucs2_len > 256)
+ if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
+ || ucs2_len > 256)
return -1;
offset = (256 - ucs2_len) * 2;
@@ -484,6 +479,8 @@ int new_password_encrypted_with_old_nt_password_hash(
return 0;
}
+#endif /* CONFIG_NO_RC4 */
+
/**
* nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
diff --git a/src/crypto/ms_funcs.h b/src/crypto/ms_funcs.h
index bd9bfee95b7c2..b5b5918e1a555 100644
--- a/src/crypto/ms_funcs.h
+++ b/src/crypto/ms_funcs.h
@@ -33,6 +33,8 @@ int nt_challenge_response(const u8 *challenge, const u8 *password,
void 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,
u8 *password_hash);
int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
diff --git a/src/crypto/random.c b/src/crypto/random.c
index bc758aa572327..3a86a93a46a8b 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -181,6 +181,7 @@ int random_get_bytes(void *buf, size_t len)
#ifdef CONFIG_FIPS
/* Mix in additional entropy from the crypto module */
+ bytes = buf;
left = len;
while (left) {
size_t siz, i;
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index 0effd9b76dd89..f9bc0ebf6e3d0 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -95,5 +95,10 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
SHA1_pos++;
}
+ os_memset(A_MD5, 0, MD5_MAC_LEN);
+ os_memset(P_MD5, 0, MD5_MAC_LEN);
+ os_memset(A_SHA1, 0, SHA1_MAC_LEN);
+ os_memset(P_SHA1, 0, SHA1_MAC_LEN);
+
return 0;
}
diff --git a/src/crypto/sha1-tprf.c b/src/crypto/sha1-tprf.c
index a52949462f77b..562510f8937d0 100644
--- a/src/crypto/sha1-tprf.c
+++ b/src/crypto/sha1-tprf.c
@@ -66,5 +66,7 @@ int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
len[0] = SHA1_MAC_LEN;
}
+ os_memset(hash, 0, SHA1_MAC_LEN);
+
return 0;
}
diff --git a/src/crypto/sha256-kdf.c b/src/crypto/sha256-kdf.c
index d8a1beb32e908..e7509ce41aba4 100644
--- a/src/crypto/sha256-kdf.c
+++ b/src/crypto/sha256-kdf.c
@@ -61,6 +61,7 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
if (iter == 255) {
os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA256_MAC_LEN);
return -1;
}
iter++;
@@ -68,9 +69,11 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
{
os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA256_MAC_LEN);
return -1;
}
}
+ os_memset(T, 0, SHA256_MAC_LEN);
return 0;
}
diff --git a/src/crypto/sha384-prf.c b/src/crypto/sha384-prf.c
new file mode 100644
index 0000000000000..653920ba283d2
--- /dev/null
+++ b/src/crypto/sha384-prf.c
@@ -0,0 +1,100 @@
+/*
+ * SHA384-based KDF (IEEE 802.11ac)
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384.h"
+#include "crypto.h"
+
+
+/**
+ * sha384_prf - SHA384-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
+ *
+ * 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)
+{
+ sha384_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+}
+
+
+/**
+ * sha384_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
+ *
+ * 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)
+{
+ u16 counter = 1;
+ size_t pos, plen;
+ u8 hash[SHA384_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 >= SHA384_MAC_LEN) {
+ hmac_sha384_vector(key, key_len, 4, addr, len,
+ &buf[pos]);
+ pos += SHA384_MAC_LEN;
+ } else {
+ hmac_sha384_vector(key, key_len, 4, addr, len, hash);
+ 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));
+}
diff --git a/src/crypto/sha384.h b/src/crypto/sha384.h
index e6a1fe41e1a10..3deafa59ec290 100644
--- a/src/crypto/sha384.h
+++ b/src/crypto/sha384.h
@@ -15,5 +15,10 @@ 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);
#endif /* SHA384_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 9ae95a66c9ed6..2e562339cc5c0 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -11,9 +11,7 @@
struct tls_connection;
-struct tls_keys {
- const u8 *master_key; /* TLS master secret */
- size_t master_key_len;
+struct tls_random {
const u8 *client_random;
size_t client_random_len;
const u8 *server_random;
@@ -81,6 +79,7 @@ struct tls_config {
int fips_mode;
int cert_in_cb;
const char *openssl_ciphers;
+ unsigned int tls_session_lifetime;
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
@@ -95,6 +94,7 @@ struct tls_config {
#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
#define TLS_CONN_EAP_FAST BIT(7)
+#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -255,6 +255,7 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
enum {
+ TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN = -4,
TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
};
@@ -265,10 +266,12 @@ enum {
* @conn: Connection context data from tls_connection_init()
* @params: Connection parameters
* Returns: 0 on success, -1 on failure,
- * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
- * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
+ * failure, or
* TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
- * PKCS#11 engine private key.
+ * PKCS#11 engine private key, or
+ * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
+ * failure.
*/
int __must_check
tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
@@ -279,10 +282,12 @@ tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
* @tls_ctx: TLS context data from tls_init()
* @params: Global TLS parameters
* Returns: 0 on success, -1 on failure,
- * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
- * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
+ * failure, or
* TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
- * PKCS#11 engine private key.
+ * PKCS#11 engine private key, or
+ * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
+ * failure.
*/
int __must_check tls_global_set_params(
void *tls_ctx, const struct tls_connection_params *params);
@@ -301,22 +306,28 @@ int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @verify_peer: 1 = verify peer certificate
+ * @flags: Connection flags (TLS_CONN_*)
+ * @session_ctx: Session caching context or %NULL to use default
+ * @session_ctx_len: Length of @session_ctx in bytes.
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_connection_set_verify(void *tls_ctx,
struct tls_connection *conn,
- int verify_peer);
+ int verify_peer,
+ unsigned int flags,
+ const u8 *session_ctx,
+ size_t session_ctx_len);
/**
- * tls_connection_get_keys - Get master key and random data from TLS connection
+ * tls_connection_get_random - Get random data from TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- * @keys: Structure of key/random data (filled on success)
+ * @data: Structure of client/server random data (filled on success)
* Returns: 0 on success, -1 on failure
*/
-int __must_check tls_connection_get_keys(void *tls_ctx,
+int __must_check tls_connection_get_random(void *tls_ctx,
struct tls_connection *conn,
- struct tls_keys *keys);
+ struct tls_random *data);
/**
* tls_connection_prf - Use TLS-PRF to derive keying material
@@ -325,23 +336,22 @@ int __must_check tls_connection_get_keys(void *tls_ctx,
* @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
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*
- * This function is optional to implement if tls_connection_get_keys() provides
- * access to master secret and server/client random values. If these values are
- * not exported from the TLS library, tls_connection_prf() is required so that
- * further keying material can be derived from the master secret. If not
- * implemented, the function will still need to be defined, but it can just
- * return -1. 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).
+ * 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.
*/
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);
/**
@@ -461,6 +471,19 @@ int __must_check tls_connection_set_cipher_list(void *tls_ctx,
u8 *ciphers);
/**
+ * tls_get_version - Get the current TLS version number
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @buf: Buffer for returning the TLS version number
+ * @buflen: buf size
+ * Returns: 0 on success, -1 on failure
+ *
+ * Get the currently used TLS version number.
+ */
+int __must_check tls_get_version(void *tls_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen);
+
+/**
* tls_get_cipher - Get current cipher name
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
@@ -527,23 +550,6 @@ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn);
-/**
- * tls_connection_get_keyblock_size - Get TLS key_block size
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: Size of the key_block for the negotiated cipher suite or -1 on
- * failure
- */
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn);
-
-/**
- * tls_capabilities - Get supported TLS capabilities
- * @tls_ctx: TLS context data from tls_init()
- * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
- */
-unsigned int tls_capabilities(void *tls_ctx);
-
typedef int (*tls_session_ticket_cb)
(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
const u8 *server_random, u8 *master_secret);
@@ -569,4 +575,14 @@ void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
int tls_get_library_version(char *buf, size_t buf_len);
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data);
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn);
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn);
+
+void tls_connection_remove_session(struct tls_connection *conn);
+
#endif /* TLS_H */
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index 65db6fcc25653..f994379b16b22 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -708,7 +708,8 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer)
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
{
if (conn == NULL || conn->session == NULL)
return -1;
@@ -722,8 +723,8 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
}
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
+int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_random *keys)
{
#if GNUTLS_VERSION_NUMBER >= 0x030012
gnutls_datum_t client, server;
@@ -747,9 +748,9 @@ int tls_connection_get_keys(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,
- u8 *out, size_t out_len)
+ int skip_keyblock, u8 *out, size_t out_len)
{
- if (conn == NULL || conn->session == NULL)
+ if (conn == NULL || conn->session == NULL || skip_keyblock)
return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
@@ -1426,6 +1427,14 @@ 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;
+}
+
+
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@@ -1476,30 +1485,39 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
}
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+ struct tls_connection *conn,
+ tls_session_ticket_cb cb, void *ctx)
{
- /* TODO */
return -1;
}
-unsigned int tls_capabilities(void *tls_ctx)
+int tls_get_library_version(char *buf, size_t buf_len)
{
- return 0;
+ return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
+ GNUTLS_VERSION, gnutls_check_version(NULL));
}
-int tls_connection_set_session_ticket_cb(void *tls_ctx,
- struct tls_connection *conn,
- tls_session_ticket_cb cb, void *ctx)
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
{
- return -1;
}
-int tls_get_library_version(char *buf, size_t buf_len)
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ return NULL;
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
{
- return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
- GNUTLS_VERSION, gnutls_check_version(NULL));
}
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 0c955da29f1d5..704751d308fcf 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -192,26 +192,31 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (params->subject_match) {
wpa_printf(MSG_INFO, "TLS: subject_match not supported");
+ tlsv1_cred_free(cred);
return -1;
}
if (params->altsubject_match) {
wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
+ tlsv1_cred_free(cred);
return -1;
}
if (params->suffix_match) {
wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
+ tlsv1_cred_free(cred);
return -1;
}
if (params->domain_match) {
wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+ tlsv1_cred_free(cred);
return -1;
}
if (params->openssl_ciphers) {
- wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ wpa_printf(MSG_INFO, "TLS: openssl_ciphers not supported");
+ tlsv1_cred_free(cred);
return -1;
}
@@ -323,7 +328,8 @@ int tls_global_set_verify(void *tls_ctx, int check_crl)
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
- int verify_peer)
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
{
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
@@ -333,16 +339,30 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
}
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
+int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
+ struct tls_random *data)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_get_random(conn->client, data);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_random(conn->server, data);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
+}
+
+
+static int tls_get_keyblock_size(struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
- return tlsv1_client_get_keys(conn->client, keys);
+ return tlsv1_client_get_keyblock_size(conn->client);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
- return tlsv1_server_get_keys(conn->server, keys);
+ return tlsv1_server_get_keyblock_size(conn->server);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
@@ -350,23 +370,41 @@ int tls_connection_get_keys(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,
- u8 *out, size_t out_len)
+ int skip_keyblock, u8 *out, size_t out_len)
{
+ int ret = -1, skip = 0;
+ u8 *tmp_out = NULL;
+ u8 *_out = out;
+
+ if (skip_keyblock) {
+ skip = tls_get_keyblock_size(conn);
+ if (skip < 0)
+ return -1;
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
+ }
+
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
- return tlsv1_client_prf(conn->client, label,
- server_random_first,
- out, out_len);
+ ret = tlsv1_client_prf(conn->client, label,
+ server_random_first,
+ _out, out_len);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
- return tlsv1_server_prf(conn->server, label,
- server_random_first,
- out, out_len);
+ ret = tlsv1_server_prf(conn->server, label,
+ server_random_first,
+ _out, out_len);
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
- return -1;
+ if (ret == 0 && skip_keyblock)
+ os_memcpy(out, _out + skip, out_len);
+ bin_clear_free(tmp_out, skip);
+
+ return ret;
}
@@ -580,6 +618,14 @@ 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;
+}
+
+
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@@ -637,27 +683,6 @@ int tls_connection_get_write_alerts(void *tls_ctx,
}
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
- if (conn->client)
- return tlsv1_client_get_keyblock_size(conn->client);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
- if (conn->server)
- return tlsv1_server_get_keyblock_size(conn->server);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
- return -1;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
- return 0;
-}
-
-
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb,
@@ -683,3 +708,26 @@ int tls_get_library_version(char *buf, size_t buf_len)
{
return os_snprintf(buf, buf_len, "internal");
}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
+{
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ return NULL;
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+}
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index a6d210afcf0f3..ae392ad8aa0f5 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -72,14 +72,15 @@ int tls_global_set_verify(void *tls_ctx, int check_crl)
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
- int verify_peer)
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
{
return -1;
}
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
+int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
+ struct tls_random *data)
{
return -1;
}
@@ -87,7 +88,7 @@ int tls_connection_get_keys(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,
- u8 *out, size_t out_len)
+ int skip_keyblock, u8 *out, size_t out_len)
{
return -1;
}
@@ -140,6 +141,13 @@ 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)
+{
+ return -1;
+}
+
+
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@@ -181,20 +189,30 @@ int tls_connection_get_write_alerts(void *tls_ctx,
}
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
+int tls_get_library_version(char *buf, size_t buf_len)
{
- return -1;
+ return os_snprintf(buf, buf_len, "none");
}
-unsigned int tls_capabilities(void *tls_ctx)
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
{
- return 0;
}
-int tls_get_library_version(char *buf, size_t buf_len)
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ return NULL;
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
{
- return os_snprintf(buf, buf_len, "none");
}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 52db8fc076ac9..8b7b47bc256d5 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1,6 +1,6 @@
/*
* SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * 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.
@@ -23,15 +23,19 @@
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif /* OPENSSL_NO_ENGINE */
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
#include "common.h"
#include "crypto.h"
+#include "sha1.h"
+#include "sha256.h"
#include "tls.h"
-#if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data)
-#define OPENSSL_SUPPORTS_CTX_APP_DATA
-#endif
-
#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
@@ -70,6 +74,7 @@ static BIO * BIO_from_keystore(const char *key)
#endif /* ANDROID */
static int tls_openssl_ref_count = 0;
+static int tls_ex_idx_session = -1;
struct tls_context {
void (*event_cb)(void *ctx, enum tls_event ev,
@@ -82,6 +87,11 @@ struct tls_context {
static struct tls_context *tls_global = NULL;
+struct tls_data {
+ SSL_CTX *ssl;
+ unsigned int tls_session_lifetime;
+};
+
struct tls_connection {
struct tls_context *context;
SSL_CTX *ssl_ctx;
@@ -105,6 +115,7 @@ struct tls_connection {
unsigned int cert_probe:1;
unsigned int server_cert_only:1;
unsigned int invalid_hb_used:1;
+ unsigned int success_data:1;
u8 srv_cert_hash[32];
@@ -113,6 +124,11 @@ struct tls_connection {
X509 *peer_cert;
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
};
@@ -735,8 +751,27 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
#endif /* OPENSSL_NO_ENGINE */
+static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+ struct wpabuf *buf;
+
+ if (tls_ex_idx_session < 0)
+ return;
+ buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (!buf)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Free application session data %p (sess %p)",
+ buf, sess);
+ wpabuf_free(buf);
+
+ SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+}
+
+
void * tls_init(const struct tls_config *conf)
{
+ struct tls_data *data;
SSL_CTX *ssl;
struct tls_context *context;
const char *ciphers;
@@ -748,7 +783,9 @@ void * tls_init(const struct tls_config *conf)
#ifdef CONFIG_FIPS
#ifdef OPENSSL_FIPS
if (conf && conf->fips_mode) {
- if (!FIPS_mode_set(1)) {
+ static int fips_enabled = 0;
+
+ if (!fips_enabled && !FIPS_mode_set(1)) {
wpa_printf(MSG_ERROR, "Failed to enable FIPS "
"mode");
ERR_load_crypto_strings();
@@ -756,8 +793,10 @@ void * tls_init(const struct tls_config *conf)
os_free(tls_global);
tls_global = NULL;
return NULL;
- } else
+ } else {
wpa_printf(MSG_INFO, "Running in FIPS mode");
+ fips_enabled = 1;
+ }
}
#else /* OPENSSL_FIPS */
if (conf && conf->fips_mode) {
@@ -791,38 +830,58 @@ void * tls_init(const struct tls_config *conf)
PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
} else {
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
- /* Newer OpenSSL can store app-data per-SSL */
context = tls_context_new(conf);
if (context == NULL)
return NULL;
-#else /* OPENSSL_SUPPORTS_CTX_APP_DATA */
- context = tls_global;
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
}
tls_openssl_ref_count++;
- ssl = SSL_CTX_new(SSLv23_method());
+ data = os_zalloc(sizeof(*data));
+ if (data)
+ ssl = SSL_CTX_new(SSLv23_method());
+ else
+ ssl = NULL;
if (ssl == NULL) {
tls_openssl_ref_count--;
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
if (context != tls_global)
os_free(context);
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
if (tls_openssl_ref_count == 0) {
os_free(tls_global);
tls_global = NULL;
}
return NULL;
}
+ data->ssl = ssl;
+ if (conf)
+ data->tls_session_lifetime = conf->tls_session_lifetime;
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
SSL_CTX_set_app_data(ssl, context);
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
+ if (data->tls_session_lifetime > 0) {
+ SSL_CTX_set_quiet_shutdown(ssl, 1);
+ /*
+ * Set default context here. In practice, this will be replaced
+ * by the per-EAP method context in tls_connection_set_verify().
+ */
+ SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
+ SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
+ SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
+ SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
+ } else {
+ SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
+ }
+
+ if (tls_ex_idx_session < 0) {
+ tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
+ 0, NULL, NULL, NULL, NULL);
+ if (tls_ex_idx_session < 0) {
+ tls_deinit(data);
+ return NULL;
+ }
+ }
#ifndef OPENSSL_NO_ENGINE
wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
@@ -835,7 +894,7 @@ void * tls_init(const struct tls_config *conf)
if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
conf->pkcs11_module_path)) {
- tls_deinit(ssl);
+ tls_deinit(data);
return NULL;
}
}
@@ -849,22 +908,23 @@ void * tls_init(const struct tls_config *conf)
wpa_printf(MSG_ERROR,
"OpenSSL: Failed to set cipher string '%s'",
ciphers);
- tls_deinit(ssl);
+ tls_deinit(data);
return NULL;
}
- return ssl;
+ return data;
}
void tls_deinit(void *ssl_ctx)
{
- SSL_CTX *ssl = ssl_ctx;
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ struct tls_data *data = ssl_ctx;
+ SSL_CTX *ssl = data->ssl;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
if (context != tls_global)
os_free(context);
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
+ if (data->tls_session_lifetime > 0)
+ SSL_CTX_flush_sessions(ssl, 0);
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
@@ -881,8 +941,31 @@ void tls_deinit(void *ssl_ctx)
os_free(tls_global);
tls_global = NULL;
}
+
+ os_free(data);
+}
+
+
+#ifndef OPENSSL_NO_ENGINE
+
+/* Cryptoki return values */
+#define CKR_PIN_INCORRECT 0x000000a0
+#define CKR_PIN_INVALID 0x000000a1
+#define CKR_PIN_LEN_RANGE 0x000000a2
+
+/* libp11 */
+#define ERR_LIB_PKCS11 ERR_LIB_USER
+
+static int tls_is_pin_error(unsigned int err)
+{
+ return ERR_GET_LIB(err) == ERR_LIB_PKCS11 &&
+ (ERR_GET_REASON(err) == CKR_PIN_INCORRECT ||
+ ERR_GET_REASON(err) == CKR_PIN_INVALID ||
+ ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE);
}
+#endif /* OPENSSL_NO_ENGINE */
+
static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
const char *pin, const char *key_id,
@@ -935,11 +1018,16 @@ static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
key_id, NULL,
&key_cb);
if (!conn->private_key) {
+ unsigned long err = ERR_get_error();
+
wpa_printf(MSG_ERROR,
"ENGINE: cannot load private key with id '%s' [%s]",
key_id,
- ERR_error_string(ERR_get_error(), NULL));
- ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ ERR_error_string(err, NULL));
+ if (tls_is_pin_error(err))
+ ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
+ else
+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
goto err;
}
}
@@ -1030,19 +1118,16 @@ static void tls_msg_cb(int write_p, int version, int content_type,
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
- SSL_CTX *ssl = ssl_ctx;
+ struct tls_data *data = ssl_ctx;
+ SSL_CTX *ssl = data->ssl;
struct tls_connection *conn;
long options;
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
struct tls_context *context = SSL_CTX_get_app_data(ssl);
-#else /* OPENSSL_SUPPORTS_CTX_APP_DATA */
- struct tls_context *context = tls_global;
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
- conn->ssl_ctx = ssl_ctx;
+ conn->ssl_ctx = ssl;
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
tls_show_errors(MSG_INFO, __func__,
@@ -1091,6 +1176,14 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
+ if (conn->success_data) {
+ /*
+ * Make sure ssl_clear_bad_session() does not remove this
+ * session.
+ */
+ SSL_set_quiet_shutdown(conn->ssl, 1);
+ SSL_shutdown(conn->ssl);
+ }
SSL_free(conn->ssl);
tls_engine_deinit(conn);
os_free(conn->subject_match);
@@ -1118,7 +1211,7 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
* and "close notify" shutdown alert would confuse AS. */
SSL_set_quiet_shutdown(conn->ssl, 1);
SSL_shutdown(conn->ssl);
- return 0;
+ return SSL_clear(conn->ssl) == 1 ? 0 : -1;
}
@@ -1617,9 +1710,9 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
#ifndef OPENSSL_NO_STDIO
-static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
+static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
X509_LOOKUP *lookup;
int ret = 0;
@@ -1649,11 +1742,12 @@ static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
#endif /* OPENSSL_NO_STDIO */
-static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
+static int tls_connection_ca_cert(struct tls_data *data,
+ struct tls_connection *conn,
const char *ca_cert, const u8 *ca_cert_blob,
size_t ca_cert_blob_len, const char *ca_path)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
X509_STORE *store;
/*
@@ -1788,7 +1882,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
tls_show_errors(MSG_WARNING, __func__,
"Failed to load root certificates");
if (ca_cert &&
- tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
+ tls_load_ca_der(data, ca_cert) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
"DER format CA certificate",
__func__);
@@ -1797,7 +1891,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
} else {
wpa_printf(MSG_DEBUG, "TLS: Trusted root "
"certificate(s) loaded");
- tls_get_errors(ssl_ctx);
+ tls_get_errors(data);
}
#else /* OPENSSL_NO_STDIO */
wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
@@ -1814,8 +1908,10 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
}
-static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
+static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
{
+ SSL_CTX *ssl_ctx = data->ssl;
+
if (ca_cert) {
if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
{
@@ -1843,7 +1939,8 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
int flags;
if (check_crl) {
- X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
+ struct tls_data *data = ssl_ctx;
+ X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
if (cs == NULL) {
tls_show_errors(MSG_INFO, __func__, "Failed to get "
"certificate store when enabling "
@@ -1901,10 +1998,44 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
}
+static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
+{
+#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
+ if (flags & TLS_CONN_DISABLE_TLSv1_0)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
+#endif /* SSL_OP_NO_TLSv1 */
+#ifdef SSL_OP_NO_TLSv1_1
+ if (flags & TLS_CONN_DISABLE_TLSv1_1)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
+#endif /* SSL_OP_NO_TLSv1_1 */
+#ifdef SSL_OP_NO_TLSv1_2
+ if (flags & TLS_CONN_DISABLE_TLSv1_2)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
+#endif /* SSL_OP_NO_TLSv1_2 */
+}
+
+
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer)
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
{
static int counter = 0;
+ struct tls_data *data = ssl_ctx;
if (conn == NULL)
return -1;
@@ -1919,20 +2050,25 @@ 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);
+ conn->flags = flags;
+
SSL_set_accept_state(conn->ssl);
- /*
- * Set session id context in order to avoid fatal errors when client
- * tries to resume a session. However, set the context to a unique
- * value in order to effectively disable session resumption for now
- * since not all areas of the server code are ready for it (e.g.,
- * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
- * handshake).
- */
- counter++;
- SSL_set_session_id_context(conn->ssl,
- (const unsigned char *) &counter,
- sizeof(counter));
+ if (data->tls_session_lifetime == 0) {
+ /*
+ * Set session id context to a unique value to make sure
+ * session resumption cannot be used either through session
+ * caching or TLS ticket extension.
+ */
+ counter++;
+ SSL_set_session_id_context(conn->ssl,
+ (const unsigned char *) &counter,
+ sizeof(counter));
+ } else if (session_ctx) {
+ SSL_set_session_id_context(conn->ssl, session_ctx,
+ session_ctx_len);
+ }
return 0;
}
@@ -2004,9 +2140,12 @@ static int tls_connection_client_cert(struct tls_connection *conn,
}
-static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
+static int tls_global_client_cert(struct tls_data *data,
+ const char *client_cert)
{
#ifndef OPENSSL_NO_STDIO
+ SSL_CTX *ssl_ctx = data->ssl;
+
if (client_cert == NULL)
return 0;
@@ -2040,7 +2179,7 @@ static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
#ifdef PKCS12_FUNCS
-static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
+static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
const char *passwd)
{
EVP_PKEY *pkey;
@@ -2052,6 +2191,8 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
pkey = NULL;
cert = NULL;
certs = NULL;
+ if (!passwd)
+ passwd = "";
if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
tls_show_errors(MSG_DEBUG, __func__,
"Failed to parse PKCS12 file");
@@ -2069,7 +2210,7 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
if (SSL_use_certificate(ssl, cert) != 1)
res = -1;
} else {
- if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1)
+ if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
res = -1;
}
X509_free(cert);
@@ -2081,13 +2222,52 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
if (SSL_use_PrivateKey(ssl, pkey) != 1)
res = -1;
} else {
- if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1)
+ if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
res = -1;
}
EVP_PKEY_free(pkey);
}
if (certs) {
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ SSL_clear_chain_certs(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) {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "Failed to add additional certificate");
+ res = -1;
+ break;
+ }
+ }
+ if (!res) {
+ /* Try to continue anyway */
+ }
+ sk_X509_free(certs);
+#ifndef OPENSSL_IS_BORINGSSL
+ res = SSL_build_cert_chain(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");
+ } else if (res == 2) {
+ wpa_printf(MSG_DEBUG,
+ "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates");
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+ /*
+ * Try to continue regardless of result since it is possible for
+ * the extra certificates not to be required.
+ */
+ 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));
@@ -2097,26 +2277,28 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
* There is no SSL equivalent for the chain cert - so
* always add it to the context...
*/
- if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
+ if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
+ {
res = -1;
break;
}
}
sk_X509_free(certs);
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
}
PKCS12_free(p12);
if (res < 0)
- tls_get_errors(ssl_ctx);
+ tls_get_errors(data);
return res;
}
#endif /* PKCS12_FUNCS */
-static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
- const char *passwd)
+static int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
+ const char *private_key, const char *passwd)
{
#ifdef PKCS12_FUNCS
FILE *f;
@@ -2135,7 +2317,7 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
return -1;
}
- return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+ return tls_parse_pkcs12(data, ssl, p12, passwd);
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
@@ -2145,7 +2327,7 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
}
-static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
+static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
const u8 *blob, size_t len, const char *passwd)
{
#ifdef PKCS12_FUNCS
@@ -2158,7 +2340,7 @@ static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
return -1;
}
- return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+ return tls_parse_pkcs12(data, ssl, p12, passwd);
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
@@ -2183,9 +2365,13 @@ static int tls_engine_get_cert(struct tls_connection *conn,
if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
0, &params, NULL, 1)) {
+ unsigned long err = ERR_get_error();
+
wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
" '%s' [%s]", cert_id,
- ERR_error_string(ERR_get_error(), NULL));
+ ERR_error_string(err, NULL));
+ if (tls_is_pin_error(err))
+ return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
}
if (!params.cert) {
@@ -2225,13 +2411,13 @@ static int tls_connection_engine_client_cert(struct tls_connection *conn,
}
-static int tls_connection_engine_ca_cert(void *_ssl_ctx,
+static int tls_connection_engine_ca_cert(struct tls_data *data,
struct tls_connection *conn,
const char *ca_cert_id)
{
#ifndef OPENSSL_NO_ENGINE
X509 *cert;
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
X509_STORE *store;
if (tls_engine_get_cert(conn, ca_cert_id, &cert))
@@ -2297,14 +2483,14 @@ static int tls_connection_engine_private_key(struct tls_connection *conn)
}
-static int tls_connection_private_key(void *_ssl_ctx,
+static int tls_connection_private_key(struct tls_data *data,
struct tls_connection *conn,
const char *private_key,
const char *private_key_passwd,
const u8 *private_key_blob,
size_t private_key_blob_len)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
char *passwd;
int ok;
@@ -2350,7 +2536,7 @@ static int tls_connection_private_key(void *_ssl_ctx,
break;
}
- if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
+ if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
private_key_blob_len, passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
"OK");
@@ -2383,7 +2569,7 @@ static int tls_connection_private_key(void *_ssl_ctx,
__func__);
#endif /* OPENSSL_NO_STDIO */
- if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
+ if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
== 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
"--> OK");
@@ -2422,9 +2608,11 @@ static int tls_connection_private_key(void *_ssl_ctx,
}
-static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
+static int tls_global_private_key(struct tls_data *data,
+ const char *private_key,
const char *private_key_passwd)
{
+ SSL_CTX *ssl_ctx = data->ssl;
char *passwd;
if (private_key == NULL)
@@ -2446,7 +2634,7 @@ static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
SSL_FILETYPE_PEM) != 1 &&
#endif /* OPENSSL_NO_STDIO */
- tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
+ tls_read_pkcs12(data, NULL, private_key, passwd)) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
os_free(passwd);
@@ -2541,7 +2729,7 @@ static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
}
-static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
+static int tls_global_dh(struct tls_data *data, const char *dh_file)
{
#ifdef OPENSSL_NO_DH
if (dh_file == NULL)
@@ -2550,6 +2738,7 @@ static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
"dh_file specified");
return -1;
#else /* OPENSSL_NO_DH */
+ SSL_CTX *ssl_ctx = data->ssl;
DH *dh;
BIO *bio;
@@ -2615,45 +2804,275 @@ static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
}
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
+int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_random *keys)
{
-#ifdef CONFIG_FIPS
- wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
- "mode");
- return -1;
-#else /* CONFIG_FIPS */
SSL *ssl;
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->master_key = ssl->session->master_key;
- keys->master_key_len = ssl->session->master_key_length;
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;
+
+ os_memset(keys, 0, sizeof(*keys));
+ keys->client_random = conn->client_random;
+ keys->client_random_len = SSL_get_client_random(
+ ssl, conn->client_random, sizeof(conn->client_random));
+ 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
+static int openssl_get_keyblock_size(SSL *ssl)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ const EVP_CIPHER *c;
+ const EVP_MD *h;
+ int md_size;
+
+ if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
+ ssl->read_hash == NULL)
+ 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;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
+ "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
+ EVP_CIPHER_iv_length(c));
+ return 2 * (EVP_CIPHER_key_length(c) +
+ md_size +
+ EVP_CIPHER_iv_length(c));
+#else
+ const SSL_CIPHER *ssl_cipher;
+ int cipher, digest;
+ const EVP_CIPHER *c;
+ const EVP_MD *h;
+
+ ssl_cipher = SSL_get_current_cipher(ssl);
+ if (!ssl_cipher)
+ return -1;
+ cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
+ digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
+ wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d",
+ cipher, digest);
+ if (cipher < 0 || digest < 0)
+ return -1;
+ c = EVP_get_cipherbynid(cipher);
+ h = EVP_get_digestbynid(digest);
+ if (!c || !h)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d",
+ EVP_CIPHER_key_length(c), EVP_MD_size(h),
+ EVP_CIPHER_iv_length(c));
+ return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) +
+ EVP_CIPHER_iv_length(c));
+#endif
+}
+#endif /* CONFIG_FIPS */
+
+
+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)
+{
+#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);
+ 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);
+ }
+
+ 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
+ SSL *ssl;
+ SSL_SESSION *sess;
+ u8 *rnd;
+ int ret = -1;
+ int skip = 0;
+ u8 *tmp_out = NULL;
+ u8 *_out = out;
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+ unsigned char server_random[SSL3_RANDOM_SIZE];
+ unsigned char master_key[64];
+ size_t master_key_len;
+ 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)
+ return -1;
+ ver = SSL_get_version(ssl);
+ sess = SSL_get_session(ssl);
+ 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;
+ }
+
+ rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
+ if (!rnd) {
+ os_free(tmp_out);
+ return -1;
+ }
+
+ SSL_get_client_random(ssl, client_random, sizeof(client_random));
+ SSL_get_server_random(ssl, server_random, sizeof(server_random));
+ 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);
+ }
+
+ if (os_strcmp(ver, "TLSv1.2") == 0) {
+ tls_prf_sha256(master_key, master_key_len,
+ label, 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,
+ _out, skip + out_len) == 0) {
+ ret = 0;
+ }
+ os_memset(master_key, 0, sizeof(master_key));
+ os_free(rnd);
+ if (ret == 0 && skip_keyblock)
+ 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,
- u8 *out, size_t out_len)
+ 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)
- 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) {
@@ -2661,7 +3080,8 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
return 0;
}
#endif
- return -1;
+ return openssl_tls_prf(conn, label, server_random_first,
+ skip_keyblock, out, out_len);
}
@@ -2676,7 +3096,7 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
* Give TLS handshake data from the server (if available) to OpenSSL
* for processing.
*/
- if (in_data &&
+ if (in_data && wpabuf_len(in_data) > 0 &&
BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
< 0) {
tls_show_errors(MSG_INFO, __func__,
@@ -2788,8 +3208,14 @@ openssl_connection_handshake(struct tls_connection *conn,
return NULL;
}
- if (SSL_is_init_finished(conn->ssl) && appl_data && in_data)
- *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data));
+ if (SSL_is_init_finished(conn->ssl)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Handshake finished - resumed=%d",
+ tls_connection_resumed(conn->ssl_ctx, conn));
+ if (appl_data && in_data)
+ *appl_data = openssl_get_appl_data(conn,
+ wpabuf_len(in_data));
+ }
if (conn->invalid_hb_used) {
wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
@@ -2968,6 +3394,21 @@ 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 defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+ if (os_strstr(buf, ":ADH-")) {
+ /*
+ * Need to drop to security level 0 to allow anonymous
+ * cipher suites for EAP-FAST.
+ */
+ SSL_set_security_level(conn->ssl, 0);
+ } else if (SSL_get_security_level(conn->ssl) == 0) {
+ /* Force at least security level 1 */
+ SSL_set_security_level(conn->ssl, 1);
+ }
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif
+
if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
tls_show_errors(MSG_INFO, __func__,
"Cipher suite configuration failed");
@@ -2978,6 +3419,22 @@ 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)
+{
+ const char *name;
+ if (conn == NULL || conn->ssl == NULL)
+ return -1;
+
+ name = SSL_get_version(conn->ssl);
+ if (name == NULL)
+ return -1;
+
+ os_strlcpy(buf, name, buflen);
+ return 0;
+}
+
+
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@@ -3300,6 +3757,7 @@ static int ocsp_status_cb(SSL *s, void *arg)
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
+ struct tls_data *data = tls_ctx;
int ret;
unsigned long err;
int can_pkcs11 = 0;
@@ -3341,6 +3799,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (can_pkcs11 == 2 && !engine_id)
engine_id = "pkcs11";
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (params->flags & TLS_CONN_EAP_FAST) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Use TLSv1_method() for EAP-FAST");
@@ -3350,6 +3810,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
}
+#endif
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
while ((err = ERR_get_error())) {
wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
@@ -3371,10 +3833,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
if (engine_id && ca_cert_id) {
- if (tls_connection_engine_ca_cert(tls_ctx, conn,
- ca_cert_id))
+ if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
- } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ } else if (tls_connection_ca_cert(data, conn, params->ca_cert,
params->ca_cert_blob,
params->ca_cert_blob_len,
params->ca_path))
@@ -3392,7 +3853,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
- } else if (tls_connection_private_key(tls_ctx, conn,
+ } else if (tls_connection_private_key(data, conn,
params->private_key,
params->private_key_passwd,
params->private_key_blob,
@@ -3416,40 +3877,30 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
-#ifdef SSL_OP_NO_TICKET
- if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
- SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
-#ifdef SSL_clear_options
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
-#endif /* SSL_OP_NO_TICKET */
-
-#ifdef SSL_OP_NO_TLSv1_1
- if (params->flags & TLS_CONN_DISABLE_TLSv1_1)
- SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_1);
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_1);
-#endif /* SSL_OP_NO_TLSv1_1 */
-#ifdef SSL_OP_NO_TLSv1_2
- if (params->flags & TLS_CONN_DISABLE_TLSv1_2)
- SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_2);
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_2);
-#endif /* SSL_OP_NO_TLSv1_2 */
+ tls_set_conn_flags(conn->ssl, params->flags);
#ifdef HAVE_OCSP
if (params->flags & TLS_CONN_REQUEST_OCSP) {
- SSL_CTX *ssl_ctx = tls_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
}
+#else /* HAVE_OCSP */
+ if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: No OCSP support included - reject configuration");
+ return -1;
+ }
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
+ }
#endif /* HAVE_OCSP */
conn->flags = params->flags;
- tls_get_errors(tls_ctx);
+ tls_get_errors(data);
return 0;
}
@@ -3458,7 +3909,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
- SSL_CTX *ssl_ctx = tls_ctx;
+ struct tls_data *data = tls_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
unsigned long err;
while ((err = ERR_get_error())) {
@@ -3466,19 +3918,12 @@ int tls_global_set_params(void *tls_ctx,
__func__, ERR_error_string(err, NULL));
}
- if (tls_global_ca_cert(ssl_ctx, params->ca_cert))
- return -1;
-
- if (tls_global_client_cert(ssl_ctx, params->client_cert))
- return -1;
-
- if (tls_global_private_key(ssl_ctx, params->private_key,
- params->private_key_passwd))
- return -1;
-
- if (tls_global_dh(ssl_ctx, params->dh_file)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
- params->dh_file);
+ 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,
+ params->private_key_passwd) ||
+ tls_global_dh(data, params->dh_file)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
return -1;
}
@@ -3514,49 +3959,6 @@ int tls_global_set_params(void *tls_ctx,
}
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
-{
- const EVP_CIPHER *c;
- const EVP_MD *h;
- int md_size;
-
- if (conn == NULL || conn->ssl == NULL ||
- conn->ssl->enc_read_ctx == NULL ||
- conn->ssl->enc_read_ctx->cipher == NULL ||
- conn->ssl->read_hash == NULL)
- return -1;
-
- c = conn->ssl->enc_read_ctx->cipher;
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
- h = EVP_MD_CTX_md(conn->ssl->read_hash);
-#else
- h = conn->ssl->read_hash;
-#endif
- if (h)
- md_size = EVP_MD_size(h);
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
- else if (conn->ssl->s3)
- md_size = conn->ssl->s3->tmp.new_mac_secret_size;
-#endif
- else
- return -1;
-
- wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
- "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
- EVP_CIPHER_iv_length(c));
- return 2 * (EVP_CIPHER_key_length(c) +
- md_size +
- EVP_CIPHER_iv_length(c));
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
- return 0;
-}
-
-
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
/* Pre-shared secred requires a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
@@ -3575,6 +3977,7 @@ 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 (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
@@ -3583,6 +3986,23 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
conn->session_ticket_len,
s->s3->client_random,
s->s3->server_random, secret);
+#else
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+ unsigned char server_random[SSL3_RANDOM_SIZE];
+
+ if (conn == NULL || conn->session_ticket_cb == NULL)
+ return 0;
+
+ SSL_get_client_random(s, client_random, sizeof(client_random));
+ SSL_get_server_random(s, server_random, sizeof(server_random));
+
+ ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+ conn->session_ticket,
+ conn->session_ticket_len,
+ client_random,
+ server_random, secret);
+#endif
+
os_free(conn->session_ticket);
conn->session_ticket = NULL;
@@ -3656,3 +4076,70 @@ int tls_get_library_version(char *buf, size_t buf_len)
OPENSSL_VERSION_TEXT,
SSLeay_version(SSLEAY_VERSION));
}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
+{
+ SSL_SESSION *sess;
+ struct wpabuf *old;
+
+ if (tls_ex_idx_session < 0)
+ goto fail;
+ sess = SSL_get_session(conn->ssl);
+ if (!sess)
+ goto fail;
+ old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (old) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
+ old);
+ wpabuf_free(old);
+ }
+ if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
+ conn->success_data = 1;
+ return;
+
+fail:
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
+ wpabuf_free(data);
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Success data accepted for resumed session");
+ conn->success_data = 1;
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ SSL_SESSION *sess;
+
+ if (tls_ex_idx_session < 0 ||
+ !(sess = SSL_get_session(conn->ssl)))
+ return NULL;
+ return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+ SSL_SESSION *sess;
+
+ sess = SSL_get_session(conn->ssl);
+ if (!sess)
+ return;
+
+ if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Session was not cached");
+ else
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Removed cached session to disable session resumption");
+}
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
deleted file mode 100644
index 31a2c946d0478..0000000000000
--- a/src/crypto/tls_schannel.c
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- * SSL/TLS interface functions for Microsoft Schannel
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-/*
- * FIX: Go through all SSPI functions and verify what needs to be freed
- * FIX: session resumption
- * TODO: add support for server cert chain validation
- * TODO: add support for CA cert validation
- * TODO: add support for EAP-TLS (client cert/key conf)
- */
-
-#include "includes.h"
-#include <windows.h>
-#include <wincrypt.h>
-#include <schannel.h>
-#define SECURITY_WIN32
-#include <security.h>
-#include <sspi.h>
-
-#include "common.h"
-#include "tls.h"
-
-
-struct tls_global {
- HMODULE hsecurity;
- PSecurityFunctionTable sspi;
- HCERTSTORE my_cert_store;
-};
-
-struct tls_connection {
- int established, start;
- int failed, read_alerts, write_alerts;
-
- SCHANNEL_CRED schannel_cred;
- CredHandle creds;
- CtxtHandle context;
-
- u8 eap_tls_prf[128];
- int eap_tls_prf_set;
-};
-
-
-static int schannel_load_lib(struct tls_global *global)
-{
- INIT_SECURITY_INTERFACE pInitSecurityInterface;
-
- global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
- if (global->hsecurity == NULL) {
- wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
- __func__, (unsigned int) GetLastError());
- return -1;
- }
-
- pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
- global->hsecurity, "InitSecurityInterfaceA");
- if (pInitSecurityInterface == NULL) {
- wpa_printf(MSG_ERROR, "%s: Could not find "
- "InitSecurityInterfaceA from Secur32.dll",
- __func__);
- FreeLibrary(global->hsecurity);
- global->hsecurity = NULL;
- return -1;
- }
-
- global->sspi = pInitSecurityInterface();
- if (global->sspi == NULL) {
- wpa_printf(MSG_ERROR, "%s: Could not read security "
- "interface - 0x%x",
- __func__, (unsigned int) GetLastError());
- FreeLibrary(global->hsecurity);
- global->hsecurity = NULL;
- return -1;
- }
-
- return 0;
-}
-
-
-void * tls_init(const struct tls_config *conf)
-{
- struct tls_global *global;
-
- global = os_zalloc(sizeof(*global));
- if (global == NULL)
- return NULL;
- if (schannel_load_lib(global)) {
- os_free(global);
- return NULL;
- }
- return global;
-}
-
-
-void tls_deinit(void *ssl_ctx)
-{
- struct tls_global *global = ssl_ctx;
-
- if (global->my_cert_store)
- CertCloseStore(global->my_cert_store, 0);
- FreeLibrary(global->hsecurity);
- os_free(global);
-}
-
-
-int tls_get_errors(void *ssl_ctx)
-{
- return 0;
-}
-
-
-struct tls_connection * tls_connection_init(void *ssl_ctx)
-{
- struct tls_connection *conn;
-
- conn = os_zalloc(sizeof(*conn));
- if (conn == NULL)
- return NULL;
- conn->start = 1;
-
- return conn;
-}
-
-
-void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return;
-
- os_free(conn);
-}
-
-
-int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
-{
- return conn ? conn->established : 0;
-}
-
-
-int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
-{
- struct tls_global *global = ssl_ctx;
- if (conn == NULL)
- return -1;
-
- conn->eap_tls_prf_set = 0;
- conn->established = conn->failed = 0;
- conn->read_alerts = conn->write_alerts = 0;
- global->sspi->DeleteSecurityContext(&conn->context);
- /* FIX: what else needs to be reseted? */
-
- return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
- const struct tls_connection_params *params)
-{
- return -1;
-}
-
-
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
-{
- return -1;
-}
-
-
-int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer)
-{
- return -1;
-}
-
-
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
-{
- /* Schannel does not export master secret or client/server random. */
- return -1;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- u8 *out, size_t out_len)
-{
- /*
- * Cannot get master_key from Schannel, but EapKeyBlock can be used to
- * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
- * EAP-TTLS cannot use this, though, since they are using different
- * labels. The only option could be to implement TLSv1 completely here
- * and just use Schannel or CryptoAPI for low-level crypto
- * functionality..
- */
-
- if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
- os_strcmp(label, "client EAP encryption") != 0 ||
- out_len > sizeof(conn->eap_tls_prf))
- return -1;
-
- os_memcpy(out, conn->eap_tls_prf, out_len);
-
- return 0;
-}
-
-
-static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
- struct tls_connection *conn)
-{
- DWORD sspi_flags, sspi_flags_out;
- SecBufferDesc outbuf;
- SecBuffer outbufs[1];
- SECURITY_STATUS status;
- TimeStamp ts_expiry;
-
- sspi_flags = ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONFIDENTIALITY |
- ISC_RET_EXTENDED_ERROR |
- ISC_REQ_ALLOCATE_MEMORY |
- ISC_REQ_MANUAL_CRED_VALIDATION;
-
- wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
-
- outbufs[0].pvBuffer = NULL;
- outbufs[0].BufferType = SECBUFFER_TOKEN;
- outbufs[0].cbBuffer = 0;
-
- outbuf.cBuffers = 1;
- outbuf.pBuffers = outbufs;
- outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
- status = global->sspi->InitializeSecurityContextW(
- &conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
- SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
- status = global->sspi->InitializeSecurityContextA(
- &conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
- SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
- if (status != SEC_I_CONTINUE_NEEDED) {
- wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
- "failed - 0x%x",
- __func__, (unsigned int) status);
- return NULL;
- }
-
- if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
- struct wpabuf *buf;
- wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
- outbufs[0].pvBuffer, outbufs[0].cbBuffer);
- conn->start = 0;
- buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
- outbufs[0].cbBuffer);
- if (buf == NULL)
- return NULL;
- global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
- return buf;
- }
-
- wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
-
- return NULL;
-}
-
-
-#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
-#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
-
-typedef struct _SecPkgContext_EapKeyBlock {
- BYTE rgbKeys[128];
- BYTE rgbIVs[64];
-} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
-#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
-
-static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
-{
- SECURITY_STATUS status;
- SecPkgContext_EapKeyBlock kb;
-
- /* Note: Windows NT and Windows Me/98/95 do not support getting
- * EapKeyBlock */
-
- status = global->sspi->QueryContextAttributes(
- &conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
- if (status != SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
- "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
- __func__, (int) status);
- return -1;
- }
-
- wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
- kb.rgbKeys, sizeof(kb.rgbKeys));
- wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
- kb.rgbIVs, sizeof(kb.rgbIVs));
-
- os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
- conn->eap_tls_prf_set = 1;
- return 0;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- struct tls_global *global = tls_ctx;
- DWORD sspi_flags, sspi_flags_out;
- SecBufferDesc inbuf, outbuf;
- SecBuffer inbufs[2], outbufs[1];
- SECURITY_STATUS status;
- TimeStamp ts_expiry;
- struct wpabuf *out_buf = NULL;
-
- if (appl_data)
- *appl_data = NULL;
-
- if (conn->start)
- return tls_conn_hs_clienthello(global, conn);
-
- wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
- (int) wpabuf_len(in_data));
-
- sspi_flags = ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONFIDENTIALITY |
- ISC_RET_EXTENDED_ERROR |
- ISC_REQ_ALLOCATE_MEMORY |
- ISC_REQ_MANUAL_CRED_VALIDATION;
-
- /* Input buffer for Schannel */
- inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
- inbufs[0].cbBuffer = wpabuf_len(in_data);
- inbufs[0].BufferType = SECBUFFER_TOKEN;
-
- /* Place for leftover data from Schannel */
- inbufs[1].pvBuffer = NULL;
- inbufs[1].cbBuffer = 0;
- inbufs[1].BufferType = SECBUFFER_EMPTY;
-
- inbuf.cBuffers = 2;
- inbuf.pBuffers = inbufs;
- inbuf.ulVersion = SECBUFFER_VERSION;
-
- /* Output buffer for Schannel */
- outbufs[0].pvBuffer = NULL;
- outbufs[0].cbBuffer = 0;
- outbufs[0].BufferType = SECBUFFER_TOKEN;
-
- outbuf.cBuffers = 1;
- outbuf.pBuffers = outbufs;
- outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
- status = global->sspi->InitializeSecurityContextW(
- &conn->creds, &conn->context, NULL, sspi_flags, 0,
- SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
- status = global->sspi->InitializeSecurityContextA(
- &conn->creds, &conn->context, NULL, sspi_flags, 0,
- SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
-
- wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
- "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
- "intype[1]=%d outlen[0]=%d",
- (int) status, (int) inbufs[0].cbBuffer,
- (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
- (int) inbufs[1].BufferType,
- (int) outbufs[0].cbBuffer);
- if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
- (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
- if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
- wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
- outbufs[0].pvBuffer, outbufs[0].cbBuffer);
- out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
- outbufs[0].cbBuffer);
- global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
- outbufs[0].pvBuffer = NULL;
- if (out_buf == NULL)
- return NULL;
- }
- }
-
- switch (status) {
- case SEC_E_INCOMPLETE_MESSAGE:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
- break;
- case SEC_I_CONTINUE_NEEDED:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
- break;
- case SEC_E_OK:
- /* TODO: verify server certificate chain */
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
- "completed successfully");
- conn->established = 1;
- tls_get_eap(global, conn);
-
- /* Need to return something to get final TLS ACK. */
- if (out_buf == NULL)
- out_buf = wpabuf_alloc(0);
-
- if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
- wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
- "application data",
- inbufs[1].pvBuffer, inbufs[1].cbBuffer);
- if (appl_data) {
- *appl_data = wpabuf_alloc_copy(
- outbufs[1].pvBuffer,
- outbufs[1].cbBuffer);
- }
- global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
- inbufs[1].pvBuffer = NULL;
- }
- break;
- case SEC_I_INCOMPLETE_CREDENTIALS:
- wpa_printf(MSG_DEBUG,
- "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
- break;
- case SEC_E_WRONG_PRINCIPAL:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
- break;
- case SEC_E_INTERNAL_ERROR:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
- break;
- }
-
- if (FAILED(status)) {
- wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
- "(out_buf=%p)", out_buf);
- conn->failed++;
- global->sspi->DeleteSecurityContext(&conn->context);
- return out_buf;
- }
-
- if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
- /* TODO: Can this happen? What to do with this data? */
- wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
- inbufs[1].pvBuffer, inbufs[1].cbBuffer);
- global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
- inbufs[1].pvBuffer = NULL;
- }
-
- return out_buf;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- struct tls_global *global = tls_ctx;
- SECURITY_STATUS status;
- SecBufferDesc buf;
- SecBuffer bufs[4];
- SecPkgContext_StreamSizes sizes;
- int i;
- struct wpabuf *out;
-
- status = global->sspi->QueryContextAttributes(&conn->context,
- SECPKG_ATTR_STREAM_SIZES,
- &sizes);
- if (status != SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
- __func__);
- return NULL;
- }
- wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
- __func__,
- (unsigned int) sizes.cbHeader,
- (unsigned int) sizes.cbTrailer);
-
- out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
- sizes.cbTrailer);
-
- os_memset(&bufs, 0, sizeof(bufs));
- bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
- bufs[0].cbBuffer = sizes.cbHeader;
- bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
-
- bufs[1].pvBuffer = wpabuf_put(out, 0);
- wpabuf_put_buf(out, in_data);
- bufs[1].cbBuffer = wpabuf_len(in_data);
- bufs[1].BufferType = SECBUFFER_DATA;
-
- bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
- bufs[2].cbBuffer = sizes.cbTrailer;
- bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
-
- buf.ulVersion = SECBUFFER_VERSION;
- buf.cBuffers = 3;
- buf.pBuffers = bufs;
-
- status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
-
- wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
- "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
- "len[2]=%d type[2]=%d",
- (int) status,
- (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
- (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
- (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
- wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
- "out_data=%p bufs %p %p %p",
- wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
- bufs[2].pvBuffer);
-
- for (i = 0; i < 3; i++) {
- if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
- {
- wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
- bufs[i].pvBuffer, bufs[i].cbBuffer);
- }
- }
-
- if (status == SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
- wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
- "from EncryptMessage", out);
- return out;
- }
-
- wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
- __func__, (int) status);
- wpabuf_free(out);
- return NULL;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- struct tls_global *global = tls_ctx;
- SECURITY_STATUS status;
- SecBufferDesc buf;
- SecBuffer bufs[4];
- int i;
- struct wpabuf *out, *tmp;
-
- wpa_hexdump_buf(MSG_MSGDUMP,
- "Schannel: Encrypted data to DecryptMessage", in_data);
- os_memset(&bufs, 0, sizeof(bufs));
- tmp = wpabuf_dup(in_data);
- if (tmp == NULL)
- return NULL;
- bufs[0].pvBuffer = wpabuf_mhead(tmp);
- bufs[0].cbBuffer = wpabuf_len(in_data);
- bufs[0].BufferType = SECBUFFER_DATA;
-
- bufs[1].BufferType = SECBUFFER_EMPTY;
- bufs[2].BufferType = SECBUFFER_EMPTY;
- bufs[3].BufferType = SECBUFFER_EMPTY;
-
- buf.ulVersion = SECBUFFER_VERSION;
- buf.cBuffers = 4;
- buf.pBuffers = bufs;
-
- status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
- NULL);
- wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
- "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
- "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
- (int) status,
- (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
- (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
- (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
- (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
- wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
- "out_data=%p bufs %p %p %p %p",
- wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
- bufs[2].pvBuffer, bufs[3].pvBuffer);
-
- switch (status) {
- case SEC_E_INCOMPLETE_MESSAGE:
- wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
- __func__);
- break;
- case SEC_E_OK:
- wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
- for (i = 0; i < 4; i++) {
- if (bufs[i].BufferType == SECBUFFER_DATA)
- break;
- }
- if (i == 4) {
- wpa_printf(MSG_DEBUG, "%s: No output data from "
- "DecryptMessage", __func__);
- wpabuf_free(tmp);
- return NULL;
- }
- wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
- "DecryptMessage",
- bufs[i].pvBuffer, bufs[i].cbBuffer);
- out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
- wpabuf_free(tmp);
- return out;
- }
-
- wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
- __func__, (int) status);
- wpabuf_free(tmp);
- return NULL;
-}
-
-
-int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
- u8 *ciphers)
-{
- return -1;
-}
-
-
-int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
- char *buf, size_t buflen)
-{
- return -1;
-}
-
-
-int tls_connection_enable_workaround(void *ssl_ctx,
- struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
- int ext_type, const u8 *data,
- size_t data_len)
-{
- return -1;
-}
-
-
-int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
- return conn->failed;
-}
-
-
-int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
- return conn->read_alerts;
-}
-
-
-int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
- return conn->write_alerts;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
- const struct tls_connection_params *params)
-{
- struct tls_global *global = tls_ctx;
- ALG_ID algs[1];
- SECURITY_STATUS status;
- TimeStamp ts_expiry;
-
- if (conn == NULL)
- return -1;
-
- if (params->subject_match) {
- wpa_printf(MSG_INFO, "TLS: subject_match not supported");
- return -1;
- }
-
- if (params->altsubject_match) {
- wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
- return -1;
- }
-
- if (params->suffix_match) {
- wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
- return -1;
- }
-
- if (params->domain_match) {
- wpa_printf(MSG_INFO, "TLS: domain_match not supported");
- return -1;
- }
-
- if (params->openssl_ciphers) {
- wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
- return -1;
- }
-
- if (global->my_cert_store == NULL &&
- (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
- NULL) {
- wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
- __func__, (unsigned int) GetLastError());
- return -1;
- }
-
- os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
- conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
- conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
- algs[0] = CALG_RSA_KEYX;
- conn->schannel_cred.cSupportedAlgs = 1;
- conn->schannel_cred.palgSupportedAlgs = algs;
- conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
-#ifdef UNICODE
- status = global->sspi->AcquireCredentialsHandleW(
- NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
- &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#else /* UNICODE */
- status = global->sspi->AcquireCredentialsHandleA(
- NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
- &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#endif /* UNICODE */
- if (status != SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
- "0x%x", __func__, (unsigned int) status);
- return -1;
- }
-
- return 0;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
- return 0;
-}
-
-
-int tls_get_library_version(char *buf, size_t buf_len)
-{
- return os_snprintf(buf, buf_len, "schannel");
-}