aboutsummaryrefslogtreecommitdiff
path: root/src/tls
diff options
context:
space:
mode:
authorRui Paulo <rpaulo@FreeBSD.org>2015-04-18 05:04:12 +0000
committerRui Paulo <rpaulo@FreeBSD.org>2015-04-18 05:04:12 +0000
commitfbffd80fb2ba16c68f799da68a119d5e69643604 (patch)
tree139aabdc99568ca0bd6e4cbdcabdc8098f06fb22 /src/tls
parent5e2639d568f6bb660501a77cc83413c3412562e3 (diff)
Notes
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/asn1.c33
-rw-r--r--src/tls/asn1.h6
-rw-r--r--src/tls/libtommath.c12
-rw-r--r--src/tls/pkcs1.c165
-rw-r--r--src/tls/pkcs1.h7
-rw-r--r--src/tls/rsa.c25
-rw-r--r--src/tls/rsa.h3
-rw-r--r--src/tls/tlsv1_client.c52
-rw-r--r--src/tls/tlsv1_client_read.c124
-rw-r--r--src/tls/tlsv1_client_write.c38
-rw-r--r--src/tls/tlsv1_common.c178
-rw-r--r--src/tls/tlsv1_common.h13
-rw-r--r--src/tls/tlsv1_record.c2
-rw-r--r--src/tls/tlsv1_server.c226
-rw-r--r--src/tls/tlsv1_server.h5
-rw-r--r--src/tls/tlsv1_server_i.h13
-rw-r--r--src/tls/tlsv1_server_read.c438
-rw-r--r--src/tls/tlsv1_server_write.c193
-rw-r--r--src/tls/x509v3.c26
19 files changed, 1196 insertions, 363 deletions
diff --git a/src/tls/asn1.c b/src/tls/asn1.c
index 53acd530d9178..cec109292d5ab 100644
--- a/src/tls/asn1.c
+++ b/src/tls/asn1.c
@@ -1,6 +1,6 @@
/*
* ASN.1 DER parsing
- * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,17 @@
#include "common.h"
#include "asn1.h"
+struct asn1_oid asn1_sha1_oid = {
+ .oid = { 1, 3, 14, 3, 2, 26 },
+ .len = 6
+};
+
+struct asn1_oid asn1_sha256_oid = {
+ .oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
+ .len = 9
+};
+
+
int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
{
const u8 *pos, *end;
@@ -140,7 +151,7 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
}
-void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
+void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len)
{
char *pos = buf;
size_t i;
@@ -155,7 +166,7 @@ void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
ret = os_snprintf(pos, buf + len - pos,
"%s%lu",
i == 0 ? "" : ".", oid->oid[i]);
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
break;
pos += ret;
}
@@ -204,3 +215,19 @@ unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
return val;
}
+
+
+int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
+{
+ size_t i;
+
+ if (a->len != b->len)
+ return 0;
+
+ for (i = 0; i < a->len; i++) {
+ if (a->oid[i] != b->oid[i])
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/src/tls/asn1.h b/src/tls/asn1.h
index 6342c4cc79fd2..74750076731de 100644
--- a/src/tls/asn1.h
+++ b/src/tls/asn1.h
@@ -60,7 +60,11 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid);
int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
const u8 **next);
-void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len);
+void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len);
unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
+int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b);
+
+extern struct asn1_oid asn1_sha1_oid;
+extern struct asn1_oid asn1_sha256_oid;
#endif /* ASN1_H */
diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c
index 741b442ca912d..3fb8fbed25e78 100644
--- a/src/tls/libtommath.c
+++ b/src/tls/libtommath.c
@@ -42,6 +42,9 @@
/* Include faster sqr at the cost of about 0.5 kB in code */
#define BN_FAST_S_MP_SQR_C
+/* About 0.25 kB of code, but ~1.7kB of stack space! */
+#define BN_FAST_S_MP_MUL_DIGS_C
+
#else /* LTM_FAST */
#define BN_MP_DIV_SMALL
@@ -139,7 +142,9 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
static int s_mp_sqr(mp_int * a, mp_int * b);
static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+#endif
#ifdef BN_MP_INIT_MULTI_C
static int mp_init_multi(mp_int *mp, ...);
@@ -671,6 +676,9 @@ static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
#ifdef BN_MP_EXPTMOD_FAST_C
}
#endif
+ if (dr == 0) {
+ /* avoid compiler warnings about possibly unused variable */
+ }
}
@@ -2339,12 +2347,14 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
/* can we use the fast multiplier? */
if (((digs) < MP_WARRAY) &&
MIN (a->used, b->used) <
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_s_mp_mul_digs (a, b, c, digs);
}
+#endif
if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
return res;
@@ -2397,6 +2407,7 @@ static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
}
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
/* Fast (comba) multiplier
*
* This is the fast column-array [comba] multiplier. It is
@@ -2482,6 +2493,7 @@ static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
mp_clamp (c);
return MP_OKAY;
}
+#endif /* BN_FAST_S_MP_MUL_DIGS_C */
/* init an mp_init for a given size */
diff --git a/src/tls/pkcs1.c b/src/tls/pkcs1.c
index b6fde5ee868ab..141ac50df401d 100644
--- a/src/tls/pkcs1.c
+++ b/src/tls/pkcs1.c
@@ -1,6 +1,6 @@
/*
* PKCS #1 (RSA Encryption)
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,7 +9,9 @@
#include "includes.h"
#include "common.h"
+#include "crypto/crypto.h"
#include "rsa.h"
+#include "asn1.h"
#include "pkcs1.h"
@@ -113,6 +115,11 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
pos++;
if (pos == end)
return -1;
+ if (pos - out - 2 < 8) {
+ /* PKCS #1 v1.5, 8.1: At least eight octets long PS */
+ wpa_printf(MSG_INFO, "LibTomCrypt: Too short padding");
+ return -1;
+ }
pos++;
*outlen -= pos - out;
@@ -142,35 +149,26 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
* BT = 00 or 01
* PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
* k = length of modulus in octets
+ *
+ * Based on 10.1.3, "The block type shall be 01" for a signature.
*/
if (len < 3 + 8 + 16 /* min hash len */ ||
- plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
+ plain[0] != 0x00 || plain[1] != 0x01) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure");
return -1;
}
pos = plain + 3;
- if (plain[1] == 0x00) {
- /* BT = 00 */
- if (plain[2] != 0x00) {
- wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
- "PS (BT=00)");
- return -1;
- }
- while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
- pos++;
- } else {
- /* BT = 01 */
- if (plain[2] != 0xff) {
- wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
- "PS (BT=01)");
- return -1;
- }
- while (pos < plain + len && *pos == 0xff)
- pos++;
+ /* BT = 01 */
+ if (plain[2] != 0xff) {
+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+ "PS (BT=01)");
+ return -1;
}
+ while (pos < plain + len && *pos == 0xff)
+ pos++;
if (pos - plain - 2 < 8) {
/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
@@ -193,3 +191,130 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
return 0;
}
+
+
+int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
+ const u8 *s, size_t s_len,
+ const struct asn1_oid *hash_alg,
+ const u8 *hash, size_t hash_len)
+{
+ int res;
+ u8 *decrypted;
+ size_t decrypted_len;
+ const u8 *pos, *end, *next, *da_end;
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+
+ decrypted = os_malloc(s_len);
+ if (decrypted == NULL)
+ return -1;
+ decrypted_len = s_len;
+ res = crypto_public_key_decrypt_pkcs1(pk, s, s_len, decrypted,
+ &decrypted_len);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "PKCS #1: RSA decrypt failed");
+ os_free(decrypted);
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "Decrypted(S)", decrypted, decrypted_len);
+
+ /*
+ * PKCS #1 v1.5, 10.1.2:
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * digest Digest
+ * }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ *
+ */
+ if (asn1_get_next(decrypted, decrypted_len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Expected SEQUENCE (DigestInfo) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ os_free(decrypted);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /*
+ * X.509:
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Expected SEQUENCE (AlgorithmIdentifier) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ os_free(decrypted);
+ return -1;
+ }
+ da_end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Failed to parse digestAlgorithm");
+ os_free(decrypted);
+ return -1;
+ }
+
+ if (!asn1_oid_equal(&oid, hash_alg)) {
+ char txt[100], txt2[100];
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ asn1_oid_to_str(hash_alg, txt2, sizeof(txt2));
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Hash alg OID mismatch: was %s, expected %s",
+ txt, txt2);
+ os_free(decrypted);
+ return -1;
+ }
+
+ /* Digest ::= OCTET STRING */
+ pos = da_end;
+ end = decrypted + decrypted_len;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #1: Expected OCTETSTRING (Digest) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ os_free(decrypted);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #1: Decrypted Digest",
+ hdr.payload, hdr.length);
+
+ if (hdr.length != hash_len ||
+ os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
+ wpa_printf(MSG_INFO, "PKCS #1: Digest value does not match calculated hash");
+ os_free(decrypted);
+ return -1;
+ }
+
+ os_free(decrypted);
+
+ if (hdr.payload + hdr.length != end) {
+ wpa_printf(MSG_INFO,
+ "PKCS #1: Extra data after signature - reject");
+
+ wpa_hexdump(MSG_DEBUG, "PKCS #1: Extra data",
+ hdr.payload + hdr.length,
+ end - hdr.payload - hdr.length);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/tls/pkcs1.h b/src/tls/pkcs1.h
index ed64defaafe08..f37ebf3875eaa 100644
--- a/src/tls/pkcs1.h
+++ b/src/tls/pkcs1.h
@@ -9,6 +9,9 @@
#ifndef PKCS1_H
#define PKCS1_H
+struct crypto_public_key;
+struct asn1_oid;
+
int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
int use_private, const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
@@ -18,5 +21,9 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len);
+int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
+ const u8 *s, size_t s_len,
+ const struct asn1_oid *hash_alg,
+ const u8 *hash, size_t hash_len);
#endif /* PKCS1_H */
diff --git a/src/tls/rsa.c b/src/tls/rsa.c
index 125c4205b705c..0b7b530bc37c2 100644
--- a/src/tls/rsa.c
+++ b/src/tls/rsa.c
@@ -1,6 +1,6 @@
/*
* RSA
- * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -116,6 +116,29 @@ error:
}
+struct crypto_rsa_key *
+crypto_rsa_import_public_key_parts(const u8 *n, size_t n_len,
+ const u8 *e, size_t e_len)
+{
+ struct crypto_rsa_key *key;
+
+ key = os_zalloc(sizeof(*key));
+ if (key == NULL)
+ return NULL;
+
+ key->n = bignum_init();
+ key->e = bignum_init();
+ if (key->n == NULL || key->e == NULL ||
+ bignum_set_unsigned_bin(key->n, n, n_len) < 0 ||
+ bignum_set_unsigned_bin(key->e, e, e_len) < 0) {
+ crypto_rsa_free(key);
+ return NULL;
+ }
+
+ return key;
+}
+
+
/**
* crypto_rsa_import_private_key - Import an RSA private key
* @buf: Key buffer (DER encoded RSA private key)
diff --git a/src/tls/rsa.h b/src/tls/rsa.h
index c236a9df44498..b65818ee1546a 100644
--- a/src/tls/rsa.h
+++ b/src/tls/rsa.h
@@ -14,6 +14,9 @@ struct crypto_rsa_key;
struct crypto_rsa_key *
crypto_rsa_import_public_key(const u8 *buf, size_t len);
struct crypto_rsa_key *
+crypto_rsa_import_public_key_parts(const u8 *n, size_t n_len,
+ const u8 *e, size_t e_len);
+struct crypto_rsa_key *
crypto_rsa_import_private_key(const u8 *buf, size_t len);
size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key);
int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 12148b61ddfc4..facdd659173db 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -459,10 +459,15 @@ struct tlsv1_client * tlsv1_client_init(void)
count = 0;
suites = conn->cipher_suites;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
@@ -565,8 +570,26 @@ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
cipher = "DES-CBC3-SHA";
break;
- case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
- cipher = "ADH-AES-128-SHA256";
+ case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC3-SHA";
+ break;
+ case TLS_DH_anon_WITH_RC4_128_MD5:
+ cipher = "ADH-RC4-MD5";
+ break;
+ case TLS_DH_anon_WITH_DES_CBC_SHA:
+ cipher = "ADH-DES-SHA";
+ break;
+ case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ cipher = "ADH-DES-CBC3-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "AES-128-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "DHE-RSA-AES-128-SHA";
break;
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
cipher = "ADH-AES-128-SHA";
@@ -574,15 +597,30 @@ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
case TLS_RSA_WITH_AES_256_CBC_SHA:
cipher = "AES-256-SHA";
break;
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- cipher = "AES-256-SHA256";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ cipher = "DHE-RSA-AES-256-SHA";
break;
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- cipher = "AES-128-SHA";
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ cipher = "ADH-AES-256-SHA";
break;
case TLS_RSA_WITH_AES_128_CBC_SHA256:
cipher = "AES-128-SHA256";
break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "AES-256-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "DHE-RSA-AES-128-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "DHE-RSA-AES-256-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ cipher = "ADH-AES-128-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ cipher = "ADH-AES-256-SHA256";
+ break;
default:
return -1;
}
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 3269ecf668ee3..9ce96803753a9 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - read handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -409,10 +409,38 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
}
+static unsigned int count_bits(const u8 *val, size_t len)
+{
+ size_t i;
+ unsigned int bits;
+ u8 tmp;
+
+ for (i = 0; i < len; i++) {
+ if (val[i])
+ break;
+ }
+ if (i == len)
+ return 0;
+
+ bits = (len - i - 1) * 8;
+ tmp = val[i];
+ while (tmp) {
+ bits++;
+ tmp >>= 1;
+ }
+
+ return bits;
+}
+
+
static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ tls_key_exchange key_exchange)
{
- const u8 *pos, *end;
+ const u8 *pos, *end, *server_params, *server_params_end;
+ u8 alert;
+ unsigned int bits;
+ u16 val;
tlsv1_client_free_dh(conn);
@@ -421,11 +449,20 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (end - pos < 3)
goto fail;
- conn->dh_p_len = WPA_GET_BE16(pos);
+ server_params = pos;
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
- (unsigned long) conn->dh_p_len);
+ if (val == 0 || val > (size_t) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %u", val);
+ goto fail;
+ }
+ conn->dh_p_len = val;
+ bits = count_bits(pos, conn->dh_p_len);
+ if (bits < 768) {
+ wpa_printf(MSG_INFO, "TLSv1: Reject under 768-bit DH prime (insecure; only %u bits)",
+ bits);
+ wpa_hexdump(MSG_DEBUG, "TLSv1: Rejected DH prime",
+ pos, conn->dh_p_len);
goto fail;
}
conn->dh_p = os_malloc(conn->dh_p_len);
@@ -438,10 +475,11 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (end - pos < 3)
goto fail;
- conn->dh_g_len = WPA_GET_BE16(pos);
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
+ if (val == 0 || val > (size_t) (end - pos))
goto fail;
+ conn->dh_g_len = val;
conn->dh_g = os_malloc(conn->dh_g_len);
if (conn->dh_g == NULL)
goto fail;
@@ -454,10 +492,11 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (end - pos < 3)
goto fail;
- conn->dh_ys_len = WPA_GET_BE16(pos);
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
+ if (val == 0 || val > (size_t) (end - pos))
goto fail;
+ conn->dh_ys_len = val;
conn->dh_ys = os_malloc(conn->dh_ys_len);
if (conn->dh_ys == NULL)
goto fail;
@@ -465,6 +504,59 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
pos += conn->dh_ys_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
conn->dh_ys, conn->dh_ys_len);
+ server_params_end = pos;
+
+ if (key_exchange == TLS_KEY_X_DHE_RSA) {
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+ int hlen;
+
+ if (conn->rl.tls_version == TLS_VERSION_1_2) {
+#ifdef CONFIG_TLSV12
+ /*
+ * RFC 5246, 4.7:
+ * TLS v1.2 adds explicit indication of the used
+ * signature and hash algorithms.
+ *
+ * struct {
+ * HashAlgorithm hash;
+ * SignatureAlgorithm signature;
+ * } SignatureAndHashAlgorithm;
+ */
+ if (end - pos < 2)
+ goto fail;
+ if (pos[0] != TLS_HASH_ALG_SHA256 ||
+ pos[1] != TLS_SIGN_ALG_RSA) {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
+ pos[0], pos[1]);
+ goto fail;
+ }
+ pos += 2;
+
+ hlen = tlsv12_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ server_params_end - server_params, hash);
+#else /* CONFIG_TLSV12 */
+ goto fail;
+#endif /* CONFIG_TLSV12 */
+ } else {
+ hlen = tls_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ server_params_end - server_params, hash);
+ }
+
+ if (hlen < 0)
+ goto fail;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash",
+ hash, hlen);
+
+ if (tls_verify_signature(conn->rl.tls_version,
+ conn->server_rsa_key,
+ hash, hlen, pos, end - pos,
+ &alert) < 0)
+ goto fail;
+ }
return 0;
@@ -543,8 +635,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
- if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
- if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
+ if (suite && (suite->key_exchange == TLS_KEY_X_DH_anon ||
+ suite->key_exchange == TLS_KEY_X_DHE_RSA)) {
+ if (tlsv1_process_diffie_hellman(conn, pos, len,
+ suite->key_exchange) < 0) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -871,8 +965,10 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
verify_data, TLS_VERIFY_DATA_LEN);
- if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+ if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECRYPT_ERROR);
return -1;
}
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index d789efb4255e2..d192f44f40882 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - write handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -205,7 +205,7 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
}
-static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
+static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
{
/* ClientDiffieHellmanPublic */
u8 *csecret, *csecret_start, *dh_yc, *shared;
@@ -399,8 +399,8 @@ static int tls_write_client_key_exchange(struct tlsv1_client *conn,
hs_length = pos;
pos += 3;
/* body - ClientKeyExchange */
- if (keyx == TLS_KEY_X_DH_anon) {
- if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
+ if (keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) {
+ if (tlsv1_key_x_dh(conn, &pos, end) < 0)
return -1;
} else {
if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
@@ -432,7 +432,6 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
size_t rlen, hlen, clen;
u8 hash[100], *hpos;
- enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
pos = *msgpos;
@@ -505,21 +504,17 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
} else {
#endif /* CONFIG_TLSV12 */
- if (alg == SIGN_ALG_RSA) {
- hlen = MD5_MAC_LEN;
- if (conn->verify.md5_cert == NULL ||
- crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
- {
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify.md5_cert = NULL;
- crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
- conn->verify.sha1_cert = NULL;
- return -1;
- }
- hpos += MD5_MAC_LEN;
- } else
- crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_cert == NULL ||
+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_cert = NULL;
+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+ conn->verify.sha1_cert = NULL;
+ return -1;
+ }
+ hpos += MD5_MAC_LEN;
conn->verify.md5_cert = NULL;
hlen = SHA1_MAC_LEN;
@@ -532,8 +527,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
}
conn->verify.sha1_cert = NULL;
- if (alg == SIGN_ALG_RSA)
- hlen += MD5_MAC_LEN;
+ hlen += MD5_MAC_LEN;
#ifdef CONFIG_TLSV12
}
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index d21286283b83a..dabc12a129788 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -1,6 +1,6 @@
/*
* TLSv1 common routines
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "x509v3.h"
@@ -33,6 +34,10 @@ static const struct tls_cipher_suite tls_cipher_suites[] = {
TLS_HASH_SHA },
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
+ { TLS_DHE_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_DHE_RSA, TLS_CIPHER_DES_CBC,
+ TLS_HASH_SHA},
+ { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
@@ -41,24 +46,31 @@ static const struct tls_cipher_suite tls_cipher_suites[] = {
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
TLS_HASH_SHA },
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
TLS_HASH_SHA },
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+ { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DHE_RSA,
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
};
-#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
-#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
+#define NUM_TLS_CIPHER_SUITES ARRAY_SIZE(tls_cipher_suites)
static const struct tls_cipher_data tls_ciphers[] = {
@@ -84,7 +96,7 @@ static const struct tls_cipher_data tls_ciphers[] = {
CRYPTO_CIPHER_ALG_AES }
};
-#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
+#define NUM_TLS_CIPHER_DATA ARRAY_SIZE(tls_ciphers)
/**
@@ -320,3 +332,161 @@ int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
outlen);
}
+
+
+#ifdef CONFIG_TLSV12
+int tlsv12_key_x_server_params_hash(u16 tls_version,
+ const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash)
+{
+ size_t hlen;
+ struct crypto_hash *ctx;
+
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
+ if (ctx == NULL)
+ return -1;
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_params, server_params_len);
+ hlen = SHA256_MAC_LEN;
+ if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+ return -1;
+
+ return hlen;
+}
+#endif /* CONFIG_TLSV12 */
+
+
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash)
+{
+ u8 *hpos;
+ size_t hlen;
+ struct crypto_hash *ctx;
+
+ hpos = hash;
+
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+ if (ctx == NULL)
+ return -1;
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_params, server_params_len);
+ hlen = MD5_MAC_LEN;
+ if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+ return -1;
+ hpos += hlen;
+
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+ if (ctx == NULL)
+ return -1;
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_params, server_params_len);
+ hlen = hash + sizeof(hash) - hpos;
+ if (crypto_hash_finish(ctx, hpos, &hlen) < 0)
+ return -1;
+ hpos += hlen;
+ return hpos - hash;
+}
+
+
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+ const u8 *data, size_t data_len,
+ const u8 *pos, size_t len, u8 *alert)
+{
+ u8 *buf;
+ const u8 *end = pos + len;
+ const u8 *decrypted;
+ u16 slen;
+ size_t buflen;
+
+ if (end - pos < 2) {
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+ slen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < slen) {
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+ if (end - pos > slen) {
+ wpa_hexdump(MSG_MSGDUMP, "Additional data after Signature",
+ pos + slen, end - pos - slen);
+ end = pos + slen;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
+ if (pk == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No public key to verify signature");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+
+ buflen = end - pos;
+ buf = os_malloc(end - pos);
+ if (buf == NULL) {
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+ if (crypto_public_key_decrypt_pkcs1(pk, pos, end - pos, buf, &buflen) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
+ os_free(buf);
+ *alert = TLS_ALERT_DECRYPT_ERROR;
+ return -1;
+ }
+ decrypted = buf;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
+ decrypted, buflen);
+
+#ifdef CONFIG_TLSV12
+ if (tls_version >= TLS_VERSION_1_2) {
+ /*
+ * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithm,
+ * digest OCTET STRING
+ * }
+ *
+ * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+ *
+ * DER encoded DigestInfo for SHA256 per RFC 3447:
+ * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+ * H
+ */
+ if (buflen >= 19 + 32 &&
+ os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+ "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+ {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-256");
+ decrypted = buf + 19;
+ buflen -= 19;
+ } else {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
+ os_free(buf);
+ *alert = TLS_ALERT_DECRYPT_ERROR;
+ return -1;
+ }
+ }
+#endif /* CONFIG_TLSV12 */
+
+ if (buflen != data_len ||
+ os_memcmp_const(decrypted, data, data_len) != 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
+ os_free(buf);
+ *alert = TLS_ALERT_DECRYPT_ERROR;
+ return -1;
+ }
+
+ os_free(buf);
+
+ return 0;
+}
diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h
index f28c0cdc47906..26e68af166069 100644
--- a/src/tls/tlsv1_common.h
+++ b/src/tls/tlsv1_common.h
@@ -1,6 +1,6 @@
/*
* TLSv1 common definitions
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -257,5 +257,16 @@ int tls_version_ok(u16 ver);
const char * tls_version_str(u16 ver);
int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
+int tlsv12_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash);
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
+ const u8 *server_random,
+ const u8 *server_params,
+ size_t server_params_len, u8 *hash);
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
+ const u8 *data, size_t data_len,
+ const u8 *pos, size_t len, u8 *alert);
#endif /* TLSV1_COMMON_H */
diff --git a/src/tls/tlsv1_record.c b/src/tls/tlsv1_record.c
index 3bec3be36f073..0c6897a8fc23b 100644
--- a/src/tls/tlsv1_record.c
+++ b/src/tls/tlsv1_record.c
@@ -456,7 +456,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
return -1;
}
if (hlen != rl->hash_size ||
- os_memcmp(hash, out_data + plen, hlen) != 0 ||
+ os_memcmp_const(hash, out_data + plen, hlen) != 0 ||
force_mac_error) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
"received message (force_mac_error=%d)",
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 2880309ebf515..93ae4888d8980 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,6 +21,31 @@
*/
+void tlsv1_server_log(struct tlsv1_server *conn, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ va_start(ap, fmt);
+ vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+
+ wpa_printf(MSG_DEBUG, "TLSv1: %s", buf);
+ if (conn->log_cb)
+ conn->log_cb(conn->log_cb_ctx, buf);
+
+ os_free(buf);
+}
+
+
void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
{
conn->alert_level = level;
@@ -250,8 +275,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
out_pos, &olen, &alert);
if (used < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
- "failed");
+ tlsv1_server_log(conn, "Record layer processing failed");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
return -1;
}
@@ -265,14 +289,13 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
if (ct == TLS_CONTENT_TYPE_ALERT) {
if (olen < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Alert "
- "underflow");
+ tlsv1_server_log(conn, "Alert underflow");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
- out_pos[0], out_pos[1]);
+ tlsv1_server_log(conn, "Received alert %d:%d",
+ out_pos[0], out_pos[1]);
if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
/* Continue processing */
pos += used;
@@ -285,13 +308,23 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
}
if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
- "0x%x", pos[0]);
+ tlsv1_server_log(conn, "Unexpected content type 0x%x",
+ pos[0]);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if ((conn->test_flags &
+ (TLS_BREAK_VERIFY_DATA | TLS_BREAK_SRV_KEY_X_HASH |
+ TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client ApplData received after invalid handshake");
+ conn->test_failure_reported = 1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
out_pos += olen;
if (out_pos > out_end) {
wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -361,8 +394,15 @@ struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
count = 0;
suites = conn->cipher_suites;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+ suites[count++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
@@ -476,14 +516,56 @@ int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
cipher = "DES-CBC3-SHA";
break;
+ case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC3-SHA";
+ break;
+ case TLS_DH_anon_WITH_RC4_128_MD5:
+ cipher = "ADH-RC4-MD5";
+ break;
+ case TLS_DH_anon_WITH_DES_CBC_SHA:
+ cipher = "ADH-DES-SHA";
+ break;
+ case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ cipher = "ADH-DES-CBC3-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "AES-128-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "DHE-RSA-AES-128-SHA";
+ break;
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
cipher = "ADH-AES-128-SHA";
break;
case TLS_RSA_WITH_AES_256_CBC_SHA:
cipher = "AES-256-SHA";
break;
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- cipher = "AES-128-SHA";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ cipher = "DHE-RSA-AES-256-SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ cipher = "ADH-AES-256-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "AES-128-SHA256";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "AES-256-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "DHE-RSA-AES-128-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "DHE-RSA-AES-256-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ cipher = "ADH-AES-128-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ cipher = "ADH-AES-256-SHA256";
break;
default:
return -1;
@@ -618,3 +700,125 @@ void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
}
+
+
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+ void (*cb)(void *ctx, const char *msg), void *ctx)
+{
+ conn->log_cb = cb;
+ conn->log_cb_ctx = ctx;
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags)
+{
+ conn->test_flags = flags;
+}
+
+
+static const u8 test_tls_prime15[1] = {
+ 15
+};
+
+static const u8 test_tls_prime511b[64] = {
+ 0x50, 0xfb, 0xf1, 0xae, 0x01, 0xf1, 0xfe, 0xe6,
+ 0xe1, 0xae, 0xdc, 0x1e, 0xbe, 0xfb, 0x9e, 0x58,
+ 0x9a, 0xd7, 0x54, 0x9d, 0x6b, 0xb3, 0x78, 0xe2,
+ 0x39, 0x7f, 0x30, 0x01, 0x25, 0xa1, 0xf9, 0x7c,
+ 0x55, 0x0e, 0xa1, 0x15, 0xcc, 0x36, 0x34, 0xbb,
+ 0x6c, 0x8b, 0x64, 0x45, 0x15, 0x7f, 0xd3, 0xe7,
+ 0x31, 0xc8, 0x8e, 0x56, 0x8e, 0x95, 0xdc, 0xea,
+ 0x9e, 0xdf, 0xf7, 0x56, 0xdd, 0xb0, 0x34, 0xdb
+};
+
+static const u8 test_tls_prime767b[96] = {
+ 0x4c, 0xdc, 0xb8, 0x21, 0x20, 0x9d, 0xe8, 0xa3,
+ 0x53, 0xd9, 0x1c, 0x18, 0xc1, 0x3a, 0x58, 0x67,
+ 0xa7, 0x85, 0xf9, 0x28, 0x9b, 0xce, 0xc0, 0xd1,
+ 0x05, 0x84, 0x61, 0x97, 0xb2, 0x86, 0x1c, 0xd0,
+ 0xd1, 0x96, 0x23, 0x29, 0x8c, 0xc5, 0x30, 0x68,
+ 0x3e, 0xf9, 0x05, 0xba, 0x60, 0xeb, 0xdb, 0xee,
+ 0x2d, 0xdf, 0x84, 0x65, 0x49, 0x87, 0x90, 0x2a,
+ 0xc9, 0x8e, 0x34, 0x63, 0x6d, 0x9a, 0x2d, 0x32,
+ 0x1c, 0x46, 0xd5, 0x4e, 0x20, 0x20, 0x90, 0xac,
+ 0xd5, 0x48, 0x79, 0x99, 0x0c, 0xe6, 0xed, 0xbf,
+ 0x79, 0xc2, 0x47, 0x50, 0x95, 0x38, 0x38, 0xbc,
+ 0xde, 0xb0, 0xd2, 0xe8, 0x97, 0xcb, 0x22, 0xbb
+};
+
+static const u8 test_tls_prime58[128] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0xc1, 0xba, 0xc8, 0x25, 0xbe, 0x2d, 0xf3
+};
+
+static const u8 test_tls_non_prime[] = {
+ /*
+ * This is not a prime and the value has the following factors:
+ * 13736783488716579923 * 16254860191773456563 * 18229434976173670763 *
+ * 11112313018289079419 * 10260802278580253339 * 12394009491575311499 *
+ * 12419059668711064739 * 14317973192687985827 * 10498605410533203179 *
+ * 16338688760390249003 * 11128963991123878883 * 12990532258280301419 *
+ * 3
+ */
+ 0x0C, 0x8C, 0x36, 0x9C, 0x6F, 0x71, 0x2E, 0xA7,
+ 0xAB, 0x32, 0xD3, 0x0F, 0x68, 0x3D, 0xB2, 0x6D,
+ 0x81, 0xDD, 0xC4, 0x84, 0x0D, 0x9C, 0x6E, 0x36,
+ 0x29, 0x70, 0xF3, 0x1E, 0x9A, 0x42, 0x0B, 0x67,
+ 0x82, 0x6B, 0xB1, 0xF2, 0xAF, 0x55, 0x28, 0xE7,
+ 0xDB, 0x67, 0x6C, 0xF7, 0x6B, 0xAC, 0xAC, 0xE5,
+ 0xF7, 0x9F, 0xD4, 0x63, 0x55, 0x70, 0x32, 0x7C,
+ 0x70, 0xFB, 0xAF, 0xB8, 0xEB, 0x37, 0xCF, 0x3F,
+ 0xFE, 0x94, 0x73, 0xF9, 0x7A, 0xC7, 0x12, 0x2E,
+ 0x9B, 0xB4, 0x7D, 0x08, 0x60, 0x83, 0x43, 0x52,
+ 0x83, 0x1E, 0xA5, 0xFC, 0xFA, 0x87, 0x12, 0xF4,
+ 0x64, 0xE2, 0xCE, 0x71, 0x17, 0x72, 0xB6, 0xAB
+};
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p,
+ size_t *dh_p_len)
+{
+ *dh_p = conn->cred->dh_p;
+ *dh_p_len = conn->cred->dh_p_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_DHE_PRIME_511B) {
+ tlsv1_server_log(conn, "TESTING: Use short 511-bit prime with DHE");
+ *dh_p = test_tls_prime511b;
+ *dh_p_len = sizeof(test_tls_prime511b);
+ } else if (conn->test_flags & TLS_DHE_PRIME_767B) {
+ tlsv1_server_log(conn, "TESTING: Use short 767-bit prime with DHE");
+ *dh_p = test_tls_prime767b;
+ *dh_p_len = sizeof(test_tls_prime767b);
+ } else if (conn->test_flags & TLS_DHE_PRIME_15) {
+ tlsv1_server_log(conn, "TESTING: Use bogus 15 \"prime\" with DHE");
+ *dh_p = test_tls_prime15;
+ *dh_p_len = sizeof(test_tls_prime15);
+ } else if (conn->test_flags & TLS_DHE_PRIME_58B) {
+ tlsv1_server_log(conn, "TESTING: Use short 58-bit prime in long container with DHE");
+ *dh_p = test_tls_prime58;
+ *dh_p_len = sizeof(test_tls_prime58);
+ } else if (conn->test_flags & TLS_DHE_NON_PRIME) {
+ tlsv1_server_log(conn, "TESTING: Use claim non-prime as the DHE prime");
+ *dh_p = test_tls_non_prime;
+ *dh_p_len = sizeof(test_tls_non_prime);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+}
diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h
index a18c69e37c16a..b2b28d1e1215a 100644
--- a/src/tls/tlsv1_server.h
+++ b/src/tls/tlsv1_server.h
@@ -45,4 +45,9 @@ void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
tlsv1_server_session_ticket_cb cb,
void *ctx);
+void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
+ void (*cb)(void *ctx, const char *msg), void *ctx);
+
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags);
+
#endif /* TLSV1_SERVER_H */
diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h
index 1f61533a5aa07..96d79b3a8ba25 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -51,13 +51,24 @@ struct tlsv1_server {
tlsv1_server_session_ticket_cb session_ticket_cb;
void *session_ticket_cb_ctx;
+ void (*log_cb)(void *ctx, const char *msg);
+ void *log_cb_ctx;
+
int use_session_ticket;
u8 *dh_secret;
size_t dh_secret_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ u32 test_flags;
+ int test_failure_reported;
+#endif /* CONFIG_TESTING_OPTIONS */
};
+void tlsv1_server_log(struct tlsv1_server *conn, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+
void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
int tlsv1_server_derive_keys(struct tlsv1_server *conn,
const u8 *pre_master_secret,
@@ -67,5 +78,7 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
u8 description, size_t *out_len);
int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
const u8 *buf, size_t *len);
+void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p,
+ size_t *dh_p_len);
#endif /* TLSV1_SERVER_I_H */
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 6f6539b1bfb5d..0f237baff9db6 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 server - read handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,6 +27,25 @@ static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
size_t *in_len);
+static int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ if ((conn->test_flags &
+ (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE |
+ TLS_DHE_PRIME_511B | TLS_DHE_PRIME_767B | TLS_DHE_PRIME_15 |
+ TLS_DHE_PRIME_58B | TLS_DHE_NON_PRIME)) &&
+ suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 &&
+ suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA &&
+ suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 &&
+ suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA &&
+ suite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
+ return 1;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return 0;
+}
+
+
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -38,8 +57,8 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
u16 ext_type, ext_len;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -53,13 +72,13 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
/* HandshakeType msg_type */
if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ClientHello)", *pos);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientHello)",
+ *pos);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
+ tlsv1_server_log(conn, "Received ClientHello");
pos++;
/* uint24 length */
len = WPA_GET_BE24(pos);
@@ -78,13 +97,13 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
if (end - pos < 2)
goto decode_error;
conn->client_version = WPA_GET_BE16(pos);
- wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
- conn->client_version >> 8, conn->client_version & 0xff);
+ tlsv1_server_log(conn, "Client version %d.%d",
+ conn->client_version >> 8,
+ conn->client_version & 0xff);
if (conn->client_version < TLS_VERSION_1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
- "ClientHello %u.%u",
- conn->client_version >> 8,
- conn->client_version & 0xff);
+ tlsv1_server_log(conn, "Unexpected protocol version in ClientHello %u.%u",
+ conn->client_version >> 8,
+ conn->client_version & 0xff);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_PROTOCOL_VERSION);
return -1;
@@ -101,8 +120,8 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
conn->rl.tls_version = TLS_VERSION_1_1;
else
conn->rl.tls_version = conn->client_version;
- wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
- tls_version_str(conn->rl.tls_version));
+ tlsv1_server_log(conn, "Using TLS v%s",
+ tls_version_str(conn->rl.tls_version));
/* Random random */
if (end - pos < TLS_RANDOM_LEN)
@@ -137,6 +156,8 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
cipher_suite = 0;
for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
+ if (testing_cipher_suite_filter(conn, conn->cipher_suites[i]))
+ continue;
c = pos;
for (j = 0; j < num_suites; j++) {
u16 tmp = WPA_GET_BE16(c);
@@ -149,8 +170,7 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
}
pos += num_suites * 2;
if (!cipher_suite) {
- wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
- "available");
+ tlsv1_server_log(conn, "No supported cipher suite available");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
@@ -180,16 +200,15 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
compr_null_found = 1;
}
if (!compr_null_found) {
- wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
- "compression");
+ tlsv1_server_log(conn, "Client does not accept NULL compression");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
}
if (end - pos == 1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
- "end of ClientHello: 0x%02x", *pos);
+ tlsv1_server_log(conn, "Unexpected extra octet in the end of ClientHello: 0x%02x",
+ *pos);
goto decode_error;
}
@@ -198,12 +217,11 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
ext_len = WPA_GET_BE16(pos);
pos += 2;
- wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
- "extensions", ext_len);
+ tlsv1_server_log(conn, "%u bytes of ClientHello extensions",
+ ext_len);
if (end - pos != ext_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
- "extension list length %u (expected %u)",
- ext_len, (unsigned int) (end - pos));
+ tlsv1_server_log(conn, "Invalid ClientHello extension list length %u (expected %u)",
+ ext_len, (unsigned int) (end - pos));
goto decode_error;
}
@@ -216,8 +234,7 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
while (pos < end) {
if (end - pos < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
- "extension_type field");
+ tlsv1_server_log(conn, "Invalid extension_type field");
goto decode_error;
}
@@ -225,8 +242,7 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
pos += 2;
if (end - pos < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
- "extension_data length field");
+ tlsv1_server_log(conn, "Invalid extension_data length field");
goto decode_error;
}
@@ -234,13 +250,12 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
pos += 2;
if (end - pos < ext_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
- "extension_data field");
+ tlsv1_server_log(conn, "Invalid extension_data field");
goto decode_error;
}
- wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
- "type %u", ext_type);
+ tlsv1_server_log(conn, "ClientHello Extension type %u",
+ ext_type);
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
"Extension data", pos, ext_len);
@@ -260,14 +275,13 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
*in_len = end - in_data;
- wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
- "ServerHello");
+ tlsv1_server_log(conn, "ClientHello OK - proceed to ServerHello");
conn->state = SERVER_HELLO;
return 0;
decode_error:
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
+ tlsv1_server_log(conn, "Failed to decode ClientHello");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -284,8 +298,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
int reason;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -295,8 +309,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
- "(len=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short Certificate message (len=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -308,9 +322,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Unexpected Certificate message length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -318,8 +331,7 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
if (conn->verify_peer) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
- "Certificate");
+ tlsv1_server_log(conn, "Client did not include Certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -329,17 +341,15 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
in_len);
}
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected Certificate/"
- "ClientKeyExchange)", type);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected Certificate/ClientKeyExchange)",
+ type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG,
- "TLSv1: Received Certificate (certificate_list len %lu)",
- (unsigned long) len);
+ tlsv1_server_log(conn, "Received Certificate (certificate_list len %lu)",
+ (unsigned long) len);
/*
* opaque ASN.1Cert<2^24-1>;
@@ -352,8 +362,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
end = pos + len;
if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
- "(left=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short Certificate (left=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -363,10 +373,9 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
pos += 3;
if ((size_t) (end - pos) != list_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
- "length (len=%lu left=%lu)",
- (unsigned long) list_len,
- (unsigned long) (end - pos));
+ tlsv1_server_log(conn, "Unexpected certificate_list length (len=%lu left=%lu)",
+ (unsigned long) list_len,
+ (unsigned long) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -375,8 +384,7 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
idx = 0;
while (pos < end) {
if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "certificate_list");
+ tlsv1_server_log(conn, "Failed to parse certificate_list");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
@@ -387,25 +395,23 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
pos += 3;
if ((size_t) (end - pos) < cert_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
- "length (len=%lu left=%lu)",
- (unsigned long) cert_len,
- (unsigned long) (end - pos));
+ tlsv1_server_log(conn, "Unexpected certificate length (len=%lu left=%lu)",
+ (unsigned long) cert_len,
+ (unsigned long) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
- (unsigned long) idx, (unsigned long) cert_len);
+ tlsv1_server_log(conn, "Certificate %lu (len %lu)",
+ (unsigned long) idx, (unsigned long) cert_len);
if (idx == 0) {
crypto_public_key_free(conn->client_rsa_key);
if (tls_parse_cert(pos, cert_len,
&conn->client_rsa_key)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
+ tlsv1_server_log(conn, "Failed to parse the certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
@@ -415,8 +421,7 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
cert = x509_certificate_parse(pos, cert_len);
if (cert == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
+ tlsv1_server_log(conn, "Failed to parse the certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
@@ -436,8 +441,8 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
&reason, 0) < 0) {
int tls_reason;
- wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
- "validation failed (reason=%d)", reason);
+ tlsv1_server_log(conn, "Server certificate chain validation failed (reason=%d)",
+ reason);
switch (reason) {
case X509_VALIDATE_BAD_CERTIFICATE:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
@@ -494,9 +499,8 @@ static int tls_process_client_key_exchange_rsa(
encr_len = WPA_GET_BE16(pos);
pos += 2;
if (pos + encr_len > end) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
- "format: encr_len=%u left=%u",
- encr_len, (unsigned int) (end - pos));
+ tlsv1_server_log(conn, "Invalid ClientKeyExchange format: encr_len=%u left=%u",
+ encr_len, (unsigned int) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -539,15 +543,13 @@ static int tls_process_client_key_exchange_rsa(
}
if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
- "length %lu", (unsigned long) outlen);
+ tlsv1_server_log(conn, "Unexpected PreMasterSecret length %lu",
+ (unsigned long) outlen);
use_random = 1;
}
if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
- "ClientKeyExchange does not match with version in "
- "ClientHello");
+ tlsv1_server_log(conn, "Client version in ClientKeyExchange does not match with version in ClientHello");
use_random = 1;
}
@@ -582,7 +584,7 @@ static int tls_process_client_key_exchange_rsa(
}
-static int tls_process_client_key_exchange_dh_anon(
+static int tls_process_client_key_exchange_dh(
struct tlsv1_server *conn, const u8 *pos, const u8 *end)
{
const u8 *dh_yc;
@@ -590,6 +592,8 @@ static int tls_process_client_key_exchange_dh_anon(
u8 *shared;
size_t shared_len;
int res;
+ const u8 *dh_p;
+ size_t dh_p_len;
/*
* struct {
@@ -600,6 +604,7 @@ static int tls_process_client_key_exchange_dh_anon(
* } ClientDiffieHellmanPublic;
*/
+ tlsv1_server_log(conn, "ClientDiffieHellmanPublic received");
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
pos, end - pos);
@@ -612,8 +617,7 @@ static int tls_process_client_key_exchange_dh_anon(
}
if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
- "length");
+ tlsv1_server_log(conn, "Invalid client public value length");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -622,9 +626,9 @@ static int tls_process_client_key_exchange_dh_anon(
dh_yc_len = WPA_GET_BE16(pos);
dh_yc = pos + 2;
- if (dh_yc + dh_yc_len > end) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
- "(length %d)", dh_yc_len);
+ if (dh_yc_len > end - dh_yc) {
+ tlsv1_server_log(conn, "Client public value overflow (length %d)",
+ dh_yc_len);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -641,7 +645,9 @@ static int tls_process_client_key_exchange_dh_anon(
return -1;
}
- shared_len = conn->cred->dh_p_len;
+ tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
+
+ shared_len = dh_p_len;
shared = os_malloc(shared_len);
if (shared == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
@@ -653,8 +659,7 @@ static int tls_process_client_key_exchange_dh_anon(
/* shared = Yc^secret mod p */
if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
- conn->dh_secret_len,
- conn->cred->dh_p, conn->cred->dh_p_len,
+ conn->dh_secret_len, dh_p, dh_p_len,
shared, &shared_len)) {
os_free(shared);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -695,8 +700,8 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
const struct tls_cipher_suite *suite;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -706,8 +711,8 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange "
- "(Left=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short ClientKeyExchange (Left=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -719,9 +724,8 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Mismatch in ClientKeyExchange length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -730,14 +734,14 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
end = pos + len;
if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ClientKeyExchange)", type);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientKeyExchange)",
+ type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
+ tlsv1_server_log(conn, "Received ClientKeyExchange");
wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
@@ -747,11 +751,11 @@ static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
else
keyx = suite->key_exchange;
- if (keyx == TLS_KEY_X_DH_anon &&
- tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
+ if ((keyx == TLS_KEY_X_DH_anon || keyx == TLS_KEY_X_DHE_RSA) &&
+ tls_process_client_key_exchange_dh(conn, pos, end) < 0)
return -1;
- if (keyx != TLS_KEY_X_DH_anon &&
+ if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA &&
tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
return -1;
@@ -769,15 +773,13 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
const u8 *pos, *end;
size_t left, len;
u8 type;
- size_t hlen, buflen;
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
- enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
- u16 slen;
+ size_t hlen;
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
+ u8 alert;
if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
if (conn->verify_peer) {
- wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
- "CertificateVerify");
+ tlsv1_server_log(conn, "Client did not include CertificateVerify");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -788,8 +790,8 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
}
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -799,8 +801,8 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
- "message (len=%lu)", (unsigned long) left);
+ tlsv1_server_log(conn, "Too short CertificateVerify message (len=%lu)",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -812,9 +814,8 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
- "message length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Unexpected CertificateVerify message length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -823,14 +824,14 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
end = pos + len;
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected CertificateVerify)", type);
+ tlsv1_server_log(conn, "Received unexpected handshake message %d (expected CertificateVerify)",
+ type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
+ tlsv1_server_log(conn, "Received CertificateVerify");
/*
* struct {
@@ -881,21 +882,17 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
} else {
#endif /* CONFIG_TLSV12 */
- if (alg == SIGN_ALG_RSA) {
- hlen = MD5_MAC_LEN;
- if (conn->verify.md5_cert == NULL ||
- crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
- {
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify.md5_cert = NULL;
- crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
- conn->verify.sha1_cert = NULL;
- return -1;
- }
- hpos += MD5_MAC_LEN;
- } else
- crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_cert == NULL ||
+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_cert = NULL;
+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+ conn->verify.sha1_cert = NULL;
+ return -1;
+ }
+ hpos += MD5_MAC_LEN;
conn->verify.md5_cert = NULL;
hlen = SHA1_MAC_LEN;
@@ -908,8 +905,7 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
}
conn->verify.sha1_cert = NULL;
- if (alg == SIGN_ALG_RSA)
- hlen += MD5_MAC_LEN;
+ hlen += MD5_MAC_LEN;
#ifdef CONFIG_TLSV12
}
@@ -917,90 +913,13 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
- if (end - pos < 2) {
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- slen = WPA_GET_BE16(pos);
- pos += 2;
- if (end - pos < slen) {
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
+ if (tls_verify_signature(conn->rl.tls_version, conn->client_rsa_key,
+ hash, hlen, pos, end - pos, &alert) < 0) {
+ tlsv1_server_log(conn, "Invalid Signature in CertificateVerify");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
return -1;
}
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
- if (conn->client_rsa_key == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
- "signature");
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- buflen = end - pos;
- buf = os_malloc(end - pos);
- if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
- pos, end - pos, buf, &buflen) < 0)
- {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
- os_free(buf);
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
-
- wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
- buf, buflen);
-
-#ifdef CONFIG_TLSV12
- if (conn->rl.tls_version >= TLS_VERSION_1_2) {
- /*
- * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
- *
- * DigestInfo ::= SEQUENCE {
- * digestAlgorithm DigestAlgorithm,
- * digest OCTET STRING
- * }
- *
- * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
- *
- * DER encoded DigestInfo for SHA256 per RFC 3447:
- * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
- * H
- */
- if (buflen >= 19 + 32 &&
- os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
- "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
- {
- wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
- "SHA-256");
- os_memmove(buf, buf + 19, buflen - 19);
- buflen -= 19;
- } else {
- wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
- "DigestInfo");
- os_free(buf);
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
- }
-#endif /* CONFIG_TLSV12 */
-
- if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
- "CertificateVerify - did not match with calculated "
- "hash");
- os_free(buf);
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
-
- os_free(buf);
-
*in_len = end - in_data;
conn->state = CHANGE_CIPHER_SPEC;
@@ -1017,8 +936,8 @@ static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
size_t left;
if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected ChangeCipherSpec; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -1028,21 +947,21 @@ static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
left = *in_len;
if (left < 1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+ tlsv1_server_log(conn, "Too short ChangeCipherSpec");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
if (*pos != TLS_CHANGE_CIPHER_SPEC) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
- "received data 0x%x", *pos);
+ tlsv1_server_log(conn, "Expected ChangeCipherSpec; received data 0x%x",
+ *pos);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+ tlsv1_server_log(conn, "Received ChangeCipherSpec");
if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
"for record layer");
@@ -1067,9 +986,48 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
u8 verify_data[TLS_VERIFY_DATA_LEN];
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+#ifdef CONFIG_TESTING_OPTIONS
+ if ((conn->test_flags &
+ (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after invalid ServerKeyExchange");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_PRIME_15) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after bogus DHE \"prime\" 15");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_PRIME_58B) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after short 58-bit DHE prime in long container");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_PRIME_511B) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-WARNING: Client Finished received after short 511-bit DHE prime (insecure)");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_PRIME_767B) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after 767-bit DHE prime (relatively insecure)");
+ conn->test_failure_reported = 1;
+ }
+
+ if ((conn->test_flags & TLS_DHE_NON_PRIME) &&
+ !conn->test_failure_reported) {
+ tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after non-prime claimed as DHE prime");
+ conn->test_failure_reported = 1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
- "received content type 0x%x", ct);
+ tlsv1_server_log(conn, "Expected Finished; received content type 0x%x",
+ ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -1079,9 +1037,8 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
left = *in_len;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
- "Finished",
- (unsigned long) left);
+ tlsv1_server_log(conn, "Too short record (left=%lu) forFinished",
+ (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -1101,18 +1058,16 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
left -= 4;
if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
- "(len=%lu > left=%lu)",
- (unsigned long) len, (unsigned long) left);
+ tlsv1_server_log(conn, "Too short buffer for Finished (len=%lu > left=%lu)",
+ (unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (len != TLS_VERIFY_DATA_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
- "in Finished: %lu (expected %d)",
- (unsigned long) len, TLS_VERIFY_DATA_LEN);
+ tlsv1_server_log(conn, "Unexpected verify_data length in Finished: %lu (expected %d)",
+ (unsigned long) len, TLS_VERIFY_DATA_LEN);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
@@ -1174,19 +1129,18 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
verify_data, TLS_VERIFY_DATA_LEN);
- if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
- wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+ if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+ tlsv1_server_log(conn, "Mismatch in verify_data");
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+ tlsv1_server_log(conn, "Received Finished");
*in_len = end - in_data;
if (conn->use_session_ticket) {
/* Abbreviated handshake using session ticket; RFC 4507 */
- wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
- "successfully");
+ tlsv1_server_log(conn, "Abbreviated handshake completed successfully");
conn->state = ESTABLISHED;
} else {
/* Full handshake */
@@ -1202,13 +1156,12 @@ int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
{
if (ct == TLS_CONTENT_TYPE_ALERT) {
if (*len < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+ tlsv1_server_log(conn, "Alert underflow");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
- buf[0], buf[1]);
+ tlsv1_server_log(conn, "Received alert %d:%d", buf[0], buf[1]);
*len = 2;
conn->state = FAILED;
return -1;
@@ -1240,9 +1193,8 @@ int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
return -1;
break;
default:
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
- "while processing received message",
- conn->state);
+ tlsv1_server_log(conn, "Unexpected state %d while processing received message",
+ conn->state);
return -1;
}
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index 6d8e55ed49a09..15e6692178ff8 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -1,6 +1,6 @@
/*
* TLSv1 server - write handshake message
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -48,7 +48,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
+ tlsv1_server_log(conn, "Send ServerHello");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -104,8 +104,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
conn->client_random, conn->server_random,
conn->master_secret);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
- "indicated failure");
+ tlsv1_server_log(conn, "SessionTicket callback indicated failure");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_HANDSHAKE_FAILURE);
return -1;
@@ -170,7 +169,7 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+ tlsv1_server_log(conn, "Send Certificate");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -245,10 +244,12 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
{
tls_key_exchange keyx;
const struct tls_cipher_suite *suite;
- u8 *pos, *rhdr, *hs_start, *hs_length;
+ u8 *pos, *rhdr, *hs_start, *hs_length, *server_params;
size_t rlen;
u8 *dh_ys;
size_t dh_ys_len;
+ const u8 *dh_p;
+ size_t dh_p_len;
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
if (suite == NULL)
@@ -261,8 +262,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
return 0;
}
- if (keyx != TLS_KEY_X_DH_anon) {
- /* TODO? */
+ if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) {
wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
"supported with key exchange type %d", keyx);
return -1;
@@ -275,8 +275,10 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
return -1;
}
+ tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
+
os_free(conn->dh_secret);
- conn->dh_secret_len = conn->cred->dh_p_len;
+ conn->dh_secret_len = dh_p_len;
conn->dh_secret = os_malloc(conn->dh_secret_len);
if (conn->dh_secret == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
@@ -295,8 +297,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
return -1;
}
- if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
- 0)
+ if (os_memcmp(conn->dh_secret, dh_p, conn->dh_secret_len) > 0)
conn->dh_secret[0] = 0; /* make sure secret < p */
pos = conn->dh_secret;
@@ -311,7 +312,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
conn->dh_secret, conn->dh_secret_len);
/* Ys = g^secret mod p */
- dh_ys_len = conn->cred->dh_p_len;
+ dh_ys_len = dh_p_len;
dh_ys = os_malloc(dh_ys_len);
if (dh_ys == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
@@ -322,8 +323,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
}
if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
conn->dh_secret, conn->dh_secret_len,
- conn->cred->dh_p, conn->cred->dh_p_len,
- dh_ys, &dh_ys_len)) {
+ dh_p, dh_p_len, dh_ys, &dh_ys_len)) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(dh_ys);
@@ -354,7 +354,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
+ tlsv1_server_log(conn, "Send ServerKeyExchange");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -369,8 +369,9 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
pos += 3;
/* body - ServerDHParams */
+ server_params = pos;
/* dh_p */
- if (pos + 2 + conn->cred->dh_p_len > end) {
+ if (pos + 2 + dh_p_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
"dh_p");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -378,10 +379,10 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
os_free(dh_ys);
return -1;
}
- WPA_PUT_BE16(pos, conn->cred->dh_p_len);
+ WPA_PUT_BE16(pos, dh_p_len);
pos += 2;
- os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
- pos += conn->cred->dh_p_len;
+ os_memcpy(pos, dh_p, dh_p_len);
+ pos += dh_p_len;
/* dh_g */
if (pos + 2 + conn->cred->dh_g_len > end) {
@@ -412,6 +413,138 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
pos += dh_ys_len;
os_free(dh_ys);
+ /*
+ * select (SignatureAlgorithm)
+ * { case anonymous: struct { };
+ * case rsa:
+ * digitally-signed struct {
+ * opaque md5_hash[16];
+ * opaque sha_hash[20];
+ * };
+ * case dsa:
+ * digitally-signed struct {
+ * opaque sha_hash[20];
+ * };
+ * } Signature;
+ *
+ * md5_hash
+ * MD5(ClientHello.random + ServerHello.random + ServerParams);
+ *
+ * sha_hash
+ * SHA(ClientHello.random + ServerHello.random + ServerParams);
+ */
+
+ if (keyx == TLS_KEY_X_DHE_RSA) {
+ u8 hash[100];
+ u8 *signed_start;
+ size_t clen;
+ int hlen;
+
+ if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+#ifdef CONFIG_TLSV12
+ hlen = tlsv12_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ pos - server_params, hash + 19);
+
+ /*
+ * RFC 5246, 4.7:
+ * TLS v1.2 adds explicit indication of the used
+ * signature and hash algorithms.
+ *
+ * struct {
+ * HashAlgorithm hash;
+ * SignatureAlgorithm signature;
+ * } SignatureAndHashAlgorithm;
+ */
+ if (hlen < 0 || pos + 2 > end) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ *pos++ = TLS_HASH_ALG_SHA256;
+ *pos++ = TLS_SIGN_ALG_RSA;
+
+ /*
+ * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithm,
+ * digest OCTET STRING
+ * }
+ *
+ * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+ *
+ * DER encoded DigestInfo for SHA256 per RFC 3447:
+ * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
+ * 04 20 || H
+ */
+ hlen += 19;
+ os_memcpy(hash,
+ "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+ "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+
+#else /* CONFIG_TLSV12 */
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+#endif /* CONFIG_TLSV12 */
+ } else {
+ hlen = tls_key_x_server_params_hash(
+ conn->rl.tls_version, conn->client_random,
+ conn->server_random, server_params,
+ pos - server_params, hash);
+ }
+
+ if (hlen < 0) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "TLS: ServerKeyExchange signed_params hash",
+ hash, hlen);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_BREAK_SRV_KEY_X_HASH) {
+ tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params hash");
+ hash[hlen - 1] ^= 0x80;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /*
+ * RFC 2246, 4.7:
+ * In digital signing, one-way hash functions are used as input
+ * for a signing algorithm. A digitally-signed element is
+ * encoded as an opaque vector <0..2^16-1>, where the length is
+ * specified by the signing algorithm and key.
+ *
+ * In RSA signing, a 36-byte structure of two hashes (one SHA
+ * and one MD5) is signed (encrypted with the private key). It
+ * is encoded with PKCS #1 block type 0 or type 1 as described
+ * in [PKCS1].
+ */
+ signed_start = pos; /* length to be filled */
+ pos += 2;
+ clen = end - pos;
+ if (conn->cred == NULL ||
+ crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
+ pos, &clen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE16(signed_start, clen);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_BREAK_SRV_KEY_X_SIGNATURE) {
+ tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params signature");
+ pos[clen - 1] ^= 0x80;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ pos += clen;
+ }
+
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
@@ -445,7 +578,7 @@ static int tls_write_server_certificate_request(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
+ tlsv1_server_log(conn, "Send CertificateRequest");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
@@ -505,7 +638,7 @@ static int tls_write_server_hello_done(struct tlsv1_server *conn,
size_t rlen;
u8 payload[4];
- wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
+ tlsv1_server_log(conn, "Send ServerHelloDone");
/* opaque fragment[TLSPlaintext.length] */
@@ -541,7 +674,7 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
size_t rlen;
u8 payload[1];
- wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+ tlsv1_server_log(conn, "Send ChangeCipherSpec");
payload[0] = TLS_CHANGE_CIPHER_SPEC;
@@ -578,7 +711,7 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
pos = *msgpos;
- wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+ tlsv1_server_log(conn, "Send Finished");
/* Encrypted Handshake Message: Finished */
@@ -635,6 +768,12 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conn->test_flags & TLS_BREAK_VERIFY_DATA) {
+ tlsv1_server_log(conn, "TESTING: Break verify_data (server)");
+ verify_data[1 + 3 + 1] ^= 0x80;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
/* Handshake */
pos = hs_start = verify_data;
@@ -736,7 +875,7 @@ static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
*out_len = pos - msg;
- wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
+ tlsv1_server_log(conn, "Handshake completed successfully");
conn->state = ESTABLISHED;
return msg;
@@ -755,8 +894,8 @@ u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
/* Abbreviated handshake was already completed. */
return NULL;
}
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
- "generating reply", conn->state);
+ tlsv1_server_log(conn, "Unexpected state %d while generating reply",
+ conn->state);
return NULL;
}
}
@@ -767,7 +906,7 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
{
u8 *alert, *pos, *length;
- wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+ tlsv1_server_log(conn, "Send Alert(%d:%d)", level, description);
*out_len = 0;
alert = os_malloc(10);
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 87c51784ea719..742af328cf8cc 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -443,17 +443,16 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
return -1;
}
- val = os_malloc(hdr.length + 1);
+ val = dup_binstr(hdr.payload, hdr.length);
if (val == NULL) {
x509_free_name(name);
return -1;
}
- os_memcpy(val, hdr.payload, hdr.length);
- val[hdr.length] = '\0';
if (os_strlen(val) != hdr.length) {
wpa_printf(MSG_INFO, "X509: Reject certificate with "
"embedded NUL byte in a string (%s[NUL])",
val);
+ os_free(val);
x509_free_name(name);
return -1;
}
@@ -513,7 +512,7 @@ void x509_name_string(struct x509_name *name, char *buf, size_t len)
ret = os_snprintf(pos, end - pos, "%s=%s, ",
x509_name_attr_str(name->attr[i].type),
name->attr[i].value);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
goto done;
pos += ret;
}
@@ -528,7 +527,7 @@ void x509_name_string(struct x509_name *name, char *buf, size_t len)
if (name->email) {
ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
name->email);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
goto done;
pos += ret;
}
@@ -1349,7 +1348,8 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
/* TODO: parse UniqueIdentifier ::= BIT STRING */
- if (hdr.payload + hdr.length == end)
+ pos = hdr.payload + hdr.length;
+ if (pos == end)
return 0;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
@@ -1367,7 +1367,8 @@ static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
/* TODO: parse UniqueIdentifier ::= BIT STRING */
- if (hdr.payload + hdr.length == end)
+ pos = hdr.payload + hdr.length;
+ if (pos == end)
return 0;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
@@ -1775,13 +1776,22 @@ skip_digest_oid:
}
if (hdr.length != hash_len ||
- os_memcmp(hdr.payload, hash, hdr.length) != 0) {
+ os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
"with calculated tbsCertificate hash");
os_free(data);
return -1;
}
+ if (hdr.payload + hdr.length < data + data_len) {
+ wpa_hexdump(MSG_INFO,
+ "X509: Extra data after certificate signature hash",
+ hdr.payload + hdr.length,
+ data + data_len - hdr.payload - hdr.length);
+ os_free(data);
+ return -1;
+ }
+
os_free(data);
wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "