← На главную

Из-за строк ASN.1 Go отвергает сертификаты, принятые OpenSSL

06.06.2026 13:52 · hackernews

Два X.509 сертификата — корневой CA и подписанный им листовой — выглядят одинаково, но один не проходит проверку в Go. openssl verify -CAfile ca.crt.pem leaf.crt.pem работает с обоими, а Go-программа с x509.Verify() выдаёт panic: x509: certificate signed by unknown authority. Всё из-за различия в двух байтах.

Дифф в DER-представлении показывает, что в сертификате, который не верифицируется, на месте типа строки стоит 0x13 (PrintableString), а в «рабочем» — 0x0c (UTF8String). Оба байта находятся перед строкой Root CA — в полях Subject и Issuer (у самоподписанного корневого сертификата они совпадают). openssl asn1parse подтверждает: в одном случае написано PRINTABLESTRING, в другом — UTF8STRING.

Логика CertPool в Go сравнивает RawSubject и RawIssuer как сырые байты. Листовой сертификат содержит Issuer в кодировке UTF8String. Когда Go ищет среди корневых сертификатов того, чей Subject совпадает с Issuer листа, он не находит совпадения, потому что у «сломанного» CA-сертификата Subject записан как PrintableString — то есть другие байты. Хотя семантически строки одинаковы, Go не делает скидок на тип ASN.1 строки.

OpenSSL же при проверке считает PrintableString и UTF8String эквивалентными, поэтому верификация проходит. Это известная особенность Go — fail-closed поведение. В реальности такое случается редко, если и CA, и leaf генерируются одним инструментом. Но если инструментарий меняется, а CA живёт долго (в примере — до 2126 года), новый лист может не пройти проверку старым кодом. Автор иронизирует, что если читатель живёт в 2126-м, то разочарован, что человечество всё ещё использует openssl.

Читать оригинал →