diff --git a/ecdsa.go b/ecdsa.go index c094232..b6f414a 100644 --- a/ecdsa.go +++ b/ecdsa.go @@ -290,6 +290,50 @@ func (c *Context) GenerateECDSAKeyPairWithAttributes(public, private AttributeSe return k, err } +// Perform CKM_ECDH1_DERIVE function with the given public key +func (c *Context) ECDH1Derive(pk Signer, pubkey *ecdsa.PublicKey) ([]byte, error) { + ecpk, ok := pk.(*pkcs11PrivateKeyECDSA) + if !ok { + return nil, errors.New("Private key is not ECDSA") + } + + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, false), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_SECRET_KEY), + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_GENERIC_SECRET), + pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, false), + pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, true), + pkcs11.NewAttribute(pkcs11.CKA_ENCRYPT, true), + pkcs11.NewAttribute(pkcs11.CKA_DECRYPT, true), + pkcs11.NewAttribute(pkcs11.CKA_WRAP, true), + pkcs11.NewAttribute(pkcs11.CKA_UNWRAP, true), + pkcs11.NewAttribute(pkcs11.CKA_VALUE_LEN, (pubkey.Curve.Params().BitSize+7)/8), + } + params := pkcs11.ECDH1DeriveParams{KDF: pkcs11.CKD_NULL, PublicKeyData: elliptic.Marshal(pubkey.Curve, pubkey.X, pubkey.Y)} + mech := []*pkcs11.Mechanism{ + pkcs11.NewMechanism(pkcs11.CKM_ECDH1_DERIVE, ¶ms), + } + + var buf []byte + err := c.withSession(func(session *pkcs11Session) error { + handle, err := session.ctx.DeriveKey(session.handle, mech, ecpk.handle, template) + if err != nil { + return err + } + + template = []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_VALUE, nil), + } + attr, err := session.ctx.GetAttributeValue(session.handle, handle, template) + if err != nil { + return err + } + buf = attr[0].Value + return nil + }) + return buf, err +} + // Sign signs a message using an ECDSA key. // // This completes the implemention of crypto.Signer for pkcs11PrivateKeyECDSA.