From f2bef3a72406caf2ae868b9db096dfc8384d0371 Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Sun, 29 Sep 2024 22:35:55 +0200 Subject: [PATCH 1/8] PKCS#11 untested --- .gitignore | 11 +- go.mod | 17 +-- go.sum | 36 +++--- pkg/vault/memory/vault.go | 24 +++- pkg/vault/pkcs11/vault.go | 230 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 277 insertions(+), 41 deletions(-) create mode 100644 pkg/vault/pkcs11/vault.go diff --git a/.gitignore b/.gitignore index 4864a9bf..beb5f9ae 100644 --- a/.gitignore +++ b/.gitignore @@ -22,12 +22,11 @@ dist .release-env .env .docker-creds -./signatory -./signatory-cli +/signatory +/signatory-cli .DS_Store # some integration_tests write secret env var to files -integration_test/gcp-token.json -integration_test/.env.vaults.cicd -integration_test/service-principal.key -**vault** \ No newline at end of file +/integration_test/gcp-token.json +/integration_test/.env.vaults.cicd +/integration_test/service-principal.key \ No newline at end of file diff --git a/go.mod b/go.mod index af1ac739..e38df865 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,14 @@ module github.com/ecadlabs/signatory -go 1.21 +go 1.22 + +toolchain go1.23.1 require ( cloud.google.com/go/kms v1.15.5 github.com/certusone/yubihsm-go v0.3.0 - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 + github.com/ecadlabs/go-pkcs11 v0.1.4 github.com/ecadlabs/goblst v1.0.0 github.com/ecadlabs/gotez/v2 v2.0.6 github.com/go-playground/validator/v10 v10.16.0 @@ -20,7 +23,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 - golang.org/x/crypto v0.23.0 + golang.org/x/crypto v0.27.0 golang.org/x/exp v0.0.0-20231127185646-65229373498e golang.org/x/oauth2 v0.15.0 google.golang.org/api v0.152.0 @@ -54,7 +57,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - golang.org/x/sync v0.5.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231127180814-3a041ad873d4 // indirect @@ -82,9 +85,9 @@ require ( github.com/spf13/pflag v1.0.5 // indirect go.opencensus.io v0.24.0 // indirect golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/term v0.20.0 - golang.org/x/text v0.15.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 + golang.org/x/text v0.18.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index 9ed84589..92b34cd7 100644 --- a/go.sum +++ b/go.sum @@ -31,12 +31,12 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/ecadlabs/go-pkcs11 v0.1.4 h1:o2WMEeoNCqU0WzVJG9stmH3anDOyfx8yRyFzJ5hMmZk= +github.com/ecadlabs/go-pkcs11 v0.1.4/go.mod h1:PwcQJwjNjjE0WtXtkTv4E0JNIcbl3cdIw+J+pRQbVjE= github.com/ecadlabs/goblst v1.0.0 h1:8/e3SQGwqbV0+ul+pg0aSNFfC3lgQcvEed3VdDBXSl8= github.com/ecadlabs/goblst v1.0.0/go.mod h1:s67gqaOol9o6fguh+evH75X5uQniOhv1HG/EU8xPLPY= -github.com/ecadlabs/gotez/v2 v2.0.5 h1:RmpCEKYlQD18TtL9vjSDRe3FYADhxlKh80DZQz8h31Q= -github.com/ecadlabs/gotez/v2 v2.0.5/go.mod h1:QypK0m1eDPmB9R7Uvgmsfm+JS7Z5Y6dIbIq1tMVYayU= github.com/ecadlabs/gotez/v2 v2.0.6 h1:P7eQ2G+SO1tTV4NHnkdNlrOHxKDo1iF9m34HTLfS3b8= github.com/ecadlabs/gotez/v2 v2.0.6/go.mod h1:QypK0m1eDPmB9R7Uvgmsfm+JS7Z5Y6dIbIq1tMVYayU= github.com/ecadlabs/pretty v0.0.0-20230412124801-f948fc689a04 h1:7WdblGykGxtGGtchW4kzTaJJO8Fm+JKhLzhttOOWr9k= @@ -222,10 +222,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= @@ -253,8 +251,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -270,26 +268,20 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= diff --git a/pkg/vault/memory/vault.go b/pkg/vault/memory/vault.go index 619c1290..4a0d25bc 100644 --- a/pkg/vault/memory/vault.go +++ b/pkg/vault/memory/vault.go @@ -19,6 +19,10 @@ type PrivateKey struct { KeyID string } +func (p *PrivateKey) Elem() (key vault.StoredKey, err error) { + return p, nil +} + // PublicKey get the public key associated with this key func (f *PrivateKey) PublicKey() crypt.PublicKey { return f.PrivateKey.Public() @@ -44,18 +48,26 @@ type Vault struct { unlocked bool } -type iterator struct { - keys []*PrivateKey +type IteratorElem interface { + Elem() (key vault.StoredKey, err error) +} + +type Iterator[T IteratorElem] struct { + keys []T idx int } -func (i *iterator) Next() (key vault.StoredKey, err error) { +func NewIterator[T IteratorElem](keys []T) *Iterator[T] { + return &Iterator[T]{keys: keys} +} + +func (i *Iterator[T]) Next() (key vault.StoredKey, err error) { if i.idx == len(i.keys) { return nil, vault.ErrDone } - key = i.keys[i.idx] + key, err = i.keys[i.idx].Elem() i.idx++ - return key, nil + return key, err } // NewUnparsed create a new in-mempory vault from Tezos encoded data. Call Unlock before use @@ -108,7 +120,7 @@ func New(src []*PrivateKey, name string) (*Vault, error) { func (v *Vault) ListPublicKeys(ctx context.Context) vault.StoredKeysIterator { v.mtx.Lock() defer v.mtx.Unlock() - return &iterator{keys: v.keys} + return &Iterator[*PrivateKey]{keys: v.keys} } // GetPublicKey retrieve a public key diff --git a/pkg/vault/pkcs11/vault.go b/pkg/vault/pkcs11/vault.go new file mode 100644 index 00000000..d766bb44 --- /dev/null +++ b/pkg/vault/pkcs11/vault.go @@ -0,0 +1,230 @@ +package pkcs11 + +import ( + "context" + "encoding/hex" + stderr "errors" + "fmt" + "net/http" + "os" + "strconv" + + "github.com/ecadlabs/go-pkcs11/pkcs11" + "github.com/ecadlabs/gotez/v2/crypt" + "github.com/ecadlabs/signatory/pkg/errors" + "github.com/ecadlabs/signatory/pkg/vault" + "github.com/ecadlabs/signatory/pkg/vault/memory" + "gopkg.in/yaml.v3" +) + +type PKCS11Vault struct { + module *pkcs11.Module + slot *pkcs11.Slot + info pkcs11.Info + conf Config +} + +type Config struct { + LibraryPath string `yaml:"library_path"` + Pin string `yaml:"pin"` + Slot uint `yaml:"slot"` + Label string `yaml:"label"` + ObjectID string `yaml:"object_id"` +} + +type iterElem struct { + obj *pkcs11.Object + v *PKCS11Vault +} + +func (i *iterElem) Elem() (vault.StoredKey, error) { + pk, err := i.obj.PrivateKey() + if err != nil { + return nil, i.v.formatError(err) + } + kp, err := pk.KeyPair() + if err != nil { + return nil, i.v.formatError(err) + } + key := &keyPair{ + obj: i.obj, + kp: kp, + } + return key, nil +} + +type keyPair struct { + obj *pkcs11.Object + kp pkcs11.KeyPair +} + +func (p *keyPair) ID() string { + return fmt.Sprintf("%08x", p.obj.Handle()) +} + +func (p *keyPair) PublicKey() crypt.PublicKey { + pub, err := crypt.NewPublicKeyFrom(p.kp.Public()) + if err != nil { + panic(err) // shouldn't happen + } + return pub +} + +func (v *PKCS11Vault) formatError(err error) error { + return fmt.Errorf("(PKCS#11/%s %d.%d): %w", v.info.Manufacturer, v.info.Version.Major, v.info.Version.Minor, err) +} + +const ( + envLibraryPath = "PKCS11_PATH" + envPin = "PKCS11_PIN" + envSlot = "PKCS11_SLOT" + envLabel = "PKCS11_LABEL" + envObjID = "PKCS11_OBJECT_ID" +) + +func New(ctx context.Context, config *Config) (*PKCS11Vault, error) { + conf := *config + if conf.LibraryPath == "" { + conf.LibraryPath = os.Getenv(envLibraryPath) + } + if conf.Pin == "" { + conf.Pin = os.Getenv(envPin) + } + if conf.Label == "" { + conf.Label = os.Getenv(envLabel) + } + if conf.ObjectID == "" { + conf.ObjectID = os.Getenv(envObjID) + } + + module, err := pkcs11.Open(config.LibraryPath) + if err != nil { + return nil, fmt.Errorf("(PKCS#11/%s): %w", config.LibraryPath, err) + } + v := PKCS11Vault{ + module: module, + info: module.Info(), + conf: conf, + } + return &v, nil +} + +type errIterator struct { + err error +} + +func (e errIterator) Next() (vault.StoredKey, error) { + return nil, e.err +} + +// GetPublicKey returns a public key by given ID +func (v *PKCS11Vault) ListPublicKeys(ctx context.Context) vault.StoredKeysIterator { + if v.slot == nil { + return errIterator{v.formatError(errors.New("locked"))} + } + + filter := []pkcs11.Filter{ + pkcs11.FilterClass(pkcs11.ClassPrivateKey), + pkcs11.FilterKeyType(pkcs11.KeyTypeEC), + } + if v.conf.Label != "" { + filter = append(filter, pkcs11.FilterLabel(v.conf.Label)) + } + if v.conf.ObjectID != "" { + id, err := hex.DecodeString(v.conf.ObjectID) + if err != nil { + return errIterator{v.formatError(err)} + } + filter = append(filter, pkcs11.FilterID(id)) + } + + objects, err := v.slot.Objects(filter...) + if err != nil { + return errIterator{v.formatError(err)} + } + + elems := make([]*iterElem, len(objects)) + for i, o := range objects { + elems[i] = &iterElem{ + obj: o, + v: v, + } + } + return memory.NewIterator(elems) +} + +func (v *PKCS11Vault) GetPublicKey(ctx context.Context, id string) (vault.StoredKey, error) { + if v.slot == nil { + return nil, v.formatError(errors.New("locked")) + } + handle, err := strconv.ParseUint(id, 16, 64) + if err != nil { + return nil, v.formatError(err) + } + obj, err := v.slot.NewObject(uint(handle)) + if err != nil { + if stderr.Is(err, pkcs11.ErrObjectHandleInvalid) { + return nil, errors.Wrap(v.formatError(err), http.StatusNotFound) + } + return nil, v.formatError(err) + } + pk, err := obj.PrivateKey() + if err != nil { + return nil, v.formatError(err) + } + kp, err := pk.KeyPair() + if err != nil { + return nil, v.formatError(err) + } + key := &keyPair{ + obj: obj, + kp: kp, + } + return key, nil +} + +func (v *PKCS11Vault) SignMessage(ctx context.Context, msg []byte, key vault.StoredKey) (crypt.Signature, error) { + if v.slot == nil { + return nil, v.formatError(errors.New("locked")) + } + kp, ok := key.(*keyPair) + if !ok { + return nil, v.formatError(fmt.Errorf("invalid key type %T", key)) + } + digest := crypt.DigestFunc(msg) + sig, err := kp.kp.Sign(nil, digest[:], nil) + if err != nil { + return nil, v.formatError(err) + } + ret, err := crypt.NewSignatureFromBytes(sig, kp.PublicKey()) + if err != nil { + return nil, v.formatError(err) + } + return ret, nil +} + +func (v *PKCS11Vault) Unlock(ctx context.Context) error { + slot, err := v.module.Slot(v.conf.Slot, pkcs11.OptUserPIN(v.conf.Pin)) + if err != nil { + return v.formatError(err) + } + v.slot = slot + return nil +} + +func (c *PKCS11Vault) Name() string { + return "PKCS#11" +} + +func init() { + vault.RegisterVault("pkcs11", func(ctx context.Context, node *yaml.Node) (vault.Vault, error) { + var conf Config + if node == nil { + return nil, errors.New("(PKCS#11): config is missing") + } + if err := node.Decode(&conf); err != nil { + return nil, err + } + return New(ctx, &conf) + }) +} From 658869d6d8fc1ede4023650daee7307ee85a929e Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Wed, 2 Oct 2024 23:38:51 +0300 Subject: [PATCH 2/8] PKCS#11 test --- cmd/signatory-cli/main.go | 1 + cmd/signatory/main.go | 1 + go.mod | 3 +- go.sum | 4 +- pkg/vault/pkcs11/pkcs11_test.go | 94 ++++++++++++++++++++++++++++++++ pkg/vault/pkcs11/vault.go | 96 ++++++++++++++++++++++++++------- pkg/vault/vault.go | 20 +++++++ 7 files changed, 198 insertions(+), 21 deletions(-) create mode 100644 pkg/vault/pkcs11/pkcs11_test.go diff --git a/cmd/signatory-cli/main.go b/cmd/signatory-cli/main.go index 3b50f530..3e036b27 100644 --- a/cmd/signatory-cli/main.go +++ b/cmd/signatory-cli/main.go @@ -19,6 +19,7 @@ import ( _ "github.com/ecadlabs/signatory/pkg/vault/hashicorp" _ "github.com/ecadlabs/signatory/pkg/vault/ledger" _ "github.com/ecadlabs/signatory/pkg/vault/mem" + _ "github.com/ecadlabs/signatory/pkg/vault/pkcs11" _ "github.com/ecadlabs/signatory/pkg/vault/yubi" ) diff --git a/cmd/signatory/main.go b/cmd/signatory/main.go index ae9048f0..593246f2 100644 --- a/cmd/signatory/main.go +++ b/cmd/signatory/main.go @@ -18,6 +18,7 @@ import ( _ "github.com/ecadlabs/signatory/pkg/vault/hashicorp" _ "github.com/ecadlabs/signatory/pkg/vault/ledger" _ "github.com/ecadlabs/signatory/pkg/vault/mem" + _ "github.com/ecadlabs/signatory/pkg/vault/pkcs11" _ "github.com/ecadlabs/signatory/pkg/vault/yubi" ) diff --git a/go.mod b/go.mod index e38df865..aa28f144 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( cloud.google.com/go/kms v1.15.5 github.com/certusone/yubihsm-go v0.3.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 - github.com/ecadlabs/go-pkcs11 v0.1.4 + github.com/ecadlabs/go-pkcs11 v0.1.6 github.com/ecadlabs/goblst v1.0.0 github.com/ecadlabs/gotez/v2 v2.0.6 github.com/go-playground/validator/v10 v10.16.0 @@ -94,3 +94,4 @@ require ( ) // replace github.com/ecadlabs/gotez/v2 => ../gotez +// replace github.com/ecadlabs/go-pkcs11 => ../go-pkcs11 diff --git a/go.sum b/go.sum index 92b34cd7..14e66d6d 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/ecadlabs/go-pkcs11 v0.1.4 h1:o2WMEeoNCqU0WzVJG9stmH3anDOyfx8yRyFzJ5hMmZk= -github.com/ecadlabs/go-pkcs11 v0.1.4/go.mod h1:PwcQJwjNjjE0WtXtkTv4E0JNIcbl3cdIw+J+pRQbVjE= +github.com/ecadlabs/go-pkcs11 v0.1.6 h1:YnskuaCjLHoY9Y3sdUxB4POlTApsmZAdc0yw7AKPpUU= +github.com/ecadlabs/go-pkcs11 v0.1.6/go.mod h1:PwcQJwjNjjE0WtXtkTv4E0JNIcbl3cdIw+J+pRQbVjE= github.com/ecadlabs/goblst v1.0.0 h1:8/e3SQGwqbV0+ul+pg0aSNFfC3lgQcvEed3VdDBXSl8= github.com/ecadlabs/goblst v1.0.0/go.mod h1:s67gqaOol9o6fguh+evH75X5uQniOhv1HG/EU8xPLPY= github.com/ecadlabs/gotez/v2 v2.0.6 h1:P7eQ2G+SO1tTV4NHnkdNlrOHxKDo1iF9m34HTLfS3b8= diff --git a/pkg/vault/pkcs11/pkcs11_test.go b/pkg/vault/pkcs11/pkcs11_test.go new file mode 100644 index 00000000..07b46094 --- /dev/null +++ b/pkg/vault/pkcs11/pkcs11_test.go @@ -0,0 +1,94 @@ +package pkcs11 + +import ( + "context" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "testing" + + "github.com/ecadlabs/gotez/v2/crypt" + "github.com/ecadlabs/signatory/pkg/vault" + "github.com/stretchr/testify/require" +) + +const ( + libSoftHSMPathUnix = "/usr/lib/softhsm/libsofthsm2.so" + libSoftHSMPathMac = "/opt/homebrew/lib/softhsm/libsofthsm2.so" + + userPIN = "1234" + soPIN = "1234" + keyLabel = "TestKey" + tokenLabel = "TestToken" +) + +func TestPKCS11Vault(t *testing.T) { + var path string + if runtime.GOOS == "darwin" { + path = libSoftHSMPathMac + } else { + path = libSoftHSMPathUnix + } + + if _, err := os.Stat(path); err != nil { + if errors.Is(err, os.ErrNotExist) { + t.Skipf("libsofthsm2 not installed, skipping testing") + } + t.Fatal(err) + } + + if _, err := exec.LookPath("pkcs11-tool"); err != nil { + if errors.Is(err, exec.ErrNotFound) { + t.Skipf("pkcs11-tool not installed, skipping testing") + } + t.Fatal(err) + } + + configPath := filepath.Join(t.TempDir(), "softhsm.conf") + tokensPath := t.TempDir() + + fd, err := os.OpenFile(configPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) + require.NoError(t, err) + fmt.Fprintf(fd, "directories.tokendir = %s\n", tokensPath) + fd.Close() + + t.Setenv("SOFTHSM2_CONF", configPath) + + out, err := exec.Command("pkcs11-tool", "--verbose", "--module", path, "--init-token", "--label", tokenLabel, "--so-pin", soPIN).CombinedOutput() + if err != nil { + t.Fatal(string(out)) + } + + out, err = exec.Command("pkcs11-tool", "--verbose", "--module", path, "--login", "--so-pin", soPIN, "--init-pin", "--pin", userPIN).CombinedOutput() + if err != nil { + t.Fatal(string(out)) + } + + out, err = exec.Command("pkcs11-tool", "--verbose", "--module", path, "--login", "--pin", userPIN, "--keypairgen", "--key-type", "EC:prime256v1", "--usage-sign", "--label", keyLabel).CombinedOutput() + if err != nil { + t.Fatal(string(out)) + } + + v, err := New(context.Background(), &Config{ + LibraryPath: path, + Pin: userPIN, + Label: keyLabel, + }) + require.NoError(t, err) + t.Cleanup(func() { v.Close() }) + + require.NoError(t, v.Unlock(context.Background())) + + keys, err := vault.Collect(v.ListPublicKeys(context.Background())) + require.NoError(t, err) + require.Len(t, keys, 1) + k0 := keys[0].PublicKey().(*crypt.ECDSAPublicKey) + + key, err := v.GetPublicKey(context.Background(), keys[0].ID()) + require.NoError(t, err) + k1 := key.PublicKey().(*crypt.ECDSAPublicKey) + require.Equal(t, k0, k1) +} diff --git a/pkg/vault/pkcs11/vault.go b/pkg/vault/pkcs11/vault.go index d766bb44..355787a0 100644 --- a/pkg/vault/pkcs11/vault.go +++ b/pkg/vault/pkcs11/vault.go @@ -14,22 +14,23 @@ import ( "github.com/ecadlabs/signatory/pkg/errors" "github.com/ecadlabs/signatory/pkg/vault" "github.com/ecadlabs/signatory/pkg/vault/memory" + log "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" ) type PKCS11Vault struct { module *pkcs11.Module slot *pkcs11.Slot - info pkcs11.Info + info *pkcs11.ModuleInfo conf Config } type Config struct { - LibraryPath string `yaml:"library_path"` - Pin string `yaml:"pin"` - Slot uint `yaml:"slot"` - Label string `yaml:"label"` - ObjectID string `yaml:"object_id"` + LibraryPath string + Pin string + Slot *uint + Label string + ObjectID []byte } type iterElem struct { @@ -71,7 +72,7 @@ func (p *keyPair) PublicKey() crypt.PublicKey { } func (v *PKCS11Vault) formatError(err error) error { - return fmt.Errorf("(PKCS#11/%s %d.%d): %w", v.info.Manufacturer, v.info.Version.Major, v.info.Version.Minor, err) + return fmt.Errorf("(PKCS#11/%s %v): %w", v.info.Manufacturer, v.info.Version, err) } const ( @@ -93,14 +94,21 @@ func New(ctx context.Context, config *Config) (*PKCS11Vault, error) { if conf.Label == "" { conf.Label = os.Getenv(envLabel) } - if conf.ObjectID == "" { - conf.ObjectID = os.Getenv(envObjID) + if conf.ObjectID == nil { + if v := os.Getenv(envObjID); v != "" { + id, err := hex.DecodeString(v) + if err != nil { + return nil, err + } + conf.ObjectID = id + } } module, err := pkcs11.Open(config.LibraryPath) if err != nil { return nil, fmt.Errorf("(PKCS#11/%s): %w", config.LibraryPath, err) } + log.Debug(module.Info()) v := PKCS11Vault{ module: module, info: module.Info(), @@ -109,6 +117,13 @@ func New(ctx context.Context, config *Config) (*PKCS11Vault, error) { return &v, nil } +func (v *PKCS11Vault) Close() error { + if err := v.slot.Close(); err != nil { + return err + } + return v.module.Close() +} + type errIterator struct { err error } @@ -130,12 +145,8 @@ func (v *PKCS11Vault) ListPublicKeys(ctx context.Context) vault.StoredKeysIterat if v.conf.Label != "" { filter = append(filter, pkcs11.FilterLabel(v.conf.Label)) } - if v.conf.ObjectID != "" { - id, err := hex.DecodeString(v.conf.ObjectID) - if err != nil { - return errIterator{v.formatError(err)} - } - filter = append(filter, pkcs11.FilterID(id)) + if v.conf.ObjectID != nil { + filter = append(filter, pkcs11.FilterID(v.conf.ObjectID)) } objects, err := v.slot.Objects(filter...) @@ -204,7 +215,28 @@ func (v *PKCS11Vault) SignMessage(ctx context.Context, msg []byte, key vault.Sto } func (v *PKCS11Vault) Unlock(ctx context.Context) error { - slot, err := v.module.Slot(v.conf.Slot, pkcs11.OptUserPIN(v.conf.Pin)) + if v.conf.Slot == nil { + // use first slot with a token + slots, err := v.module.SlotIDs() + if err != nil { + return v.formatError(err) + } + for _, s := range slots { + si, err := v.module.SlotInfo(s) + if err != nil { + return v.formatError(err) + } + if si.Token != nil { + v.conf.Slot = &s + break + } + } + if v.conf.Slot == nil { + return v.formatError(errors.New("Token not found")) + } + } + + slot, err := v.module.Slot(*v.conf.Slot, pkcs11.OptUserPIN(v.conf.Pin)) if err != nil { return v.formatError(err) } @@ -216,15 +248,43 @@ func (c *PKCS11Vault) Name() string { return "PKCS#11" } +func (c *PKCS11Vault) VaultName() string { + return fmt.Sprintf("%s %v", c.info.Manufacturer, c.info.Version) +} + +type yamlConfig struct { + LibraryPath string `yaml:"library_path"` + Pin string `yaml:"pin"` + Slot uint `yaml:"slot"` + Label string `yaml:"label"` + ObjectID string `yaml:"object_id"` +} + func init() { vault.RegisterVault("pkcs11", func(ctx context.Context, node *yaml.Node) (vault.Vault, error) { - var conf Config + var yamlConf yamlConfig if node == nil { return nil, errors.New("(PKCS#11): config is missing") } - if err := node.Decode(&conf); err != nil { + if err := node.Decode(&yamlConf); err != nil { return nil, err } + conf := Config{ + LibraryPath: yamlConf.LibraryPath, + Pin: yamlConf.Pin, + Slot: &yamlConf.Slot, + Label: yamlConf.Label, + } + if yamlConf.ObjectID != "" { + var err error + conf.ObjectID, err = hex.DecodeString(yamlConf.ObjectID) + if err != nil { + return nil, err + } + } + return New(ctx, &conf) }) } + +var _ vault.VaultNamer = (*PKCS11Vault)(nil) diff --git a/pkg/vault/vault.go b/pkg/vault/vault.go index 1f770b5d..f879e800 100644 --- a/pkg/vault/vault.go +++ b/pkg/vault/vault.go @@ -99,4 +99,24 @@ func Commands() []*cobra.Command { return commands } +func Collect(it StoredKeysIterator) ([]StoredKey, error) { + var keys []StoredKey +keyLoop: + for { + key, err := it.Next() + if err != nil { + switch { + case errors.Is(err, ErrDone): + break keyLoop + case errors.Is(err, ErrKey): + continue keyLoop + default: + return nil, err + } + } + keys = append(keys, key) + } + return keys, nil +} + var _ Factory = (registry)(nil) From 439e48d85478cbb38e7448db4b597d0393638d7b Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Wed, 2 Oct 2024 23:55:24 +0300 Subject: [PATCH 3/8] PKCS#11 doc --- docs/pkcs11.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/pkcs11.md diff --git a/docs/pkcs11.md b/docs/pkcs11.md new file mode 100644 index 00000000..fdc82aa7 --- /dev/null +++ b/docs/pkcs11.md @@ -0,0 +1,36 @@ +--- +id: pkcs11 +title: PKCS#11 +--- + +# PKCS#11 Vault + +## Configuration + +||||| +|--- |--- |--- |--- | +|Name|Type|Required|Description| +|library_path|string|✅|Library Path| +|pin|string|✅|User PIN| +|slot|string||Slot ID| +|label|string||Limit key search to the specified label (use in case of multiple key pairs in the same token)| +|object_ih|hex||Limit key search to the specified object ID (use in case of multiple key pairs in the same token)| + +**Note**: If the token contains multiple key pairs, every pair must have unique label or ID shared between private and public parts. + +### Example + +```yaml +library_path: /opt/homebrew/lib/softhsm/libsofthsm2.so +pin: 1234 +slot: 0x4d0b85a2 +label: TestKey +``` + +## Environment variables + +* `PKCS11_PATH` +* `PKCS11_PIN` +* `PKCS11_SLOT` +* `PKCS11_LABEL` +* `PKCS11_OBJECT_ID` From 70f7e04ed9b6a55dd6a4313279388760775b0712 Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Thu, 10 Oct 2024 22:53:57 +0300 Subject: [PATCH 4/8] missing docs --- README.md | 2 ++ docs/start.md | 1 + 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index 5a7b15e8..6f7d3e14 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ In the first year of the Tezos network operation, there was anecdotal evidence t | AWS KMS | ✅ | | Ledger Nano S/S+ (Baking only) | ✅ | | Hashicorp Vault | ✅ | +| PKCS#11 | ✅ | ### Tezos Address Types @@ -90,6 +91,7 @@ In Tezos, you can infer the signing algorithm from the first three characters of | AWS KMS | ❌ | ✅ | ✅ | | Azure KMS | ❌ | ✅ | ✅ | | YubiHSM2 | ✅ | ✅ | ✅ | +| PKCS#11 | ❌ | ✅ | ✅ | --- diff --git a/docs/start.md b/docs/start.md index 4f55bc19..7863408c 100644 --- a/docs/start.md +++ b/docs/start.md @@ -151,6 +151,7 @@ tezos: * [GCP Key Management](gcp_kms.md) * [YubiHSM2](yubihsm.md) * [Hashicorp Vault](hashicorp_vault.md) +* [PKCS#11](pkcs11.md) --- From 9825b45c40858367674565f77b5c38cb890aa678 Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Thu, 10 Oct 2024 22:54:36 +0300 Subject: [PATCH 5/8] limit PKCS#11 handle parsing to 32 bit --- pkg/vault/pkcs11/vault.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vault/pkcs11/vault.go b/pkg/vault/pkcs11/vault.go index 355787a0..fdf2ada6 100644 --- a/pkg/vault/pkcs11/vault.go +++ b/pkg/vault/pkcs11/vault.go @@ -168,7 +168,7 @@ func (v *PKCS11Vault) GetPublicKey(ctx context.Context, id string) (vault.Stored if v.slot == nil { return nil, v.formatError(errors.New("locked")) } - handle, err := strconv.ParseUint(id, 16, 64) + handle, err := strconv.ParseUint(id, 16, 32) if err != nil { return nil, v.formatError(err) } From 02c1f293158ba541bbcfdfb25fd97fb1cb1406fa Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Mon, 14 Oct 2024 00:03:29 +0300 Subject: [PATCH 6/8] Ed25519 support for PKCS#11 backend --- README.md | 2 +- go.mod | 12 +++++----- go.sum | 24 +++++++++---------- pkg/vault/pkcs11/vault.go | 49 +++++++++++++++++++++------------------ 4 files changed, 46 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 6f7d3e14..d9164a10 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ In Tezos, you can infer the signing algorithm from the first three characters of | AWS KMS | ❌ | ✅ | ✅ | | Azure KMS | ❌ | ✅ | ✅ | | YubiHSM2 | ✅ | ✅ | ✅ | -| PKCS#11 | ❌ | ✅ | ✅ | +| PKCS#11 | ✅ | ✅ | ✅ | --- diff --git a/go.mod b/go.mod index aa28f144..58055437 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( cloud.google.com/go/kms v1.15.5 github.com/certusone/yubihsm-go v0.3.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 - github.com/ecadlabs/go-pkcs11 v0.1.6 + github.com/ecadlabs/go-pkcs11 v0.2.0 github.com/ecadlabs/goblst v1.0.0 github.com/ecadlabs/gotez/v2 v2.0.6 github.com/go-playground/validator/v10 v10.16.0 @@ -22,8 +22,8 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 - github.com/stretchr/testify v1.8.4 - golang.org/x/crypto v0.27.0 + github.com/stretchr/testify v1.9.0 + golang.org/x/crypto v0.28.0 golang.org/x/exp v0.0.0-20231127185646-65229373498e golang.org/x/oauth2 v0.15.0 google.golang.org/api v0.152.0 @@ -85,9 +85,9 @@ require ( github.com/spf13/pflag v1.0.5 // indirect go.opencensus.io v0.24.0 // indirect golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.24.0 - golang.org/x/text v0.18.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 + golang.org/x/text v0.19.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index 14e66d6d..c581d91c 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/ecadlabs/go-pkcs11 v0.1.6 h1:YnskuaCjLHoY9Y3sdUxB4POlTApsmZAdc0yw7AKPpUU= -github.com/ecadlabs/go-pkcs11 v0.1.6/go.mod h1:PwcQJwjNjjE0WtXtkTv4E0JNIcbl3cdIw+J+pRQbVjE= +github.com/ecadlabs/go-pkcs11 v0.2.0 h1:/WWqMUWFOFr9j5O4E6LEort0YiqEeHriFtvwbtpCwNo= +github.com/ecadlabs/go-pkcs11 v0.2.0/go.mod h1:PwAVBY0muwp6quQFmSDcB5Ekl4TjGG7cEQQwY9KpNVc= github.com/ecadlabs/goblst v1.0.0 h1:8/e3SQGwqbV0+ul+pg0aSNFfC3lgQcvEed3VdDBXSl8= github.com/ecadlabs/goblst v1.0.0/go.mod h1:s67gqaOol9o6fguh+evH75X5uQniOhv1HG/EU8xPLPY= github.com/ecadlabs/gotez/v2 v2.0.6 h1:P7eQ2G+SO1tTV4NHnkdNlrOHxKDo1iF9m34HTLfS3b8= @@ -211,8 +211,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -222,8 +222,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= @@ -268,20 +268,20 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= diff --git a/pkg/vault/pkcs11/vault.go b/pkg/vault/pkcs11/vault.go index fdf2ada6..8b558fa5 100644 --- a/pkg/vault/pkcs11/vault.go +++ b/pkg/vault/pkcs11/vault.go @@ -19,10 +19,10 @@ import ( ) type PKCS11Vault struct { - module *pkcs11.Module - slot *pkcs11.Slot - info *pkcs11.ModuleInfo - conf Config + module *pkcs11.Module + session *pkcs11.Session + info *pkcs11.ModuleInfo + conf Config } type Config struct { @@ -43,15 +43,21 @@ func (i *iterElem) Elem() (vault.StoredKey, error) { if err != nil { return nil, i.v.formatError(err) } - kp, err := pk.KeyPair() - if err != nil { - return nil, i.v.formatError(err) - } - key := &keyPair{ - obj: i.obj, - kp: kp, + + switch pk.(type) { + case *pkcs11.ECDSAPrivateKey, *pkcs11.Ed25519PrivateKey: + kp, err := pk.KeyPair(pkcs11.MatchLabel | pkcs11.MatchID) + if err != nil { + return nil, i.v.formatError(err) + } + key := &keyPair{ + obj: i.obj, + kp: kp, + } + return key, nil + default: + return nil, vault.ErrKey } - return key, nil } type keyPair struct { @@ -118,7 +124,7 @@ func New(ctx context.Context, config *Config) (*PKCS11Vault, error) { } func (v *PKCS11Vault) Close() error { - if err := v.slot.Close(); err != nil { + if err := v.session.Close(); err != nil { return err } return v.module.Close() @@ -134,13 +140,12 @@ func (e errIterator) Next() (vault.StoredKey, error) { // GetPublicKey returns a public key by given ID func (v *PKCS11Vault) ListPublicKeys(ctx context.Context) vault.StoredKeysIterator { - if v.slot == nil { + if v.session == nil { return errIterator{v.formatError(errors.New("locked"))} } filter := []pkcs11.Filter{ pkcs11.FilterClass(pkcs11.ClassPrivateKey), - pkcs11.FilterKeyType(pkcs11.KeyTypeEC), } if v.conf.Label != "" { filter = append(filter, pkcs11.FilterLabel(v.conf.Label)) @@ -149,7 +154,7 @@ func (v *PKCS11Vault) ListPublicKeys(ctx context.Context) vault.StoredKeysIterat filter = append(filter, pkcs11.FilterID(v.conf.ObjectID)) } - objects, err := v.slot.Objects(filter...) + objects, err := v.session.Objects(filter...) if err != nil { return errIterator{v.formatError(err)} } @@ -165,14 +170,14 @@ func (v *PKCS11Vault) ListPublicKeys(ctx context.Context) vault.StoredKeysIterat } func (v *PKCS11Vault) GetPublicKey(ctx context.Context, id string) (vault.StoredKey, error) { - if v.slot == nil { + if v.session == nil { return nil, v.formatError(errors.New("locked")) } handle, err := strconv.ParseUint(id, 16, 32) if err != nil { return nil, v.formatError(err) } - obj, err := v.slot.NewObject(uint(handle)) + obj, err := v.session.NewObject(uint(handle)) if err != nil { if stderr.Is(err, pkcs11.ErrObjectHandleInvalid) { return nil, errors.Wrap(v.formatError(err), http.StatusNotFound) @@ -183,7 +188,7 @@ func (v *PKCS11Vault) GetPublicKey(ctx context.Context, id string) (vault.Stored if err != nil { return nil, v.formatError(err) } - kp, err := pk.KeyPair() + kp, err := pk.KeyPair(pkcs11.MatchLabel | pkcs11.MatchID) if err != nil { return nil, v.formatError(err) } @@ -195,7 +200,7 @@ func (v *PKCS11Vault) GetPublicKey(ctx context.Context, id string) (vault.Stored } func (v *PKCS11Vault) SignMessage(ctx context.Context, msg []byte, key vault.StoredKey) (crypt.Signature, error) { - if v.slot == nil { + if v.session == nil { return nil, v.formatError(errors.New("locked")) } kp, ok := key.(*keyPair) @@ -236,11 +241,11 @@ func (v *PKCS11Vault) Unlock(ctx context.Context) error { } } - slot, err := v.module.Slot(*v.conf.Slot, pkcs11.OptUserPIN(v.conf.Pin)) + session, err := v.module.NewSession(*v.conf.Slot, pkcs11.OptUserPIN(v.conf.Pin)) if err != nil { return v.formatError(err) } - v.slot = slot + v.session = session return nil } From 574a7de5cac959b071671639db2d7678a0201d0b Mon Sep 17 00:00:00 2001 From: Eugene Zagidullin Date: Tue, 29 Oct 2024 23:26:48 +0200 Subject: [PATCH 7/8] go-pkcs11 v0.2.1 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 56e831b9..0984e7dd 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( cloud.google.com/go/kms v1.15.5 github.com/certusone/yubihsm-go v0.3.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 - github.com/ecadlabs/go-pkcs11 v0.2.0 + github.com/ecadlabs/go-pkcs11 v0.2.1 github.com/ecadlabs/goblst v1.0.0 github.com/ecadlabs/gotez/v2 v2.1.3 github.com/go-playground/validator/v10 v10.16.0 diff --git a/go.sum b/go.sum index 241175a5..87b61a2d 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/ecadlabs/go-pkcs11 v0.2.0 h1:/WWqMUWFOFr9j5O4E6LEort0YiqEeHriFtvwbtpCwNo= -github.com/ecadlabs/go-pkcs11 v0.2.0/go.mod h1:PwAVBY0muwp6quQFmSDcB5Ekl4TjGG7cEQQwY9KpNVc= +github.com/ecadlabs/go-pkcs11 v0.2.1 h1:/3qAVS+lTNyrlBYXq6lq+tmp9fz24/5YSY3bVzTuMsg= +github.com/ecadlabs/go-pkcs11 v0.2.1/go.mod h1:PwAVBY0muwp6quQFmSDcB5Ekl4TjGG7cEQQwY9KpNVc= github.com/ecadlabs/goblst v1.0.0 h1:8/e3SQGwqbV0+ul+pg0aSNFfC3lgQcvEed3VdDBXSl8= github.com/ecadlabs/goblst v1.0.0/go.mod h1:s67gqaOol9o6fguh+evH75X5uQniOhv1HG/EU8xPLPY= github.com/ecadlabs/gotez/v2 v2.1.3 h1:RGNtvb+UAtstTQYCsdE4XAeaEZwj3a5AliLluEOsoAg= From a031f52d93302b63a4519abbf556dd4468087ee9 Mon Sep 17 00:00:00 2001 From: GImbrailo Date: Tue, 29 Oct 2024 15:26:11 -0700 Subject: [PATCH 8/8] chore: remove windows builds from goreleaser --- .goreleaser.yml | 72 ++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 2371e35a..c0ff85b0 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -198,43 +198,43 @@ builds: - '{{ if .IsSnapshot }}-cover{{ else }}-v{{ end }}' # WINDOWS - - id: signatory-windows-amd - binary: signatory - env: - - CGO_ENABLED=1 - - CC=x86_64-w64-mingw32-gcc - - CXX=x86_64-w64-mingw32-g++ - - >- - {{- if .IsSnapshot }}GOEXPERIMENT=coverageredesign{{- end }} - main: ./cmd/signatory/main.go - ldflags: - - '-X github.com/ecadlabs/signatory/pkg/metrics.GitRevision={{.Version}}' - - '-X github.com/ecadlabs/signatory/pkg/metrics.GitBranch={{.Version}}' - goos: - - windows - goarch: - - amd64 - flags: - - '{{ if .IsSnapshot }}-cover{{ else }}-v{{ end }}' + # - id: signatory-windows-amd + # binary: signatory + # env: + # - CGO_ENABLED=1 + # - CC=x86_64-w64-mingw32-gcc + # - CXX=x86_64-w64-mingw32-g++ + # - >- + # {{- if .IsSnapshot }}GOEXPERIMENT=coverageredesign{{- end }} + # main: ./cmd/signatory/main.go + # ldflags: + # - '-X github.com/ecadlabs/signatory/pkg/metrics.GitRevision={{.Version}}' + # - '-X github.com/ecadlabs/signatory/pkg/metrics.GitBranch={{.Version}}' + # goos: + # - windows + # goarch: + # - amd64 + # flags: + # - '{{ if .IsSnapshot }}-cover{{ else }}-v{{ end }}' - - id: signatory-cli-windows-amd - binary: signatory-cli - env: - - CGO_ENABLED=1 - - CC=x86_64-w64-mingw32-gcc - - CXX=x86_64-w64-mingw32-g++ - - >- - {{- if .IsSnapshot }}GOEXPERIMENT=coverageredesign{{- end }} - main: ./cmd/signatory-cli/main.go - ldflags: - - '-X github.com/ecadlabs/signatory/pkg/metrics.GitRevision={{.Version}}' - - '-X github.com/ecadlabs/signatory/pkg/metrics.GitBranch={{.Version}}' - goos: - - windows - goarch: - - amd64 - flags: - - '{{ if .IsSnapshot }}-cover{{ else }}-v{{ end }}' + # - id: signatory-cli-windows-amd + # binary: signatory-cli + # env: + # - CGO_ENABLED=1 + # - CC=x86_64-w64-mingw32-gcc + # - CXX=x86_64-w64-mingw32-g++ + # - >- + # {{- if .IsSnapshot }}GOEXPERIMENT=coverageredesign{{- end }} + # main: ./cmd/signatory-cli/main.go + # ldflags: + # - '-X github.com/ecadlabs/signatory/pkg/metrics.GitRevision={{.Version}}' + # - '-X github.com/ecadlabs/signatory/pkg/metrics.GitBranch={{.Version}}' + # goos: + # - windows + # goarch: + # - amd64 + # flags: + # - '{{ if .IsSnapshot }}-cover{{ else }}-v{{ end }}' dockers: - ids: