Cumulative patch from commit bf3214b59321f67375df1ee85722b2beb74e1f7a
bf3214b P2P: Fix re-invoked client interface completion on data connection
63502c6 P2P: Fix P2P_CANCEL for p2p_in_invitation case
e007d53 EST: Comment out X509_REQ_print calls on Android with BoringSSL
e6f4832 EST: Add CSR generation support with BoringSSL
ed2566a EST: Implement pkcs7_to_cert() with BoringSSL
8d27efa HTTP (curl): OCSP with BoringSSL
213e158 BoringSSL: Move OCSP implementation into a separate file
f846211 BoringSSL: Support new SHA_CTX definition for EAP-SIM PRF
b34c623 OpenSSL: Fix build with current OpenSSL master branch snapshot
759a8a3 nl80211: Cancel all pending TX frame cookies
9ea91cd EAP-EKE peer: Fix memory leak on error path
328f49a P2P: Complete group formation on client data connection
0e559dc WPS: Support parallel UPnP WPS protocol runs
bea48f7 Allow sched_scan_plans to be updated at runtime
32c0226 Add support for configuring scheduled scan plans
09ea430 nl80211: Add support for multiple scan plans for scheduled scan
dd895e9 P2P: Make p2p_go_configured() more robust against unexpected calls
8811988 TLS client: Fix session_resumed status after TLS session ticket use
7fff91a Fix tls_connection_prf() regression with CONFIG_TLS=internal
1adf262 TLS: Add support for extKeyUsage X.509v3 extension
0755577 Add TEST_FAIL() support for internal hash functions
4104267 Fix memory leak on NFC DH generation error path
c5864dc TLS client: Add certificate chain validation failure callbacks
896a97d TLS client: Add support for disabling TLS versions
0cbc22b TLS client: Use TLS_CONN_* flags
20804fe TLS: Add support for tls_get_version()
f2a6ad0 TLS client: Add support for server certificate probing
b115eeb TLS: Add TLS v1.2 signature algorithm support for SHA384 and SHA512
c0acec3 crypto: Add CRYPTO_HASH_ALG_SHA384 and CRYPTO_HASH_ALG_SHA512
0aed915 TLS client: Add signature_algorithms extension into ClientHello
9e8809a TLS client: Validate certificates with SHA384 and SHA512 hashes
6bb6a9c Add SHA384 and SHA512 implementations from LibTomCrypt library
fdc1614 TLS client: Add support for validating server certificate hash
3665776 TLS client: Do not verify CA certificates when ca_cert is not specified
11c9ddb Add TEST_FAIL() condition to aes_128_cbc_encrypt/decrypt()
ea52a46 EAP-SIM peer: Fix memory leak on reauth error path
1a33c94 EAP-SAKE: Fix a typo in attribute parser debug print
53401e9 Abort ongoing scans on FLUSH command
e929eb3 wlantest: Add -N command line argument to remove write buffering
3c41749 hostapd: Add Transmit Power Envelope IE when VHT is enabled
2ea2166 Add control interface command for aborting an ongoing scan
4ead7cf Abort an ongoing scan before connect
4f30add nl80211: Add support for aborting an ongoing scan
5ef0b84 Sync with mac80211-next.git include/uapi/linux/nl80211.h
0530eb1 mesh: Clear wpa_s cipher selection on starting mesh
1d6955e nl80211: Fix SIGNAL_POLL in IBSS and mesh
0f29bc6 IBSS/mesh: Add support for VHT80P80 configuration
c27f4c9 P2P: Add support for VHT 80+80 MHz and 160 MHz
bee5d8e nl80211: Add VHT 160 MHz channel flags
5e1da9c P2P: Define operating classes for VHT 80+80 and 160
ea70811 FST: Improve parsing of Multiband IEs
b47d05a FST: Make FST peer connection check more permissive in hostapd
39c3c9b Remove wpa_supplicant/tests
9b635d0 Remove link_test and test_wpa
9e68742 Fix CONFIG_NO_WPA=y build
eb926f1 Comment out wpas_reenabled_network_time with CONFIG_NO_SCAN_PROCESSING
f231b3d FST: Fix STA MB IEs creation
ed7820b P2P: Add a testing option to force P2P GO CSA
6cbbae2 P2P: Set p2p_go_wait_client in invitation_result() cb
83702b6 Android: Give user the option for selecting browser for HS 2.0 OSU
cadffac wpa_cli: Add an option to set created interface type
0f039e3 Add an option to create interface of a certain type with INTERFACE_ADD
d8a3b66 driver: Make setting up AP optional when creating AP interface
36e8206 Check for LIBRESSL_VERSION_NUMBER in tls_openssl.c
2c51c0b P2P: Clear send action work without waiting on find/stop/listen
6bdc43c AP: Avoid 20/40 MHz co-ex scan if PRI/SEC switch is not allowed
757785d nl80211: Clear ignore_next_local_deauth flag
cb2a926 nl80211: Clear ignore_next_local_deauth and ignore_deauth_event
f32227e Add QCA vendor attribute and event to indicate subnet change status
d38c7be Skip SELECT_NETWORK steps only if already connected or connecting
25eb7fc Fix EAPOL reauth after FT protocol or offloaded PMKSA cache use
f68d491 FT auth: Fix EAPOL reauthentication after FT protocol run
a65efbf Add VHT support for Mesh
a73c984 Set WMM flag to Mesh STA by default
9a8d9f7 Assign QCA vendor command and attribute for Tx power reduction in dB
747ba10 nl80211: Do not return incomplete hw capability info
5e238cc WPS: Reconnect for a failed data connection when STA_AUTOCONNECT is 0
442cc8c dbus: Fix memory leak in sending InvitationReceived signal
0603bcb hostapd: Process MAC ACLs on a station association event (SME in driver)
89a11ad RSN: Remove check for proactive_key_caching while setting PMK offload
d381963 Extend QCA roam event with subnet change indication
Change-Id: I122220f59ef56e25ed2749a37370a40afafa177a
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index 3e90350..d181e72 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -47,7 +47,9 @@
sha256.o \
sha256-prf.o \
sha256-tlsprf.o \
- sha256-internal.o
+ sha256-internal.o \
+ sha384-internal.o \
+ sha512-internal.o
LIB_OBJS += crypto_internal.o
LIB_OBJS += crypto_internal-cipher.o
diff --git a/src/crypto/aes-cbc.c b/src/crypto/aes-cbc.c
index 2833cfc..0835f2c 100644
--- a/src/crypto/aes-cbc.c
+++ b/src/crypto/aes-cbc.c
@@ -28,6 +28,9 @@
u8 *pos = data;
int i, j, blocks;
+ if (TEST_FAIL())
+ return -1;
+
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
@@ -61,6 +64,9 @@
u8 *pos = data;
int i, j, blocks;
+ if (TEST_FAIL())
+ return -1;
+
ctx = aes_decrypt_init(key, 16);
if (ctx == NULL)
return -1;
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 534c4bd..bdc3ba6 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -80,6 +80,28 @@
u8 *mac);
/**
+ * sha384_vector - SHA384 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac);
+
+/**
+ * sha512_vector - SHA512 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac);
+
+/**
* des_encrypt - Encrypt one block with DES
* @clear: 8 octets (in)
* @key: 7 octets (in) (no parity bits included)
@@ -135,7 +157,8 @@
enum crypto_hash_alg {
CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
- CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
+ CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256,
+ CRYPTO_HASH_ALG_SHA384, CRYPTO_HASH_ALG_SHA512
};
struct crypto_hash;
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index f3602da..d391f48 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -11,6 +11,8 @@
#include "common.h"
#include "crypto.h"
#include "sha256_i.h"
+#include "sha384_i.h"
+#include "sha512_i.h"
#include "sha1_i.h"
#include "md5_i.h"
@@ -22,6 +24,12 @@
#ifdef CONFIG_SHA256
struct sha256_state sha256;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ struct sha384_state sha384;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ struct sha512_state sha512;
+#endif /* CONFIG_INTERNAL_SHA512 */
} u;
u8 key[64];
size_t key_len;
@@ -54,6 +62,16 @@
sha256_init(&ctx->u.sha256);
break;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ case CRYPTO_HASH_ALG_SHA384:
+ sha384_init(&ctx->u.sha384);
+ break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ case CRYPTO_HASH_ALG_SHA512:
+ sha512_init(&ctx->u.sha512);
+ break;
+#endif /* CONFIG_INTERNAL_SHA512 */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (key_len > sizeof(k_pad)) {
MD5Init(&ctx->u.md5);
@@ -142,6 +160,16 @@
sha256_process(&ctx->u.sha256, data, len);
break;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ case CRYPTO_HASH_ALG_SHA384:
+ sha384_process(&ctx->u.sha384, data, len);
+ break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ case CRYPTO_HASH_ALG_SHA512:
+ sha512_process(&ctx->u.sha512, data, len);
+ break;
+#endif /* CONFIG_INTERNAL_SHA512 */
default:
break;
}
@@ -191,6 +219,28 @@
sha256_done(&ctx->u.sha256, mac);
break;
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_INTERNAL_SHA384
+ case CRYPTO_HASH_ALG_SHA384:
+ if (*len < 48) {
+ *len = 48;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 48;
+ sha384_done(&ctx->u.sha384, mac);
+ break;
+#endif /* CONFIG_INTERNAL_SHA384 */
+#ifdef CONFIG_INTERNAL_SHA512
+ case CRYPTO_HASH_ALG_SHA512:
+ if (*len < 64) {
+ *len = 64;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 64;
+ sha512_done(&ctx->u.sha512, mac);
+ break;
+#endif /* CONFIG_INTERNAL_SHA512 */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (*len < 16) {
*len = 16;
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
index 2b19a4a..087953b 100644
--- a/src/crypto/crypto_module_tests.c
+++ b/src/crypto/crypto_module_tests.c
@@ -1605,6 +1605,35 @@
}
+static int test_fips186_2_prf(void)
+{
+ /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
+ u8 xkey[] = {
+ 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
+ 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
+ 0xeb, 0x5a, 0x38, 0xb6
+ };
+ u8 w[] = {
+ 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
+ 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
+ 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
+ 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
+ 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
+ };
+ u8 buf[40];
+
+ wpa_printf(MSG_INFO,
+ "Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)");
+ if (fips186_2_prf(xkey, sizeof(xkey), buf, sizeof(buf)) < 0 ||
+ os_memcmp(w, buf, sizeof(w)) != 0) {
+ wpa_printf(MSG_INFO, "fips186_2_prf failed");
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int test_ms_funcs(void)
{
#ifndef CONFIG_FIPS
@@ -1721,6 +1750,7 @@
test_md5() ||
test_sha1() ||
test_sha256() ||
+ test_fips186_2_prf() ||
test_ms_funcs())
ret = -1;
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 9e344d1..ad2d2d4 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -345,6 +345,9 @@
int clen, len;
u8 buf[16];
+ if (TEST_FAIL())
+ return -1;
+
EVP_CIPHER_CTX_init(&ctx);
if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
return -1;
@@ -370,6 +373,9 @@
int plen, len;
u8 buf[16];
+ if (TEST_FAIL())
+ return -1;
+
EVP_CIPHER_CTX_init(&ctx);
if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
return -1;
diff --git a/src/crypto/dh_group5.c b/src/crypto/dh_group5.c
index ccdbfc8..425c848 100644
--- a/src/crypto/dh_group5.c
+++ b/src/crypto/dh_group5.c
@@ -15,6 +15,7 @@
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
+ wpabuf_free(*publ);
*publ = dh_init(dh_groups_get(5), priv);
if (*publ == NULL)
return NULL;
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index 3aeb2bb..7912361 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1218,14 +1218,19 @@
pv_len = dh->prime_len;
pv = wpabuf_alloc(pv_len);
- if (pv == NULL)
+ if (pv == NULL) {
+ wpabuf_clear_free(*priv);
+ *priv = NULL;
return NULL;
+ }
if (crypto_mod_exp(dh->generator, dh->generator_len,
wpabuf_head(*priv), wpabuf_len(*priv),
dh->prime, dh->prime_len, wpabuf_mhead(pv),
&pv_len) < 0) {
wpabuf_clear_free(pv);
wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+ wpabuf_clear_free(*priv);
+ *priv = NULL;
return NULL;
}
wpabuf_put(pv, pv_len);
diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c
index fb03efc..9d094b8 100644
--- a/src/crypto/fips_prf_openssl.c
+++ b/src/crypto/fips_prf_openssl.c
@@ -17,6 +17,19 @@
{
SHA_CTX context;
os_memset(&context, 0, sizeof(context));
+#if defined(OPENSSL_IS_BORINGSSL) && !defined(ANDROID)
+ context.h[0] = state[0];
+ context.h[1] = state[1];
+ context.h[2] = state[2];
+ context.h[3] = state[3];
+ context.h[4] = state[4];
+ SHA1_Transform(&context, data);
+ state[0] = context.h[0];
+ state[1] = context.h[1];
+ state[2] = context.h[2];
+ state[3] = context.h[3];
+ state[4] = context.h[4];
+#else
context.h0 = state[0];
context.h1 = state[1];
context.h2 = state[2];
@@ -28,6 +41,7 @@
state[2] = context.h2;
state[3] = context.h3;
state[4] = context.h4;
+#endif
}
diff --git a/src/crypto/md4-internal.c b/src/crypto/md4-internal.c
index cd5e6ca..d9c737a 100644
--- a/src/crypto/md4-internal.c
+++ b/src/crypto/md4-internal.c
@@ -31,6 +31,9 @@
MD4_CTX ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
MD4Init(&ctx);
for (i = 0; i < num_elem; i++)
MD4Update(&ctx, addr[i], len[i]);
diff --git a/src/crypto/md5-internal.c b/src/crypto/md5-internal.c
index f0a2a5d..944698a 100644
--- a/src/crypto/md5-internal.c
+++ b/src/crypto/md5-internal.c
@@ -33,6 +33,9 @@
MD5_CTX ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
MD5Init(&ctx);
for (i = 0; i < num_elem; i++)
MD5Update(&ctx, addr[i], len[i]);
diff --git a/src/crypto/sha1-internal.c b/src/crypto/sha1-internal.c
index 24bc3ff..f6658e6 100644
--- a/src/crypto/sha1-internal.c
+++ b/src/crypto/sha1-internal.c
@@ -33,6 +33,9 @@
SHA1_CTX ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
SHA1Init(&ctx);
for (i = 0; i < num_elem; i++)
SHA1Update(&ctx, addr[i], len[i]);
diff --git a/src/crypto/sha256-internal.c b/src/crypto/sha256-internal.c
index 35299b0..86a548e 100644
--- a/src/crypto/sha256-internal.c
+++ b/src/crypto/sha256-internal.c
@@ -28,6 +28,9 @@
struct sha256_state ctx;
size_t i;
+ if (TEST_FAIL())
+ return -1;
+
sha256_init(&ctx);
for (i = 0; i < num_elem; i++)
if (sha256_process(&ctx, addr[i], len[i]))
diff --git a/src/crypto/sha384-internal.c b/src/crypto/sha384-internal.c
new file mode 100644
index 0000000..646f729
--- /dev/null
+++ b/src/crypto/sha384-internal.c
@@ -0,0 +1,92 @@
+/*
+ * SHA-384 hash implementation and interface functions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384_i.h"
+#include "crypto.h"
+
+
+/**
+ * sha384_vector - SHA384 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ struct sha384_state ctx;
+ size_t i;
+
+ sha384_init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ if (sha384_process(&ctx, addr[i], len[i]))
+ return -1;
+ if (sha384_done(&ctx, mac))
+ return -1;
+ return 0;
+}
+
+
+/* ===== start - public domain SHA384 implementation ===== */
+
+/* This is based on SHA384 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define CONST64(n) n ## ULL
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+void sha384_init(struct sha384_state *md)
+{
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = CONST64(0xcbbb9d5dc1059ed8);
+ md->state[1] = CONST64(0x629a292a367cd507);
+ md->state[2] = CONST64(0x9159015a3070dd17);
+ md->state[3] = CONST64(0x152fecd8f70e5939);
+ md->state[4] = CONST64(0x67332667ffc00b31);
+ md->state[5] = CONST64(0x8eb44a8768581511);
+ md->state[6] = CONST64(0xdb0c2e0d64f98fa7);
+ md->state[7] = CONST64(0x47b5481dbefa4fa4);
+}
+
+int sha384_process(struct sha384_state *md, const unsigned char *in,
+ unsigned long inlen)
+{
+ return sha512_process(md, in, inlen);
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (48 bytes)
+ @return CRYPT_OK if successful
+*/
+int sha384_done(struct sha384_state *md, unsigned char *out)
+{
+ unsigned char buf[64];
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ if (sha512_done(md, buf) != 0)
+ return -1;
+
+ os_memcpy(out, buf, 48);
+ return 0;
+}
+
+/* ===== end - public domain SHA384 implementation ===== */
diff --git a/src/crypto/sha384_i.h b/src/crypto/sha384_i.h
new file mode 100644
index 0000000..a00253f
--- /dev/null
+++ b/src/crypto/sha384_i.h
@@ -0,0 +1,23 @@
+/*
+ * SHA-384 internal definitions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA384_I_H
+#define SHA384_I_H
+
+#include "sha512_i.h"
+
+#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE
+
+#define sha384_state sha512_state
+
+void sha384_init(struct sha384_state *md);
+int sha384_process(struct sha384_state *md, const unsigned char *in,
+ unsigned long inlen);
+int sha384_done(struct sha384_state *md, unsigned char *out);
+
+#endif /* SHA384_I_H */
diff --git a/src/crypto/sha512-internal.c b/src/crypto/sha512-internal.c
new file mode 100644
index 0000000..66ef331
--- /dev/null
+++ b/src/crypto/sha512-internal.c
@@ -0,0 +1,264 @@
+/*
+ * SHA-512 hash implementation and interface functions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha512_i.h"
+#include "crypto.h"
+
+
+/**
+ * sha512_vector - SHA512 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ struct sha512_state ctx;
+ size_t i;
+
+ sha512_init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ if (sha512_process(&ctx, addr[i], len[i]))
+ return -1;
+ if (sha512_done(&ctx, mac))
+ return -1;
+ return 0;
+}
+
+
+/* ===== start - public domain SHA512 implementation ===== */
+
+/* This is based on SHA512 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define CONST64(n) n ## ULL
+
+/* the K array */
+static const u64 K[80] = {
+ CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
+ CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
+ CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
+ CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
+ CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
+ CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
+ CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
+ CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
+ CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
+ CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
+ CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
+ CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
+ CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
+ CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
+ CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
+ CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
+ CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
+ CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
+ CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
+ CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
+ CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
+ CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
+ CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
+ CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
+ CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
+ CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
+ CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
+ CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
+ CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
+ CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
+ CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
+ CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
+ CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
+ CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
+ CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
+ CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
+ CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
+ CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
+ CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
+ CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)
+};
+
+/* Various logical functions */
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) ROR64c(x, n)
+#define R(x, n) (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) n))
+#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
+#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
+#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
+#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+#define ROR64c(x, y) \
+ ( ((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) (y) & CONST64(63))) | \
+ ((x) << ((u64) (64 - ((y) & CONST64(63)))))) & \
+ CONST64(0xFFFFFFFFFFFFFFFF))
+
+/* compress 1024-bits */
+static int sha512_compress(struct sha512_state *md, unsigned char *buf)
+{
+ u64 S[8], W[80], t0, t1;
+ int i;
+
+ /* copy state into S */
+ for (i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+
+ /* copy the state into 1024-bits into W[0..15] */
+ for (i = 0; i < 16; i++)
+ W[i] = WPA_GET_BE64(buf + (8 * i));
+
+ /* fill W[16..79] */
+ for (i = 16; i < 80; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+ W[i - 16];
+ }
+
+ /* Compress */
+ for (i = 0; i < 80; i++) {
+ t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i];
+ t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]);
+ S[7] = S[6];
+ S[6] = S[5];
+ S[5] = S[4];
+ S[4] = S[3] + t0;
+ S[3] = S[2];
+ S[2] = S[1];
+ S[1] = S[0];
+ S[0] = t0 + t1;
+ }
+
+ /* feedback */
+ for (i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+
+ return 0;
+}
+
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+void sha512_init(struct sha512_state *md)
+{
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = CONST64(0x6a09e667f3bcc908);
+ md->state[1] = CONST64(0xbb67ae8584caa73b);
+ md->state[2] = CONST64(0x3c6ef372fe94f82b);
+ md->state[3] = CONST64(0xa54ff53a5f1d36f1);
+ md->state[4] = CONST64(0x510e527fade682d1);
+ md->state[5] = CONST64(0x9b05688c2b3e6c1f);
+ md->state[6] = CONST64(0x1f83d9abfb41bd6b);
+ md->state[7] = CONST64(0x5be0cd19137e2179);
+}
+
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+int sha512_process(struct sha512_state *md, const unsigned char *in,
+ unsigned long inlen)
+{
+ unsigned long n;
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= SHA512_BLOCK_SIZE) {
+ if (sha512_compress(md, (unsigned char *) in) < 0)
+ return -1;
+ md->length += SHA512_BLOCK_SIZE * 8;
+ in += SHA512_BLOCK_SIZE;
+ inlen -= SHA512_BLOCK_SIZE;
+ } else {
+ n = MIN(inlen, (SHA512_BLOCK_SIZE - md->curlen));
+ os_memcpy(md->buf + md->curlen, in, n);
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == SHA512_BLOCK_SIZE) {
+ if (sha512_compress(md, md->buf) < 0)
+ return -1;
+ md->length += 8 * SHA512_BLOCK_SIZE;
+ md->curlen = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (64 bytes)
+ @return CRYPT_OK if successful
+*/
+int sha512_done(struct sha512_state *md, unsigned char *out)
+{
+ int i;
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ /* increase the length of the message */
+ md->length += md->curlen * CONST64(8);
+
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char) 0x80;
+
+ /* if the length is currently above 112 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 112) {
+ while (md->curlen < 128) {
+ md->buf[md->curlen++] = (unsigned char) 0;
+ }
+ sha512_compress(md, md->buf);
+ md->curlen = 0;
+ }
+
+ /* pad upto 120 bytes of zeroes
+ * note: that from 112 to 120 is the 64 MSB of the length. We assume
+ * that you won't hash > 2^64 bits of data... :-)
+ */
+ while (md->curlen < 120) {
+ md->buf[md->curlen++] = (unsigned char) 0;
+ }
+
+ /* store length */
+ WPA_PUT_BE64(md->buf + 120, md->length);
+ sha512_compress(md, md->buf);
+
+ /* copy output */
+ for (i = 0; i < 8; i++)
+ WPA_PUT_BE64(out + (8 * i), md->state[i]);
+
+ return 0;
+}
+
+/* ===== end - public domain SHA512 implementation ===== */
diff --git a/src/crypto/sha512_i.h b/src/crypto/sha512_i.h
new file mode 100644
index 0000000..1089589
--- /dev/null
+++ b/src/crypto/sha512_i.h
@@ -0,0 +1,25 @@
+/*
+ * SHA-512 internal definitions
+ * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA512_I_H
+#define SHA512_I_H
+
+#define SHA512_BLOCK_SIZE 128
+
+struct sha512_state {
+ u64 length, state[8];
+ u32 curlen;
+ u8 buf[SHA512_BLOCK_SIZE];
+};
+
+void sha512_init(struct sha512_state *md);
+int sha512_process(struct sha512_state *md, const unsigned char *in,
+ unsigned long inlen);
+int sha512_done(struct sha512_state *md, unsigned char *out);
+
+#endif /* SHA512_I_H */
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 1b82245..dcbb31d 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -23,6 +23,11 @@
int server;
struct tlsv1_credentials *server_cred;
int check_crl;
+
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data);
+ void *cb_ctx;
+ int cert_in_cb;
};
struct tls_connection {
@@ -51,6 +56,11 @@
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
+ if (conf) {
+ global->event_cb = conf->event_cb;
+ global->cb_ctx = conf->cb_ctx;
+ global->cert_in_cb = conf->cert_in_cb;
+ }
return global;
}
@@ -97,6 +107,8 @@
os_free(conn);
return NULL;
}
+ tlsv1_client_set_cb(conn->client, global->event_cb,
+ global->cb_ctx, global->cert_in_cb);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
@@ -261,8 +273,7 @@
return -1;
}
- tlsv1_client_set_time_checks(
- conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
+ tlsv1_client_set_flags(conn->client, params->flags);
return 0;
#else /* CONFIG_TLS_INTERNAL_CLIENT */
@@ -392,14 +403,14 @@
if (conn->client) {
ret = tlsv1_client_prf(conn->client, label,
server_random_first,
- _out, out_len);
+ _out, skip + out_len);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
ret = tlsv1_server_prf(conn->server, label,
server_random_first,
- _out, out_len);
+ _out, skip + out_len);
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
if (ret == 0 && skip_keyblock)
@@ -623,7 +634,12 @@
int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- /* TODO */
+ if (conn == NULL)
+ return -1;
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_get_version(conn->client, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
return -1;
}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index c2bb8c5..471ae2b 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -30,16 +30,12 @@
#include <openssl/dh.h>
#endif
-#ifdef OPENSSL_IS_BORINGSSL
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
-#endif /* OPENSSL_IS_BORINGSSL */
-
#include "common.h"
#include "crypto.h"
#include "sha1.h"
#include "sha256.h"
#include "tls.h"
+#include "tls_openssl.h"
#if OPENSSL_VERSION_NUMBER < 0x10000000L
/* ERR_remove_thread_state replaces ERR_remove_state and the latter is
@@ -1654,819 +1650,6 @@
}
-#ifdef OPENSSL_IS_BORINGSSL
-
-/*
- * CertID ::= SEQUENCE {
- * hashAlgorithm AlgorithmIdentifier,
- * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
- * issuerKeyHash OCTET STRING, -- Hash of Issuer's public key
- * serialNumber CertificateSerialNumber }
- */
-typedef struct {
- X509_ALGOR *hashAlgorithm;
- ASN1_OCTET_STRING *issuerNameHash;
- ASN1_OCTET_STRING *issuerKeyHash;
- ASN1_INTEGER *serialNumber;
-} CertID;
-
-/*
- * ResponseBytes ::= SEQUENCE {
- * responseType OBJECT IDENTIFIER,
- * response OCTET STRING }
- */
-typedef struct {
- ASN1_OBJECT *responseType;
- ASN1_OCTET_STRING *response;
-} ResponseBytes;
-
-/*
- * OCSPResponse ::= SEQUENCE {
- * responseStatus OCSPResponseStatus,
- * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
- */
-typedef struct {
- ASN1_ENUMERATED *responseStatus;
- ResponseBytes *responseBytes;
-} OCSPResponse;
-
-ASN1_SEQUENCE(ResponseBytes) = {
- ASN1_SIMPLE(ResponseBytes, responseType, ASN1_OBJECT),
- ASN1_SIMPLE(ResponseBytes, response, ASN1_OCTET_STRING)
-} ASN1_SEQUENCE_END(ResponseBytes);
-
-ASN1_SEQUENCE(OCSPResponse) = {
- ASN1_SIMPLE(OCSPResponse, responseStatus, ASN1_ENUMERATED),
- ASN1_EXP_OPT(OCSPResponse, responseBytes, ResponseBytes, 0)
-} ASN1_SEQUENCE_END(OCSPResponse);
-
-IMPLEMENT_ASN1_FUNCTIONS(OCSPResponse);
-
-/*
- * ResponderID ::= CHOICE {
- * byName [1] Name,
- * byKey [2] KeyHash }
- */
-typedef struct {
- int type;
- union {
- X509_NAME *byName;
- ASN1_OCTET_STRING *byKey;
- } value;
-} ResponderID;
-
-/*
- * RevokedInfo ::= SEQUENCE {
- * revocationTime GeneralizedTime,
- * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
- */
-typedef struct {
- ASN1_GENERALIZEDTIME *revocationTime;
- ASN1_ENUMERATED *revocationReason;
-} RevokedInfo;
-
-/*
- * CertStatus ::= CHOICE {
- * good [0] IMPLICIT NULL,
- * revoked [1] IMPLICIT RevokedInfo,
- * unknown [2] IMPLICIT UnknownInfo }
- */
-typedef struct {
- int type;
- union {
- ASN1_NULL *good;
- RevokedInfo *revoked;
- ASN1_NULL *unknown;
- } value;
-} CertStatus;
-
-/*
- * SingleResponse ::= SEQUENCE {
- * certID CertID,
- * certStatus CertStatus,
- * thisUpdate GeneralizedTime,
- * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
- * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
- */
-typedef struct {
- CertID *certID;
- CertStatus *certStatus;
- ASN1_GENERALIZEDTIME *thisUpdate;
- ASN1_GENERALIZEDTIME *nextUpdate;
- STACK_OF(X509_EXTENSION) *singleExtensions;
-} SingleResponse;
-
-/*
- * ResponseData ::= SEQUENCE {
- * version [0] EXPLICIT Version DEFAULT v1,
- * responderID ResponderID,
- * producedAt GeneralizedTime,
- * responses SEQUENCE OF SingleResponse,
- * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
- */
-typedef struct {
- ASN1_INTEGER *version;
- ResponderID *responderID;
- ASN1_GENERALIZEDTIME *producedAt;
- STACK_OF(SingleResponse) *responses;
- STACK_OF(X509_EXTENSION) *responseExtensions;
-} ResponseData;
-
-/*
- * BasicOCSPResponse ::= SEQUENCE {
- * tbsResponseData ResponseData,
- * signatureAlgorithm AlgorithmIdentifier,
- * signature BIT STRING,
- * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
- */
-typedef struct {
- ResponseData *tbsResponseData;
- X509_ALGOR *signatureAlgorithm;
- ASN1_BIT_STRING *signature;
- STACK_OF(X509) *certs;
-} BasicOCSPResponse;
-
-ASN1_SEQUENCE(CertID) = {
- ASN1_SIMPLE(CertID, hashAlgorithm, X509_ALGOR),
- ASN1_SIMPLE(CertID, issuerNameHash, ASN1_OCTET_STRING),
- ASN1_SIMPLE(CertID, issuerKeyHash, ASN1_OCTET_STRING),
- ASN1_SIMPLE(CertID, serialNumber, ASN1_INTEGER)
-} ASN1_SEQUENCE_END(CertID);
-
-ASN1_CHOICE(ResponderID) = {
- ASN1_EXP(ResponderID, value.byName, X509_NAME, 1),
- ASN1_EXP(ResponderID, value.byKey, ASN1_OCTET_STRING, 2)
-} ASN1_CHOICE_END(ResponderID);
-
-ASN1_SEQUENCE(RevokedInfo) = {
- ASN1_SIMPLE(RevokedInfo, revocationTime, ASN1_GENERALIZEDTIME),
- ASN1_EXP_OPT(RevokedInfo, revocationReason, ASN1_ENUMERATED, 0)
-} ASN1_SEQUENCE_END(RevokedInfo);
-
-ASN1_CHOICE(CertStatus) = {
- ASN1_IMP(CertStatus, value.good, ASN1_NULL, 0),
- ASN1_IMP(CertStatus, value.revoked, RevokedInfo, 1),
- ASN1_IMP(CertStatus, value.unknown, ASN1_NULL, 2)
-} ASN1_CHOICE_END(CertStatus);
-
-ASN1_SEQUENCE(SingleResponse) = {
- ASN1_SIMPLE(SingleResponse, certID, CertID),
- ASN1_SIMPLE(SingleResponse, certStatus, CertStatus),
- ASN1_SIMPLE(SingleResponse, thisUpdate, ASN1_GENERALIZEDTIME),
- ASN1_EXP_OPT(SingleResponse, nextUpdate, ASN1_GENERALIZEDTIME, 0),
- ASN1_EXP_SEQUENCE_OF_OPT(SingleResponse, singleExtensions,
- X509_EXTENSION, 1)
-} ASN1_SEQUENCE_END(SingleResponse);
-
-ASN1_SEQUENCE(ResponseData) = {
- ASN1_EXP_OPT(ResponseData, version, ASN1_INTEGER, 0),
- ASN1_SIMPLE(ResponseData, responderID, ResponderID),
- ASN1_SIMPLE(ResponseData, producedAt, ASN1_GENERALIZEDTIME),
- ASN1_SEQUENCE_OF(ResponseData, responses, SingleResponse),
- ASN1_EXP_SEQUENCE_OF_OPT(ResponseData, responseExtensions,
- X509_EXTENSION, 1)
-} ASN1_SEQUENCE_END(ResponseData);
-
-ASN1_SEQUENCE(BasicOCSPResponse) = {
- ASN1_SIMPLE(BasicOCSPResponse, tbsResponseData, ResponseData),
- ASN1_SIMPLE(BasicOCSPResponse, signatureAlgorithm, X509_ALGOR),
- ASN1_SIMPLE(BasicOCSPResponse, signature, ASN1_BIT_STRING),
- ASN1_EXP_SEQUENCE_OF_OPT(BasicOCSPResponse, certs, X509, 0)
-} ASN1_SEQUENCE_END(BasicOCSPResponse);
-
-IMPLEMENT_ASN1_FUNCTIONS(BasicOCSPResponse);
-
-#define sk_SingleResponse_num(sk) \
-sk_num(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk))
-
-#define sk_SingleResponse_value(sk, i) \
- ((SingleResponse *) \
- sk_value(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk), (i)))
-
-
-static char * mem_bio_to_str(BIO *out)
-{
- char *txt;
- size_t rlen;
- int res;
-
- rlen = BIO_ctrl_pending(out);
- txt = os_malloc(rlen + 1);
- if (!txt) {
- BIO_free(out);
- return NULL;
- }
-
- res = BIO_read(out, txt, rlen);
- BIO_free(out);
- if (res < 0) {
- os_free(txt);
- return NULL;
- }
-
- txt[res] = '\0';
- return txt;
-}
-
-
-static char * generalizedtime_str(ASN1_GENERALIZEDTIME *t)
-{
- BIO *out;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return NULL;
-
- if (!ASN1_GENERALIZEDTIME_print(out, t)) {
- BIO_free(out);
- return NULL;
- }
-
- return mem_bio_to_str(out);
-}
-
-
-static char * responderid_str(ResponderID *rid)
-{
- BIO *out;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return NULL;
-
- switch (rid->type) {
- case 0:
- X509_NAME_print_ex(out, rid->value.byName, 0, XN_FLAG_ONELINE);
- break;
- case 1:
- i2a_ASN1_STRING(out, rid->value.byKey, V_ASN1_OCTET_STRING);
- break;
- default:
- BIO_free(out);
- return NULL;
- }
-
- return mem_bio_to_str(out);
-}
-
-
-static char * octet_string_str(ASN1_OCTET_STRING *o)
-{
- BIO *out;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return NULL;
-
- i2a_ASN1_STRING(out, o, V_ASN1_OCTET_STRING);
- return mem_bio_to_str(out);
-}
-
-
-static char * integer_str(ASN1_INTEGER *i)
-{
- BIO *out;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return NULL;
-
- i2a_ASN1_INTEGER(out, i);
- return mem_bio_to_str(out);
-}
-
-
-static char * algor_str(X509_ALGOR *alg)
-{
- BIO *out;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return NULL;
-
- i2a_ASN1_OBJECT(out, alg->algorithm);
- return mem_bio_to_str(out);
-}
-
-
-static char * extensions_str(const char *title, STACK_OF(X509_EXTENSION) *ext)
-{
- BIO *out;
-
- if (!ext)
- return NULL;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return NULL;
-
- if (!X509V3_extensions_print(out, title, ext, 0, 0)) {
- BIO_free(out);
- return NULL;
- }
- return mem_bio_to_str(out);
-}
-
-
-static int ocsp_resp_valid(ASN1_GENERALIZEDTIME *thisupd,
- ASN1_GENERALIZEDTIME *nextupd)
-{
- time_t now, tmp;
-
- if (!ASN1_GENERALIZEDTIME_check(thisupd)) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Invalid OCSP response thisUpdate");
- return 0;
- }
-
- time(&now);
- tmp = now + 5 * 60; /* allow five minute clock difference */
- if (X509_cmp_time(thisupd, &tmp) > 0) {
- wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response not yet valid");
- return 0;
- }
-
- if (!nextupd)
- return 1; /* OK - no limit on response age */
-
- if (!ASN1_GENERALIZEDTIME_check(nextupd)) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Invalid OCSP response nextUpdate");
- return 0;
- }
-
- tmp = now - 5 * 60; /* allow five minute clock difference */
- if (X509_cmp_time(nextupd, &tmp) < 0) {
- wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response expired");
- return 0;
- }
-
- if (ASN1_STRING_cmp(nextupd, thisupd) < 0) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: OCSP response nextUpdate before thisUpdate");
- return 0;
- }
-
- /* Both thisUpdate and nextUpdate are valid */
- return -1;
-}
-
-
-static int issuer_match(X509 *cert, X509 *issuer, CertID *certid)
-{
- X509_NAME *iname;
- ASN1_BIT_STRING *ikey;
- const EVP_MD *dgst;
- unsigned int len;
- unsigned char md[EVP_MAX_MD_SIZE];
- ASN1_OCTET_STRING *hash;
- char *txt;
-
- dgst = EVP_get_digestbyobj(certid->hashAlgorithm->algorithm);
- if (!dgst) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Could not find matching hash algorithm for OCSP");
- return -1;
- }
-
- iname = X509_get_issuer_name(cert);
- if (!X509_NAME_digest(iname, dgst, md, &len))
- return -1;
- hash = ASN1_OCTET_STRING_new();
- if (!hash)
- return -1;
- if (!ASN1_OCTET_STRING_set(hash, md, len)) {
- ASN1_OCTET_STRING_free(hash);
- return -1;
- }
-
- txt = octet_string_str(hash);
- if (txt) {
- wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerNameHash: %s",
- txt);
- os_free(txt);
- }
-
- if (ASN1_OCTET_STRING_cmp(certid->issuerNameHash, hash)) {
- ASN1_OCTET_STRING_free(hash);
- return -1;
- }
-
- ikey = X509_get0_pubkey_bitstr(issuer);
- if (!EVP_Digest(ikey->data, ikey->length, md, &len, dgst, NULL) ||
- !ASN1_OCTET_STRING_set(hash, md, len)) {
- ASN1_OCTET_STRING_free(hash);
- return -1;
- }
-
- txt = octet_string_str(hash);
- if (txt) {
- wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerKeyHash: %s",
- txt);
- os_free(txt);
- }
-
- if (ASN1_OCTET_STRING_cmp(certid->issuerKeyHash, hash)) {
- ASN1_OCTET_STRING_free(hash);
- return -1;
- }
-
- ASN1_OCTET_STRING_free(hash);
- return 0;
-}
-
-
-static X509 * ocsp_find_signer(STACK_OF(X509) *certs, ResponderID *rid)
-{
- unsigned int i;
- unsigned char hash[SHA_DIGEST_LENGTH];
-
- if (rid->type == 0) {
- /* byName */
- return X509_find_by_subject(certs, rid->value.byName);
- }
-
- /* byKey */
- if (rid->value.byKey->length != SHA_DIGEST_LENGTH)
- return NULL;
- for (i = 0; i < sk_X509_num(certs); i++) {
- X509 *x = sk_X509_value(certs, i);
-
- X509_pubkey_digest(x, EVP_sha1(), hash, NULL);
- if (os_memcmp(rid->value.byKey->data, hash,
- SHA_DIGEST_LENGTH) == 0)
- return x;
- }
-
- return NULL;
-}
-
-
-enum ocsp_result {
- OCSP_GOOD, OCSP_REVOKED, OCSP_NO_RESPONSE, OCSP_INVALID
-};
-
-static enum ocsp_result check_ocsp_resp(struct tls_connection *conn,
- X509 *cert, X509 *issuer)
-{
- const uint8_t *resp_data;
- size_t resp_len;
- OCSPResponse *resp;
- int status;
- ResponseBytes *bytes;
- const u8 *basic_data;
- size_t basic_len;
- BasicOCSPResponse *basic;
- ResponseData *rd;
- char *txt;
- int i, num;
- unsigned int j, num_resp;
- SingleResponse *matching_resp = NULL, *cmp_sresp;
- enum ocsp_result result = OCSP_INVALID;
- X509_STORE *store;
- STACK_OF(X509) *untrusted = NULL, *certs = NULL, *chain = NULL;
- X509_STORE_CTX ctx;
- X509 *signer, *tmp_cert;
- int signer_trusted = 0;
- EVP_PKEY *skey;
- int ret;
- char buf[256];
-
- txt = integer_str(X509_get_serialNumber(cert));
- if (txt) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Searching OCSP response for peer certificate serialNumber: %s", txt);
- os_free(txt);
- }
-
- SSL_get0_ocsp_response(conn->ssl, &resp_data, &resp_len);
- if (resp_data == NULL || resp_len == 0) {
- wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
- return OCSP_NO_RESPONSE;
- }
-
- wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", resp_data, resp_len);
-
- resp = d2i_OCSPResponse(NULL, &resp_data, resp_len);
- if (!resp) {
- wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSPResponse");
- return OCSP_INVALID;
- }
-
- status = ASN1_ENUMERATED_get(resp->responseStatus);
- if (status != 0) {
- wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d",
- status);
- return OCSP_INVALID;
- }
-
- bytes = resp->responseBytes;
-
- if (!bytes ||
- OBJ_obj2nid(bytes->responseType) != NID_id_pkix_OCSP_basic) {
- wpa_printf(MSG_INFO,
- "OpenSSL: Could not find BasicOCSPResponse");
- return OCSP_INVALID;
- }
-
- basic_data = ASN1_STRING_data(bytes->response);
- basic_len = ASN1_STRING_length(bytes->response);
- wpa_hexdump(MSG_DEBUG, "OpenSSL: BasicOCSPResponse",
- basic_data, basic_len);
-
- basic = d2i_BasicOCSPResponse(NULL, &basic_data, basic_len);
- if (!basic) {
- wpa_printf(MSG_INFO,
- "OpenSSL: Could not parse BasicOCSPResponse");
- OCSPResponse_free(resp);
- return OCSP_INVALID;
- }
-
- rd = basic->tbsResponseData;
-
- if (basic->certs) {
- untrusted = sk_X509_dup(basic->certs);
-
- num = sk_X509_num(basic->certs);
- for (i = 0; i < num; i++) {
- X509 *extra_cert;
-
- extra_cert = sk_X509_value(basic->certs, i);
- X509_NAME_oneline(X509_get_subject_name(extra_cert),
- buf, sizeof(buf));
- wpa_printf(MSG_DEBUG,
- "OpenSSL: BasicOCSPResponse cert %s", buf);
-
- if (!sk_X509_push(untrusted, extra_cert)) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Could not add certificate to the untrusted stack");
- }
- }
- }
-
- store = SSL_CTX_get_cert_store(conn->ssl_ctx);
- if (conn->peer_issuer) {
- if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
- tls_show_errors(MSG_INFO, __func__,
- "OpenSSL: Could not add issuer to certificate store");
- }
- certs = sk_X509_new_null();
- if (certs) {
- tmp_cert = X509_dup(conn->peer_issuer);
- if (tmp_cert && !sk_X509_push(certs, tmp_cert)) {
- tls_show_errors(
- MSG_INFO, __func__,
- "OpenSSL: Could not add issuer to OCSP responder trust store");
- X509_free(tmp_cert);
- sk_X509_free(certs);
- certs = NULL;
- }
- if (certs && conn->peer_issuer_issuer) {
- tmp_cert = X509_dup(conn->peer_issuer_issuer);
- if (tmp_cert &&
- !sk_X509_push(certs, tmp_cert)) {
- tls_show_errors(
- MSG_INFO, __func__,
- "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
- X509_free(tmp_cert);
- }
- }
- }
- }
-
- signer = ocsp_find_signer(certs, rd->responderID);
- if (!signer)
- signer = ocsp_find_signer(untrusted, rd->responderID);
- else
- signer_trusted = 1;
- if (!signer) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Could not find OCSP signer certificate");
- goto fail;
- }
-
- skey = X509_get_pubkey(signer);
- if (!skey) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Could not get OCSP signer public key");
- goto fail;
- }
- if (ASN1_item_verify(ASN1_ITEM_rptr(ResponseData),
- basic->signatureAlgorithm, basic->signature,
- basic->tbsResponseData, skey) <= 0) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: BasicOCSPResponse signature is invalid");
- goto fail;
- }
-
- X509_NAME_oneline(X509_get_subject_name(signer), buf, sizeof(buf));
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Found OCSP signer certificate %s and verified BasicOCSPResponse signature",
- buf);
-
- if (!X509_STORE_CTX_init(&ctx, store, signer, untrusted))
- goto fail;
- X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER);
- ret = X509_verify_cert(&ctx);
- chain = X509_STORE_CTX_get1_chain(&ctx);
- X509_STORE_CTX_cleanup(&ctx);
- if (ret <= 0) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Could not validate OCSP signer certificate");
- goto fail;
- }
-
- if (!chain || sk_X509_num(chain) <= 0) {
- wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP signer chain found");
- goto fail;
- }
-
- if (!signer_trusted) {
- X509_check_purpose(signer, -1, 0);
- if ((signer->ex_flags & EXFLAG_XKUSAGE) &&
- (signer->ex_xkusage & XKU_OCSP_SIGN)) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: OCSP signer certificate delegation OK");
- } else {
- tmp_cert = sk_X509_value(chain, sk_X509_num(chain) - 1);
- if (X509_check_trust(tmp_cert, NID_OCSP_sign, 0) !=
- X509_TRUST_TRUSTED) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: OCSP signer certificate not trusted");
- result = OCSP_NO_RESPONSE;
- goto fail;
- }
- }
- }
-
- wpa_printf(MSG_DEBUG, "OpenSSL: OCSP version: %lu",
- ASN1_INTEGER_get(rd->version));
-
- txt = responderid_str(rd->responderID);
- if (txt) {
- wpa_printf(MSG_DEBUG, "OpenSSL: OCSP responderID: %s",
- txt);
- os_free(txt);
- }
-
- txt = generalizedtime_str(rd->producedAt);
- if (txt) {
- wpa_printf(MSG_DEBUG, "OpenSSL: OCSP producedAt: %s",
- txt);
- os_free(txt);
- }
-
- num_resp = sk_SingleResponse_num(rd->responses);
- if (num_resp == 0) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: No OCSP SingleResponse within BasicOCSPResponse");
- result = OCSP_NO_RESPONSE;
- goto fail;
- }
- cmp_sresp = sk_SingleResponse_value(rd->responses, 0);
- for (j = 0; j < num_resp; j++) {
- SingleResponse *sresp;
- CertID *cid1, *cid2;
-
- sresp = sk_SingleResponse_value(rd->responses, j);
- wpa_printf(MSG_DEBUG, "OpenSSL: OCSP SingleResponse %u/%u",
- j + 1, num_resp);
-
- txt = algor_str(sresp->certID->hashAlgorithm);
- if (txt) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: certID hashAlgorithm: %s", txt);
- os_free(txt);
- }
-
- txt = octet_string_str(sresp->certID->issuerNameHash);
- if (txt) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: certID issuerNameHash: %s", txt);
- os_free(txt);
- }
-
- txt = octet_string_str(sresp->certID->issuerKeyHash);
- if (txt) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: certID issuerKeyHash: %s", txt);
- os_free(txt);
- }
-
- txt = integer_str(sresp->certID->serialNumber);
- if (txt) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: certID serialNumber: %s", txt);
- os_free(txt);
- }
-
- switch (sresp->certStatus->type) {
- case 0:
- wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: good");
- break;
- case 1:
- wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: revoked");
- break;
- default:
- wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: unknown");
- break;
- }
-
- txt = generalizedtime_str(sresp->thisUpdate);
- if (txt) {
- wpa_printf(MSG_DEBUG, "OpenSSL: thisUpdate: %s", txt);
- os_free(txt);
- }
-
- if (sresp->nextUpdate) {
- txt = generalizedtime_str(sresp->nextUpdate);
- if (txt) {
- wpa_printf(MSG_DEBUG, "OpenSSL: nextUpdate: %s",
- txt);
- os_free(txt);
- }
- }
-
- txt = extensions_str("singleExtensions",
- sresp->singleExtensions);
- if (txt) {
- wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
- os_free(txt);
- }
-
- cid1 = cmp_sresp->certID;
- cid2 = sresp->certID;
- if (j > 0 &&
- (OBJ_cmp(cid1->hashAlgorithm->algorithm,
- cid2->hashAlgorithm->algorithm) != 0 ||
- ASN1_OCTET_STRING_cmp(cid1->issuerNameHash,
- cid2->issuerNameHash) != 0 ||
- ASN1_OCTET_STRING_cmp(cid1->issuerKeyHash,
- cid2->issuerKeyHash) != 0)) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Different OCSP response issuer information between SingleResponse values within BasicOCSPResponse");
- goto fail;
- }
-
- if (!matching_resp && issuer &&
- ASN1_INTEGER_cmp(sresp->certID->serialNumber,
- X509_get_serialNumber(cert)) == 0 &&
- issuer_match(cert, issuer, sresp->certID) == 0) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: This response matches peer certificate");
- matching_resp = sresp;
- }
- }
-
- txt = extensions_str("responseExtensions", rd->responseExtensions);
- if (txt) {
- wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
- os_free(txt);
- }
-
- if (!matching_resp) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: Could not find OCSP response that matches the peer certificate");
- result = OCSP_NO_RESPONSE;
- goto fail;
- }
-
- if (!ocsp_resp_valid(matching_resp->thisUpdate,
- matching_resp->nextUpdate)) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: OCSP response not valid at this time");
- goto fail;
- }
-
- if (matching_resp->certStatus->type == 1) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: OCSP response indicated that the peer certificate has been revoked");
- result = OCSP_REVOKED;
- goto fail;
- }
-
- if (matching_resp->certStatus->type != 0) {
- wpa_printf(MSG_DEBUG,
- "OpenSSL: OCSP response did not indicate good status");
- result = OCSP_NO_RESPONSE;
- goto fail;
- }
-
- /* OCSP response indicated the certificate is good. */
- result = OCSP_GOOD;
-fail:
- sk_X509_pop_free(chain, X509_free);
- sk_X509_free(untrusted);
- sk_X509_pop_free(certs, X509_free);
- BasicOCSPResponse_free(basic);
- OCSPResponse_free(resp);
-
- return result;
-}
-
-#endif /* OPENSSL_IS_BORINGSSL */
-
-
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
@@ -2613,10 +1796,13 @@
}
#ifdef OPENSSL_IS_BORINGSSL
- if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP)) {
+ if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ preverify_ok) {
enum ocsp_result res;
- res = check_ocsp_resp(conn, err_cert, conn->peer_issuer);
+ res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+ conn->peer_issuer,
+ conn->peer_issuer_issuer);
if (res == OCSP_REVOKED) {
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
@@ -3163,7 +2349,7 @@
}
if (certs) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
SSL_clear_chain_certs(ssl);
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
@@ -3746,7 +2932,7 @@
if (conn == NULL || keys == NULL)
return -1;
ssl = conn->ssl;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
return -1;
@@ -3775,7 +2961,7 @@
#ifndef CONFIG_FIPS
static int openssl_get_keyblock_size(SSL *ssl)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
const EVP_CIPHER *c;
const EVP_MD *h;
int md_size;
@@ -3845,7 +3031,7 @@
"mode");
return -1;
#else /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
SSL *ssl;
u8 *rnd;
int ret = -1;
@@ -4328,7 +3514,7 @@
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
if (os_strstr(buf, ":ADH-")) {
/*
@@ -4917,7 +4103,7 @@
struct tls_connection *conn = arg;
int ret;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
@@ -5012,9 +4198,15 @@
int tls_get_library_version(char *buf, size_t buf_len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
+ OPENSSL_VERSION_TEXT,
+ OpenSSL_version(OPENSSL_VERSION));
+#else
return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
OPENSSL_VERSION_TEXT,
SSLeay_version(SSLEAY_VERSION));
+#endif
}
diff --git a/src/crypto/tls_openssl.h b/src/crypto/tls_openssl.h
new file mode 100644
index 0000000..2a62d5c
--- /dev/null
+++ b/src/crypto/tls_openssl.h
@@ -0,0 +1,19 @@
+/*
+ * SSL/TLS interface functions for OpenSSL
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLS_OPENSSL_H
+#define TLS_OPENSSL_H
+
+enum ocsp_result {
+ OCSP_GOOD, OCSP_REVOKED, OCSP_NO_RESPONSE, OCSP_INVALID
+};
+
+enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert,
+ X509 *issuer, X509 *issuer_issuer);
+
+#endif /* TLS_OPENSSL_H */
diff --git a/src/crypto/tls_openssl_ocsp.c b/src/crypto/tls_openssl_ocsp.c
new file mode 100644
index 0000000..37c87f4
--- /dev/null
+++ b/src/crypto/tls_openssl_ocsp.c
@@ -0,0 +1,843 @@
+/*
+ * SSL/TLS interface functions for OpenSSL - BoringSSL OCSP
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#endif /* OPENSSL_IS_BORINGSSL */
+
+#include "common.h"
+#include "tls_openssl.h"
+
+
+#ifdef OPENSSL_IS_BORINGSSL
+
+static void tls_show_errors(int level, const char *func, const char *txt)
+{
+ unsigned long err;
+
+ wpa_printf(level, "OpenSSL: %s - %s %s",
+ func, txt, ERR_error_string(ERR_get_error(), NULL));
+
+ while ((err = ERR_get_error())) {
+ wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
+ ERR_error_string(err, NULL));
+ }
+}
+
+
+/*
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuer's public key
+ * serialNumber CertificateSerialNumber }
+ */
+typedef struct {
+ X509_ALGOR *hashAlgorithm;
+ ASN1_OCTET_STRING *issuerNameHash;
+ ASN1_OCTET_STRING *issuerKeyHash;
+ ASN1_INTEGER *serialNumber;
+} CertID;
+
+/*
+ * ResponseBytes ::= SEQUENCE {
+ * responseType OBJECT IDENTIFIER,
+ * response OCTET STRING }
+ */
+typedef struct {
+ ASN1_OBJECT *responseType;
+ ASN1_OCTET_STRING *response;
+} ResponseBytes;
+
+/*
+ * OCSPResponse ::= SEQUENCE {
+ * responseStatus OCSPResponseStatus,
+ * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+ */
+typedef struct {
+ ASN1_ENUMERATED *responseStatus;
+ ResponseBytes *responseBytes;
+} OCSPResponse;
+
+ASN1_SEQUENCE(ResponseBytes) = {
+ ASN1_SIMPLE(ResponseBytes, responseType, ASN1_OBJECT),
+ ASN1_SIMPLE(ResponseBytes, response, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(ResponseBytes);
+
+ASN1_SEQUENCE(OCSPResponse) = {
+ ASN1_SIMPLE(OCSPResponse, responseStatus, ASN1_ENUMERATED),
+ ASN1_EXP_OPT(OCSPResponse, responseBytes, ResponseBytes, 0)
+} ASN1_SEQUENCE_END(OCSPResponse);
+
+IMPLEMENT_ASN1_FUNCTIONS(OCSPResponse);
+
+/*
+ * ResponderID ::= CHOICE {
+ * byName [1] Name,
+ * byKey [2] KeyHash }
+ */
+typedef struct {
+ int type;
+ union {
+ X509_NAME *byName;
+ ASN1_OCTET_STRING *byKey;
+ } value;
+} ResponderID;
+
+/*
+ * RevokedInfo ::= SEQUENCE {
+ * revocationTime GeneralizedTime,
+ * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
+ */
+typedef struct {
+ ASN1_GENERALIZEDTIME *revocationTime;
+ ASN1_ENUMERATED *revocationReason;
+} RevokedInfo;
+
+/*
+ * CertStatus ::= CHOICE {
+ * good [0] IMPLICIT NULL,
+ * revoked [1] IMPLICIT RevokedInfo,
+ * unknown [2] IMPLICIT UnknownInfo }
+ */
+typedef struct {
+ int type;
+ union {
+ ASN1_NULL *good;
+ RevokedInfo *revoked;
+ ASN1_NULL *unknown;
+ } value;
+} CertStatus;
+
+/*
+ * SingleResponse ::= SEQUENCE {
+ * certID CertID,
+ * certStatus CertStatus,
+ * thisUpdate GeneralizedTime,
+ * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct {
+ CertID *certID;
+ CertStatus *certStatus;
+ ASN1_GENERALIZEDTIME *thisUpdate;
+ ASN1_GENERALIZEDTIME *nextUpdate;
+ STACK_OF(X509_EXTENSION) *singleExtensions;
+} SingleResponse;
+
+/*
+ * ResponseData ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * responderID ResponderID,
+ * producedAt GeneralizedTime,
+ * responses SEQUENCE OF SingleResponse,
+ * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct {
+ ASN1_INTEGER *version;
+ ResponderID *responderID;
+ ASN1_GENERALIZEDTIME *producedAt;
+ STACK_OF(SingleResponse) *responses;
+ STACK_OF(X509_EXTENSION) *responseExtensions;
+} ResponseData;
+
+/*
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+typedef struct {
+ ResponseData *tbsResponseData;
+ X509_ALGOR *signatureAlgorithm;
+ ASN1_BIT_STRING *signature;
+ STACK_OF(X509) *certs;
+} BasicOCSPResponse;
+
+ASN1_SEQUENCE(CertID) = {
+ ASN1_SIMPLE(CertID, hashAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE(CertID, issuerNameHash, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(CertID, issuerKeyHash, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(CertID, serialNumber, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(CertID);
+
+ASN1_CHOICE(ResponderID) = {
+ ASN1_EXP(ResponderID, value.byName, X509_NAME, 1),
+ ASN1_EXP(ResponderID, value.byKey, ASN1_OCTET_STRING, 2)
+} ASN1_CHOICE_END(ResponderID);
+
+ASN1_SEQUENCE(RevokedInfo) = {
+ ASN1_SIMPLE(RevokedInfo, revocationTime, ASN1_GENERALIZEDTIME),
+ ASN1_EXP_OPT(RevokedInfo, revocationReason, ASN1_ENUMERATED, 0)
+} ASN1_SEQUENCE_END(RevokedInfo);
+
+ASN1_CHOICE(CertStatus) = {
+ ASN1_IMP(CertStatus, value.good, ASN1_NULL, 0),
+ ASN1_IMP(CertStatus, value.revoked, RevokedInfo, 1),
+ ASN1_IMP(CertStatus, value.unknown, ASN1_NULL, 2)
+} ASN1_CHOICE_END(CertStatus);
+
+ASN1_SEQUENCE(SingleResponse) = {
+ ASN1_SIMPLE(SingleResponse, certID, CertID),
+ ASN1_SIMPLE(SingleResponse, certStatus, CertStatus),
+ ASN1_SIMPLE(SingleResponse, thisUpdate, ASN1_GENERALIZEDTIME),
+ ASN1_EXP_OPT(SingleResponse, nextUpdate, ASN1_GENERALIZEDTIME, 0),
+ ASN1_EXP_SEQUENCE_OF_OPT(SingleResponse, singleExtensions,
+ X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(SingleResponse);
+
+ASN1_SEQUENCE(ResponseData) = {
+ ASN1_EXP_OPT(ResponseData, version, ASN1_INTEGER, 0),
+ ASN1_SIMPLE(ResponseData, responderID, ResponderID),
+ ASN1_SIMPLE(ResponseData, producedAt, ASN1_GENERALIZEDTIME),
+ ASN1_SEQUENCE_OF(ResponseData, responses, SingleResponse),
+ ASN1_EXP_SEQUENCE_OF_OPT(ResponseData, responseExtensions,
+ X509_EXTENSION, 1)
+} ASN1_SEQUENCE_END(ResponseData);
+
+ASN1_SEQUENCE(BasicOCSPResponse) = {
+ ASN1_SIMPLE(BasicOCSPResponse, tbsResponseData, ResponseData),
+ ASN1_SIMPLE(BasicOCSPResponse, signatureAlgorithm, X509_ALGOR),
+ ASN1_SIMPLE(BasicOCSPResponse, signature, ASN1_BIT_STRING),
+ ASN1_EXP_SEQUENCE_OF_OPT(BasicOCSPResponse, certs, X509, 0)
+} ASN1_SEQUENCE_END(BasicOCSPResponse);
+
+IMPLEMENT_ASN1_FUNCTIONS(BasicOCSPResponse);
+
+#define sk_SingleResponse_num(sk) \
+sk_num(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk))
+
+#define sk_SingleResponse_value(sk, i) \
+ ((SingleResponse *) \
+ sk_value(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk), (i)))
+
+
+static char * mem_bio_to_str(BIO *out)
+{
+ char *txt;
+ size_t rlen;
+ int res;
+
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (!txt) {
+ BIO_free(out);
+ return NULL;
+ }
+
+ res = BIO_read(out, txt, rlen);
+ BIO_free(out);
+ if (res < 0) {
+ os_free(txt);
+ return NULL;
+ }
+
+ txt[res] = '\0';
+ return txt;
+}
+
+
+static char * generalizedtime_str(ASN1_GENERALIZEDTIME *t)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ if (!ASN1_GENERALIZEDTIME_print(out, t)) {
+ BIO_free(out);
+ return NULL;
+ }
+
+ return mem_bio_to_str(out);
+}
+
+
+static char * responderid_str(ResponderID *rid)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ switch (rid->type) {
+ case 0:
+ X509_NAME_print_ex(out, rid->value.byName, 0, XN_FLAG_ONELINE);
+ break;
+ case 1:
+ i2a_ASN1_STRING(out, rid->value.byKey, V_ASN1_OCTET_STRING);
+ break;
+ default:
+ BIO_free(out);
+ return NULL;
+ }
+
+ return mem_bio_to_str(out);
+}
+
+
+static char * octet_string_str(ASN1_OCTET_STRING *o)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ i2a_ASN1_STRING(out, o, V_ASN1_OCTET_STRING);
+ return mem_bio_to_str(out);
+}
+
+
+static char * integer_str(ASN1_INTEGER *i)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ i2a_ASN1_INTEGER(out, i);
+ return mem_bio_to_str(out);
+}
+
+
+static char * algor_str(X509_ALGOR *alg)
+{
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ i2a_ASN1_OBJECT(out, alg->algorithm);
+ return mem_bio_to_str(out);
+}
+
+
+static char * extensions_str(const char *title, STACK_OF(X509_EXTENSION) *ext)
+{
+ BIO *out;
+
+ if (!ext)
+ return NULL;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return NULL;
+
+ if (!X509V3_extensions_print(out, title, ext, 0, 0)) {
+ BIO_free(out);
+ return NULL;
+ }
+ return mem_bio_to_str(out);
+}
+
+
+static int ocsp_resp_valid(ASN1_GENERALIZEDTIME *thisupd,
+ ASN1_GENERALIZEDTIME *nextupd)
+{
+ time_t now, tmp;
+
+ if (!ASN1_GENERALIZEDTIME_check(thisupd)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid OCSP response thisUpdate");
+ return 0;
+ }
+
+ time(&now);
+ tmp = now + 5 * 60; /* allow five minute clock difference */
+ if (X509_cmp_time(thisupd, &tmp) > 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response not yet valid");
+ return 0;
+ }
+
+ if (!nextupd)
+ return 1; /* OK - no limit on response age */
+
+ if (!ASN1_GENERALIZEDTIME_check(nextupd)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid OCSP response nextUpdate");
+ return 0;
+ }
+
+ tmp = now - 5 * 60; /* allow five minute clock difference */
+ if (X509_cmp_time(nextupd, &tmp) < 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response expired");
+ return 0;
+ }
+
+ if (ASN1_STRING_cmp(nextupd, thisupd) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response nextUpdate before thisUpdate");
+ return 0;
+ }
+
+ /* Both thisUpdate and nextUpdate are valid */
+ return -1;
+}
+
+
+static int issuer_match(X509 *cert, X509 *issuer, CertID *certid)
+{
+ X509_NAME *iname;
+ ASN1_BIT_STRING *ikey;
+ const EVP_MD *dgst;
+ unsigned int len;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ ASN1_OCTET_STRING *hash;
+ char *txt;
+
+ dgst = EVP_get_digestbyobj(certid->hashAlgorithm->algorithm);
+ if (!dgst) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not find matching hash algorithm for OCSP");
+ return -1;
+ }
+
+ iname = X509_get_issuer_name(cert);
+ if (!X509_NAME_digest(iname, dgst, md, &len))
+ return -1;
+ hash = ASN1_OCTET_STRING_new();
+ if (!hash)
+ return -1;
+ if (!ASN1_OCTET_STRING_set(hash, md, len)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ txt = octet_string_str(hash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerNameHash: %s",
+ txt);
+ os_free(txt);
+ }
+
+ if (ASN1_OCTET_STRING_cmp(certid->issuerNameHash, hash)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ ikey = X509_get0_pubkey_bitstr(issuer);
+ if (!EVP_Digest(ikey->data, ikey->length, md, &len, dgst, NULL) ||
+ !ASN1_OCTET_STRING_set(hash, md, len)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ txt = octet_string_str(hash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: calculated issuerKeyHash: %s",
+ txt);
+ os_free(txt);
+ }
+
+ if (ASN1_OCTET_STRING_cmp(certid->issuerKeyHash, hash)) {
+ ASN1_OCTET_STRING_free(hash);
+ return -1;
+ }
+
+ ASN1_OCTET_STRING_free(hash);
+ return 0;
+}
+
+
+static X509 * ocsp_find_signer(STACK_OF(X509) *certs, ResponderID *rid)
+{
+ unsigned int i;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (rid->type == 0) {
+ /* byName */
+ return X509_find_by_subject(certs, rid->value.byName);
+ }
+
+ /* byKey */
+ if (rid->value.byKey->length != SHA_DIGEST_LENGTH)
+ return NULL;
+ for (i = 0; i < sk_X509_num(certs); i++) {
+ X509 *x = sk_X509_value(certs, i);
+
+ X509_pubkey_digest(x, EVP_sha1(), hash, NULL);
+ if (os_memcmp(rid->value.byKey->data, hash,
+ SHA_DIGEST_LENGTH) == 0)
+ return x;
+ }
+
+ return NULL;
+}
+
+
+enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert,
+ X509 *issuer, X509 *issuer_issuer)
+{
+ const uint8_t *resp_data;
+ size_t resp_len;
+ OCSPResponse *resp;
+ int status;
+ ResponseBytes *bytes;
+ const u8 *basic_data;
+ size_t basic_len;
+ BasicOCSPResponse *basic;
+ ResponseData *rd;
+ char *txt;
+ int i, num;
+ unsigned int j, num_resp;
+ SingleResponse *matching_resp = NULL, *cmp_sresp;
+ enum ocsp_result result = OCSP_INVALID;
+ X509_STORE *store;
+ STACK_OF(X509) *untrusted = NULL, *certs = NULL, *chain = NULL;
+ X509_STORE_CTX ctx;
+ X509 *signer, *tmp_cert;
+ int signer_trusted = 0;
+ EVP_PKEY *skey;
+ int ret;
+ char buf[256];
+
+ txt = integer_str(X509_get_serialNumber(cert));
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Searching OCSP response for peer certificate serialNumber: %s", txt);
+ os_free(txt);
+ }
+
+ SSL_get0_ocsp_response(ssl, &resp_data, &resp_len);
+ if (resp_data == NULL || resp_len == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+ return OCSP_NO_RESPONSE;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", resp_data, resp_len);
+
+ resp = d2i_OCSPResponse(NULL, &resp_data, resp_len);
+ if (!resp) {
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSPResponse");
+ return OCSP_INVALID;
+ }
+
+ status = ASN1_ENUMERATED_get(resp->responseStatus);
+ if (status != 0) {
+ wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d",
+ status);
+ return OCSP_INVALID;
+ }
+
+ bytes = resp->responseBytes;
+
+ if (!bytes ||
+ OBJ_obj2nid(bytes->responseType) != NID_id_pkix_OCSP_basic) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Could not find BasicOCSPResponse");
+ return OCSP_INVALID;
+ }
+
+ basic_data = ASN1_STRING_data(bytes->response);
+ basic_len = ASN1_STRING_length(bytes->response);
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: BasicOCSPResponse",
+ basic_data, basic_len);
+
+ basic = d2i_BasicOCSPResponse(NULL, &basic_data, basic_len);
+ if (!basic) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Could not parse BasicOCSPResponse");
+ OCSPResponse_free(resp);
+ return OCSP_INVALID;
+ }
+
+ rd = basic->tbsResponseData;
+
+ if (basic->certs) {
+ untrusted = sk_X509_dup(basic->certs);
+
+ num = sk_X509_num(basic->certs);
+ for (i = 0; i < num; i++) {
+ X509 *extra_cert;
+
+ extra_cert = sk_X509_value(basic->certs, i);
+ X509_NAME_oneline(X509_get_subject_name(extra_cert),
+ buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: BasicOCSPResponse cert %s", buf);
+
+ if (!sk_X509_push(untrusted, extra_cert)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not add certificate to the untrusted stack");
+ }
+ }
+ }
+
+ store = SSL_CTX_get_cert_store(ssl_ctx);
+ if (issuer) {
+ if (X509_STORE_add_cert(store, issuer) != 1) {
+ tls_show_errors(MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer to certificate store");
+ }
+ certs = sk_X509_new_null();
+ if (certs) {
+ tmp_cert = X509_dup(issuer);
+ if (tmp_cert && !sk_X509_push(certs, tmp_cert)) {
+ tls_show_errors(
+ MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer to OCSP responder trust store");
+ X509_free(tmp_cert);
+ sk_X509_free(certs);
+ certs = NULL;
+ }
+ if (certs && issuer_issuer) {
+ tmp_cert = X509_dup(issuer_issuer);
+ if (tmp_cert &&
+ !sk_X509_push(certs, tmp_cert)) {
+ tls_show_errors(
+ MSG_INFO, __func__,
+ "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
+ X509_free(tmp_cert);
+ }
+ }
+ }
+ }
+
+ signer = ocsp_find_signer(certs, rd->responderID);
+ if (!signer)
+ signer = ocsp_find_signer(untrusted, rd->responderID);
+ else
+ signer_trusted = 1;
+ if (!signer) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not find OCSP signer certificate");
+ goto fail;
+ }
+
+ skey = X509_get_pubkey(signer);
+ if (!skey) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not get OCSP signer public key");
+ goto fail;
+ }
+ if (ASN1_item_verify(ASN1_ITEM_rptr(ResponseData),
+ basic->signatureAlgorithm, basic->signature,
+ basic->tbsResponseData, skey) <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: BasicOCSPResponse signature is invalid");
+ goto fail;
+ }
+
+ X509_NAME_oneline(X509_get_subject_name(signer), buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Found OCSP signer certificate %s and verified BasicOCSPResponse signature",
+ buf);
+
+ if (!X509_STORE_CTX_init(&ctx, store, signer, untrusted))
+ goto fail;
+ X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER);
+ ret = X509_verify_cert(&ctx);
+ chain = X509_STORE_CTX_get1_chain(&ctx);
+ X509_STORE_CTX_cleanup(&ctx);
+ if (ret <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not validate OCSP signer certificate");
+ goto fail;
+ }
+
+ if (!chain || sk_X509_num(chain) <= 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP signer chain found");
+ goto fail;
+ }
+
+ if (!signer_trusted) {
+ X509_check_purpose(signer, -1, 0);
+ if ((signer->ex_flags & EXFLAG_XKUSAGE) &&
+ (signer->ex_xkusage & XKU_OCSP_SIGN)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP signer certificate delegation OK");
+ } else {
+ tmp_cert = sk_X509_value(chain, sk_X509_num(chain) - 1);
+ if (X509_check_trust(tmp_cert, NID_OCSP_sign, 0) !=
+ X509_TRUST_TRUSTED) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP signer certificate not trusted");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP version: %lu",
+ ASN1_INTEGER_get(rd->version));
+
+ txt = responderid_str(rd->responderID);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP responderID: %s",
+ txt);
+ os_free(txt);
+ }
+
+ txt = generalizedtime_str(rd->producedAt);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP producedAt: %s",
+ txt);
+ os_free(txt);
+ }
+
+ num_resp = sk_SingleResponse_num(rd->responses);
+ if (num_resp == 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: No OCSP SingleResponse within BasicOCSPResponse");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+ cmp_sresp = sk_SingleResponse_value(rd->responses, 0);
+ for (j = 0; j < num_resp; j++) {
+ SingleResponse *sresp;
+ CertID *cid1, *cid2;
+
+ sresp = sk_SingleResponse_value(rd->responses, j);
+ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP SingleResponse %u/%u",
+ j + 1, num_resp);
+
+ txt = algor_str(sresp->certID->hashAlgorithm);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID hashAlgorithm: %s", txt);
+ os_free(txt);
+ }
+
+ txt = octet_string_str(sresp->certID->issuerNameHash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID issuerNameHash: %s", txt);
+ os_free(txt);
+ }
+
+ txt = octet_string_str(sresp->certID->issuerKeyHash);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID issuerKeyHash: %s", txt);
+ os_free(txt);
+ }
+
+ txt = integer_str(sresp->certID->serialNumber);
+ if (txt) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: certID serialNumber: %s", txt);
+ os_free(txt);
+ }
+
+ switch (sresp->certStatus->type) {
+ case 0:
+ wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: good");
+ break;
+ case 1:
+ wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: revoked");
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "OpenSSL: certStatus: unknown");
+ break;
+ }
+
+ txt = generalizedtime_str(sresp->thisUpdate);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: thisUpdate: %s", txt);
+ os_free(txt);
+ }
+
+ if (sresp->nextUpdate) {
+ txt = generalizedtime_str(sresp->nextUpdate);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: nextUpdate: %s",
+ txt);
+ os_free(txt);
+ }
+ }
+
+ txt = extensions_str("singleExtensions",
+ sresp->singleExtensions);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
+ os_free(txt);
+ }
+
+ cid1 = cmp_sresp->certID;
+ cid2 = sresp->certID;
+ if (j > 0 &&
+ (OBJ_cmp(cid1->hashAlgorithm->algorithm,
+ cid2->hashAlgorithm->algorithm) != 0 ||
+ ASN1_OCTET_STRING_cmp(cid1->issuerNameHash,
+ cid2->issuerNameHash) != 0 ||
+ ASN1_OCTET_STRING_cmp(cid1->issuerKeyHash,
+ cid2->issuerKeyHash) != 0)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Different OCSP response issuer information between SingleResponse values within BasicOCSPResponse");
+ goto fail;
+ }
+
+ if (!matching_resp && issuer &&
+ ASN1_INTEGER_cmp(sresp->certID->serialNumber,
+ X509_get_serialNumber(cert)) == 0 &&
+ issuer_match(cert, issuer, sresp->certID) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: This response matches peer certificate");
+ matching_resp = sresp;
+ }
+ }
+
+ txt = extensions_str("responseExtensions", rd->responseExtensions);
+ if (txt) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s", txt);
+ os_free(txt);
+ }
+
+ if (!matching_resp) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not find OCSP response that matches the peer certificate");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+
+ if (!ocsp_resp_valid(matching_resp->thisUpdate,
+ matching_resp->nextUpdate)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response not valid at this time");
+ goto fail;
+ }
+
+ if (matching_resp->certStatus->type == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response indicated that the peer certificate has been revoked");
+ result = OCSP_REVOKED;
+ goto fail;
+ }
+
+ if (matching_resp->certStatus->type != 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: OCSP response did not indicate good status");
+ result = OCSP_NO_RESPONSE;
+ goto fail;
+ }
+
+ /* OCSP response indicated the certificate is good. */
+ result = OCSP_GOOD;
+fail:
+ sk_X509_pop_free(chain, X509_free);
+ sk_X509_free(untrusted);
+ sk_X509_pop_free(certs, X509_free);
+ BasicOCSPResponse_free(basic);
+ OCSPResponse_free(resp);
+
+ return result;
+}
+
+#endif /* OPENSSL_IS_BORINGSSL */