Exemplo n.º 1
0
static int tls_process_client_key_exchange_dh_anon(
        struct tlsv1_server *conn, const u8 *pos, const u8 *end) {
    const u8 *dh_yc;
    u16 dh_yc_len;
    u8 *shared;
    size_t shared_len;
    int res;

    /*
     * struct {
     *   select (PublicValueEncoding) {
     *     case implicit: struct { };
     *     case explicit: opaque dh_Yc<1..2^16-1>;
     *   } dh_public;
     * } ClientDiffieHellmanPublic;
     */

    wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
            pos, end - pos);

    if (end == pos) {
        wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding "
                "not supported");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }

    if (end - pos < 3) {
        wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
                "length");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }

    dh_yc_len = WPA_GET_BE16(pos);
    dh_yc = pos + 2;

    if (dh_yc + dh_yc_len > end) {
        wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
                "(length %d)", dh_yc_len);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }

    wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
            dh_yc, dh_yc_len);

    if (conn->cred == NULL || conn->cred->dh_p == NULL ||
            conn->dh_secret == NULL) {
        wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }

    shared_len = conn->cred->dh_p_len;
    shared = os_malloc(shared_len);
    if (shared == NULL) {
        wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
                "DH");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }

    /* shared = Yc^secret mod p */
    if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
            conn->dh_secret_len,
            conn->cred->dh_p, conn->cred->dh_p_len,
            shared, &shared_len)) {
        os_free(shared);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }
    wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
            shared, shared_len);

    os_memset(conn->dh_secret, 0, conn->dh_secret_len);
    os_free(conn->dh_secret);
    conn->dh_secret = NULL;

    res = tlsv1_server_derive_keys(conn, shared, shared_len);

    /* Clear the pre-master secret since it is not needed anymore */
    os_memset(shared, 0, shared_len);
    os_free(shared);

    if (res) {
        wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }

    return 0;
}
static int tls_write_server_hello(struct tlsv1_server *conn,
				  u8 **msgpos, u8 *end)
{
	u8 *pos, *rhdr, *hs_start, *hs_length;
	struct os_time now;
	size_t rlen;

	pos = *msgpos;

	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
	rhdr = pos;
	pos += TLS_RECORD_HEADER_LEN;

	os_get_time(&now);
	WPA_PUT_BE32(conn->server_random, now.sec);
	if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
			   "server_random");
		return -1;
	}
	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
		    conn->server_random, TLS_RANDOM_LEN);

	conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
	if (os_get_random(conn->session_id, conn->session_id_len)) {
		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
			   "session_id");
		return -1;
	}
	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
		    conn->session_id, conn->session_id_len);

	/* opaque fragment[TLSPlaintext.length] */

	/* Handshake */
	hs_start = pos;
	/* HandshakeType msg_type */
	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
	/* uint24 length (to be filled) */
	hs_length = pos;
	pos += 3;
	/* body - ServerHello */
	/* ProtocolVersion server_version */
	WPA_PUT_BE16(pos, TLS_VERSION);
	pos += 2;
	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
	os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
	pos += TLS_RANDOM_LEN;
	/* SessionID session_id */
	*pos++ = conn->session_id_len;
	os_memcpy(pos, conn->session_id, conn->session_id_len);
	pos += conn->session_id_len;
	/* CipherSuite cipher_suite */
	WPA_PUT_BE16(pos, conn->cipher_suite);
	pos += 2;
	/* CompressionMethod compression_method */
	*pos++ = TLS_COMPRESSION_NULL;

	if (conn->session_ticket && conn->session_ticket_cb) {
		int res = conn->session_ticket_cb(
			conn->session_ticket_cb_ctx,
			conn->session_ticket, conn->session_ticket_len,
			conn->client_random, conn->server_random,
			conn->master_secret);
		if (res < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
				   "indicated failure");
			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
					   TLS_ALERT_HANDSHAKE_FAILURE);
			return -1;
		}
		conn->use_session_ticket = res;

		if (conn->use_session_ticket) {
			if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
					   "derive keys");
				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
						   TLS_ALERT_INTERNAL_ERROR);
				return -1;
			}
		}

		/*
		 * RFC 4507 specifies that server would include an empty
		 * SessionTicket extension in ServerHello and a
		 * NewSessionTicket message after the ServerHello. However,
		 * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
		 * extension at the moment, does not use such extensions.
		 *
		 * TODO: Add support for configuring RFC 4507 behavior and make
		 * EAP-FAST disable it.
		 */
	}

	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);

	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
				   TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	pos = rhdr + rlen;

	*msgpos = pos;

	return 0;
}
Exemplo n.º 3
0
static int tls_process_client_key_exchange_rsa(
        struct tlsv1_server *conn, const u8 *pos, const u8 *end) {
    u8 *out;
    size_t outlen, outbuflen;
    int res;
    int use_random = 0;

    if (end - pos < 2) {
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }

    pos += 2;

    outbuflen = outlen = end - pos;
    out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
            outlen : TLS_PRE_MASTER_SECRET_LEN);
    if (out == NULL) {
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }

    /*
     * struct {
     *   ProtocolVersion client_version;
     *   opaque random[46];
     * } PreMasterSecret;
     *
     * struct {
     *   public-key-encrypted PreMasterSecret pre_master_secret;
     * } EncryptedPreMasterSecret;
     */

    /*
     * Note: To avoid Bleichenbacher attack, we do not report decryption or
     * parsing errors from EncryptedPreMasterSecret processing to the
     * client. Instead, a random pre-master secret is used to force the
     * handshake to fail.
     */

    if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
            pos, end - pos,
            out, &outlen) < 0) {
        wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
                "PreMasterSecret (encr_len=%d outlen=%lu)",
                (int) (end - pos), (unsigned long) outlen);
        use_random = 1;
    }

    if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
        wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
                "length %lu", (unsigned long) outlen);
        use_random = 1;
    }

    if (WPA_GET_BE16(out) != conn->client_version) {
        wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
                "ClientKeyExchange does not match with version in "
                "ClientHello");
        use_random = 1;
    }

    if (use_random) {
        wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret "
                "to avoid revealing information about private key");
        outlen = TLS_PRE_MASTER_SECRET_LEN;
        if (os_get_random(out, outlen)) {
            wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
                    "data");
            tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                    TLS_ALERT_INTERNAL_ERROR);
            os_free(out);
            return -1;
        }
    }

    res = tlsv1_server_derive_keys(conn, out, outlen);

    /* Clear the pre-master secret since it is not needed anymore */
    os_memset(out, 0, outbuflen);
    os_free(out);

    if (res) {
        wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }

    return 0;
}