Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
			 const u8 *data, size_t data_len,
			 const u8 *pos, size_t len, u8 *alert)
{
	u8 *buf;
	const u8 *end = pos + len;
	const u8 *decrypted;
	u16 slen;
	size_t buflen;

	if (end - pos < 2) {
		*alert = TLS_ALERT_DECODE_ERROR;
		return -1;
	}
	slen = WPA_GET_BE16(pos);
	pos += 2;
	if (end - pos < slen) {
		*alert = TLS_ALERT_DECODE_ERROR;
		return -1;
	}
	if (end - pos > slen) {
		wpa_hexdump(MSG_MSGDUMP, "Additional data after Signature",
			    pos + slen, end - pos - slen);
		end = pos + slen;
	}

	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
	if (pk == NULL) {
		wpa_printf(MSG_DEBUG, "TLSv1: No public key to verify signature");
		*alert = TLS_ALERT_INTERNAL_ERROR;
		return -1;
	}

	buflen = end - pos;
	buf = os_malloc(end - pos);
	if (buf == NULL) {
		*alert = TLS_ALERT_INTERNAL_ERROR;
		return -1;
	}
	if (crypto_public_key_decrypt_pkcs1(pk, pos, end - pos, buf, &buflen) <
	    0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
		os_free(buf);
		*alert = TLS_ALERT_DECRYPT_ERROR;
		return -1;
	}
	decrypted = buf;

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

#ifdef CONFIG_TLSV12
	if (tls_version >= TLS_VERSION_1_2) {
		/*
		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
		 *
		 * DigestInfo ::= SEQUENCE {
		 *   digestAlgorithm DigestAlgorithm,
		 *   digest OCTET STRING
		 * }
		 *
		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
		 *
		 * DER encoded DigestInfo for SHA256 per RFC 3447:
		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
		 * H
		 */
		if (buflen >= 19 + 32 &&
		    os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
			      "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
		{
			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-256");
			decrypted = buf + 19;
			buflen -= 19;
		} else if (buflen >= 19 + 48 &&
		    os_memcmp(buf, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01"
			      "\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19) == 0)
		{
			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-384");
			decrypted = buf + 19;
			buflen -= 19;
		} else if (buflen >= 19 + 64 &&
		    os_memcmp(buf, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01"
			      "\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19) == 0)
		{
			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-512");
			decrypted = buf + 19;
			buflen -= 19;

		} else {
			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
			os_free(buf);
			*alert = TLS_ALERT_DECRYPT_ERROR;
			return -1;
		}
	}
#endif /* CONFIG_TLSV12 */

	if (buflen != data_len ||
	    os_memcmp_const(decrypted, data, data_len) != 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
		os_free(buf);
		*alert = TLS_ALERT_DECRYPT_ERROR;
		return -1;
	}

	os_free(buf);

	return 0;
}