{"record":{"id":"52f01f61d08c4582","repo":"slackhq/nebula","slug":"pkcs11-module-gave-us-a-nil-cka-public-key-info-a","errorCode":null,"errorMessage":"pkcs11 module gave us a nil CKA_PUBLIC_KEY_INFO, and looking up the public key also failed: %w","messagePattern":"pkcs11 module gave us a nil CKA_PUBLIC_KEY_INFO, and looking up the public key also failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkclient/pkclient_cgo.go","lineNumber":213,"sourceCode":"\tif tmpKey == nil || len(tmpKey) == 0 {\n\t\treturn nil, fmt.Errorf(\"got an empty secret key\")\n\t}\n\tsecret := make([]byte, NoiseKeySize)\n\tcopy(secret[:], tmpKey[:NoiseKeySize])\n\treturn secret, nil\n}\n\nfunc (c *PKClient) GetPubKey() ([]byte, error) {\n\td, err := c.privKeyObj.Attribute(pkcs11.CKA_PUBLIC_KEY_INFO)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif d != nil && len(d) > 0 {\n\t\treturn formatPubkeyFromPublicKeyInfoAttr(d)\n\t}\n\tc.pubKeyObj, err = c.findDeriveKey(c.id, c.label, false)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"pkcs11 module gave us a nil CKA_PUBLIC_KEY_INFO, and looking up the public key also failed: %w\", err)\n\t}\n\td, err = c.pubKeyObj.Attribute(pkcs11.CKA_EC_POINT)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"pkcs11 module gave us a nil CKA_PUBLIC_KEY_INFO, and reading CKA_EC_POINT also failed: %w\", err)\n\t}\n\tif d == nil || len(d) < 1 {\n\t\treturn nil, fmt.Errorf(\"pkcs11 module gave us a nil or empty CKA_EC_POINT\")\n\t}\n\tswitch len(d) {\n\tcase 65: //length of 0x04 + len(X) + len(Y)\n\t\treturn d, nil\n\tcase 67: //as above, DER-encoded IIRC?\n\t\treturn d[2:], nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown public key length: %d\", len(d))\n\t}\n}\n","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/pkclient/pkclient_cgo.go#L195-L231","documentation":"GetPubKey prefers the CKA_PUBLIC_KEY_INFO attribute of the client's key object to reconstruct the public key. When that attribute is nil, it falls back to locating the public key object via findDeriveKey and wrapping that failure with this error, indicating both paths to obtain the public key failed.","triggerScenarios":"Calling GetPubKey (used by ca and signCert) on a token whose private key has no CKA_PUBLIC_KEY_INFO attribute AND no matching public key object can be found by id/label.","commonSituations":"Minimal HSM provisioning that only stored the private key without the public key object; vendor module that doesn't expose CKA_PUBLIC_KEY_INFO; id/label mismatch preventing the public key lookup; pkcs11-backed certificates where the public half was never stored.","solutions":["Store/enable CKA_PUBLIC_KEY_INFO on the key object (or re-import with it) so the primary path works.","Ensure a matching public key object with the same CKA_ID/CKA_LABEL exists on the token.","Check findDeriveKey's search template attributes (CKA_CLASS=CKO_PUBLIC_KEY, CKA_DERIVE) match how the key was provisioned.","Regenerate the keypair on the HSM with full public object attributes."],"exampleFix":"// before: provision private key only\npkcs11-tool --keypairgen --id 01 --label nebula --key-type EC:prime256v1 --usage-derive\n// after: also verify public object exists\npkcs11-tool --list-objects --type pubkey --id 01","handlingStrategy":"validation","validationCode":"// Before GetPubKey: confirm both key objects exist on the token\nout, _ := exec.Command(\"pkcs11-tool\", \"--module\", hsmPath, \"--slot\", slot,\n  \"--login\", \"--pin\", pin, \"--list-objects\").Output()\nneedPriv := strings.Contains(string(out), \"Private Key\")\nneedPub := strings.Contains(string(out), \"Public Key\")\nif !needPriv || !needPub { return errors.New(\"token missing private or public key object\") }","typeGuard":null,"tryCatchPattern":"pub, err := client.GetPubKey()\nif err != nil {\n  if strings.Contains(err.Error(), \"nil CKA_PUBLIC_KEY_INFO\") {\n    return fmt.Errorf(\"HSM not fully provisioned (missing CKA_PUBLIC_KEY_INFO/public object): %w\", err)\n  }\n  return err\n}","preventionTips":["Provision keypairs with CKA_PUBLIC_KEY_INFO or a stored public key object.","Use standard tooling (nebula-cert pkcs11 generates complete keypairs) instead of manual imports.","Audit tokens with pkcs11-tool --list-objects as part of deployment health checks.","Keep CKA_ID/CKA_LABEL consistent between private and public objects."],"tags":["pkcs11","hsm","public-key","attribute-missing"],"backgroundTag":"hsm-public-key-info-missing","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"}