...

Source file src/github.com/ThalesIgnite/crypto11/keys.go

Documentation: github.com/ThalesIgnite/crypto11

     1  // Copyright 2016, 2017 Thales e-Security, Inc
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining
     4  // a copy of this software and associated documentation files (the
     5  // "Software"), to deal in the Software without restriction, including
     6  // without limitation the rights to use, copy, modify, merge, publish,
     7  // distribute, sublicense, and/or sell copies of the Software, and to
     8  // permit persons to whom the Software is furnished to do so, subject to
     9  // the following conditions:
    10  //
    11  // The above copyright notice and this permission notice shall be
    12  // included in all copies or substantial portions of the Software.
    13  //
    14  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    15  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    16  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    17  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    18  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    19  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    20  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21  
    22  package crypto11
    23  
    24  import (
    25  	"crypto"
    26  	"crypto/x509"
    27  	"github.com/miekg/pkcs11"
    28  	"github.com/pkg/errors"
    29  )
    30  
    31  const maxHandlePerFind = 20
    32  
    33  // errNoCkaId is returned if a private key is found which has no CKA_ID attribute
    34  var errNoCkaId = errors.New("private key has no CKA_ID")
    35  
    36  // errNoPublicHalf is returned if a public half cannot be found to match a given private key
    37  var errNoPublicHalf = errors.New("could not find public key to match private key")
    38  
    39  func findKeysWithAttributes(session *pkcs11Session, template []*pkcs11.Attribute) (handles []pkcs11.ObjectHandle, err error) {
    40  	if err = session.ctx.FindObjectsInit(session.handle, template); err != nil {
    41  		return nil, err
    42  	}
    43  	defer func() {
    44  		finalErr := session.ctx.FindObjectsFinal(session.handle)
    45  		if err == nil {
    46  			err = finalErr
    47  		}
    48  	}()
    49  
    50  	newhandles, _, err := session.ctx.FindObjects(session.handle, maxHandlePerFind)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	for len(newhandles) > 0 {
    56  		handles = append(handles, newhandles...)
    57  
    58  		newhandles, _, err = session.ctx.FindObjects(session.handle, maxHandlePerFind)
    59  		if err != nil {
    60  			return nil, err
    61  		}
    62  	}
    63  
    64  	return handles, nil
    65  }
    66  
    67  // Find key objects.  For asymmetric keys this only finds one half so
    68  // callers will call it twice. Returns nil if the key does not exist on the token.
    69  func findKeys(session *pkcs11Session, id []byte, label []byte, keyclass *uint, keytype *uint) (handles []pkcs11.ObjectHandle, err error) {
    70  	var template []*pkcs11.Attribute
    71  
    72  	if keyclass != nil {
    73  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_CLASS, *keyclass))
    74  	}
    75  	if keytype != nil {
    76  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, *keytype))
    77  	}
    78  	if id != nil {
    79  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_ID, id))
    80  	}
    81  	if label != nil {
    82  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_LABEL, label))
    83  	}
    84  
    85  	if handles, err = findKeysWithAttributes(session, template); err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	return handles, nil
    90  }
    91  
    92  // Find a key object.  For asymmetric keys this only finds one half so
    93  // callers will call it twice. Returns nil if the key does not exist on the token.
    94  func findKey(session *pkcs11Session, id []byte, label []byte, keyclass *uint, keytype *uint) (obj *pkcs11.ObjectHandle, err error) {
    95  	handles, err := findKeys(session, id, label, keyclass, keytype)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	if len(handles) == 0 {
   101  		return nil, nil
   102  	}
   103  	return &handles[0], nil
   104  }
   105  
   106  // Takes a handles to the private half of a keypair, locates the public half with the matching CKA_ID and CKA_LABEL
   107  // values and constructs a keypair object from them both.
   108  func (c *Context) makeKeyPair(session *pkcs11Session, privHandle *pkcs11.ObjectHandle) (signer Signer, certificate *x509.Certificate, err error) {
   109  	attributes := []*pkcs11.Attribute{
   110  		pkcs11.NewAttribute(pkcs11.CKA_ID, nil),
   111  		pkcs11.NewAttribute(pkcs11.CKA_LABEL, nil),
   112  		pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, 0),
   113  	}
   114  	if attributes, err = session.ctx.GetAttributeValue(session.handle, *privHandle, attributes); err != nil {
   115  		return nil, nil, err
   116  	}
   117  	id := attributes[0].Value
   118  	label := attributes[1].Value
   119  	keyType := bytesToUlong(attributes[2].Value)
   120  
   121  	// Ensure the private key actually has a non-empty CKA_ID to match on
   122  	if id == nil || len(id) == 0 {
   123  		return nil, nil, errNoCkaId
   124  	}
   125  
   126  	var pubHandle *pkcs11.ObjectHandle
   127  
   128  	// Find the public half which has a matching CKA_ID
   129  	pubHandle, err = findKey(session, id, label, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType)
   130  	if err != nil {
   131  		p11Err, ok := err.(pkcs11.Error)
   132  
   133  		if len(label) == 0 && ok && p11Err == pkcs11.CKR_TEMPLATE_INCONSISTENT {
   134  			// This probably means we are using a token that doesn't like us passing empty attributes in a template.
   135  			// For instance CloudHSM cannot search for a key with CKA_LABEL="". So if the private key doesn't have a
   136  			// label, we need to pass nil into findKeys, then match against the first key without a label.
   137  
   138  			pubHandles, err := findKeys(session, id, nil, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType)
   139  			if err != nil {
   140  				return nil, nil, err
   141  			}
   142  
   143  			for _, handle := range pubHandles {
   144  				template := []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_LABEL, nil)}
   145  				template, err = session.ctx.GetAttributeValue(session.handle, handle, template)
   146  				if err != nil {
   147  					return nil, nil, err
   148  				}
   149  				if len(template[0].Value) == 0 {
   150  					pubHandle = &handle
   151  					break
   152  				}
   153  			}
   154  		} else {
   155  			return nil, nil, err
   156  		}
   157  	}
   158  
   159  	if pubHandle == nil {
   160  		// Try harder to find a matching public key, based on CKA_ID alone
   161  		pubHandle, err = findKey(session, id, nil, uintPtr(pkcs11.CKO_PUBLIC_KEY), &keyType)
   162  	}
   163  
   164  	resultPkcs11PrivateKey := pkcs11PrivateKey{
   165  		pkcs11Object: pkcs11Object{
   166  			handle:  *privHandle,
   167  			context: c,
   168  		},
   169  	}
   170  
   171  	var pub crypto.PublicKey
   172  	certificate, _ = findCertificate(session, id, nil, nil)
   173  	if certificate != nil && pubHandle == nil {
   174  		pub = certificate.PublicKey
   175  	}
   176  
   177  	if pub == nil && pubHandle == nil {
   178  		// We can't return a Signer if we don't have private and public key. Treat it as an error.
   179  		return nil, nil, errNoPublicHalf
   180  	}
   181  
   182  	switch keyType {
   183  	case pkcs11.CKK_DSA:
   184  		result := &pkcs11PrivateKeyDSA{pkcs11PrivateKey: resultPkcs11PrivateKey}
   185  		if pubHandle != nil {
   186  			if pub, err = exportDSAPublicKey(session, *pubHandle); err != nil {
   187  				return nil, nil, err
   188  			}
   189  			result.pkcs11PrivateKey.pubKeyHandle = *pubHandle
   190  		}
   191  
   192  		result.pkcs11PrivateKey.pubKey = pub
   193  		return result, certificate, nil
   194  
   195  	case pkcs11.CKK_RSA:
   196  		result := &pkcs11PrivateKeyRSA{pkcs11PrivateKey: resultPkcs11PrivateKey}
   197  		if pubHandle != nil {
   198  			if pub, err = exportRSAPublicKey(session, *pubHandle); err != nil {
   199  				return nil, nil, err
   200  			}
   201  			result.pkcs11PrivateKey.pubKeyHandle = *pubHandle
   202  		}
   203  
   204  		result.pkcs11PrivateKey.pubKey = pub
   205  		return result, certificate, nil
   206  
   207  	case pkcs11.CKK_ECDSA:
   208  		result := &pkcs11PrivateKeyECDSA{pkcs11PrivateKey: resultPkcs11PrivateKey}
   209  		if pubHandle != nil {
   210  			if pub, err = exportECDSAPublicKey(session, *pubHandle); err != nil {
   211  				return nil, nil, err
   212  			}
   213  			result.pkcs11PrivateKey.pubKeyHandle = *pubHandle
   214  		}
   215  
   216  		result.pkcs11PrivateKey.pubKey = pub
   217  		return result, certificate, nil
   218  
   219  	default:
   220  		return nil, nil, errors.Errorf("unsupported key type: %X", keyType)
   221  	}
   222  }
   223  
   224  // FindKeyPair retrieves a previously created asymmetric key pair, or nil if it cannot be found.
   225  //
   226  // At least one of id and label must be specified.
   227  // Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key.
   228  // If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned
   229  // because we cannot implement crypto.Signer without the public key.
   230  func (c *Context) FindKeyPair(id []byte, label []byte) (Signer, error) {
   231  	if c.closed.Get() {
   232  		return nil, errClosed
   233  	}
   234  
   235  	result, err := c.FindKeyPairs(id, label)
   236  	if err != nil {
   237  		return nil, err
   238  	}
   239  
   240  	if len(result) == 0 {
   241  		return nil, nil
   242  	}
   243  
   244  	return result[0], nil
   245  }
   246  
   247  // FindKeyPairs retrieves all matching asymmetric key pairs, or a nil slice if none can be found.
   248  //
   249  // At least one of id and label must be specified.
   250  // Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key.
   251  // If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned
   252  // because we cannot implement crypto.Signer without the public key.
   253  func (c *Context) FindKeyPairs(id []byte, label []byte) (signer []Signer, err error) {
   254  	if c.closed.Get() {
   255  		return nil, errClosed
   256  	}
   257  
   258  	if id == nil && label == nil {
   259  		return nil, errors.New("id and label cannot both be nil")
   260  	}
   261  
   262  	attributes := NewAttributeSet()
   263  
   264  	if id != nil {
   265  		err = attributes.Set(CkaId, id)
   266  		if err != nil {
   267  			return nil, err
   268  		}
   269  	}
   270  	if label != nil {
   271  		err = attributes.Set(CkaLabel, label)
   272  		if err != nil {
   273  			return nil, err
   274  		}
   275  	}
   276  
   277  	return c.FindKeyPairsWithAttributes(attributes)
   278  }
   279  
   280  // FindKeyPairWithAttributes retrieves a previously created asymmetric key pair, or nil if it cannot be found.
   281  // The given attributes are matched against the private half only. Then the public half with a matching CKA_ID
   282  // and CKA_LABEL values is found.
   283  //
   284  // Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key.
   285  // If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned
   286  // because we cannot implement crypto.Signer without the public key.
   287  func (c *Context) FindKeyPairWithAttributes(attributes AttributeSet) (Signer, error) {
   288  	if c.closed.Get() {
   289  		return nil, errClosed
   290  	}
   291  
   292  	result, err := c.FindKeyPairsWithAttributes(attributes)
   293  	if err != nil {
   294  		return nil, err
   295  	}
   296  
   297  	if len(result) == 0 {
   298  		return nil, nil
   299  	}
   300  
   301  	return result[0], nil
   302  }
   303  
   304  // FindKeyPairsWithAttributes retrieves previously created asymmetric key pairs, or nil if none can be found.
   305  // The given attributes are matched against the private half only. Then the public half with a matching CKA_ID
   306  // and CKA_LABEL values is found.
   307  //
   308  // Only private keys that have a non-empty CKA_ID will be found, as this is required to locate the matching public key.
   309  // If the private key is found, but the public key with a corresponding CKA_ID is not, the key is not returned
   310  // because we cannot implement crypto.Signer without the public key.
   311  func (c *Context) FindKeyPairsWithAttributes(attributes AttributeSet) (signer []Signer, err error) {
   312  	if c.closed.Get() {
   313  		return nil, errClosed
   314  	}
   315  
   316  	var keys []Signer
   317  
   318  	if _, ok := attributes[CkaClass]; ok {
   319  		return nil, errors.Errorf("keypair attribute set must not contain CkaClass")
   320  	}
   321  
   322  	err = c.withSession(func(session *pkcs11Session) error {
   323  		// Add the private key class to the template to find the private half
   324  		privAttributes := attributes.Copy()
   325  		err = privAttributes.Set(CkaClass, pkcs11.CKO_PRIVATE_KEY)
   326  		if err != nil {
   327  			return err
   328  		}
   329  
   330  		privHandles, err := findKeysWithAttributes(session, privAttributes.ToSlice())
   331  		if err != nil {
   332  			return err
   333  		}
   334  
   335  		for _, privHandle := range privHandles {
   336  			k, _, err := c.makeKeyPair(session, &privHandle)
   337  
   338  			if err == errNoCkaId || err == errNoPublicHalf {
   339  				continue
   340  			}
   341  			if err != nil {
   342  				return err
   343  			}
   344  
   345  			keys = append(keys, k)
   346  		}
   347  
   348  		return nil
   349  	})
   350  
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  
   355  	return keys, nil
   356  }
   357  
   358  // FindAllKeyPairs retrieves all existing asymmetric key pairs, or a nil slice if none can be found.
   359  //
   360  // If a private key is found, but the corresponding public key is not, the key is not returned because we cannot
   361  // implement crypto.Signer without the public key.
   362  func (c *Context) FindAllKeyPairs() ([]Signer, error) {
   363  	if c.closed.Get() {
   364  		return nil, errClosed
   365  	}
   366  
   367  	return c.FindKeyPairsWithAttributes(NewAttributeSet())
   368  }
   369  
   370  // Public returns the public half of a private key.
   371  //
   372  // This partially implements the go.crypto.Signer and go.crypto.Decrypter interfaces for
   373  // pkcs11PrivateKey. (The remains of the implementation is in the
   374  // key-specific types.)
   375  func (k pkcs11PrivateKey) Public() crypto.PublicKey {
   376  	return k.pubKey
   377  }
   378  
   379  // FindKey retrieves a previously created symmetric key, or nil if it cannot be found.
   380  //
   381  // Either (but not both) of id and label may be nil, in which case they are ignored.
   382  func (c *Context) FindKey(id []byte, label []byte) (*SecretKey, error) {
   383  	if c.closed.Get() {
   384  		return nil, errClosed
   385  	}
   386  
   387  	result, err := c.FindKeys(id, label)
   388  	if err != nil {
   389  		return nil, err
   390  	}
   391  
   392  	if len(result) == 0 {
   393  		return nil, nil
   394  	}
   395  
   396  	return result[0], nil
   397  }
   398  
   399  // FindKeys retrieves all matching symmetric keys, or a nil slice if none can be found.
   400  //
   401  // At least one of id and label must be specified.
   402  func (c *Context) FindKeys(id []byte, label []byte) (key []*SecretKey, err error) {
   403  	if c.closed.Get() {
   404  		return nil, errClosed
   405  	}
   406  
   407  	if id == nil && label == nil {
   408  		return nil, errors.New("id and label cannot both be nil")
   409  	}
   410  
   411  	attributes := NewAttributeSet()
   412  
   413  	if id != nil {
   414  		err = attributes.Set(CkaId, id)
   415  		if err != nil {
   416  			return nil, err
   417  		}
   418  	}
   419  	if label != nil {
   420  		err = attributes.Set(CkaLabel, label)
   421  		if err != nil {
   422  			return nil, err
   423  		}
   424  	}
   425  
   426  	return c.FindKeysWithAttributes(attributes)
   427  }
   428  
   429  // FindKeyWithAttributes retrieves a previously created symmetric key, or nil if it cannot be found.
   430  func (c *Context) FindKeyWithAttributes(attributes AttributeSet) (*SecretKey, error) {
   431  	if c.closed.Get() {
   432  		return nil, errClosed
   433  	}
   434  
   435  	result, err := c.FindKeysWithAttributes(attributes)
   436  	if err != nil {
   437  		return nil, err
   438  	}
   439  
   440  	if len(result) == 0 {
   441  		return nil, nil
   442  	}
   443  
   444  	return result[0], nil
   445  }
   446  
   447  // FindKeysWithAttributes retrieves previously created symmetric keys, or a nil slice if none can be found.
   448  func (c *Context) FindKeysWithAttributes(attributes AttributeSet) ([]*SecretKey, error) {
   449  	if c.closed.Get() {
   450  		return nil, errClosed
   451  	}
   452  
   453  	var keys []*SecretKey
   454  
   455  	if _, ok := attributes[CkaClass]; ok {
   456  		return nil, errors.Errorf("key attribute set must not contain CkaClass")
   457  	}
   458  
   459  	err := c.withSession(func(session *pkcs11Session) error {
   460  		// Add the private key class to the template to find the private half
   461  		privAttributes := attributes.Copy()
   462  		err := privAttributes.Set(CkaClass, pkcs11.CKO_SECRET_KEY)
   463  		if err != nil {
   464  			return err
   465  		}
   466  
   467  		privHandles, err := findKeysWithAttributes(session, privAttributes.ToSlice())
   468  		if err != nil {
   469  			return err
   470  		}
   471  
   472  		for _, privHandle := range privHandles {
   473  			attributes := []*pkcs11.Attribute{
   474  				pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, 0),
   475  			}
   476  			if attributes, err = session.ctx.GetAttributeValue(session.handle, privHandle, attributes); err != nil {
   477  				return err
   478  			}
   479  			keyType := bytesToUlong(attributes[0].Value)
   480  
   481  			if cipher, ok := Ciphers[int(keyType)]; ok {
   482  				k := &SecretKey{pkcs11Object{privHandle, c}, cipher}
   483  				keys = append(keys, k)
   484  			} else {
   485  				return errors.Errorf("unsupported key type: %X", keyType)
   486  			}
   487  		}
   488  
   489  		return nil
   490  	})
   491  
   492  	if err != nil {
   493  		return nil, err
   494  	}
   495  	return keys, nil
   496  }
   497  
   498  // FindAllKeyPairs retrieves all existing symmetric keys, or a nil slice if none can be found.
   499  func (c *Context) FindAllKeys() ([]*SecretKey, error) {
   500  	if c.closed.Get() {
   501  		return nil, errClosed
   502  	}
   503  
   504  	return c.FindKeysWithAttributes(NewAttributeSet())
   505  }
   506  
   507  func uintPtr(i uint) *uint { return &i }
   508  
   509  func (c *Context) getAttributes(handle pkcs11.ObjectHandle, attributes []AttributeType) (a AttributeSet, err error) {
   510  	values := NewAttributeSet()
   511  
   512  	err = c.withSession(func(session *pkcs11Session) error {
   513  		var attrs []*pkcs11.Attribute
   514  		for _, a := range attributes {
   515  			attrs = append(attrs, pkcs11.NewAttribute(a, nil))
   516  		}
   517  
   518  		p11values, err := session.ctx.GetAttributeValue(session.handle, handle, attrs)
   519  		if err != nil {
   520  			return err
   521  		}
   522  
   523  		values.AddIfNotPresent(p11values)
   524  
   525  		return nil
   526  	})
   527  
   528  	return values, err
   529  }
   530  
   531  // GetAttributes gets the values of the specified attributes on the given key or keypair.
   532  // If the key is asymmetric, then the attributes are retrieved from the private half.
   533  //
   534  // If the object is not a crypto11 key or keypair then an error is returned.
   535  func (c *Context) GetAttributes(key interface{}, attributes []AttributeType) (a AttributeSet, err error) {
   536  	if c.closed.Get() {
   537  		return nil, errClosed
   538  	}
   539  
   540  	var handle pkcs11.ObjectHandle
   541  
   542  	switch k := (key).(type) {
   543  	case *pkcs11PrivateKeyDSA:
   544  		handle = k.handle
   545  	case *pkcs11PrivateKeyRSA:
   546  		handle = k.handle
   547  	case *pkcs11PrivateKeyECDSA:
   548  		handle = k.handle
   549  	case *SecretKey:
   550  		handle = k.handle
   551  	default:
   552  		return nil, errors.Errorf("not a PKCS#11 key")
   553  	}
   554  
   555  	return c.getAttributes(handle, attributes)
   556  }
   557  
   558  // GetAttribute gets the value of the specified attribute on the given key or keypair.
   559  // If the key is asymmetric, then the attribute is retrieved from the private half.
   560  //
   561  // If the object is not a crypto11 key or keypair then an error is returned.
   562  func (c *Context) GetAttribute(key interface{}, attribute AttributeType) (a *Attribute, err error) {
   563  	if c.closed.Get() {
   564  		return nil, errClosed
   565  	}
   566  
   567  	set, err := c.GetAttributes(key, []AttributeType{attribute})
   568  	if err != nil {
   569  		return nil, err
   570  	}
   571  
   572  	return set[attribute], nil
   573  }
   574  
   575  // GetPubAttributes gets the values of the specified attributes on the public half of the given keypair.
   576  //
   577  // If the object is not a crypto11 keypair then an error is returned.
   578  func (c *Context) GetPubAttributes(key interface{}, attributes []AttributeType) (a AttributeSet, err error) {
   579  	if c.closed.Get() {
   580  		return nil, errClosed
   581  	}
   582  
   583  	var handle pkcs11.ObjectHandle
   584  
   585  	switch k := (key).(type) {
   586  	case *pkcs11PrivateKeyDSA:
   587  		handle = k.pubKeyHandle
   588  	case *pkcs11PrivateKeyRSA:
   589  		handle = k.pubKeyHandle
   590  	case *pkcs11PrivateKeyECDSA:
   591  		handle = k.pubKeyHandle
   592  	default:
   593  		return nil, errors.Errorf("not an asymmetric PKCS#11 key")
   594  	}
   595  
   596  	return c.getAttributes(handle, attributes)
   597  }
   598  
   599  // GetPubAttribute gets the value of the specified attribute on the public half of the given key.
   600  //
   601  // If the object is not a crypto11 keypair then an error is returned.
   602  func (c *Context) GetPubAttribute(key interface{}, attribute AttributeType) (a *Attribute, err error) {
   603  	if c.closed.Get() {
   604  		return nil, errClosed
   605  	}
   606  
   607  	set, err := c.GetPubAttributes(key, []AttributeType{attribute})
   608  	if err != nil {
   609  		return nil, err
   610  	}
   611  
   612  	return set[attribute], nil
   613  }
   614  

View as plain text