{"record":{"id":"03c20ef6c2acbd35","repo":"slackhq/nebula","slug":"key-was-not-32-bytes-is-invalid-ecdsa-p256-privat-03c20e","errorCode":null,"errorMessage":"key was not 32 bytes, is invalid ECDSA P256 private key","messagePattern":"key was not 32 bytes, is invalid ECDSA P256 private key","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/pem.go","lineNumber":271,"sourceCode":"\tk, r := pem.Decode(b)\n\tif k == nil {\n\t\treturn nil, r, 0, fmt.Errorf(\"input did not contain a valid PEM encoded block\")\n\t}\n\tvar curve Curve\n\tswitch k.Type {\n\tcase EncryptedEd25519PrivateKeyBanner:\n\t\treturn nil, nil, Curve_CURVE25519, ErrPrivateKeyEncrypted\n\tcase EncryptedECDSAP256PrivateKeyBanner:\n\t\treturn nil, nil, Curve_P256, ErrPrivateKeyEncrypted\n\tcase Ed25519PrivateKeyBanner:\n\t\tcurve = Curve_CURVE25519\n\t\tif len(k.Bytes) != ed25519.PrivateKeySize {\n\t\t\treturn nil, r, 0, fmt.Errorf(\"key was not %d bytes, is invalid Ed25519 private key\", ed25519.PrivateKeySize)\n\t\t}\n\tcase ECDSAP256PrivateKeyBanner:\n\t\tcurve = Curve_P256\n\t\tif len(k.Bytes) != 32 {\n\t\t\treturn nil, r, 0, fmt.Errorf(\"key was not 32 bytes, is invalid ECDSA P256 private key\")\n\t\t}\n\tdefault:\n\t\treturn nil, r, 0, fmt.Errorf(\"bytes did not contain a proper Ed25519/ECDSA private key banner\")\n\t}\n\treturn k.Bytes, r, curve, nil\n}\n","sourceCodeStart":253,"sourceCodeEnd":278,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/pem.go#L253-L278","documentation":"The PEM block was recognized as an ECDSA P256 signing private key (ECDSAP256PrivateKeyBanner), but the decoded bytes are not exactly 32 bytes (the P-256 scalar size). The key body is truncated, padded, or malformed even though the banner is correct, so the library rejects it.","triggerScenarios":"Call UnmarshalSigningPrivateKeyFromPEM with a block of type ECDSAP256PrivateKeyBanner whose k.Bytes length != 32 — e.g. DER-wrapped key material, a truncated scalar, or extra bytes appended.","commonSituations":"Exporting a P256 key from another tool in SEC1/PKCS#8 DER form (longer than 32 bytes) and pasting it under the nebula banner, or copy/paste truncation of the base64 body.","solutions":["Emit exactly the 32-byte raw scalar under the ECDSA P256 banner (use nebula-cert to generate)","Strip DER/ASN.1 wrapping: extract the raw 32-byte private scalar before PEM-encoding","Verify len(decoded bytes) == 32 before calling the API"],"exampleFix":"// before: DER-encoded key pasted raw\nblock.Bytes = derBytes // e.g. 121 bytes\n// after\nblock.Bytes = rawScalar // exactly 32 bytes (d parameter)","handlingStrategy":"validation","validationCode":"blk, _ := pem.Decode(data)\nif blk != nil && blk.Type == \"NEBULA ECDSA P256 SIGNING PRIVATE KEY\" && len(blk.Bytes) != 32 {\n    return fmt.Errorf(\"P256 signing key must be a raw 32-byte scalar, got %d bytes (DER-wrapped?)\", len(blk.Bytes))\n}","typeGuard":"func isValidP256SigningKey(b []byte) bool {\n    blk, _ := pem.Decode(b)\n    return blk != nil && blk.Type == \"NEBULA ECDSA P256 SIGNING PRIVATE KEY\" && len(blk.Bytes) == 32\n}","tryCatchPattern":"key, _, _, err := nebula.UnmarshalSigningPrivateKeyFromPEM(raw)\nif err != nil {\n    return fmt.Errorf(\"P256 signing key body must be exactly 32 bytes: %w\", err)\n}","preventionTips":["Do not paste openssl/PKCS#8 DER key material under a nebula banner","Extract the raw scalar (d) before PEM-encoding P256 keys","Prefer nebula-cert generated keys over converted external keys"],"tags":["pem","ecdsa","p256","signing-key","key-length"],"backgroundTag":"invalid-pem-key-length","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}