forked from TrueCloudLab/certificates
Add initial set of unit tests for pkcs11 kms.
This commit is contained in:
parent
a6c784d5dd
commit
294f84b8d4
5 changed files with 945 additions and 36 deletions
|
@ -26,16 +26,29 @@ type CertificateManager interface {
|
|||
// ErrNotImplemented is the type of error returned if an operation is not
|
||||
// implemented.
|
||||
type ErrNotImplemented struct {
|
||||
msg string
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e ErrNotImplemented) Error() string {
|
||||
if e.msg != "" {
|
||||
return e.msg
|
||||
if e.Message != "" {
|
||||
return e.Message
|
||||
}
|
||||
return "not implemented"
|
||||
}
|
||||
|
||||
// ErrAlreadyExists is the type of error returned if a key already exists. This
|
||||
// is currently only implmented on pkcs11.
|
||||
type ErrAlreadyExists struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e ErrAlreadyExists) Error() string {
|
||||
if e.Message != "" {
|
||||
return e.Message
|
||||
}
|
||||
return "key already exists"
|
||||
}
|
||||
|
||||
// Type represents the KMS type used.
|
||||
type Type string
|
||||
|
||||
|
|
|
@ -21,9 +21,25 @@ import (
|
|||
// specified.
|
||||
const DefaultRSASize = 3072
|
||||
|
||||
// P11 defines the methods on crypto11.Context that this package will use. This
|
||||
// interface will be used for unit testing.
|
||||
type P11 interface {
|
||||
FindKeyPair(id, label []byte) (crypto11.Signer, error)
|
||||
FindCertificate(id, label []byte, serial *big.Int) (*x509.Certificate, error)
|
||||
ImportCertificateWithLabel(id, label []byte, cert *x509.Certificate) error
|
||||
DeleteCertificate(id, label []byte, serial *big.Int) error
|
||||
GenerateRSAKeyPairWithLabel(id, label []byte, bits int) (crypto11.SignerDecrypter, error)
|
||||
GenerateECDSAKeyPairWithLabel(id, label []byte, curve elliptic.Curve) (crypto11.Signer, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
var p11Configure = func(config *crypto11.Config) (P11, error) {
|
||||
return crypto11.Configure(config)
|
||||
}
|
||||
|
||||
// PKCS11 is the implementation of a KMS using the PKCS #11 standard.
|
||||
type PKCS11 struct {
|
||||
context *crypto11.Context
|
||||
p11 P11
|
||||
}
|
||||
|
||||
// New returns a new PKCS11 KMS.
|
||||
|
@ -54,13 +70,13 @@ func New(ctx context.Context, opts apiv1.Options) (*PKCS11, error) {
|
|||
return nil, errors.New("kms uri 'token' or 'serial' are mutually exclusive")
|
||||
}
|
||||
|
||||
p11Ctx, err := crypto11.Configure(&config)
|
||||
p11, err := p11Configure(&config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error initializing PKCS#11")
|
||||
}
|
||||
|
||||
return &PKCS11{
|
||||
context: p11Ctx,
|
||||
p11: p11,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -76,7 +92,7 @@ func (k *PKCS11) GetPublicKey(req *apiv1.GetPublicKeyRequest) (crypto.PublicKey,
|
|||
return nil, errors.New("getPublicKeyRequest 'name' cannot be empty")
|
||||
}
|
||||
|
||||
signer, err := findSigner(k.context, req.Name)
|
||||
signer, err := findSigner(k.p11, req.Name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getPublicKey failed")
|
||||
}
|
||||
|
@ -93,7 +109,7 @@ func (k *PKCS11) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespons
|
|||
return nil, errors.New("createKeyRequest 'bits' cannot be negative")
|
||||
}
|
||||
|
||||
signer, err := generateKey(k.context, req)
|
||||
signer, err := generateKey(k.p11, req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "createKey failed")
|
||||
}
|
||||
|
@ -115,7 +131,7 @@ func (k *PKCS11) CreateSigner(req *apiv1.CreateSignerRequest) (crypto.Signer, er
|
|||
return nil, errors.New("createSignerRequest 'signingKey' cannot be empty")
|
||||
}
|
||||
|
||||
signer, err := findSigner(k.context, req.SigningKey)
|
||||
signer, err := findSigner(k.p11, req.SigningKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "createSigner failed")
|
||||
}
|
||||
|
@ -129,7 +145,7 @@ func (k *PKCS11) LoadCertificate(req *apiv1.LoadCertificateRequest) (*x509.Certi
|
|||
if req.Name == "" {
|
||||
return nil, errors.New("loadCertificateRequest 'name' cannot be nil")
|
||||
}
|
||||
cert, err := findCertificate(k.context, req.Name)
|
||||
cert, err := findCertificate(k.p11, req.Name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "loadCertificate failed")
|
||||
}
|
||||
|
@ -151,7 +167,7 @@ func (k *PKCS11) StoreCertificate(req *apiv1.StoreCertificateRequest) error {
|
|||
return errors.Wrap(err, "storeCertificate failed")
|
||||
}
|
||||
|
||||
if err := k.context.ImportCertificateWithLabel(id, object, req.Certificate); err != nil {
|
||||
if err := k.p11.ImportCertificateWithLabel(id, object, req.Certificate); err != nil {
|
||||
return errors.Wrap(err, "storeCertificate failed")
|
||||
}
|
||||
|
||||
|
@ -164,7 +180,7 @@ func (k *PKCS11) DeleteKey(uri string) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "deleteKey failed")
|
||||
}
|
||||
signer, err := k.context.FindKeyPair(id, object)
|
||||
signer, err := k.p11.FindKeyPair(id, object)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "deleteKey failed")
|
||||
}
|
||||
|
@ -183,7 +199,7 @@ func (k *PKCS11) DeleteCertificate(uri string) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "deleteCertificate failed")
|
||||
}
|
||||
if err := k.context.DeleteCertificate(id, object, nil); err != nil {
|
||||
if err := k.p11.DeleteCertificate(id, object, nil); err != nil {
|
||||
return errors.Wrap(err, "deleteCertificate failed")
|
||||
}
|
||||
return nil
|
||||
|
@ -191,7 +207,7 @@ func (k *PKCS11) DeleteCertificate(uri string) error {
|
|||
|
||||
// Close releases the connection to the PKCS#11 module.
|
||||
func (k *PKCS11) Close() error {
|
||||
return errors.Wrap(k.context.Close(), "error closing pkcs#11 context")
|
||||
return errors.Wrap(k.p11.Close(), "error closing pkcs#11 context")
|
||||
}
|
||||
|
||||
func toByte(s string) []byte {
|
||||
|
@ -201,7 +217,24 @@ func toByte(s string) []byte {
|
|||
return []byte(s)
|
||||
}
|
||||
|
||||
func generateKey(ctx *crypto11.Context, req *apiv1.CreateKeyRequest) (crypto11.Signer, error) {
|
||||
func parseObject(rawuri string) ([]byte, []byte, error) {
|
||||
u, err := uri.ParseWithScheme("pkcs11", rawuri)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
id, err := u.GetHex("id")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
object := u.Get("object")
|
||||
if len(id) == 0 && object == "" {
|
||||
return nil, nil, errors.Errorf("key with uri %s is not valid, id or object are required", rawuri)
|
||||
}
|
||||
|
||||
return id, toByte(object), nil
|
||||
}
|
||||
|
||||
func generateKey(ctx P11, req *apiv1.CreateKeyRequest) (crypto11.Signer, error) {
|
||||
id, object, err := parseObject(req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -211,7 +244,9 @@ func generateKey(ctx *crypto11.Context, req *apiv1.CreateKeyRequest) (crypto11.S
|
|||
return nil, err
|
||||
}
|
||||
if signer != nil {
|
||||
return nil, errors.Errorf("%s already exists", req.Name)
|
||||
return nil, apiv1.ErrAlreadyExists{
|
||||
Message: req.Name + " already exists",
|
||||
}
|
||||
}
|
||||
|
||||
bits := req.Bits
|
||||
|
@ -239,24 +274,7 @@ func generateKey(ctx *crypto11.Context, req *apiv1.CreateKeyRequest) (crypto11.S
|
|||
}
|
||||
}
|
||||
|
||||
func parseObject(rawuri string) ([]byte, []byte, error) {
|
||||
u, err := uri.ParseWithScheme("pkcs11", rawuri)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
id, err := u.GetHex("id")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
object := u.Get("object")
|
||||
if len(id) == 0 && object == "" {
|
||||
return nil, nil, errors.Errorf("key with uri %s is not valid, id or object are required", rawuri)
|
||||
}
|
||||
|
||||
return id, toByte(object), nil
|
||||
}
|
||||
|
||||
func findSigner(ctx *crypto11.Context, rawuri string) (crypto11.Signer, error) {
|
||||
func findSigner(ctx P11, rawuri string) (crypto11.Signer, error) {
|
||||
id, object, err := parseObject(rawuri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -271,7 +289,7 @@ func findSigner(ctx *crypto11.Context, rawuri string) (crypto11.Signer, error) {
|
|||
return signer, nil
|
||||
}
|
||||
|
||||
func findCertificate(ctx *crypto11.Context, rawuri string) (*x509.Certificate, error) {
|
||||
func findCertificate(ctx P11, rawuri string) (*x509.Certificate, error) {
|
||||
u, err := uri.ParseWithScheme("pkcs11", rawuri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -1,3 +1,644 @@
|
|||
// +build cgo
|
||||
|
||||
package pkcs11
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/smallstep/certificates/kms/apiv1"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
opts apiv1.Options
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *PKCS11
|
||||
wantErr bool
|
||||
}{}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := New(tt.args.ctx, tt.args.opts)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("New() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCS11_GetPublicKey(t *testing.T) {
|
||||
setupSoftHSM2, setupYubiHSM2 := setupFuncs(t)
|
||||
type args struct {
|
||||
req *apiv1.GetPublicKeyRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) *PKCS11
|
||||
args args
|
||||
want crypto.PublicKey
|
||||
wantErr bool
|
||||
}{
|
||||
// SoftHSM2
|
||||
{"softhsm RSA", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=7371;object=rsa-key",
|
||||
}}, &rsa.PublicKey{}, false},
|
||||
{"softhsm RSA by id", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=7371",
|
||||
}}, &rsa.PublicKey{}, false},
|
||||
{"softhsm RSA by label", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:object=rsa-key",
|
||||
}}, &rsa.PublicKey{}, false},
|
||||
{"softhsm ECDSA", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=7373;object=ecdsa-p256-key",
|
||||
}}, &ecdsa.PublicKey{}, false},
|
||||
{"softhsm ECDSA by id", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=7373",
|
||||
}}, &ecdsa.PublicKey{}, false},
|
||||
{"softhsm ECDSA by label", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:object=ecdsa-p256-key",
|
||||
}}, &ecdsa.PublicKey{}, false},
|
||||
// YubiHSM2
|
||||
{"yubiHSM2 RSA", setupYubiHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=7371;object=rsa-key",
|
||||
}}, &rsa.PublicKey{}, false},
|
||||
{"yubiHSM2 RSA by id", setupYubiHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=7371",
|
||||
}}, &rsa.PublicKey{}, false},
|
||||
{"yubiHSM2 RSA by label", setupYubiHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:object=rsa-key",
|
||||
}}, &rsa.PublicKey{}, false},
|
||||
{"yubiHSM2 ECDSA", setupYubiHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=7373;object=ecdsa-p256-key",
|
||||
}}, &ecdsa.PublicKey{}, false},
|
||||
{"yubiHSM2 ECDSA by id", setupYubiHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=7373",
|
||||
}}, &ecdsa.PublicKey{}, false},
|
||||
{"yubiHSM2 ECDSA by label", setupYubiHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:object=ecdsa-p256-key",
|
||||
}}, &ecdsa.PublicKey{}, false},
|
||||
// Errors
|
||||
{"fail name", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "",
|
||||
}}, nil, true},
|
||||
{"fail uri", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "https:id=9999;object=https",
|
||||
}}, nil, true},
|
||||
{"fail softhsm missing", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=9999;object=rsa-key",
|
||||
}}, nil, true},
|
||||
{"fail yubiHSM2 missing", setupYubiHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:id=9999;object=ecdsa-p256-key",
|
||||
}}, nil, true},
|
||||
{"fail softhsm FindKeyPair", setupSoftHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:foo=bar",
|
||||
}}, nil, true},
|
||||
{"fail yubiHSM2 FindKeyPair", setupYubiHSM2, args{&apiv1.GetPublicKeyRequest{
|
||||
Name: "pkcs11:foo=bar",
|
||||
}}, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
k := tt.setup(t)
|
||||
got, err := k.GetPublicKey(tt.args.req)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("PKCS11.GetPublicKey() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if reflect.TypeOf(got) != reflect.TypeOf(tt.want) {
|
||||
t.Errorf("PKCS11.GetPublicKey() = %T, want %T", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCS11_CreateKey(t *testing.T) {
|
||||
setupSoftHSM2, setupYubiHSM2 := setupFuncs(t)
|
||||
type args struct {
|
||||
req *apiv1.CreateKeyRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) *PKCS11
|
||||
args args
|
||||
want *apiv1.CreateKeyResponse
|
||||
wantErr bool
|
||||
}{
|
||||
// SoftHSM2
|
||||
{"softhsm Default", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=ecdsa-create-key",
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=ecdsa-create-key",
|
||||
PublicKey: &ecdsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=ecdsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm RSA SHA256WithRSA", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSA,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm RSA SHA384WithRSA", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA384WithRSA,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm RSA SHA512WithRSA", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA512WithRSA,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm RSA SHA256WithRSAPSS", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSAPSS,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm RSA SHA384WithRSAPSS", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA384WithRSAPSS,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm RSA SHA512WithRSAPSS", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA512WithRSAPSS,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm RSA 2048", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSA,
|
||||
Bits: 2048,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm RSA 4096", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSA,
|
||||
Bits: 4096,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm ECDSA P256", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.ECDSAWithSHA256,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &ecdsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm ECDSA P384", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.ECDSAWithSHA384,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &ecdsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"softhsm ECDSA P521", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.ECDSAWithSHA512,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &ecdsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
// YubiHSM2
|
||||
{"yubihsm RSA", setupYubiHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSA,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"yubihsm RSA 2048", setupYubiHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSA,
|
||||
Bits: 2048,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"yubihsm RSA 4096", setupYubiHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSA,
|
||||
Bits: 4096,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &rsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"yubihsm Default", setupYubiHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=ecdsa-create-key",
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=ecdsa-create-key",
|
||||
PublicKey: &ecdsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=ecdsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"yubihsm ECDSA P256", setupYubiHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.ECDSAWithSHA256,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &ecdsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"yubihsm ECDSA P384", setupYubiHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.ECDSAWithSHA384,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &ecdsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
{"yubihsm ECDSA P521", setupYubiHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.ECDSAWithSHA512,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "pkcs11:id=7771;object=rsa-create-key",
|
||||
PublicKey: &ecdsa.PublicKey{},
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7771;object=rsa-create-key",
|
||||
},
|
||||
}, false},
|
||||
// Errors
|
||||
{"fail name", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "",
|
||||
}}, nil, true},
|
||||
{"fail bits", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=9999;object=rsa-create-key",
|
||||
Bits: -1,
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSAPSS,
|
||||
}}, nil, true},
|
||||
{"fail ed25519", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=9999;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.PureEd25519,
|
||||
}}, nil, true},
|
||||
{"fail unknown", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=9999;object=rsa-create-key",
|
||||
SignatureAlgorithm: apiv1.SignatureAlgorithm(100),
|
||||
}}, nil, true},
|
||||
{"fail uri", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:id=xxxx;object=https",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSAPSS,
|
||||
}}, nil, true},
|
||||
{"fail softhsm FindKeyPair", setupSoftHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:foo=bar",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSAPSS,
|
||||
}}, nil, true},
|
||||
{"fail yubihsm FindKeyPair", setupYubiHSM2, args{&apiv1.CreateKeyRequest{
|
||||
Name: "pkcs11:foo=bar",
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSAPSS,
|
||||
}}, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
k := tt.setup(t)
|
||||
got, err := k.CreateKey(tt.args.req)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("PKCS11.CreateKey() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != nil {
|
||||
got.PublicKey = tt.want.PublicKey
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("PKCS11.CreateKey() = %v, want %v", got, tt.want)
|
||||
}
|
||||
if got != nil {
|
||||
if err := k.DeleteKey(got.Name); err != nil {
|
||||
t.Errorf("PKCS11.DeleteKey() error = %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCS11_CreateSigner(t *testing.T) {
|
||||
data := []byte("buggy-coheir-RUBRIC-rabbet-liberal-eaglet-khartoum-stagger")
|
||||
setupSoftHSM2, setupYubiHSM2 := setupFuncs(t)
|
||||
|
||||
type args struct {
|
||||
req *apiv1.CreateSignerRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) *PKCS11
|
||||
args args
|
||||
algorithm apiv1.SignatureAlgorithm
|
||||
signerOpts crypto.SignerOpts
|
||||
wantErr bool
|
||||
}{
|
||||
// SoftHSM2
|
||||
{"softhsm RSA", setupSoftHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7371;object=rsa-key",
|
||||
}}, apiv1.SHA256WithRSA, crypto.SHA256, false},
|
||||
{"softhsm RSA PSS", setupSoftHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7371;object=rsa-key",
|
||||
}}, apiv1.SHA256WithRSA, crypto.SHA256, false},
|
||||
{"softhsm ECDSA P256", setupSoftHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7373;object=ecdsa-p256-key",
|
||||
}}, apiv1.ECDSAWithSHA256, crypto.SHA256, false},
|
||||
{"softhsm ECDSA P384", setupSoftHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7374;object=ecdsa-p384-key",
|
||||
}}, apiv1.ECDSAWithSHA384, crypto.SHA384, false},
|
||||
{"softhsm ECDSA P521", setupSoftHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7375;object=ecdsa-p521-key",
|
||||
}}, apiv1.ECDSAWithSHA512, crypto.SHA512, false},
|
||||
// YubiHSM2
|
||||
{"yubihsm RSA", setupYubiHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7371;object=rsa-key",
|
||||
}}, apiv1.SHA256WithRSA, crypto.SHA256, false},
|
||||
{"yubihsm RSA PSS", setupYubiHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7371;object=rsa-key",
|
||||
}}, apiv1.SHA256WithRSA, crypto.SHA256, false},
|
||||
{"yubihsm ECDSA P256", setupYubiHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7373;object=ecdsa-p256-key",
|
||||
}}, apiv1.ECDSAWithSHA256, crypto.SHA256, false},
|
||||
{"yubihsm ECDSA P384", setupYubiHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7374;object=ecdsa-p384-key",
|
||||
}}, apiv1.ECDSAWithSHA384, crypto.SHA384, false},
|
||||
{"yubihsm ECDSA P521", setupYubiHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:id=7375;object=ecdsa-p521-key",
|
||||
}}, apiv1.ECDSAWithSHA512, crypto.SHA512, false},
|
||||
// Errors
|
||||
{"fail SigningKey", setupSoftHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "",
|
||||
}}, 0, nil, true},
|
||||
{"fail uri", setupSoftHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "https:id=7375;object=ecdsa-p521-key",
|
||||
}}, 0, nil, true},
|
||||
{"fail softhsm FindKeyPair", setupSoftHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:foo=bar",
|
||||
}}, 0, nil, true},
|
||||
{"fail yubihsm FindKeyPair", setupYubiHSM2, args{&apiv1.CreateSignerRequest{
|
||||
SigningKey: "pkcs11:foo=bar",
|
||||
}}, 0, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
k := tt.setup(t)
|
||||
got, err := k.CreateSigner(tt.args.req)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("PKCS11.CreateSigner() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if got != nil {
|
||||
hash := tt.signerOpts.HashFunc()
|
||||
h := hash.New()
|
||||
h.Write(data)
|
||||
digest := h.Sum(nil)
|
||||
sig, err := got.Sign(rand.Reader, digest, tt.signerOpts)
|
||||
if err != nil {
|
||||
t.Errorf("cyrpto.Signer.Sign() error = %v", err)
|
||||
}
|
||||
|
||||
switch tt.algorithm {
|
||||
case apiv1.SHA256WithRSA, apiv1.SHA384WithRSA, apiv1.SHA512WithRSA:
|
||||
pub := got.Public().(*rsa.PublicKey)
|
||||
if err := rsa.VerifyPKCS1v15(pub, hash, digest, sig); err != nil {
|
||||
t.Errorf("rsa.VerifyPKCS1v15() error = %v", err)
|
||||
}
|
||||
case apiv1.UnspecifiedSignAlgorithm, apiv1.SHA256WithRSAPSS, apiv1.SHA384WithRSAPSS, apiv1.SHA512WithRSAPSS:
|
||||
pub := got.Public().(*rsa.PublicKey)
|
||||
if err := rsa.VerifyPSS(pub, hash, digest, sig, tt.signerOpts.(*rsa.PSSOptions)); err != nil {
|
||||
t.Errorf("rsa.VerifyPSS() error = %v", err)
|
||||
}
|
||||
case apiv1.ECDSAWithSHA256, apiv1.ECDSAWithSHA384, apiv1.ECDSAWithSHA512:
|
||||
pub := got.Public().(*ecdsa.PublicKey)
|
||||
if !ecdsa.VerifyASN1(pub, digest, sig) {
|
||||
t.Error("ecdsa.VerifyASN1() failed")
|
||||
}
|
||||
default:
|
||||
t.Errorf("signature algorithm %s is not supported", tt.algorithm)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCS11_LoadCertificate(t *testing.T) {
|
||||
setupSoftHSM2, setupYubiHSM2 := setupFuncs(t)
|
||||
|
||||
getCertFn := func(i, j int) func() *x509.Certificate {
|
||||
return func() *x509.Certificate {
|
||||
return testCerts[i].Certificates[j]
|
||||
}
|
||||
}
|
||||
|
||||
type args struct {
|
||||
req *apiv1.LoadCertificateRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) *PKCS11
|
||||
args args
|
||||
wantFn func() *x509.Certificate
|
||||
wantErr bool
|
||||
}{
|
||||
{"softhsm", setupSoftHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:id=7370;object=root",
|
||||
}}, getCertFn(0, 0), false},
|
||||
{"softhsm by id", setupSoftHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:id=7370",
|
||||
}}, getCertFn(0, 0), false},
|
||||
{"softhsm by label", setupSoftHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:object=root",
|
||||
}}, getCertFn(0, 0), false},
|
||||
{"yubihsm", setupYubiHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:id=7370;object=root",
|
||||
}}, getCertFn(0, 1), false},
|
||||
{"yubihsm by id", setupYubiHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:id=7370",
|
||||
}}, getCertFn(0, 1), false},
|
||||
{"yubihsm by label", setupYubiHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:object=root",
|
||||
}}, getCertFn(0, 1), false},
|
||||
{"fail softhsm missing", setupSoftHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:id=9999;object=root",
|
||||
}}, nil, true},
|
||||
{"fail yubihsm missing", setupSoftHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:id=9999;object=root",
|
||||
}}, nil, true},
|
||||
{"fail name", setupSoftHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "",
|
||||
}}, nil, true},
|
||||
{"fail uri", setupSoftHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:id=xxxx;object=root",
|
||||
}}, nil, true},
|
||||
{"fail softhsm FindCertificate", setupSoftHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:foo=bar",
|
||||
}}, nil, true},
|
||||
{"fail yubihsm FindCertificate", setupYubiHSM2, args{&apiv1.LoadCertificateRequest{
|
||||
Name: "pkcs11:foo=bar",
|
||||
}}, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
k := tt.setup(t)
|
||||
got, err := k.LoadCertificate(tt.args.req)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("PKCS11.LoadCertificate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
var want *x509.Certificate
|
||||
if tt.wantFn != nil {
|
||||
want = tt.wantFn()
|
||||
got.Raw, got.RawIssuer, got.RawSubject, got.RawTBSCertificate, got.RawSubjectPublicKeyInfo = nil, nil, nil, nil, nil
|
||||
want.Raw, want.RawIssuer, want.RawSubject, want.RawTBSCertificate, want.RawSubjectPublicKeyInfo = nil, nil, nil, nil, nil
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("PKCS11.LoadCertificate() = %v, want %v", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCS11_StoreCertificate(t *testing.T) {
|
||||
setupSoftHSM2, setupYubiHSM2 := setupFuncs(t)
|
||||
|
||||
pub, priv, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("ed25519.GenerateKey() error = %v", err)
|
||||
}
|
||||
|
||||
cert, err := generateCertificate(pub, priv)
|
||||
if err != nil {
|
||||
t.Fatalf("x509.CreateCertificate() error = %v", err)
|
||||
}
|
||||
|
||||
type args struct {
|
||||
req *apiv1.StoreCertificateRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) *PKCS11
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{"softhsm", setupSoftHSM2, args{&apiv1.StoreCertificateRequest{
|
||||
Name: "pkcs11:id=7771;object=root",
|
||||
Certificate: cert,
|
||||
}}, false},
|
||||
{"yubihsm", setupYubiHSM2, args{&apiv1.StoreCertificateRequest{
|
||||
Name: "pkcs11:id=7771;object=root",
|
||||
Certificate: cert,
|
||||
}}, false},
|
||||
{"fail name", setupSoftHSM2, args{&apiv1.StoreCertificateRequest{
|
||||
Name: "",
|
||||
Certificate: cert,
|
||||
}}, true},
|
||||
{"fail certificate", setupSoftHSM2, args{&apiv1.StoreCertificateRequest{
|
||||
Name: "pkcs11:id=7771;object=root",
|
||||
Certificate: nil,
|
||||
}}, true},
|
||||
{"fail uri", setupSoftHSM2, args{&apiv1.StoreCertificateRequest{
|
||||
Name: "http:id=7771;object=root",
|
||||
Certificate: cert,
|
||||
}}, true},
|
||||
{"fail softhsm ImportCertificateWithLabel", setupSoftHSM2, args{&apiv1.StoreCertificateRequest{
|
||||
Name: "pkcs11:foo=bar",
|
||||
Certificate: cert,
|
||||
}}, true},
|
||||
{"fail yubihsm ImportCertificateWithLabel", setupYubiHSM2, args{&apiv1.StoreCertificateRequest{
|
||||
Name: "pkcs11:foo=bar",
|
||||
Certificate: cert,
|
||||
}}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
k := tt.setup(t)
|
||||
if err := k.StoreCertificate(tt.args.req); (err != nil) != tt.wantErr {
|
||||
t.Errorf("PKCS11.StoreCertificate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if !tt.wantErr {
|
||||
got, err := k.LoadCertificate(&apiv1.LoadCertificateRequest{
|
||||
Name: tt.args.req.Name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("PKCS11.LoadCertificate() error = %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, cert) {
|
||||
t.Errorf("PKCS11.LoadCertificate() = %v, want %v", got, cert)
|
||||
}
|
||||
if err := k.DeleteCertificate(tt.args.req.Name); err != nil {
|
||||
t.Errorf("PKCS11.DeleteCertificate() error = %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
235
kms/pkcs11/setup_test.go
Normal file
235
kms/pkcs11/setup_test.go
Normal file
|
@ -0,0 +1,235 @@
|
|||
// +build cgo
|
||||
|
||||
package pkcs11
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/ThalesIgnite/crypto11"
|
||||
"github.com/smallstep/certificates/kms/apiv1"
|
||||
)
|
||||
|
||||
var (
|
||||
softHSM2Once sync.Once
|
||||
yubiHSM2Once sync.Once
|
||||
)
|
||||
|
||||
var (
|
||||
testKeys = []struct {
|
||||
Name string
|
||||
SignatureAlgorithm apiv1.SignatureAlgorithm
|
||||
Bits int
|
||||
}{
|
||||
{"pkcs11:id=7371;object=rsa-key", apiv1.SHA256WithRSA, 2048},
|
||||
{"pkcs11:id=7372;object=rsa-pss-key", apiv1.SHA256WithRSAPSS, DefaultRSASize},
|
||||
{"pkcs11:id=7373;object=ecdsa-p256-key", apiv1.ECDSAWithSHA256, 0},
|
||||
{"pkcs11:id=7374;object=ecdsa-p384-key", apiv1.ECDSAWithSHA384, 0},
|
||||
{"pkcs11:id=7375;object=ecdsa-p521-key", apiv1.ECDSAWithSHA512, 0},
|
||||
}
|
||||
|
||||
testCerts = []struct {
|
||||
Name string
|
||||
Key string
|
||||
Certificates []*x509.Certificate
|
||||
}{
|
||||
{"pkcs11:id=7370;object=root", "pkcs11:id=7373;object=ecdsa-p256-key", nil},
|
||||
}
|
||||
)
|
||||
|
||||
func generateCertificate(pub crypto.PublicKey, signer crypto.Signer) (*x509.Certificate, error) {
|
||||
now := time.Now()
|
||||
template := &x509.Certificate{
|
||||
Subject: pkix.Name{CommonName: "Test Root Certificate"},
|
||||
Issuer: pkix.Name{CommonName: "Test Root Certificate"},
|
||||
IsCA: true,
|
||||
MaxPathLen: 1,
|
||||
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
||||
NotBefore: now,
|
||||
NotAfter: now.Add(time.Hour),
|
||||
SerialNumber: big.NewInt(100),
|
||||
}
|
||||
|
||||
b, err := x509.CreateCertificate(rand.Reader, template, template, pub, signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return x509.ParseCertificate(b)
|
||||
}
|
||||
|
||||
func setup(t *testing.T, k *PKCS11) {
|
||||
for _, tk := range testKeys {
|
||||
_, err := k.CreateKey(&apiv1.CreateKeyRequest{
|
||||
Name: tk.Name,
|
||||
SignatureAlgorithm: tk.SignatureAlgorithm,
|
||||
Bits: tk.Bits,
|
||||
})
|
||||
if err != nil && !errors.Is(errors.Cause(err), apiv1.ErrAlreadyExists{
|
||||
Message: tk.Name + " already exists",
|
||||
}) {
|
||||
t.Errorf("PKCS11.GetPublicKey() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, c := range testCerts {
|
||||
signer, err := k.CreateSigner(&apiv1.CreateSignerRequest{
|
||||
SigningKey: c.Key,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("PKCS11.CreateSigner() error = %v", err)
|
||||
continue
|
||||
}
|
||||
cert, err := generateCertificate(signer.Public(), signer)
|
||||
if err != nil {
|
||||
t.Errorf("x509.CreateCertificate() error = %v", err)
|
||||
continue
|
||||
}
|
||||
if err := k.StoreCertificate(&apiv1.StoreCertificateRequest{
|
||||
Name: c.Name,
|
||||
Certificate: cert,
|
||||
}); err != nil {
|
||||
t.Errorf("PKCS1.StoreCertificate() error = %v", err)
|
||||
continue
|
||||
}
|
||||
testCerts[i].Certificates = append(testCerts[i].Certificates, cert)
|
||||
}
|
||||
}
|
||||
|
||||
func teardown(t *testing.T, k *PKCS11) {
|
||||
for _, tk := range testKeys {
|
||||
if err := k.DeleteKey(tk.Name); err != nil {
|
||||
t.Errorf("PKCS11.DeleteKey() error = %v", err)
|
||||
}
|
||||
}
|
||||
for _, tc := range testCerts {
|
||||
if err := k.DeleteCertificate(tc.Name); err != nil {
|
||||
t.Errorf("PKCS11.DeleteCertificate() error = %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type setupFunc func(t *testing.T) *PKCS11
|
||||
|
||||
func setupFuncs(t *testing.T) (setupFunc, setupFunc) {
|
||||
var sh2, yh2 *PKCS11
|
||||
t.Cleanup(func() {
|
||||
if sh2 != nil {
|
||||
sh2.Close()
|
||||
}
|
||||
if yh2 != nil {
|
||||
yh2.Close()
|
||||
}
|
||||
})
|
||||
setupSoftHSM2 := func(t *testing.T) *PKCS11 {
|
||||
if sh2 != nil {
|
||||
return sh2
|
||||
}
|
||||
sh2 = softHSM2(t)
|
||||
return sh2
|
||||
}
|
||||
setupYubiHSM2 := func(t *testing.T) *PKCS11 {
|
||||
if yh2 != nil {
|
||||
return yh2
|
||||
}
|
||||
yh2 = yubiHSM2(t)
|
||||
return yh2
|
||||
}
|
||||
return setupSoftHSM2, setupYubiHSM2
|
||||
}
|
||||
|
||||
// softHSM2 configures a *PKCS11 KMS to be used with softHSM2. To initialize
|
||||
// this tests, we should run:
|
||||
// softhsm2-util --init-token --free \
|
||||
// --token pkcs11-test --label pkcs11-test \
|
||||
// --so-pin password --pin password
|
||||
//
|
||||
// To delete we should run:
|
||||
// softhsm2-util --delete-token --token pkcs11-test
|
||||
func softHSM2(t *testing.T) *PKCS11 {
|
||||
t.Helper()
|
||||
if runtime.GOARCH != "amd64" {
|
||||
t.Skipf("softHSM2 test skipped on %s:%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
var path string
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
path = "/usr/local/lib/softhsm/libsofthsm2.so"
|
||||
case "linux":
|
||||
path = "/usr/lib/softhsm/libsofthsm2.so"
|
||||
default:
|
||||
t.Skipf("softHSM2 test skipped on %s", runtime.GOOS)
|
||||
return nil
|
||||
}
|
||||
p11, err := crypto11.Configure(&crypto11.Config{
|
||||
Path: path,
|
||||
TokenLabel: "pkcs11-test",
|
||||
Pin: "password",
|
||||
})
|
||||
if err != nil {
|
||||
t.Skipf("softHSM test skipped on %s: %v", runtime.GOOS, err)
|
||||
}
|
||||
|
||||
k := &PKCS11{
|
||||
p11: p11,
|
||||
}
|
||||
|
||||
// Setup
|
||||
softHSM2Once.Do(func() {
|
||||
teardown(t, k)
|
||||
setup(t, k)
|
||||
})
|
||||
|
||||
return k
|
||||
}
|
||||
|
||||
// yubiHSM2 configures a *PKCS11 KMS to be used with YubiHSM2. To initialize
|
||||
// this tests, we should run:
|
||||
// yubihsm-connector -d
|
||||
func yubiHSM2(t *testing.T) *PKCS11 {
|
||||
t.Helper()
|
||||
if runtime.GOARCH != "amd64" {
|
||||
t.Skipf("yubiHSM2 test skipped on %s:%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
var path string
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
path = "/usr/local/lib/pkcs11/yubihsm_pkcs11.dylib"
|
||||
case "linux":
|
||||
path = "/usr/lib/x86_64-linux-gnu/pkcs11/yubihsm_pkcs11.so"
|
||||
default:
|
||||
t.Skipf("yubiHSM2 test skipped on %s", runtime.GOOS)
|
||||
return nil
|
||||
}
|
||||
p11, err := crypto11.Configure(&crypto11.Config{
|
||||
Path: path,
|
||||
TokenLabel: "YubiHSM",
|
||||
Pin: "0001password",
|
||||
})
|
||||
if err != nil {
|
||||
t.Skipf("yubiHSM2 test skipped on %s: %v", runtime.GOOS, err)
|
||||
}
|
||||
|
||||
k := &PKCS11{
|
||||
p11: p11,
|
||||
}
|
||||
|
||||
// Setup
|
||||
yubiHSM2Once.Do(func() {
|
||||
teardown(t, k)
|
||||
setup(t, k)
|
||||
})
|
||||
|
||||
return k
|
||||
}
|
|
@ -189,7 +189,9 @@ func StringDecode(s string) string {
|
|||
// HexDecode deocdes the string s using Percent-Encoding or regular hex
|
||||
// encoding.
|
||||
func HexDecode(s string) ([]byte, error) {
|
||||
if strings.HasPrefix(s, "%") {
|
||||
if s == "" {
|
||||
return nil, nil
|
||||
} else if strings.HasPrefix(s, "%") {
|
||||
return PercentDecode(s)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue