From patchwork Thu Jan 18 02:26:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Sean Parkinson X-Patchwork-Id: 863184 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="gr+eNzF/"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zMy7K07qMz9t66 for ; Fri, 19 Jan 2018 08:40:45 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:To:Date:Message-Id:Subject:Mime-Version :From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=3EAdMexZHwmQGUkEZb78Qf3AZTHeg7r8UKCNjr5DDBo=; b=gr+eNzF/BaAYoH 6htYwF0aY9fgtm467CGQgtOu2jUUhnymHH8tK0O9EDLKdmn6cWRAcgfmu+4bWrhEqgxB8te05cIT+ ONzkQbFj7U2JIip7yzT29V9IR22Hpf6qQBUYuDUsjJpkDiBl7/0RUpOMlvVohc9x+DD9ZM+V0q4fl GzAZyurGa/J+cyk1+CAWEfAEvy5f2rrcUPnboBVNiYYKg9InKb9PQbRnsxoZJN8dGE1RXv/+tD09h RYu2FvbtrcPaDky6KIwT2gezUaX7gsD5th2UmxnxV+wbTISTG/pVFLLBI6FfeW6s/492RGACp1kGy QNuN70SqU97nr3/ya3DA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.89 #1 (Red Hat Linux)) id 1ecHv4-00005Z-Ia; Thu, 18 Jan 2018 21:40:22 +0000 Received: from p3plsmtpa07-02.prod.phx3.secureserver.net ([173.201.192.231]) by bombadil.infradead.org with esmtps (Exim 4.89 #1 (Red Hat Linux)) id 1ebzvN-0005ZZ-PS for hostap@lists.infradead.org; Thu, 18 Jan 2018 02:27:36 +0000 Received: from [192.168.0.7] ([218.215.147.158]) by :SMTPAUTH: with SMTP id bzuZeUvXuuDuQbzv5ed2dE; Wed, 17 Jan 2018 19:27:17 -0700 From: Sean Parkinson Mime-Version: 1.0 (Mac OS X Mail 11.1 \(3445.4.7\)) Subject: Proposed Patch: Support for wolfSSL Message-Id: <35F71B52-8428-4A0E-B14C-20CFF8CBCA65@wolfssl.com> Date: Thu, 18 Jan 2018 12:26:39 +1000 To: hostap@lists.infradead.org X-Mailer: Apple Mail (2.3445.4.7) X-CMAE-Envelope: MS4wfKt146DfXe67hv9MaKsjSYzyZEb0mm0V8upGVH0I+qZev7rrFVRme+b+eoCbJEFuUXnnS3ejp8j8IxNX7/2krkrBwFsVenunvSp9z0yzjiD3F5yPmKdH b8HhhRs4DvgbUKv0oFbSabFnbZw/3jNrvFjVWEkBHN1HQ5fp5ZBjypD9T+8ZSI8jLMdpsyJpu/pX//AEGzcbP/yEaPEzNql+oPBSCMBgosvq+qqVQsFb/KBT X-Spam-Note: CRM114 run bypassed due to message size (136067 bytes) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [173.201.192.231 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [173.201.192.231 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-Mailman-Approved-At: Thu, 18 Jan 2018 13:40:20 -0800 X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jouni Malinen , Todd A Ouska Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org I’ve prepared a new patch with the changes as asked for by Jouni. This patch was written to allow hostap to be compiled with the wolfSSL cryptography and TLS library. Thanks, Sean :-) — Sean Parkinson sean@wolfssl.com wolfSSL Inc From b80083836a5896e01eeee2ad108ca3d45de2f919 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 17 Jan 2018 16:42:14 +1000 Subject: [PATCH] Add support for wolfSSL cryptographic library Signed-off-by: Sean Parkinson Signed-off-by: Sean Parkinson Signed-off-by: Sean Parkinson --- hostapd/Makefile | 48 +- src/crypto/crypto_wolfssl.c | 1607 ++++++++++++++++++++++ src/crypto/fips_prf_wolfssl.c | 85 ++ src/crypto/tls_wolfssl.c | 2057 +++++++++++++++++++++++++++++ tests/hwsim/example-hostapd.config | 5 + tests/hwsim/example-wpa_supplicant.config | 4 + tests/hwsim/test_ap_eap.py | 50 +- wpa_supplicant/Makefile | 53 + 8 files changed, 3896 insertions(+), 13 deletions(-) create mode 100644 src/crypto/crypto_wolfssl.c create mode 100644 src/crypto/fips_prf_wolfssl.c create mode 100644 src/crypto/tls_wolfssl.c diff --git a/hostapd/Makefile b/hostapd/Makefile index 418ab95..4a8299d 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -651,6 +651,27 @@ CFLAGS += -DCONFIG_TLSV12 NEED_SHA256=y endif +ifeq ($(CONFIG_TLS), wolfssl) +CFLAGS += -DCRYPTO_ABSTRACT_API +ifdef TLS_FUNCS +OBJS += ../src/crypto/tls_wolfssl.o +LIBS += -lwolfssl -lm +endif +OBJS += ../src/crypto/crypto_wolfssl.o +HOBJS += ../src/crypto/crypto_wolfssl.o +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_wolfssl.o +endif +NEED_SHA256=y +NEED_TLS_PRF_SHA256=y +LIBS += -lwolfssl -lm +LIBS_h += -lwolfssl -lm +ifdef CONFIG_TLS_ADD_DL +LIBS += -ldl +LIBS_h += -ldl +endif +endif + ifeq ($(CONFIG_TLS), openssl) ifdef TLS_FUNCS OBJS += ../src/crypto/tls_openssl.o @@ -855,8 +876,10 @@ AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o endif ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) AESOBJS += ../src/crypto/aes-wrap.o endif +endif ifdef NEED_AES_EAX AESOBJS += ../src/crypto/aes-eax.o NEED_AES_CTR=y @@ -881,19 +904,23 @@ endif ifdef NEED_AES_UNWRAP ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) NEED_AES_DEC=y AESOBJS += ../src/crypto/aes-unwrap.o endif endif endif +endif ifdef NEED_AES_CBC NEED_AES_DEC=y ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) AESOBJS += ../src/crypto/aes-cbc.o endif endif endif +endif ifdef NEED_AES_DEC ifdef CONFIG_INTERNAL_AES AESOBJS += ../src/crypto/aes-internal-dec.o @@ -907,10 +934,12 @@ ifdef NEED_SHA1 ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) SHA1OBJS += ../src/crypto/sha1.o endif endif endif +endif SHA1OBJS += ../src/crypto/sha1-prf.o ifdef CONFIG_INTERNAL_SHA1 SHA1OBJS += ../src/crypto/sha1-internal.o @@ -919,8 +948,10 @@ SHA1OBJS += ../src/crypto/fips_prf_internal.o endif endif ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) SHA1OBJS += ../src/crypto/sha1-pbkdf2.o endif +endif ifdef NEED_T_PRF SHA1OBJS += ../src/crypto/sha1-tprf.o endif @@ -936,10 +967,12 @@ endif ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) OBJS += ../src/crypto/md5.o endif endif endif +endif ifdef NEED_MD5 ifdef CONFIG_INTERNAL_MD5 @@ -955,6 +988,7 @@ endif endif ifdef NEED_DES +CFLAGS += -DCONFIG_DES ifdef CONFIG_INTERNAL_DES OBJS += ../src/crypto/des-internal.o endif @@ -977,10 +1011,12 @@ CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) OBJS += ../src/crypto/sha256.o endif endif endif +endif OBJS += ../src/crypto/sha256-prf.o ifdef CONFIG_INTERNAL_SHA256 OBJS += ../src/crypto/sha256-internal.o @@ -1003,10 +1039,12 @@ CFLAGS += -DCONFIG_SHA384 ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) OBJS += ../src/crypto/sha384.o endif endif endif +endif OBJS += ../src/crypto/sha384-prf.o endif ifdef NEED_SHA512 @@ -1056,10 +1094,12 @@ HOBJS += ../src/utils/eloop.o HOBJS += $(SHA1OBJS) ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) HOBJS += ../src/crypto/md5.o endif endif endif +endif ifdef CONFIG_RADIUS_SERVER CFLAGS += -DRADIUS_SERVER @@ -1250,7 +1290,13 @@ endif ifdef CONFIG_INTERNAL_MD5 NOBJS += ../src/crypto/md5-internal.o endif -NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o +ifneq ($(CONFIG_TLS), openssl) +NOBJS += ../src/crypto/crypto_openssl.o +endif +ifneq ($(CONFIG_TLS), wolfssl) +NOBJS += ../src/crypto/crypto_wolfssl.o +endif +NOBJS += ../src/utils/os_$(CONFIG_OS).o NOBJS += ../src/utils/wpa_debug.o NOBJS += ../src/utils/wpabuf.o ifdef CONFIG_WPA_TRACE diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c new file mode 100644 index 0000000..ccff47e --- /dev/null +++ b/src/crypto/crypto_wolfssl.c @@ -0,0 +1,1607 @@ +/* + * WPA Supplicant / wrapper functions for libwolfssl + * Copyright (c) 2004-2017, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto.h" + +#define WOLFSSL_AES_DIRECT +#define HAVE_AESGCM +#define HAVE_AES_KEYWRAP +#define WOLFSSL_SHA384 +#define WOLFSSL_SHA512 +#define WOLFSSL_CMAC +#define HAVE_ECC +#define USE_FAST_MATH +#define WOLFSSL_KEY_GEN + +#include +/* wolfSSL headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_FIPS +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + Md4 md4; + size_t i; + + if (TEST_FAIL()) + return -1; + + wc_InitMd4(&md4); + + for (i = 0; i < num_elem; i++) + wc_Md4Update(&md4, addr[i], len[i]); + + wc_Md4Final(&md4, mac); + + return 0; +} + +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + Md5 md5; + size_t i; + + if (TEST_FAIL()) + return -1; + + wc_InitMd5(&md5); + + for (i = 0; i < num_elem; i++) + wc_Md5Update(&md5, addr[i], len[i]); + + wc_Md5Final(&md5, mac); + + return 0; +} +#endif + +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + Sha sha; + size_t i; + + if (TEST_FAIL()) + return -1; + + wc_InitSha(&sha); + + for (i = 0; i < num_elem; i++) + wc_ShaUpdate(&sha, addr[i], len[i]); + + wc_ShaFinal(&sha, mac); + + return 0; +} + +#ifndef NO_SHA256_WRAPPER +int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + Sha256 sha256; + size_t i; + + if (TEST_FAIL()) + return -1; + + wc_InitSha256(&sha256); + + for (i = 0; i < num_elem; i++) + wc_Sha256Update(&sha256, addr[i], len[i]); + + wc_Sha256Final(&sha256, mac); + + return 0; +} +#endif /* NO_SHA256_WRAPPER */ + +#ifdef CONFIG_SHA384 +int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + Sha384 sha384; + size_t i; + + if (TEST_FAIL()) + return -1; + + wc_InitSha384(&sha384); + + for (i = 0; i < num_elem; i++) + wc_Sha384Update(&sha384, addr[i], len[i]); + + wc_Sha384Final(&sha384, mac); + + return 0; +} +#endif /* CONFIG_SHA384 */ + +static int wolfssl_hmac_vector(int type, const u8 *key, + size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac, + unsigned int mdlen) +{ + Hmac hmac; + int i; + + (void)mdlen; + + if (TEST_FAIL()) + return -1; + + if (wc_HmacSetKey(&hmac, type, key, (word32)key_len) != 0) + return -1; + for (i = 0; i < num_elem; i++) + if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0) + return -1; + if (wc_HmacFinal(&hmac, mac) != 0) + return -1; + return 0; +} + +#ifndef CONFIG_FIPS +int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return wolfssl_hmac_vector(MD5, key, key_len, num_elem, addr, len, mac, 16); +} + + +int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); +} +#endif + +int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return wolfssl_hmac_vector(SHA, key, key_len, num_elem, addr, + len, mac, 20); +} + + +int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); +} + +#ifdef CONFIG_SHA256 + +int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return wolfssl_hmac_vector(SHA256, key, key_len, num_elem, addr, len, mac, + 32); +} + + +int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); +} + +#endif /* CONFIG_SHA256 */ + + +#ifdef CONFIG_SHA384 + +int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return wolfssl_hmac_vector(SHA384, key, key_len, num_elem, addr, len, mac, + 48); +} + + +int hmac_sha384(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac); +} + +#endif /* CONFIG_SHA384 */ + +int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid, + ssid_len, iterations, buflen, SHA) != 0) + return -1; + return 0; +} + + +#ifdef CONFIG_DES +int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) +{ + Des des; + u8 pkey[8], next, tmp; + int i; + + /* Add parity bits to the key */ + next = 0; + for (i = 0; i < 7; i++) { + tmp = key[i]; + pkey[i] = (tmp >> i) | next | 1; + next = tmp << (7 - i); + } + pkey[i] = next | 1; + + wc_Des_SetKey(&des, pkey, NULL, DES_ENCRYPTION); + wc_Des_EcbEncrypt(&des, cypher, clear, DES_BLOCK_SIZE); + + return 0; +} +#endif + +void * aes_encrypt_init(const u8 *key, size_t len) +{ + Aes* aes; + + if (TEST_FAIL()) + return NULL; + + aes = os_malloc(sizeof(Aes)); + if (aes == NULL) + return NULL; + + if (wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION) < 0) { + os_free(aes); + return NULL; + } + + return aes; +} + +int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) +{ + wc_AesEncryptDirect((Aes*)ctx, crypt, plain); + return 0; +} + + +void aes_encrypt_deinit(void *ctx) +{ + if (ctx != NULL) + os_free(ctx); +} + + +void* aes_decrypt_init(const u8 *key, size_t len) +{ + Aes* aes; + + if (TEST_FAIL()) + return NULL; + + aes = os_malloc(sizeof(Aes)); + if (aes == NULL) + return NULL; + + if (wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION) < 0) { + os_free(aes); + return NULL; + } + + return aes; +} + + +int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) +{ + wc_AesDecryptDirect((Aes*)ctx, plain, crypt); + return 0; +} + + +void aes_decrypt_deinit(void *ctx) +{ + if (ctx != NULL) + os_free(ctx); +} + +int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + Aes aes; + int ret; + + if (TEST_FAIL()) + return -1; + + ret = wc_AesSetKey(&aes, key, 16, iv, AES_ENCRYPTION); + if (ret != 0) + return -1; + + ret = wc_AesCbcEncrypt(&aes, data, data, data_len); + if (ret != 0) + return -1; + return 0; +} + + +int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + Aes aes; + int ret; + + if (TEST_FAIL()) + return -1; + + ret = wc_AesSetKey(&aes, key, 16, iv, AES_DECRYPTION); + if (ret != 0) + return -1; + + ret = wc_AesCbcDecrypt(&aes, data, data, data_len); + if (ret != 0) + return -1; + return 0; +} + +#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) +{ + int ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8, + NULL); + return ret != (n + 1) * 8 ? -1 : 0; +} + + +int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, + u8 *plain) +{ + int ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8, + NULL); + return ret != n * 8 ? -1 : 0; +} + +#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */ +#endif /* CONFIG_FIPS */ + +#ifndef CONFIG_NO_RC4 +int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data, + size_t data_len) +{ +#ifndef NO_RC4 + Arc4 arc4; + unsigned char skip_buf[16]; + + wc_Arc4SetKey(&arc4, key, keylen); + + while (skip >= sizeof(skip_buf)) { + size_t len = skip; + if (len > sizeof(skip_buf)) + len = sizeof(skip_buf); + wc_Arc4Process(&arc4, skip_buf, skip_buf, len); + skip -= len; + } + + wc_Arc4Process(&arc4, data, data, data_len); + + return 0; +#else + return -1; +#endif +} +#endif /* CONFIG_NO_RC4 */ + +#if defined(EAP_IKEV2) || defined(EAP_IKEV2_DYNAMIC) \ + || defined(EAP_SERVER_IKEV2) +union wolfssl_cipher +{ + Aes aes; + Des3 des3; + Arc4 arc4; +}; + +struct crypto_cipher { + enum crypto_cipher_alg alg; + union wolfssl_cipher enc; + union wolfssl_cipher dec; +}; + +struct crypto_cipher* crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len) +{ + struct crypto_cipher *ctx; + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + switch (alg) { +#ifndef CONFIG_NO_RC4 +#ifndef NO_RC4 + case CRYPTO_CIPHER_ALG_RC4: + wc_Arc4SetKey(&ctx->enc.arc4, key, key_len); + wc_Arc4SetKey(&ctx->dec.arc4, key, key_len); + break; +#endif /* NO_RC4 */ +#endif /* CONFIG_NO_RC4 */ +#ifndef NO_AES + case CRYPTO_CIPHER_ALG_AES: + switch (key_len) { + case 16: + case 24: + case 32: + break; + default: + os_free(ctx); + return NULL; + } + if (wc_AesSetKey(&ctx->enc.aes, key, key_len, iv, AES_ENCRYPTION) || + wc_AesSetKey(&ctx->dec.aes, key, key_len, iv, AES_DECRYPTION)) { + os_free(ctx); + return NULL; + } + break; +#endif /* NO_AES */ +#ifndef NO_DES3 + case CRYPTO_CIPHER_ALG_3DES: + if (key_len != DES3_KEYLEN || + wc_Des3_SetKey(&ctx->enc.des3, key, iv, DES_ENCRYPTION) || + wc_Des3_SetKey(&ctx->dec.des3, key, iv, DES_DECRYPTION)) { + os_free(ctx); + return NULL; + } + break; +#endif /* NO_DES3 */ + case CRYPTO_CIPHER_ALG_RC2: + case CRYPTO_CIPHER_ALG_DES: + default: + os_free(ctx); + return NULL; + } + + ctx->alg = alg; + + return ctx; +} + +int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, + u8 *crypt, size_t len) +{ + switch (ctx->alg) { +#ifndef CONFIG_NO_RC4 +#ifndef NO_RC4 + case CRYPTO_CIPHER_ALG_RC4: + wc_Arc4Process(&ctx->enc.arc4, crypt, plain, len); + return 0; +#endif /* NO_RC4 */ +#endif /* CONFIG_NO_RC4 */ +#ifndef NO_AES + case CRYPTO_CIPHER_ALG_AES: + if (wc_AesCbcEncrypt(&ctx->enc.aes, crypt, plain, len) != 0) + return -1; + return 0; +#endif /* NO_AES */ +#ifndef NO_DES3 + case CRYPTO_CIPHER_ALG_3DES: + if (wc_Des3_CbcEncrypt(&ctx->enc.des3, crypt, plain, len) != 0) + return -1; + return 0; +#endif /* NO_DES3 */ + default: + return -1; + } + return -1; +} + + +int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, + u8 *plain, size_t len) +{ + switch (ctx->alg) { +#ifndef CONFIG_NO_RC4 +#ifndef NO_RC4 + case CRYPTO_CIPHER_ALG_RC4: + wc_Arc4Process(&ctx->dec.arc4, plain, crypt, len); + return 0; +#endif /* NO_RC4 */ +#endif /* CONFIG_NO_RC4 */ +#ifndef NO_AES + case CRYPTO_CIPHER_ALG_AES: + if (wc_AesCbcDecrypt(&ctx->dec.aes, plain, crypt, len) != 0) + return -1; + return 0; +#endif /* NO_AES */ +#ifndef NO_DES3 + case CRYPTO_CIPHER_ALG_3DES: + if (wc_Des3_CbcDecrypt(&ctx->dec.des3, plain, crypt, len) != 0) + return -1; + return 0; +#endif /* NO_DES3 */ + default: + return -1; + } + return -1; +} + + +void crypto_cipher_deinit(struct crypto_cipher *ctx) +{ + if (ctx != NULL) + os_free(ctx); +} +#endif + +#ifdef CONFIG_WPS_NFC +static const unsigned char RFC3526_PRIME_1536[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, + 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, + 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, + 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, + 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, + 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, + 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, + 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, + 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, + 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, + 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, + 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, + 0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +}; +static const unsigned char RFC3526_GENERATOR_1536[] = { + 0x02 +}; + +#define RFC3526_LEN sizeof(RFC3526_PRIME_1536) + +void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) +{ + WC_RNG rng; + DhKey* ret = NULL; + DhKey* dh = NULL; + struct wpabuf* privkey = NULL; + struct wpabuf* pubkey = NULL; + word32 privSz, pubSz; + + *priv = NULL; + wpabuf_free(*publ); + *publ = NULL; + + dh = os_malloc(sizeof(DhKey)); + if (dh == NULL) + return NULL; + wc_InitDhKey(dh); + + if (wc_InitRng(&rng) != 0) { + os_free(dh); + return NULL; + } + + privkey = wpabuf_alloc(RFC3526_LEN); + pubkey = wpabuf_alloc(RFC3526_LEN); + if (privkey == NULL || pubkey == NULL) + goto done; + + if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), + RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536)) + != 0) + goto done; + + if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &privSz, + wpabuf_mhead(pubkey), &pubSz) != 0) + goto done; + + wpabuf_put(privkey, privSz); + wpabuf_put(pubkey, pubSz); + + ret = dh; + *priv = privkey; + *publ = pubkey; + dh = NULL; + privkey = NULL; + pubkey = NULL; +done: + wpabuf_clear_free(pubkey); + wpabuf_clear_free(privkey); + if (dh != NULL) { + wc_FreeDhKey(dh); + os_free(dh); + } + wc_FreeRng(&rng); + return ret; +} + +void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) +{ + DhKey* ret = NULL; + DhKey* dh; + byte* secret; + word32 secretSz; + + dh = os_malloc(sizeof(DhKey)); + if (dh == NULL) + return NULL; + wc_InitDhKey(dh); + + secret = os_malloc(RFC3526_LEN); + if (secret == NULL) + goto done; + + if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), + RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536)) + != 0) + goto done; + + if (wc_DhAgree(dh, secret, &secretSz, wpabuf_head(priv), wpabuf_len(priv), + RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536)) != 0) + goto done; + + if (secretSz != wpabuf_len(publ) || + os_memcmp(secret, wpabuf_head(publ), secretSz) != 0) + goto done; + + ret = dh; + dh = NULL; +done: + if (dh != NULL) { + wc_FreeDhKey(dh); + os_free(dh); + } + if (secret != NULL) + os_free(secret); + return ret; +} + +struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, + const struct wpabuf *own_private) +{ + struct wpabuf* ret = NULL; + struct wpabuf* secret; + word32 secretSz; + + secret = wpabuf_alloc(RFC3526_LEN); + if (secret == NULL) + goto done; + + if (wc_DhAgree(ctx, wpabuf_mhead(secret), &secretSz, + wpabuf_head(own_private), wpabuf_len(own_private), + wpabuf_head(peer_public), wpabuf_len(peer_public)) != 0) + goto done; + + wpabuf_put(secret, secretSz); + + ret = secret; + secret = NULL; +done: + wpabuf_clear_free(secret); + return ret; +} + +void dh5_free(void *ctx) +{ + if (ctx == NULL) + return; + + wc_FreeDhKey(ctx); + os_free(ctx); +} +#endif + +int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey, + u8 *pubkey) +{ + int ret = -1; + WC_RNG rng; + DhKey* dh = NULL; + word32 privSz, pubSz; + + if (TEST_FAIL()) + return -1; + + dh = os_malloc(sizeof(DhKey)); + if (dh == NULL) + return -1; + wc_InitDhKey(dh); + + if (wc_InitRng(&rng) != 0) { + os_free(dh); + return -1; + } + + if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0) + goto done; + + if (wc_DhGenerateKeyPair(dh, &rng, privkey, &privSz, pubkey, &pubSz) != 0) + goto done; + + if (privSz < prime_len) { + size_t padSz = prime_len - privSz; + os_memmove(privkey + padSz, privkey, privSz); + os_memset(privkey, 0, padSz); + } + + if (pubSz < prime_len) { + size_t padSz = prime_len - pubSz; + os_memmove(pubkey + padSz, pubkey, pubSz); + os_memset(pubkey, 0, padSz); + } + ret = 0; +done: + wc_FreeDhKey(dh); + os_free(dh); + wc_FreeRng(&rng); + return ret; +} + +int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len, + const u8 *privkey, size_t privkey_len, + const u8 *pubkey, size_t pubkey_len, + u8 *secret, size_t *len) +{ + int ret = -1; + DhKey* dh; + word32 secretSz; + + dh = os_malloc(sizeof(DhKey)); + if (dh == NULL) + return -1; + wc_InitDhKey(dh); + + if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0) + goto done; + + if (wc_DhAgree(dh, secret, &secretSz, privkey, privkey_len, pubkey, + pubkey_len) != 0) + goto done; + + *len = secretSz; + ret = 0; +done: + wc_FreeDhKey(dh); + os_free(dh); + return ret; +} + +#ifdef CONFIG_FIPS +int crypto_get_random(void *buf, size_t len) +{ + int ret = 0; + WC_RNG rng; + + if (wc_InitRng(&rng) != 0) + return -1; + if (wc_RNG_GenerateBlock(&rng, buf, len) != 0) + ret = -1; + wc_FreeRng(&rng); + return ret; +} +#endif + +#if defined(EAP_PWD) || defined(EAP_SERVER_PWD) +struct crypto_hash { + Hmac hmac; + int size; +}; + +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, + size_t key_len) +{ + struct crypto_hash* ret = NULL; + struct crypto_hash* hash; + int type; + + hash = os_malloc(sizeof(*hash)); + if (hash == NULL) + goto done; + + switch (alg) { +#ifndef NO_MD5 + case CRYPTO_HASH_ALG_HMAC_MD5: + hash->size = 16; + type = MD5; + break; +#endif +#ifndef NO_SHA + case CRYPTO_HASH_ALG_HMAC_SHA1: + type = SHA; + hash->size = 20; + break; +#endif +#ifdef CONFIG_SHA256 +#ifndef NO_SHA256 + case CRYPTO_HASH_ALG_HMAC_SHA256: + type = SHA256; + hash->size = 32; + break; +#endif +#endif + default: + goto done; + } + + if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0) + goto done; + + ret = hash; + hash = NULL; +done: + if (hash != NULL) + os_free(hash); + return ret; +} +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) +{ + if (ctx == NULL) + return; + wc_HmacUpdate(&ctx->hmac, data, len); +} + +int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) +{ + int ret = 0; + + if (ctx == NULL) + return -2; + + if (mac == NULL || len == NULL) + goto done; + + if (wc_HmacFinal(&ctx->hmac, mac) != 0) { + ret = -1; + goto done; + } + + *len = ctx->size; + ret = 0; +done: + if (ctx != NULL) + bin_clear_free(ctx, sizeof(*ctx)); + return ret; +} +#endif + +#ifdef CONFIG_WOLFSSL_CMAC +int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + Cmac cmac; + int i; + word32 sz; + + if (TEST_FAIL()) + return -1; + + if (wc_InitCmac(&cmac, key, key_len, WC_CMAC_AES, NULL) != 0) + return -1; + + for (i = 0; i < num_elem; i++) + if (wc_CmacUpdate(&cmac, addr[i], len[i]) != 0) + return -1; + + sz = AES_BLOCK_SIZE; + if (wc_CmacFinal(&cmac, mac, &sz) != 0 || sz != AES_BLOCK_SIZE) + return -1; + + return 0; +} + + +int omac1_aes_128_vector(const u8 *key, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return omac1_aes_vector(key, 16, num_elem, addr, len, mac); +} + + +int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) +{ + return omac1_aes_128_vector(key, 1, &data, &data_len, mac); +} + + +int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac) +{ + return omac1_aes_vector(key, 32, 1, &data, &data_len, mac); +} +#endif + + +struct crypto_bignum* crypto_bignum_init(void) +{ + mp_int* a; + + if (TEST_FAIL()) + return NULL; + + a = os_malloc(sizeof(*a)); + if (mp_init(a) != MP_OKAY) { + os_free(a); + a = NULL; + } + + return (struct crypto_bignum*)a; +} + + +struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len) +{ + mp_int* a; + + if (TEST_FAIL()) + return NULL; + + a = (mp_int*)crypto_bignum_init(); + if (a == NULL) + return NULL; + + if (mp_read_unsigned_bin(a, buf, len) != MP_OKAY) { + os_free(a); + a = NULL; + } + + return (struct crypto_bignum*)a; +} + + +void crypto_bignum_deinit(struct crypto_bignum *n, int clear) +{ + if (n == NULL) + return; + + if (clear) + mp_forcezero((mp_int*)n); + mp_clear((mp_int*)n); + os_free((mp_int*)n); +} + + +int crypto_bignum_to_bin(const struct crypto_bignum *a, + u8 *buf, size_t buflen, size_t padlen) +{ + int num_bytes, offset; + + if (TEST_FAIL()) + return -1; + + if (padlen > buflen) + return -1; + + num_bytes = (mp_count_bits((mp_int*)a) + 7) / 8; + if ((size_t)num_bytes > buflen) + return -1; + if (padlen > (size_t)num_bytes) + offset = padlen - num_bytes; + else + offset = 0; + + os_memset(buf, 0, offset); + mp_to_unsigned_bin((mp_int*)a, buf + offset); + + return num_bytes + offset; +} + +int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m) +{ + int ret = 0; + WC_RNG rng; + + if (wc_InitRng(&rng) != 0) + return -1; + if (mp_rand_prime((mp_int*)r, (mp_count_bits((mp_int*)m) + 7) / 8 * 2, &rng, + NULL) != 0) { + ret = -1; + } + if (ret == 0 && mp_mod((mp_int*)r, (mp_int*)m, (mp_int*)r) != 0) + ret = -1; + wc_FreeRng(&rng); + return ret; +} + +int crypto_bignum_add(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *r) +{ + return mp_add((mp_int*)a, (mp_int*)b, (mp_int*)r) == MP_OKAY ? 0 : -1; +} + + +int crypto_bignum_mod(const struct crypto_bignum *a, + const struct crypto_bignum *m, + struct crypto_bignum *r) +{ + return mp_mod((mp_int*)a, (mp_int*)m, (mp_int*)r) == MP_OKAY ? 0 : -1; +} + + +int crypto_bignum_exptmod(const struct crypto_bignum *b, + const struct crypto_bignum *e, + const struct crypto_bignum *m, + struct crypto_bignum *r) +{ + int res; + + if (TEST_FAIL()) + return -1; + + res = mp_exptmod((mp_int*)b, (mp_int*)e, (mp_int*)m, (mp_int*)r); + return res == MP_OKAY ? 0 : -1; +} + + +int crypto_bignum_inverse(const struct crypto_bignum *a, + const struct crypto_bignum *m, + struct crypto_bignum *r) +{ + if (TEST_FAIL()) + return -1; + return mp_invmod((mp_int*)a, (mp_int*)m, (mp_int*)r) == MP_OKAY ? 0 : -1; +} + + +int crypto_bignum_sub(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *r) +{ + if (TEST_FAIL()) + return -1; + return mp_add((mp_int*)a, (mp_int*)b, (mp_int*)r) == MP_OKAY ? 0 : -1; +} + + +int crypto_bignum_div(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *d) +{ + if (TEST_FAIL()) + return -1; + return mp_div((mp_int*)a, (mp_int*)b, (mp_int*)d, NULL) == MP_OKAY ? 0 : -1; +} + + +int crypto_bignum_mulmod(const struct crypto_bignum *a, + const struct crypto_bignum *b, + const struct crypto_bignum *m, + struct crypto_bignum *d) +{ + int res; + + if (TEST_FAIL()) + return -1; + + res = mp_mulmod((mp_int*)a, (mp_int*)b, (mp_int*)m, (mp_int*)d); + return res == MP_OKAY ? 0 : -1; +} + +int crypto_bignum_rshift(const struct crypto_bignum *a, int n, + struct crypto_bignum *r) +{ + if (mp_copy((mp_int*)a, (mp_int*)r) != MP_OKAY) + return -1; + mp_rshd((mp_int*)r, n); + return 0; +} + +int crypto_bignum_cmp(const struct crypto_bignum *a, + const struct crypto_bignum *b) +{ + return mp_cmp((mp_int*)a, (mp_int*)b); +} + + +int crypto_bignum_bits(const struct crypto_bignum *a) +{ + return mp_count_bits((mp_int*)a); +} + + +int crypto_bignum_is_zero(const struct crypto_bignum *a) +{ + return mp_iszero((mp_int*)a); +} + + +int crypto_bignum_is_one(const struct crypto_bignum *a) +{ + return mp_isone((mp_int*)a); +} + +int crypto_bignum_is_odd(const struct crypto_bignum *a) +{ + return mp_isodd((mp_int*)a); +} + + +int crypto_bignum_legendre(const struct crypto_bignum *a, + const struct crypto_bignum *p) +{ + mp_int t; + int ret; + int res = -2; + + if (TEST_FAIL()) + return -2; + + if (mp_init(&t) != MP_OKAY) { + return -2; + } + + /* t = (p-1) / 2 */ + ret = mp_sub_d((mp_int*)p, 1, &t); + if (ret == MP_OKAY) + mp_rshb(&t, 1); + if (ret == MP_OKAY) + ret = mp_exptmod((mp_int*)a, &t, (mp_int*)p, &t); + if (ret == MP_OKAY) { + if (mp_isone(&t)) + res = 1; + else if (mp_iszero(&t)) + res = 0; + else + res = -1; + } + + mp_clear(&t); + return res; +} + + +#ifdef CONFIG_ECC +extern int ecc_map(ecc_point*, mp_int*, mp_digit); +extern int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, + mp_int* a, mp_int* modulus, mp_digit mp); + +struct crypto_ec { + ecc_key key; + mp_int a; + mp_int prime; + mp_int order; + mp_digit montB; + mp_int b; +}; + +struct crypto_ec * crypto_ec_init(int group) +{ + int built = 0; + struct crypto_ec *e; + int curve_id; + + /* Map from IANA registry for IKE D-H groups to OpenSSL NID */ + switch (group) { + case 19: + curve_id = ECC_SECP256R1; + break; + case 20: + curve_id = ECC_SECP384R1; + break; + case 21: + curve_id = ECC_SECP521R1; + break; + case 25: + curve_id = ECC_SECP192R1; + break; + case 26: + curve_id = ECC_SECP224R1; + break; +#ifdef HAVE_ECC_BRAINPOOL + case 27: + curve_id = ECC_BRAINPOOLP224R1; + break; + case 28: + curve_id = ECC_BRAINPOOLP256R1; + break; + case 29: + curve_id = ECC_BRAINPOOLP384R1; + break; + case 30: + curve_id = ECC_BRAINPOOLP512R1; + break; +#endif /* HAVE_ECC_BRAINPOOL */ + default: + return NULL; + } + + e = os_zalloc(sizeof(*e)); + if (e == NULL) + return NULL; + + if (wc_ecc_init(&e->key) != 0) + goto done; + if (wc_ecc_set_curve(&e->key, 0, curve_id) != 0) + goto done; + + if (mp_init(&e->a) != MP_OKAY) + goto done; + if (mp_init(&e->prime) != MP_OKAY) + goto done; + if (mp_init(&e->order) != MP_OKAY) + goto done; + if (mp_init(&e->b) != MP_OKAY) + goto done; + + if (mp_read_radix(&e->a, e->key.dp->Af, 16) != MP_OKAY) + goto done; + if (mp_read_radix(&e->b, e->key.dp->Bf, 16) != MP_OKAY) + goto done; + if (mp_read_radix(&e->prime, e->key.dp->prime, 16) != MP_OKAY) + goto done; + if (mp_read_radix(&e->order, e->key.dp->order, 16) != MP_OKAY) + goto done; + + if (mp_montgomery_setup(&e->prime, &e->montB) != MP_OKAY) + goto done; + + built = 1; +done: + if (!built) { + crypto_ec_deinit(e); + e = NULL; + } + return e; +} + + +void crypto_ec_deinit(struct crypto_ec* e) +{ + if (e == NULL) + return; + + mp_clear(&e->b); + mp_clear(&e->order); + mp_clear(&e->prime); + mp_clear(&e->a); + wc_ecc_free(&e->key); + os_free(e); +} + +int crypto_ec_cofactor(struct crypto_ec* e, struct crypto_bignum* cofactor) +{ + if (e == NULL || cofactor == NULL) + return -1; + + mp_set((mp_int*)cofactor, e->key.dp->cofactor); + return 0; +} + +struct crypto_ec_point* crypto_ec_point_init(struct crypto_ec* e) +{ + if (TEST_FAIL()) + return NULL; + if (e == NULL) + return NULL; + return (struct crypto_ec_point*)wc_ecc_new_point(); +} + + +size_t crypto_ec_prime_len(struct crypto_ec *e) +{ + return (mp_count_bits(&e->prime) + 7) / 8; +} + + +size_t crypto_ec_prime_len_bits(struct crypto_ec *e) +{ + return mp_count_bits(&e->prime); +} + + +size_t crypto_ec_order_len(struct crypto_ec *e) +{ + return (mp_count_bits(&e->order) + 7) / 8; +} + + +const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e) +{ + return (const struct crypto_bignum *)&e->prime; +} + + +const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e) +{ + return (const struct crypto_bignum *)&e->order; +} + + +void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear) +{ + ecc_point* point = (ecc_point*)p; + + if (p == NULL) + return; + + if (clear) { + mp_forcezero(point->x); + mp_forcezero(point->y); + mp_forcezero(point->z); + } + wc_ecc_del_point(point); +} + +int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p, + struct crypto_bignum *x) +{ + return mp_copy(((ecc_point*)p)->x, (mp_int*)x) == MP_OKAY ? 0 : -1; +} + +int crypto_ec_point_to_bin(struct crypto_ec *e, + const struct crypto_ec_point *point, u8 *x, u8 *y) +{ + ecc_point* p = (ecc_point*)point; + + if (TEST_FAIL()) + return -1; + + if (!mp_isone(p->z)) { + if (ecc_map(p, &e->prime, e->montB) != MP_OKAY) + return -1; + } + + if (x != NULL) { + if (crypto_bignum_to_bin((struct crypto_bignum *)p->x, x, + e->key.dp->size, e->key.dp->size) <= 0) { + return -1; + } + } + if (y != NULL) { + if (crypto_bignum_to_bin((struct crypto_bignum *)p->y, y, + e->key.dp->size, e->key.dp->size) <= 0) { + return -1; + } + } + + return 0; +} + + +struct crypto_ec_point* crypto_ec_point_from_bin(struct crypto_ec *e, + const u8 *val) +{ + ecc_point* point = NULL; + int loaded = 0; + + if (TEST_FAIL()) + return NULL; + + point = wc_ecc_new_point(); + if (point == NULL) + goto done; + + if (mp_read_unsigned_bin(point->x, val, e->key.dp->size) != MP_OKAY) + goto done; + val += e->key.dp->size; + if (mp_read_unsigned_bin(point->y, val, e->key.dp->size) != MP_OKAY) + goto done; + mp_set(point->z, 1); + + loaded = 1; +done: + if (!loaded) { + wc_ecc_del_point(point); + point = NULL; + } + return (struct crypto_ec_point*)point; +} + + +int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a, + const struct crypto_ec_point *b, + struct crypto_ec_point *c) +{ + mp_int mu; + ecc_point *ta = NULL, *tb = NULL; + ecc_point *pa = (ecc_point*)a, *pb = (ecc_point*)b; + mp_int *modulus = &e->prime; + int ret; + + if (TEST_FAIL()) + return -1; + + if ((ret = mp_init(&mu)) != MP_OKAY) { + return -1; + } + if ((ret = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) { + mp_clear(&mu); + return -1; + } + + if (!mp_isone(&mu)) { + ta = wc_ecc_new_point(); + if (ta == NULL) { + mp_clear(&mu); + return -1; + } + tb = wc_ecc_new_point(); + if (tb == NULL) { + wc_ecc_del_point(ta); + mp_clear(&mu); + return -1; + } + + if (mp_mulmod(pa->x, &mu, modulus, ta->x) != MP_OKAY) { + ret = -1; + goto end; + } + if (mp_mulmod(pa->y, &mu, modulus, ta->y) != MP_OKAY) { + ret = -1; + goto end; + } + if (mp_mulmod(pa->z, &mu, modulus, ta->z) != MP_OKAY) { + ret = -1; + goto end; + } + if (mp_mulmod(pb->x, &mu, modulus, tb->x) != MP_OKAY) { + ret = -1; + goto end; + } + if (mp_mulmod(pb->y, &mu, modulus, tb->y) != MP_OKAY) { + ret = -1; + goto end; + } + if (mp_mulmod(pb->z, &mu, modulus, tb->z) != MP_OKAY) { + ret = -1; + goto end; + } + pa = ta; + pb = tb; + } + + ret = ecc_projective_add_point(pa, pb, (ecc_point*)c, &e->a, &e->prime, + e->montB); + if (ret != 0) { + ret = -1; + goto end; + } + + if (ecc_map((ecc_point*)c, &e->prime, e->montB) != MP_OKAY) + ret = -1; + else + ret = 0; +end: + wc_ecc_del_point(tb); + wc_ecc_del_point(ta); + mp_clear(&mu); + return ret; +} + + +int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p, + const struct crypto_bignum *b, + struct crypto_ec_point *res) +{ + int ret; + + if (TEST_FAIL()) + return -1; + + ret = wc_ecc_mulmod((mp_int*)b, (ecc_point*)p, (ecc_point*)res, &e->a, + &e->prime, 1); + return ret == 0 ? 0 : -1; +} + + +int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p) +{ + ecc_point* point = (ecc_point*)p; + + if (TEST_FAIL()) + return -1; + + if (mp_sub(&e->prime, point->y, point->y) != MP_OKAY) + return -1; + + return 0; +} + + +int crypto_ec_point_solve_y_coord(struct crypto_ec *e, + struct crypto_ec_point *p, + const struct crypto_bignum *x, int y_bit) +{ + byte buf[MAX_ECC_BYTES + 1]; + int ret; + int prime_len = crypto_ec_prime_len(e); + + if (TEST_FAIL()) + return -1; + + buf[0] = 0x2 + (byte)y_bit; + ret = crypto_bignum_to_bin(x, buf + 1, prime_len, prime_len); + if (ret <= 0) { + return -1; + } + ret = wc_ecc_import_point_der(buf, ret + 1, e->key.idx, (ecc_point*)p); + if (ret != 0) + return -1; + + return 0; +} + + +struct crypto_bignum * +crypto_ec_point_compute_y_sqr(struct crypto_ec *e, + const struct crypto_bignum *x) +{ + mp_int* y2 = NULL; + mp_int t; + int calced = 0; + + if (TEST_FAIL()) + return NULL; + + if (mp_init(&t) != MP_OKAY) + return NULL; + + y2 = (mp_int*)crypto_bignum_init(); + if (y2 == NULL) + goto done; + + if (mp_sqrmod((mp_int*)x, &e->prime, y2) != 0) + goto done; + if (mp_mulmod((mp_int*)x, &t, &e->prime, y2) != 0) + goto done; + if (mp_mulmod((mp_int*)x, &e->a, &e->prime, &t) != 0) + goto done; + if (mp_addmod(y2, &t, &e->prime, y2) != 0) + goto done; + if (mp_addmod(y2, &e->b, &e->prime, y2) != 0) + goto done; + + calced = 1; +done: + if (!calced) { + if (y2 != NULL) { + mp_clear(y2); + os_free(y2); + } + mp_clear(&t); + } + + return (struct crypto_bignum*)y2; +} + + +int crypto_ec_point_is_at_infinity(struct crypto_ec *e, + const struct crypto_ec_point *p) +{ + return wc_ecc_point_is_at_infinity((ecc_point*)p); +} + + +int crypto_ec_point_is_on_curve(struct crypto_ec *e, + const struct crypto_ec_point *p) +{ + return wc_ecc_is_point((ecc_point*)p, &e->a, &e->b, &e->prime) == MP_OKAY; +} + + +int crypto_ec_point_cmp(const struct crypto_ec *e, + const struct crypto_ec_point *a, + const struct crypto_ec_point *b) +{ + return wc_ecc_cmp_point((ecc_point*)a, (ecc_point*)b); +} + +#endif /* CONFIG_ECC */ diff --git a/src/crypto/fips_prf_wolfssl.c b/src/crypto/fips_prf_wolfssl.c new file mode 100644 index 0000000..becacec --- /dev/null +++ b/src/crypto/fips_prf_wolfssl.c @@ -0,0 +1,85 @@ +/* + * FIPS 186-2 PRF for libcrypto + * Copyright (c) 2004-2017, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" +#include + +#include "common.h" +#include "crypto.h" + + +static void sha1_transform(u32 *state, const u8 data[64]) +{ + Sha sha; + os_memset(&sha, 0, sizeof(sha)); + sha.digest[0] = state[0]; + sha.digest[1] = state[1]; + sha.digest[2] = state[2]; + sha.digest[3] = state[3]; + sha.digest[4] = state[4]; + wc_ShaUpdate(&sha, data, 64); + state[0] = sha.digest[0]; + state[1] = sha.digest[1]; + state[2] = sha.digest[2]; + state[3] = sha.digest[3]; + state[4] = sha.digest[4]; +} + + +int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) +{ + u8 xkey[64]; + u32 t[5], _t[5]; + int i, j, m, k; + u8 *xpos = x; + u32 carry; + + if (seed_len < sizeof(xkey)) + os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len); + else + seed_len = sizeof(xkey); + + /* FIPS 186-2 + change notice 1 */ + + os_memcpy(xkey, seed, seed_len); + t[0] = 0x67452301; + t[1] = 0xEFCDAB89; + t[2] = 0x98BADCFE; + t[3] = 0x10325476; + t[4] = 0xC3D2E1F0; + + m = xlen / 40; + for (j = 0; j < m; j++) { + /* XSEED_j = 0 */ + for (i = 0; i < 2; i++) { + /* XVAL = (XKEY + XSEED_j) mod 2^b */ + + /* w_i = G(t, XVAL) */ + os_memcpy(_t, t, 20); + sha1_transform(_t, xkey); + WPA_PUT_BE32(xpos, _t[0]); + WPA_PUT_BE32(xpos + 4, _t[1]); + WPA_PUT_BE32(xpos + 8, _t[2]); + WPA_PUT_BE32(xpos + 12, _t[3]); + WPA_PUT_BE32(xpos + 16, _t[4]); + + /* XKEY = (1 + XKEY + w_i) mod 2^b */ + carry = 1; + for (k = 19; k >= 0; k--) { + carry += xkey[k] + xpos[k]; + xkey[k] = carry & 0xff; + carry >>= 8; + } + + xpos += 20; + } + /* x_j = w_0|w_1 */ + } + + return 0; +} diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c new file mode 100644 index 0000000..ecd5db2 --- /dev/null +++ b/src/crypto/tls_wolfssl.c @@ -0,0 +1,2057 @@ +/* + * SSL/TLS interface functions for wolfSSL TLS case + * Copyright (c) 2004-2017, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto.h" +#include "tls.h" + +#define OPENSSL_EXTRA +#define HAVE_STUNNEL +#define HAVE_SECRET_CALLBACK +#define HAVE_SESSION_TICKET +#define HAVE_OCSP +#define HAVE_CERTIFICATE_STATUS_REQUEST +#define HAVE_CERTIFICATE_STATUS_REQUEST_V2 +#ifndef WOLFSSL_DER_LOAD +#define WOLFSSL_DER_LOAD +#endif +#if 0 +/* Enable if a debug build of wolfSSL is installed. */ +#define DEBUG_WOLFSSL +#endif + +/* wolfSSL includes */ +#include +#include +#include + +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) +#define HAVE_AESGCM +#include +#endif + +#if !defined(CONFIG_FIPS) && \ + (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \ + defined(EAP_SERVER_FAST)) +#define WOLFSSL_NEED_EAP_FAST_PRF +#endif + +#define SECRET_LEN 48 +#define RAN_LEN 32 +#define SESSION_TICKET_LEN 256 + +static int tlsRefCount = 0; + +static int tls_ex_idx_session = 0; + + +/* tls input data for wolfSSL Read Callback */ +struct tls_in_data { + const struct wpabuf* in_data; + size_t consumed; /* how many bytes have we used already */ +}; + + +/* tls output data for wolfSSL Write Callback */ +struct tls_out_data { + struct wpabuf* out_data; +}; + +struct tls_context { + void (*event_cb)(void *ctx, enum tls_event ev, + union tls_event_data *data); + void *cb_ctx; + int cert_in_cb; + char *ocsp_stapling_response; +}; + +static struct tls_context *tls_global = NULL; + +/* wolfssl tls_connection */ +struct tls_connection { + struct tls_context* context; + WOLFSSL* ssl; + int readAlerts; + int writeAlerts; + int failed; + struct tls_in_data input; + struct tls_out_data output; + char* subjectMatch; + char* altSubjectMatch; + char* suffixMatch; + char* domainMatch; + + u8 srv_cert_hash[32]; + + unsigned char client_random[RAN_LEN]; + unsigned char server_random[RAN_LEN]; + unsigned int flags; +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) + tls_session_ticket_cb session_ticket_cb; + void* session_ticket_cb_ctx; + byte session_ticket[SESSION_TICKET_LEN]; +#endif + unsigned int ca_cert_verify:1; + unsigned int cert_probe:1; + unsigned int server_cert_only:1; + unsigned int success_data:1; + + WOLFSSL_X509* peer_cert; + WOLFSSL_X509* peer_issuer; + WOLFSSL_X509* peer_issuer_issuer; + +}; + + +static struct tls_context * tls_context_new(const struct tls_config *conf) +{ + struct tls_context *context = os_zalloc(sizeof(*context)); + if (context == NULL) + return NULL; + if (conf) { + context->event_cb = conf->event_cb; + context->cb_ctx = conf->cb_ctx; + context->cert_in_cb = conf->cert_in_cb; + } + return context; +} + + +static void ResetInData(struct tls_in_data* in, const struct wpabuf* buf) +{ + /* old one not owned by us so don't free */ + in->in_data = buf; + in->consumed = 0; +} + + +static void ResetOutData(struct tls_out_data* out) +{ + /* old one not owned by us so don't free */ + out->out_data = wpabuf_alloc_copy("", 0); +} + + +/* wolfSSL I/O Receive CallBack */ +static int wolfsslReceiveCb(WOLFSSL *ssl, char* buf, int sz, void* ctx) +{ + size_t get = sz; + struct tls_in_data* data = (struct tls_in_data*)ctx; + + if (data == NULL) + return -1; + + if (get > (wpabuf_len(data->in_data) - data->consumed)) + get = wpabuf_len(data->in_data) - data->consumed; + + os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get); + data->consumed += get; + + if (get == 0) + return -2; /* WANT_READ */ + + return (int)get; +} + + +/* wolfSSL I/O Send CallBack */ +static int wolfsslSendCb(WOLFSSL *ssl, char* buf, int sz, void* ctx) +{ + struct wpabuf* tmp; + struct tls_out_data* data = (struct tls_out_data*)ctx; + + if (data == NULL) + return -1; + + wpa_printf(MSG_DEBUG, "SSL: adding %d bytes", sz); + + tmp = wpabuf_alloc_copy(buf, sz); + data->out_data = wpabuf_concat(data->out_data, tmp); + + if (data->out_data == NULL) + return -1; + + return sz; +} + +static void remove_session_cb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess) +{ + struct wpabuf *buf; + + buf = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session); + if (!buf) + return; + wpa_printf(MSG_DEBUG, + "wolfSSL: Free application session data %p (sess %p)", + buf, sess); + wpabuf_free(buf); + + wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL); +} + +void* tls_init(const struct tls_config *conf) +{ + WOLFSSL_CTX* sslCtx; + struct tls_context *context; + const char *ciphers; + +#ifdef DEBUG_WOLFSSL + wolfSSL_Debugging_ON(); +#endif + + context = tls_context_new(conf); + if (context == NULL) + return NULL; + + if (tlsRefCount == 0) { + tls_global = context; + + if (wolfSSL_Init() < 0) + return NULL; + /* wolfSSL_Debugging_ON(); */ + } + + tlsRefCount++; + + sslCtx = wolfSSL_CTX_new(wolfSSLv23_client_method()); /* start as client */ + if (sslCtx == NULL) { + tlsRefCount--; + if (context != tls_global) + os_free(context); + if (tlsRefCount == 0) { + os_free(tls_global); + tls_global = NULL; + } + } + wolfSSL_SetIORecv(sslCtx, wolfsslReceiveCb); + wolfSSL_SetIOSend(sslCtx, wolfsslSendCb); + wolfSSL_CTX_set_ex_data(sslCtx, 0, context); + + if (conf->tls_session_lifetime > 0) { + wolfSSL_CTX_set_quiet_shutdown(sslCtx, 1); + wolfSSL_CTX_set_session_cache_mode(sslCtx, SSL_SESS_CACHE_SERVER); + wolfSSL_CTX_set_timeout(sslCtx, conf->tls_session_lifetime); + wolfSSL_CTX_sess_set_remove_cb(sslCtx, remove_session_cb); + } else { + wolfSSL_CTX_set_session_cache_mode(sslCtx, SSL_SESS_CACHE_CLIENT); + } + + if (conf && conf->openssl_ciphers) + ciphers = conf->openssl_ciphers; + else + ciphers = "ALL"; + if (wolfSSL_CTX_set_cipher_list(sslCtx, ciphers) != 1) { + wpa_printf(MSG_ERROR, + "wolfSSL: Failed to set cipher string '%s'", + ciphers); + tls_deinit(sslCtx); + return NULL; + } + + return sslCtx; +} + + +void tls_deinit(void *ssl_ctx) +{ + struct tls_context *context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0); + + if (context != tls_global) + os_free(context); + + wolfSSL_CTX_free((WOLFSSL_CTX*)ssl_ctx); + + tlsRefCount--; + if (tlsRefCount == 0) { + wolfSSL_Cleanup(); + os_free(tls_global); + tls_global = NULL; + } +} + + +int tls_get_errors(void *tls_ctx) +{ +#ifdef DEBUG_WOLFSSL +#if 0 + unsigned long err; + err = wolfSSL_ERR_peek_last_error_line(NULL, NULL); + if (err != 0) { + wpa_printf(MSG_INFO, "TLS - SSL error: %s", + wolfSSL_ERR_error_string(err, NULL)); + return 1; + } +#endif +#endif + return 0; +} + + +struct tls_connection* tls_connection_init(void *tls_ctx) +{ + WOLFSSL_CTX* sslCtx = (WOLFSSL_CTX*)tls_ctx; + struct tls_connection* conn; + + wpa_printf(MSG_DEBUG, "SSL: connection init"); + + conn = os_zalloc(sizeof(*conn)); + if (conn == NULL) + return NULL; + conn->ssl = wolfSSL_new(sslCtx); + if (conn->ssl == NULL) { + os_free(conn); + return NULL; + } + + wolfSSL_SetIOReadCtx(conn->ssl, &conn->input); + wolfSSL_SetIOWriteCtx(conn->ssl, &conn->output); + wolfSSL_set_ex_data(conn->ssl, 0, conn); + conn->context = wolfSSL_CTX_get_ex_data(sslCtx, 0); + + /* Need randoms post-hanshake for EAP-FAST, export key and deriving session + * ID in EAP method in EAP methodss. + */ + wolfSSL_KeepArrays(conn->ssl); + wolfSSL_KeepHandshakeResources(conn->ssl); + wolfSSL_UseClientSuites(conn->ssl); + + return conn; +} + + +void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return; + + wpa_printf(MSG_DEBUG, "SSL: connection deinit"); + + /* parts */ + wolfSSL_free(conn->ssl); + os_free(conn->subjectMatch); + os_free(conn->altSubjectMatch); + os_free(conn->suffixMatch); + os_free(conn->domainMatch); + + /* self */ + os_free(conn); +} + + +int tls_connection_established(void *tls_ctx, struct tls_connection *conn) +{ + return conn ? wolfSSL_is_init_finished(conn->ssl) : 0; +} + + +int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) +{ + WOLFSSL_SESSION* session; + + if (conn == NULL) + return -1; + + wpa_printf(MSG_DEBUG, "SSL: connection shutdown"); + + /* Set quiet as OpenSSL does */ + wolfSSL_set_quiet_shutdown(conn->ssl, 1); + wolfSSL_shutdown(conn->ssl); + + session = wolfSSL_get_session(conn->ssl); + if (wolfSSL_clear(conn->ssl) != 1) + return -1; + wolfSSL_set_session(conn->ssl, session); + + return 0; +} + + +static int tls_connection_set_subject_match(struct tls_connection *conn, + const char *subjectMatch, + const char *altSubjectMatch, + const char *suffixMatch, + const char *domainMatch) +{ + os_free(conn->subjectMatch); + conn->subjectMatch = NULL; + if (subjectMatch) { + conn->subjectMatch = os_strdup(subjectMatch); + if (conn->subjectMatch == NULL) + return -1; + } + + os_free(conn->altSubjectMatch); + conn->altSubjectMatch = NULL; + if (altSubjectMatch) { + conn->altSubjectMatch = os_strdup(altSubjectMatch); + if (conn->altSubjectMatch == NULL) + return -1; + } + + os_free(conn->suffixMatch); + conn->suffixMatch = NULL; + if (suffixMatch) { + conn->suffixMatch = os_strdup(suffixMatch); + if (conn->suffixMatch == NULL) + return -1; + } + + os_free(conn->domainMatch); + conn->domainMatch = NULL; + if (domainMatch) { + conn->domainMatch = os_strdup(domainMatch); + if (conn->domainMatch == NULL) + return -1; + } + + return 0; +} + + +static int tls_connection_dh(struct tls_connection* conn, const char* dh_file, + const u8* dh_blob, size_t blob_len) +{ + if (dh_file == NULL && dh_blob == NULL) + return 0; + + wolfSSL_set_accept_state(conn->ssl); + + if (dh_blob) { + if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len, + SSL_FILETYPE_ASN1) < 0) { + wpa_printf(MSG_INFO, "SSL: use dh der blob failed"); + return -1; + } + wpa_printf(MSG_DEBUG, "SSL: use dh blob OK"); + return 0; + } + + if (dh_file) { + wpa_printf(MSG_INFO, "SSL: use dh pem file: %s", dh_file); + if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file, SSL_FILETYPE_PEM) < 0) { + wpa_printf(MSG_INFO, "SSL: use dh pem file failed"); + if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file, + SSL_FILETYPE_ASN1) < 0) { + wpa_printf(MSG_INFO, "SSL: use dh der file failed"); + return -1; + } + } + wpa_printf(MSG_DEBUG, "SSL: use dh file OK"); + return 0; + } + + return 0; +} + + +static int tls_connection_client_cert(struct tls_connection* conn, + const char* client_cert, + const u8* client_cert_blob, + size_t blob_len) +{ + if (client_cert == NULL && client_cert_blob == NULL) + return 0; + + if (client_cert_blob) { + if (wolfSSL_use_certificate_buffer(conn->ssl, client_cert_blob, blob_len, + SSL_FILETYPE_ASN1) < 0) { + wpa_printf(MSG_INFO, "SSL: use client cert der blob failed"); + return -1; + } + wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK"); + return 0; + } + + if (client_cert) { + if (wolfSSL_use_certificate_file(conn->ssl, client_cert, + SSL_FILETYPE_PEM) < 0) { + wpa_printf(MSG_INFO, "SSL: use client cert pem file failed"); + if (wolfSSL_use_certificate_file(conn->ssl, client_cert, + SSL_FILETYPE_ASN1) < 0) { + wpa_printf(MSG_INFO, "SSL: use client cert der file failed"); + return -1; + } + } + wpa_printf(MSG_DEBUG, "SSL: use client cert file OK"); + return 0; + } + + return 0; +} + + +static int tls_passwd_cb(char *buf, int size, int rwflag, void *password) +{ + if (password == NULL) + return 0; + os_strlcpy(buf, (char *) password, size); + return os_strlen(buf); +} + + +static int tls_connection_private_key(void* tls_ctx, + struct tls_connection *conn, + const char* private_key, + const char* private_key_passwd, + const u8* private_key_blob, + size_t blob_len) +{ + WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)tls_ctx; + char* passwd = NULL; + int ok = 0; + + if (private_key == NULL && private_key_blob == NULL) + return 0; + + if (private_key_passwd) { + passwd = os_strdup(private_key_passwd); + if (passwd == NULL) + return -1; + } + + wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb); + wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd); + + if (private_key_blob) { + if (wolfSSL_use_PrivateKey_buffer(conn->ssl, private_key_blob, blob_len, + SSL_FILETYPE_ASN1) < 0) { + wpa_printf(MSG_INFO, "SSL: use private der blob failed"); + } + else { + wpa_printf(MSG_DEBUG, "SSL: use private key blob OK"); + ok = 1; + } + } + + if (!ok && private_key) { + if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key, + SSL_FILETYPE_PEM) < 0) { + wpa_printf(MSG_INFO, "SSL: use private key pem file failed"); + if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key, + SSL_FILETYPE_ASN1) < 0) { + wpa_printf(MSG_INFO, "SSL: use private key der file failed"); + } + else + ok = 1; + } + else + ok = 1; + + if (ok) + wpa_printf(MSG_DEBUG, "SSL: use private key file OK"); + } + + wolfSSL_CTX_set_default_passwd_cb(ctx, NULL); + os_free(passwd); + + if (!ok) + return -1; + + return 0; +} + +#define GEN_EMAIL 1 +#define GEN_DNS ALT_NAMES_OID +#define GEN_URI 6 + +static int tls_match_altSubject_component(WOLFSSL_X509 *cert, int type, + const char *value, size_t len) +{ + WOLFSSL_ASN1_OBJECT *gen; + void *ext; + int found = 0; + int i; + + ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL); + + for (i = 0; ext && i < wolfSSL_sk_num((void*)ext); i++) { + gen = wolfSSL_sk_value((void*)ext, i); + if (gen->type != type) + continue; + if (os_strlen((char *) gen->obj) == len && + os_memcmp(value, gen->obj, len) == 0) + found++; + } + + wolfSSL_sk_ASN1_OBJECT_free(ext); + + return found; +} + + +static int tls_match_altSubject(WOLFSSL_X509 *cert, const char *match) +{ + int type; + const char *pos, *end; + size_t len; + + pos = match; + do { + if (os_strncmp(pos, "EMAIL:", 6) == 0) { + type = GEN_EMAIL; + pos += 6; + } else if (os_strncmp(pos, "DNS:", 4) == 0) { + type = GEN_DNS; + pos += 4; + } else if (os_strncmp(pos, "URI:", 4) == 0) { + type = GEN_URI; + pos += 4; + } else { + wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " + "match '%s'", pos); + return 0; + } + end = os_strchr(pos, ';'); + while (end) { + if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || + os_strncmp(end + 1, "DNS:", 4) == 0 || + os_strncmp(end + 1, "URI:", 4) == 0) + break; + end = os_strchr(end + 1, ';'); + } + if (end) + len = end - pos; + else + len = os_strlen(pos); + if (tls_match_altSubject_component(cert, type, pos, len) > 0) + return 1; + pos = end + 1; + } while (end); + return 0; +} + + +#ifndef CONFIG_NATIVE_WINDOWS +static int domain_suffix_match(const char *val, size_t len, const char *match, + int full) +{ + size_t i, match_len; + + /* Check for embedded nuls that could mess up suffix matching */ + for (i = 0; i < len; i++) { + if (val[i] == '\0') { + wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject"); + return 0; + } + } + + match_len = os_strlen(match); + if (match_len > len || (full && match_len != len)) + return 0; + + if (os_strncasecmp(val + len - match_len, match, + match_len) != 0) + return 0; /* no match */ + + if (match_len == len) + return 1; /* exact match */ + + if (val[len - match_len - 1] == '.') + return 1; /* full label match completes suffix match */ + + wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match"); + return 0; +} +#endif /* CONFIG_NATIVE_WINDOWS */ + + +static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full) +{ +#ifdef CONFIG_NATIVE_WINDOWS + /* wincrypt.h has conflicting X509_NAME definition */ + return -1; +#else /* CONFIG_NATIVE_WINDOWS */ + WOLFSSL_ASN1_OBJECT *gen; + void *ext; + int i; + int j; + int dns_name = 0; + WOLFSSL_X509_NAME *name; + + wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s", + full ? "": "suffix ", match); + + ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL); + + for (j = 0; ext && j < wolfSSL_sk_num((void*)ext); j++) { + gen = wolfSSL_sk_value((void*)ext, j); + if (gen->type != ALT_NAMES_OID) + continue; + dns_name++; + wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName", + gen->obj, os_strlen((char *)gen->obj)); + if (domain_suffix_match((const char*)gen->obj, + os_strlen((char *)gen->obj), match, + full) == 1) { + wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found", + full ? "Match" : "Suffix match"); + wolfSSL_sk_ASN1_OBJECT_free(ext); + return 1; + } + } + wolfSSL_sk_ASN1_OBJECT_free(ext); + + if (dns_name) { + wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched"); + return 0; + } + + name = wolfSSL_X509_get_subject_name(cert); + i = -1; + for (;;) { + WOLFSSL_X509_NAME_ENTRY *e; + WOLFSSL_ASN1_STRING *cn; + + i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME, + i); + if (i == -1) + break; + e = wolfSSL_X509_NAME_get_entry(name, i); + if (e == NULL) + continue; + cn = wolfSSL_X509_NAME_ENTRY_get_data(e); + if (cn == NULL) + continue; + wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName", + cn->data, cn->length); + if (domain_suffix_match(cn->data, cn->length, match, full) == 1) + { + wpa_printf(MSG_DEBUG, "TLS: %s in commonName found", + full ? "Match" : "Suffix match"); + return 1; + } + } + + wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found", + full ? "": "suffix "); + return 0; +#endif /* CONFIG_NATIVE_WINDOWS */ +} + +static enum tls_fail_reason wolfssl_tls_fail_reason(int err) +{ + switch (err) { + case X509_V_ERR_CERT_REVOKED: + return TLS_FAIL_REVOKED; + case ASN_BEFORE_DATE_E: + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CRL_NOT_YET_VALID: + return TLS_FAIL_NOT_YET_VALID; + case ASN_AFTER_DATE_E: + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_CRL_HAS_EXPIRED: + return TLS_FAIL_EXPIRED; + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + case X509_V_ERR_UNABLE_TO_GET_CRL: + case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + case X509_V_ERR_INVALID_CA: + return TLS_FAIL_UNTRUSTED; + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + case X509_V_ERR_CERT_UNTRUSTED: + case X509_V_ERR_CERT_REJECTED: + return TLS_FAIL_BAD_CERTIFICATE; + default: + return TLS_FAIL_UNSPECIFIED; + } +} + +static const char* wolfssl_tls_err_string(int err, const char *err_str) +{ + switch (err) { + case ASN_BEFORE_DATE_E: + return "certificate is not yet valid"; + case ASN_AFTER_DATE_E: + return "certificate has expired"; + default: + return err_str; + } +} + +static struct wpabuf * get_x509_cert(WOLFSSL_X509 *cert) +{ + struct wpabuf *buf = NULL; + const u8 *data; + int cert_len; + + data = wolfSSL_X509_get_der(cert, &cert_len); + if (data != NULL) + buf = wpabuf_alloc_copy(data, cert_len); + + return buf; +} + +static void wolfssl_tls_fail_event(struct tls_connection *conn, + WOLFSSL_X509 *err_cert, int err, int depth, + const char *subject, const char *err_str, + enum tls_fail_reason reason) +{ + union tls_event_data ev; + struct wpabuf *cert = NULL; + struct tls_context *context = conn->context; + + if (context->event_cb == NULL) + return; + + cert = get_x509_cert(err_cert); + os_memset(&ev, 0, sizeof(ev)); + ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ? + reason : wolfssl_tls_fail_reason(err); + ev.cert_fail.depth = depth; + ev.cert_fail.subject = subject; + ev.cert_fail.reason_txt = wolfssl_tls_err_string(err, err_str); + ev.cert_fail.cert = cert; + context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); + wpabuf_free(cert); +} + + +static void wolfssl_tls_cert_event(struct tls_connection *conn, + WOLFSSL_X509 *err_cert, int depth, + const char *subject) +{ + struct wpabuf *cert = NULL; + union tls_event_data ev; + struct tls_context *context = conn->context; + char *altSubject[TLS_MAX_ALT_SUBJECT]; + int alt, num_altSubject = 0; + WOLFSSL_ASN1_OBJECT *gen; + void *ext; + int i; +#ifdef CONFIG_SHA256 + u8 hash[32]; +#endif /* CONFIG_SHA256 */ + + if (context->event_cb == NULL) + return; + + os_memset(&ev, 0, sizeof(ev)); + if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) || + context->cert_in_cb) { + cert = get_x509_cert(err_cert); + ev.peer_cert.cert = cert; + } +#ifdef CONFIG_SHA256 + if (cert) { + const u8 *addr[1]; + size_t len[1]; + addr[0] = wpabuf_head(cert); + len[0] = wpabuf_len(cert); + if (sha256_vector(1, addr, len, hash) == 0) { + ev.peer_cert.hash = hash; + ev.peer_cert.hash_len = sizeof(hash); + } + } +#endif /* CONFIG_SHA256 */ + ev.peer_cert.depth = depth; + ev.peer_cert.subject = subject; + + ext = wolfSSL_X509_get_ext_d2i(err_cert, ALT_NAMES_OID, NULL, NULL); + for (i = 0; ext && i < wolfSSL_sk_num((void*)ext); i++) { + char *pos; + + if (num_altSubject == TLS_MAX_ALT_SUBJECT) + break; + gen = wolfSSL_sk_value((void*)ext, i); +#if 0 + if (gen->type != GEN_EMAIL && + gen->type != GEN_DNS && + gen->type != GEN_URI) + continue; +#endif + + pos = os_malloc(10 + os_strlen((char *)gen->obj) + 1); + if (pos == NULL) + break; + altSubject[num_altSubject++] = pos; + +#if 0 + switch (gen->type) { + case GEN_EMAIL: + os_memcpy(pos, "EMAIL:", 6); + pos += 6; + break; + case GEN_DNS: + os_memcpy(pos, "DNS:", 4); + pos += 4; + break; + case GEN_URI: + os_memcpy(pos, "URI:", 4); + pos += 4; + break; + } +#else + os_memcpy(pos, "DNS:", 4); + pos += 4; +#endif + + os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj)); + pos += os_strlen((char *)gen->obj); + *pos = '\0'; + } + wolfSSL_sk_ASN1_OBJECT_free(ext); + + for (alt = 0; alt < num_altSubject; alt++) + ev.peer_cert.altsubject[alt] = altSubject[alt]; + ev.peer_cert.num_altsubject = num_altSubject; + + context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev); + wpabuf_free(cert); + for (alt = 0; alt < num_altSubject; alt++) + os_free(altSubject[alt]); +} + +static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx) +{ + char buf[256]; + WOLFSSL_X509 *err_cert; + int err, depth; + WOLFSSL *ssl; + struct tls_connection *conn; + struct tls_context *context; + char *match, *altmatch, *suffix_match, *domain_match; + const char *err_str; + + err_cert = wolfSSL_X509_STORE_CTX_get_current_cert(x509_ctx); + if (err_cert == NULL) { + wpa_printf(MSG_DEBUG, "wolfSSL: No Cert\n"); + return 0; + } + + err = wolfSSL_X509_STORE_CTX_get_error(x509_ctx); + depth = wolfSSL_X509_STORE_CTX_get_error_depth(x509_ctx); + ssl = wolfSSL_X509_STORE_CTX_get_ex_data(x509_ctx, + wolfSSL_get_ex_data_X509_STORE_CTX_idx()); + wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(err_cert), buf, + sizeof(buf)); + + conn = wolfSSL_get_ex_data(ssl, 0); + if (conn == NULL) { + wpa_printf(MSG_DEBUG, "wolfSSL: No ex_data\n"); + return 0; + } + + if (depth == 0) + conn->peer_cert = err_cert; + else if (depth == 1) + conn->peer_issuer = err_cert; + else if (depth == 2) + conn->peer_issuer_issuer = err_cert; + + context = conn->context; + match = conn->subjectMatch; + altmatch = conn->altSubjectMatch; + suffix_match = conn->suffixMatch; + domain_match = conn->domainMatch; + + if (!preverify_ok && !conn->ca_cert_verify) + preverify_ok = 1; + if (!preverify_ok && depth > 0 && conn->server_cert_only) + preverify_ok = 1; + if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) && + (err == X509_V_ERR_CERT_HAS_EXPIRED || + err == ASN_AFTER_DATE_E || err == ASN_BEFORE_DATE_E || + err == X509_V_ERR_CERT_NOT_YET_VALID)) { + wpa_printf(MSG_DEBUG, "wolfSSL: Ignore certificate validity " + "time mismatch"); + preverify_ok = 1; + } + + err_str = wolfSSL_X509_verify_cert_error_string(err); + +#ifdef CONFIG_SHA256 + /* + * Do not require preverify_ok so we can explicity allow otherwise + * invalid pinned server certificates. + */ + if (depth == 0 && conn->server_cert_only) { + struct wpabuf *cert; + cert = get_x509_cert(err_cert); + if (!cert) { + wpa_printf(MSG_DEBUG, "wolfSSL: Could not fetch " + "server certificate data"); + preverify_ok = 0; + } else { + u8 hash[32]; + const u8 *addr[1]; + size_t len[1]; + addr[0] = wpabuf_head(cert); + len[0] = wpabuf_len(cert); + if (sha256_vector(1, addr, len, hash) < 0 || + os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { + err_str = "Server certificate mismatch"; + err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; + preverify_ok = 0; + } else if (!preverify_ok) { + /* + * Certificate matches pinned certificate, allow + * regardless of other problems. + */ + wpa_printf(MSG_DEBUG, + "wolfSSL: Ignore validation issues for a pinned server certificate"); + preverify_ok = 1; + } + wpabuf_free(cert); + } + } +#endif /* CONFIG_SHA256 */ + + if (!preverify_ok) { + wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," + " error %d (%s) depth %d for '%s'", err, err_str, + depth, buf); + wolfssl_tls_fail_event(conn, err_cert, err, depth, buf, + err_str, TLS_FAIL_UNSPECIFIED); + return preverify_ok; + } + + wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " + "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", + preverify_ok, err, err_str, + conn->ca_cert_verify, depth, buf); + if (depth == 0 && match && os_strstr(buf, match) == NULL) { + wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " + "match with '%s'", buf, match); + preverify_ok = 0; + wolfssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Subject mismatch", + TLS_FAIL_SUBJECT_MISMATCH); + } else if (depth == 0 && altmatch && + !tls_match_altSubject(err_cert, altmatch)) { + wpa_printf(MSG_WARNING, "TLS: altSubjectName match " + "'%s' not found", altmatch); + preverify_ok = 0; + wolfssl_tls_fail_event(conn, err_cert, err, depth, buf, + "AltSubject mismatch", + TLS_FAIL_ALTSUBJECT_MISMATCH); + } else if (depth == 0 && suffix_match && + !tls_match_suffix(err_cert, suffix_match, 0)) { + wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found", + suffix_match); + preverify_ok = 0; + wolfssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Domain suffix mismatch", + TLS_FAIL_DOMAIN_SUFFIX_MISMATCH); + } else if (depth == 0 && domain_match && + !tls_match_suffix(err_cert, domain_match, 1)) { + wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found", + domain_match); + preverify_ok = 0; + wolfssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Domain mismatch", + TLS_FAIL_DOMAIN_MISMATCH); + } else + wolfssl_tls_cert_event(conn, err_cert, depth, buf); + + if (conn->cert_probe && preverify_ok && depth == 0) { + wpa_printf(MSG_DEBUG, "wolfSSL: Reject server certificate " + "on probe-only run"); + preverify_ok = 0; + wolfssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Server certificate chain probe", + TLS_FAIL_SERVER_CHAIN_PROBE); + } + +#ifdef HAVE_OCSP_OPENSSL + if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) && + preverify_ok) { + enum ocsp_result res; + + res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert, + conn->peer_issuer, + conn->peer_issuer_issuer); + if (res == OCSP_REVOKED) { + preverify_ok = 0; + wolfssl_tls_fail_event(conn, err_cert, err, depth, buf, + "certificate revoked", + TLS_FAIL_REVOKED); + if (err == X509_V_OK) + X509_STORE_CTX_set_error( + x509_ctx, X509_V_ERR_CERT_REVOKED); + } else if (res != OCSP_GOOD && + (conn->flags & TLS_CONN_REQUIRE_OCSP)) { + preverify_ok = 0; + wolfssl_tls_fail_event(conn, err_cert, err, depth, buf, + "bad certificate status response", + TLS_FAIL_UNSPECIFIED); + } + } +#endif /* HAVE_OCSP */ + if (depth == 0 && preverify_ok && context->event_cb != NULL) + context->event_cb(context->cb_ctx, + TLS_CERT_CHAIN_SUCCESS, NULL); + + return preverify_ok; +} + +static int tls_connection_ca_cert(void* tls_ctx, struct tls_connection *conn, + const char* ca_cert, + const u8* ca_cert_blob, size_t blob_len, + const char *ca_path) +{ + WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)tls_ctx; + + wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); + conn->ca_cert_verify = 1; + + if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { + wpa_printf(MSG_DEBUG, "wolfSSL: Probe for server certificate chain"); + conn->cert_probe = 1; + conn->ca_cert_verify = 0; + return 0; + } + + if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { +#ifdef CONFIG_SHA256 + const char *pos = ca_cert + 7; + if (os_strncmp(pos, "server/sha256/", 14) != 0) { + wpa_printf(MSG_DEBUG, "wolfSSL: Unsupported ca_cert " + "hash value '%s'", ca_cert); + return -1; + } + pos += 14; + if (os_strlen(pos) != 32 * 2) { + wpa_printf(MSG_DEBUG, "wolfSSL: Unexpected SHA256 " + "hash length in ca_cert '%s'", ca_cert); + return -1; + } + if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { + wpa_printf(MSG_DEBUG, "wolfSSL: Invalid SHA256 hash " + "value in ca_cert '%s'", ca_cert); + return -1; + } + conn->server_cert_only = 1; + wpa_printf(MSG_DEBUG, "wolfSSL: Checking only server " + "certificate match"); + return 0; +#else /* CONFIG_SHA256 */ + wpa_printf(MSG_INFO, "No SHA256 included in the build - " + "cannot validate server certificate hash"); + return -1; +#endif /* CONFIG_SHA256 */ + } + + if (ca_cert_blob) { + if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len, + SSL_FILETYPE_ASN1) != SSL_SUCCESS) { + wpa_printf(MSG_INFO, "SSL: failed to load ca blob"); + return -1; + } + wpa_printf(MSG_DEBUG, "SSL: use ca cert blob OK"); + return 0; + + } + + if (ca_cert || ca_path) { + WOLFSSL_X509_STORE *cm = wolfSSL_X509_STORE_new(); + if (cm == NULL) { + wpa_printf(MSG_INFO, "SSL: failed to create certificate store"); + return -1; + } + wolfSSL_CTX_set_cert_store(ctx, cm); + XFREE(cm, NULL, DYNAMIC_TYPE_X509_STORE); + + if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path) + != SSL_SUCCESS) { + wpa_printf(MSG_INFO, "SSL: failed to load ca_cert as pem"); + + if (ca_cert) { + if (wolfSSL_CTX_der_load_verify_locations(ctx, ca_cert, + SSL_FILETYPE_ASN1) != SSL_SUCCESS) { + wpa_printf(MSG_INFO, "SSL: failed to load ca_cert as der"); + return -1; + } + } + else + return -1; + } + return 0; + } + + conn->ca_cert_verify = 0; + return 0; +} + +static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags) +{ +#ifdef HAVE_SESSION_TICKET +#if 0 + if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET)) + wolfSSL_UseSessionTicket(ssl); +#endif +#endif /* HAVE_SESSION_TICKET */ + + if (flags & TLS_CONN_DISABLE_TLSv1_0) + wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1); + if (flags & TLS_CONN_DISABLE_TLSv1_1) + wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1); + if (flags & TLS_CONN_DISABLE_TLSv1_2) + wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2); +} + +int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, + const struct tls_connection_params *params) +{ + wpa_printf(MSG_DEBUG, "SSL: set params"); + + if (tls_connection_set_subject_match(conn, params->subject_match, + params->altsubject_match, + params->suffix_match, + params->domain_match) < 0) { + wpa_printf(MSG_INFO, "Error setting subject match"); + return -1; + } + + if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert, + params->ca_cert_blob, params->ca_cert_blob_len, + params->ca_path) < 0) { + wpa_printf(MSG_INFO, "Error setting ca cert"); + return -1; + } + + if (tls_connection_client_cert(conn, params->client_cert, + params->client_cert_blob, + params->client_cert_blob_len) < 0) { + wpa_printf(MSG_INFO, "Error setting client cert"); + return -1; + } + + if (tls_connection_private_key(tls_ctx, conn, params->private_key, + params->private_key_passwd, + params->private_key_blob, + params->private_key_blob_len) < 0) { + wpa_printf(MSG_INFO, "Error setting private key"); + return -1; + } + + if (tls_connection_dh(conn, params->dh_file, params->dh_blob, + params->dh_blob_len) < 0) { + wpa_printf(MSG_INFO, "Error setting dh"); + return -1; + } + + if (params->openssl_ciphers && wolfSSL_set_cipher_list(conn->ssl, + params->openssl_ciphers) != 1) { + wpa_printf(MSG_INFO, "wolfSSL: Failed to set cipher string '%s'", + params->openssl_ciphers); + return -1; + } + + tls_set_conn_flags(conn->ssl, params->flags); + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST + if (params->flags & TLS_CONN_REQUEST_OCSP) { + if (wolfSSL_UseOCSPStapling(conn->ssl, WOLFSSL_CSR_OCSP, + WOLFSSL_CSR_OCSP_USE_NONCE) != SSL_SUCCESS) + return -1; + wolfSSL_CTX_EnableOCSP(tls_ctx, 0); + } +#endif +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + if (params->flags & TLS_CONN_REQUEST_OCSP) { + if (wolfSSL_UseOCSPStaplingV2(conn->ssl, WOLFSSL_CSR2_OCSP_MULTI, 0) + != SSL_SUCCESS) { + return -1; + } + wolfSSL_CTX_EnableOCSP(tls_ctx, 0); + } +#endif +#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \ + !defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) +#ifdef HAVE_OCSP + if (params->flags & TLS_CONN_REQUEST_OCSP) { + wolfSSL_CTX_EnableOCSP(ctx, 0); + } +#else /* HAVE_OCSP */ + if (params->flags & TLS_CONN_REQUIRE_OCSP) { + wpa_printf(MSG_INFO, + "wolfSSL: No OCSP support included - reject configuration"); + return -1; + } + if (params->flags & TLS_CONN_REQUEST_OCSP) { + wpa_printf(MSG_DEBUG, + "wolfSSL: No OCSP support included - allow optional OCSP " + "case to continue"); + } +#endif /* HAVE_OCSP */ +#endif /* !HAVE_CERTIFICATE_STATUS_REQUEST && + * !HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + + conn->flags = params->flags; + + return 0; +} + + +static int tls_global_ca_cert(void* ssl_ctx, const char* ca_cert) +{ + WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)ssl_ctx; + + if (ca_cert) { + if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, NULL) != 1) { + wpa_printf(MSG_WARNING, "Failed to load root certificates"); + return -1; + } + + wpa_printf(MSG_DEBUG, "TLS: Trusted root certificate(s) loaded"); + } + + return 0; +} + + +static int tls_global_client_cert(void* ssl_ctx, const char* client_cert) +{ + WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)ssl_ctx; + + if (client_cert == NULL) + return 0; + + if (wolfSSL_CTX_use_certificate_file(ctx, client_cert, + SSL_FILETYPE_ASN1) != SSL_SUCCESS && + wolfSSL_CTX_use_certificate_file(ctx, client_cert, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + wpa_printf(MSG_INFO, "Failed to load client certificate"); + return -1; + } + wpa_printf(MSG_DEBUG, "SSL: Loaded global client certificate: %s", client_cert); + + return 0; +} + + +static int tls_global_private_key(void* ssl_ctx, const char* private_key, + const char* private_key_passwd) +{ + WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)ssl_ctx; + char* passwd = NULL; + int ret = 0; + + if (private_key == NULL) + return 0; + + if (private_key_passwd) { + passwd = os_strdup(private_key_passwd); + if (passwd == NULL) + return -1; + } + + wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb); + wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd); + + if (wolfSSL_CTX_use_PrivateKey_file(ctx, private_key, + SSL_FILETYPE_ASN1) != 1 && + wolfSSL_CTX_use_PrivateKey_file(ctx, private_key, + SSL_FILETYPE_PEM) != 1 ) { + wpa_printf(MSG_INFO, "Failed to load private key"); + ret = -1; + } + wpa_printf(MSG_DEBUG, "SSL: Loaded global private key"); + + os_free(passwd); + wolfSSL_CTX_set_default_passwd_cb(ctx, NULL); + + return ret; +} + + +static int tls_global_dh(void* ssl_ctx, const char* dh_file, + const u8* dh_blob, size_t blob_len) +{ + WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)ssl_ctx; + + if (dh_file == NULL && dh_blob == NULL) + return 0; + + if (dh_blob) { + if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len, + SSL_FILETYPE_ASN1) < 0) { + wpa_printf(MSG_INFO, "SSL: global use dh der blob failed"); + return -1; + } + wpa_printf(MSG_DEBUG, "SSL: global use dh blob OK"); + return 0; + } + + if (dh_file) { + if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) < 0) { + wpa_printf(MSG_INFO, "SSL: global use dh pem file failed"); + if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, + SSL_FILETYPE_ASN1) < 0) { + wpa_printf(MSG_INFO, "SSL: global use dh der file failed"); + return -1; + } + } + wpa_printf(MSG_DEBUG, "SSL: global use dh file OK"); + return 0; + } + + return 0; +} + +#ifdef HAVE_OCSP +int ocsp_status_cb(void* unused, const char* url, int urlSz, + unsigned char* request, int requestSz, + unsigned char** response) +{ + size_t len; + + (void)unused; + + if (url == NULL) { + wpa_printf(MSG_DEBUG, "wolfSSL: OCSP status callback - no response " + "configured"); + *response = NULL; + return 0; + } + + *response = (unsigned char*)os_readfile(url, &len); + if (*response == NULL) { + wpa_printf(MSG_DEBUG, "wolfSSL: OCSP status callback - could not read " + "response file"); + return -1; + } + wpa_printf(MSG_DEBUG, "wolfSSL: OCSP status callback - send cached " + "response"); + return len; +} + +void ocsp_resp_free_cb(void* ocsp_stapling_response, unsigned char* response) +{ + os_free(response); +} +#endif + +int tls_global_set_params(void* tls_ctx, + const struct tls_connection_params* params) +{ + wpa_printf(MSG_DEBUG, "SSL: global set params"); + + if (tls_global_ca_cert(tls_ctx, params->ca_cert) < 0) { + wpa_printf(MSG_INFO, "SSL: Failed to load ca cert file '%s'", + params->ca_cert); + return -1; + } + + if (tls_global_client_cert(tls_ctx, params->client_cert) < 0) { + wpa_printf(MSG_INFO, "SSL: Failed to load client cert file '%s'", + params->client_cert); + return -1; + } + + if (tls_global_private_key(tls_ctx, params->private_key, + params->private_key_passwd) < 0) { + wpa_printf(MSG_INFO, "SSL: Failed to load private key file '%s'", + params->private_key); + return -1; + } + + if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob, + params->dh_blob_len) < 0) { + wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'", + params->dh_file); + return -1; + } + + if (params->openssl_ciphers && wolfSSL_CTX_set_cipher_list(tls_ctx, + params->openssl_ciphers) != 1) { + wpa_printf(MSG_INFO, "wolfSSL: Failed to set cipher string '%s'", + params->openssl_ciphers); + return -1; + } + +#ifdef HAVE_SESSION_TICKET + /* Session ticket is off by default - can't disable once on. */ + if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET)) + wolfSSL_CTX_UseSessionTicket(tls_ctx); +#endif + +#ifdef HAVE_OCSP + if (params->ocsp_stapling_response) { + wolfSSL_CTX_SetOCSP_OverrideURL(tls_ctx, + params->ocsp_stapling_response); + wolfSSL_CTX_SetOCSP_Cb(tls_ctx, ocsp_status_cb, ocsp_resp_free_cb, + NULL); + } +#endif + + return 0; +} + + +int tls_global_set_verify(void *tls_ctx, int check_crl) +{ + wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl); + + if (check_crl) { + /* Hack to Enable CRLs. */ + wolfSSL_CTX_LoadCRLBuffer((WOLFSSL_CTX*)tls_ctx, NULL, 0, + SSL_FILETYPE_PEM); + } + return 0; +} + + +int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, + int verify_peer, unsigned int flags, + const u8 *session_ctx, size_t session_ctx_len) +{ + if (conn == NULL) + return -1; + + wpa_printf(MSG_DEBUG, "SSL: set verify: %d", verify_peer); + + if (verify_peer) { + conn->ca_cert_verify = 1; + wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + tls_verify_cb); + } + else { + conn->ca_cert_verify = 0; + wolfSSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); + } + + wolfSSL_set_accept_state(conn->ssl); + + /* do we need to fake a session like OpenSSL does here ? */ + + return 0; +} + + +static struct wpabuf* wolfssl_handshake(struct tls_connection *conn, + const struct wpabuf *in_data, + int server) +{ + int res; + + ResetOutData(&conn->output); + + /* Initiate TLS handshake or continue the existing handshake */ + if (server) { + wolfSSL_set_accept_state(conn->ssl); + res = wolfSSL_accept(conn->ssl); + wpa_printf(MSG_DEBUG, "SSL: wolfSSL_accept: %d", res); + } + else { + wolfSSL_set_connect_state(conn->ssl); + res = wolfSSL_connect(conn->ssl); + wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect: %d", res); + } + if (res != 1) { + int err = wolfSSL_get_error(conn->ssl, res); + if (err == SSL_ERROR_WANT_READ) + wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect - want more data"); + else if (err == SSL_ERROR_WANT_WRITE) + wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect - want to write"); + else { + char msg[80]; + wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect - failed %s", + wolfSSL_ERR_error_string(err, msg)); + conn->failed++; + } + } + + return conn->output.out_data; +} + + +static struct wpabuf* wolfssl_get_appl_data(struct tls_connection *conn, + size_t max_len) +{ + int res; + struct wpabuf* appl_data = wpabuf_alloc(max_len + 100); + + if (appl_data == NULL) + return NULL; + + res = wolfSSL_read(conn->ssl, wpabuf_mhead(appl_data), + wpabuf_size(appl_data)); + if (res < 0) { + int err = wolfSSL_get_error(conn->ssl, res); + if (err == SSL_ERROR_WANT_READ || + err == SSL_ERROR_WANT_WRITE) { + wpa_printf(MSG_DEBUG, "SSL: No Application Data included"); + } else { + char msg[80]; + wpa_printf(MSG_DEBUG, "Failed to read possible Application Data %s", + wolfSSL_ERR_error_string(err, msg)); + } + + wpabuf_free(appl_data); + return NULL; + } + + wpabuf_put(appl_data, res); + wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " + "message", appl_data); + return appl_data; +} + + + + +static struct wpabuf* wolfssl_connection_handshake(struct tls_connection* conn, + const struct wpabuf* in_data, struct wpabuf** appl_data, int server) +{ + struct wpabuf* out_data; + + ResetInData(&conn->input, in_data); + + if (appl_data) + *appl_data = NULL; + + out_data = wolfssl_handshake(conn, in_data, server); + if (out_data == NULL) + return NULL; + + if (wolfSSL_is_init_finished(conn->ssl)) { + wpa_printf(MSG_DEBUG, "wolfSSL: Handshake finished - resumed=%d", + tls_connection_resumed(NULL, conn)); + if (appl_data && in_data) + *appl_data = wolfssl_get_appl_data(conn, wpabuf_len(in_data)); + } + + return out_data; +} + + +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return wolfssl_connection_handshake(conn, in_data, appl_data, 0); +} + + +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return wolfssl_connection_handshake(conn, in_data, appl_data, 1); +} + + +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) +{ + int res; + + if (conn == NULL) + return NULL; + + wpa_printf(MSG_DEBUG, "SSL: encrypt: %ld bytes", wpabuf_len(in_data)); + + ResetOutData(&conn->output); + + res = wolfSSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); + if (res < 0) { + int err = wolfSSL_get_error(conn->ssl, res); + char msg[80]; + wpa_printf(MSG_INFO, "Encryption failed - SSL_write: %s", + wolfSSL_ERR_error_string(err, msg)); + return NULL; + } + + return conn->output.out_data; +} + + +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) +{ + int res; + struct wpabuf *buf; + + if (conn == NULL) + return NULL; + + wpa_printf(MSG_DEBUG, "SSL: decrypt"); + + ResetInData(&conn->input, in_data); + + /* Read decrypted data for further processing */ + /* + * Even though we try to disable TLS compression, it is possible that + * this cannot be done with all TLS libraries. Add extra buffer space + * to handle the possibility of the decrypted data being longer than + * input data. + */ + buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (buf == NULL) + return NULL; + res = wolfSSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); + if (res < 0) { + wpa_printf(MSG_INFO, "Decryption failed - SSL_read"); + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + + wpa_printf(MSG_DEBUG, "SSL: decrypt: %ld bytes", wpabuf_len(buf)); + + return buf; +} + + +int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) +{ + return conn ? wolfSSL_session_reused(conn->ssl) : 0; +} + + +int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, + u8 *ciphers) +{ + char buf[128], *pos, *end; + u8 *c; + int ret; + + if (conn == NULL || conn->ssl == NULL || ciphers == NULL) + return -1; + + buf[0] = '\0'; + pos = buf; + end = pos + sizeof(buf); + + c = ciphers; + while (*c != TLS_CIPHER_NONE) { + const char *suite; + + switch (*c) { + case TLS_CIPHER_RC4_SHA: + suite = "RC4-SHA"; + break; + case TLS_CIPHER_AES128_SHA: + suite = "AES128-SHA"; + break; + case TLS_CIPHER_RSA_DHE_AES128_SHA: + suite = "DHE-RSA-AES128-SHA"; + break; + case TLS_CIPHER_ANON_DH_AES128_SHA: + suite = "ADH-AES128-SHA"; + break; + case TLS_CIPHER_RSA_DHE_AES256_SHA: + suite = "DHE-RSA-AES256-SHA"; + break; + case TLS_CIPHER_AES256_SHA: + suite = "AES256-SHA"; + break; + default: + wpa_printf(MSG_DEBUG, "TLS: Unsupported " + "cipher selection: %d", *c); + return -1; + } + ret = os_snprintf(pos, end - pos, ":%s", suite); + if (ret < 0 || ret >= end - pos) + break; + pos += ret; + + c++; + } + + wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", buf + 1); + + if (wolfSSL_set_cipher_list(conn->ssl, buf + 1) != 1) { + wpa_printf(MSG_DEBUG, "Cipher suite configuration failed"); + return -1; + } + + return 0; +} + + +int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, + char *buf, size_t buflen) +{ + WOLFSSL_CIPHER* cipher; + const char* name; + + if (conn == NULL || conn->ssl == NULL) + return -1; + + cipher = wolfSSL_get_current_cipher(conn->ssl); + if (cipher == NULL) + return -1; + + name = wolfSSL_CIPHER_get_name(cipher); + if (name == NULL) + return -1; + + if (os_strcmp(name, "SSL_RSA_WITH_RC4_128_SHA") == 0) + os_strlcpy(buf, "RC4-SHA", buflen); + else if (os_strcmp(name, "TLS_RSA_WITH_AES_128_CBC_SHA") == 0) + os_strlcpy(buf, "AES128-SHA", buflen); + else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA") == 0) + os_strlcpy(buf, "DHE-RSA-AES128-SHA", buflen); + else if (os_strcmp(name, "TLS_DH_anon_WITH_AES_128_CBC_SHA") == 0) + os_strlcpy(buf, "ADH-AES128-SHA", buflen); + else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA") == 0) + os_strlcpy(buf, "DHE-RSA-AES256-SHA", buflen); + else if (os_strcmp(name, "TLS_RSA_WITH_AES_256_CBC_SHA") == 0) + os_strlcpy(buf, "AES256-SHA", buflen); + else + os_strlcpy(buf, name, buflen); + + return 0; +} + + +int tls_connection_enable_workaround(void *tls_ctx, + struct tls_connection *conn) +{ + /* no empty fragments in wolfSSL for now */ + return 0; +} + + +int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + + return conn->failed; +} + + +int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + + return conn->readAlerts; +} + + +int tls_connection_get_write_alerts(void *tls_ctx, + struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + + return conn->writeAlerts; +} + + + +int tls_get_library_version(char *buf, size_t buf_len) +{ + return os_snprintf(buf, buf_len, "wolfSSL build=%s run=%s", WOLFSSL_VERSION, + wolfSSL_lib_version()); +} + +int tls_get_version(void *ssl_ctx, struct tls_connection *conn, + char *buf, size_t buflen) +{ + const char *name; + if (conn == NULL || conn->ssl == NULL) + return -1; + + name = wolfSSL_get_version(conn->ssl); + if (name == NULL) + return -1; + + os_strlcpy(buf, name, buflen); + return 0; +} + +int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn, + struct tls_random *keys) +{ + WOLFSSL *ssl; + + if (conn == NULL || keys == NULL) + return -1; + ssl = conn->ssl; + if (ssl == NULL) + return -1; + + os_memset(keys, 0, sizeof(*keys)); + keys->client_random = conn->client_random; + keys->client_random_len = wolfSSL_get_client_random( + ssl, conn->client_random, sizeof(conn->client_random)); + keys->server_random = conn->server_random; + keys->server_random_len = wolfSSL_get_server_random( + ssl, conn->server_random, sizeof(conn->server_random)); + + return 0; +} + +int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, + const char *label, u8 *out, size_t out_len) +{ + if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0) + return -1; + return 0; +} + +int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn, + u8 *out, size_t out_len) +{ + int ret; + + if (conn == NULL || conn->ssl == NULL) + return -1; + + ret = wolfSSL_make_eap_keys(conn->ssl, out, out_len, "key expansion"); + if (ret != 0) + return -1; + return 0; +} + +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) +int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, + int ext_type, const u8 *data, + size_t data_len) +{ + (void)ssl_ctx; + + if (conn == NULL || conn->ssl == NULL || ext_type != 35) + return -1; + + if (wolfSSL_set_SessionTicket(conn->ssl, data, (unsigned int)data_len) != 1) + return -1; + + return 0; +} + +static int tls_sess_sec_cb(WOLFSSL *s, void *secret, int *secret_len, void *arg) +{ + struct tls_connection *conn = arg; + int ret; + unsigned char client_random[RAN_LEN]; + unsigned char server_random[RAN_LEN]; + word32 ticketLen = (word32)sizeof(conn->session_ticket); + + if (conn == NULL || conn->session_ticket_cb == NULL) + return 1; + + if (wolfSSL_get_client_random(s, client_random, sizeof(client_random)) == 0) + return 1; + if (wolfSSL_get_server_random(s, server_random, sizeof(server_random)) == 0) + return 1; + if (wolfSSL_get_SessionTicket(s, conn->session_ticket, &ticketLen) != 1) + return 1; + + if (ticketLen == 0) + return 0; + + ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, + conn->session_ticket, ticketLen, + client_random, server_random, secret); + if (ret <= 0) + return 1; + + *secret_len = SECRET_LEN; + return 0; +} +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ + +int tls_connection_set_session_ticket_cb(void *tls_ctx, + struct tls_connection *conn, + tls_session_ticket_cb cb, + void *ctx) +{ +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) + conn->session_ticket_cb = cb; + conn->session_ticket_cb_ctx = ctx; + + if (cb) { + if (wolfSSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb, + conn) != 1) + return -1; + } else { + if (wolfSSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) + return -1; + } + + return 0; +#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ + return -1; +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ +} + +void tls_connection_set_success_data_resumed(struct tls_connection *conn) +{ + wpa_printf(MSG_DEBUG, "wolfSSL: Success data accepted for resumed session"); +} + +void tls_connection_remove_session(struct tls_connection *conn) +{ + WOLFSSL_SESSION *sess; + + sess = wolfSSL_get_session(conn->ssl); + if (!sess) + return; + + wolfSSL_SSL_SESSION_set_timeout(sess, 0); + wpa_printf(MSG_DEBUG, "wolfSSL: Removed cached session to disable session " + "resumption"); +} + +void tls_connection_set_success_data(struct tls_connection *conn, + struct wpabuf *data) +{ + WOLFSSL_SESSION *sess; + struct wpabuf *old; + + wpa_printf(MSG_DEBUG, "wolfSSL: Set success data"); + + sess = wolfSSL_get_session(conn->ssl); + if (sess == NULL) { + wpa_printf(MSG_DEBUG, "wolfSSL: No session found for success data"); + goto fail; + } + old = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session); + if (old) { + wpa_printf(MSG_DEBUG, "wolfSSL: Replacing old success data %p", old); + wpabuf_free(old); + } + if (wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1) + goto fail; + + wpa_printf(MSG_DEBUG, "wolfSSL: Stored success data %p", data); + conn->success_data = 1; + return; + +fail: + wpa_printf(MSG_INFO, "wolfSSL: Failed to store success data"); + wpabuf_free(data); +} + +const struct wpabuf * +tls_connection_get_success_data(struct tls_connection *conn) +{ + WOLFSSL_SESSION *sess; + + wpa_printf(MSG_DEBUG, "wolfSSL: Get success data"); + + if ((sess = wolfSSL_get_session(conn->ssl)) == NULL) + return NULL; + return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session); +} + + diff --git a/tests/hwsim/example-hostapd.config b/tests/hwsim/example-hostapd.config index 71a2070..2333585 100644 --- a/tests/hwsim/example-hostapd.config +++ b/tests/hwsim/example-hostapd.config @@ -1,5 +1,9 @@ #CC=ccache gcc +#CFLAGS += -L/usr/local/include/wolfssl +#LIBS += -L/usr/local/lib + + CONFIG_DRIVER_NONE=y CONFIG_DRIVER_NL80211=y CONFIG_RSN_PREAUTH=y @@ -8,6 +12,7 @@ CONFIG_RSN_PREAUTH=y #CONFIG_INTERNAL_LIBTOMMATH=y #CONFIG_INTERNAL_LIBTOMMATH_FAST=y CONFIG_TLS=openssl +#CONFIG_TLS=wolfssl CONFIG_EAP=y CONFIG_ERP=y diff --git a/tests/hwsim/example-wpa_supplicant.config b/tests/hwsim/example-wpa_supplicant.config index 4587cf7..a30b7ac 100644 --- a/tests/hwsim/example-wpa_supplicant.config +++ b/tests/hwsim/example-wpa_supplicant.config @@ -1,6 +1,10 @@ #CC=ccache gcc +#CFLAGS += -L/usr/local/include/wolfssl +#LIBS += -L/usr/local/lib + CONFIG_TLS=openssl +#CONFIG_TLS=wolfssl #CONFIG_TLS=internal #CONFIG_INTERNAL_LIBTOMMATH=y #CONFIG_INTERNAL_LIBTOMMATH_FAST=y diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py index 818e341..983a850 100644 --- a/tests/hwsim/test_ap_eap.py +++ b/tests/hwsim/test_ap_eap.py @@ -40,12 +40,12 @@ def check_eap_capa(dev, method): def check_subject_match_support(dev): tls = dev.request("GET tls_library") - if not tls.startswith("OpenSSL"): + if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"): raise HwsimSkip("subject_match not supported with this TLS library: " + tls) def check_altsubject_match_support(dev): tls = dev.request("GET tls_library") - if not tls.startswith("OpenSSL"): + if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"): raise HwsimSkip("altsubject_match not supported with this TLS library: " + tls) def check_domain_match(dev): @@ -60,7 +60,7 @@ def check_domain_suffix_match(dev): def check_domain_match_full(dev): tls = dev.request("GET tls_library") - if not tls.startswith("OpenSSL"): + if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"): raise HwsimSkip("domain_suffix_match requires full match with this TLS library: " + tls) def check_cert_probe_support(dev): @@ -99,6 +99,8 @@ def check_pkcs12_support(dev): tls = dev.request("GET tls_library") #if tls.startswith("internal"): # raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls) + if tls.startswith("wolfSSL"): + raise HwsimSkip("PKCS#12 not supported with this TLS library: " + tls) def check_dh_dsa_support(dev): tls = dev.request("GET tls_library") @@ -2906,7 +2908,11 @@ def test_ap_wpa2_eap_ikev2_oom(dev, apdev): time.sleep(0.02) dev[0].request("REMOVE_NETWORK all") - tests = [ (1, "os_get_random;dh_init") ] + tls = dev[0].request("GET tls_library") + if not tls.startswith("wolfSSL"): + tests = [ (1, "os_get_random;dh_init") ] + else: + tests = [ (1, "crypto_dh_init;dh_init") ] for count, func in tests: with fail_test(dev[0], count, func): dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="IKEV2", @@ -3620,8 +3626,8 @@ def test_ap_wpa2_eap_fast_cipher_suites(dev, apdev): """EAP-FAST and different TLS cipher suites""" check_eap_capa(dev[0], "FAST") tls = dev[0].request("GET tls_library") - if not tls.startswith("OpenSSL"): - raise HwsimSkip("TLS library is not OpenSSL: " + tls) + if not tls.startswith("OpenSSL") and not tls.startswith("wolfSSL"): + raise HwsimSkip("TLS library is not OpenSSL or wolfSSL: " + tls) params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") hapd = hostapd.add_ap(apdev[0], params) @@ -3826,6 +3832,7 @@ def int_eap_server_params(): def test_ap_wpa2_eap_tls_ocsp_key_id(dev, apdev, params): """EAP-TLS and OCSP certificate signed OCSP response using key ID""" check_ocsp_support(dev[0]) + check_pkcs12_support(dev[0]) ocsp = os.path.join(params['logdir'], "ocsp-server-cache-key-id.der") if not os.path.exists(ocsp): raise HwsimSkip("No OCSP response available") @@ -3841,6 +3848,7 @@ def test_ap_wpa2_eap_tls_ocsp_key_id(dev, apdev, params): def test_ap_wpa2_eap_tls_ocsp_ca_signed_good(dev, apdev, params): """EAP-TLS and CA signed OCSP response (good)""" check_ocsp_support(dev[0]) + check_pkcs12_support(dev[0]) ocsp = os.path.join(params['logdir'], "ocsp-resp-ca-signed.der") if not os.path.exists(ocsp): raise HwsimSkip("No OCSP response available") @@ -3856,6 +3864,7 @@ def test_ap_wpa2_eap_tls_ocsp_ca_signed_good(dev, apdev, params): def test_ap_wpa2_eap_tls_ocsp_ca_signed_revoked(dev, apdev, params): """EAP-TLS and CA signed OCSP response (revoked)""" check_ocsp_support(dev[0]) + check_pkcs12_support(dev[0]) ocsp = os.path.join(params['logdir'], "ocsp-resp-ca-signed-revoked.der") if not os.path.exists(ocsp): raise HwsimSkip("No OCSP response available") @@ -3887,6 +3896,7 @@ def test_ap_wpa2_eap_tls_ocsp_ca_signed_revoked(dev, apdev, params): def test_ap_wpa2_eap_tls_ocsp_ca_signed_unknown(dev, apdev, params): """EAP-TLS and CA signed OCSP response (unknown)""" check_ocsp_support(dev[0]) + check_pkcs12_support(dev[0]) ocsp = os.path.join(params['logdir'], "ocsp-resp-ca-signed-unknown.der") if not os.path.exists(ocsp): raise HwsimSkip("No OCSP response available") @@ -3916,6 +3926,7 @@ def test_ap_wpa2_eap_tls_ocsp_ca_signed_unknown(dev, apdev, params): def test_ap_wpa2_eap_tls_ocsp_server_signed(dev, apdev, params): """EAP-TLS and server signed OCSP response""" check_ocsp_support(dev[0]) + check_pkcs12_support(dev[0]) ocsp = os.path.join(params['logdir'], "ocsp-resp-server-signed.der") if not os.path.exists(ocsp): raise HwsimSkip("No OCSP response available") @@ -3945,6 +3956,7 @@ def test_ap_wpa2_eap_tls_ocsp_server_signed(dev, apdev, params): def test_ap_wpa2_eap_tls_ocsp_invalid_data(dev, apdev): """WPA2-Enterprise connection using EAP-TLS and invalid OCSP data""" check_ocsp_support(dev[0]) + check_pkcs12_support(dev[0]) params = int_eap_server_params() params["ocsp_stapling_response"] = "auth_serv/ocsp-req.der" hostapd.add_ap(apdev[0], params) @@ -3971,6 +3983,7 @@ def test_ap_wpa2_eap_tls_ocsp_invalid_data(dev, apdev): def test_ap_wpa2_eap_tls_ocsp_invalid(dev, apdev): """WPA2-Enterprise connection using EAP-TLS and invalid OCSP response""" check_ocsp_support(dev[0]) + check_pkcs12_support(dev[0]) params = int_eap_server_params() params["ocsp_stapling_response"] = "auth_serv/ocsp-server-cache.der-invalid" hostapd.add_ap(apdev[0], params) @@ -3997,6 +4010,7 @@ def test_ap_wpa2_eap_tls_ocsp_invalid(dev, apdev): def test_ap_wpa2_eap_tls_ocsp_unknown_sign(dev, apdev): """WPA2-Enterprise connection using EAP-TLS and unknown OCSP signer""" check_ocsp_support(dev[0]) + check_pkcs12_support(dev[0]) params = int_eap_server_params() params["ocsp_stapling_response"] = "auth_serv/ocsp-server-cache.der-unknown-sign" hostapd.add_ap(apdev[0], params) @@ -4096,7 +4110,7 @@ def test_ap_wpa2_eap_ttls_optional_ocsp_unknown(dev, apdev, params): def test_ap_wpa2_eap_tls_intermediate_ca(dev, apdev, params): """EAP-TLS with intermediate server/user CA""" params = int_eap_server_params() - params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem" + params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem" params["server_cert"] = "auth_serv/iCA-server/server.pem" params["private_key"] = "auth_serv/iCA-server/server.key" hostapd.add_ap(apdev[0], params) @@ -4201,7 +4215,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_sha1(dev, apdev, params): def run_ap_wpa2_eap_tls_intermediate_ca_ocsp(dev, apdev, params, md): params = int_eap_server_params() - params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem" + params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem" params["server_cert"] = "auth_serv/iCA-server/server.pem" params["private_key"] = "auth_serv/iCA-server/server.key" fn = ica_ocsp("server.pem", md) @@ -4236,7 +4250,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked_sha1(dev, apdev, params): def run_ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked(dev, apdev, params, md): params = int_eap_server_params() - params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem" + params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem" params["server_cert"] = "auth_serv/iCA-server/server-revoked.pem" params["private_key"] = "auth_serv/iCA-server/server-revoked.key" fn = ica_ocsp("server-revoked.pem", md) @@ -4286,7 +4300,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi_missing_resp(dev, apdev, par check_ocsp_multi_support(dev[0]) params = int_eap_server_params() - params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem" + params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem" params["server_cert"] = "auth_serv/iCA-server/server.pem" params["private_key"] = "auth_serv/iCA-server/server.key" fn = ica_ocsp("server.pem") @@ -4336,7 +4350,7 @@ def test_ap_wpa2_eap_tls_intermediate_ca_ocsp_multi(dev, apdev, params): check_ocsp_multi_support(dev[0]) params = int_eap_server_params() - params["ca_cert"] = "auth_serv/iCA-server/ca-and-root.pem" + params["ca_cert"] = "auth_serv/iCA-user/ca-and-root.pem" params["server_cert"] = "auth_serv/iCA-server/server.pem" params["private_key"] = "auth_serv/iCA-server/server.key" fn = ica_ocsp("server.pem") @@ -4384,6 +4398,7 @@ def test_ap_wpa2_eap_tls_ocsp_multi_revoked(dev, apdev, params): """EAP-TLS and CA signed OCSP multi response (revoked)""" check_ocsp_support(dev[0]) check_ocsp_multi_support(dev[0]) + check_pkcs12_support(dev[0]) ocsp_revoked = os.path.join(params['logdir'], "ocsp-resp-ca-signed-revoked.der") @@ -4443,6 +4458,7 @@ def test_ap_wpa2_eap_tls_ocsp_multi_revoked(dev, apdev, params): def test_ap_wpa2_eap_tls_domain_suffix_match_cn_full(dev, apdev): """WPA2-Enterprise using EAP-TLS and domain suffix match (CN)""" check_domain_match_full(dev[0]) + check_pkcs12_support(dev[0]) params = int_eap_server_params() params["server_cert"] = "auth_serv/server-no-dnsname.pem" params["private_key"] = "auth_serv/server-no-dnsname.key" @@ -4457,6 +4473,7 @@ def test_ap_wpa2_eap_tls_domain_suffix_match_cn_full(dev, apdev): def test_ap_wpa2_eap_tls_domain_match_cn(dev, apdev): """WPA2-Enterprise using EAP-TLS and domainmatch (CN)""" check_domain_match(dev[0]) + check_pkcs12_support(dev[0]) params = int_eap_server_params() params["server_cert"] = "auth_serv/server-no-dnsname.pem" params["private_key"] = "auth_serv/server-no-dnsname.key" @@ -4471,6 +4488,7 @@ def test_ap_wpa2_eap_tls_domain_match_cn(dev, apdev): def test_ap_wpa2_eap_tls_domain_suffix_match_cn(dev, apdev): """WPA2-Enterprise using EAP-TLS and domain suffix match (CN)""" check_domain_match_full(dev[0]) + check_pkcs12_support(dev[0]) params = int_eap_server_params() params["server_cert"] = "auth_serv/server-no-dnsname.pem" params["private_key"] = "auth_serv/server-no-dnsname.key" @@ -4485,6 +4503,7 @@ def test_ap_wpa2_eap_tls_domain_suffix_match_cn(dev, apdev): def test_ap_wpa2_eap_tls_domain_suffix_mismatch_cn(dev, apdev): """WPA2-Enterprise using EAP-TLS and domain suffix mismatch (CN)""" check_domain_suffix_match(dev[0]) + check_pkcs12_support(dev[0]) params = int_eap_server_params() params["server_cert"] = "auth_serv/server-no-dnsname.pem" params["private_key"] = "auth_serv/server-no-dnsname.key" @@ -4513,6 +4532,7 @@ def test_ap_wpa2_eap_tls_domain_suffix_mismatch_cn(dev, apdev): def test_ap_wpa2_eap_tls_domain_mismatch_cn(dev, apdev): """WPA2-Enterprise using EAP-TLS and domain mismatch (CN)""" check_domain_match(dev[0]) + check_pkcs12_support(dev[0]) params = int_eap_server_params() params["server_cert"] = "auth_serv/server-no-dnsname.pem" params["private_key"] = "auth_serv/server-no-dnsname.key" @@ -5304,6 +5324,11 @@ def test_ap_wpa2_eap_tls_versions(dev, apdev): check_tls_ver(dev[0], hapd, "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1", "TLSv1.2") + if tls.startswith("wolfSSL"): + if "build=3.10.0" in tls and "run=3.10.0" in tls: + check_tls_ver(dev[0], hapd, + "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1", + "TLSv1.2") elif tls.startswith("internal"): check_tls_ver(dev[0], hapd, "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1", "TLSv1.2") @@ -5351,7 +5376,7 @@ def test_rsn_ie_proto_eap_sta(dev, apdev): def check_tls_session_resumption_capa(dev, hapd): tls = hapd.request("GET tls_library") if not tls.startswith("OpenSSL"): - raise HwsimSkip("hostapd TLS library is not OpenSSL: " + tls) + raise HwsimSkip("hostapd TLS library is not OpenSSL or wolfSSL: " + tls) tls = dev.request("GET tls_library") if not tls.startswith("OpenSSL"): @@ -5497,6 +5522,7 @@ def test_eap_ttls_no_session_resumption(dev, apdev): def test_eap_peap_session_resumption(dev, apdev): """EAP-PEAP session resumption""" + check_eap_capa(dev[0], "MSCHAPV2") params = int_eap_server_params() params['tls_session_lifetime'] = '60' hapd = hostapd.add_ap(apdev[0], params) diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 4431755..efa9b90 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -93,8 +93,12 @@ endif ifdef CONFIG_FIPS CONFIG_NO_RANDOM_POOL= +ifeq ($(CONFIG_TLS), wolfssl) +CONFIG_WOLFSSL_CMAC=y +else CONFIG_OPENSSL_CMAC=y endif +endif OBJS = config.o OBJS += notify.o @@ -709,6 +713,9 @@ endif ifdef CONFIG_EAP_PWD CFLAGS += -DEAP_PWD +ifeq ($(CONFIG_TLS), wolfssl) +CFLAGS += -DCONFIG_ECC +endif OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o CONFIG_IEEE8021X_EAPOL=y NEED_SHA256=y @@ -1054,6 +1061,22 @@ CFLAGS += -DCONFIG_TLSV12 NEED_SHA256=y endif +ifeq ($(CONFIG_TLS), wolfssl) +CONFIG_WOLFSSL_CMAC=y +CFLAGS += -DCRYPTO_ABSTRACT_API +ifdef TLS_FUNCS +CFLAGS += -DWOLFSSL_DER_LOAD -I/usr/local/include/wolfssl +OBJS += ../src/crypto/tls_wolfssl.o +endif +OBJS += ../src/crypto/crypto_wolfssl.o +OBJS_p += ../src/crypto/crypto_wolfssl.o +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_wolfssl.o +endif +LIBS += -lwolfssl -lm +LIBS_p += -lwolfssl -lm +endif + ifeq ($(CONFIG_TLS), openssl) ifdef TLS_FUNCS CFLAGS += -DEAP_TLS_OPENSSL @@ -1274,8 +1297,10 @@ AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-dec.o endif ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) NEED_INTERNAL_AES_WRAP=y endif +endif ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP # Seems to be needed at least with BoringSSL NEED_INTERNAL_AES_WRAP=y @@ -1314,10 +1339,21 @@ ifdef CONFIG_OPENSSL_CMAC CFLAGS += -DCONFIG_OPENSSL_CMAC else ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) AESOBJS += ../src/crypto/aes-omac1.o endif endif endif +ifdef CONFIG_WOLFSSL_CMAC +CFLAGS += -DCONFIG_WOLFSSL_CMAC +else +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) +AESOBJS += ../src/crypto/aes-omac1.o +endif +endif +endif +endif ifdef NEED_AES_WRAP NEED_AES_ENC=y ifdef NEED_INTERNAL_AES_WRAP @@ -1328,10 +1364,12 @@ ifdef NEED_AES_CBC NEED_AES_ENC=y ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) AESOBJS += ../src/crypto/aes-cbc.o endif endif endif +endif ifdef NEED_AES_ENC ifdef CONFIG_INTERNAL_AES AESOBJS += ../src/crypto/aes-internal-enc.o @@ -1345,10 +1383,12 @@ ifdef NEED_SHA1 ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) SHA1OBJS += ../src/crypto/sha1.o endif endif endif +endif SHA1OBJS += ../src/crypto/sha1-prf.o ifdef CONFIG_INTERNAL_SHA1 SHA1OBJS += ../src/crypto/sha1-internal.o @@ -1360,9 +1400,11 @@ ifdef CONFIG_NO_WPA_PASSPHRASE CFLAGS += -DCONFIG_NO_PBKDF2 else ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) SHA1OBJS += ../src/crypto/sha1-pbkdf2.o endif endif +endif ifdef NEED_T_PRF SHA1OBJS += ../src/crypto/sha1-tprf.o endif @@ -1375,11 +1417,13 @@ ifndef CONFIG_FIPS ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) MD5OBJS += ../src/crypto/md5.o endif endif endif endif +endif ifdef NEED_MD5 ifdef CONFIG_INTERNAL_MD5 MD5OBJS += ../src/crypto/md5-internal.o @@ -1397,6 +1441,9 @@ endif DESOBJS = # none needed when not internal ifdef NEED_DES +ifndef CONFIG_FIPS +CFLAGS += -DCONFIG_DES +endif ifdef CONFIG_INTERNAL_DES DESOBJS += ../src/crypto/des-internal.o endif @@ -1420,10 +1467,12 @@ CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) SHA256OBJS += ../src/crypto/sha256.o endif endif endif +endif SHA256OBJS += ../src/crypto/sha256-prf.o ifdef CONFIG_INTERNAL_SHA256 SHA256OBJS += ../src/crypto/sha256-internal.o @@ -1457,10 +1506,12 @@ ifdef NEED_SHA384 ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) OBJS += ../src/crypto/sha384.o endif endif endif +endif CFLAGS += -DCONFIG_SHA384 OBJS += ../src/crypto/sha384-prf.o endif @@ -1668,9 +1719,11 @@ endif ifdef CONFIG_FIPS CFLAGS += -DCONFIG_FIPS ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) $(error CONFIG_FIPS=y requires CONFIG_TLS=openssl) endif endif +endif OBJS += $(SHA1OBJS) $(DESOBJS)