slackhq/nebula · error

unknown public key type: %T

Error message

unknown public key type: %T

What it means

formatPubkeyFromPublicKeyInfoAttr only supports ECDSA public keys from the HSM's certificate/key object; any other key type (RSA, Ed25519, etc.) hits the default branch and fails with this error naming the Go type via %T. The library throws it because it derives the Noise pubkey via ECDH, which requires an EC key.

Source

Thrown at pkclient/pkclient.go:70

func ecKeyToArray(key *ecdsa.PublicKey) []byte {
	x := make([]byte, 32)
	y := make([]byte, 32)
	key.X.FillBytes(x)
	key.Y.FillBytes(y)
	return append([]byte{0x04}, append(x, y...)...)
}

func formatPubkeyFromPublicKeyInfoAttr(d []byte) ([]byte, error) {
	e, err := x509.ParsePKIXPublicKey(d)
	if err != nil {
		return nil, err
	}
	switch t := e.(type) {
	case *ecdsa.PublicKey:
		return ecKeyToArray(e.(*ecdsa.PublicKey)), nil
	default:
		return nil, fmt.Errorf("unknown public key type: %T", t)
	}
}

func (c *PKClient) Test() error {
	pub, err := c.GetPubKey()
	if err != nil {
		return fmt.Errorf("failed to get public key: %w", err)
	}
	out, err := c.DeriveNoise(pub) //do an ECDH with ourselves as a quick test
	if err != nil {
		return err
	}
	if len(out) != NoiseKeySize {
		return fmt.Errorf("got a key of %d bytes, expected %d", len(out), NoiseKeySize)
	}
	return nil
}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Provision the HSM key as an EC P-256 (prime256v1) key instead of RSA
  2. Verify the object id/label in config points at the EC key, not another object
  3. Check the object's attributes (CKA_KEY_TYPE should be CKK_EC)
  4. List slot objects with pkcs11-tool or similar to confirm key type
  5. Re-issue the certificate for the existing EC key if the cert is RSA-signed

Example fix

// before (HSM provisioning)
pkcs11-tool --keypairgen --key-type rsa:2048
// after
pkcs11-tool --keypairgen --key-type EC:prime256v1 --usage-derive
Defensive patterns

Strategy: validation

Validate before calling

// verify key type before New()/Test()
info, _ := session.GetAttributeValue(privKeyObj, []*pkcs11.Attribute{
    pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, false),
})
if binary.BigEndian.Uint16(info[0].Value) != 0x0017 { // CKK_EC
    return errors.New("HSM key must be EC (CKK_EC) for noise derivation")
}

Type guard

func isECKey(pub interface{}) (*ecdsa.PublicKey, bool) {
    k, ok := pub.(*ecdsa.PublicKey)
    return k, ok
}

Try / catch

_, err := client.GetPubKey()
if err != nil {
    if strings.Contains(err.Error(), "unknown public key type") {
        return fmt.Errorf("re-provision HSM key as EC P-256: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: GetPubKey() calls formatPubkeyFromPublicKeyInfoAttr with a pkcs11 key attribute whose decoded Go type is not *ecdsa.PublicKey — e.g. the HSM slot holds an RSA key with the configured id/label.

Common situations: HSM provisioned with an RSA certificate/key instead of EC P-256; multiple objects sharing the same id/label with the wrong one selected first; older HSM provisioning scripts using RSA.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/c519a751cea5ab0e. Report an issue: GitHub.