...

Source file src/github.com/sassoftware/relic/token/p11token/import.go

Documentation: github.com/sassoftware/relic/token/p11token

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package p11token
    18  
    19  import (
    20  	"crypto"
    21  	"crypto/ecdsa"
    22  	"crypto/rand"
    23  	"crypto/rsa"
    24  	"encoding/hex"
    25  	"errors"
    26  
    27  	"github.com/miekg/pkcs11"
    28  	"github.com/sassoftware/relic/lib/pkcs8"
    29  	"github.com/sassoftware/relic/token"
    30  )
    31  
    32  // Common attributes for new public keys
    33  var newPublicKeyAttrs = []*pkcs11.Attribute{
    34  	pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
    35  	pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
    36  	pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false),
    37  	pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true),
    38  }
    39  
    40  // Common attributes for new private keys
    41  var newPrivateKeyAttrs = []*pkcs11.Attribute{
    42  	pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY),
    43  	pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
    44  	pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true),
    45  	pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true),
    46  	pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false),
    47  	pkcs11.NewAttribute(pkcs11.CKA_SIGN, true),
    48  }
    49  
    50  // Import a PKCS#8 encoded key using a random 3DES key and the Unwrap function.
    51  // For some HSMs this is the only way to import keys.
    52  func (tok *Token) importPkcs8(pk8 []byte, attrs []*pkcs11.Attribute) error {
    53  	// Generate a temporary 3DES key
    54  	genMech := []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_DES3_KEY_GEN, nil)}
    55  	wrapKey, err := tok.ctx.GenerateKey(tok.sh, genMech, []*pkcs11.Attribute{
    56  		pkcs11.NewAttribute(pkcs11.CKA_TOKEN, false),
    57  		pkcs11.NewAttribute(pkcs11.CKA_ENCRYPT, true),
    58  		pkcs11.NewAttribute(pkcs11.CKA_UNWRAP, true),
    59  	})
    60  	if err != nil {
    61  		return err
    62  	}
    63  	defer tok.ctx.DestroyObject(tok.sh, wrapKey)
    64  	// Encrypt key
    65  	iv := make([]byte, 8)
    66  	if _, err := rand.Reader.Read(iv); err != nil {
    67  		return err
    68  	}
    69  	encMech := []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_DES3_CBC_PAD, iv)}
    70  	if err := tok.ctx.EncryptInit(tok.sh, encMech, wrapKey); err != nil {
    71  		return err
    72  	}
    73  	wrapped, err := tok.ctx.Encrypt(tok.sh, pk8)
    74  	if err != nil {
    75  		return err
    76  	}
    77  	// Unwrap key into token
    78  	if _, err := tok.ctx.UnwrapKey(tok.sh, encMech, wrapKey, wrapped, attrs); err != nil {
    79  		return err
    80  	}
    81  	return nil
    82  }
    83  
    84  // Import an RSA or ECDSA private key into the token
    85  func (tok *Token) Import(keyName string, privKey crypto.PrivateKey) (token.Key, error) {
    86  	keyConf, err := tok.config.GetKey(keyName)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	if keyConf.Label == "" {
    91  		return nil, errors.New("Key attribute 'label' must be defined in order to create an object")
    92  	}
    93  	keyID := makeKeyID()
    94  	if keyID == nil {
    95  		return nil, errors.New("failed to make key ID")
    96  	}
    97  	var pubTypeAttrs, privTypeAttrs []*pkcs11.Attribute
    98  	var keyType uint
    99  	switch priv := privKey.(type) {
   100  	case *rsa.PrivateKey:
   101  		keyType = pkcs11.CKK_RSA
   102  		pubTypeAttrs, privTypeAttrs, err = rsaImportAttrs(priv)
   103  	case *ecdsa.PrivateKey:
   104  		keyType = pkcs11.CKK_ECDSA
   105  		pubTypeAttrs, privTypeAttrs, err = ecdsaImportAttrs(priv)
   106  	default:
   107  		return nil, errors.New("Unsupported key type")
   108  	}
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	commonAttrs := []*pkcs11.Attribute{
   113  		pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, keyType),
   114  		pkcs11.NewAttribute(pkcs11.CKA_ID, keyID),
   115  		pkcs11.NewAttribute(pkcs11.CKA_LABEL, keyConf.Label),
   116  	}
   117  	pubAttrs := attrConcat(commonAttrs, newPublicKeyAttrs, pubTypeAttrs)
   118  	privAttrsSensitive := attrConcat(commonAttrs, newPrivateKeyAttrs, privTypeAttrs)
   119  	pubHandle, err := tok.ctx.CreateObject(tok.sh, pubAttrs)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	_, err = tok.ctx.CreateObject(tok.sh, privAttrsSensitive)
   124  	if err2, ok := err.(pkcs11.Error); ok && err2 == pkcs11.CKR_TEMPLATE_INCONSISTENT {
   125  		// Some HSMs don't seem to allow importing private keys directly so use
   126  		// key wrapping to sneak it in. Exclude the "sensitive" attrs since
   127  		// only the flags, label etc. are useful for Unwrap
   128  		privAttrsUnwrap := attrConcat(commonAttrs, newPrivateKeyAttrs)
   129  		var pk8 []byte
   130  		pk8, err = pkcs8.MarshalPKCS8PrivateKey(privKey)
   131  		if err == nil {
   132  			err = tok.importPkcs8(pk8, privAttrsUnwrap)
   133  		}
   134  	}
   135  	if err != nil {
   136  		tok.ctx.DestroyObject(tok.sh, pubHandle)
   137  		return nil, err
   138  	}
   139  	keyConf.ID = hex.EncodeToString(keyID)
   140  	return tok.getKey(keyConf, keyName)
   141  }
   142  
   143  // Generate an RSA or ECDSA key in the token
   144  func (tok *Token) Generate(keyName string, keyType token.KeyType, bits uint) (token.Key, error) {
   145  	tok.mutex.Lock()
   146  	defer tok.mutex.Unlock()
   147  	keyConf, err := tok.config.GetKey(keyName)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	if keyConf.Label == "" {
   152  		return nil, errors.New("Key attribute 'label' must be defined in order to create an object")
   153  	}
   154  	keyID := makeKeyID()
   155  	if keyID == nil {
   156  		return nil, errors.New("failed to make key ID")
   157  	}
   158  	var pubTypeAttrs []*pkcs11.Attribute
   159  	var mech *pkcs11.Mechanism
   160  	switch keyType {
   161  	case token.KeyTypeRsa:
   162  		pubTypeAttrs, mech, err = rsaGenerateAttrs(bits)
   163  	case token.KeyTypeEcdsa:
   164  		pubTypeAttrs, mech, err = ecdsaGenerateAttrs(bits)
   165  	default:
   166  		return nil, errors.New("Unsupported key type")
   167  	}
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  	commonAttrs := []*pkcs11.Attribute{
   172  		pkcs11.NewAttribute(pkcs11.CKA_ID, keyID),
   173  		pkcs11.NewAttribute(pkcs11.CKA_LABEL, keyConf.Label),
   174  	}
   175  	pubAttrs := attrConcat(commonAttrs, newPublicKeyAttrs, pubTypeAttrs)
   176  	privAttrs := attrConcat(commonAttrs, newPrivateKeyAttrs)
   177  	if _, _, err := tok.ctx.GenerateKeyPair(tok.sh, []*pkcs11.Mechanism{mech}, pubAttrs, privAttrs); err != nil {
   178  		if err2, ok := err.(pkcs11.Error); ok && err2 == pkcs11.CKR_MECHANISM_INVALID && mech.Mechanism == pkcs11.CKM_RSA_X9_31_KEY_PAIR_GEN {
   179  			mech.Mechanism = pkcs11.CKM_RSA_PKCS_KEY_PAIR_GEN
   180  			if _, _, err := tok.ctx.GenerateKeyPair(tok.sh, []*pkcs11.Mechanism{mech}, pubAttrs, privAttrs); err != nil {
   181  				return nil, err
   182  			}
   183  		} else {
   184  			return nil, err
   185  		}
   186  	}
   187  	keyConf.ID = hex.EncodeToString(keyID)
   188  	return tok.getKey(keyConf, keyName)
   189  }
   190  
   191  func attrConcat(attrSets ...[]*pkcs11.Attribute) []*pkcs11.Attribute {
   192  	ret := make([]*pkcs11.Attribute, 0)
   193  	for _, attrs := range attrSets {
   194  		ret = append(ret, attrs...)
   195  	}
   196  	return ret
   197  }
   198  

View as plain text