From e0addbd3e8028c076574515a0942c5bd7ccdf3bc Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Tue, 13 Aug 2019 18:10:25 +0100 Subject: [PATCH 01/21] Implement FindKeyPairs function --- keys.go | 255 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 189 insertions(+), 66 deletions(-) diff --git a/keys.go b/keys.go index 9320696..56e93dd 100644 --- a/keys.go +++ b/keys.go @@ -30,14 +30,9 @@ import ( // Find a key object. For asymmetric keys this only finds one half so // callers will call it twice. Returns nil if the key does not exist on the token. -func findKey(session *pkcs11Session, id []byte, label []byte, keyclass *uint, keytype *uint) (obj *pkcs11.ObjectHandle, err error) { - var handles []pkcs11.ObjectHandle +func findKeys(session *pkcs11Session, id []byte, label []byte, keyclass *uint, keytype *uint) (handles []pkcs11.ObjectHandle, err error) { var template []*pkcs11.Attribute - if id == nil && label == nil { - return nil, errors.New("id and label cannot both be nil") - } - if keyclass != nil { template = append(template, pkcs11.NewAttribute(pkcs11.CKA_CLASS, *keyclass)) } @@ -62,28 +57,104 @@ func findKey(session *pkcs11Session, id []byte, label []byte, keyclass *uint, ke if handles, _, err = session.ctx.FindObjects(session.handle, 1); err != nil { return nil, err } + + return handles, nil +} + +// Find a key object. For asymmetric keys this only finds one half so +// callers will call it twice. Returns nil if the key does not exist on the token. +func findKey(session *pkcs11Session, id []byte, label []byte, keyclass *uint, keytype *uint) (obj *pkcs11.ObjectHandle, err error) { + handles, err := findKeys(session, id, label, keyclass, keytype) + if len(handles) == 0 { return nil, nil } return &handles[0], nil } +func (c *Context) makeKeyPair(session *pkcs11Session, id []byte, label []byte, privHandle *pkcs11.ObjectHandle) (signer Signer, err error) { + attributes := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, 0), + } + if attributes, err = session.ctx.GetAttributeValue(session.handle, *privHandle, attributes); err != nil { + return nil, err + } + keyType := bytesToUlong(attributes[0].Value) + + pubHandle, err := findKey(session, id, label, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType) + if err != nil { + return nil, err + } + if pubHandle == nil { + // We can't return a Signer if we don't have private and public key. Treat it as an error. + return nil, errors.New("could not find public key to match private key") + } + + var pub crypto.PublicKey + switch keyType { + case pkcs11.CKK_DSA: + if pub, err = exportDSAPublicKey(session, *pubHandle); err != nil { + return nil, err + } + return &pkcs11PrivateKeyDSA{ + pkcs11PrivateKey: pkcs11PrivateKey{ + pkcs11Object: pkcs11Object{ + handle: *privHandle, + context: c, + }, + pubKeyHandle: *pubHandle, + pubKey: pub, + }}, nil + + case pkcs11.CKK_RSA: + if pub, err = exportRSAPublicKey(session, *pubHandle); err != nil { + return nil, err + } + return &pkcs11PrivateKeyRSA{ + pkcs11PrivateKey: pkcs11PrivateKey{ + pkcs11Object: pkcs11Object{ + handle: *privHandle, + context: c, + }, + pubKeyHandle: *pubHandle, + pubKey: pub, + }}, nil + + case pkcs11.CKK_ECDSA: + if pub, err = exportECDSAPublicKey(session, *pubHandle); err != nil { + return nil, err + } + return &pkcs11PrivateKeyECDSA{ + pkcs11PrivateKey: pkcs11PrivateKey{ + pkcs11Object: pkcs11Object{ + handle: *privHandle, + context: c, + }, + pubKeyHandle: *pubHandle, + pubKey: pub, + }}, nil + + default: + return nil, errors.Errorf("unsupported key type: %X", keyType) + } +} + // FindKeyPair retrieves a previously created asymmetric key pair, or nil if it cannot be found. // // At least one of id and label must be specified. If the private key is found, but the public key is // not, an error is returned because we cannot implement crypto.Signer without the public key. func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { - if c.closed.Get() { return nil, errClosed } + if id == nil && label == nil { + return nil, errors.New("id and label cannot both be nil") + } + var k Signer err := c.withSession(func(session *pkcs11Session) error { - - var pub crypto.PublicKey - privHandle, err := findKey(session, id, label, uintPtr(pkcs11.CKO_PRIVATE_KEY), nil) if err != nil { return err @@ -93,73 +164,83 @@ func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { return nil } - attributes := []*pkcs11.Attribute{ - pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, 0), - } - if attributes, err = session.ctx.GetAttributeValue(session.handle, *privHandle, attributes); err != nil { + k, err = c.makeKeyPair(session, id, label, privHandle) + if err != nil { return err } - keyType := bytesToUlong(attributes[0].Value) - pubHandle, err := findKey(session, id, label, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType) + return nil + }) + return k, err +} + +// FindKeyPairs retrieves all matching asymmetric key pairs, or a nil slice if none can be found. +// +// At least one of id and label must be specified. +// If a private key is found, but the corresponding public key is not, the key is not returned because we cannot +// implement crypto.Signer without the public key. +func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { + if c.closed.Get() { + return nil, errClosed + } + + if id == nil && label == nil { + return nil, errors.New("id and label cannot both be nil") + } + + var keys []Signer + + err := c.withSession(func(session *pkcs11Session) error { + privHandles, err := findKeys(session, id, label, uintPtr(pkcs11.CKO_PRIVATE_KEY), nil) if err != nil { return err } - if pubHandle == nil { - // We can't return a Signer if we don't have private and public key. Treat it as an error. - return errors.New("could not find public key to match private key") - } - switch keyType { - case pkcs11.CKK_DSA: - if pub, err = exportDSAPublicKey(session, *pubHandle); err != nil { - return err + for _, privHandle := range(privHandles) { + k, err := c.makeKeyPair(session, id, label, &privHandle) + if err != nil { + continue } - k = &pkcs11PrivateKeyDSA{ - pkcs11PrivateKey: pkcs11PrivateKey{ - pkcs11Object: pkcs11Object{ - handle: *privHandle, - context: c, - }, - pubKeyHandle: *pubHandle, - pubKey: pub, - }} - - case pkcs11.CKK_RSA: - if pub, err = exportRSAPublicKey(session, *pubHandle); err != nil { - return err - } - k = &pkcs11PrivateKeyRSA{ - pkcs11PrivateKey: pkcs11PrivateKey{ - pkcs11Object: pkcs11Object{ - handle: *privHandle, - context: c, - }, - pubKeyHandle: *pubHandle, - pubKey: pub, - }} - - case pkcs11.CKK_ECDSA: - if pub, err = exportECDSAPublicKey(session, *pubHandle); err != nil { - return err - } - k = &pkcs11PrivateKeyECDSA{ - pkcs11PrivateKey: pkcs11PrivateKey{ - pkcs11Object: pkcs11Object{ - handle: *privHandle, - context: c, - }, - pubKeyHandle: *pubHandle, - pubKey: pub, - }} - - default: - return errors.Errorf("unsupported key type: %X", keyType) + + keys = append(keys, k) } return nil }) - return k, err + return keys, err +} + +// FindAllKeyPairs retrieves all existing asymmetric key pairs, or a nil slice if none can be found. +// +// If a private key is found, but the corresponding public key is not, the key is not returned because we cannot +// implement crypto.Signer without the public key. +func (c *Context) FindAllKeyPairs() ([]Signer, error) { + //if c.closed.Get() { + // return nil, errClosed + //} + // + //var keys []Signer + // + //err := c.withSession(func(session *pkcs11Session) error { + // privHandles, err := findKeys(session, nil, nil, uintPtr(pkcs11.CKO_PRIVATE_KEY), nil) + // if err != nil { + // return err + // } + // + // for _, privHandle := range(privHandles) { + // k, err := c.makeKeyPair(session, id, label, &privHandle) + // if err != nil { + // continue + // } + // + // keys = append(keys, k) + // } + // + // return nil + //}) + //return keys, err + + return nil, errors.Errorf("Not yet supported") } // Public returns the public half of a private key. @@ -175,11 +256,14 @@ func (k pkcs11PrivateKey) Public() crypto.PublicKey { // // Either (but not both) of id and label may be nil, in which case they are ignored. func (c *Context) FindKey(id []byte, label []byte) (*SecretKey, error) { - if c.closed.Get() { return nil, errClosed } + if id == nil && label == nil { + return nil, errors.New("id and label cannot both be nil") + } + var k *SecretKey err := c.withSession(func(session *pkcs11Session) error { @@ -211,4 +295,43 @@ func (c *Context) FindKey(id []byte, label []byte) (*SecretKey, error) { return k, err } +// FindKeys retrieves all matching symmetric keys, or a nil slice if none can be found. +// +// At least one of id and label must be specified. +func (c *Context) FindKeys(id []byte, label []byte) ([]*SecretKey, error) { + return nil, errors.Errorf("Not yet supported") +} + +// FindAllKeyPairs retrieves all existing symmetric keys, or a nil slice if none can be found. +func (c *Context) FindAllKeys() ([]*SecretKey, error) { + return nil, errors.Errorf("Not yet supported") +} + func uintPtr(i uint) *uint { return &i } + +// GetAttributes gets the values of the specified attributes on the given key +func (c *Context) GetAttributes(signer *crypto.Signer, attributes []AttributeType) (a AttributeSet, err error) { + if c.closed.Get() { + return nil, errClosed + } + + //if sig, ok := (*signer).(Signer); !ok { + // nil, return errors.Errorf("not a PKCS#11 key") + //} + // + //err := c.withSession(func(session *pkcs11Session) error { + // session.ctx.GetAttributeValue(session.handle, ) + //}) + + return nil, errors.Errorf("Not yet supported") +} + +// GetAttributes gets the value of the specified attribute on the given key +func (c *Context) GetAttribute(signer *crypto.Signer, attribute AttributeType) (a *Attribute, err error) { + set, err := c.GetAttributes(signer, []AttributeType{attribute}) + if err != nil { + return nil, err + } + + return set[attribute], nil +} \ No newline at end of file From e71a83ae97ee4dca6bfcd8f8906a110a33018c30 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Wed, 14 Aug 2019 12:16:52 +0100 Subject: [PATCH 02/21] Implement functions for getting multiple keypairs or all keypairs and some refactoring to support these --- keys.go | 160 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 74 deletions(-) diff --git a/keys.go b/keys.go index 56e93dd..4f43cc1 100644 --- a/keys.go +++ b/keys.go @@ -28,7 +28,37 @@ import ( "github.com/pkg/errors" ) -// Find a key object. For asymmetric keys this only finds one half so +const maxHandlePerFind = 20 + +func findKeysWithAttributes(session *pkcs11Session, template []*pkcs11.Attribute) (handles []pkcs11.ObjectHandle, err error) { + if err = session.ctx.FindObjectsInit(session.handle, template); err != nil { + return nil, err + } + defer func() { + finalErr := session.ctx.FindObjectsFinal(session.handle) + if err == nil { + err = finalErr + } + }() + + newhandles, _, err := session.ctx.FindObjects(session.handle, maxHandlePerFind) + if err != nil { + return nil, err + } + + for len(newhandles) > 0 { + handles = append(handles, newhandles...) + + newhandles, _, err = session.ctx.FindObjects(session.handle, maxHandlePerFind) + if err != nil { + return nil, err + } + } + + return handles, nil +} + +// Find key objects. For asymmetric keys this only finds one half so // callers will call it twice. Returns nil if the key does not exist on the token. func findKeys(session *pkcs11Session, id []byte, label []byte, keyclass *uint, keytype *uint) (handles []pkcs11.ObjectHandle, err error) { var template []*pkcs11.Attribute @@ -45,16 +75,8 @@ func findKeys(session *pkcs11Session, id []byte, label []byte, keyclass *uint, k if label != nil { template = append(template, pkcs11.NewAttribute(pkcs11.CKA_LABEL, label)) } - if err = session.ctx.FindObjectsInit(session.handle, template); err != nil { - return nil, err - } - defer func() { - finalErr := session.ctx.FindObjectsFinal(session.handle) - if err == nil { - err = finalErr - } - }() - if handles, _, err = session.ctx.FindObjects(session.handle, 1); err != nil { + + if handles, err = findKeysWithAttributes(session, template); err != nil { return nil, err } @@ -72,16 +94,21 @@ func findKey(session *pkcs11Session, id []byte, label []byte, keyclass *uint, ke return &handles[0], nil } -func (c *Context) makeKeyPair(session *pkcs11Session, id []byte, label []byte, privHandle *pkcs11.ObjectHandle) (signer Signer, err error) { +// Takes a handles to the private half of a keypair, locates the public half with the matching CKA_ID +// value and constructs a keypair object from them both. +func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectHandle) (signer Signer, err error) { attributes := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_ID, nil), pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, 0), } if attributes, err = session.ctx.GetAttributeValue(session.handle, *privHandle, attributes); err != nil { return nil, err } - keyType := bytesToUlong(attributes[0].Value) + id := attributes[0].Value + keyType := bytesToUlong(attributes[1].Value) - pubHandle, err := findKey(session, id, label, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType) + // Find the public half which has a matching CKA_ID + pubHandle, err := findKey(session, id, nil, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType) if err != nil { return nil, err } @@ -144,60 +171,47 @@ func (c *Context) makeKeyPair(session *pkcs11Session, id []byte, label []byte, p // At least one of id and label must be specified. If the private key is found, but the public key is // not, an error is returned because we cannot implement crypto.Signer without the public key. func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { - if c.closed.Get() { - return nil, errClosed + result, err := c.FindKeyPairs(id, label) + if err != nil { + return nil, err } - if id == nil && label == nil { - return nil, errors.New("id and label cannot both be nil") + if len(result) == 0 { + return nil, nil } - var k Signer - - err := c.withSession(func(session *pkcs11Session) error { - privHandle, err := findKey(session, id, label, uintPtr(pkcs11.CKO_PRIVATE_KEY), nil) - if err != nil { - return err - } - if privHandle == nil { - // Cannot continue, no key found - return nil - } - - k, err = c.makeKeyPair(session, id, label, privHandle) - if err != nil { - return err - } - - return nil - }) - return k, err + return result[0], nil } -// FindKeyPairs retrieves all matching asymmetric key pairs, or a nil slice if none can be found. +// FindKeyPairsWithAttributes retrieves previously created asymmetric key pairs, or nil if none can be found. +// The given attributes are matched against the private half only. Then the public half with a matching CKA_ID +// value is found. // -// At least one of id and label must be specified. // If a private key is found, but the corresponding public key is not, the key is not returned because we cannot -// implement crypto.Signer without the public key. -func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { +//// implement crypto.Signer without the public key. +func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) ([]Signer, error) { if c.closed.Get() { return nil, errClosed } - if id == nil && label == nil { - return nil, errors.New("id and label cannot both be nil") - } - var keys []Signer + if _, ok := attributes[CkaClass]; ok { + return nil, errors.Errorf("keypair attribute set must not contain CkaClass") + } + err := c.withSession(func(session *pkcs11Session) error { - privHandles, err := findKeys(session, id, label, uintPtr(pkcs11.CKO_PRIVATE_KEY), nil) + // Add the private key class to the template to find the private half + privAttributes := attributes.Copy() + privAttributes[CkaClass] = pkcs11.NewAttribute(CkaClass, pkcs11.CKO_PRIVATE_KEY) + + privHandles, err := findKeysWithAttributes(session, privAttributes.ToSlice()) if err != nil { return err } for _, privHandle := range(privHandles) { - k, err := c.makeKeyPair(session, id, label, &privHandle) + k, err := c.makeKeyPair(session, &privHandle) if err != nil { continue } @@ -207,40 +221,38 @@ func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { return nil }) + return keys, err } +// FindKeyPairs retrieves all matching asymmetric key pairs, or a nil slice if none can be found. +// +// At least one of id and label must be specified. +// If a private key is found, but the corresponding public key is not, the key is not returned because we cannot +// implement crypto.Signer without the public key. +func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { + if id == nil && label == nil { + return nil, errors.New("id and label cannot both be nil") + } + + attributes := NewAttributeSet() + + if id != nil { + attributes[CkaId] = pkcs11.NewAttribute(CkaId, id) + } + if label != nil { + attributes[CkaLabel] = pkcs11.NewAttribute(CkaLabel, label) + } + + return c.FindKeyPairsWithAttributes(attributes) +} + // FindAllKeyPairs retrieves all existing asymmetric key pairs, or a nil slice if none can be found. // // If a private key is found, but the corresponding public key is not, the key is not returned because we cannot // implement crypto.Signer without the public key. func (c *Context) FindAllKeyPairs() ([]Signer, error) { - //if c.closed.Get() { - // return nil, errClosed - //} - // - //var keys []Signer - // - //err := c.withSession(func(session *pkcs11Session) error { - // privHandles, err := findKeys(session, nil, nil, uintPtr(pkcs11.CKO_PRIVATE_KEY), nil) - // if err != nil { - // return err - // } - // - // for _, privHandle := range(privHandles) { - // k, err := c.makeKeyPair(session, id, label, &privHandle) - // if err != nil { - // continue - // } - // - // keys = append(keys, k) - // } - // - // return nil - //}) - //return keys, err - - return nil, errors.Errorf("Not yet supported") + return c.FindKeyPairsWithAttributes(NewAttributeSet()) } // Public returns the public half of a private key. From 41ed51c47f2159fa0eaae70ce107a92c8fb51a1b Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Wed, 14 Aug 2019 12:37:21 +0100 Subject: [PATCH 03/21] Consistent function ordering --- keys.go | 74 ++++++++++++++++++++++++++++++++++++---------------- keys_test.go | 6 +++++ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/keys.go b/keys.go index 4f43cc1..f0b2981 100644 --- a/keys.go +++ b/keys.go @@ -183,6 +183,41 @@ func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { return result[0], nil } +// FindKeyPairs retrieves all matching asymmetric key pairs, or a nil slice if none can be found. +// +// At least one of id and label must be specified. +// If a private key is found, but the corresponding public key is not, the key is not returned because we cannot +// implement crypto.Signer without the public key. +func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { + if id == nil && label == nil { + return nil, errors.New("id and label cannot both be nil") + } + + attributes := NewAttributeSet() + + if id != nil { + attributes[CkaId] = pkcs11.NewAttribute(CkaId, id) + } + if label != nil { + attributes[CkaLabel] = pkcs11.NewAttribute(CkaLabel, label) + } + + return c.FindKeyPairsWithAttributes(attributes) +} + +func (c *Context) FindKeyPairWithAttributes(attributes AttributeSet) (Signer, error) { + result, err := c.FindKeyPairsWithAttributes(attributes) + if err != nil { + return nil, err + } + + if len(result) == 0 { + return nil, nil + } + + return result[0], nil +} + // FindKeyPairsWithAttributes retrieves previously created asymmetric key pairs, or nil if none can be found. // The given attributes are matched against the private half only. Then the public half with a matching CKA_ID // value is found. @@ -225,28 +260,6 @@ func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) ([]Signer, return keys, err } -// FindKeyPairs retrieves all matching asymmetric key pairs, or a nil slice if none can be found. -// -// At least one of id and label must be specified. -// If a private key is found, but the corresponding public key is not, the key is not returned because we cannot -// implement crypto.Signer without the public key. -func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { - if id == nil && label == nil { - return nil, errors.New("id and label cannot both be nil") - } - - attributes := NewAttributeSet() - - if id != nil { - attributes[CkaId] = pkcs11.NewAttribute(CkaId, id) - } - if label != nil { - attributes[CkaLabel] = pkcs11.NewAttribute(CkaLabel, label) - } - - return c.FindKeyPairsWithAttributes(attributes) -} - // FindAllKeyPairs retrieves all existing asymmetric key pairs, or a nil slice if none can be found. // // If a private key is found, but the corresponding public key is not, the key is not returned because we cannot @@ -314,6 +327,23 @@ func (c *Context) FindKeys(id []byte, label []byte) ([]*SecretKey, error) { return nil, errors.Errorf("Not yet supported") } +func (c *Context) FindKeyWithAttributes(attributes AttributeSet) (*SecretKey, error) { + result, err := c.FindKeysWithAttributes(attributes) + if err != nil { + return nil, err + } + + if len(result) == 0 { + return nil, nil + } + + return result[0], nil +} + +func (c *Context) FindKeysWithAttributes(attributes AttributeSet) ([]*SecretKey, error) { + return nil, errors.Errorf("Not yet supported") +} + // FindAllKeyPairs retrieves all existing symmetric keys, or a nil slice if none can be found. func (c *Context) FindAllKeys() ([]*SecretKey, error) { return nil, errors.Errorf("Not yet supported") diff --git a/keys_test.go b/keys_test.go index 152b33a..e116865 100644 --- a/keys_test.go +++ b/keys_test.go @@ -18,6 +18,12 @@ func TestFindKeysRequiresIdOrLabel(t *testing.T) { _, err = ctx.FindKey(nil, nil) assert.Error(t, err) + _, err = ctx.FindKeys(nil, nil) + assert.Error(t, err) + _, err = ctx.FindKeyPair(nil, nil) assert.Error(t, err) + + _, err = ctx.FindKeyPairs(nil, nil) + assert.Error(t, err) } From 943a6e6622fd60e40339306bf6755545aebe81b8 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Wed, 14 Aug 2019 12:44:02 +0100 Subject: [PATCH 04/21] Implement functions for getting multiple symmetric keys --- keys.go | 98 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 36 deletions(-) diff --git a/keys.go b/keys.go index f0b2981..b415e30 100644 --- a/keys.go +++ b/keys.go @@ -281,50 +281,36 @@ func (k pkcs11PrivateKey) Public() crypto.PublicKey { // // Either (but not both) of id and label may be nil, in which case they are ignored. func (c *Context) FindKey(id []byte, label []byte) (*SecretKey, error) { - if c.closed.Get() { - return nil, errClosed + result, err := c.FindKeys(id, label) + if err != nil { + return nil, err } - if id == nil && label == nil { - return nil, errors.New("id and label cannot both be nil") + if len(result) == 0 { + return nil, nil } - var k *SecretKey - - err := c.withSession(func(session *pkcs11Session) error { - privHandle, err := findKey(session, id, label, uintPtr(pkcs11.CKO_SECRET_KEY), nil) - if err != nil { - return err - } - if privHandle == nil { - // Key does not exist - return nil - } - - attributes := []*pkcs11.Attribute{ - pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, 0), - } - if attributes, err = session.ctx.GetAttributeValue(session.handle, *privHandle, attributes); err != nil { - return err - } - keyType := bytesToUlong(attributes[0].Value) - - if cipher, ok := Ciphers[int(keyType)]; ok { - k = &SecretKey{pkcs11Object{*privHandle, c}, cipher} - } else { - return errors.Errorf("unsupported key type: %X", keyType) - } - return nil - }) - - return k, err + return result[0], nil } // FindKeys retrieves all matching symmetric keys, or a nil slice if none can be found. // // At least one of id and label must be specified. func (c *Context) FindKeys(id []byte, label []byte) ([]*SecretKey, error) { - return nil, errors.Errorf("Not yet supported") + if id == nil && label == nil { + return nil, errors.New("id and label cannot both be nil") + } + + attributes := NewAttributeSet() + + if id != nil { + attributes[CkaId] = pkcs11.NewAttribute(CkaId, id) + } + if label != nil { + attributes[CkaLabel] = pkcs11.NewAttribute(CkaLabel, label) + } + + return c.FindKeysWithAttributes(attributes) } func (c *Context) FindKeyWithAttributes(attributes AttributeSet) (*SecretKey, error) { @@ -341,12 +327,52 @@ func (c *Context) FindKeyWithAttributes(attributes AttributeSet) (*SecretKey, er } func (c *Context) FindKeysWithAttributes(attributes AttributeSet) ([]*SecretKey, error) { - return nil, errors.Errorf("Not yet supported") + if c.closed.Get() { + return nil, errClosed + } + + var keys []*SecretKey + + if _, ok := attributes[CkaClass]; ok { + return nil, errors.Errorf("key attribute set must not contain CkaClass") + } + + err := c.withSession(func(session *pkcs11Session) error { + // Add the private key class to the template to find the private half + privAttributes := attributes.Copy() + privAttributes[CkaClass] = pkcs11.NewAttribute(CkaClass, pkcs11.CKO_SECRET_KEY) + + privHandles, err := findKeysWithAttributes(session, privAttributes.ToSlice()) + if err != nil { + return err + } + + for _, privHandle := range(privHandles) { + attributes := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, 0), + } + if attributes, err = session.ctx.GetAttributeValue(session.handle, privHandle, attributes); err != nil { + return err + } + keyType := bytesToUlong(attributes[0].Value) + + if cipher, ok := Ciphers[int(keyType)]; ok { + k := &SecretKey{pkcs11Object{privHandle, c}, cipher} + keys = append(keys, k) + } else { + return errors.Errorf("unsupported key type: %X", keyType) + } + } + + return nil + }) + + return keys, err } // FindAllKeyPairs retrieves all existing symmetric keys, or a nil slice if none can be found. func (c *Context) FindAllKeys() ([]*SecretKey, error) { - return nil, errors.Errorf("Not yet supported") + return c.FindKeysWithAttributes(NewAttributeSet()) } func uintPtr(i uint) *uint { return &i } From 907da9d99caa3d5d34290483803eebeff06d1767 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Wed, 14 Aug 2019 15:11:03 +0100 Subject: [PATCH 05/21] Initial implementation of function for getting attribute values --- keys.go | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/keys.go b/keys.go index b415e30..b1882df 100644 --- a/keys.go +++ b/keys.go @@ -23,7 +23,6 @@ package crypto11 import ( "crypto" - "github.com/miekg/pkcs11" "github.com/pkg/errors" ) @@ -378,28 +377,53 @@ func (c *Context) FindAllKeys() ([]*SecretKey, error) { func uintPtr(i uint) *uint { return &i } // GetAttributes gets the values of the specified attributes on the given key -func (c *Context) GetAttributes(signer *crypto.Signer, attributes []AttributeType) (a AttributeSet, err error) { +func (c *Context) GetAttributes(signer crypto.Signer, attributes []AttributeType) (a AttributeSet, err error) { if c.closed.Get() { return nil, errClosed } - //if sig, ok := (*signer).(Signer); !ok { - // nil, return errors.Errorf("not a PKCS#11 key") - //} - // - //err := c.withSession(func(session *pkcs11Session) error { - // session.ctx.GetAttributeValue(session.handle, ) - //}) + var handle pkcs11.ObjectHandle + + switch s := (signer).(type) { + case *pkcs11PrivateKeyDSA: + handle = s.handle + case *pkcs11PrivateKeyRSA: + handle = s.handle + case *pkcs11PrivateKeyECDSA: + handle = s.handle + default: + return nil, errors.Errorf("not a PKCS#11 key") + } + + values := NewAttributeSet() - return nil, errors.Errorf("Not yet supported") + err = c.withSession(func(session *pkcs11Session) error { + var attrs []*pkcs11.Attribute + for _, a := range(attributes) { + attrs = append(attrs, pkcs11.NewAttribute(a, nil)) + } + + p11values, err := session.ctx.GetAttributeValue(session.handle, handle, attrs) + if err != nil { + return err + } + + for _, a := range(p11values) { + values[a.Type] = pkcs11.NewAttribute(a.Type, a.Value) + } + + return nil + }) + + return values, err } // GetAttributes gets the value of the specified attribute on the given key -func (c *Context) GetAttribute(signer *crypto.Signer, attribute AttributeType) (a *Attribute, err error) { +func (c *Context) GetAttribute(signer crypto.Signer, attribute AttributeType) (a *Attribute, err error) { set, err := c.GetAttributes(signer, []AttributeType{attribute}) if err != nil { return nil, err } return set[attribute], nil -} \ No newline at end of file +} From 5b0e90746f29a069a05965b0d3feeb19f48fa7da Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Thu, 15 Aug 2019 11:34:47 +0100 Subject: [PATCH 06/21] Add support for getting the attributes of symmetric and public keys --- keys.go | 84 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/keys.go b/keys.go index b1882df..4993118 100644 --- a/keys.go +++ b/keys.go @@ -376,25 +376,7 @@ func (c *Context) FindAllKeys() ([]*SecretKey, error) { func uintPtr(i uint) *uint { return &i } -// GetAttributes gets the values of the specified attributes on the given key -func (c *Context) GetAttributes(signer crypto.Signer, attributes []AttributeType) (a AttributeSet, err error) { - if c.closed.Get() { - return nil, errClosed - } - - var handle pkcs11.ObjectHandle - - switch s := (signer).(type) { - case *pkcs11PrivateKeyDSA: - handle = s.handle - case *pkcs11PrivateKeyRSA: - handle = s.handle - case *pkcs11PrivateKeyECDSA: - handle = s.handle - default: - return nil, errors.Errorf("not a PKCS#11 key") - } - +func (c *Context) getAttributes(handle pkcs11.ObjectHandle, attributes []AttributeType) (a AttributeSet, err error) { values := NewAttributeSet() err = c.withSession(func(session *pkcs11Session) error { @@ -418,12 +400,70 @@ func (c *Context) GetAttributes(signer crypto.Signer, attributes []AttributeType return values, err } -// GetAttributes gets the value of the specified attribute on the given key -func (c *Context) GetAttribute(signer crypto.Signer, attribute AttributeType) (a *Attribute, err error) { - set, err := c.GetAttributes(signer, []AttributeType{attribute}) +// GetAttributes gets the values of the specified attributes on the given key +// If the key is asymmetric, then the attributes are retrieved from the private half +func (c *Context) GetAttributes(key interface{}, attributes []AttributeType) (a AttributeSet, err error) { + if c.closed.Get() { + return nil, errClosed + } + + var handle pkcs11.ObjectHandle + + switch k := (key).(type) { + case *pkcs11PrivateKeyDSA: + handle = k.handle + case *pkcs11PrivateKeyRSA: + handle = k.handle + case *pkcs11PrivateKeyECDSA: + handle = k.handle + case *SecretKey: + handle = k.handle + default: + return nil, errors.Errorf("not a PKCS#11 key") + } + + return c.getAttributes(handle, attributes) +} + +// GetAttribute gets the value of the specified attribute on the given key +// If the key is asymmetric, then the attribute is retrieved from the private half +func (c *Context) GetAttribute(key interface{}, attribute AttributeType) (a *Attribute, err error) { + set, err := c.GetAttributes(key, []AttributeType{attribute}) if err != nil { return nil, err } return set[attribute], nil } + +// GetPubAttributes gets the values of the specified attributes on the public half of the given key +func (c *Context) GetPubAttributes(key interface{}, attributes []AttributeType) (a AttributeSet, err error) { + if c.closed.Get() { + return nil, errClosed + } + + var handle pkcs11.ObjectHandle + + switch k := (key).(type) { + case *pkcs11PrivateKeyDSA: + handle = k.pubKeyHandle + case *pkcs11PrivateKeyRSA: + handle = k.pubKeyHandle + case *pkcs11PrivateKeyECDSA: + handle = k.pubKeyHandle + default: + return nil, errors.Errorf("not an asymmetric PKCS#11 key") + } + + return c.getAttributes(handle, attributes) +} + +// GetPubAttribute gets the value of the specified attribute on the public half of the given key +func (c *Context) GetPubAttribute(key interface{}, attribute AttributeType) (a *Attribute, err error) { + set, err := c.GetPubAttributes(key, []AttributeType{attribute}) + if err != nil { + return nil, err + } + + return set[attribute], nil +} \ No newline at end of file From 69efe9a24131cb2af77d4b28ae617e57e986bf82 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Fri, 16 Aug 2019 11:02:12 +0100 Subject: [PATCH 07/21] Add back matching public keys based on CKA_LABEL as well as CKA_ID --- keys.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/keys.go b/keys.go index 4993118..17ba2f0 100644 --- a/keys.go +++ b/keys.go @@ -98,16 +98,18 @@ func findKey(session *pkcs11Session, id []byte, label []byte, keyclass *uint, ke func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectHandle) (signer Signer, err error) { attributes := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_ID, nil), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, nil), pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, 0), } if attributes, err = session.ctx.GetAttributeValue(session.handle, *privHandle, attributes); err != nil { return nil, err } id := attributes[0].Value - keyType := bytesToUlong(attributes[1].Value) + label := attributes[1].Value + keyType := bytesToUlong(attributes[2].Value) // Find the public half which has a matching CKA_ID - pubHandle, err := findKey(session, id, nil, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType) + pubHandle, err := findKey(session, id, label, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType) if err != nil { return nil, err } From fc378c6756446b8839e9a865d954297f2e5dc268 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Fri, 16 Aug 2019 15:24:22 +0100 Subject: [PATCH 08/21] Clean up test keys --- close_test.go | 6 ++++++ dsa_test.go | 2 ++ ecdsa_test.go | 1 + hmac_test.go | 1 + rsa_test.go | 1 + symmetric_test.go | 3 +++ thread_test.go | 1 + 7 files changed, 15 insertions(+) diff --git a/close_test.go b/close_test.go index afdb477..51db70f 100644 --- a/close_test.go +++ b/close_test.go @@ -56,6 +56,12 @@ func TestClose(t *testing.T) { require.NoError(t, err) testDsaSigning(t, key2.(*pkcs11PrivateKeyDSA), pSize, fmt.Sprintf("close%d", i)) + + if i == 4 { + err = key2.Delete() + require.NoError(t, err) + } + require.NoError(t, ctx.Close()) } } diff --git a/dsa_test.go b/dsa_test.go index f53937f..b155a01 100644 --- a/dsa_test.go +++ b/dsa_test.go @@ -117,6 +117,8 @@ func TestHardDSA(t *testing.T) { key, err := ctx.GenerateDSAKeyPairWithLabel(id, label, params) require.NoError(t, err) require.NotNil(t, key) + defer key.Delete() + testDsaSigning(t, key, pSize, "hard1") key2, err := ctx.FindKeyPair(id, nil) diff --git a/ecdsa_test.go b/ecdsa_test.go index 3422fac..dde920e 100644 --- a/ecdsa_test.go +++ b/ecdsa_test.go @@ -74,6 +74,7 @@ func TestHardECDSA(t *testing.T) { key, err := ctx.GenerateECDSAKeyPairWithLabel(id, label, curve) require.NoError(t, err) require.NotNil(t, key) + defer key.Delete() testEcdsaSigning(t, key, crypto.SHA1) testEcdsaSigning(t, key, crypto.SHA224) diff --git a/hmac_test.go b/hmac_test.go index 28354f2..6762c92 100644 --- a/hmac_test.go +++ b/hmac_test.go @@ -61,6 +61,7 @@ func testHmac(t *testing.T, ctx *Context, keytype int, mech int, length int, xle key, err := ctx.GenerateSecretKey(id, 256, Ciphers[keytype]) require.NoError(t, err) require.NotNil(t, key) + defer key.Delete() t.Run("Short", func(t *testing.T) { input := []byte("a short string") diff --git a/rsa_test.go b/rsa_test.go index ba90a35..9934c1e 100644 --- a/rsa_test.go +++ b/rsa_test.go @@ -78,6 +78,7 @@ func TestHardRSA(t *testing.T) { key, err := ctx.GenerateRSAKeyPairWithLabel(id, label, nbits) require.NoError(t, err) require.NotNil(t, key) + defer key.Delete() var key2, key3 crypto.PrivateKey diff --git a/symmetric_test.go b/symmetric_test.go index 7f06d3b..bbe9f37 100644 --- a/symmetric_test.go +++ b/symmetric_test.go @@ -51,6 +51,7 @@ func testHardSymmetric(t *testing.T, ctx *Context, keytype int, bits int) { key, err := ctx.GenerateSecretKey(id, bits, Ciphers[keytype]) require.NoError(t, err) require.NotNil(t, key) + defer key.Delete() var key2 *SecretKey t.Run("Find", func(t *testing.T) { @@ -245,6 +246,8 @@ func BenchmarkCBC(b *testing.B) { id := randomBytes() key, err := ctx.GenerateSecretKey(id, 128, Ciphers[pkcs11.CKK_AES]) require.NoError(b, err) + require.NotNil(b, key) + defer key.Delete() iv := make([]byte, 16) plaintext := make([]byte, 65536) diff --git a/thread_test.go b/thread_test.go index 280690a..7398644 100644 --- a/thread_test.go +++ b/thread_test.go @@ -44,6 +44,7 @@ func TestThreadedRSA(t *testing.T) { id := randomBytes() key, err := ctx.GenerateRSAKeyPair(id, 1024) require.NoError(t, err) + defer key.Delete() done := make(chan int) started := time.Now() From 0fb931b6769c4d7bde35296f03676e2817d59ff7 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Fri, 16 Aug 2019 16:10:08 +0100 Subject: [PATCH 09/21] Add tests for new multiple key finding function and attribute getting functions --- keys_test.go | 222 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 213 insertions(+), 9 deletions(-) diff --git a/keys_test.go b/keys_test.go index e116865..d4e652b 100644 --- a/keys_test.go +++ b/keys_test.go @@ -1,13 +1,17 @@ package crypto11 import ( + "crypto/rand" + "crypto/rsa" + "github.com/miekg/pkcs11" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestFindKeysRequiresIdOrLabel(t *testing.T) { +// withContext executes a test function with a context. +func withContext(t *testing.T, f func(ctx *Context)) { ctx, err := ConfigureFromFile("config") require.NoError(t, err) @@ -15,15 +19,215 @@ func TestFindKeysRequiresIdOrLabel(t *testing.T) { require.NoError(t, ctx.Close()) }() - _, err = ctx.FindKey(nil, nil) - assert.Error(t, err) + f(ctx) +} + +func TestFindKeysRequiresIdOrLabel(t *testing.T) { + withContext(t, func(ctx *Context) { + _, err := ctx.FindKey(nil, nil) + assert.Error(t, err) + + _, err = ctx.FindKeys(nil, nil) + assert.Error(t, err) + + _, err = ctx.FindKeyPair(nil, nil) + assert.Error(t, err) + + _, err = ctx.FindKeyPairs(nil, nil) + assert.Error(t, err) + }) +} + +func TestFindingKeysWithAttributes(t *testing.T) { + withContext(t, func(ctx *Context) { + id := randomBytes() + id2 := randomBytes() + + key, err := ctx.GenerateSecretKey(id, 128, CipherAES) + require.NoError(t, err) + require.NotNil(t, key) + defer key.Delete() + + key, err = ctx.GenerateSecretKey(id2, 128, CipherAES) + require.NoError(t, err) + require.NotNil(t, key) + defer key.Delete() + + key, err = ctx.GenerateSecretKey(id2, 256, CipherAES) + require.NoError(t, err) + require.NotNil(t, key) + defer key.Delete() + + attrs, err := NewAttributeSetWithID(id) + require.NoError(t, err) + + keys, err := ctx.FindKeysWithAttributes(attrs) + require.Len(t, keys, 1) + + attrs, err = NewAttributeSetWithID(id2) + require.NoError(t, err) + + keys, err = ctx.FindKeysWithAttributes(attrs) + require.Len(t, keys, 2) + + attrs = NewAttributeSet() + attrs.AddIfNotPresent([]*Attribute{ + pkcs11.NewAttribute(CkaValueLen, 16), + }) + + keys, err = ctx.FindKeysWithAttributes(attrs) + require.Len(t, keys, 2) + + attrs = NewAttributeSet() + attrs.AddIfNotPresent([]*Attribute{ + pkcs11.NewAttribute(CkaValueLen, 32), + }) + + keys, err = ctx.FindKeysWithAttributes(attrs) + require.Len(t, keys, 1) + }) +} + +func TestFindingKeyPairsWithAttributes(t *testing.T) { + withContext(t, func(ctx *Context) { + id := randomBytes() + id2 := randomBytes() + + key, err := ctx.GenerateRSAKeyPair(id, 1024) + require.NoError(t, err) + require.NotNil(t, key) + defer key.Delete() + + key, err = ctx.GenerateRSAKeyPair(id2, 1024) + require.NoError(t, err) + require.NotNil(t, key) + defer key.Delete() + + key, err = ctx.GenerateRSAKeyPair(id2, 2048) + require.NoError(t, err) + require.NotNil(t, key) + defer key.Delete() + + attrs, err := NewAttributeSetWithID(id) + require.NoError(t, err) + + keys, err := ctx.FindKeyPairsWithAttributes(attrs) + require.Len(t, keys, 1) + + attrs, err = NewAttributeSetWithID(id2) + require.NoError(t, err) - _, err = ctx.FindKeys(nil, nil) - assert.Error(t, err) + keys, err = ctx.FindKeyPairsWithAttributes(attrs) + require.Len(t, keys, 2) + + attrs = NewAttributeSet() + attrs.AddIfNotPresent([]*Attribute{ + pkcs11.NewAttribute(CkaPublicExponent, []byte{1, 0, 1}), + }) + + keys, err = ctx.FindKeyPairsWithAttributes(attrs) + require.Len(t, keys, 3) + }) +} + +func TestFindingAllKeys(t *testing.T) { + withContext(t, func(ctx *Context) { + for i := 0; i < 10; i++ { + id := randomBytes() + key, err := ctx.GenerateSecretKey(id, 128, CipherAES) + require.NoError(t, err) + require.NotNil(t, key) + + defer key.Delete() + } + + keys, err := ctx.FindAllKeys() + require.NoError(t, err) + require.NotNil(t, keys) + + require.Len(t, keys, 10) + }) +} + +func TestFindingAllKeyPairs(t *testing.T) { + withContext(t, func(ctx *Context) { + for i := 1; i <= 5; i++ { + id := randomBytes() + key, err := ctx.GenerateRSAKeyPair(id, 1024) + require.NoError(t, err) + require.NotNil(t, key) + + defer key.Delete() + } + + keys, err := ctx.FindAllKeyPairs() + require.NoError(t, err) + require.NotNil(t, keys) + + require.Len(t, keys, 5) + }) +} + +func TestGettingPrivateKeyAttributes(t *testing.T) { + withContext(t, func(ctx *Context) { + id := randomBytes() + + key, err := ctx.GenerateRSAKeyPair(id, 1024) + require.NoError(t, err) + require.NotNil(t, key) + defer key.Delete() + + attrs, err := ctx.GetAttributes(key, []AttributeType{CkaModulus}) + require.NoError(t, err) + require.NotNil(t, attrs) + require.Len(t, attrs, 1) + + require.Len(t, attrs[CkaModulus].Value, 128) + }) +} + +func TestGettingPublicKeyAttributes(t *testing.T) { + withContext(t, func(ctx *Context) { + id := randomBytes() + + key, err := ctx.GenerateRSAKeyPair(id, 1024) + require.NoError(t, err) + require.NotNil(t, key) + defer key.Delete() + + attrs, err := ctx.GetPubAttributes(key, []AttributeType{CkaModulusBits}) + require.NoError(t, err) + require.NotNil(t, attrs) + require.Len(t, attrs, 1) + + require.Equal(t, uint(1024), bytesToUlong(attrs[CkaModulusBits].Value)) + }) +} + +func TestGettingSecretKeyAttributes(t *testing.T) { + withContext(t, func(ctx *Context) { + id := randomBytes() + + key, err := ctx.GenerateSecretKey(id, 128, CipherAES) + require.NoError(t, err) + require.NotNil(t, key) + defer key.Delete() + + attrs, err := ctx.GetAttributes(key, []AttributeType{CkaValueLen}) + require.NoError(t, err) + require.NotNil(t, attrs) + require.Len(t, attrs, 1) + + require.Equal(t, uint(16), bytesToUlong(attrs[CkaValueLen].Value)) + }) +} - _, err = ctx.FindKeyPair(nil, nil) - assert.Error(t, err) +func TestGettingUnsupportedKeyTypeAttributes(t *testing.T) { + withContext(t, func(ctx *Context) { + key, err := rsa.GenerateKey(rand.Reader, 1024) + require.NoError(t, err) - _, err = ctx.FindKeyPairs(nil, nil) - assert.Error(t, err) + _, err = ctx.GetAttributes(key, []AttributeType{CkaModulusBits}) + require.Error(t, err) + }) } From fc04ba462c007593e366bbad0435d98107b07d11 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 13:00:56 +0100 Subject: [PATCH 10/21] Add new functions to close tests --- close_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/close_test.go b/close_test.go index 51db70f..d3e7cfc 100644 --- a/close_test.go +++ b/close_test.go @@ -89,9 +89,21 @@ func TestErrorAfterClosed(t *testing.T) { _, err = ctx.FindKey(bytes, nil) assert.Equal(t, errClosed, err) + _, err = ctx.FindKeys(bytes, nil) + assert.Equal(t, errClosed, err) + + _, err = ctx.FindKeysWithAttributes(NewAttributeSet()) + assert.Equal(t, errClosed, err) + _, err = ctx.FindKeyPair(bytes, nil) assert.Equal(t, errClosed, err) + _, err = ctx.FindKeyPairs(bytes, nil) + assert.Equal(t, errClosed, err) + + _, err = ctx.FindKeyPairsWithAttributes(NewAttributeSet()) + assert.Equal(t, errClosed, err) + _, err = ctx.GenerateSecretKey(bytes, 256, CipherAES) assert.Equal(t, errClosed, err) @@ -129,4 +141,16 @@ func TestErrorAfterClosed(t *testing.T) { err = ctx.ImportCertificateWithAttributes(NewAttributeSet(), cert) assert.Equal(t, errClosed, err) + + _, err = ctx.GetAttribute(nil, CkaLabel) + assert.Equal(t, errClosed, err) + + _, err = ctx.GetAttributes(nil, []AttributeType{CkaLabel}) + assert.Equal(t, errClosed, err) + + _, err = ctx.GetPubAttribute(nil, CkaLabel) + assert.Equal(t, errClosed, err) + + _, err = ctx.GetPubAttributes(nil, []AttributeType{CkaLabel}) + assert.Equal(t, errClosed, err) } From 7d708c6d372111b7761db1879eba5ca4afbceb7a Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 14:10:20 +0100 Subject: [PATCH 11/21] Various updates to comments --- keys.go | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/keys.go b/keys.go index 17ba2f0..e8246be 100644 --- a/keys.go +++ b/keys.go @@ -93,8 +93,8 @@ func findKey(session *pkcs11Session, id []byte, label []byte, keyclass *uint, ke return &handles[0], nil } -// Takes a handles to the private half of a keypair, locates the public half with the matching CKA_ID -// value and constructs a keypair object from them both. +// Takes a handles to the private half of a keypair, locates the public half with the matching CKA_ID and CKA_LABEL +// values and constructs a keypair object from them both. func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectHandle) (signer Signer, err error) { attributes := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_ID, nil), @@ -169,8 +169,9 @@ func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectH // FindKeyPair retrieves a previously created asymmetric key pair, or nil if it cannot be found. // -// At least one of id and label must be specified. If the private key is found, but the public key is -// not, an error is returned because we cannot implement crypto.Signer without the public key. +// At least one of id and label must be specified. +// If the private key is found, but the public key is not, the key is not returned because we cannot +// implement crypto.Signer without the public key. func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { result, err := c.FindKeyPairs(id, label) if err != nil { @@ -206,6 +207,12 @@ func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { return c.FindKeyPairsWithAttributes(attributes) } +// FindKeyPairWithAttributes retrieves a previously created asymmetric key pair, or nil if it cannot be found. +// The given attributes are matched against the private half only. Then the public half with a matching CKA_ID +// and CKA_LABEL values is found. +// +// If a private key is found, but the corresponding public key is not, the key is not returned because we cannot +// implement crypto.Signer without the public key. func (c *Context) FindKeyPairWithAttributes(attributes AttributeSet) (Signer, error) { result, err := c.FindKeyPairsWithAttributes(attributes) if err != nil { @@ -221,10 +228,10 @@ func (c *Context) FindKeyPairWithAttributes(attributes AttributeSet) (Signer, er // FindKeyPairsWithAttributes retrieves previously created asymmetric key pairs, or nil if none can be found. // The given attributes are matched against the private half only. Then the public half with a matching CKA_ID -// value is found. +// and CKA_LABEL values is found. // // If a private key is found, but the corresponding public key is not, the key is not returned because we cannot -//// implement crypto.Signer without the public key. +// implement crypto.Signer without the public key. func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) ([]Signer, error) { if c.closed.Get() { return nil, errClosed @@ -314,6 +321,7 @@ func (c *Context) FindKeys(id []byte, label []byte) ([]*SecretKey, error) { return c.FindKeysWithAttributes(attributes) } +// FindKeyWithAttributes retrieves a previously created symmetric key, or nil if it cannot be found. func (c *Context) FindKeyWithAttributes(attributes AttributeSet) (*SecretKey, error) { result, err := c.FindKeysWithAttributes(attributes) if err != nil { @@ -327,6 +335,7 @@ func (c *Context) FindKeyWithAttributes(attributes AttributeSet) (*SecretKey, er return result[0], nil } +// FindKeysWithAttributes retrieves previously created symmetric keys, or a nil slice if none can be found. func (c *Context) FindKeysWithAttributes(attributes AttributeSet) ([]*SecretKey, error) { if c.closed.Get() { return nil, errClosed @@ -402,8 +411,10 @@ func (c *Context) getAttributes(handle pkcs11.ObjectHandle, attributes []Attribu return values, err } -// GetAttributes gets the values of the specified attributes on the given key -// If the key is asymmetric, then the attributes are retrieved from the private half +// GetAttributes gets the values of the specified attributes on the given key or keypair. +// If the key is asymmetric, then the attributes are retrieved from the private half. +// +// If the object is not a crypto11 key or keypair then an error is returned. func (c *Context) GetAttributes(key interface{}, attributes []AttributeType) (a AttributeSet, err error) { if c.closed.Get() { return nil, errClosed @@ -427,8 +438,10 @@ func (c *Context) GetAttributes(key interface{}, attributes []AttributeType) (a return c.getAttributes(handle, attributes) } -// GetAttribute gets the value of the specified attribute on the given key -// If the key is asymmetric, then the attribute is retrieved from the private half +// GetAttribute gets the value of the specified attribute on the given key or keypair. +// If the key is asymmetric, then the attribute is retrieved from the private half. +// +// If the object is not a crypto11 key or keypair then an error is returned. func (c *Context) GetAttribute(key interface{}, attribute AttributeType) (a *Attribute, err error) { set, err := c.GetAttributes(key, []AttributeType{attribute}) if err != nil { @@ -438,7 +451,9 @@ func (c *Context) GetAttribute(key interface{}, attribute AttributeType) (a *Att return set[attribute], nil } -// GetPubAttributes gets the values of the specified attributes on the public half of the given key +// GetPubAttributes gets the values of the specified attributes on the public half of the given keypair. +// +// If the object is not a crypto11 keypair then an error is returned. func (c *Context) GetPubAttributes(key interface{}, attributes []AttributeType) (a AttributeSet, err error) { if c.closed.Get() { return nil, errClosed @@ -460,7 +475,9 @@ func (c *Context) GetPubAttributes(key interface{}, attributes []AttributeType) return c.getAttributes(handle, attributes) } -// GetPubAttribute gets the value of the specified attribute on the public half of the given key +// GetPubAttribute gets the value of the specified attribute on the public half of the given key. +// +// If the object is not a crypto11 keypair then an error is returned. func (c *Context) GetPubAttribute(key interface{}, attribute AttributeType) (a *Attribute, err error) { set, err := c.GetPubAttributes(key, []AttributeType{attribute}) if err != nil { From c446202ae27a7d07bdb9d671dbb625b1ebc1d236 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 15:26:33 +0100 Subject: [PATCH 12/21] Ensure a private key has a CKA_ID value before trying to find the corresponding public key --- keys.go | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/keys.go b/keys.go index e8246be..da6bc97 100644 --- a/keys.go +++ b/keys.go @@ -108,6 +108,11 @@ func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectH label := attributes[1].Value keyType := bytesToUlong(attributes[2].Value) + // Ensure the private key actually has a non-empty CKA_ID to match on + if id == nil || len(id) == 0 { + return nil, errors.New("private key has no CKA_ID") + } + // Find the public half which has a matching CKA_ID pubHandle, err := findKey(session, id, label, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType) if err != nil { @@ -170,8 +175,9 @@ func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectH // FindKeyPair retrieves a previously created asymmetric key pair, or nil if it cannot be found. // // At least one of id and label must be specified. -// If the private key is found, but the public key is not, the key is not returned because we cannot -// implement crypto.Signer without the public key. +// Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key. +// If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned +// because we cannot implement crypto.Signer without the public key. func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { result, err := c.FindKeyPairs(id, label) if err != nil { @@ -188,8 +194,9 @@ func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { // FindKeyPairs retrieves all matching asymmetric key pairs, or a nil slice if none can be found. // // At least one of id and label must be specified. -// If a private key is found, but the corresponding public key is not, the key is not returned because we cannot -// implement crypto.Signer without the public key. +// Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key. +// If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned +// because we cannot implement crypto.Signer without the public key. func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { if id == nil && label == nil { return nil, errors.New("id and label cannot both be nil") @@ -211,8 +218,9 @@ func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { // The given attributes are matched against the private half only. Then the public half with a matching CKA_ID // and CKA_LABEL values is found. // -// If a private key is found, but the corresponding public key is not, the key is not returned because we cannot -// implement crypto.Signer without the public key. +// Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key. +// If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned +// because we cannot implement crypto.Signer without the public key. func (c *Context) FindKeyPairWithAttributes(attributes AttributeSet) (Signer, error) { result, err := c.FindKeyPairsWithAttributes(attributes) if err != nil { @@ -230,8 +238,9 @@ func (c *Context) FindKeyPairWithAttributes(attributes AttributeSet) (Signer, er // The given attributes are matched against the private half only. Then the public half with a matching CKA_ID // and CKA_LABEL values is found. // -// If a private key is found, but the corresponding public key is not, the key is not returned because we cannot -// implement crypto.Signer without the public key. +// Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key. +// If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned +// because we cannot implement crypto.Signer without the public key. func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) ([]Signer, error) { if c.closed.Get() { return nil, errClosed From 505112439877fa40f5b2c88370b453326ffe9164 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 15:40:10 +0100 Subject: [PATCH 13/21] Use AttributeSet.Set() --- keys.go | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/keys.go b/keys.go index da6bc97..32010e0 100644 --- a/keys.go +++ b/keys.go @@ -197,7 +197,7 @@ func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { // Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key. // If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned // because we cannot implement crypto.Signer without the public key. -func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { +func (c *Context) FindKeyPairs(id []byte, label []byte) (signer []Signer, err error) { if id == nil && label == nil { return nil, errors.New("id and label cannot both be nil") } @@ -205,10 +205,16 @@ func (c *Context) FindKeyPairs(id []byte, label []byte) ([]Signer, error) { attributes := NewAttributeSet() if id != nil { - attributes[CkaId] = pkcs11.NewAttribute(CkaId, id) + err = attributes.Set(CkaId, id) + if err != nil { + return nil, err + } } if label != nil { - attributes[CkaLabel] = pkcs11.NewAttribute(CkaLabel, label) + err = attributes.Set(CkaLabel, label) + if err != nil { + return nil, err + } } return c.FindKeyPairsWithAttributes(attributes) @@ -241,7 +247,7 @@ func (c *Context) FindKeyPairWithAttributes(attributes AttributeSet) (Signer, er // Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key. // If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned // because we cannot implement crypto.Signer without the public key. -func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) ([]Signer, error) { +func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) (signer []Signer, err error) { if c.closed.Get() { return nil, errClosed } @@ -252,10 +258,13 @@ func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) ([]Signer, return nil, errors.Errorf("keypair attribute set must not contain CkaClass") } - err := c.withSession(func(session *pkcs11Session) error { + err = c.withSession(func(session *pkcs11Session) error { // Add the private key class to the template to find the private half privAttributes := attributes.Copy() - privAttributes[CkaClass] = pkcs11.NewAttribute(CkaClass, pkcs11.CKO_PRIVATE_KEY) + err = attributes.Set(CkaClass, pkcs11.CKO_PRIVATE_KEY) + if err != nil { + return err + } privHandles, err := findKeysWithAttributes(session, privAttributes.ToSlice()) if err != nil { @@ -313,7 +322,7 @@ func (c *Context) FindKey(id []byte, label []byte) (*SecretKey, error) { // FindKeys retrieves all matching symmetric keys, or a nil slice if none can be found. // // At least one of id and label must be specified. -func (c *Context) FindKeys(id []byte, label []byte) ([]*SecretKey, error) { +func (c *Context) FindKeys(id []byte, label []byte) (key []*SecretKey, err error) { if id == nil && label == nil { return nil, errors.New("id and label cannot both be nil") } @@ -321,10 +330,16 @@ func (c *Context) FindKeys(id []byte, label []byte) ([]*SecretKey, error) { attributes := NewAttributeSet() if id != nil { - attributes[CkaId] = pkcs11.NewAttribute(CkaId, id) + err = attributes.Set(CkaId, id) + if err != nil { + return nil, err + } } if label != nil { - attributes[CkaLabel] = pkcs11.NewAttribute(CkaLabel, label) + err = attributes.Set(CkaLabel, label) + if err != nil { + return nil, err + } } return c.FindKeysWithAttributes(attributes) @@ -359,7 +374,10 @@ func (c *Context) FindKeysWithAttributes(attributes AttributeSet) ([]*SecretKey, err := c.withSession(func(session *pkcs11Session) error { // Add the private key class to the template to find the private half privAttributes := attributes.Copy() - privAttributes[CkaClass] = pkcs11.NewAttribute(CkaClass, pkcs11.CKO_SECRET_KEY) + err := attributes.Set(CkaClass, pkcs11.CKO_SECRET_KEY) + if err != nil { + return err + } privHandles, err := findKeysWithAttributes(session, privAttributes.ToSlice()) if err != nil { @@ -411,7 +429,10 @@ func (c *Context) getAttributes(handle pkcs11.ObjectHandle, attributes []Attribu } for _, a := range(p11values) { - values[a.Type] = pkcs11.NewAttribute(a.Type, a.Value) + err = values.Set(a.Type, a.Value) + if err != nil { + return err + } } return nil From 692befd1ce8bb440261749123df773ad08205a81 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 15:42:33 +0100 Subject: [PATCH 14/21] Do closed check before anything else at the beginning of each public function --- keys.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/keys.go b/keys.go index 32010e0..dfa2ddd 100644 --- a/keys.go +++ b/keys.go @@ -179,6 +179,10 @@ func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectH // If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned // because we cannot implement crypto.Signer without the public key. func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { + if c.closed.Get() { + return nil, errClosed + } + result, err := c.FindKeyPairs(id, label) if err != nil { return nil, err @@ -198,6 +202,10 @@ func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) { // If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned // because we cannot implement crypto.Signer without the public key. func (c *Context) FindKeyPairs(id []byte, label []byte) (signer []Signer, err error) { + if c.closed.Get() { + return nil, errClosed + } + if id == nil && label == nil { return nil, errors.New("id and label cannot both be nil") } @@ -228,6 +236,10 @@ func (c *Context) FindKeyPairs(id []byte, label []byte) (signer []Signer, err er // If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned // because we cannot implement crypto.Signer without the public key. func (c *Context) FindKeyPairWithAttributes(attributes AttributeSet) (Signer, error) { + if c.closed.Get() { + return nil, errClosed + } + result, err := c.FindKeyPairsWithAttributes(attributes) if err != nil { return nil, err @@ -291,6 +303,10 @@ func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) (signer [] // If a private key is found, but the corresponding public key is not, the key is not returned because we cannot // implement crypto.Signer without the public key. func (c *Context) FindAllKeyPairs() ([]Signer, error) { + if c.closed.Get() { + return nil, errClosed + } + return c.FindKeyPairsWithAttributes(NewAttributeSet()) } @@ -307,6 +323,10 @@ func (k pkcs11PrivateKey) Public() crypto.PublicKey { // // Either (but not both) of id and label may be nil, in which case they are ignored. func (c *Context) FindKey(id []byte, label []byte) (*SecretKey, error) { + if c.closed.Get() { + return nil, errClosed + } + result, err := c.FindKeys(id, label) if err != nil { return nil, err @@ -323,6 +343,10 @@ func (c *Context) FindKey(id []byte, label []byte) (*SecretKey, error) { // // At least one of id and label must be specified. func (c *Context) FindKeys(id []byte, label []byte) (key []*SecretKey, err error) { + if c.closed.Get() { + return nil, errClosed + } + if id == nil && label == nil { return nil, errors.New("id and label cannot both be nil") } @@ -347,6 +371,10 @@ func (c *Context) FindKeys(id []byte, label []byte) (key []*SecretKey, err error // FindKeyWithAttributes retrieves a previously created symmetric key, or nil if it cannot be found. func (c *Context) FindKeyWithAttributes(attributes AttributeSet) (*SecretKey, error) { + if c.closed.Get() { + return nil, errClosed + } + result, err := c.FindKeysWithAttributes(attributes) if err != nil { return nil, err @@ -409,6 +437,10 @@ func (c *Context) FindKeysWithAttributes(attributes AttributeSet) ([]*SecretKey, // FindAllKeyPairs retrieves all existing symmetric keys, or a nil slice if none can be found. func (c *Context) FindAllKeys() ([]*SecretKey, error) { + if c.closed.Get() { + return nil, errClosed + } + return c.FindKeysWithAttributes(NewAttributeSet()) } @@ -473,6 +505,10 @@ func (c *Context) GetAttributes(key interface{}, attributes []AttributeType) (a // // If the object is not a crypto11 key or keypair then an error is returned. func (c *Context) GetAttribute(key interface{}, attribute AttributeType) (a *Attribute, err error) { + if c.closed.Get() { + return nil, errClosed + } + set, err := c.GetAttributes(key, []AttributeType{attribute}) if err != nil { return nil, err @@ -509,6 +545,10 @@ func (c *Context) GetPubAttributes(key interface{}, attributes []AttributeType) // // If the object is not a crypto11 keypair then an error is returned. func (c *Context) GetPubAttribute(key interface{}, attribute AttributeType) (a *Attribute, err error) { + if c.closed.Get() { + return nil, errClosed + } + set, err := c.GetPubAttributes(key, []AttributeType{attribute}) if err != nil { return nil, err From af5b359fed7c1dfc70541378d2451e9f3e10b269 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 17:28:31 +0100 Subject: [PATCH 15/21] Fix mistakenly modifying the wrong attribute list --- keys.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keys.go b/keys.go index dfa2ddd..8269822 100644 --- a/keys.go +++ b/keys.go @@ -273,7 +273,7 @@ func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) (signer [] err = c.withSession(func(session *pkcs11Session) error { // Add the private key class to the template to find the private half privAttributes := attributes.Copy() - err = attributes.Set(CkaClass, pkcs11.CKO_PRIVATE_KEY) + err = privAttributes.Set(CkaClass, pkcs11.CKO_PRIVATE_KEY) if err != nil { return err } @@ -402,7 +402,7 @@ func (c *Context) FindKeysWithAttributes(attributes AttributeSet) ([]*SecretKey, err := c.withSession(func(session *pkcs11Session) error { // Add the private key class to the template to find the private half privAttributes := attributes.Copy() - err := attributes.Set(CkaClass, pkcs11.CKO_SECRET_KEY) + err := privAttributes.Set(CkaClass, pkcs11.CKO_SECRET_KEY) if err != nil { return err } From 6b8be4d630a8687ecf711fcc9b811c8ff924d90c Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 17:33:16 +0100 Subject: [PATCH 16/21] Use AttributeList.Set() in tests as well --- keys_test.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/keys_test.go b/keys_test.go index d4e652b..54e69d0 100644 --- a/keys_test.go +++ b/keys_test.go @@ -3,7 +3,6 @@ package crypto11 import ( "crypto/rand" "crypto/rsa" - "github.com/miekg/pkcs11" "testing" "github.com/stretchr/testify/assert" @@ -71,17 +70,15 @@ func TestFindingKeysWithAttributes(t *testing.T) { require.Len(t, keys, 2) attrs = NewAttributeSet() - attrs.AddIfNotPresent([]*Attribute{ - pkcs11.NewAttribute(CkaValueLen, 16), - }) + err = attrs.Set(CkaValueLen, 16) + require.NoError(t, err) keys, err = ctx.FindKeysWithAttributes(attrs) require.Len(t, keys, 2) attrs = NewAttributeSet() - attrs.AddIfNotPresent([]*Attribute{ - pkcs11.NewAttribute(CkaValueLen, 32), - }) + err = attrs.Set(CkaValueLen, 32) + require.NoError(t, err) keys, err = ctx.FindKeysWithAttributes(attrs) require.Len(t, keys, 1) @@ -121,9 +118,8 @@ func TestFindingKeyPairsWithAttributes(t *testing.T) { require.Len(t, keys, 2) attrs = NewAttributeSet() - attrs.AddIfNotPresent([]*Attribute{ - pkcs11.NewAttribute(CkaPublicExponent, []byte{1, 0, 1}), - }) + err = attrs.Set(CkaPublicExponent, []byte{1, 0, 1}) + require.NoError(t, err) keys, err = ctx.FindKeyPairsWithAttributes(attrs) require.Len(t, keys, 3) From 5ca3b2e3ef894c38ea71c07212b3e8aa8e12500a Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 17:35:01 +0100 Subject: [PATCH 17/21] Remove unnecessary parenthesis --- keys.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/keys.go b/keys.go index 8269822..73c5e34 100644 --- a/keys.go +++ b/keys.go @@ -283,7 +283,7 @@ func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) (signer [] return err } - for _, privHandle := range(privHandles) { + for _, privHandle := range privHandles { k, err := c.makeKeyPair(session, &privHandle) if err != nil { continue @@ -412,7 +412,7 @@ func (c *Context) FindKeysWithAttributes(attributes AttributeSet) ([]*SecretKey, return err } - for _, privHandle := range(privHandles) { + for _, privHandle := range privHandles { attributes := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, 0), } @@ -451,7 +451,7 @@ func (c *Context) getAttributes(handle pkcs11.ObjectHandle, attributes []Attribu err = c.withSession(func(session *pkcs11Session) error { var attrs []*pkcs11.Attribute - for _, a := range(attributes) { + for _, a := range attributes { attrs = append(attrs, pkcs11.NewAttribute(a, nil)) } @@ -460,7 +460,7 @@ func (c *Context) getAttributes(handle pkcs11.ObjectHandle, attributes []Attribu return err } - for _, a := range(p11values) { + for _, a := range p11values { err = values.Set(a.Type, a.Value) if err != nil { return err From 6d3df30e7b3b8fb040ebe7173f628b326a20a450 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 17:37:49 +0100 Subject: [PATCH 18/21] Use AttributeSet.AddIfNotPresent() instead of a manual loop --- keys.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/keys.go b/keys.go index 73c5e34..e5ecb09 100644 --- a/keys.go +++ b/keys.go @@ -460,12 +460,7 @@ func (c *Context) getAttributes(handle pkcs11.ObjectHandle, attributes []Attribu return err } - for _, a := range p11values { - err = values.Set(a.Type, a.Value) - if err != nil { - return err - } - } + values.AddIfNotPresent(p11values) return nil }) From afc7e83647ee5f333cf415854c152036f59094d9 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Mon, 19 Aug 2019 17:44:24 +0100 Subject: [PATCH 19/21] Remove unnecessary nil checks from key generation in tests --- keys_test.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/keys_test.go b/keys_test.go index 54e69d0..3fb0798 100644 --- a/keys_test.go +++ b/keys_test.go @@ -44,17 +44,14 @@ func TestFindingKeysWithAttributes(t *testing.T) { key, err := ctx.GenerateSecretKey(id, 128, CipherAES) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() key, err = ctx.GenerateSecretKey(id2, 128, CipherAES) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() key, err = ctx.GenerateSecretKey(id2, 256, CipherAES) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() attrs, err := NewAttributeSetWithID(id) @@ -92,17 +89,14 @@ func TestFindingKeyPairsWithAttributes(t *testing.T) { key, err := ctx.GenerateRSAKeyPair(id, 1024) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() key, err = ctx.GenerateRSAKeyPair(id2, 1024) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() key, err = ctx.GenerateRSAKeyPair(id2, 2048) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() attrs, err := NewAttributeSetWithID(id) @@ -132,7 +126,6 @@ func TestFindingAllKeys(t *testing.T) { id := randomBytes() key, err := ctx.GenerateSecretKey(id, 128, CipherAES) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() } @@ -151,7 +144,6 @@ func TestFindingAllKeyPairs(t *testing.T) { id := randomBytes() key, err := ctx.GenerateRSAKeyPair(id, 1024) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() } @@ -170,7 +162,6 @@ func TestGettingPrivateKeyAttributes(t *testing.T) { key, err := ctx.GenerateRSAKeyPair(id, 1024) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() attrs, err := ctx.GetAttributes(key, []AttributeType{CkaModulus}) @@ -188,7 +179,6 @@ func TestGettingPublicKeyAttributes(t *testing.T) { key, err := ctx.GenerateRSAKeyPair(id, 1024) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() attrs, err := ctx.GetPubAttributes(key, []AttributeType{CkaModulusBits}) @@ -206,7 +196,6 @@ func TestGettingSecretKeyAttributes(t *testing.T) { key, err := ctx.GenerateSecretKey(id, 128, CipherAES) require.NoError(t, err) - require.NotNil(t, key) defer key.Delete() attrs, err := ctx.GetAttributes(key, []AttributeType{CkaValueLen}) From 940db92386c7c59e14d91adc20466c46eef27f8c Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Thu, 22 Aug 2019 11:59:08 +0100 Subject: [PATCH 20/21] Missing error check --- keys.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/keys.go b/keys.go index e5ecb09..b07507e 100644 --- a/keys.go +++ b/keys.go @@ -86,6 +86,9 @@ func findKeys(session *pkcs11Session, id []byte, label []byte, keyclass *uint, k // callers will call it twice. Returns nil if the key does not exist on the token. func findKey(session *pkcs11Session, id []byte, label []byte, keyclass *uint, keytype *uint) (obj *pkcs11.ObjectHandle, err error) { handles, err := findKeys(session, id, label, keyclass, keytype) + if err != nil { + return nil, err + } if len(handles) == 0 { return nil, nil From c074415f6ab24bde23e3df4bb9737252c7af78e2 Mon Sep 17 00:00:00 2001 From: Sean Burton Date: Thu, 22 Aug 2019 11:59:25 +0100 Subject: [PATCH 21/21] Only skip keys on specific errors (no CKA_ID or no public half), but fail hard on any other unexpected errors --- keys.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/keys.go b/keys.go index b07507e..88e3d8c 100644 --- a/keys.go +++ b/keys.go @@ -29,6 +29,12 @@ import ( const maxHandlePerFind = 20 +// errNoCkaId is returned if a private key is found which has no CKA_ID attribute +var errNoCkaId = errors.New("private key has no CKA_ID") + +// errNoPublicHalf is returned if a public half cannot be found to match a given private key +var errNoPublicHalf = errors.New("could not find public key to match private key") + func findKeysWithAttributes(session *pkcs11Session, template []*pkcs11.Attribute) (handles []pkcs11.ObjectHandle, err error) { if err = session.ctx.FindObjectsInit(session.handle, template); err != nil { return nil, err @@ -113,7 +119,7 @@ func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectH // Ensure the private key actually has a non-empty CKA_ID to match on if id == nil || len(id) == 0 { - return nil, errors.New("private key has no CKA_ID") + return nil, errNoCkaId } // Find the public half which has a matching CKA_ID @@ -123,7 +129,7 @@ func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectH } if pubHandle == nil { // We can't return a Signer if we don't have private and public key. Treat it as an error. - return nil, errors.New("could not find public key to match private key") + return nil, errNoPublicHalf } var pub crypto.PublicKey @@ -288,9 +294,13 @@ func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) (signer [] for _, privHandle := range privHandles { k, err := c.makeKeyPair(session, &privHandle) - if err != nil { + + if err == errNoCkaId || err == errNoPublicHalf { continue } + if err != nil { + return err + } keys = append(keys, k) }