slackhq/nebula · error

failed to find private key for deriving: %w

Error message

failed to find private key for deriving: %w

What it means

pkclient.New() opens a PKCS#11 session, logs in, and then calls findDeriveKey to locate the HSM object holding the private key used for ECDH derivation. If no matching private key object exists in the token for the given id/label, the client is logged out and closed and this error wraps the underlying lookup failure.

Source

Thrown at pkclient/pkclient_cgo.go:78

		return nil, fmt.Errorf("failed to open session on slot %d", slotId)
	}

	if len(pin) != 0 {
		err = client.session.Login(pin)
		if err != nil {
			// ignore "already logged in"
			if !errors.Is(err, pkcs11.Error(256)) {
				_ = client.session.Close()
				return nil, fmt.Errorf("unable to login. error: %w", err)
			}
		}
	}

	// Make sure the hsm has a private key for deriving
	client.privKeyObj, err = client.findDeriveKey(client.id, client.label, true)
	if err != nil {
		_ = client.Close() //log out, close session, destroy module
		return nil, fmt.Errorf("failed to find private key for deriving: %w", err)
	}

	return client, nil
}

// Close cleans up properly and logs out
func (c *PKClient) Close() error {
	var err error = nil
	if c.session != nil {
		_ = c.session.Logout() //if logout fails, we still want to close
		err = c.session.Close()
	}

	c.module.Destroy()
	return err
}

// Try to find a suitable key on the hsm for key derivation

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Verify the id/label passed to New() matches the private key object on the token (use pkcs11-tool --list-objects --type privkey).
  2. Re-generate or re-import the key with CKA_DERIVE=CK_TRUE set (required for ECDH).
  3. Confirm the correct slot was targeted — the key may live in another slot on the same module.
  4. Check that the HSM partition is initialized and objects were not wiped by re-initialization.

Example fix

// before
client, err := pkclient.New("/usr/lib/softhsm2.so", 0, pin, wrongID, "nebula")
// after
client, err := pkclient.New("/usr/lib/softhsm2.so", 0, pin, certID, "nebula") // id/label matching the HSM key object
Defensive patterns

Strategy: validation

Validate before calling

// Before New(): verify a derivable private key exists on the token
out, err := exec.Command("pkcs11-tool", "--module", hsmPath,
  "--slot", slot, "--login", "--pin", pin,
  "--list-objects", "--type", "privkey", "--id", id).Output()
if err != nil || !strings.Contains(string(out), "Private Key") {
  return fmt.Errorf("no derivable private key for id %s on token", id)
}

Type guard

func hasPrivateKeyAndDeriveAttr(attrs []pkcs11.Attribute) bool {
  for _, a := range attrs {
    if a.Type == pkcs11.CKA_PRIVATE && len(a.Value) == 1 && a.Value[0] == 1 &&
       a.Type == pkcs11.CKA_DERIVE { return true }
  }
  return false
}

Try / catch

client, err := pkclient.New(hsmPath, slotId, pin, id, label)
if err != nil {
  var target *pkclient.Error
  if errors.As(err, &target) && strings.Contains(err.Error(), "failed to find private key") {
    return fmt.Errorf("HSM key for id=%q label=%q missing or not derivable; check provisioning: %w", id, label, err)
  }
  return err
}

Prevention

When it happens

Trigger: Calling pkclient.New(hsmPath, slotId, pin, id, label) when the token contains no private key matching the supplied CKA_ID and/or CKA_LABEL, or findDeriveKey fails (e.g. search template matches nothing, object is not CKA_DERIVE=true).

Common situations: Wrong id/label configured in the nebula cert vs what's stored on the HSM; key was generated without the DERIVE attribute; key exists in a different slot; provisioning script never imported the private key; smartcard/HSM was re-initialized wiping objects.

Related errors


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