int tls_get_peer_cert(struct tls *ctx, struct tls_cert **cert_p, const char *fingerprint_algo) { SSL *conn = ctx->ssl_conn; X509 *peer; int res; *cert_p = NULL; if (!conn) { tls_set_errorx(ctx, "not connected"); return -1; } peer = SSL_get_peer_certificate(conn); if (!peer) { tls_set_errorx(ctx, "peer does not have cert"); return TLS_NO_CERT; } res = tls_parse_cert(ctx, cert_p, fingerprint_algo, peer); if (res == 0) check_verify_error(ctx, *cert_p); return res; }
static int tls_process_certificate(struct tlsv1_server *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); 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 Certificate 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 Certificate 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; } if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { if (conn->verify_peer) { wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " "Certificate"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } return tls_process_client_key_exchange(conn, ct, in_data, in_len); } if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected Certificate/" "ClientKeyExchange)", type); tlsv1_server_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); tlsv1_server_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)); tlsv1_server_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"); tlsv1_server_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)); tlsv1_server_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->client_rsa_key); if (tls_parse_cert(pos, cert_len, &conn->client_rsa_key)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "the certificate"); tlsv1_server_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"); tlsv1_server_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 (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; } tlsv1_server_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 = CLIENT_KEY_EXCHANGE; return 0; }