コード例 #1
0
ファイル: tlsv1_server_read.c プロジェクト: 09sea98/rtl8188eu
int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
				   const u8 *buf, size_t *len)
{
	if (ct == TLS_CONTENT_TYPE_ALERT) {
		if (*len < 2) {
			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
			tlsv1_server_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;
	}

	switch (conn->state) {
	case CLIENT_HELLO:
		if (tls_process_client_hello(conn, ct, buf, len))
			return -1;
		break;
	case CLIENT_CERTIFICATE:
		if (tls_process_certificate(conn, ct, buf, len))
			return -1;
		break;
	case CLIENT_KEY_EXCHANGE:
		if (tls_process_client_key_exchange(conn, ct, buf, len))
			return -1;
		break;
	case CERTIFICATE_VERIFY:
		if (tls_process_certificate_verify(conn, ct, buf, len))
			return -1;
		break;
	case CHANGE_CIPHER_SPEC:
		if (tls_process_change_cipher_spec(conn, ct, buf, len))
			return -1;
		break;
	case CLIENT_FINISHED:
		if (tls_process_client_finished(conn, ct, buf, 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;
}
コード例 #2
0
static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
        const u8 *in_data, size_t *in_len) {
    const u8 *pos, *end;
    size_t left, len;
    u8 type;
    size_t hlen, buflen;
    u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;

    enum {
        SIGN_ALG_RSA, SIGN_ALG_DSA
    } alg = SIGN_ALG_RSA;
    u16 slen;

    if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
        if (conn->verify_peer) {
            wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
                    "CertificateVerify");
            tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                    TLS_ALERT_UNEXPECTED_MESSAGE);
            return -1;
        }

        return tls_process_change_cipher_spec(conn, ct, in_data,
                in_len);
    }

    if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
        wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
                "received content type 0x%x", ct);
        tlsv1_server_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 CertificateVerify "
                "message (len=%lu)", (unsigned long) left);
        tlsv1_server_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 CertificateVerify "
                "message length (len=%lu != left=%lu)",
                (unsigned long) len, (unsigned long) left);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECODE_ERROR);
        return -1;
    }

    end = pos + len;

    if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
        wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
                "message %d (expected CertificateVerify)", type);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_UNEXPECTED_MESSAGE);
        return -1;
    }

    wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");

    /*
     * struct {
     *   Signature signature;
     * } CertificateVerify;
     */

    hpos = hash;

    if (alg == SIGN_ALG_RSA) {
        hlen = MD5_MAC_LEN;
        if (conn->verify.md5_cert == NULL ||
                crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
            tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                    TLS_ALERT_INTERNAL_ERROR);
            conn->verify.md5_cert = NULL;
            crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
            conn->verify.sha1_cert = NULL;
            return -1;
        }
        hpos += MD5_MAC_LEN;
    } else
        crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);

    conn->verify.md5_cert = NULL;
    hlen = SHA1_MAC_LEN;
    if (conn->verify.sha1_cert == NULL ||
            crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
        conn->verify.sha1_cert = NULL;
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }
    conn->verify.sha1_cert = NULL;

    if (alg == SIGN_ALG_RSA)
        hlen += MD5_MAC_LEN;

    wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);

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

    wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
    if (conn->client_rsa_key == NULL) {
        wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
                "signature");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }

    buflen = end - pos;
    buf = os_malloc(end - pos);
    if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
            pos, end - pos, buf, &buflen) < 0) {
        wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
        os_free(buf);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECRYPT_ERROR);
        return -1;
    }

    wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
            buf, buflen);

    if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
        wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
                "CertificateVerify - did not match with calculated "
                "hash");
        os_free(buf);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_DECRYPT_ERROR);
        return -1;
    }

    os_free(buf);

    *in_len = end - in_data;

    conn->state = CHANGE_CIPHER_SPEC;

    return 0;
}