...

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

Documentation: github.com/ThalesIgnite/crypto11

     1  // Copyright 2018 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  	"errors"
    26  
    27  	"github.com/miekg/pkcs11"
    28  )
    29  
    30  // SymmetricGenParams holds a consistent (key type, mechanism) key generation pair.
    31  type SymmetricGenParams struct {
    32  	// Key type (CKK_...)
    33  	KeyType uint
    34  
    35  	// Key generation mechanism (CKM_..._KEY_GEN)
    36  	GenMech uint
    37  }
    38  
    39  // SymmetricCipher represents information about a symmetric cipher.
    40  type SymmetricCipher struct {
    41  	// Possible key generation parameters
    42  	// (For HMAC this varies between PKCS#11 implementations.)
    43  	GenParams []SymmetricGenParams
    44  
    45  	// Block size in bytes
    46  	BlockSize int
    47  
    48  	// True if encryption supported
    49  	Encrypt bool
    50  
    51  	// True if MAC supported
    52  	MAC bool
    53  
    54  	// ECB mechanism (CKM_..._ECB)
    55  	ECBMech uint
    56  
    57  	// CBC mechanism (CKM_..._CBC)
    58  	CBCMech uint
    59  
    60  	// CBC mechanism with PKCS#7 padding (CKM_..._CBC)
    61  	CBCPKCSMech uint
    62  
    63  	// GCM mechanism (CKM_..._GCM)
    64  	GCMMech uint
    65  }
    66  
    67  // CipherAES describes the AES cipher. Use this with the
    68  // GenerateSecretKey... functions.
    69  var CipherAES = &SymmetricCipher{
    70  	GenParams: []SymmetricGenParams{
    71  		{
    72  			KeyType: pkcs11.CKK_AES,
    73  			GenMech: pkcs11.CKM_AES_KEY_GEN,
    74  		},
    75  	},
    76  	BlockSize:   16,
    77  	Encrypt:     true,
    78  	MAC:         false,
    79  	ECBMech:     pkcs11.CKM_AES_ECB,
    80  	CBCMech:     pkcs11.CKM_AES_CBC,
    81  	CBCPKCSMech: pkcs11.CKM_AES_CBC_PAD,
    82  	GCMMech:     pkcs11.CKM_AES_GCM,
    83  }
    84  
    85  // CipherDES3 describes the three-key triple-DES cipher. Use this with the
    86  // GenerateSecretKey... functions.
    87  var CipherDES3 = &SymmetricCipher{
    88  	GenParams: []SymmetricGenParams{
    89  		{
    90  			KeyType: pkcs11.CKK_DES3,
    91  			GenMech: pkcs11.CKM_DES3_KEY_GEN,
    92  		},
    93  	},
    94  	BlockSize:   8,
    95  	Encrypt:     true,
    96  	MAC:         false,
    97  	ECBMech:     pkcs11.CKM_DES3_ECB,
    98  	CBCMech:     pkcs11.CKM_DES3_CBC,
    99  	CBCPKCSMech: pkcs11.CKM_DES3_CBC_PAD,
   100  	GCMMech:     0,
   101  }
   102  
   103  // CipherGeneric describes the CKK_GENERIC_SECRET key type. Use this with the
   104  // GenerateSecretKey... functions.
   105  //
   106  // The spec promises that this mechanism can be used to perform HMAC
   107  // operations, although implementations vary;
   108  // CipherHMACSHA1 and so on may give better results.
   109  var CipherGeneric = &SymmetricCipher{
   110  	GenParams: []SymmetricGenParams{
   111  		{
   112  			KeyType: pkcs11.CKK_GENERIC_SECRET,
   113  			GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
   114  		},
   115  	},
   116  	BlockSize: 64,
   117  	Encrypt:   false,
   118  	MAC:       true,
   119  	ECBMech:   0,
   120  	CBCMech:   0,
   121  	GCMMech:   0,
   122  }
   123  
   124  // CipherHMACSHA1 describes the CKK_SHA_1_HMAC key type. Use this with the
   125  // GenerateSecretKey... functions.
   126  var CipherHMACSHA1 = &SymmetricCipher{
   127  	GenParams: []SymmetricGenParams{
   128  		{
   129  			KeyType: pkcs11.CKK_SHA_1_HMAC,
   130  			GenMech: CKM_NC_SHA_1_HMAC_KEY_GEN,
   131  		},
   132  		{
   133  			KeyType: pkcs11.CKK_GENERIC_SECRET,
   134  			GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
   135  		},
   136  	},
   137  	BlockSize: 64,
   138  	Encrypt:   false,
   139  	MAC:       true,
   140  	ECBMech:   0,
   141  	CBCMech:   0,
   142  	GCMMech:   0,
   143  }
   144  
   145  // CipherHMACSHA224 describes the CKK_SHA224_HMAC key type. Use this with the
   146  // GenerateSecretKey... functions.
   147  var CipherHMACSHA224 = &SymmetricCipher{
   148  	GenParams: []SymmetricGenParams{
   149  		{
   150  			KeyType: pkcs11.CKK_SHA224_HMAC,
   151  			GenMech: CKM_NC_SHA224_HMAC_KEY_GEN,
   152  		},
   153  		{
   154  			KeyType: pkcs11.CKK_GENERIC_SECRET,
   155  			GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
   156  		},
   157  	},
   158  	BlockSize: 64,
   159  	Encrypt:   false,
   160  	MAC:       true,
   161  	ECBMech:   0,
   162  	CBCMech:   0,
   163  	GCMMech:   0,
   164  }
   165  
   166  // CipherHMACSHA256 describes the CKK_SHA256_HMAC key type. Use this with the
   167  // GenerateSecretKey... functions.
   168  var CipherHMACSHA256 = &SymmetricCipher{
   169  	GenParams: []SymmetricGenParams{
   170  		{
   171  			KeyType: pkcs11.CKK_SHA256_HMAC,
   172  			GenMech: CKM_NC_SHA256_HMAC_KEY_GEN,
   173  		},
   174  		{
   175  			KeyType: pkcs11.CKK_GENERIC_SECRET,
   176  			GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
   177  		},
   178  	},
   179  	BlockSize: 64,
   180  	Encrypt:   false,
   181  	MAC:       true,
   182  	ECBMech:   0,
   183  	CBCMech:   0,
   184  	GCMMech:   0,
   185  }
   186  
   187  // CipherHMACSHA384 describes the CKK_SHA384_HMAC key type. Use this with the
   188  // GenerateSecretKey... functions.
   189  var CipherHMACSHA384 = &SymmetricCipher{
   190  	GenParams: []SymmetricGenParams{
   191  		{
   192  			KeyType: pkcs11.CKK_SHA384_HMAC,
   193  			GenMech: CKM_NC_SHA384_HMAC_KEY_GEN,
   194  		},
   195  		{
   196  			KeyType: pkcs11.CKK_GENERIC_SECRET,
   197  			GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
   198  		},
   199  	},
   200  	BlockSize: 64,
   201  	Encrypt:   false,
   202  	MAC:       true,
   203  	ECBMech:   0,
   204  	CBCMech:   0,
   205  	GCMMech:   0,
   206  }
   207  
   208  // CipherHMACSHA512 describes the CKK_SHA512_HMAC key type. Use this with the
   209  // GenerateSecretKey... functions.
   210  var CipherHMACSHA512 = &SymmetricCipher{
   211  	GenParams: []SymmetricGenParams{
   212  		{
   213  			KeyType: pkcs11.CKK_SHA512_HMAC,
   214  			GenMech: CKM_NC_SHA512_HMAC_KEY_GEN,
   215  		},
   216  		{
   217  			KeyType: pkcs11.CKK_GENERIC_SECRET,
   218  			GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
   219  		},
   220  	},
   221  	BlockSize: 128,
   222  	Encrypt:   false,
   223  	MAC:       true,
   224  	ECBMech:   0,
   225  	CBCMech:   0,
   226  	GCMMech:   0,
   227  }
   228  
   229  // Ciphers is a map of PKCS#11 key types (CKK_...) to symmetric cipher information.
   230  var Ciphers = map[int]*SymmetricCipher{
   231  	pkcs11.CKK_AES:            CipherAES,
   232  	pkcs11.CKK_DES3:           CipherDES3,
   233  	pkcs11.CKK_GENERIC_SECRET: CipherGeneric,
   234  	pkcs11.CKK_SHA_1_HMAC:     CipherHMACSHA1,
   235  	pkcs11.CKK_SHA224_HMAC:    CipherHMACSHA224,
   236  	pkcs11.CKK_SHA256_HMAC:    CipherHMACSHA256,
   237  	pkcs11.CKK_SHA384_HMAC:    CipherHMACSHA384,
   238  	pkcs11.CKK_SHA512_HMAC:    CipherHMACSHA512,
   239  }
   240  
   241  // SecretKey contains a reference to a loaded PKCS#11 symmetric key object.
   242  //
   243  // A *SecretKey implements the cipher.Block interface, allowing it be used
   244  // as the argument to cipher.NewCBCEncrypter and similar methods.
   245  // For bulk operation this is very inefficient;
   246  // using NewCBCEncrypterCloser, NewCBCEncrypter or NewCBC from this package is
   247  // much faster.
   248  type SecretKey struct {
   249  	pkcs11Object
   250  
   251  	// Symmetric cipher information
   252  	Cipher *SymmetricCipher
   253  }
   254  
   255  // GenerateSecretKey creates an secret key of given length and type. The id parameter is used to
   256  // set CKA_ID and must be non-nil.
   257  func (c *Context) GenerateSecretKey(id []byte, bits int, cipher *SymmetricCipher) (*SecretKey, error) {
   258  	if c.closed.Get() {
   259  		return nil, errClosed
   260  	}
   261  
   262  	template, err := NewAttributeSetWithID(id)
   263  	if err != nil {
   264  		return nil, err
   265  	}
   266  	return c.GenerateSecretKeyWithAttributes(template, bits, cipher)
   267  }
   268  
   269  // GenerateSecretKey creates an secret key of given length and type. The id and label parameters are used to
   270  // set CKA_ID and CKA_LABEL respectively and must be non-nil.
   271  func (c *Context) GenerateSecretKeyWithLabel(id, label []byte, bits int, cipher *SymmetricCipher) (*SecretKey, error) {
   272  	if c.closed.Get() {
   273  		return nil, errClosed
   274  	}
   275  
   276  	template, err := NewAttributeSetWithIDAndLabel(id, label)
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  	return c.GenerateSecretKeyWithAttributes(template, bits, cipher)
   281  
   282  }
   283  
   284  // GenerateSecretKeyWithAttributes creates an secret key of given length and type. After this function returns, template
   285  // will contain the attributes applied to the key. If required attributes are missing, they will be set to a default
   286  // value.
   287  func (c *Context) GenerateSecretKeyWithAttributes(template AttributeSet, bits int, cipher *SymmetricCipher) (k *SecretKey, err error) {
   288  	if c.closed.Get() {
   289  		return nil, errClosed
   290  	}
   291  
   292  	err = c.withSession(func(session *pkcs11Session) error {
   293  
   294  		// CKK_*_HMAC exists but there is no specific corresponding CKM_*_KEY_GEN
   295  		// mechanism. Therefore we attempt both CKM_GENERIC_SECRET_KEY_GEN and
   296  		// vendor-specific mechanisms.
   297  
   298  		template.AddIfNotPresent([]*pkcs11.Attribute{
   299  			pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_SECRET_KEY),
   300  			pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
   301  			pkcs11.NewAttribute(pkcs11.CKA_SIGN, cipher.MAC),
   302  			pkcs11.NewAttribute(pkcs11.CKA_VERIFY, cipher.MAC),
   303  			pkcs11.NewAttribute(pkcs11.CKA_ENCRYPT, cipher.Encrypt), // Not supported on CloudHSM
   304  			pkcs11.NewAttribute(pkcs11.CKA_DECRYPT, cipher.Encrypt), // Not supported on CloudHSM
   305  			pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true),
   306  			pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false),
   307  		})
   308  		if bits > 0 {
   309  			_ = template.Set(pkcs11.CKA_VALUE_LEN, bits/8) // safe for an int
   310  		}
   311  
   312  		for n, genMech := range cipher.GenParams {
   313  
   314  			_ = template.Set(CkaKeyType, genMech.KeyType)
   315  
   316  			mech := []*pkcs11.Mechanism{pkcs11.NewMechanism(genMech.GenMech, nil)}
   317  
   318  			privHandle, err := session.ctx.GenerateKey(session.handle, mech, template.ToSlice())
   319  			if err == nil {
   320  				k = &SecretKey{pkcs11Object{privHandle, c}, cipher}
   321  				return nil
   322  			}
   323  
   324  			// As a special case, AWS CloudHSM does not accept CKA_ENCRYPT and CKA_DECRYPT on a
   325  			// Generic Secret key. If we are in that special case, try again without those attributes.
   326  			if e, ok := err.(pkcs11.Error); ok && e == pkcs11.CKR_ARGUMENTS_BAD && genMech.GenMech == pkcs11.CKM_GENERIC_SECRET_KEY_GEN {
   327  				adjustedTemplate := template.Copy()
   328  				adjustedTemplate.Unset(CkaEncrypt)
   329  				adjustedTemplate.Unset(CkaDecrypt)
   330  
   331  				privHandle, err = session.ctx.GenerateKey(session.handle, mech, adjustedTemplate.ToSlice())
   332  				if err == nil {
   333  					// Store the actual attributes
   334  					template.cloneFrom(adjustedTemplate)
   335  
   336  					k = &SecretKey{pkcs11Object{privHandle, c}, cipher}
   337  					return nil
   338  				}
   339  			}
   340  
   341  			if n == len(cipher.GenParams)-1 {
   342  				// If we have tried all available gen params, we should return a sensible error. So we skip the
   343  				// retry logic below and return directly.
   344  				return err
   345  			}
   346  
   347  			// nShield returns CKR_TEMPLATE_INCONSISTENT if if doesn't like the CKK/CKM combination.
   348  			// AWS CloudHSM returns CKR_ATTRIBUTE_VALUE_INVALID in the same circumstances.
   349  			if e, ok := err.(pkcs11.Error); ok &&
   350  				e == pkcs11.CKR_TEMPLATE_INCONSISTENT || e == pkcs11.CKR_ATTRIBUTE_VALUE_INVALID {
   351  				continue
   352  			}
   353  
   354  			return err
   355  		}
   356  
   357  		// We can only get here if there were no GenParams
   358  		return errors.New("cipher must have GenParams")
   359  	})
   360  	return
   361  }
   362  
   363  // Delete deletes the secret key from the token.
   364  func (key *SecretKey) Delete() error {
   365  	return key.pkcs11Object.Delete()
   366  }
   367  

View as plain text