github.com/letsencrypt/boulder@v0.20251208.0/pkcs11helpers/helpers.go (about) 1 package pkcs11helpers 2 3 import ( 4 "crypto" 5 "crypto/ecdsa" 6 "crypto/elliptic" 7 "crypto/rsa" 8 "encoding/asn1" 9 "errors" 10 "fmt" 11 "io" 12 "math/big" 13 14 "github.com/miekg/pkcs11" 15 ) 16 17 type PKCtx interface { 18 GenerateKeyPair(pkcs11.SessionHandle, []*pkcs11.Mechanism, []*pkcs11.Attribute, []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error) 19 GetAttributeValue(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) 20 SignInit(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error 21 Sign(pkcs11.SessionHandle, []byte) ([]byte, error) 22 GenerateRandom(pkcs11.SessionHandle, int) ([]byte, error) 23 FindObjectsInit(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) error 24 FindObjects(sh pkcs11.SessionHandle, max int) ([]pkcs11.ObjectHandle, bool, error) 25 FindObjectsFinal(sh pkcs11.SessionHandle) error 26 } 27 28 // Session represents a session with a given PKCS#11 module. It is not safe for 29 // concurrent access. 30 type Session struct { 31 Module PKCtx 32 Session pkcs11.SessionHandle 33 } 34 35 func Initialize(module string, slot uint, pin string) (*Session, error) { 36 ctx := pkcs11.New(module) 37 if ctx == nil { 38 return nil, errors.New("failed to load module") 39 } 40 err := ctx.Initialize() 41 if err != nil { 42 return nil, fmt.Errorf("couldn't initialize context: %s", err) 43 } 44 45 session, err := ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) 46 if err != nil { 47 return nil, fmt.Errorf("couldn't open session: %s", err) 48 } 49 50 err = ctx.Login(session, pkcs11.CKU_USER, pin) 51 if err != nil { 52 return nil, fmt.Errorf("couldn't login: %s", err) 53 } 54 55 return &Session{ctx, session}, nil 56 } 57 58 // https://tools.ietf.org/html/rfc5759#section-3.2 59 var curveOIDs = map[string]asn1.ObjectIdentifier{ 60 "P-256": {1, 2, 840, 10045, 3, 1, 7}, 61 "P-384": {1, 3, 132, 0, 34}, 62 } 63 64 // getPublicKeyID looks up the given public key in the PKCS#11 token, and 65 // returns its ID as a []byte, for use in looking up the corresponding private 66 // key. 67 func (s *Session) getPublicKeyID(label string, publicKey crypto.PublicKey) ([]byte, error) { 68 var template []*pkcs11.Attribute 69 switch key := publicKey.(type) { 70 case *rsa.PublicKey: 71 template = []*pkcs11.Attribute{ 72 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), 73 pkcs11.NewAttribute(pkcs11.CKA_LABEL, []byte(label)), 74 pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_RSA), 75 pkcs11.NewAttribute(pkcs11.CKA_MODULUS, key.N.Bytes()), 76 pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, big.NewInt(int64(key.E)).Bytes()), 77 } 78 case *ecdsa.PublicKey: 79 // http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/os/pkcs11-curr-v2.40-os.html#_ftn1 80 // PKCS#11 v2.20 specified that the CKA_EC_POINT was to be store in a DER-encoded 81 // OCTET STRING. 82 rawValue := asn1.RawValue{ 83 Tag: asn1.TagOctetString, 84 Bytes: elliptic.Marshal(key.Curve, key.X, key.Y), 85 } 86 marshalledPoint, err := asn1.Marshal(rawValue) 87 if err != nil { 88 return nil, err 89 } 90 curveOID, err := asn1.Marshal(curveOIDs[key.Curve.Params().Name]) 91 if err != nil { 92 return nil, err 93 } 94 template = []*pkcs11.Attribute{ 95 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), 96 pkcs11.NewAttribute(pkcs11.CKA_LABEL, []byte(label)), 97 pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), 98 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, curveOID), 99 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, marshalledPoint), 100 } 101 default: 102 return nil, fmt.Errorf("unsupported public key of type %T", publicKey) 103 } 104 105 publicKeyHandle, err := s.FindObject(template) 106 if err != nil { 107 return nil, err 108 } 109 110 attrs, err := s.Module.GetAttributeValue(s.Session, publicKeyHandle, []*pkcs11.Attribute{ 111 pkcs11.NewAttribute(pkcs11.CKA_ID, nil), 112 }) 113 if err != nil { 114 return nil, err 115 } 116 if len(attrs) == 1 && attrs[0].Type == pkcs11.CKA_ID { 117 return attrs[0].Value, nil 118 } 119 return nil, fmt.Errorf("invalid result from GetAttributeValue") 120 } 121 122 // getPrivateKey gets a handle to the private key whose CKA_ID matches the 123 // provided publicKeyID. 124 func (s *Session) getPrivateKey(publicKeyID []byte) (pkcs11.ObjectHandle, error) { 125 return s.FindObject([]*pkcs11.Attribute{ 126 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), 127 pkcs11.NewAttribute(pkcs11.CKA_ID, publicKeyID), 128 }) 129 } 130 131 func (s *Session) GetAttributeValue(object pkcs11.ObjectHandle, attributes []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 132 return s.Module.GetAttributeValue(s.Session, object, attributes) 133 } 134 135 func (s *Session) GenerateKeyPair(m []*pkcs11.Mechanism, pubAttrs []*pkcs11.Attribute, privAttrs []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error) { 136 return s.Module.GenerateKeyPair(s.Session, m, pubAttrs, privAttrs) 137 } 138 139 func (s *Session) GetRSAPublicKey(object pkcs11.ObjectHandle) (*rsa.PublicKey, error) { 140 // Retrieve the public exponent and modulus for the public key 141 attrs, err := s.Module.GetAttributeValue(s.Session, object, []*pkcs11.Attribute{ 142 pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil), 143 pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil), 144 }) 145 if err != nil { 146 return nil, fmt.Errorf("Failed to retrieve key attributes: %s", err) 147 } 148 149 // Attempt to build the public key from the retrieved attributes 150 pubKey := &rsa.PublicKey{} 151 gotMod, gotExp := false, false 152 for _, a := range attrs { 153 switch a.Type { 154 case pkcs11.CKA_PUBLIC_EXPONENT: 155 pubKey.E = int(big.NewInt(0).SetBytes(a.Value).Int64()) 156 gotExp = true 157 case pkcs11.CKA_MODULUS: 158 pubKey.N = big.NewInt(0).SetBytes(a.Value) 159 gotMod = true 160 } 161 } 162 // Fail if we are missing either the public exponent or modulus 163 if !gotExp || !gotMod { 164 return nil, errors.New("Couldn't retrieve modulus and exponent") 165 } 166 return pubKey, nil 167 } 168 169 // oidDERToCurve maps the hex of the DER encoding of the various curve OIDs to 170 // the relevant curve parameters 171 var oidDERToCurve = map[string]elliptic.Curve{ 172 "06052B81040021": elliptic.P224(), 173 "06082A8648CE3D030107": elliptic.P256(), 174 "06052B81040022": elliptic.P384(), 175 "06052B81040023": elliptic.P521(), 176 } 177 178 func (s *Session) GetECDSAPublicKey(object pkcs11.ObjectHandle) (*ecdsa.PublicKey, error) { 179 // Retrieve the curve and public point for the generated public key 180 attrs, err := s.Module.GetAttributeValue(s.Session, object, []*pkcs11.Attribute{ 181 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil), 182 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil), 183 }) 184 if err != nil { 185 return nil, fmt.Errorf("Failed to retrieve key attributes: %s", err) 186 } 187 188 pubKey := &ecdsa.PublicKey{} 189 var pointBytes []byte 190 for _, a := range attrs { 191 switch a.Type { 192 case pkcs11.CKA_EC_PARAMS: 193 rCurve, present := oidDERToCurve[fmt.Sprintf("%X", a.Value)] 194 if !present { 195 return nil, errors.New("Unknown curve OID value returned") 196 } 197 pubKey.Curve = rCurve 198 case pkcs11.CKA_EC_POINT: 199 pointBytes = a.Value 200 } 201 } 202 if pointBytes == nil || pubKey.Curve == nil { 203 return nil, errors.New("Couldn't retrieve EC point and EC parameters") 204 } 205 206 x, y := elliptic.Unmarshal(pubKey.Curve, pointBytes) 207 if x == nil { 208 // http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/os/pkcs11-curr-v2.40-os.html#_ftn1 209 // PKCS#11 v2.20 specified that the CKA_EC_POINT was to be stored in a DER-encoded 210 // OCTET STRING. 211 var point asn1.RawValue 212 _, err = asn1.Unmarshal(pointBytes, &point) 213 if err != nil { 214 return nil, fmt.Errorf("Failed to unmarshal returned CKA_EC_POINT: %s", err) 215 } 216 if len(point.Bytes) == 0 { 217 return nil, errors.New("Invalid CKA_EC_POINT value returned, OCTET string is empty") 218 } 219 x, y = elliptic.Unmarshal(pubKey.Curve, point.Bytes) 220 if x == nil { 221 return nil, errors.New("Invalid CKA_EC_POINT value returned, point is malformed") 222 } 223 } 224 pubKey.X, pubKey.Y = x, y 225 226 return pubKey, nil 227 } 228 229 type keyType int 230 231 const ( 232 RSAKey keyType = iota 233 ECDSAKey 234 ) 235 236 // Hash identifiers required for PKCS#11 RSA signing. Only support SHA-256, SHA-384, 237 // and SHA-512 238 var hashIdents = map[crypto.Hash][]byte{ 239 crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, 240 crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, 241 crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, 242 } 243 244 func (s *Session) Sign(object pkcs11.ObjectHandle, keyType keyType, digest []byte, hash crypto.Hash) ([]byte, error) { 245 if len(digest) != hash.Size() { 246 return nil, errors.New("digest length doesn't match hash length") 247 } 248 249 mech := make([]*pkcs11.Mechanism, 1) 250 switch keyType { 251 case RSAKey: 252 mech[0] = pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS, nil) 253 prefix, ok := hashIdents[hash] 254 if !ok { 255 return nil, errors.New("unsupported hash function") 256 } 257 digest = append(prefix, digest...) 258 case ECDSAKey: 259 mech[0] = pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil) 260 } 261 262 err := s.Module.SignInit(s.Session, mech, object) 263 if err != nil { 264 return nil, fmt.Errorf("failed to initialize signing operation: %s", err) 265 } 266 signature, err := s.Module.Sign(s.Session, digest) 267 if err != nil { 268 return nil, fmt.Errorf("failed to sign data: %s", err) 269 } 270 271 return signature, nil 272 } 273 274 var ErrNoObject = errors.New("no objects found matching provided template") 275 276 // FindObject looks up a PKCS#11 object handle based on the provided template. 277 // In the case where zero or more than one objects are found to match the 278 // template an error is returned. 279 func (s *Session) FindObject(tmpl []*pkcs11.Attribute) (pkcs11.ObjectHandle, error) { 280 err := s.Module.FindObjectsInit(s.Session, tmpl) 281 if err != nil { 282 return 0, err 283 } 284 handles, _, err := s.Module.FindObjects(s.Session, 2) 285 if err != nil { 286 return 0, err 287 } 288 err = s.Module.FindObjectsFinal(s.Session) 289 if err != nil { 290 return 0, err 291 } 292 if len(handles) == 0 { 293 return 0, ErrNoObject 294 } 295 if len(handles) > 1 { 296 return 0, fmt.Errorf("too many objects (%d) that match the provided template", len(handles)) 297 } 298 return handles[0], nil 299 } 300 301 // x509Signer is a convenience wrapper used for converting between the 302 // PKCS#11 ECDSA signature format and the RFC 5480 one which is required 303 // for X.509 certificates 304 type x509Signer struct { 305 session *Session 306 objectHandle pkcs11.ObjectHandle 307 keyType keyType 308 309 pub crypto.PublicKey 310 } 311 312 // Sign signs a digest. If the signing key is ECDSA then the signature 313 // is converted from the PKCS#11 format to the RFC 5480 format. For RSA keys a 314 // conversion step is not needed. 315 func (p *x509Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { 316 signature, err := p.session.Sign(p.objectHandle, p.keyType, digest, opts.HashFunc()) 317 if err != nil { 318 return nil, err 319 } 320 321 if p.keyType == ECDSAKey { 322 // Convert from the PKCS#11 format to the RFC 5480 format so that 323 // it can be used in a X.509 certificate 324 r := big.NewInt(0).SetBytes(signature[:len(signature)/2]) 325 s := big.NewInt(0).SetBytes(signature[len(signature)/2:]) 326 signature, err = asn1.Marshal(struct { 327 R, S *big.Int 328 }{R: r, S: s}) 329 if err != nil { 330 return nil, fmt.Errorf("failed to convert signature to RFC 5480 format: %s", err) 331 } 332 } 333 return signature, nil 334 } 335 336 func (p *x509Signer) Public() crypto.PublicKey { 337 return p.pub 338 } 339 340 // NewSigner constructs an x509Signer for the private key object associated with the 341 // given label and public key. 342 func (s *Session) NewSigner(label string, publicKey crypto.PublicKey) (crypto.Signer, error) { 343 var kt keyType 344 switch publicKey.(type) { 345 case *rsa.PublicKey: 346 kt = RSAKey 347 case *ecdsa.PublicKey: 348 kt = ECDSAKey 349 default: 350 return nil, fmt.Errorf("unsupported public key of type %T", publicKey) 351 } 352 353 publicKeyID, err := s.getPublicKeyID(label, publicKey) 354 if err != nil { 355 return nil, fmt.Errorf("looking up public key: %s", err) 356 } 357 358 // Fetch the private key by matching its id to the public key handle. 359 privateKeyHandle, err := s.getPrivateKey(publicKeyID) 360 if err != nil { 361 return nil, fmt.Errorf("getting private key: %s", err) 362 } 363 return &x509Signer{ 364 session: s, 365 objectHandle: privateKeyHandle, 366 keyType: kt, 367 pub: publicKey, 368 }, nil 369 } 370 371 func NewMock() *MockCtx { 372 return &MockCtx{} 373 } 374 375 func NewSessionWithMock() (*Session, *MockCtx) { 376 ctx := NewMock() 377 return &Session{ctx, 0}, ctx 378 } 379 380 type MockCtx struct { 381 GenerateKeyPairFunc func(pkcs11.SessionHandle, []*pkcs11.Mechanism, []*pkcs11.Attribute, []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error) 382 GetAttributeValueFunc func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) 383 SignInitFunc func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error 384 SignFunc func(pkcs11.SessionHandle, []byte) ([]byte, error) 385 GenerateRandomFunc func(pkcs11.SessionHandle, int) ([]byte, error) 386 FindObjectsInitFunc func(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) error 387 FindObjectsFunc func(sh pkcs11.SessionHandle, max int) ([]pkcs11.ObjectHandle, bool, error) 388 FindObjectsFinalFunc func(sh pkcs11.SessionHandle) error 389 } 390 391 func (mc MockCtx) GenerateKeyPair(s pkcs11.SessionHandle, m []*pkcs11.Mechanism, a1 []*pkcs11.Attribute, a2 []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error) { 392 return mc.GenerateKeyPairFunc(s, m, a1, a2) 393 } 394 395 func (mc MockCtx) GetAttributeValue(s pkcs11.SessionHandle, o pkcs11.ObjectHandle, a []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) { 396 return mc.GetAttributeValueFunc(s, o, a) 397 } 398 399 func (mc MockCtx) SignInit(s pkcs11.SessionHandle, m []*pkcs11.Mechanism, o pkcs11.ObjectHandle) error { 400 return mc.SignInitFunc(s, m, o) 401 } 402 403 func (mc MockCtx) Sign(s pkcs11.SessionHandle, m []byte) ([]byte, error) { 404 return mc.SignFunc(s, m) 405 } 406 407 func (mc MockCtx) GenerateRandom(s pkcs11.SessionHandle, c int) ([]byte, error) { 408 return mc.GenerateRandomFunc(s, c) 409 } 410 411 func (mc MockCtx) FindObjectsInit(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) error { 412 return mc.FindObjectsInitFunc(sh, temp) 413 } 414 415 func (mc MockCtx) FindObjects(sh pkcs11.SessionHandle, max int) ([]pkcs11.ObjectHandle, bool, error) { 416 return mc.FindObjectsFunc(sh, max) 417 } 418 419 func (mc MockCtx) FindObjectsFinal(sh pkcs11.SessionHandle) error { 420 return mc.FindObjectsFinalFunc(sh) 421 }