boulder/cmd/ceremony/key_test.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")
}