139beb93cSSam Leffler /*
239beb93cSSam Leffler * TLSv1 server - write handshake message
35b9c547cSRui Paulo * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui 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"
14f05cddf9SRui Paulo #include "crypto/sha256.h"
15e28a4053SRui Paulo #include "crypto/tls.h"
16f05cddf9SRui 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
tls_server_cert_chain_der_len(struct tlsv1_server * conn)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
294bc52338SCy Schubert cert = conn->cred ? conn->cred->cert : NULL;
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
tls_write_server_hello(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)4239beb93cSSam Leffler static int tls_write_server_hello(struct tlsv1_server *conn,
4339beb93cSSam Leffler u8 **msgpos, u8 *end)
4439beb93cSSam Leffler {
45780fb4a2SCy Schubert u8 *pos, *rhdr, *hs_start, *hs_length, *ext_start;
4639beb93cSSam Leffler struct os_time now;
4739beb93cSSam Leffler size_t rlen;
4839beb93cSSam Leffler
4939beb93cSSam Leffler pos = *msgpos;
5039beb93cSSam Leffler
515b9c547cSRui Paulo tlsv1_server_log(conn, "Send ServerHello");
5239beb93cSSam Leffler rhdr = pos;
5339beb93cSSam Leffler pos += TLS_RECORD_HEADER_LEN;
5439beb93cSSam Leffler
5539beb93cSSam Leffler os_get_time(&now);
564bc52338SCy Schubert #ifdef TEST_FUZZ
574bc52338SCy Schubert now.sec = 0xfffefdfc;
584bc52338SCy Schubert #endif /* TEST_FUZZ */
5939beb93cSSam Leffler WPA_PUT_BE32(conn->server_random, now.sec);
60f05cddf9SRui Paulo if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
6139beb93cSSam Leffler wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
6239beb93cSSam Leffler "server_random");
6339beb93cSSam Leffler return -1;
6439beb93cSSam Leffler }
6539beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
6639beb93cSSam Leffler conn->server_random, TLS_RANDOM_LEN);
6739beb93cSSam Leffler
6839beb93cSSam Leffler conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
69f05cddf9SRui Paulo if (random_get_bytes(conn->session_id, conn->session_id_len)) {
7039beb93cSSam Leffler wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
7139beb93cSSam Leffler "session_id");
7239beb93cSSam Leffler return -1;
7339beb93cSSam Leffler }
7439beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
7539beb93cSSam Leffler conn->session_id, conn->session_id_len);
7639beb93cSSam Leffler
7739beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */
7839beb93cSSam Leffler
7939beb93cSSam Leffler /* Handshake */
8039beb93cSSam Leffler hs_start = pos;
8139beb93cSSam Leffler /* HandshakeType msg_type */
8239beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
8339beb93cSSam Leffler /* uint24 length (to be filled) */
8439beb93cSSam Leffler hs_length = pos;
8539beb93cSSam Leffler pos += 3;
8639beb93cSSam Leffler /* body - ServerHello */
8739beb93cSSam Leffler /* ProtocolVersion server_version */
88f05cddf9SRui Paulo WPA_PUT_BE16(pos, conn->rl.tls_version);
8939beb93cSSam Leffler pos += 2;
9039beb93cSSam Leffler /* Random random: uint32 gmt_unix_time, opaque random_bytes */
9139beb93cSSam Leffler os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
9239beb93cSSam Leffler pos += TLS_RANDOM_LEN;
9339beb93cSSam Leffler /* SessionID session_id */
9439beb93cSSam Leffler *pos++ = conn->session_id_len;
9539beb93cSSam Leffler os_memcpy(pos, conn->session_id, conn->session_id_len);
9639beb93cSSam Leffler pos += conn->session_id_len;
9739beb93cSSam Leffler /* CipherSuite cipher_suite */
9839beb93cSSam Leffler WPA_PUT_BE16(pos, conn->cipher_suite);
9939beb93cSSam Leffler pos += 2;
10039beb93cSSam Leffler /* CompressionMethod compression_method */
10139beb93cSSam Leffler *pos++ = TLS_COMPRESSION_NULL;
10239beb93cSSam Leffler
103780fb4a2SCy Schubert /* Extension */
104780fb4a2SCy Schubert ext_start = pos;
105780fb4a2SCy Schubert pos += 2;
106780fb4a2SCy Schubert
107780fb4a2SCy Schubert if (conn->status_request) {
108780fb4a2SCy Schubert /* Add a status_request extension with empty extension_data */
109780fb4a2SCy Schubert /* ExtensionsType extension_type = status_request(5) */
110780fb4a2SCy Schubert WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
111780fb4a2SCy Schubert pos += 2;
112780fb4a2SCy Schubert /* opaque extension_data<0..2^16-1> length */
113780fb4a2SCy Schubert WPA_PUT_BE16(pos, 0);
114780fb4a2SCy Schubert pos += 2;
115780fb4a2SCy Schubert }
116780fb4a2SCy Schubert
117780fb4a2SCy Schubert if (conn->status_request_v2) {
118780fb4a2SCy Schubert /*
119780fb4a2SCy Schubert Add a status_request_v2 extension with empty extension_data
120780fb4a2SCy Schubert */
121780fb4a2SCy Schubert /* ExtensionsType extension_type = status_request_v2(17) */
122780fb4a2SCy Schubert WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
123780fb4a2SCy Schubert pos += 2;
124780fb4a2SCy Schubert /* opaque extension_data<0..2^16-1> length */
125780fb4a2SCy Schubert WPA_PUT_BE16(pos, 0);
126780fb4a2SCy Schubert pos += 2;
127780fb4a2SCy Schubert }
128780fb4a2SCy Schubert
12939beb93cSSam Leffler if (conn->session_ticket && conn->session_ticket_cb) {
13039beb93cSSam Leffler int res = conn->session_ticket_cb(
13139beb93cSSam Leffler conn->session_ticket_cb_ctx,
13239beb93cSSam Leffler conn->session_ticket, conn->session_ticket_len,
13339beb93cSSam Leffler conn->client_random, conn->server_random,
13439beb93cSSam Leffler conn->master_secret);
13539beb93cSSam Leffler if (res < 0) {
1365b9c547cSRui Paulo tlsv1_server_log(conn, "SessionTicket callback indicated failure");
13739beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
13839beb93cSSam Leffler TLS_ALERT_HANDSHAKE_FAILURE);
13939beb93cSSam Leffler return -1;
14039beb93cSSam Leffler }
14139beb93cSSam Leffler conn->use_session_ticket = res;
14239beb93cSSam Leffler
14339beb93cSSam Leffler if (conn->use_session_ticket) {
14439beb93cSSam Leffler if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
14539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
14639beb93cSSam Leffler "derive keys");
14739beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
14839beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
14939beb93cSSam Leffler return -1;
15039beb93cSSam Leffler }
15139beb93cSSam Leffler }
15239beb93cSSam Leffler
15339beb93cSSam Leffler /*
15439beb93cSSam Leffler * RFC 4507 specifies that server would include an empty
15539beb93cSSam Leffler * SessionTicket extension in ServerHello and a
15639beb93cSSam Leffler * NewSessionTicket message after the ServerHello. However,
15739beb93cSSam Leffler * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
15839beb93cSSam Leffler * extension at the moment, does not use such extensions.
15939beb93cSSam Leffler *
16039beb93cSSam Leffler * TODO: Add support for configuring RFC 4507 behavior and make
16139beb93cSSam Leffler * EAP-FAST disable it.
16239beb93cSSam Leffler */
16339beb93cSSam Leffler }
16439beb93cSSam Leffler
165780fb4a2SCy Schubert if (pos == ext_start + 2)
166780fb4a2SCy Schubert pos -= 2; /* no extensions */
167780fb4a2SCy Schubert else
168780fb4a2SCy Schubert WPA_PUT_BE16(ext_start, pos - ext_start - 2);
169780fb4a2SCy Schubert
17039beb93cSSam Leffler WPA_PUT_BE24(hs_length, pos - hs_length - 3);
17139beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
17239beb93cSSam Leffler
17339beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
174f05cddf9SRui Paulo rhdr, end - rhdr, hs_start, pos - hs_start,
175f05cddf9SRui Paulo &rlen) < 0) {
17639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
17739beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
17839beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
17939beb93cSSam Leffler return -1;
18039beb93cSSam Leffler }
18139beb93cSSam Leffler pos = rhdr + rlen;
18239beb93cSSam Leffler
18339beb93cSSam Leffler *msgpos = pos;
18439beb93cSSam Leffler
18539beb93cSSam Leffler return 0;
18639beb93cSSam Leffler }
18739beb93cSSam Leffler
18839beb93cSSam Leffler
tls_write_server_certificate(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)18939beb93cSSam Leffler static int tls_write_server_certificate(struct tlsv1_server *conn,
19039beb93cSSam Leffler u8 **msgpos, u8 *end)
19139beb93cSSam Leffler {
19239beb93cSSam Leffler u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
19339beb93cSSam Leffler size_t rlen;
19439beb93cSSam Leffler struct x509_certificate *cert;
19539beb93cSSam Leffler const struct tls_cipher_suite *suite;
19639beb93cSSam Leffler
19739beb93cSSam Leffler suite = tls_get_cipher_suite(conn->rl.cipher_suite);
19839beb93cSSam Leffler if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
19939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
20039beb93cSSam Leffler "using anonymous DH");
20139beb93cSSam Leffler return 0;
20239beb93cSSam Leffler }
20339beb93cSSam Leffler
20439beb93cSSam Leffler pos = *msgpos;
205780fb4a2SCy Schubert if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
206780fb4a2SCy Schubert tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
207780fb4a2SCy Schubert TLS_ALERT_INTERNAL_ERROR);
208780fb4a2SCy Schubert return -1;
209780fb4a2SCy Schubert }
21039beb93cSSam Leffler
2115b9c547cSRui Paulo tlsv1_server_log(conn, "Send Certificate");
21239beb93cSSam Leffler rhdr = pos;
21339beb93cSSam Leffler pos += TLS_RECORD_HEADER_LEN;
21439beb93cSSam Leffler
21539beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */
21639beb93cSSam Leffler
21739beb93cSSam Leffler /* Handshake */
21839beb93cSSam Leffler hs_start = pos;
21939beb93cSSam Leffler /* HandshakeType msg_type */
22039beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
22139beb93cSSam Leffler /* uint24 length (to be filled) */
22239beb93cSSam Leffler hs_length = pos;
22339beb93cSSam Leffler pos += 3;
22439beb93cSSam Leffler /* body - Certificate */
22539beb93cSSam Leffler /* uint24 length (to be filled) */
22639beb93cSSam Leffler cert_start = pos;
22739beb93cSSam Leffler pos += 3;
22839beb93cSSam Leffler cert = conn->cred->cert;
22939beb93cSSam Leffler while (cert) {
230780fb4a2SCy Schubert if (3 + cert->cert_len > (size_t) (end - pos)) {
23139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
23239beb93cSSam Leffler "for Certificate (cert_len=%lu left=%lu)",
23339beb93cSSam Leffler (unsigned long) cert->cert_len,
23439beb93cSSam Leffler (unsigned long) (end - pos));
23539beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
23639beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
23739beb93cSSam Leffler return -1;
23839beb93cSSam Leffler }
23939beb93cSSam Leffler WPA_PUT_BE24(pos, cert->cert_len);
24039beb93cSSam Leffler pos += 3;
24139beb93cSSam Leffler os_memcpy(pos, cert->cert_start, cert->cert_len);
24239beb93cSSam Leffler pos += cert->cert_len;
24339beb93cSSam Leffler
24439beb93cSSam Leffler if (x509_certificate_self_signed(cert))
24539beb93cSSam Leffler break;
24639beb93cSSam Leffler cert = x509_certificate_get_subject(conn->cred->trusted_certs,
24739beb93cSSam Leffler &cert->issuer);
24839beb93cSSam Leffler }
24939beb93cSSam Leffler if (cert == conn->cred->cert || cert == NULL) {
25039beb93cSSam Leffler /*
25139beb93cSSam Leffler * Server was not configured with all the needed certificates
25239beb93cSSam Leffler * to form a full certificate chain. The client may fail to
25339beb93cSSam Leffler * validate the chain unless it is configured with all the
25439beb93cSSam Leffler * missing CA certificates.
25539beb93cSSam Leffler */
25639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
25739beb93cSSam Leffler "not configured - validation may fail");
25839beb93cSSam Leffler }
25939beb93cSSam Leffler WPA_PUT_BE24(cert_start, pos - cert_start - 3);
26039beb93cSSam Leffler
26139beb93cSSam Leffler WPA_PUT_BE24(hs_length, pos - hs_length - 3);
26239beb93cSSam Leffler
26339beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
264f05cddf9SRui Paulo rhdr, end - rhdr, hs_start, pos - hs_start,
265f05cddf9SRui Paulo &rlen) < 0) {
26639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
26739beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
26839beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
26939beb93cSSam Leffler return -1;
27039beb93cSSam Leffler }
27139beb93cSSam Leffler pos = rhdr + rlen;
27239beb93cSSam Leffler
27339beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
27439beb93cSSam Leffler
27539beb93cSSam Leffler *msgpos = pos;
27639beb93cSSam Leffler
27739beb93cSSam Leffler return 0;
27839beb93cSSam Leffler }
27939beb93cSSam Leffler
28039beb93cSSam Leffler
tls_write_server_certificate_status(struct tlsv1_server * conn,u8 ** msgpos,u8 * end,int ocsp_multi,char * ocsp_resp,size_t ocsp_resp_len)281780fb4a2SCy Schubert static int tls_write_server_certificate_status(struct tlsv1_server *conn,
282780fb4a2SCy Schubert u8 **msgpos, u8 *end,
283780fb4a2SCy Schubert int ocsp_multi,
284780fb4a2SCy Schubert char *ocsp_resp,
285780fb4a2SCy Schubert size_t ocsp_resp_len)
286780fb4a2SCy Schubert {
287780fb4a2SCy Schubert u8 *pos, *rhdr, *hs_start, *hs_length;
288780fb4a2SCy Schubert size_t rlen;
289780fb4a2SCy Schubert
290780fb4a2SCy Schubert if (!ocsp_resp) {
291780fb4a2SCy Schubert /*
292780fb4a2SCy Schubert * Client did not request certificate status or there is no
293780fb4a2SCy Schubert * matching response cached.
294780fb4a2SCy Schubert */
295780fb4a2SCy Schubert return 0;
296780fb4a2SCy Schubert }
297780fb4a2SCy Schubert
298780fb4a2SCy Schubert pos = *msgpos;
299780fb4a2SCy Schubert if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + ocsp_resp_len >
300780fb4a2SCy Schubert (unsigned int) (end - pos)) {
301780fb4a2SCy Schubert tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
302780fb4a2SCy Schubert TLS_ALERT_INTERNAL_ERROR);
303780fb4a2SCy Schubert return -1;
304780fb4a2SCy Schubert }
305780fb4a2SCy Schubert
306780fb4a2SCy Schubert tlsv1_server_log(conn, "Send CertificateStatus (multi=%d)", ocsp_multi);
307780fb4a2SCy Schubert rhdr = pos;
308780fb4a2SCy Schubert pos += TLS_RECORD_HEADER_LEN;
309780fb4a2SCy Schubert
310780fb4a2SCy Schubert /* opaque fragment[TLSPlaintext.length] */
311780fb4a2SCy Schubert
312780fb4a2SCy Schubert /* Handshake */
313780fb4a2SCy Schubert hs_start = pos;
314780fb4a2SCy Schubert /* HandshakeType msg_type */
315780fb4a2SCy Schubert *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS;
316780fb4a2SCy Schubert /* uint24 length (to be filled) */
317780fb4a2SCy Schubert hs_length = pos;
318780fb4a2SCy Schubert pos += 3;
319780fb4a2SCy Schubert
320780fb4a2SCy Schubert /* body - CertificateStatus
321780fb4a2SCy Schubert *
322780fb4a2SCy Schubert * struct {
323780fb4a2SCy Schubert * CertificateStatusType status_type;
324780fb4a2SCy Schubert * select (status_type) {
325780fb4a2SCy Schubert * case ocsp: OCSPResponse;
326780fb4a2SCy Schubert * case ocsp_multi: OCSPResponseList;
327780fb4a2SCy Schubert * } response;
328780fb4a2SCy Schubert * } CertificateStatus;
329780fb4a2SCy Schubert *
330780fb4a2SCy Schubert * opaque OCSPResponse<1..2^24-1>;
331780fb4a2SCy Schubert *
332780fb4a2SCy Schubert * struct {
333780fb4a2SCy Schubert * OCSPResponse ocsp_response_list<1..2^24-1>;
334780fb4a2SCy Schubert * } OCSPResponseList;
335780fb4a2SCy Schubert */
336780fb4a2SCy Schubert
337780fb4a2SCy Schubert /* CertificateStatusType status_type */
338780fb4a2SCy Schubert if (ocsp_multi)
339780fb4a2SCy Schubert *pos++ = 2; /* ocsp_multi(2) */
340780fb4a2SCy Schubert else
341780fb4a2SCy Schubert *pos++ = 1; /* ocsp(1) */
342780fb4a2SCy Schubert /* uint24 length of OCSPResponse */
343780fb4a2SCy Schubert WPA_PUT_BE24(pos, ocsp_resp_len);
344780fb4a2SCy Schubert pos += 3;
345780fb4a2SCy Schubert os_memcpy(pos, ocsp_resp, ocsp_resp_len);
346780fb4a2SCy Schubert pos += ocsp_resp_len;
347780fb4a2SCy Schubert
348780fb4a2SCy Schubert WPA_PUT_BE24(hs_length, pos - hs_length - 3);
349780fb4a2SCy Schubert
350780fb4a2SCy Schubert if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
351780fb4a2SCy Schubert rhdr, end - rhdr, hs_start, pos - hs_start,
352780fb4a2SCy Schubert &rlen) < 0) {
353780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
354780fb4a2SCy Schubert tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
355780fb4a2SCy Schubert TLS_ALERT_INTERNAL_ERROR);
356780fb4a2SCy Schubert return -1;
357780fb4a2SCy Schubert }
358780fb4a2SCy Schubert pos = rhdr + rlen;
359780fb4a2SCy Schubert
360780fb4a2SCy Schubert tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
361780fb4a2SCy Schubert
362780fb4a2SCy Schubert *msgpos = pos;
363780fb4a2SCy Schubert
364780fb4a2SCy Schubert return 0;
365780fb4a2SCy Schubert }
366780fb4a2SCy Schubert
367780fb4a2SCy Schubert
tls_write_server_key_exchange(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)36839beb93cSSam Leffler static int tls_write_server_key_exchange(struct tlsv1_server *conn,
36939beb93cSSam Leffler u8 **msgpos, u8 *end)
37039beb93cSSam Leffler {
37139beb93cSSam Leffler tls_key_exchange keyx;
37239beb93cSSam Leffler const struct tls_cipher_suite *suite;
3735b9c547cSRui Paulo u8 *pos, *rhdr, *hs_start, *hs_length, *server_params;
37439beb93cSSam Leffler size_t rlen;
37539beb93cSSam Leffler u8 *dh_ys;
37639beb93cSSam Leffler size_t dh_ys_len;
3775b9c547cSRui Paulo const u8 *dh_p;
3785b9c547cSRui Paulo size_t dh_p_len;
37939beb93cSSam Leffler
38039beb93cSSam Leffler suite = tls_get_cipher_suite(conn->rl.cipher_suite);
38139beb93cSSam Leffler if (suite == NULL)
38239beb93cSSam Leffler keyx = TLS_KEY_X_NULL;
38339beb93cSSam Leffler else
38439beb93cSSam Leffler keyx = suite->key_exchange;
38539beb93cSSam Leffler
38639beb93cSSam Leffler if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
38739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
38839beb93cSSam Leffler return 0;
38939beb93cSSam Leffler }
39039beb93cSSam Leffler
3915b9c547cSRui Paulo if (keyx != TLS_KEY_X_DH_anon && keyx != TLS_KEY_X_DHE_RSA) {
39239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
39339beb93cSSam Leffler "supported with key exchange type %d", keyx);
39439beb93cSSam Leffler return -1;
39539beb93cSSam Leffler }
39639beb93cSSam Leffler
39739beb93cSSam Leffler if (conn->cred == NULL || conn->cred->dh_p == NULL ||
39839beb93cSSam Leffler conn->cred->dh_g == NULL) {
39939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
40039beb93cSSam Leffler "ServerKeyExhcange");
40139beb93cSSam Leffler return -1;
40239beb93cSSam Leffler }
40339beb93cSSam Leffler
4045b9c547cSRui Paulo tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len);
4055b9c547cSRui Paulo
40639beb93cSSam Leffler os_free(conn->dh_secret);
4075b9c547cSRui Paulo conn->dh_secret_len = dh_p_len;
40839beb93cSSam Leffler conn->dh_secret = os_malloc(conn->dh_secret_len);
40939beb93cSSam Leffler if (conn->dh_secret == NULL) {
41039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
41139beb93cSSam Leffler "memory for secret (Diffie-Hellman)");
41239beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
41339beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
41439beb93cSSam Leffler return -1;
41539beb93cSSam Leffler }
416f05cddf9SRui Paulo if (random_get_bytes(conn->dh_secret, conn->dh_secret_len)) {
41739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
41839beb93cSSam Leffler "data for Diffie-Hellman");
41939beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
42039beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
42139beb93cSSam Leffler os_free(conn->dh_secret);
42239beb93cSSam Leffler conn->dh_secret = NULL;
42339beb93cSSam Leffler return -1;
42439beb93cSSam Leffler }
42539beb93cSSam Leffler
4265b9c547cSRui Paulo if (os_memcmp(conn->dh_secret, dh_p, conn->dh_secret_len) > 0)
42739beb93cSSam Leffler conn->dh_secret[0] = 0; /* make sure secret < p */
42839beb93cSSam Leffler
42939beb93cSSam Leffler pos = conn->dh_secret;
43039beb93cSSam Leffler while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
43139beb93cSSam Leffler pos++;
43239beb93cSSam Leffler if (pos != conn->dh_secret) {
43339beb93cSSam Leffler os_memmove(conn->dh_secret, pos,
43439beb93cSSam Leffler conn->dh_secret_len - (pos - conn->dh_secret));
43539beb93cSSam Leffler conn->dh_secret_len -= pos - conn->dh_secret;
43639beb93cSSam Leffler }
43739beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
43839beb93cSSam Leffler conn->dh_secret, conn->dh_secret_len);
43939beb93cSSam Leffler
44039beb93cSSam Leffler /* Ys = g^secret mod p */
4415b9c547cSRui Paulo dh_ys_len = dh_p_len;
44239beb93cSSam Leffler dh_ys = os_malloc(dh_ys_len);
44339beb93cSSam Leffler if (dh_ys == NULL) {
44439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
44539beb93cSSam Leffler "Diffie-Hellman");
44639beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
44739beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
44839beb93cSSam Leffler return -1;
44939beb93cSSam Leffler }
45039beb93cSSam Leffler if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
45139beb93cSSam Leffler conn->dh_secret, conn->dh_secret_len,
4525b9c547cSRui Paulo dh_p, dh_p_len, dh_ys, &dh_ys_len)) {
45339beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
45439beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
45539beb93cSSam Leffler os_free(dh_ys);
45639beb93cSSam Leffler return -1;
45739beb93cSSam Leffler }
45839beb93cSSam Leffler
45939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
46039beb93cSSam Leffler dh_ys, dh_ys_len);
46139beb93cSSam Leffler
46239beb93cSSam Leffler /*
46339beb93cSSam Leffler * struct {
46439beb93cSSam Leffler * select (KeyExchangeAlgorithm) {
46539beb93cSSam Leffler * case diffie_hellman:
46639beb93cSSam Leffler * ServerDHParams params;
46739beb93cSSam Leffler * Signature signed_params;
46839beb93cSSam Leffler * case rsa:
46939beb93cSSam Leffler * ServerRSAParams params;
47039beb93cSSam Leffler * Signature signed_params;
47139beb93cSSam Leffler * };
47239beb93cSSam Leffler * } ServerKeyExchange;
47339beb93cSSam Leffler *
47439beb93cSSam Leffler * struct {
47539beb93cSSam Leffler * opaque dh_p<1..2^16-1>;
47639beb93cSSam Leffler * opaque dh_g<1..2^16-1>;
47739beb93cSSam Leffler * opaque dh_Ys<1..2^16-1>;
47839beb93cSSam Leffler * } ServerDHParams;
47939beb93cSSam Leffler */
48039beb93cSSam Leffler
48139beb93cSSam Leffler pos = *msgpos;
48239beb93cSSam Leffler
4835b9c547cSRui Paulo tlsv1_server_log(conn, "Send ServerKeyExchange");
48439beb93cSSam Leffler rhdr = pos;
48539beb93cSSam Leffler pos += TLS_RECORD_HEADER_LEN;
48639beb93cSSam Leffler
48739beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */
48839beb93cSSam Leffler
48939beb93cSSam Leffler /* Handshake */
49039beb93cSSam Leffler hs_start = pos;
49139beb93cSSam Leffler /* HandshakeType msg_type */
49239beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
49339beb93cSSam Leffler /* uint24 length (to be filled) */
49439beb93cSSam Leffler hs_length = pos;
49539beb93cSSam Leffler pos += 3;
49639beb93cSSam Leffler
49739beb93cSSam Leffler /* body - ServerDHParams */
4985b9c547cSRui Paulo server_params = pos;
49939beb93cSSam Leffler /* dh_p */
500780fb4a2SCy Schubert if (2 + dh_p_len > (size_t) (end - pos)) {
50139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
50239beb93cSSam Leffler "dh_p");
50339beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
50439beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
50539beb93cSSam Leffler os_free(dh_ys);
50639beb93cSSam Leffler return -1;
50739beb93cSSam Leffler }
5085b9c547cSRui Paulo WPA_PUT_BE16(pos, dh_p_len);
50939beb93cSSam Leffler pos += 2;
5105b9c547cSRui Paulo os_memcpy(pos, dh_p, dh_p_len);
5115b9c547cSRui Paulo pos += dh_p_len;
51239beb93cSSam Leffler
51339beb93cSSam Leffler /* dh_g */
514780fb4a2SCy Schubert if (2 + conn->cred->dh_g_len > (size_t) (end - pos)) {
51539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
51639beb93cSSam Leffler "dh_g");
51739beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
51839beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
51939beb93cSSam Leffler os_free(dh_ys);
52039beb93cSSam Leffler return -1;
52139beb93cSSam Leffler }
52239beb93cSSam Leffler WPA_PUT_BE16(pos, conn->cred->dh_g_len);
52339beb93cSSam Leffler pos += 2;
52439beb93cSSam Leffler os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
52539beb93cSSam Leffler pos += conn->cred->dh_g_len;
52639beb93cSSam Leffler
52739beb93cSSam Leffler /* dh_Ys */
528780fb4a2SCy Schubert if (2 + dh_ys_len > (size_t) (end - pos)) {
52939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
53039beb93cSSam Leffler "dh_Ys");
53139beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
53239beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
53339beb93cSSam Leffler os_free(dh_ys);
53439beb93cSSam Leffler return -1;
53539beb93cSSam Leffler }
53639beb93cSSam Leffler WPA_PUT_BE16(pos, dh_ys_len);
53739beb93cSSam Leffler pos += 2;
53839beb93cSSam Leffler os_memcpy(pos, dh_ys, dh_ys_len);
53939beb93cSSam Leffler pos += dh_ys_len;
54039beb93cSSam Leffler os_free(dh_ys);
54139beb93cSSam Leffler
5425b9c547cSRui Paulo /*
5435b9c547cSRui Paulo * select (SignatureAlgorithm)
5445b9c547cSRui Paulo * { case anonymous: struct { };
5455b9c547cSRui Paulo * case rsa:
5465b9c547cSRui Paulo * digitally-signed struct {
5475b9c547cSRui Paulo * opaque md5_hash[16];
5485b9c547cSRui Paulo * opaque sha_hash[20];
5495b9c547cSRui Paulo * };
5505b9c547cSRui Paulo * case dsa:
5515b9c547cSRui Paulo * digitally-signed struct {
5525b9c547cSRui Paulo * opaque sha_hash[20];
5535b9c547cSRui Paulo * };
5545b9c547cSRui Paulo * } Signature;
5555b9c547cSRui Paulo *
5565b9c547cSRui Paulo * md5_hash
5575b9c547cSRui Paulo * MD5(ClientHello.random + ServerHello.random + ServerParams);
5585b9c547cSRui Paulo *
5595b9c547cSRui Paulo * sha_hash
5605b9c547cSRui Paulo * SHA(ClientHello.random + ServerHello.random + ServerParams);
5615b9c547cSRui Paulo */
5625b9c547cSRui Paulo
5635b9c547cSRui Paulo if (keyx == TLS_KEY_X_DHE_RSA) {
5645b9c547cSRui Paulo u8 hash[100];
5655b9c547cSRui Paulo u8 *signed_start;
5665b9c547cSRui Paulo size_t clen;
5675b9c547cSRui Paulo int hlen;
5685b9c547cSRui Paulo
5695b9c547cSRui Paulo if (conn->rl.tls_version >= TLS_VERSION_1_2) {
5705b9c547cSRui Paulo #ifdef CONFIG_TLSV12
5715b9c547cSRui Paulo hlen = tlsv12_key_x_server_params_hash(
572780fb4a2SCy Schubert conn->rl.tls_version, TLS_HASH_ALG_SHA256,
573780fb4a2SCy Schubert conn->client_random,
5745b9c547cSRui Paulo conn->server_random, server_params,
5755b9c547cSRui Paulo pos - server_params, hash + 19);
5765b9c547cSRui Paulo
5775b9c547cSRui Paulo /*
5785b9c547cSRui Paulo * RFC 5246, 4.7:
5795b9c547cSRui Paulo * TLS v1.2 adds explicit indication of the used
5805b9c547cSRui Paulo * signature and hash algorithms.
5815b9c547cSRui Paulo *
5825b9c547cSRui Paulo * struct {
5835b9c547cSRui Paulo * HashAlgorithm hash;
5845b9c547cSRui Paulo * SignatureAlgorithm signature;
5855b9c547cSRui Paulo * } SignatureAndHashAlgorithm;
5865b9c547cSRui Paulo */
587780fb4a2SCy Schubert if (hlen < 0 || end - pos < 2) {
5885b9c547cSRui Paulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
5895b9c547cSRui Paulo TLS_ALERT_INTERNAL_ERROR);
5905b9c547cSRui Paulo return -1;
5915b9c547cSRui Paulo }
5925b9c547cSRui Paulo *pos++ = TLS_HASH_ALG_SHA256;
5935b9c547cSRui Paulo *pos++ = TLS_SIGN_ALG_RSA;
5945b9c547cSRui Paulo
5955b9c547cSRui Paulo /*
5965b9c547cSRui Paulo * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
5975b9c547cSRui Paulo *
5985b9c547cSRui Paulo * DigestInfo ::= SEQUENCE {
5995b9c547cSRui Paulo * digestAlgorithm DigestAlgorithm,
6005b9c547cSRui Paulo * digest OCTET STRING
6015b9c547cSRui Paulo * }
6025b9c547cSRui Paulo *
6035b9c547cSRui Paulo * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
6045b9c547cSRui Paulo *
6055b9c547cSRui Paulo * DER encoded DigestInfo for SHA256 per RFC 3447:
6065b9c547cSRui Paulo * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
6075b9c547cSRui Paulo * 04 20 || H
6085b9c547cSRui Paulo */
6095b9c547cSRui Paulo hlen += 19;
6105b9c547cSRui Paulo os_memcpy(hash,
6115b9c547cSRui Paulo "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
6125b9c547cSRui Paulo "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
6135b9c547cSRui Paulo
6145b9c547cSRui Paulo #else /* CONFIG_TLSV12 */
6155b9c547cSRui Paulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
6165b9c547cSRui Paulo TLS_ALERT_INTERNAL_ERROR);
6175b9c547cSRui Paulo return -1;
6185b9c547cSRui Paulo #endif /* CONFIG_TLSV12 */
6195b9c547cSRui Paulo } else {
6205b9c547cSRui Paulo hlen = tls_key_x_server_params_hash(
6215b9c547cSRui Paulo conn->rl.tls_version, conn->client_random,
6225b9c547cSRui Paulo conn->server_random, server_params,
623*a90b9d01SCy Schubert pos - server_params, hash, sizeof(hash));
6245b9c547cSRui Paulo }
6255b9c547cSRui Paulo
6265b9c547cSRui Paulo if (hlen < 0) {
6275b9c547cSRui Paulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
6285b9c547cSRui Paulo TLS_ALERT_INTERNAL_ERROR);
6295b9c547cSRui Paulo return -1;
6305b9c547cSRui Paulo }
6315b9c547cSRui Paulo
6325b9c547cSRui Paulo wpa_hexdump(MSG_MSGDUMP, "TLS: ServerKeyExchange signed_params hash",
6335b9c547cSRui Paulo hash, hlen);
6345b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
6355b9c547cSRui Paulo if (conn->test_flags & TLS_BREAK_SRV_KEY_X_HASH) {
6365b9c547cSRui Paulo tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params hash");
6375b9c547cSRui Paulo hash[hlen - 1] ^= 0x80;
6385b9c547cSRui Paulo }
6395b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
6405b9c547cSRui Paulo
6415b9c547cSRui Paulo /*
6425b9c547cSRui Paulo * RFC 2246, 4.7:
6435b9c547cSRui Paulo * In digital signing, one-way hash functions are used as input
6445b9c547cSRui Paulo * for a signing algorithm. A digitally-signed element is
6455b9c547cSRui Paulo * encoded as an opaque vector <0..2^16-1>, where the length is
6465b9c547cSRui Paulo * specified by the signing algorithm and key.
6475b9c547cSRui Paulo *
6485b9c547cSRui Paulo * In RSA signing, a 36-byte structure of two hashes (one SHA
6495b9c547cSRui Paulo * and one MD5) is signed (encrypted with the private key). It
6505b9c547cSRui Paulo * is encoded with PKCS #1 block type 0 or type 1 as described
6515b9c547cSRui Paulo * in [PKCS1].
6525b9c547cSRui Paulo */
6535b9c547cSRui Paulo signed_start = pos; /* length to be filled */
6545b9c547cSRui Paulo pos += 2;
6555b9c547cSRui Paulo clen = end - pos;
6565b9c547cSRui Paulo if (conn->cred == NULL ||
6575b9c547cSRui Paulo crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
6585b9c547cSRui Paulo pos, &clen) < 0) {
6595b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
6605b9c547cSRui Paulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
6615b9c547cSRui Paulo TLS_ALERT_INTERNAL_ERROR);
6625b9c547cSRui Paulo return -1;
6635b9c547cSRui Paulo }
6645b9c547cSRui Paulo WPA_PUT_BE16(signed_start, clen);
6655b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
6665b9c547cSRui Paulo if (conn->test_flags & TLS_BREAK_SRV_KEY_X_SIGNATURE) {
6675b9c547cSRui Paulo tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params signature");
6685b9c547cSRui Paulo pos[clen - 1] ^= 0x80;
6695b9c547cSRui Paulo }
6705b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
6715b9c547cSRui Paulo
6725b9c547cSRui Paulo pos += clen;
6735b9c547cSRui Paulo }
6745b9c547cSRui Paulo
67539beb93cSSam Leffler WPA_PUT_BE24(hs_length, pos - hs_length - 3);
67639beb93cSSam Leffler
67739beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
678f05cddf9SRui Paulo rhdr, end - rhdr, hs_start, pos - hs_start,
679f05cddf9SRui Paulo &rlen) < 0) {
68039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
68139beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
68239beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
68339beb93cSSam Leffler return -1;
68439beb93cSSam Leffler }
68539beb93cSSam Leffler pos = rhdr + rlen;
68639beb93cSSam Leffler
68739beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
68839beb93cSSam Leffler
68939beb93cSSam Leffler *msgpos = pos;
69039beb93cSSam Leffler
69139beb93cSSam Leffler return 0;
69239beb93cSSam Leffler }
69339beb93cSSam Leffler
69439beb93cSSam Leffler
tls_write_server_certificate_request(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)69539beb93cSSam Leffler static int tls_write_server_certificate_request(struct tlsv1_server *conn,
69639beb93cSSam Leffler u8 **msgpos, u8 *end)
69739beb93cSSam Leffler {
69839beb93cSSam Leffler u8 *pos, *rhdr, *hs_start, *hs_length;
69939beb93cSSam Leffler size_t rlen;
70039beb93cSSam Leffler
70139beb93cSSam Leffler if (!conn->verify_peer) {
70239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
70339beb93cSSam Leffler return 0;
70439beb93cSSam Leffler }
70539beb93cSSam Leffler
70639beb93cSSam Leffler pos = *msgpos;
70739beb93cSSam Leffler
7085b9c547cSRui Paulo tlsv1_server_log(conn, "Send CertificateRequest");
70939beb93cSSam Leffler rhdr = pos;
71039beb93cSSam Leffler pos += TLS_RECORD_HEADER_LEN;
71139beb93cSSam Leffler
71239beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */
71339beb93cSSam Leffler
71439beb93cSSam Leffler /* Handshake */
71539beb93cSSam Leffler hs_start = pos;
71639beb93cSSam Leffler /* HandshakeType msg_type */
71739beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
71839beb93cSSam Leffler /* uint24 length (to be filled) */
71939beb93cSSam Leffler hs_length = pos;
72039beb93cSSam Leffler pos += 3;
72139beb93cSSam Leffler /* body - CertificateRequest */
72239beb93cSSam Leffler
72339beb93cSSam Leffler /*
72439beb93cSSam Leffler * enum {
72539beb93cSSam Leffler * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
72639beb93cSSam Leffler * (255)
72739beb93cSSam Leffler * } ClientCertificateType;
72839beb93cSSam Leffler * ClientCertificateType certificate_types<1..2^8-1>
72939beb93cSSam Leffler */
73039beb93cSSam Leffler *pos++ = 1;
73139beb93cSSam Leffler *pos++ = 1; /* rsa_sign */
73239beb93cSSam Leffler
73339beb93cSSam Leffler /*
73439beb93cSSam Leffler * opaque DistinguishedName<1..2^16-1>
73539beb93cSSam Leffler * DistinguishedName certificate_authorities<3..2^16-1>
73639beb93cSSam Leffler */
73739beb93cSSam Leffler /* TODO: add support for listing DNs for trusted CAs */
73839beb93cSSam Leffler WPA_PUT_BE16(pos, 0);
73939beb93cSSam Leffler pos += 2;
74039beb93cSSam Leffler
74139beb93cSSam Leffler WPA_PUT_BE24(hs_length, pos - hs_length - 3);
74239beb93cSSam Leffler
74339beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
744f05cddf9SRui Paulo rhdr, end - rhdr, hs_start, pos - hs_start,
745f05cddf9SRui Paulo &rlen) < 0) {
74639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
74739beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
74839beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
74939beb93cSSam Leffler return -1;
75039beb93cSSam Leffler }
75139beb93cSSam Leffler pos = rhdr + rlen;
75239beb93cSSam Leffler
75339beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
75439beb93cSSam Leffler
75539beb93cSSam Leffler *msgpos = pos;
75639beb93cSSam Leffler
75739beb93cSSam Leffler return 0;
75839beb93cSSam Leffler }
75939beb93cSSam Leffler
76039beb93cSSam Leffler
tls_write_server_hello_done(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)76139beb93cSSam Leffler static int tls_write_server_hello_done(struct tlsv1_server *conn,
76239beb93cSSam Leffler u8 **msgpos, u8 *end)
76339beb93cSSam Leffler {
764f05cddf9SRui Paulo u8 *pos;
76539beb93cSSam Leffler size_t rlen;
766f05cddf9SRui Paulo u8 payload[4];
76739beb93cSSam Leffler
7685b9c547cSRui Paulo tlsv1_server_log(conn, "Send ServerHelloDone");
76939beb93cSSam Leffler
77039beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */
77139beb93cSSam Leffler
77239beb93cSSam Leffler /* Handshake */
773f05cddf9SRui Paulo pos = payload;
77439beb93cSSam Leffler /* HandshakeType msg_type */
77539beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
776f05cddf9SRui Paulo /* uint24 length */
777f05cddf9SRui Paulo WPA_PUT_BE24(pos, 0);
77839beb93cSSam Leffler pos += 3;
77939beb93cSSam Leffler /* body - ServerHelloDone (empty) */
78039beb93cSSam Leffler
78139beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
782f05cddf9SRui Paulo *msgpos, end - *msgpos, payload, pos - payload,
783f05cddf9SRui Paulo &rlen) < 0) {
78439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
78539beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
78639beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
78739beb93cSSam Leffler return -1;
78839beb93cSSam Leffler }
78939beb93cSSam Leffler
790f05cddf9SRui Paulo tls_verify_hash_add(&conn->verify, payload, pos - payload);
79139beb93cSSam Leffler
792f05cddf9SRui Paulo *msgpos += rlen;
79339beb93cSSam Leffler
79439beb93cSSam Leffler return 0;
79539beb93cSSam Leffler }
79639beb93cSSam Leffler
79739beb93cSSam Leffler
tls_write_server_change_cipher_spec(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)79839beb93cSSam Leffler static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
79939beb93cSSam Leffler u8 **msgpos, u8 *end)
80039beb93cSSam Leffler {
80139beb93cSSam Leffler size_t rlen;
802f05cddf9SRui Paulo u8 payload[1];
80339beb93cSSam Leffler
8045b9c547cSRui Paulo tlsv1_server_log(conn, "Send ChangeCipherSpec");
805f05cddf9SRui Paulo
806f05cddf9SRui Paulo payload[0] = TLS_CHANGE_CIPHER_SPEC;
807f05cddf9SRui Paulo
80839beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
809f05cddf9SRui Paulo *msgpos, end - *msgpos, payload, sizeof(payload),
810f05cddf9SRui Paulo &rlen) < 0) {
81139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
81239beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
81339beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
81439beb93cSSam Leffler return -1;
81539beb93cSSam Leffler }
81639beb93cSSam Leffler
81739beb93cSSam Leffler if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
81839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
81939beb93cSSam Leffler "record layer");
82039beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
82139beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
82239beb93cSSam Leffler return -1;
82339beb93cSSam Leffler }
82439beb93cSSam Leffler
825f05cddf9SRui Paulo *msgpos += rlen;
82639beb93cSSam Leffler
82739beb93cSSam Leffler return 0;
82839beb93cSSam Leffler }
82939beb93cSSam Leffler
83039beb93cSSam Leffler
tls_write_server_finished(struct tlsv1_server * conn,u8 ** msgpos,u8 * end)83139beb93cSSam Leffler static int tls_write_server_finished(struct tlsv1_server *conn,
83239beb93cSSam Leffler u8 **msgpos, u8 *end)
83339beb93cSSam Leffler {
834f05cddf9SRui Paulo u8 *pos, *hs_start;
83539beb93cSSam Leffler size_t rlen, hlen;
836f05cddf9SRui Paulo u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
83739beb93cSSam Leffler u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
83839beb93cSSam Leffler
83939beb93cSSam Leffler pos = *msgpos;
84039beb93cSSam Leffler
8415b9c547cSRui Paulo tlsv1_server_log(conn, "Send Finished");
84239beb93cSSam Leffler
84339beb93cSSam Leffler /* Encrypted Handshake Message: Finished */
84439beb93cSSam Leffler
845f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
846f05cddf9SRui Paulo if (conn->rl.tls_version >= TLS_VERSION_1_2) {
847f05cddf9SRui Paulo hlen = SHA256_MAC_LEN;
848f05cddf9SRui Paulo if (conn->verify.sha256_server == NULL ||
849f05cddf9SRui Paulo crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
850f05cddf9SRui Paulo < 0) {
851f05cddf9SRui Paulo conn->verify.sha256_server = NULL;
852f05cddf9SRui Paulo tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
853f05cddf9SRui Paulo TLS_ALERT_INTERNAL_ERROR);
854f05cddf9SRui Paulo return -1;
855f05cddf9SRui Paulo }
856f05cddf9SRui Paulo conn->verify.sha256_server = NULL;
857f05cddf9SRui Paulo } else {
858f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
859f05cddf9SRui Paulo
86039beb93cSSam Leffler hlen = MD5_MAC_LEN;
86139beb93cSSam Leffler if (conn->verify.md5_server == NULL ||
86239beb93cSSam Leffler crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
86339beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
86439beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
86539beb93cSSam Leffler conn->verify.md5_server = NULL;
86639beb93cSSam Leffler crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
86739beb93cSSam Leffler conn->verify.sha1_server = NULL;
86839beb93cSSam Leffler return -1;
86939beb93cSSam Leffler }
87039beb93cSSam Leffler conn->verify.md5_server = NULL;
87139beb93cSSam Leffler hlen = SHA1_MAC_LEN;
87239beb93cSSam Leffler if (conn->verify.sha1_server == NULL ||
87339beb93cSSam Leffler crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
87439beb93cSSam Leffler &hlen) < 0) {
87539beb93cSSam Leffler conn->verify.sha1_server = NULL;
87639beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
87739beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
87839beb93cSSam Leffler return -1;
87939beb93cSSam Leffler }
88039beb93cSSam Leffler conn->verify.sha1_server = NULL;
881f05cddf9SRui Paulo hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
88239beb93cSSam Leffler
883f05cddf9SRui Paulo #ifdef CONFIG_TLSV12
884f05cddf9SRui Paulo }
885f05cddf9SRui Paulo #endif /* CONFIG_TLSV12 */
886f05cddf9SRui Paulo
887f05cddf9SRui Paulo if (tls_prf(conn->rl.tls_version,
888f05cddf9SRui Paulo conn->master_secret, TLS_MASTER_SECRET_LEN,
889f05cddf9SRui Paulo "server finished", hash, hlen,
890f05cddf9SRui Paulo verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
89139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
89239beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
89339beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
89439beb93cSSam Leffler return -1;
89539beb93cSSam Leffler }
89639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
897f05cddf9SRui Paulo verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
8985b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
8995b9c547cSRui Paulo if (conn->test_flags & TLS_BREAK_VERIFY_DATA) {
9005b9c547cSRui Paulo tlsv1_server_log(conn, "TESTING: Break verify_data (server)");
9015b9c547cSRui Paulo verify_data[1 + 3 + 1] ^= 0x80;
9025b9c547cSRui Paulo }
9035b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
90439beb93cSSam Leffler
90539beb93cSSam Leffler /* Handshake */
906f05cddf9SRui Paulo pos = hs_start = verify_data;
90739beb93cSSam Leffler /* HandshakeType msg_type */
90839beb93cSSam Leffler *pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
909f05cddf9SRui Paulo /* uint24 length */
910f05cddf9SRui Paulo WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
91139beb93cSSam Leffler pos += 3;
91239beb93cSSam Leffler pos += TLS_VERIFY_DATA_LEN;
91339beb93cSSam Leffler tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
91439beb93cSSam Leffler
91539beb93cSSam Leffler if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
916f05cddf9SRui Paulo *msgpos, end - *msgpos, hs_start, pos - hs_start,
917f05cddf9SRui Paulo &rlen) < 0) {
91839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
91939beb93cSSam Leffler tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
92039beb93cSSam Leffler TLS_ALERT_INTERNAL_ERROR);
92139beb93cSSam Leffler return -1;
92239beb93cSSam Leffler }
92339beb93cSSam Leffler
924f05cddf9SRui Paulo *msgpos += rlen;
92539beb93cSSam Leffler
92639beb93cSSam Leffler return 0;
92739beb93cSSam Leffler }
92839beb93cSSam Leffler
92939beb93cSSam Leffler
tls_send_server_hello(struct tlsv1_server * conn,size_t * out_len)93039beb93cSSam Leffler static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
93139beb93cSSam Leffler {
93239beb93cSSam Leffler u8 *msg, *end, *pos;
93339beb93cSSam Leffler size_t msglen;
934780fb4a2SCy Schubert int ocsp_multi = 0;
935780fb4a2SCy Schubert char *ocsp_resp = NULL;
936780fb4a2SCy Schubert size_t ocsp_resp_len = 0;
93739beb93cSSam Leffler
93839beb93cSSam Leffler *out_len = 0;
93939beb93cSSam Leffler
940780fb4a2SCy Schubert if (conn->status_request_multi &&
941780fb4a2SCy Schubert conn->cred->ocsp_stapling_response_multi) {
942780fb4a2SCy Schubert ocsp_resp = os_readfile(
943780fb4a2SCy Schubert conn->cred->ocsp_stapling_response_multi,
944780fb4a2SCy Schubert &ocsp_resp_len);
945780fb4a2SCy Schubert ocsp_multi = 1;
946780fb4a2SCy Schubert } else if ((conn->status_request || conn->status_request_v2) &&
947780fb4a2SCy Schubert conn->cred->ocsp_stapling_response) {
948780fb4a2SCy Schubert ocsp_resp = os_readfile(conn->cred->ocsp_stapling_response,
949780fb4a2SCy Schubert &ocsp_resp_len);
950780fb4a2SCy Schubert }
951780fb4a2SCy Schubert if (!ocsp_resp)
952780fb4a2SCy Schubert ocsp_resp_len = 0;
953780fb4a2SCy Schubert
954780fb4a2SCy Schubert msglen = 1000 + tls_server_cert_chain_der_len(conn) + ocsp_resp_len;
95539beb93cSSam Leffler
95639beb93cSSam Leffler msg = os_malloc(msglen);
957780fb4a2SCy Schubert if (msg == NULL) {
958780fb4a2SCy Schubert os_free(ocsp_resp);
95939beb93cSSam Leffler return NULL;
960780fb4a2SCy Schubert }
96139beb93cSSam Leffler
96239beb93cSSam Leffler pos = msg;
96339beb93cSSam Leffler end = msg + msglen;
96439beb93cSSam Leffler
96539beb93cSSam Leffler if (tls_write_server_hello(conn, &pos, end) < 0) {
96639beb93cSSam Leffler os_free(msg);
967780fb4a2SCy Schubert os_free(ocsp_resp);
96839beb93cSSam Leffler return NULL;
96939beb93cSSam Leffler }
97039beb93cSSam Leffler
97139beb93cSSam Leffler if (conn->use_session_ticket) {
972780fb4a2SCy Schubert os_free(ocsp_resp);
973780fb4a2SCy Schubert
97439beb93cSSam Leffler /* Abbreviated handshake using session ticket; RFC 4507 */
97539beb93cSSam Leffler if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
97639beb93cSSam Leffler tls_write_server_finished(conn, &pos, end) < 0) {
97739beb93cSSam Leffler os_free(msg);
97839beb93cSSam Leffler return NULL;
97939beb93cSSam Leffler }
98039beb93cSSam Leffler
98139beb93cSSam Leffler *out_len = pos - msg;
98239beb93cSSam Leffler
98339beb93cSSam Leffler conn->state = CHANGE_CIPHER_SPEC;
98439beb93cSSam Leffler
98539beb93cSSam Leffler return msg;
98639beb93cSSam Leffler }
98739beb93cSSam Leffler
98839beb93cSSam Leffler /* Full handshake */
98939beb93cSSam Leffler if (tls_write_server_certificate(conn, &pos, end) < 0 ||
990780fb4a2SCy Schubert tls_write_server_certificate_status(conn, &pos, end, ocsp_multi,
991780fb4a2SCy Schubert ocsp_resp, ocsp_resp_len) < 0 ||
99239beb93cSSam Leffler tls_write_server_key_exchange(conn, &pos, end) < 0 ||
99339beb93cSSam Leffler tls_write_server_certificate_request(conn, &pos, end) < 0 ||
99439beb93cSSam Leffler tls_write_server_hello_done(conn, &pos, end) < 0) {
99539beb93cSSam Leffler os_free(msg);
996780fb4a2SCy Schubert os_free(ocsp_resp);
99739beb93cSSam Leffler return NULL;
99839beb93cSSam Leffler }
999780fb4a2SCy Schubert os_free(ocsp_resp);
100039beb93cSSam Leffler
100139beb93cSSam Leffler *out_len = pos - msg;
100239beb93cSSam Leffler
100339beb93cSSam Leffler conn->state = CLIENT_CERTIFICATE;
100439beb93cSSam Leffler
100539beb93cSSam Leffler return msg;
100639beb93cSSam Leffler }
100739beb93cSSam Leffler
100839beb93cSSam Leffler
tls_send_change_cipher_spec(struct tlsv1_server * conn,size_t * out_len)100939beb93cSSam Leffler static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
101039beb93cSSam Leffler size_t *out_len)
101139beb93cSSam Leffler {
101239beb93cSSam Leffler u8 *msg, *end, *pos;
101339beb93cSSam Leffler
101439beb93cSSam Leffler *out_len = 0;
101539beb93cSSam Leffler
101639beb93cSSam Leffler msg = os_malloc(1000);
101739beb93cSSam Leffler if (msg == NULL)
101839beb93cSSam Leffler return NULL;
101939beb93cSSam Leffler
102039beb93cSSam Leffler pos = msg;
102139beb93cSSam Leffler end = msg + 1000;
102239beb93cSSam Leffler
102339beb93cSSam Leffler if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
102439beb93cSSam Leffler tls_write_server_finished(conn, &pos, end) < 0) {
102539beb93cSSam Leffler os_free(msg);
102639beb93cSSam Leffler return NULL;
102739beb93cSSam Leffler }
102839beb93cSSam Leffler
102939beb93cSSam Leffler *out_len = pos - msg;
103039beb93cSSam Leffler
10315b9c547cSRui Paulo tlsv1_server_log(conn, "Handshake completed successfully");
103239beb93cSSam Leffler conn->state = ESTABLISHED;
103339beb93cSSam Leffler
103439beb93cSSam Leffler return msg;
103539beb93cSSam Leffler }
103639beb93cSSam Leffler
103739beb93cSSam Leffler
tlsv1_server_handshake_write(struct tlsv1_server * conn,size_t * out_len)103839beb93cSSam Leffler u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
103939beb93cSSam Leffler {
104039beb93cSSam Leffler switch (conn->state) {
104139beb93cSSam Leffler case SERVER_HELLO:
104239beb93cSSam Leffler return tls_send_server_hello(conn, out_len);
104339beb93cSSam Leffler case SERVER_CHANGE_CIPHER_SPEC:
104439beb93cSSam Leffler return tls_send_change_cipher_spec(conn, out_len);
104539beb93cSSam Leffler default:
104639beb93cSSam Leffler if (conn->state == ESTABLISHED && conn->use_session_ticket) {
104739beb93cSSam Leffler /* Abbreviated handshake was already completed. */
104839beb93cSSam Leffler return NULL;
104939beb93cSSam Leffler }
10505b9c547cSRui Paulo tlsv1_server_log(conn, "Unexpected state %d while generating reply",
10515b9c547cSRui Paulo conn->state);
105239beb93cSSam Leffler return NULL;
105339beb93cSSam Leffler }
105439beb93cSSam Leffler }
105539beb93cSSam Leffler
105639beb93cSSam Leffler
tlsv1_server_send_alert(struct tlsv1_server * conn,u8 level,u8 description,size_t * out_len)105739beb93cSSam Leffler u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
105839beb93cSSam Leffler u8 description, size_t *out_len)
105939beb93cSSam Leffler {
106039beb93cSSam Leffler u8 *alert, *pos, *length;
106139beb93cSSam Leffler
10625b9c547cSRui Paulo tlsv1_server_log(conn, "Send Alert(%d:%d)", level, description);
106339beb93cSSam Leffler *out_len = 0;
106439beb93cSSam Leffler
106539beb93cSSam Leffler alert = os_malloc(10);
106639beb93cSSam Leffler if (alert == NULL)
106739beb93cSSam Leffler return NULL;
106839beb93cSSam Leffler
106939beb93cSSam Leffler pos = alert;
107039beb93cSSam Leffler
107139beb93cSSam Leffler /* TLSPlaintext */
107239beb93cSSam Leffler /* ContentType type */
107339beb93cSSam Leffler *pos++ = TLS_CONTENT_TYPE_ALERT;
107439beb93cSSam Leffler /* ProtocolVersion version */
1075f05cddf9SRui Paulo WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
1076f05cddf9SRui Paulo TLS_VERSION);
107739beb93cSSam Leffler pos += 2;
107839beb93cSSam Leffler /* uint16 length (to be filled) */
107939beb93cSSam Leffler length = pos;
108039beb93cSSam Leffler pos += 2;
108139beb93cSSam Leffler /* opaque fragment[TLSPlaintext.length] */
108239beb93cSSam Leffler
108339beb93cSSam Leffler /* Alert */
108439beb93cSSam Leffler /* AlertLevel level */
108539beb93cSSam Leffler *pos++ = level;
108639beb93cSSam Leffler /* AlertDescription description */
108739beb93cSSam Leffler *pos++ = description;
108839beb93cSSam Leffler
108939beb93cSSam Leffler WPA_PUT_BE16(length, pos - length - 2);
109039beb93cSSam Leffler *out_len = pos - alert;
109139beb93cSSam Leffler
109239beb93cSSam Leffler return alert;
109339beb93cSSam Leffler }
1094