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; }
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; }