Сообщение об ошибке
asn1: structure error: tags don't match
Полное сообщение дополняется ожидаемым и найденным тегами и контекстом поля, например «tags don't match (16 vs {class:0 tag:2 ...}) ... AlgorithmIdentifier @2». Обрезанные входные данные дают родственную ошибку «asn1: syntax error: data truncated». В текущих версиях Go это сообщение выдают парсеры открытых ключей и PKCS#8; x509.ParseCertificate сообщает о тех же ошибках как «x509: malformed certificate».
Go encoding/asn1 — surfaced through crypto/x509 parsers
Что это означает
DER-декодер Go обнаружил не тот тег ASN.1, которого требует целевая структура: вы разбираете более-менее корректный DER в неподходящую структуру Go или разбираете то, что вообще не DER. Числа в сообщении — теги ASN.1 (16 = SEQUENCE, 2 = INTEGER, 13 в PEM-файле = дефис, с которого он начинается), и по ним обычно можно точно определить, что с чем перепутано.
Почему это происходит
Байты PEM переданы DER-парсеру
частоParsePKIXPublicKey, ParsePKCS8PrivateKey и подобные функции принимают двоичный DER. Самая частая причина ошибки — передать им текст PEM (дефисы и base64), не вызвав сначала pem.Decode. (ParseCertificate тоже отвергает текст PEM, с ошибкой «x509: malformed certificate».)
Не тот парсер для контейнера ключа
частоЗакрытый ключ или целый сертификат передан в ParsePKIXPublicKey. У каждого контейнера своя структура, и проверка тегов ловит подмену на первом же поле, где они расходятся. Если перепутаны парсеры закрытых ключей, сообщение полезнее: ParseECPrivateKey на байтах PKCS#8 выдаёт «x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)», и наоборот.
Вовсе не сертификат и не ключ
иногда64-байтовая подпись в формате raw, JWT или служебные байты протокола, разобранные как ASN.1. Если входные данные начинаются не с 0x30 (SEQUENCE), их не примет ни один парсер семейства X.509.
Как исправить
- 1.
Всегда сначала вызывайте pem.Decode
Извлеките блок DER (и проверьте метку), прежде чем вызывать какой-либо парсер.
go block, _ := pem.Decode(pemBytes) if block == nil { return fmt.Errorf("input is not PEM") } cert, err := x509.ParseCertificate(block.Bytes) // block.Type == "CERTIFICATE" - 2.
Пробуйте парсеры контейнеров по порядку
Если контейнер закрытого ключа неизвестен, пробуйте PKCS#8, затем SEC1, затем PKCS#1 — стандартный порядок разбора для ключей из разных источников.
go if k, err := x509.ParsePKCS8PrivateKey(der); err == nil { return k, nil } if k, err := x509.ParseECPrivateKey(der); err == nil { return k, nil } if k, err := x509.ParsePKCS1PrivateKey(der); err == nil { return k, nil } return nil, errors.New("unrecognized private key format") - 3.
Посмотрите на первые байты
Одна строка hexdump показывает, DER ли у вас вообще, а openssl asn1parse выводит структуру, которую можно сопоставить с выбранным парсером.
bash head -c 16 key.der | xxd # 30 81/82 ... → SEQUENCE, plausibly DER openssl asn1parse -inform der -in key.der | head -3