161 lines
5.3 KiB
Go
161 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"math/big"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/letsencrypt/boulder/pkcs11helpers"
|
|
"github.com/letsencrypt/boulder/test"
|
|
"github.com/miekg/pkcs11"
|
|
)
|
|
|
|
func setupCtx() pkcs11helpers.MockCtx {
|
|
return pkcs11helpers.MockCtx{
|
|
GenerateKeyPairFunc: func(pkcs11.SessionHandle, []*pkcs11.Mechanism, []*pkcs11.Attribute, []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error) {
|
|
return 0, 0, nil
|
|
},
|
|
SignInitFunc: func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error {
|
|
return nil
|
|
},
|
|
GenerateRandomFunc: func(pkcs11.SessionHandle, int) ([]byte, error) {
|
|
return []byte{1, 2, 3}, nil
|
|
},
|
|
FindObjectsInitFunc: func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
|
|
return nil
|
|
},
|
|
FindObjectsFunc: func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
|
|
return nil, false, nil
|
|
},
|
|
FindObjectsFinalFunc: func(pkcs11.SessionHandle) error {
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestGenerateKeyRSA(t *testing.T) {
|
|
tmp := t.TempDir()
|
|
|
|
ctx := setupCtx()
|
|
rsaPriv, err := rsa.GenerateKey(rand.Reader, 1024)
|
|
test.AssertNotError(t, err, "Failed to generate a test RSA key")
|
|
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
|
|
return []*pkcs11.Attribute{
|
|
pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, big.NewInt(int64(rsaPriv.E)).Bytes()),
|
|
pkcs11.NewAttribute(pkcs11.CKA_MODULUS, rsaPriv.N.Bytes()),
|
|
}, nil
|
|
}
|
|
ctx.SignFunc = func(_ pkcs11.SessionHandle, msg []byte) ([]byte, error) {
|
|
// Chop of the hash identifier and feed back into rsa.SignPKCS1v15
|
|
return rsa.SignPKCS1v15(rand.Reader, rsaPriv, crypto.SHA256, msg[19:])
|
|
}
|
|
s := &pkcs11helpers.Session{Module: &ctx, Session: 0}
|
|
keyPath := path.Join(tmp, "test-rsa-key.pem")
|
|
keyInfo, err := generateKey(s, "", keyPath, keyGenConfig{
|
|
Type: "rsa",
|
|
RSAModLength: 1024,
|
|
})
|
|
test.AssertNotError(t, err, "Failed to generate RSA key")
|
|
diskKeyBytes, err := os.ReadFile(keyPath)
|
|
test.AssertNotError(t, err, "Failed to load key from disk")
|
|
block, _ := pem.Decode(diskKeyBytes)
|
|
diskKey, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
test.AssertNotError(t, err, "Failed to parse disk key")
|
|
test.AssertDeepEquals(t, diskKey, keyInfo.key)
|
|
}
|
|
|
|
func setECGenerateFuncs(ctx *pkcs11helpers.MockCtx) {
|
|
ecPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
|
|
return []*pkcs11.Attribute{
|
|
pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 8, 42, 134, 72, 206, 61, 3, 1, 7}),
|
|
pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, elliptic.Marshal(elliptic.P256(), ecPriv.X, ecPriv.Y)),
|
|
}, nil
|
|
}
|
|
ctx.SignFunc = func(_ pkcs11.SessionHandle, msg []byte) ([]byte, error) {
|
|
return ecPKCS11Sign(ecPriv, msg)
|
|
}
|
|
}
|
|
|
|
func TestGenerateKeyEC(t *testing.T) {
|
|
tmp := t.TempDir()
|
|
|
|
ctx := setupCtx()
|
|
setECGenerateFuncs(&ctx)
|
|
keyPath := path.Join(tmp, "test-ecdsa-key.pem")
|
|
s := &pkcs11helpers.Session{Module: &ctx, Session: 0}
|
|
keyInfo, err := generateKey(s, "", keyPath, keyGenConfig{
|
|
Type: "ecdsa",
|
|
ECDSACurve: "P-256",
|
|
})
|
|
test.AssertNotError(t, err, "Failed to generate ECDSA key")
|
|
diskKeyBytes, err := os.ReadFile(keyPath)
|
|
test.AssertNotError(t, err, "Failed to load key from disk")
|
|
block, _ := pem.Decode(diskKeyBytes)
|
|
diskKey, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
test.AssertNotError(t, err, "Failed to parse disk key")
|
|
test.AssertDeepEquals(t, diskKey, keyInfo.key)
|
|
}
|
|
|
|
func setFindObjectsFuncs(label string, ctx *pkcs11helpers.MockCtx) {
|
|
var objectsFound []pkcs11.ObjectHandle
|
|
ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, template []*pkcs11.Attribute) error {
|
|
for _, attr := range template {
|
|
if attr.Type == pkcs11.CKA_LABEL && string(attr.Value) == label {
|
|
objectsFound = []pkcs11.ObjectHandle{1}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
|
|
return objectsFound, false, nil
|
|
}
|
|
ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error {
|
|
objectsFound = nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func TestGenerateKeySlotHasSomethingWithLabel(t *testing.T) {
|
|
tmp := t.TempDir()
|
|
|
|
ctx := setupCtx()
|
|
label := "someLabel"
|
|
setFindObjectsFuncs(label, &ctx)
|
|
keyPath := path.Join(tmp, "should-not-exist.pem")
|
|
s := &pkcs11helpers.Session{Module: &ctx, Session: 0}
|
|
_, err := generateKey(s, label, keyPath, keyGenConfig{
|
|
Type: "ecdsa",
|
|
ECDSACurve: "P-256",
|
|
})
|
|
test.AssertError(t, err, "expected failure for a slot with an object already in it")
|
|
test.Assert(t, strings.HasPrefix(err.Error(), "expected no preexisting objects with label"), "wrong error")
|
|
}
|
|
|
|
func TestGenerateKeySlotHasSomethingWithDifferentLabel(t *testing.T) {
|
|
tmp := t.TempDir()
|
|
|
|
ctx := setupCtx()
|
|
setECGenerateFuncs(&ctx)
|
|
setFindObjectsFuncs("someLabel", &ctx)
|
|
keyPath := path.Join(tmp, "should-not-exist.pem")
|
|
s := &pkcs11helpers.Session{Module: &ctx, Session: 0}
|
|
_, err := generateKey(s, "someOtherLabel", keyPath, keyGenConfig{
|
|
Type: "ecdsa",
|
|
ECDSACurve: "P-256",
|
|
})
|
|
test.AssertNotError(t, err, "expected success even though there was an object with a different label")
|
|
}
|