summaryrefslogtreecommitdiff
path: root/src/tls/tlsv1_server_write.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tls/tlsv1_server_write.c')
-rw-r--r--src/tls/tlsv1_server_write.c193
1 files changed, 166 insertions, 27 deletions
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index 6d8e55ed49a0..15e6692178ff 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);