github.com/letsencrypt/boulder@v0.20251208.0/pkcs11helpers/helpers_test.go (about) 1 package pkcs11helpers 2 3 import ( 4 "bytes" 5 "crypto" 6 "crypto/ecdsa" 7 "crypto/elliptic" 8 "crypto/rand" 9 "crypto/rsa" 10 "crypto/sha256" 11 "encoding/asn1" 12 "errors" 13 "math/big" 14 "strings" 15 "testing" 16 17 "github.com/letsencrypt/boulder/test" 18 "github.com/miekg/pkcs11" 19 ) 20 21 func TestGetECDSAPublicKey(t *testing.T) { 22 ctx := &MockCtx{} 23 s := &Session{ctx, 0} 24 25 // test attribute retrieval failing 26 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 27 return nil, errors.New("yup") 28 } 29 _, err := s.GetECDSAPublicKey(0) 30 test.AssertError(t, err, "ecPub didn't fail on GetAttributeValue error") 31 32 // test we fail to construct key with missing params and point 33 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 34 return []*pkcs11.Attribute{}, nil 35 } 36 _, err = s.GetECDSAPublicKey(0) 37 test.AssertError(t, err, "ecPub didn't fail with empty attribute list") 38 39 // test we fail to construct key with unknown curve 40 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 41 return []*pkcs11.Attribute{ 42 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{1, 2, 3}), 43 }, nil 44 } 45 _, err = s.GetECDSAPublicKey(0) 46 test.AssertError(t, err, "ecPub didn't fail with unknown curve") 47 48 // test we fail to construct key with invalid EC point (invalid encoding) 49 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 50 return []*pkcs11.Attribute{ 51 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 8, 42, 134, 72, 206, 61, 3, 1, 7}), 52 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{255}), 53 }, nil 54 } 55 _, err = s.GetECDSAPublicKey(0) 56 test.AssertError(t, err, "ecPub didn't fail with invalid EC point (invalid encoding)") 57 58 // test we fail to construct key with invalid EC point (empty octet string) 59 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 60 return []*pkcs11.Attribute{ 61 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 8, 42, 134, 72, 206, 61, 3, 1, 7}), 62 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{4, 0}), 63 }, nil 64 } 65 _, err = s.GetECDSAPublicKey(0) 66 test.AssertError(t, err, "ecPub didn't fail with invalid EC point (empty octet string)") 67 68 // test we fail to construct key with invalid EC point (octet string, invalid contents) 69 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 70 return []*pkcs11.Attribute{ 71 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 8, 42, 134, 72, 206, 61, 3, 1, 7}), 72 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{4, 4, 4, 1, 2, 3}), 73 }, nil 74 } 75 _, err = s.GetECDSAPublicKey(0) 76 test.AssertError(t, err, "ecPub didn't fail with invalid EC point (octet string, invalid contents)") 77 78 // test we don't fail with the correct attributes (traditional encoding) 79 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 80 return []*pkcs11.Attribute{ 81 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 5, 43, 129, 4, 0, 33}), 82 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{4, 217, 225, 246, 210, 153, 134, 246, 104, 95, 79, 122, 206, 135, 241, 37, 114, 199, 87, 56, 167, 83, 56, 136, 174, 6, 145, 97, 239, 221, 49, 67, 148, 13, 126, 65, 90, 208, 195, 193, 171, 105, 40, 98, 132, 124, 30, 189, 215, 197, 178, 226, 166, 238, 240, 57, 215}), 83 }, nil 84 } 85 _, err = s.GetECDSAPublicKey(0) 86 test.AssertNotError(t, err, "ecPub failed with valid attributes (traditional encoding)") 87 88 // test we don't fail with the correct attributes (non-traditional encoding) 89 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 90 return []*pkcs11.Attribute{ 91 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 5, 43, 129, 4, 0, 33}), 92 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{4, 57, 4, 217, 225, 246, 210, 153, 134, 246, 104, 95, 79, 122, 206, 135, 241, 37, 114, 199, 87, 56, 167, 83, 56, 136, 174, 6, 145, 97, 239, 221, 49, 67, 148, 13, 126, 65, 90, 208, 195, 193, 171, 105, 40, 98, 132, 124, 30, 189, 215, 197, 178, 226, 166, 238, 240, 57, 215}), 93 }, nil 94 } 95 _, err = s.GetECDSAPublicKey(0) 96 test.AssertNotError(t, err, "ecPub failed with valid attributes (non-traditional encoding)") 97 } 98 99 func TestRSAPublicKey(t *testing.T) { 100 ctx := &MockCtx{} 101 s := &Session{ctx, 0} 102 103 // test attribute retrieval failing 104 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 105 return nil, errors.New("yup") 106 } 107 _, err := s.GetRSAPublicKey(0) 108 test.AssertError(t, err, "rsaPub didn't fail on GetAttributeValue error") 109 110 // test we fail to construct key with missing modulus and exp 111 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 112 return []*pkcs11.Attribute{}, nil 113 } 114 _, err = s.GetRSAPublicKey(0) 115 test.AssertError(t, err, "rsaPub didn't fail with empty attribute list") 116 117 // test we don't fail with the correct attributes 118 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 119 return []*pkcs11.Attribute{ 120 pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, []byte{1, 0, 1}), 121 pkcs11.NewAttribute(pkcs11.CKA_MODULUS, []byte{255}), 122 }, nil 123 } 124 _, err = s.GetRSAPublicKey(0) 125 test.AssertNotError(t, err, "rsaPub failed with valid attributes") 126 } 127 128 func findObjectsInitOK(pkcs11.SessionHandle, []*pkcs11.Attribute) error { 129 return nil 130 } 131 132 func findObjectsOK(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) { 133 return []pkcs11.ObjectHandle{1}, false, nil 134 } 135 136 func findObjectsFinalOK(pkcs11.SessionHandle) error { 137 return nil 138 } 139 140 func newMock() *MockCtx { 141 return &MockCtx{ 142 FindObjectsInitFunc: findObjectsInitOK, 143 FindObjectsFunc: findObjectsOK, 144 FindObjectsFinalFunc: findObjectsFinalOK, 145 } 146 } 147 148 func newSessionWithMock() (*Session, *MockCtx) { 149 ctx := newMock() 150 return &Session{ctx, 0}, ctx 151 } 152 153 func TestFindObjectFailsOnFailedInit(t *testing.T) { 154 ctx := MockCtx{} 155 ctx.FindObjectsFinalFunc = findObjectsFinalOK 156 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) { 157 return []pkcs11.ObjectHandle{1}, false, nil 158 } 159 160 // test FindObject fails when FindObjectsInit fails 161 ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error { 162 return errors.New("broken") 163 } 164 s := &Session{ctx, 0} 165 _, err := s.FindObject(nil) 166 test.AssertError(t, err, "FindObject didn't fail when FindObjectsInit failed") 167 } 168 169 func TestFindObjectFailsOnFailedFindObjects(t *testing.T) { 170 ctx := MockCtx{} 171 ctx.FindObjectsInitFunc = findObjectsInitOK 172 ctx.FindObjectsFinalFunc = findObjectsFinalOK 173 174 // test FindObject fails when FindObjects fails 175 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) { 176 return nil, false, errors.New("broken") 177 } 178 s := &Session{ctx, 0} 179 _, err := s.FindObject(nil) 180 test.AssertError(t, err, "FindObject didn't fail when FindObjects failed") 181 } 182 183 func TestFindObjectFailsOnNoHandles(t *testing.T) { 184 ctx := MockCtx{} 185 ctx.FindObjectsInitFunc = findObjectsInitOK 186 ctx.FindObjectsFinalFunc = findObjectsFinalOK 187 188 // test FindObject fails when no handles are returned 189 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) { 190 return []pkcs11.ObjectHandle{}, false, nil 191 } 192 s := &Session{ctx, 0} 193 _, err := s.FindObject(nil) 194 test.AssertEquals(t, err, ErrNoObject) 195 } 196 197 func TestFindObjectFailsOnMultipleHandles(t *testing.T) { 198 ctx := MockCtx{} 199 ctx.FindObjectsInitFunc = findObjectsInitOK 200 ctx.FindObjectsFinalFunc = findObjectsFinalOK 201 202 // test FindObject fails when multiple handles are returned 203 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) { 204 return []pkcs11.ObjectHandle{1, 2, 3}, false, nil 205 } 206 s := &Session{ctx, 0} 207 _, err := s.FindObject(nil) 208 test.AssertError(t, err, "FindObject didn't fail when FindObjects returns multiple handles") 209 test.Assert(t, strings.HasPrefix(err.Error(), "too many objects"), "FindObject failed with wrong error") 210 } 211 212 func TestFindObjectFailsOnFinalizeFailure(t *testing.T) { 213 ctx := MockCtx{} 214 ctx.FindObjectsInitFunc = findObjectsInitOK 215 216 // test FindObject fails when FindObjectsFinal fails 217 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) { 218 return []pkcs11.ObjectHandle{1}, false, nil 219 } 220 ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error { 221 return errors.New("broken") 222 } 223 s := &Session{ctx, 0} 224 _, err := s.FindObject(nil) 225 test.AssertError(t, err, "FindObject didn't fail when FindObjectsFinal fails") 226 } 227 228 func TestFindObjectSucceeds(t *testing.T) { 229 ctx := MockCtx{} 230 ctx.FindObjectsInitFunc = findObjectsInitOK 231 ctx.FindObjectsFinalFunc = findObjectsFinalOK 232 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) { 233 return []pkcs11.ObjectHandle{1}, false, nil 234 } 235 s := &Session{ctx, 0} 236 237 // test FindObject works 238 handle, err := s.FindObject(nil) 239 test.AssertNotError(t, err, "FindObject failed when everything worked as expected") 240 test.AssertEquals(t, handle, pkcs11.ObjectHandle(1)) 241 } 242 243 func TestX509Signer(t *testing.T) { 244 ctx := MockCtx{} 245 246 // test that x509Signer.Sign properly converts the PKCS#11 format signature to 247 // the RFC 5480 format signature 248 ctx.SignInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error { 249 return nil 250 } 251 tk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 252 test.AssertNotError(t, err, "Failed to generate test key") 253 ctx.SignFunc = func(_ pkcs11.SessionHandle, digest []byte) ([]byte, error) { 254 r, s, err := ecdsa.Sign(rand.Reader, tk, digest[:]) 255 if err != nil { 256 return nil, err 257 } 258 rBytes := r.Bytes() 259 sBytes := s.Bytes() 260 // http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/os/pkcs11-curr-v2.40-os.html 261 // Section 2.3.1: EC Signatures 262 // "If r and s have different octet length, the shorter of both must be padded with 263 // leading zero octets such that both have the same octet length." 264 switch { 265 case len(rBytes) < len(sBytes): 266 padding := make([]byte, len(sBytes)-len(rBytes)) 267 rBytes = append(padding, rBytes...) 268 case len(rBytes) > len(sBytes): 269 padding := make([]byte, len(rBytes)-len(sBytes)) 270 sBytes = append(padding, sBytes...) 271 } 272 return append(rBytes, sBytes...), nil 273 } 274 digest := sha256.Sum256([]byte("hello")) 275 s := &Session{ctx, 0} 276 signer := &x509Signer{session: s, keyType: ECDSAKey, pub: tk.Public()} 277 signature, err := signer.Sign(nil, digest[:], crypto.SHA256) 278 test.AssertNotError(t, err, "x509Signer.Sign failed") 279 280 var rfcFormat struct { 281 R, S *big.Int 282 } 283 rest, err := asn1.Unmarshal(signature, &rfcFormat) 284 test.AssertNotError(t, err, "asn1.Unmarshal failed trying to parse signature") 285 test.Assert(t, len(rest) == 0, "Signature had trailing garbage") 286 verified := ecdsa.Verify(&tk.PublicKey, digest[:], rfcFormat.R, rfcFormat.S) 287 test.Assert(t, verified, "Failed to verify RFC format signature") 288 // For the sake of coverage 289 test.AssertEquals(t, signer.Public(), tk.Public()) 290 } 291 292 func TestGetKeyWhenLabelIsWrong(t *testing.T) { 293 s, ctx := newSessionWithMock() 294 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1} 295 rightLabel := "label" 296 var objectsToReturn []pkcs11.ObjectHandle 297 298 ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, attr []*pkcs11.Attribute) error { 299 objectsToReturn = []pkcs11.ObjectHandle{1} 300 for _, a := range attr { 301 if a.Type == pkcs11.CKA_LABEL && !bytes.Equal(a.Value, []byte(rightLabel)) { 302 objectsToReturn = nil 303 } 304 } 305 return nil 306 } 307 ctx.FindObjectsFunc = func(_ pkcs11.SessionHandle, _ int) ([]pkcs11.ObjectHandle, bool, error) { 308 return objectsToReturn, false, nil 309 } 310 ctx.FindObjectsFinalFunc = func(_ pkcs11.SessionHandle) error { 311 return nil 312 } 313 314 _, err := s.NewSigner("wrong-label", pubKey) 315 test.AssertError(t, err, "newSigner didn't fail when label was a mismatch for public key") 316 expected := "no objects found matching provided template" 317 if !strings.Contains(err.Error(), expected) { 318 t.Errorf("expected error to contain %q but it was %q", expected, err) 319 } 320 } 321 322 func TestGetKeyWhenGetAttributeValueFails(t *testing.T) { 323 s, ctx := newSessionWithMock() 324 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1} 325 326 // test newSigner fails when GetAttributeValue fails 327 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 328 return nil, errors.New("broken") 329 } 330 _, err := s.NewSigner("label", pubKey) 331 test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type failed") 332 } 333 334 func TestGetKeyWhenGetAttributeValueReturnsNone(t *testing.T) { 335 s, ctx := newSessionWithMock() 336 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1} 337 338 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 339 return nil, errors.New("broken") 340 } 341 // test newSigner fails when GetAttributeValue returns no attributes 342 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 343 return nil, nil 344 } 345 _, err := s.NewSigner("label", pubKey) 346 test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type returned no attributes") 347 } 348 349 func TestGetKeyWhenFindObjectForPublicKeyFails(t *testing.T) { 350 s, ctx := newSessionWithMock() 351 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1} 352 353 // test newSigner fails when FindObject for public key 354 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 355 return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC)}, nil 356 } 357 ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error { 358 if bytes.Equal(tmpl[0].Value, []byte{2, 0, 0, 0, 0, 0, 0, 0}) { 359 return errors.New("broken") 360 } 361 return nil 362 } 363 _, err := s.NewSigner("label", pubKey) 364 test.AssertError(t, err, "newSigner didn't fail when FindObject for public key handle failed") 365 } 366 367 func TestGetKeyWhenFindObjectForPrivateKeyReturnsUnknownType(t *testing.T) { 368 s, ctx := newSessionWithMock() 369 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1} 370 371 // test newSigner fails when FindObject for private key returns unknown CKA_KEY_TYPE 372 ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error { 373 return nil 374 } 375 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 376 return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{2, 0, 0, 0, 0, 0, 0, 0})}, nil 377 } 378 _, err := s.NewSigner("label", pubKey) 379 test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key returned unknown key type") 380 } 381 382 func TestGetKeyWhenFindObjectForPrivateKeyFails(t *testing.T) { 383 s, ctx := newSessionWithMock() 384 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1} 385 386 // test newSigner fails when FindObject for private key fails 387 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 388 return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{0, 0, 0, 0, 0, 0, 0, 0})}, nil 389 } 390 _, err := s.NewSigner("label", pubKey) 391 test.AssertError(t, err, "newSigner didn't fail when GetRSAPublicKey fails") 392 393 // test newSigner fails when GetECDSAPublicKey fails 394 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 395 return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{3, 0, 0, 0, 0, 0, 0, 0})}, nil 396 } 397 _, err = s.NewSigner("label", pubKey) 398 test.AssertError(t, err, "newSigner didn't fail when GetECDSAPublicKey fails") 399 } 400 401 func TestGetKeySucceeds(t *testing.T) { 402 s, ctx := newSessionWithMock() 403 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1} 404 405 // test newSigner works when everything... works 406 ctx.GetAttributeValueFunc = func(_ pkcs11.SessionHandle, _ pkcs11.ObjectHandle, attrs []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 407 var returns []*pkcs11.Attribute 408 for _, attr := range attrs { 409 switch attr.Type { 410 case pkcs11.CKA_ID: 411 returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_ID, []byte{99})) 412 default: 413 return nil, errors.New("GetAttributeValue got unexpected attribute type") 414 } 415 } 416 return returns, nil 417 } 418 _, err := s.NewSigner("label", pubKey) 419 test.AssertNotError(t, err, "newSigner failed when everything worked properly") 420 }