Error message
Failed to read asymmetric key
Node.js crypto — e.g. code ERR_OSSL_ASN1_WRONG_TAG
What it means
createPublicKey()/createPrivateKey() got DER (or mis-labeled PEM) whose ASN.1 structure does not match the type you declared — for example type: "spki" while the bytes are actually a SEC1 EC private key. OpenSSL parsed far enough to know the tags are wrong, then stopped. The accompanying code (ERR_OSSL_ASN1_WRONG_TAG and relatives) names the ASN.1-level mismatch. Unlike the DECODER-routines "unsupported" error, which means nothing parseable was found at all, this one means the bytes were recognizably the wrong structure for the declared type.
Why it happens
Declared type does not match the bytes
commonThe DER world has several containers: SPKI for public keys, PKCS#8 for private keys, SEC1 for legacy EC private keys, PKCS#1 for legacy RSA. Declaring type: "pkcs8" for SEC1 bytes (or spki for a certificate) trips the tag check immediately.
Base64 not decoded, or double-decoded
commonPassing base64 text with format: "der" (so OpenSSL parses ASCII as ASN.1), or Buffer.from(pem, "base64") on a full PEM including its header lines, both produce byte soup with wrong tags.
A raw EC point instead of a key structure
occasional65 uncompressed-point bytes (0x04‖X‖Y) are not DER — they are the payload that lives inside an SPKI. Feeding them directly to createPublicKey fails; they must be wrapped or imported via JWK/WebCrypto raw import.
How to fix it
- 1.
Identify the structure, then declare it truthfully
asn1parse prints the outer structure. An SPKI starts with a SEQUENCE containing an AlgorithmIdentifier; PKCS#8 starts with a version INTEGER 0; SEC1 EC keys with INTEGER 1.
bash openssl asn1parse -inform der -in key.der | head -5 - 2.
Match Node options to the container
Once you know the container, the mapping is mechanical.
js // SPKI public key createPublicKey({ key: der, format: "der", type: "spki" }); // PKCS#8 private key createPrivateKey({ key: der, format: "der", type: "pkcs8" }); // SEC1 (BEGIN EC PRIVATE KEY) private key createPrivateKey({ key: der, format: "der", type: "sec1" }); - 3.
Convert legacy containers once, at the edge
Standardize on PKCS#8/SPKI in storage so application code never guesses.
bash openssl pkey -in legacy-ec.pem -out key-pkcs8.pem # any private → PKCS#8 openssl pkey -in key-pkcs8.pem -pubout -out pub-spki.pem # derive SPKI public