...

Source file src/github.com/letsencrypt/boulder/pkcs11helpers/helpers.go

Documentation: github.com/letsencrypt/boulder/pkcs11helpers

     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:   4, // in Go 1.6+ this is 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 hashIdentifiers = 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 := hashIdentifiers[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  }
   422  

View as plain text