139beb93cSSam Leffler /* 239beb93cSSam Leffler * TLSv1 server - write handshake message 3*f05cddf9SRui Paulo * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 12e28a4053SRui Paulo #include "crypto/md5.h" 13e28a4053SRui Paulo #include "crypto/sha1.h" 14*f05cddf9SRui Paulo #include "crypto/sha256.h" 15e28a4053SRui Paulo #include "crypto/tls.h" 16*f05cddf9SRui Paulo #include "crypto/random.h" 1739beb93cSSam Leffler #include "x509v3.h" 1839beb93cSSam Leffler #include "tlsv1_common.h" 1939beb93cSSam Leffler #include "tlsv1_record.h" 2039beb93cSSam Leffler #include "tlsv1_server.h" 2139beb93cSSam Leffler #include "tlsv1_server_i.h" 2239beb93cSSam Leffler 2339beb93cSSam Leffler 2439beb93cSSam Leffler static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn) 2539beb93cSSam Leffler { 2639beb93cSSam Leffler size_t len = 0; 2739beb93cSSam Leffler struct x509_certificate *cert; 2839beb93cSSam Leffler 2939beb93cSSam Leffler cert = conn->cred->cert; 3039beb93cSSam Leffler while (cert) { 3139beb93cSSam Leffler len += 3 + cert->cert_len; 3239beb93cSSam Leffler if (x509_certificate_self_signed(cert)) 3339beb93cSSam Leffler break; 3439beb93cSSam Leffler cert = x509_certificate_get_subject(conn->cred->trusted_certs, 3539beb93cSSam Leffler &cert->issuer); 3639beb93cSSam Leffler } 3739beb93cSSam Leffler 3839beb93cSSam Leffler return len; 3939beb93cSSam Leffler } 4039beb93cSSam Leffler 4139beb93cSSam Leffler 4239beb93cSSam Leffler static int tls_write_server_hello(struct tlsv1_server *conn, 4339beb93cSSam Leffler u8 **msgpos, u8 *end) 4439beb93cSSam Leffler { 4539beb93cSSam Leffler u8 *pos, *rhdr, *hs_start, *hs_length; 4639beb93cSSam Leffler struct os_time now; 4739beb93cSSam Leffler size_t rlen; 4839beb93cSSam Leffler 4939beb93cSSam Leffler pos = *msgpos; 5039beb93cSSam Leffler 5139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello"); 5239beb93cSSam Leffler rhdr = pos; 5339beb93cSSam Leffler pos += TLS_RECORD_HEADER_LEN; 5439beb93cSSam Leffler 5539beb93cSSam Leffler os_get_time(&now); 5639beb93cSSam Leffler WPA_PUT_BE32(conn->server_random, now.sec); 57*f05cddf9SRui Paulo if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) { 5839beb93cSSam Leffler wpa_printf(MSG_ERROR, "TLSv1: Could not generate " 5939beb93cSSam Leffler "server_random"); 6039beb93cSSam Leffler return -1; 6139beb93cSSam Leffler } 6239beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", 6339beb93cSSam Leffler conn->server_random, TLS_RANDOM_LEN); 6439beb93cSSam Leffler 6539beb93cSSam Leffler conn->session_id_len = TLS_SESSION_ID_MAX_LEN; 66*f05cddf9SRui Paulo if (random_get_bytes(conn->session_id, conn->session_id_len)) { 6739beb93cSSam Leffler wpa_printf(MSG_ERROR, "TLSv1: Could not generate " 6839beb93cSSam Leffler "session_id"); 6939beb93cSSam Leffler return -1; 7039beb93cSSam Leffler } 7139beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", 7239beb93cSSam Leffler conn->session_id, conn->session_id_len); 7339beb93cSSam Leffler 7439beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */ 7539beb93cSSam Leffler 7639beb93cSSam Leffler /* Handshake */ 7739beb93cSSam Leffler hs_start = pos; 7839beb93cSSam Leffler /* HandshakeType msg_type */ 7939beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO; 8039beb93cSSam Leffler /* uint24 length (to be filled) */ 8139beb93cSSam Leffler hs_length = pos; 8239beb93cSSam Leffler pos += 3; 8339beb93cSSam Leffler /* body - ServerHello */ 8439beb93cSSam Leffler /* ProtocolVersion server_version */ 85*f05cddf9SRui Paulo WPA_PUT_BE16(pos, conn->rl.tls_version); 8639beb93cSSam Leffler pos += 2; 8739beb93cSSam Leffler /* Random random: uint32 gmt_unix_time, opaque random_bytes */ 8839beb93cSSam Leffler os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN); 8939beb93cSSam Leffler pos += TLS_RANDOM_LEN; 9039beb93cSSam Leffler /* SessionID session_id */ 9139beb93cSSam Leffler *pos++ = conn->session_id_len; 9239beb93cSSam Leffler os_memcpy(pos, conn->session_id, conn->session_id_len); 9339beb93cSSam Leffler pos += conn->session_id_len; 9439beb93cSSam Leffler /* CipherSuite cipher_suite */ 9539beb93cSSam Leffler WPA_PUT_BE16(pos, conn->cipher_suite); 9639beb93cSSam Leffler pos += 2; 9739beb93cSSam Leffler /* CompressionMethod compression_method */ 9839beb93cSSam Leffler *pos++ = TLS_COMPRESSION_NULL; 9939beb93cSSam Leffler 10039beb93cSSam Leffler if (conn->session_ticket && conn->session_ticket_cb) { 10139beb93cSSam Leffler int res = conn->session_ticket_cb( 10239beb93cSSam Leffler conn->session_ticket_cb_ctx, 10339beb93cSSam Leffler conn->session_ticket, conn->session_ticket_len, 10439beb93cSSam Leffler conn->client_random, conn->server_random, 10539beb93cSSam Leffler conn->master_secret); 10639beb93cSSam Leffler if (res < 0) { 10739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " 10839beb93cSSam Leffler "indicated failure"); 10939beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 11039beb93cSSam Leffler TLS_ALERT_HANDSHAKE_FAILURE); 11139beb93cSSam Leffler return -1; 11239beb93cSSam Leffler } 11339beb93cSSam Leffler conn->use_session_ticket = res; 11439beb93cSSam Leffler 11539beb93cSSam Leffler if (conn->use_session_ticket) { 11639beb93cSSam Leffler if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) { 11739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to " 11839beb93cSSam Leffler "derive keys"); 11939beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 12039beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 12139beb93cSSam Leffler return -1; 12239beb93cSSam Leffler } 12339beb93cSSam Leffler } 12439beb93cSSam Leffler 12539beb93cSSam Leffler /* 12639beb93cSSam Leffler * RFC 4507 specifies that server would include an empty 12739beb93cSSam Leffler * SessionTicket extension in ServerHello and a 12839beb93cSSam Leffler * NewSessionTicket message after the ServerHello. However, 12939beb93cSSam Leffler * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket 13039beb93cSSam Leffler * extension at the moment, does not use such extensions. 13139beb93cSSam Leffler * 13239beb93cSSam Leffler * TODO: Add support for configuring RFC 4507 behavior and make 13339beb93cSSam Leffler * EAP-FAST disable it. 13439beb93cSSam Leffler */ 13539beb93cSSam Leffler } 13639beb93cSSam Leffler 13739beb93cSSam Leffler WPA_PUT_BE24(hs_length, pos - hs_length - 3); 13839beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 13939beb93cSSam Leffler 14039beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 141*f05cddf9SRui Paulo rhdr, end - rhdr, hs_start, pos - hs_start, 142*f05cddf9SRui Paulo &rlen) < 0) { 14339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); 14439beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 14539beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 14639beb93cSSam Leffler return -1; 14739beb93cSSam Leffler } 14839beb93cSSam Leffler pos = rhdr + rlen; 14939beb93cSSam Leffler 15039beb93cSSam Leffler *msgpos = pos; 15139beb93cSSam Leffler 15239beb93cSSam Leffler return 0; 15339beb93cSSam Leffler } 15439beb93cSSam Leffler 15539beb93cSSam Leffler 15639beb93cSSam Leffler static int tls_write_server_certificate(struct tlsv1_server *conn, 15739beb93cSSam Leffler u8 **msgpos, u8 *end) 15839beb93cSSam Leffler { 15939beb93cSSam Leffler u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; 16039beb93cSSam Leffler size_t rlen; 16139beb93cSSam Leffler struct x509_certificate *cert; 16239beb93cSSam Leffler const struct tls_cipher_suite *suite; 16339beb93cSSam Leffler 16439beb93cSSam Leffler suite = tls_get_cipher_suite(conn->rl.cipher_suite); 16539beb93cSSam Leffler if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { 16639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when " 16739beb93cSSam Leffler "using anonymous DH"); 16839beb93cSSam Leffler return 0; 16939beb93cSSam Leffler } 17039beb93cSSam Leffler 17139beb93cSSam Leffler pos = *msgpos; 17239beb93cSSam Leffler 17339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); 17439beb93cSSam Leffler rhdr = pos; 17539beb93cSSam Leffler pos += TLS_RECORD_HEADER_LEN; 17639beb93cSSam Leffler 17739beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */ 17839beb93cSSam Leffler 17939beb93cSSam Leffler /* Handshake */ 18039beb93cSSam Leffler hs_start = pos; 18139beb93cSSam Leffler /* HandshakeType msg_type */ 18239beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; 18339beb93cSSam Leffler /* uint24 length (to be filled) */ 18439beb93cSSam Leffler hs_length = pos; 18539beb93cSSam Leffler pos += 3; 18639beb93cSSam Leffler /* body - Certificate */ 18739beb93cSSam Leffler /* uint24 length (to be filled) */ 18839beb93cSSam Leffler cert_start = pos; 18939beb93cSSam Leffler pos += 3; 19039beb93cSSam Leffler cert = conn->cred->cert; 19139beb93cSSam Leffler while (cert) { 19239beb93cSSam Leffler if (pos + 3 + cert->cert_len > end) { 19339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " 19439beb93cSSam Leffler "for Certificate (cert_len=%lu left=%lu)", 19539beb93cSSam Leffler (unsigned long) cert->cert_len, 19639beb93cSSam Leffler (unsigned long) (end - pos)); 19739beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 19839beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 19939beb93cSSam Leffler return -1; 20039beb93cSSam Leffler } 20139beb93cSSam Leffler WPA_PUT_BE24(pos, cert->cert_len); 20239beb93cSSam Leffler pos += 3; 20339beb93cSSam Leffler os_memcpy(pos, cert->cert_start, cert->cert_len); 20439beb93cSSam Leffler pos += cert->cert_len; 20539beb93cSSam Leffler 20639beb93cSSam Leffler if (x509_certificate_self_signed(cert)) 20739beb93cSSam Leffler break; 20839beb93cSSam Leffler cert = x509_certificate_get_subject(conn->cred->trusted_certs, 20939beb93cSSam Leffler &cert->issuer); 21039beb93cSSam Leffler } 21139beb93cSSam Leffler if (cert == conn->cred->cert || cert == NULL) { 21239beb93cSSam Leffler /* 21339beb93cSSam Leffler * Server was not configured with all the needed certificates 21439beb93cSSam Leffler * to form a full certificate chain. The client may fail to 21539beb93cSSam Leffler * validate the chain unless it is configured with all the 21639beb93cSSam Leffler * missing CA certificates. 21739beb93cSSam Leffler */ 21839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain " 21939beb93cSSam Leffler "not configured - validation may fail"); 22039beb93cSSam Leffler } 22139beb93cSSam Leffler WPA_PUT_BE24(cert_start, pos - cert_start - 3); 22239beb93cSSam Leffler 22339beb93cSSam Leffler WPA_PUT_BE24(hs_length, pos - hs_length - 3); 22439beb93cSSam Leffler 22539beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 226*f05cddf9SRui Paulo rhdr, end - rhdr, hs_start, pos - hs_start, 227*f05cddf9SRui Paulo &rlen) < 0) { 22839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 22939beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 23039beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 23139beb93cSSam Leffler return -1; 23239beb93cSSam Leffler } 23339beb93cSSam Leffler pos = rhdr + rlen; 23439beb93cSSam Leffler 23539beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 23639beb93cSSam Leffler 23739beb93cSSam Leffler *msgpos = pos; 23839beb93cSSam Leffler 23939beb93cSSam Leffler return 0; 24039beb93cSSam Leffler } 24139beb93cSSam Leffler 24239beb93cSSam Leffler 24339beb93cSSam Leffler static int tls_write_server_key_exchange(struct tlsv1_server *conn, 24439beb93cSSam Leffler u8 **msgpos, u8 *end) 24539beb93cSSam Leffler { 24639beb93cSSam Leffler tls_key_exchange keyx; 24739beb93cSSam Leffler const struct tls_cipher_suite *suite; 24839beb93cSSam Leffler u8 *pos, *rhdr, *hs_start, *hs_length; 24939beb93cSSam Leffler size_t rlen; 25039beb93cSSam Leffler u8 *dh_ys; 25139beb93cSSam Leffler size_t dh_ys_len; 25239beb93cSSam Leffler 25339beb93cSSam Leffler suite = tls_get_cipher_suite(conn->rl.cipher_suite); 25439beb93cSSam Leffler if (suite == NULL) 25539beb93cSSam Leffler keyx = TLS_KEY_X_NULL; 25639beb93cSSam Leffler else 25739beb93cSSam Leffler keyx = suite->key_exchange; 25839beb93cSSam Leffler 25939beb93cSSam Leffler if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { 26039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed"); 26139beb93cSSam Leffler return 0; 26239beb93cSSam Leffler } 26339beb93cSSam Leffler 26439beb93cSSam Leffler if (keyx != TLS_KEY_X_DH_anon) { 26539beb93cSSam Leffler /* TODO? */ 26639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet " 26739beb93cSSam Leffler "supported with key exchange type %d", keyx); 26839beb93cSSam Leffler return -1; 26939beb93cSSam Leffler } 27039beb93cSSam Leffler 27139beb93cSSam Leffler if (conn->cred == NULL || conn->cred->dh_p == NULL || 27239beb93cSSam Leffler conn->cred->dh_g == NULL) { 27339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for " 27439beb93cSSam Leffler "ServerKeyExhcange"); 27539beb93cSSam Leffler return -1; 27639beb93cSSam Leffler } 27739beb93cSSam Leffler 27839beb93cSSam Leffler os_free(conn->dh_secret); 27939beb93cSSam Leffler conn->dh_secret_len = conn->cred->dh_p_len; 28039beb93cSSam Leffler conn->dh_secret = os_malloc(conn->dh_secret_len); 28139beb93cSSam Leffler if (conn->dh_secret == NULL) { 28239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " 28339beb93cSSam Leffler "memory for secret (Diffie-Hellman)"); 28439beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 28539beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 28639beb93cSSam Leffler return -1; 28739beb93cSSam Leffler } 288*f05cddf9SRui Paulo if (random_get_bytes(conn->dh_secret, conn->dh_secret_len)) { 28939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " 29039beb93cSSam Leffler "data for Diffie-Hellman"); 29139beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 29239beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 29339beb93cSSam Leffler os_free(conn->dh_secret); 29439beb93cSSam Leffler conn->dh_secret = NULL; 29539beb93cSSam Leffler return -1; 29639beb93cSSam Leffler } 29739beb93cSSam Leffler 29839beb93cSSam Leffler if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) > 29939beb93cSSam Leffler 0) 30039beb93cSSam Leffler conn->dh_secret[0] = 0; /* make sure secret < p */ 30139beb93cSSam Leffler 30239beb93cSSam Leffler pos = conn->dh_secret; 30339beb93cSSam Leffler while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0) 30439beb93cSSam Leffler pos++; 30539beb93cSSam Leffler if (pos != conn->dh_secret) { 30639beb93cSSam Leffler os_memmove(conn->dh_secret, pos, 30739beb93cSSam Leffler conn->dh_secret_len - (pos - conn->dh_secret)); 30839beb93cSSam Leffler conn->dh_secret_len -= pos - conn->dh_secret; 30939beb93cSSam Leffler } 31039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value", 31139beb93cSSam Leffler conn->dh_secret, conn->dh_secret_len); 31239beb93cSSam Leffler 31339beb93cSSam Leffler /* Ys = g^secret mod p */ 31439beb93cSSam Leffler dh_ys_len = conn->cred->dh_p_len; 31539beb93cSSam Leffler dh_ys = os_malloc(dh_ys_len); 31639beb93cSSam Leffler if (dh_ys == NULL) { 31739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for " 31839beb93cSSam Leffler "Diffie-Hellman"); 31939beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 32039beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 32139beb93cSSam Leffler return -1; 32239beb93cSSam Leffler } 32339beb93cSSam Leffler if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, 32439beb93cSSam Leffler conn->dh_secret, conn->dh_secret_len, 32539beb93cSSam Leffler conn->cred->dh_p, conn->cred->dh_p_len, 32639beb93cSSam Leffler dh_ys, &dh_ys_len)) { 32739beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 32839beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 32939beb93cSSam Leffler os_free(dh_ys); 33039beb93cSSam Leffler return -1; 33139beb93cSSam Leffler } 33239beb93cSSam Leffler 33339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", 33439beb93cSSam Leffler dh_ys, dh_ys_len); 33539beb93cSSam Leffler 33639beb93cSSam Leffler /* 33739beb93cSSam Leffler * struct { 33839beb93cSSam Leffler * select (KeyExchangeAlgorithm) { 33939beb93cSSam Leffler * case diffie_hellman: 34039beb93cSSam Leffler * ServerDHParams params; 34139beb93cSSam Leffler * Signature signed_params; 34239beb93cSSam Leffler * case rsa: 34339beb93cSSam Leffler * ServerRSAParams params; 34439beb93cSSam Leffler * Signature signed_params; 34539beb93cSSam Leffler * }; 34639beb93cSSam Leffler * } ServerKeyExchange; 34739beb93cSSam Leffler * 34839beb93cSSam Leffler * struct { 34939beb93cSSam Leffler * opaque dh_p<1..2^16-1>; 35039beb93cSSam Leffler * opaque dh_g<1..2^16-1>; 35139beb93cSSam Leffler * opaque dh_Ys<1..2^16-1>; 35239beb93cSSam Leffler * } ServerDHParams; 35339beb93cSSam Leffler */ 35439beb93cSSam Leffler 35539beb93cSSam Leffler pos = *msgpos; 35639beb93cSSam Leffler 35739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange"); 35839beb93cSSam Leffler rhdr = pos; 35939beb93cSSam Leffler pos += TLS_RECORD_HEADER_LEN; 36039beb93cSSam Leffler 36139beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */ 36239beb93cSSam Leffler 36339beb93cSSam Leffler /* Handshake */ 36439beb93cSSam Leffler hs_start = pos; 36539beb93cSSam Leffler /* HandshakeType msg_type */ 36639beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE; 36739beb93cSSam Leffler /* uint24 length (to be filled) */ 36839beb93cSSam Leffler hs_length = pos; 36939beb93cSSam Leffler pos += 3; 37039beb93cSSam Leffler 37139beb93cSSam Leffler /* body - ServerDHParams */ 37239beb93cSSam Leffler /* dh_p */ 37339beb93cSSam Leffler if (pos + 2 + conn->cred->dh_p_len > end) { 37439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " 37539beb93cSSam Leffler "dh_p"); 37639beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 37739beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 37839beb93cSSam Leffler os_free(dh_ys); 37939beb93cSSam Leffler return -1; 38039beb93cSSam Leffler } 38139beb93cSSam Leffler WPA_PUT_BE16(pos, conn->cred->dh_p_len); 38239beb93cSSam Leffler pos += 2; 38339beb93cSSam Leffler os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len); 38439beb93cSSam Leffler pos += conn->cred->dh_p_len; 38539beb93cSSam Leffler 38639beb93cSSam Leffler /* dh_g */ 38739beb93cSSam Leffler if (pos + 2 + conn->cred->dh_g_len > end) { 38839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " 38939beb93cSSam Leffler "dh_g"); 39039beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 39139beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 39239beb93cSSam Leffler os_free(dh_ys); 39339beb93cSSam Leffler return -1; 39439beb93cSSam Leffler } 39539beb93cSSam Leffler WPA_PUT_BE16(pos, conn->cred->dh_g_len); 39639beb93cSSam Leffler pos += 2; 39739beb93cSSam Leffler os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len); 39839beb93cSSam Leffler pos += conn->cred->dh_g_len; 39939beb93cSSam Leffler 40039beb93cSSam Leffler /* dh_Ys */ 40139beb93cSSam Leffler if (pos + 2 + dh_ys_len > end) { 40239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " 40339beb93cSSam Leffler "dh_Ys"); 40439beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 40539beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 40639beb93cSSam Leffler os_free(dh_ys); 40739beb93cSSam Leffler return -1; 40839beb93cSSam Leffler } 40939beb93cSSam Leffler WPA_PUT_BE16(pos, dh_ys_len); 41039beb93cSSam Leffler pos += 2; 41139beb93cSSam Leffler os_memcpy(pos, dh_ys, dh_ys_len); 41239beb93cSSam Leffler pos += dh_ys_len; 41339beb93cSSam Leffler os_free(dh_ys); 41439beb93cSSam Leffler 41539beb93cSSam Leffler WPA_PUT_BE24(hs_length, pos - hs_length - 3); 41639beb93cSSam Leffler 41739beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 418*f05cddf9SRui Paulo rhdr, end - rhdr, hs_start, pos - hs_start, 419*f05cddf9SRui Paulo &rlen) < 0) { 42039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 42139beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 42239beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 42339beb93cSSam Leffler return -1; 42439beb93cSSam Leffler } 42539beb93cSSam Leffler pos = rhdr + rlen; 42639beb93cSSam Leffler 42739beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 42839beb93cSSam Leffler 42939beb93cSSam Leffler *msgpos = pos; 43039beb93cSSam Leffler 43139beb93cSSam Leffler return 0; 43239beb93cSSam Leffler } 43339beb93cSSam Leffler 43439beb93cSSam Leffler 43539beb93cSSam Leffler static int tls_write_server_certificate_request(struct tlsv1_server *conn, 43639beb93cSSam Leffler u8 **msgpos, u8 *end) 43739beb93cSSam Leffler { 43839beb93cSSam Leffler u8 *pos, *rhdr, *hs_start, *hs_length; 43939beb93cSSam Leffler size_t rlen; 44039beb93cSSam Leffler 44139beb93cSSam Leffler if (!conn->verify_peer) { 44239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed"); 44339beb93cSSam Leffler return 0; 44439beb93cSSam Leffler } 44539beb93cSSam Leffler 44639beb93cSSam Leffler pos = *msgpos; 44739beb93cSSam Leffler 44839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest"); 44939beb93cSSam Leffler rhdr = pos; 45039beb93cSSam Leffler pos += TLS_RECORD_HEADER_LEN; 45139beb93cSSam Leffler 45239beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */ 45339beb93cSSam Leffler 45439beb93cSSam Leffler /* Handshake */ 45539beb93cSSam Leffler hs_start = pos; 45639beb93cSSam Leffler /* HandshakeType msg_type */ 45739beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST; 45839beb93cSSam Leffler /* uint24 length (to be filled) */ 45939beb93cSSam Leffler hs_length = pos; 46039beb93cSSam Leffler pos += 3; 46139beb93cSSam Leffler /* body - CertificateRequest */ 46239beb93cSSam Leffler 46339beb93cSSam Leffler /* 46439beb93cSSam Leffler * enum { 46539beb93cSSam Leffler * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), 46639beb93cSSam Leffler * (255) 46739beb93cSSam Leffler * } ClientCertificateType; 46839beb93cSSam Leffler * ClientCertificateType certificate_types<1..2^8-1> 46939beb93cSSam Leffler */ 47039beb93cSSam Leffler *pos++ = 1; 47139beb93cSSam Leffler *pos++ = 1; /* rsa_sign */ 47239beb93cSSam Leffler 47339beb93cSSam Leffler /* 47439beb93cSSam Leffler * opaque DistinguishedName<1..2^16-1> 47539beb93cSSam Leffler * DistinguishedName certificate_authorities<3..2^16-1> 47639beb93cSSam Leffler */ 47739beb93cSSam Leffler /* TODO: add support for listing DNs for trusted CAs */ 47839beb93cSSam Leffler WPA_PUT_BE16(pos, 0); 47939beb93cSSam Leffler pos += 2; 48039beb93cSSam Leffler 48139beb93cSSam Leffler WPA_PUT_BE24(hs_length, pos - hs_length - 3); 48239beb93cSSam Leffler 48339beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 484*f05cddf9SRui Paulo rhdr, end - rhdr, hs_start, pos - hs_start, 485*f05cddf9SRui Paulo &rlen) < 0) { 48639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 48739beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 48839beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 48939beb93cSSam Leffler return -1; 49039beb93cSSam Leffler } 49139beb93cSSam Leffler pos = rhdr + rlen; 49239beb93cSSam Leffler 49339beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 49439beb93cSSam Leffler 49539beb93cSSam Leffler *msgpos = pos; 49639beb93cSSam Leffler 49739beb93cSSam Leffler return 0; 49839beb93cSSam Leffler } 49939beb93cSSam Leffler 50039beb93cSSam Leffler 50139beb93cSSam Leffler static int tls_write_server_hello_done(struct tlsv1_server *conn, 50239beb93cSSam Leffler u8 **msgpos, u8 *end) 50339beb93cSSam Leffler { 504*f05cddf9SRui Paulo u8 *pos; 50539beb93cSSam Leffler size_t rlen; 506*f05cddf9SRui Paulo u8 payload[4]; 50739beb93cSSam Leffler 50839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone"); 50939beb93cSSam Leffler 51039beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */ 51139beb93cSSam Leffler 51239beb93cSSam Leffler /* Handshake */ 513*f05cddf9SRui Paulo pos = payload; 51439beb93cSSam Leffler /* HandshakeType msg_type */ 51539beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE; 516*f05cddf9SRui Paulo /* uint24 length */ 517*f05cddf9SRui Paulo WPA_PUT_BE24(pos, 0); 51839beb93cSSam Leffler pos += 3; 51939beb93cSSam Leffler /* body - ServerHelloDone (empty) */ 52039beb93cSSam Leffler 52139beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 522*f05cddf9SRui Paulo *msgpos, end - *msgpos, payload, pos - payload, 523*f05cddf9SRui Paulo &rlen) < 0) { 52439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); 52539beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 52639beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 52739beb93cSSam Leffler return -1; 52839beb93cSSam Leffler } 52939beb93cSSam Leffler 530*f05cddf9SRui Paulo tls_verify_hash_add(&conn->verify, payload, pos - payload); 53139beb93cSSam Leffler 532*f05cddf9SRui Paulo *msgpos += rlen; 53339beb93cSSam Leffler 53439beb93cSSam Leffler return 0; 53539beb93cSSam Leffler } 53639beb93cSSam Leffler 53739beb93cSSam Leffler 53839beb93cSSam Leffler static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn, 53939beb93cSSam Leffler u8 **msgpos, u8 *end) 54039beb93cSSam Leffler { 54139beb93cSSam Leffler size_t rlen; 542*f05cddf9SRui Paulo u8 payload[1]; 54339beb93cSSam Leffler 54439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); 545*f05cddf9SRui Paulo 546*f05cddf9SRui Paulo payload[0] = TLS_CHANGE_CIPHER_SPEC; 547*f05cddf9SRui Paulo 54839beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, 549*f05cddf9SRui Paulo *msgpos, end - *msgpos, payload, sizeof(payload), 550*f05cddf9SRui Paulo &rlen) < 0) { 55139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); 55239beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 55339beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 55439beb93cSSam Leffler return -1; 55539beb93cSSam Leffler } 55639beb93cSSam Leffler 55739beb93cSSam Leffler if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { 55839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " 55939beb93cSSam Leffler "record layer"); 56039beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 56139beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 56239beb93cSSam Leffler return -1; 56339beb93cSSam Leffler } 56439beb93cSSam Leffler 565*f05cddf9SRui Paulo *msgpos += rlen; 56639beb93cSSam Leffler 56739beb93cSSam Leffler return 0; 56839beb93cSSam Leffler } 56939beb93cSSam Leffler 57039beb93cSSam Leffler 57139beb93cSSam Leffler static int tls_write_server_finished(struct tlsv1_server *conn, 57239beb93cSSam Leffler u8 **msgpos, u8 *end) 57339beb93cSSam Leffler { 574*f05cddf9SRui Paulo u8 *pos, *hs_start; 57539beb93cSSam Leffler size_t rlen, hlen; 576*f05cddf9SRui Paulo u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN]; 57739beb93cSSam Leffler u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; 57839beb93cSSam Leffler 57939beb93cSSam Leffler pos = *msgpos; 58039beb93cSSam Leffler 58139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); 58239beb93cSSam Leffler 58339beb93cSSam Leffler /* Encrypted Handshake Message: Finished */ 58439beb93cSSam Leffler 585*f05cddf9SRui Paulo #ifdef CONFIG_TLSV12 586*f05cddf9SRui Paulo if (conn->rl.tls_version >= TLS_VERSION_1_2) { 587*f05cddf9SRui Paulo hlen = SHA256_MAC_LEN; 588*f05cddf9SRui Paulo if (conn->verify.sha256_server == NULL || 589*f05cddf9SRui Paulo crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) 590*f05cddf9SRui Paulo < 0) { 591*f05cddf9SRui Paulo conn->verify.sha256_server = NULL; 592*f05cddf9SRui Paulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 593*f05cddf9SRui Paulo TLS_ALERT_INTERNAL_ERROR); 594*f05cddf9SRui Paulo return -1; 595*f05cddf9SRui Paulo } 596*f05cddf9SRui Paulo conn->verify.sha256_server = NULL; 597*f05cddf9SRui Paulo } else { 598*f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */ 599*f05cddf9SRui Paulo 60039beb93cSSam Leffler hlen = MD5_MAC_LEN; 60139beb93cSSam Leffler if (conn->verify.md5_server == NULL || 60239beb93cSSam Leffler crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { 60339beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 60439beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 60539beb93cSSam Leffler conn->verify.md5_server = NULL; 60639beb93cSSam Leffler crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); 60739beb93cSSam Leffler conn->verify.sha1_server = NULL; 60839beb93cSSam Leffler return -1; 60939beb93cSSam Leffler } 61039beb93cSSam Leffler conn->verify.md5_server = NULL; 61139beb93cSSam Leffler hlen = SHA1_MAC_LEN; 61239beb93cSSam Leffler if (conn->verify.sha1_server == NULL || 61339beb93cSSam Leffler crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, 61439beb93cSSam Leffler &hlen) < 0) { 61539beb93cSSam Leffler conn->verify.sha1_server = NULL; 61639beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 61739beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 61839beb93cSSam Leffler return -1; 61939beb93cSSam Leffler } 62039beb93cSSam Leffler conn->verify.sha1_server = NULL; 621*f05cddf9SRui Paulo hlen = MD5_MAC_LEN + SHA1_MAC_LEN; 62239beb93cSSam Leffler 623*f05cddf9SRui Paulo #ifdef CONFIG_TLSV12 624*f05cddf9SRui Paulo } 625*f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */ 626*f05cddf9SRui Paulo 627*f05cddf9SRui Paulo if (tls_prf(conn->rl.tls_version, 628*f05cddf9SRui Paulo conn->master_secret, TLS_MASTER_SECRET_LEN, 629*f05cddf9SRui Paulo "server finished", hash, hlen, 630*f05cddf9SRui Paulo verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) { 63139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); 63239beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 63339beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 63439beb93cSSam Leffler return -1; 63539beb93cSSam Leffler } 63639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", 637*f05cddf9SRui Paulo verify_data + 1 + 3, TLS_VERIFY_DATA_LEN); 63839beb93cSSam Leffler 63939beb93cSSam Leffler /* Handshake */ 640*f05cddf9SRui Paulo pos = hs_start = verify_data; 64139beb93cSSam Leffler /* HandshakeType msg_type */ 64239beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; 643*f05cddf9SRui Paulo /* uint24 length */ 644*f05cddf9SRui Paulo WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN); 64539beb93cSSam Leffler pos += 3; 64639beb93cSSam Leffler pos += TLS_VERIFY_DATA_LEN; 64739beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); 64839beb93cSSam Leffler 64939beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, 650*f05cddf9SRui Paulo *msgpos, end - *msgpos, hs_start, pos - hs_start, 651*f05cddf9SRui Paulo &rlen) < 0) { 65239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); 65339beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, 65439beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR); 65539beb93cSSam Leffler return -1; 65639beb93cSSam Leffler } 65739beb93cSSam Leffler 658*f05cddf9SRui Paulo *msgpos += rlen; 65939beb93cSSam Leffler 66039beb93cSSam Leffler return 0; 66139beb93cSSam Leffler } 66239beb93cSSam Leffler 66339beb93cSSam Leffler 66439beb93cSSam Leffler static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len) 66539beb93cSSam Leffler { 66639beb93cSSam Leffler u8 *msg, *end, *pos; 66739beb93cSSam Leffler size_t msglen; 66839beb93cSSam Leffler 66939beb93cSSam Leffler *out_len = 0; 67039beb93cSSam Leffler 67139beb93cSSam Leffler msglen = 1000 + tls_server_cert_chain_der_len(conn); 67239beb93cSSam Leffler 67339beb93cSSam Leffler msg = os_malloc(msglen); 67439beb93cSSam Leffler if (msg == NULL) 67539beb93cSSam Leffler return NULL; 67639beb93cSSam Leffler 67739beb93cSSam Leffler pos = msg; 67839beb93cSSam Leffler end = msg + msglen; 67939beb93cSSam Leffler 68039beb93cSSam Leffler if (tls_write_server_hello(conn, &pos, end) < 0) { 68139beb93cSSam Leffler os_free(msg); 68239beb93cSSam Leffler return NULL; 68339beb93cSSam Leffler } 68439beb93cSSam Leffler 68539beb93cSSam Leffler if (conn->use_session_ticket) { 68639beb93cSSam Leffler /* Abbreviated handshake using session ticket; RFC 4507 */ 68739beb93cSSam Leffler if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || 68839beb93cSSam Leffler tls_write_server_finished(conn, &pos, end) < 0) { 68939beb93cSSam Leffler os_free(msg); 69039beb93cSSam Leffler return NULL; 69139beb93cSSam Leffler } 69239beb93cSSam Leffler 69339beb93cSSam Leffler *out_len = pos - msg; 69439beb93cSSam Leffler 69539beb93cSSam Leffler conn->state = CHANGE_CIPHER_SPEC; 69639beb93cSSam Leffler 69739beb93cSSam Leffler return msg; 69839beb93cSSam Leffler } 69939beb93cSSam Leffler 70039beb93cSSam Leffler /* Full handshake */ 70139beb93cSSam Leffler if (tls_write_server_certificate(conn, &pos, end) < 0 || 70239beb93cSSam Leffler tls_write_server_key_exchange(conn, &pos, end) < 0 || 70339beb93cSSam Leffler tls_write_server_certificate_request(conn, &pos, end) < 0 || 70439beb93cSSam Leffler tls_write_server_hello_done(conn, &pos, end) < 0) { 70539beb93cSSam Leffler os_free(msg); 70639beb93cSSam Leffler return NULL; 70739beb93cSSam Leffler } 70839beb93cSSam Leffler 70939beb93cSSam Leffler *out_len = pos - msg; 71039beb93cSSam Leffler 71139beb93cSSam Leffler conn->state = CLIENT_CERTIFICATE; 71239beb93cSSam Leffler 71339beb93cSSam Leffler return msg; 71439beb93cSSam Leffler } 71539beb93cSSam Leffler 71639beb93cSSam Leffler 71739beb93cSSam Leffler static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn, 71839beb93cSSam Leffler size_t *out_len) 71939beb93cSSam Leffler { 72039beb93cSSam Leffler u8 *msg, *end, *pos; 72139beb93cSSam Leffler 72239beb93cSSam Leffler *out_len = 0; 72339beb93cSSam Leffler 72439beb93cSSam Leffler msg = os_malloc(1000); 72539beb93cSSam Leffler if (msg == NULL) 72639beb93cSSam Leffler return NULL; 72739beb93cSSam Leffler 72839beb93cSSam Leffler pos = msg; 72939beb93cSSam Leffler end = msg + 1000; 73039beb93cSSam Leffler 73139beb93cSSam Leffler if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || 73239beb93cSSam Leffler tls_write_server_finished(conn, &pos, end) < 0) { 73339beb93cSSam Leffler os_free(msg); 73439beb93cSSam Leffler return NULL; 73539beb93cSSam Leffler } 73639beb93cSSam Leffler 73739beb93cSSam Leffler *out_len = pos - msg; 73839beb93cSSam Leffler 73939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully"); 74039beb93cSSam Leffler conn->state = ESTABLISHED; 74139beb93cSSam Leffler 74239beb93cSSam Leffler return msg; 74339beb93cSSam Leffler } 74439beb93cSSam Leffler 74539beb93cSSam Leffler 74639beb93cSSam Leffler u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len) 74739beb93cSSam Leffler { 74839beb93cSSam Leffler switch (conn->state) { 74939beb93cSSam Leffler case SERVER_HELLO: 75039beb93cSSam Leffler return tls_send_server_hello(conn, out_len); 75139beb93cSSam Leffler case SERVER_CHANGE_CIPHER_SPEC: 75239beb93cSSam Leffler return tls_send_change_cipher_spec(conn, out_len); 75339beb93cSSam Leffler default: 75439beb93cSSam Leffler if (conn->state == ESTABLISHED && conn->use_session_ticket) { 75539beb93cSSam Leffler /* Abbreviated handshake was already completed. */ 75639beb93cSSam Leffler return NULL; 75739beb93cSSam Leffler } 75839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " 75939beb93cSSam Leffler "generating reply", conn->state); 76039beb93cSSam Leffler return NULL; 76139beb93cSSam Leffler } 76239beb93cSSam Leffler } 76339beb93cSSam Leffler 76439beb93cSSam Leffler 76539beb93cSSam Leffler u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, 76639beb93cSSam Leffler u8 description, size_t *out_len) 76739beb93cSSam Leffler { 76839beb93cSSam Leffler u8 *alert, *pos, *length; 76939beb93cSSam Leffler 77039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); 77139beb93cSSam Leffler *out_len = 0; 77239beb93cSSam Leffler 77339beb93cSSam Leffler alert = os_malloc(10); 77439beb93cSSam Leffler if (alert == NULL) 77539beb93cSSam Leffler return NULL; 77639beb93cSSam Leffler 77739beb93cSSam Leffler pos = alert; 77839beb93cSSam Leffler 77939beb93cSSam Leffler /* TLSPlaintext */ 78039beb93cSSam Leffler /* ContentType type */ 78139beb93cSSam Leffler *pos++ = TLS_CONTENT_TYPE_ALERT; 78239beb93cSSam Leffler /* ProtocolVersion version */ 783*f05cddf9SRui Paulo WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version : 784*f05cddf9SRui Paulo TLS_VERSION); 78539beb93cSSam Leffler pos += 2; 78639beb93cSSam Leffler /* uint16 length (to be filled) */ 78739beb93cSSam Leffler length = pos; 78839beb93cSSam Leffler pos += 2; 78939beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */ 79039beb93cSSam Leffler 79139beb93cSSam Leffler /* Alert */ 79239beb93cSSam Leffler /* AlertLevel level */ 79339beb93cSSam Leffler *pos++ = level; 79439beb93cSSam Leffler /* AlertDescription description */ 79539beb93cSSam Leffler *pos++ = description; 79639beb93cSSam Leffler 79739beb93cSSam Leffler WPA_PUT_BE16(length, pos - length - 2); 79839beb93cSSam Leffler *out_len = pos - alert; 79939beb93cSSam Leffler 80039beb93cSSam Leffler return alert; 80139beb93cSSam Leffler } 802