github.com/letsencrypt/boulder@v0.20251208.0/cmd/ceremony/key_test.go (about) 1 package main 2 3 import ( 4 "crypto" 5 "crypto/ecdsa" 6 "crypto/elliptic" 7 "crypto/rand" 8 "crypto/rsa" 9 "crypto/x509" 10 "encoding/pem" 11 "math/big" 12 "os" 13 "path" 14 "strings" 15 "testing" 16 17 "github.com/letsencrypt/boulder/pkcs11helpers" 18 "github.com/letsencrypt/boulder/test" 19 "github.com/miekg/pkcs11" 20 ) 21 22 func setupCtx() pkcs11helpers.MockCtx { 23 return pkcs11helpers.MockCtx{ 24 GenerateKeyPairFunc: func(pkcs11.SessionHandle, []*pkcs11.Mechanism, []*pkcs11.Attribute, []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error) { 25 return 0, 0, nil 26 }, 27 SignInitFunc: func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error { 28 return nil 29 }, 30 GenerateRandomFunc: func(pkcs11.SessionHandle, int) ([]byte, error) { 31 return []byte{1, 2, 3}, nil 32 }, 33 FindObjectsInitFunc: func(pkcs11.SessionHandle, []*pkcs11.Attribute) error { 34 return nil 35 }, 36 FindObjectsFunc: func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) { 37 return nil, false, nil 38 }, 39 FindObjectsFinalFunc: func(pkcs11.SessionHandle) error { 40 return nil 41 }, 42 } 43 } 44 45 func TestGenerateKeyRSA(t *testing.T) { 46 tmp := t.TempDir() 47 48 ctx := setupCtx() 49 rsaPriv, err := rsa.GenerateKey(rand.Reader, 1024) 50 test.AssertNotError(t, err, "Failed to generate a test RSA key") 51 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 52 return []*pkcs11.Attribute{ 53 pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, big.NewInt(int64(rsaPriv.E)).Bytes()), 54 pkcs11.NewAttribute(pkcs11.CKA_MODULUS, rsaPriv.N.Bytes()), 55 }, nil 56 } 57 ctx.SignFunc = func(_ pkcs11.SessionHandle, msg []byte) ([]byte, error) { 58 // Chop of the hash identifier and feed back into rsa.SignPKCS1v15 59 return rsa.SignPKCS1v15(rand.Reader, rsaPriv, crypto.SHA256, msg[19:]) 60 } 61 s := &pkcs11helpers.Session{Module: &ctx, Session: 0} 62 keyPath := path.Join(tmp, "test-rsa-key.pem") 63 keyInfo, err := generateKey(s, "", keyPath, keyGenConfig{ 64 Type: "rsa", 65 RSAModLength: 1024, 66 }) 67 test.AssertNotError(t, err, "Failed to generate RSA key") 68 diskKeyBytes, err := os.ReadFile(keyPath) 69 test.AssertNotError(t, err, "Failed to load key from disk") 70 block, _ := pem.Decode(diskKeyBytes) 71 diskKey, err := x509.ParsePKIXPublicKey(block.Bytes) 72 test.AssertNotError(t, err, "Failed to parse disk key") 73 test.AssertDeepEquals(t, diskKey, keyInfo.key) 74 } 75 76 func setECGenerateFuncs(ctx *pkcs11helpers.MockCtx) { 77 ecPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 78 if err != nil { 79 panic(err) 80 } 81 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 82 return []*pkcs11.Attribute{ 83 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 8, 42, 134, 72, 206, 61, 3, 1, 7}), 84 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, elliptic.Marshal(elliptic.P256(), ecPriv.X, ecPriv.Y)), 85 }, nil 86 } 87 ctx.SignFunc = func(_ pkcs11.SessionHandle, msg []byte) ([]byte, error) { 88 return ecPKCS11Sign(ecPriv, msg) 89 } 90 } 91 92 func TestGenerateKeyEC(t *testing.T) { 93 tmp := t.TempDir() 94 95 ctx := setupCtx() 96 setECGenerateFuncs(&ctx) 97 keyPath := path.Join(tmp, "test-ecdsa-key.pem") 98 s := &pkcs11helpers.Session{Module: &ctx, Session: 0} 99 keyInfo, err := generateKey(s, "", keyPath, keyGenConfig{ 100 Type: "ecdsa", 101 ECDSACurve: "P-256", 102 }) 103 test.AssertNotError(t, err, "Failed to generate ECDSA key") 104 diskKeyBytes, err := os.ReadFile(keyPath) 105 test.AssertNotError(t, err, "Failed to load key from disk") 106 block, _ := pem.Decode(diskKeyBytes) 107 diskKey, err := x509.ParsePKIXPublicKey(block.Bytes) 108 test.AssertNotError(t, err, "Failed to parse disk key") 109 test.AssertDeepEquals(t, diskKey, keyInfo.key) 110 } 111 112 func setFindObjectsFuncs(label string, ctx *pkcs11helpers.MockCtx) { 113 var objectsFound []pkcs11.ObjectHandle 114 ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, template []*pkcs11.Attribute) error { 115 for _, attr := range template { 116 if attr.Type == pkcs11.CKA_LABEL && string(attr.Value) == label { 117 objectsFound = []pkcs11.ObjectHandle{1} 118 } 119 } 120 return nil 121 } 122 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) { 123 return objectsFound, false, nil 124 } 125 ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error { 126 objectsFound = nil 127 return nil 128 } 129 } 130 131 func TestGenerateKeySlotHasSomethingWithLabel(t *testing.T) { 132 tmp := t.TempDir() 133 134 ctx := setupCtx() 135 label := "someLabel" 136 setFindObjectsFuncs(label, &ctx) 137 keyPath := path.Join(tmp, "should-not-exist.pem") 138 s := &pkcs11helpers.Session{Module: &ctx, Session: 0} 139 _, err := generateKey(s, label, keyPath, keyGenConfig{ 140 Type: "ecdsa", 141 ECDSACurve: "P-256", 142 }) 143 test.AssertError(t, err, "expected failure for a slot with an object already in it") 144 test.Assert(t, strings.HasPrefix(err.Error(), "expected no preexisting objects with label"), "wrong error") 145 } 146 147 func TestGenerateKeySlotHasSomethingWithDifferentLabel(t *testing.T) { 148 tmp := t.TempDir() 149 150 ctx := setupCtx() 151 setECGenerateFuncs(&ctx) 152 setFindObjectsFuncs("someLabel", &ctx) 153 keyPath := path.Join(tmp, "should-not-exist.pem") 154 s := &pkcs11helpers.Session{Module: &ctx, Session: 0} 155 _, err := generateKey(s, "someOtherLabel", keyPath, keyGenConfig{ 156 Type: "ecdsa", 157 ECDSACurve: "P-256", 158 }) 159 test.AssertNotError(t, err, "expected success even though there was an object with a different label") 160 }