Cumulative patch from commit 8b48e3200680f71ae083b84793e6bdc2099416d2
8b48e32 wpa_cli: Add MAC address randomization in scan
fb37588 ctrl_iface: Add MAC address randomization in scan processing
56c76fa scan: Add MAC address randomization in scan handling
86056fe nl80211: Handle MAC address randomization in scan/sched_scan
ff23ed2 driver: Add definitions for MAC address randomization in scan
7db53bb wpa_cli: Implement TDLS start/cancel channel switching commands
72b2605 nl80211: Pass TDLS channel-switch start/stop params to kernel
6b90dea TDLS: Propagate enable/disable channel-switch commands to driver
d9d3b78 TDLS: Track TDLS channel switch prohibition in BSS
4daa572 TDLS: Add channel-switch capability flag
ca16586 Sync with wireless-testing.git include/uapi/linux/nl80211.h
8c42b36 WMM AC: Reconfigure tspecs on reassociation to the same BSS
677e7a9 WMM AC: Do not fail on unknown IEs in Association Response
fecc2bb WMM AC: Delete tspecs on roaming
20fe745 WMM AC: Print user-priority in wmm_ac_status
730a0d1 nl80211: Always register management frames handler
...
209702d Add possibility to set the setband parameter
ee82e33 Do not trigger the scan during initialization on Android platforms
e69ae5f Reject new SCAN commands if there is a pending request
...
59d7148 nl80211: Provide subtype and reason code for AP SME drivers
9d4ff04 Add external EAPOL transmission option for testing purposes
61fc904 P2P: Handle improper WPS termination on GO during group formation
58b40fd P2P: Clear p2p_go_group_formation_completed on GO start
c155305 Complete sme-connect radio work when clearing connection state
debb2da P2P: Report group removal reason PSK_FAILURE in timeout case
51465a0 The master branch is now used for v2.4 development
Change-Id: I9b9cfa5c5cd4d26b2f3f5595f7c226ac60de6258
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index 2a92109..3e90350 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -26,6 +26,7 @@
aes-internal-dec.o \
aes-internal-enc.o \
aes-omac1.o \
+ aes-siv.o \
aes-unwrap.o \
aes-wrap.o \
des-internal.o \
diff --git a/src/crypto/aes-omac1.c b/src/crypto/aes-omac1.c
index 27895eb..c2b0686 100644
--- a/src/crypto/aes-omac1.c
+++ b/src/crypto/aes-omac1.c
@@ -65,6 +65,13 @@
for (i = 0; i < AES_BLOCK_SIZE; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
+ /*
+ * Stop if there are no more bytes to process
+ * since there are no more entries in the array.
+ */
+ if (i + 1 == AES_BLOCK_SIZE &&
+ left == AES_BLOCK_SIZE)
+ break;
e++;
pos = addr[e];
end = pos + len[e];
@@ -83,6 +90,12 @@
for (i = 0; i < left; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
+ /*
+ * Stop if there are no more bytes to process
+ * since there are no more entries in the array.
+ */
+ if (i + 1 == left)
+ break;
e++;
pos = addr[e];
end = pos + len[e];
diff --git a/src/crypto/aes-siv.c b/src/crypto/aes-siv.c
new file mode 100644
index 0000000..ff4b823
--- /dev/null
+++ b/src/crypto/aes-siv.c
@@ -0,0 +1,187 @@
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+
+static const u8 zero[AES_BLOCK_SIZE];
+
+
+static void dbl(u8 *pad)
+{
+ int i, carry;
+
+ carry = pad[0] & 0x80;
+ for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+ pad[AES_BLOCK_SIZE - 1] <<= 1;
+ if (carry)
+ pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+static void xor(u8 *a, const u8 *b)
+{
+ int i;
+
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ *a++ ^= *b++;
+}
+
+
+static void xorend(u8 *a, int alen, const u8 *b, int blen)
+{
+ int i;
+
+ if (alen < blen)
+ return;
+
+ for (i = 0; i < blen; i++)
+ a[alen - blen + i] ^= b[i];
+}
+
+
+static void pad_block(u8 *pad, const u8 *addr, size_t len)
+{
+ os_memset(pad, 0, AES_BLOCK_SIZE);
+ os_memcpy(pad, addr, len);
+
+ if (len < AES_BLOCK_SIZE)
+ pad[len] = 0x80;
+}
+
+
+int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
+ size_t *len, u8 *mac)
+{
+ u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
+ u8 *buf = NULL;
+ int ret;
+ size_t i;
+
+ if (!num_elem) {
+ os_memcpy(tmp, zero, sizeof(zero));
+ tmp[AES_BLOCK_SIZE - 1] = 1;
+ return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ }
+
+ ret = omac1_aes_128(key, zero, sizeof(zero), tmp);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_elem - 1; i++) {
+ ret = omac1_aes_128(key, addr[i], len[i], tmp2);
+ if (ret)
+ return ret;
+
+ dbl(tmp);
+ xor(tmp, tmp2);
+ }
+ if (len[i] >= AES_BLOCK_SIZE) {
+ buf = os_malloc(len[i]);
+ if (!buf)
+ return -ENOMEM;
+
+ os_memcpy(buf, addr[i], len[i]);
+ xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
+ ret = omac1_aes_128(key, buf, len[i], mac);
+ os_free(buf);
+ return ret;
+ }
+
+ dbl(tmp);
+ pad_block(tmp2, addr[i], len[i]);
+ xor(tmp, tmp2);
+
+ return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+}
+
+
+int aes_siv_encrypt(const u8 *key, const u8 *pw,
+ size_t pwlen, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *out)
+{
+ const u8 *_addr[6];
+ size_t _len[6];
+ const u8 *k1 = key, *k2 = key + 16;
+ u8 v[AES_BLOCK_SIZE];
+ size_t i;
+ u8 *iv, *crypt_pw;
+
+ if (num_elem > ARRAY_SIZE(_addr) - 1)
+ return -1;
+
+ for (i = 0; i < num_elem; i++) {
+ _addr[i] = addr[i];
+ _len[i] = len[i];
+ }
+ _addr[num_elem] = pw;
+ _len[num_elem] = pwlen;
+
+ if (aes_s2v(k1, num_elem + 1, _addr, _len, v))
+ return -1;
+
+ iv = out;
+ crypt_pw = out + AES_BLOCK_SIZE;
+
+ os_memcpy(iv, v, AES_BLOCK_SIZE);
+ os_memcpy(crypt_pw, pw, pwlen);
+
+ /* zero out 63rd and 31st bits of ctr (from right) */
+ v[8] &= 0x7f;
+ v[12] &= 0x7f;
+ return aes_128_ctr_encrypt(k2, v, crypt_pw, pwlen);
+}
+
+
+int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out)
+{
+ const u8 *_addr[6];
+ size_t _len[6];
+ const u8 *k1 = key, *k2 = key + 16;
+ size_t crypt_len;
+ size_t i;
+ int ret;
+ u8 iv[AES_BLOCK_SIZE];
+ u8 check[AES_BLOCK_SIZE];
+
+ if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1)
+ return -1;
+ crypt_len = iv_c_len - AES_BLOCK_SIZE;
+
+ for (i = 0; i < num_elem; i++) {
+ _addr[i] = addr[i];
+ _len[i] = len[i];
+ }
+ _addr[num_elem] = out;
+ _len[num_elem] = crypt_len;
+
+ os_memcpy(iv, iv_crypt, AES_BLOCK_SIZE);
+ os_memcpy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len);
+
+ iv[8] &= 0x7f;
+ iv[12] &= 0x7f;
+
+ ret = aes_128_ctr_encrypt(k2, iv, out, crypt_len);
+ if (ret)
+ return ret;
+
+ ret = aes_s2v(k1, num_elem + 1, _addr, _len, check);
+ if (ret)
+ return ret;
+ if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
+ return 0;
+
+ return -1;
+}
diff --git a/src/crypto/aes_siv.h b/src/crypto/aes_siv.h
new file mode 100644
index 0000000..463cf65
--- /dev/null
+++ b/src/crypto/aes_siv.h
@@ -0,0 +1,19 @@
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_SIV_H
+#define AES_SIV_H
+
+int aes_siv_encrypt(const u8 *key, const u8 *pw,
+ size_t pwlen, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *out);
+int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out);
+
+#endif /* AES_SIV_H */
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 053740e..bc758aa 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -232,12 +232,8 @@
*/
fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (fd < 0) {
-#ifndef CONFIG_NO_STDOUT_DEBUG
- int error = errno;
- perror("open(/dev/random)");
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(error));
-#endif /* CONFIG_NO_STDOUT_DEBUG */
+ strerror(errno));
return -1;
}
@@ -417,12 +413,8 @@
random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (random_fd < 0) {
-#ifndef CONFIG_NO_STDOUT_DEBUG
- int error = errno;
- perror("open(/dev/random)");
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(error));
-#endif /* CONFIG_NO_STDOUT_DEBUG */
+ strerror(errno));
return;
}
wpa_printf(MSG_DEBUG, "random: Trying to read entropy from "
diff --git a/src/crypto/sha256-kdf.c b/src/crypto/sha256-kdf.c
new file mode 100644
index 0000000..d8a1beb
--- /dev/null
+++ b/src/crypto/sha256-kdf.c
@@ -0,0 +1,76 @@
+/*
+ * HMAC-SHA256 KDF (RFC 5295)
+ * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+
+
+/**
+ * hmac_sha256_kdf - HMAC-SHA256 based KDF (RFC 5295)
+ * @secret: Key for KDF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2.
+ */
+int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen)
+{
+ u8 T[SHA256_MAC_LEN];
+ u8 iter = 1;
+ const unsigned char *addr[4];
+ size_t len[4];
+ size_t pos, clen;
+
+ addr[0] = T;
+ len[0] = SHA256_MAC_LEN;
+ addr[1] = (const unsigned char *) label;
+ len[1] = os_strlen(label) + 1;
+ addr[2] = seed;
+ len[2] = seed_len;
+ addr[3] = &iter;
+ len[3] = 1;
+
+ if (hmac_sha256_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
+ return -1;
+
+ pos = 0;
+ for (;;) {
+ clen = outlen - pos;
+ if (clen > SHA256_MAC_LEN)
+ clen = SHA256_MAC_LEN;
+ os_memcpy(out + pos, T, clen);
+ pos += clen;
+
+ if (pos == outlen)
+ break;
+
+ if (iter == 255) {
+ os_memset(out, 0, outlen);
+ return -1;
+ }
+ iter++;
+
+ if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
+ {
+ os_memset(out, 0, outlen);
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index 7596a52..b15f511 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,6 +1,6 @@
/*
* SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,5 +23,8 @@
void tls_prf_sha256(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
+int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
#endif /* SHA256_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 65e0f79..345ebc7 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -74,6 +74,7 @@
const char *pkcs11_module_path;
int fips_mode;
int cert_in_cb;
+ const char *openssl_ciphers;
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
@@ -87,6 +88,7 @@
#define TLS_CONN_REQUIRE_OCSP BIT(4)
#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
+#define TLS_CONN_EAP_FAST BIT(7)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -123,6 +125,7 @@
* specific for now)
* @cert_id: the certificate's id when using engine
* @ca_cert_id: the CA certificate's id when using engine
+ * @openssl_ciphers: OpenSSL cipher configuration
* @flags: Parameter options (TLS_CONN_*)
* @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
* or %NULL if OCSP is not enabled
@@ -161,6 +164,7 @@
const char *key_id;
const char *cert_id;
const char *ca_cert_id;
+ const char *openssl_ciphers;
unsigned int flags;
const char *ocsp_stapling_response;
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index cb23eb9..20d0a31 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -81,7 +81,7 @@
};
struct tls_connection {
- gnutls_session session;
+ gnutls_session_t session;
char *subject_match, *altsubject_match;
int read_alerts, write_alerts, failed;
@@ -199,7 +199,7 @@
}
-static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
+static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
size_t len)
{
struct tls_connection *conn = (struct tls_connection *) ptr;
@@ -228,7 +228,7 @@
}
-static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
+static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
size_t len)
{
struct tls_connection *conn = (struct tls_connection *) ptr;
@@ -286,7 +286,7 @@
gnutls_transport_set_pull_function(conn->session, tls_pull_func);
gnutls_transport_set_push_function(conn->session, tls_push_func);
- gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
+ gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
return 0;
@@ -563,16 +563,29 @@
}
if (params->client_cert && params->private_key) {
- /* TODO: private_key_passwd? */
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_file2(
+ conn->xcred, params->client_cert, params->private_key,
+ GNUTLS_X509_FMT_PEM, params->private_key_passwd, 0);
+#else
+ /* private_key_passwd not (easily) supported here */
ret = gnutls_certificate_set_x509_key_file(
conn->xcred, params->client_cert, params->private_key,
GNUTLS_X509_FMT_PEM);
+#endif
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
"in PEM format: %s", gnutls_strerror(ret));
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_file2(
+ conn->xcred, params->client_cert,
+ params->private_key, GNUTLS_X509_FMT_DER,
+ params->private_key_passwd, 0);
+#else
ret = gnutls_certificate_set_x509_key_file(
conn->xcred, params->client_cert,
params->private_key, GNUTLS_X509_FMT_DER);
+#endif
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client "
"cert/key in DER format: %s",
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index e153422..c72134a 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -45,14 +45,6 @@
#define ERR_remove_thread_state(tid) ERR_remove_state(0)
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
-/*
- * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
- * 2008-11-15. This version uses a bit different API compared to the old patch.
- */
-#define CONFIG_OPENSSL_TICKET_OVERRIDE
-#endif
-
#if defined(OPENSSL_IS_BORINGSSL)
/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
typedef size_t stack_index_t;
@@ -700,12 +692,15 @@
NULL, NULL
};
- if (!pkcs11_so_path || !pkcs11_module_path)
+ if (!pkcs11_so_path)
return 0;
pre_cmd[1] = pkcs11_so_path;
pre_cmd[3] = engine_id;
- post_cmd[1] = pkcs11_module_path;
+ if (pkcs11_module_path)
+ post_cmd[1] = pkcs11_module_path;
+ else
+ post_cmd[0] = NULL;
wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
pkcs11_so_path);
@@ -747,6 +742,7 @@
{
SSL_CTX *ssl;
struct tls_context *context;
+ const char *ciphers;
if (tls_openssl_ref_count == 0) {
tls_global = context = tls_context_new(conf);
@@ -809,7 +805,7 @@
}
tls_openssl_ref_count++;
- ssl = SSL_CTX_new(TLSv1_method());
+ ssl = SSL_CTX_new(SSLv23_method());
if (ssl == NULL) {
tls_openssl_ref_count--;
#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
@@ -823,19 +819,22 @@
return NULL;
}
+ SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
SSL_CTX_set_app_data(ssl, context);
#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
#ifndef OPENSSL_NO_ENGINE
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+ ERR_load_ENGINE_strings();
+ ENGINE_load_dynamic();
+
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
conf->pkcs11_module_path)) {
- wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
- ERR_load_ENGINE_strings();
- ENGINE_load_dynamic();
-
if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
conf->pkcs11_module_path)) {
@@ -845,6 +844,18 @@
}
#endif /* OPENSSL_NO_ENGINE */
+ if (conf && conf->openssl_ciphers)
+ ciphers = conf->openssl_ciphers;
+ else
+ ciphers = "DEFAULT:!EXP:!LOW";
+ if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to set cipher string '%s'",
+ ciphers);
+ tls_deinit(ssl);
+ return NULL;
+ }
+
return ssl;
}
@@ -886,16 +897,6 @@
wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
return -1;
}
-#ifndef ANDROID
- if (pin == NULL) {
- wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
- return -1;
- }
-#endif
- if (key_id == NULL) {
- wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
- return -1;
- }
ERR_clear_error();
#ifdef ANDROID
@@ -916,21 +917,34 @@
wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
#ifndef ANDROID
- if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
+ if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
ERR_error_string(ERR_get_error(), NULL));
goto err;
}
#endif
- /* load private key first in-case PIN is required for cert */
- conn->private_key = ENGINE_load_private_key(conn->engine,
- key_id, NULL, NULL);
- if (!conn->private_key) {
- wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
- " '%s' [%s]", key_id,
- ERR_error_string(ERR_get_error(), NULL));
- ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
- goto err;
+ if (key_id) {
+ /*
+ * Ensure that the ENGINE does not attempt to use the OpenSSL
+ * UI system to obtain a PIN, if we didn't provide one.
+ */
+ struct {
+ const void *password;
+ const char *prompt_info;
+ } key_cb = { "", NULL };
+
+ /* load private key first in-case PIN is required for cert */
+ conn->private_key = ENGINE_load_private_key(conn->engine,
+ key_id, NULL,
+ &key_cb);
+ if (!conn->private_key) {
+ wpa_printf(MSG_ERROR,
+ "ENGINE: cannot load private key with id '%s' [%s]",
+ key_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ goto err;
+ }
}
/* handle a certificate and/or CA certificate */
@@ -2852,7 +2866,7 @@
return -1;
}
ret = os_snprintf(pos, end - pos, ":%s", suite);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
@@ -2907,15 +2921,9 @@
if (conn == NULL || conn->ssl == NULL || ext_type != 35)
return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
data_len) != 1)
return -1;
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
- if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
- data_len) != 1)
- return -1;
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
return 0;
}
@@ -3201,20 +3209,64 @@
{
int ret;
unsigned long err;
+ int can_pkcs11 = 0;
+ const char *key_id = params->key_id;
+ const char *cert_id = params->cert_id;
+ const char *ca_cert_id = params->ca_cert_id;
+ const char *engine_id = params->engine ? params->engine_id : NULL;
if (conn == NULL)
return -1;
+ /*
+ * If the engine isn't explicitly configured, and any of the
+ * cert/key fields are actually PKCS#11 URIs, then automatically
+ * use the PKCS#11 ENGINE.
+ */
+ if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
+ can_pkcs11 = 1;
+
+ if (!key_id && params->private_key && can_pkcs11 &&
+ os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
+ can_pkcs11 = 2;
+ key_id = params->private_key;
+ }
+
+ if (!cert_id && params->client_cert && can_pkcs11 &&
+ os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
+ can_pkcs11 = 2;
+ cert_id = params->client_cert;
+ }
+
+ if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
+ os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
+ can_pkcs11 = 2;
+ ca_cert_id = params->ca_cert;
+ }
+
+ /* If we need to automatically enable the PKCS#11 ENGINE, do so. */
+ if (can_pkcs11 == 2 && !engine_id)
+ engine_id = "pkcs11";
+
+ if (params->flags & TLS_CONN_EAP_FAST) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Use TLSv1_method() for EAP-FAST");
+ if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to set TLSv1_method() for EAP-FAST");
+ return -1;
+ }
+ }
+
while ((err = ERR_get_error())) {
wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
__func__, ERR_error_string(err, NULL));
}
- if (params->engine) {
+ if (engine_id) {
wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
- ret = tls_engine_init(conn, params->engine_id, params->pin,
- params->key_id, params->cert_id,
- params->ca_cert_id);
+ ret = tls_engine_init(conn, engine_id, params->pin,
+ key_id, cert_id, ca_cert_id);
if (ret)
return ret;
}
@@ -3224,9 +3276,9 @@
params->suffix_match))
return -1;
- if (params->engine && params->ca_cert_id) {
+ if (engine_id && ca_cert_id) {
if (tls_connection_engine_ca_cert(tls_ctx, conn,
- params->ca_cert_id))
+ ca_cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
params->ca_cert_blob,
@@ -3234,15 +3286,15 @@
params->ca_path))
return -1;
- if (params->engine && params->cert_id) {
- if (tls_connection_engine_client_cert(conn, params->cert_id))
+ if (engine_id && cert_id) {
+ if (tls_connection_engine_client_cert(conn, cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_client_cert(conn, params->client_cert,
params->client_cert_blob,
params->client_cert_blob_len))
return -1;
- if (params->engine && params->key_id) {
+ if (engine_id && key_id) {
wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
@@ -3262,6 +3314,14 @@
return -1;
}
+ if (params->openssl_ciphers &&
+ SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
@@ -3328,6 +3388,14 @@
return -1;
}
+ if (params->openssl_ciphers &&
+ SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
@@ -3432,7 +3500,6 @@
}
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
int len, void *arg)
{
@@ -3458,62 +3525,6 @@
return 1;
}
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
-static void tls_hello_ext_cb(SSL *s, int client_server, int type,
- unsigned char *data, int len, void *arg)
-{
- struct tls_connection *conn = arg;
-
- if (conn == NULL || conn->session_ticket_cb == NULL)
- return;
-
- wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
- type, len);
-
- if (type == TLSEXT_TYPE_session_ticket && !client_server) {
- os_free(conn->session_ticket);
- conn->session_ticket = NULL;
-
- wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
- "extension", data, len);
- conn->session_ticket = os_malloc(len);
- if (conn->session_ticket == NULL)
- return;
-
- os_memcpy(conn->session_ticket, data, len);
- conn->session_ticket_len = len;
- }
-}
-#else /* SSL_OP_NO_TICKET */
-static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
-{
- struct tls_connection *conn = arg;
-
- if (conn == NULL || conn->session_ticket_cb == NULL)
- return 0;
-
- wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
- ext->type, ext->length);
-
- os_free(conn->session_ticket);
- conn->session_ticket = NULL;
-
- if (ext->type == 35) {
- wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
- "extension", ext->data, ext->length);
- conn->session_ticket = os_malloc(ext->length);
- if (conn->session_ticket == NULL)
- return SSL_AD_INTERNAL_ERROR;
-
- os_memcpy(conn->session_ticket, ext->data, ext->length);
- conn->session_ticket_len = ext->length;
- }
-
- return 0;
-}
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
@@ -3530,33 +3541,12 @@
if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
conn) != 1)
return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
SSL_set_session_ticket_ext_cb(conn->ssl,
tls_session_ticket_ext_cb, conn);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
- SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
- SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
- if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
- conn) != 1)
- return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
} else {
if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
- SSL_set_tlsext_debug_callback(conn->ssl, NULL);
- SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
- if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
- return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
}
return 0;