Mensagem de erro
asn1: structure error: tags don't match
A mensagem completa acrescenta as tags esperada e encontrada, além do contexto do campo, por exemplo “tags don't match (16 vs {class:0 tag:2 ...}) ... AlgorithmIdentifier @2”. Entradas truncadas produzem o erro da mesma família “asn1: syntax error: data truncated”. No Go atual, a mensagem vem dos parsers de chave pública e de PKCS#8; o x509.ParseCertificate relata os mesmos erros como “x509: malformed certificate”.
Go encoding/asn1 — surfaced through crypto/x509 parsers
O que significa
O decodificador DER do Go encontrou uma tag ASN.1 diferente da que a estrutura de destino exige — você está decodificando um DER mais ou menos válido na estrutura Go errada, ou decodificando algo que nem é DER. Os números na mensagem são tags ASN.1 (16 = SEQUENCE, 2 = INTEGER, 13 em um arquivo PEM = o hífen com que ele começa), que normalmente identificam a confusão com precisão.
Por que acontece
Bytes PEM passados a um parser DER
comumParsePKIXPublicKey, ParsePKCS8PrivateKey e funções parecidas recebem DER binário. Entregar a elas texto PEM (hífens e base64) sem chamar pem.Decode antes é, de longe, o gatilho mais comum. (ParseCertificate também rejeita texto PEM, com “x509: malformed certificate”.)
Parser errado para o contêiner da chave
comumUma chave privada ou um certificado inteiro passado para ParsePKIXPublicKey — cada contêiner tem uma estrutura própria, e a verificação de tags detecta a troca no primeiro campo divergente. Trocar os parsers de chave privada gera uma mensagem mais útil: ParseECPrivateKey com bytes PKCS#8 diz “x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)”, e vice-versa.
Não é certificado nem chave
ocasionalUma assinatura raw de 64 bytes, um JWT ou bytes de enquadramento de protocolo interpretados como ASN.1. Se a entrada começa com qualquer coisa diferente de 0x30 (SEQUENCE), nenhum parser da família X.509 vai aceitá-la.
Como corrigir
- 1.
Sempre chamar pem.Decode primeiro
Extraia o bloco DER (e confira o rótulo) antes de chamar qualquer parser.
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.
Testar os parsers de contêiner em ordem
Quando o contêiner da chave privada é desconhecido, tente PKCS#8, depois SEC1, depois PKCS#1 — a triagem padrão para chaves de origens diversas.
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.
Examinar os primeiros bytes
Uma linha de hexdump mostra se o que você tem é mesmo DER, e o openssl asn1parse exibe a estrutura para comparar com o parser escolhido.
bash head -c 16 key.der | xxd # 30 81/82 ... → SEQUENCE, plausibly DER openssl asn1parse -inform der -in key.der | head -3