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) {
                if (tlsv1_process_diffie_hellman(conn, pos, len) < 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;
}
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;
}
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) < 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 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;
}