1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057 |
- /*
- * TLSv1 client - read handshake message
- * 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.
- */
- #include "includes.h"
- #include "common.h"
- #include "crypto/md5.h"
- #include "crypto/sha1.h"
- #include "crypto/sha256.h"
- #include "crypto/tls.h"
- #include "x509v3.h"
- #include "tlsv1_common.h"
- #include "tlsv1_record.h"
- #include "tlsv1_client.h"
- #include "tlsv1_client_i.h"
- static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len);
- static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len);
- static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len);
- static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
- {
- const u8 *pos, *end;
- size_t left, len, i;
- u16 cipher_suite;
- u16 tls_version;
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- pos = in_data;
- left = *in_len;
- if (left < 4)
- goto decode_error;
- /* HandshakeType msg_type */
- if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ServerHello)", *pos);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
- pos++;
- /* uint24 length */
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
- if (len > left)
- goto decode_error;
- /* body - ServerHello */
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
- end = pos + len;
- /* ProtocolVersion server_version */
- if (end - pos < 2)
- goto decode_error;
- tls_version = WPA_GET_BE16(pos);
- if (!tls_version_ok(tls_version)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
- "ServerHello %u.%u", pos[0], pos[1]);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_PROTOCOL_VERSION);
- return -1;
- }
- pos += 2;
- wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
- tls_version_str(tls_version));
- conn->rl.tls_version = tls_version;
- /* Random random */
- if (end - pos < TLS_RANDOM_LEN)
- goto decode_error;
- os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
- pos += TLS_RANDOM_LEN;
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
- conn->server_random, TLS_RANDOM_LEN);
- /* SessionID session_id */
- if (end - pos < 1)
- goto decode_error;
- if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
- goto decode_error;
- if (conn->session_id_len && conn->session_id_len == *pos &&
- os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
- pos += 1 + conn->session_id_len;
- wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
- conn->session_resumed = 1;
- } else {
- conn->session_id_len = *pos;
- pos++;
- os_memcpy(conn->session_id, pos, conn->session_id_len);
- pos += conn->session_id_len;
- }
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
- conn->session_id, conn->session_id_len);
- /* CipherSuite cipher_suite */
- if (end - pos < 2)
- goto decode_error;
- cipher_suite = WPA_GET_BE16(pos);
- pos += 2;
- for (i = 0; i < conn->num_cipher_suites; i++) {
- if (cipher_suite == conn->cipher_suites[i])
- break;
- }
- if (i == conn->num_cipher_suites) {
- wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
- "cipher suite 0x%04x", cipher_suite);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_ILLEGAL_PARAMETER);
- return -1;
- }
- if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
- wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
- "cipher suite for a resumed connection (0x%04x != "
- "0x%04x)", cipher_suite, conn->prev_cipher_suite);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_ILLEGAL_PARAMETER);
- return -1;
- }
- if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
- "record layer");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- conn->prev_cipher_suite = cipher_suite;
- /* CompressionMethod compression_method */
- if (end - pos < 1)
- goto decode_error;
- if (*pos != TLS_COMPRESSION_NULL) {
- wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
- "compression 0x%02x", *pos);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_ILLEGAL_PARAMETER);
- return -1;
- }
- pos++;
- if (end != pos) {
- /* TODO: ServerHello extensions */
- wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
- "end of ServerHello", pos, end - pos);
- goto decode_error;
- }
- if (conn->session_ticket_included && conn->session_ticket_cb) {
- /* TODO: include SessionTicket extension if one was included in
- * ServerHello */
- int res = conn->session_ticket_cb(
- conn->session_ticket_cb_ctx, NULL, 0,
- conn->client_random, conn->server_random,
- conn->master_secret);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
- "indicated failure");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_HANDSHAKE_FAILURE);
- return -1;
- }
- conn->use_session_ticket = !!res;
- }
- if ((conn->session_resumed || conn->use_session_ticket) &&
- tls_derive_keys(conn, NULL, 0)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- *in_len = end - in_data;
- conn->state = (conn->session_resumed || conn->use_session_ticket) ?
- SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;
- return 0;
- decode_error:
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
- {
- const u8 *pos, *end;
- size_t left, len, list_len, cert_len, idx;
- u8 type;
- struct x509_certificate *chain = NULL, *last = NULL, *cert;
- int reason;
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- pos = in_data;
- left = *in_len;
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
- "(len=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- type = *pos++;
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
- if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE)
- return tls_process_server_key_exchange(conn, ct, in_data,
- in_len);
- if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
- return tls_process_certificate_request(conn, ct, in_data,
- in_len);
- if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
- return tls_process_server_hello_done(conn, ct, in_data,
- in_len);
- if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected Certificate/"
- "ServerKeyExchange/CertificateRequest/"
- "ServerHelloDone)", type);
- tls_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);
- /*
- * opaque ASN.1Cert<2^24-1>;
- *
- * struct {
- * ASN.1Cert certificate_list<1..2^24-1>;
- * } Certificate;
- */
- end = pos + len;
- if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
- "(left=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- list_len = WPA_GET_BE24(pos);
- 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));
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- idx = 0;
- while (pos < end) {
- if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "certificate_list");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- x509_certificate_chain_free(chain);
- return -1;
- }
- cert_len = WPA_GET_BE24(pos);
- 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));
- tls_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);
- if (idx == 0) {
- crypto_public_key_free(conn->server_rsa_key);
- if (tls_parse_cert(pos, cert_len,
- &conn->server_rsa_key)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_BAD_CERTIFICATE);
- x509_certificate_chain_free(chain);
- return -1;
- }
- }
- cert = x509_certificate_parse(pos, cert_len);
- if (cert == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_BAD_CERTIFICATE);
- x509_certificate_chain_free(chain);
- return -1;
- }
- if (last == NULL)
- chain = cert;
- else
- last->next = cert;
- last = cert;
- idx++;
- pos += cert_len;
- }
- if (conn->cred &&
- x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
- &reason, conn->disable_time_checks)
- < 0) {
- int tls_reason;
- wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
- "validation failed (reason=%d)", reason);
- switch (reason) {
- case X509_VALIDATE_BAD_CERTIFICATE:
- tls_reason = TLS_ALERT_BAD_CERTIFICATE;
- break;
- case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
- tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
- break;
- case X509_VALIDATE_CERTIFICATE_REVOKED:
- tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
- break;
- case X509_VALIDATE_CERTIFICATE_EXPIRED:
- tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
- break;
- case X509_VALIDATE_CERTIFICATE_UNKNOWN:
- tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
- break;
- case X509_VALIDATE_UNKNOWN_CA:
- tls_reason = TLS_ALERT_UNKNOWN_CA;
- break;
- default:
- tls_reason = TLS_ALERT_BAD_CERTIFICATE;
- break;
- }
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
- x509_certificate_chain_free(chain);
- return -1;
- }
- x509_certificate_chain_free(chain);
- *in_len = end - in_data;
- conn->state = SERVER_KEY_EXCHANGE;
- return 0;
- }
- static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
- const u8 *buf, size_t len,
- tls_key_exchange key_exchange)
- {
- const u8 *pos, *end, *server_params, *server_params_end;
- u8 alert;
- tlsv1_client_free_dh(conn);
- pos = buf;
- end = buf + len;
- if (end - pos < 3)
- goto fail;
- server_params = pos;
- conn->dh_p_len = 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);
- goto fail;
- }
- conn->dh_p = os_malloc(conn->dh_p_len);
- if (conn->dh_p == NULL)
- goto fail;
- os_memcpy(conn->dh_p, pos, conn->dh_p_len);
- pos += conn->dh_p_len;
- wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
- conn->dh_p, conn->dh_p_len);
- if (end - pos < 3)
- goto fail;
- conn->dh_g_len = WPA_GET_BE16(pos);
- pos += 2;
- if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
- goto fail;
- conn->dh_g = os_malloc(conn->dh_g_len);
- if (conn->dh_g == NULL)
- goto fail;
- os_memcpy(conn->dh_g, pos, conn->dh_g_len);
- pos += conn->dh_g_len;
- wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
- conn->dh_g, conn->dh_g_len);
- if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
- goto fail;
- if (end - pos < 3)
- goto fail;
- conn->dh_ys_len = WPA_GET_BE16(pos);
- pos += 2;
- if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
- goto fail;
- conn->dh_ys = os_malloc(conn->dh_ys_len);
- if (conn->dh_ys == NULL)
- goto fail;
- os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
- 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;
- fail:
- wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed");
- tlsv1_client_free_dh(conn);
- return -1;
- }
- static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
- {
- const u8 *pos, *end;
- size_t left, len;
- u8 type;
- 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);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- pos = in_data;
- left = *in_len;
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange "
- "(Left=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- type = *pos++;
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
- if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- end = pos + len;
- if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
- return tls_process_certificate_request(conn, ct, in_data,
- in_len);
- if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
- return tls_process_server_hello_done(conn, ct, in_data,
- in_len);
- if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ServerKeyExchange/"
- "CertificateRequest/ServerHelloDone)", type);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange");
- if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
- wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed "
- "with the selected cipher suite");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- 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 ||
- 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;
- }
- } else {
- wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- *in_len = end - in_data;
- conn->state = SERVER_CERTIFICATE_REQUEST;
- return 0;
- }
- static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
- {
- const u8 *pos, *end;
- size_t left, len;
- u8 type;
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- pos = in_data;
- left = *in_len;
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest "
- "(left=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- type = *pos++;
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
- if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- end = pos + len;
- if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
- return tls_process_server_hello_done(conn, ct, in_data,
- in_len);
- if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected CertificateRequest/"
- "ServerHelloDone)", type);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest");
- conn->certificate_requested = 1;
- *in_len = end - in_data;
- conn->state = SERVER_HELLO_DONE;
- return 0;
- }
- static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
- {
- const u8 *pos, *end;
- size_t left, len;
- u8 type;
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- pos = in_data;
- left = *in_len;
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone "
- "(left=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- type = *pos++;
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
- if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- end = pos + len;
- if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ServerHelloDone)", type);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
- *in_len = end - in_data;
- conn->state = CLIENT_KEY_EXCHANGE;
- return 0;
- }
- static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
- u8 ct, const u8 *in_data,
- size_t *in_len)
- {
- const u8 *pos;
- size_t left;
- if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
- "received content type 0x%x", ct);
- if (conn->use_session_ticket) {
- int res;
- wpa_printf(MSG_DEBUG, "TLSv1: Server may have "
- "rejected SessionTicket");
- conn->use_session_ticket = 0;
- /* Notify upper layers that SessionTicket failed */
- res = conn->session_ticket_cb(
- conn->session_ticket_cb_ctx, NULL, 0, NULL,
- NULL, NULL);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket "
- "callback indicated failure");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_HANDSHAKE_FAILURE);
- return -1;
- }
- conn->state = SERVER_CERTIFICATE;
- return tls_process_certificate(conn, ct, in_data,
- in_len);
- }
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- pos = in_data;
- left = *in_len;
- if (left < 1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
- tls_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);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
- if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
- "for record layer");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- *in_len = pos + 1 - in_data;
- conn->state = SERVER_FINISHED;
- return 0;
- }
- static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
- {
- const u8 *pos, *end;
- size_t left, len, hlen;
- u8 verify_data[TLS_VERIFY_DATA_LEN];
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- pos = in_data;
- left = *in_len;
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
- "Finished",
- (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
- "type 0x%x", pos[0]);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- len = WPA_GET_BE24(pos + 1);
- pos += 4;
- 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);
- tls_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);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
- pos, TLS_VERIFY_DATA_LEN);
- #ifdef CONFIG_TLSV12
- if (conn->rl.tls_version >= TLS_VERSION_1_2) {
- hlen = SHA256_MAC_LEN;
- if (conn->verify.sha256_server == NULL ||
- crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
- < 0) {
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify.sha256_server = NULL;
- return -1;
- }
- conn->verify.sha256_server = NULL;
- } else {
- #endif /* CONFIG_TLSV12 */
- hlen = MD5_MAC_LEN;
- if (conn->verify.md5_server == NULL ||
- crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify.md5_server = NULL;
- crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
- conn->verify.sha1_server = NULL;
- return -1;
- }
- conn->verify.md5_server = NULL;
- hlen = SHA1_MAC_LEN;
- if (conn->verify.sha1_server == NULL ||
- crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
- &hlen) < 0) {
- conn->verify.sha1_server = NULL;
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- conn->verify.sha1_server = NULL;
- hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
- #ifdef CONFIG_TLSV12
- }
- #endif /* CONFIG_TLSV12 */
- if (tls_prf(conn->rl.tls_version,
- conn->master_secret, TLS_MASTER_SECRET_LEN,
- "server finished", hash, hlen,
- verify_data, TLS_VERIFY_DATA_LEN)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
- 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) {
- wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
- *in_len = end - in_data;
- conn->state = (conn->session_resumed || conn->use_session_ticket) ?
- CHANGE_CIPHER_SPEC : ACK_FINISHED;
- return 0;
- }
- static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len,
- u8 **out_data, size_t *out_len)
- {
- const u8 *pos;
- size_t left;
- if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- pos = in_data;
- left = *in_len;
- wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake",
- pos, left);
- *out_data = os_malloc(left);
- if (*out_data) {
- os_memcpy(*out_data, pos, left);
- *out_len = left;
- }
- return 0;
- }
- int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
- const u8 *buf, size_t *len,
- u8 **out_data, size_t *out_len)
- {
- if (ct == TLS_CONTENT_TYPE_ALERT) {
- if (*len < 2) {
- wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
- tls_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]);
- *len = 2;
- conn->state = FAILED;
- return -1;
- }
- if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 &&
- buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) {
- size_t hr_len = WPA_GET_BE24(buf + 1);
- if (hr_len > *len - 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest");
- *len = 4 + hr_len;
- return 0;
- }
- switch (conn->state) {
- case SERVER_HELLO:
- if (tls_process_server_hello(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_CERTIFICATE:
- if (tls_process_certificate(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_KEY_EXCHANGE:
- if (tls_process_server_key_exchange(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_CERTIFICATE_REQUEST:
- if (tls_process_certificate_request(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_HELLO_DONE:
- if (tls_process_server_hello_done(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_CHANGE_CIPHER_SPEC:
- if (tls_process_server_change_cipher_spec(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_FINISHED:
- if (tls_process_server_finished(conn, ct, buf, len))
- return -1;
- break;
- case ACK_FINISHED:
- if (out_data &&
- tls_process_application_data(conn, ct, buf, len, out_data,
- out_len))
- return -1;
- break;
- default:
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
- "while processing received message",
- conn->state);
- return -1;
- }
- if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
- tls_verify_hash_add(&conn->verify, buf, *len);
- return 0;
- }
|