github.com/true-sqn/fabric@v2.1.1+incompatible/bccsp/pkcs11/pkcs11.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package pkcs11
     8  
     9  import (
    10  	"crypto/ecdsa"
    11  	"crypto/elliptic"
    12  	"crypto/sha256"
    13  	"encoding/asn1"
    14  	"encoding/hex"
    15  	"fmt"
    16  	"math/big"
    17  	"sync"
    18  	"time"
    19  
    20  	"github.com/miekg/pkcs11"
    21  	"go.uber.org/zap/zapcore"
    22  )
    23  
    24  func loadLib(lib, pin, label string) (*pkcs11.Ctx, uint, *pkcs11.SessionHandle, error) {
    25  	var slot uint
    26  	logger.Debugf("Loading pkcs11 library [%s]\n", lib)
    27  	if lib == "" {
    28  		return nil, slot, nil, fmt.Errorf("No PKCS11 library default")
    29  	}
    30  
    31  	ctx := pkcs11.New(lib)
    32  	if ctx == nil {
    33  		return nil, slot, nil, fmt.Errorf("Instantiate failed [%s]", lib)
    34  	}
    35  
    36  	ctx.Initialize()
    37  	slots, err := ctx.GetSlotList(true)
    38  	if err != nil {
    39  		return nil, slot, nil, fmt.Errorf("Could not get Slot List [%s]", err)
    40  	}
    41  	found := false
    42  	for _, s := range slots {
    43  		info, errToken := ctx.GetTokenInfo(s)
    44  		if errToken != nil {
    45  			continue
    46  		}
    47  		logger.Debugf("Looking for %s, found label %s\n", label, info.Label)
    48  		if label == info.Label {
    49  			found = true
    50  			slot = s
    51  			break
    52  		}
    53  	}
    54  	if !found {
    55  		return nil, slot, nil, fmt.Errorf("Could not find token with label %s", label)
    56  	}
    57  
    58  	session := createSession(ctx, slot, pin)
    59  
    60  	logger.Debugf("Created new pkcs11 session %+v on slot %d\n", session, slot)
    61  
    62  	if pin == "" {
    63  		return nil, slot, nil, fmt.Errorf("No PIN set")
    64  	}
    65  	err = ctx.Login(session, pkcs11.CKU_USER, pin)
    66  	if err != nil {
    67  		if err != pkcs11.Error(pkcs11.CKR_USER_ALREADY_LOGGED_IN) {
    68  			return nil, slot, nil, fmt.Errorf("Login failed [%s]", err)
    69  		}
    70  	}
    71  
    72  	return ctx, slot, &session, nil
    73  }
    74  
    75  func (csp *impl) getSession() (session pkcs11.SessionHandle) {
    76  	select {
    77  	case session = <-csp.sessions:
    78  		_, err := csp.ctx.GetSessionInfo(session)
    79  		if err != nil {
    80  			logger.Warningf("Get session info failed [%s], closing existing session and getting a new session\n", err)
    81  			csp.ctx.CloseSession(session)
    82  			session = createSession(csp.ctx, csp.slot, csp.pin)
    83  		} else {
    84  			logger.Debugf("Reusing existing pkcs11 session %+v on slot %d\n", session, csp.slot)
    85  		}
    86  
    87  	default:
    88  		// cache is empty (or completely in use), create a new session
    89  		session = createSession(csp.ctx, csp.slot, csp.pin)
    90  	}
    91  	return session
    92  }
    93  
    94  func createSession(ctx *pkcs11.Ctx, slot uint, pin string) pkcs11.SessionHandle {
    95  	var s pkcs11.SessionHandle
    96  	var err error
    97  	// attempt 10 times to open a session with a 100ms delay after each attempt
    98  	for i := 0; i < 10; i++ {
    99  		s, err = ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION)
   100  		if err != nil {
   101  			logger.Warningf("OpenSession failed, retrying [%s]\n", err)
   102  		} else {
   103  			break
   104  		}
   105  		time.Sleep(100 * time.Millisecond)
   106  	}
   107  	if err != nil {
   108  		logger.Fatalf("OpenSession failed [%s]", err)
   109  	}
   110  	logger.Debugf("Created new pkcs11 session %+v on slot %d\n", s, slot)
   111  	session := s
   112  
   113  	err = ctx.Login(session, pkcs11.CKU_USER, pin)
   114  	if err != nil {
   115  		if err != pkcs11.Error(pkcs11.CKR_USER_ALREADY_LOGGED_IN) {
   116  			logger.Errorf("Login failed [%s]", err)
   117  		}
   118  	}
   119  	return session
   120  }
   121  
   122  func (csp *impl) returnSession(session pkcs11.SessionHandle) {
   123  	select {
   124  	case csp.sessions <- session:
   125  		// returned session back to session cache
   126  	default:
   127  		// have plenty of sessions in cache, dropping
   128  		csp.ctx.CloseSession(session)
   129  	}
   130  }
   131  
   132  // Look for an EC key by SKI, stored in CKA_ID
   133  func (csp *impl) getECKey(ski []byte) (pubKey *ecdsa.PublicKey, isPriv bool, err error) {
   134  	p11lib := csp.ctx
   135  	session := csp.getSession()
   136  	defer csp.returnSession(session)
   137  	isPriv = true
   138  	_, err = findKeyPairFromSKI(p11lib, session, ski, privateKeyType)
   139  	if err != nil {
   140  		isPriv = false
   141  		logger.Debugf("Private key not found [%s] for SKI [%s], looking for Public key", err, hex.EncodeToString(ski))
   142  	}
   143  
   144  	publicKey, err := findKeyPairFromSKI(p11lib, session, ski, publicKeyType)
   145  	if err != nil {
   146  		return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski))
   147  	}
   148  
   149  	ecpt, marshaledOid, err := ecPoint(p11lib, session, *publicKey)
   150  	if err != nil {
   151  		return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski))
   152  	}
   153  
   154  	curveOid := new(asn1.ObjectIdentifier)
   155  	_, err = asn1.Unmarshal(marshaledOid, curveOid)
   156  	if err != nil {
   157  		return nil, false, fmt.Errorf("Failed Unmarshaling Curve OID [%s]\n%s", err.Error(), hex.EncodeToString(marshaledOid))
   158  	}
   159  
   160  	curve := namedCurveFromOID(*curveOid)
   161  	if curve == nil {
   162  		return nil, false, fmt.Errorf("Cound not recognize Curve from OID")
   163  	}
   164  	x, y := elliptic.Unmarshal(curve, ecpt)
   165  	if x == nil {
   166  		return nil, false, fmt.Errorf("Failed Unmarshaling Public Key")
   167  	}
   168  
   169  	pubKey = &ecdsa.PublicKey{Curve: curve, X: x, Y: y}
   170  	return pubKey, isPriv, nil
   171  }
   172  
   173  // RFC 5480, 2.1.1.1. Named Curve
   174  //
   175  // secp224r1 OBJECT IDENTIFIER ::= {
   176  //   iso(1) identified-organization(3) certicom(132) curve(0) 33 }
   177  //
   178  // secp256r1 OBJECT IDENTIFIER ::= {
   179  //   iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
   180  //   prime(1) 7 }
   181  //
   182  // secp384r1 OBJECT IDENTIFIER ::= {
   183  //   iso(1) identified-organization(3) certicom(132) curve(0) 34 }
   184  //
   185  // secp521r1 OBJECT IDENTIFIER ::= {
   186  //   iso(1) identified-organization(3) certicom(132) curve(0) 35 }
   187  //
   188  var (
   189  	oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
   190  	oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
   191  	oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
   192  	oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
   193  )
   194  
   195  func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve {
   196  	switch {
   197  	case oid.Equal(oidNamedCurveP224):
   198  		return elliptic.P224()
   199  	case oid.Equal(oidNamedCurveP256):
   200  		return elliptic.P256()
   201  	case oid.Equal(oidNamedCurveP384):
   202  		return elliptic.P384()
   203  	case oid.Equal(oidNamedCurveP521):
   204  		return elliptic.P521()
   205  	}
   206  	return nil
   207  }
   208  
   209  func (csp *impl) generateECKey(curve asn1.ObjectIdentifier, ephemeral bool) (ski []byte, pubKey *ecdsa.PublicKey, err error) {
   210  	p11lib := csp.ctx
   211  	session := csp.getSession()
   212  	defer csp.returnSession(session)
   213  
   214  	id := nextIDCtr()
   215  	publabel := fmt.Sprintf("BCPUB%s", id.Text(16))
   216  	prvlabel := fmt.Sprintf("BCPRV%s", id.Text(16))
   217  
   218  	marshaledOID, err := asn1.Marshal(curve)
   219  	if err != nil {
   220  		return nil, nil, fmt.Errorf("Could not marshal OID [%s]", err.Error())
   221  	}
   222  
   223  	pubkeyT := []*pkcs11.Attribute{
   224  		pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC),
   225  		pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
   226  		pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral),
   227  		pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true),
   228  		pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID),
   229  
   230  		pkcs11.NewAttribute(pkcs11.CKA_ID, publabel),
   231  		pkcs11.NewAttribute(pkcs11.CKA_LABEL, publabel),
   232  	}
   233  
   234  	prvkeyT := []*pkcs11.Attribute{
   235  		pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC),
   236  		pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY),
   237  		pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral),
   238  		pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true),
   239  		pkcs11.NewAttribute(pkcs11.CKA_SIGN, true),
   240  
   241  		pkcs11.NewAttribute(pkcs11.CKA_ID, prvlabel),
   242  		pkcs11.NewAttribute(pkcs11.CKA_LABEL, prvlabel),
   243  
   244  		pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false),
   245  		pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true),
   246  	}
   247  
   248  	pub, prv, err := p11lib.GenerateKeyPair(session,
   249  		[]*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_EC_KEY_PAIR_GEN, nil)},
   250  		pubkeyT, prvkeyT)
   251  
   252  	if err != nil {
   253  		return nil, nil, fmt.Errorf("P11: keypair generate failed [%s]", err)
   254  	}
   255  
   256  	ecpt, _, err := ecPoint(p11lib, session, pub)
   257  	if err != nil {
   258  		return nil, nil, fmt.Errorf("Error querying EC-point: [%s]", err)
   259  	}
   260  	hash := sha256.Sum256(ecpt)
   261  	ski = hash[:]
   262  
   263  	// set CKA_ID of the both keys to SKI(public key) and CKA_LABEL to hex string of SKI
   264  	setskiT := []*pkcs11.Attribute{
   265  		pkcs11.NewAttribute(pkcs11.CKA_ID, ski),
   266  		pkcs11.NewAttribute(pkcs11.CKA_LABEL, hex.EncodeToString(ski)),
   267  	}
   268  
   269  	logger.Infof("Generated new P11 key, SKI %x\n", ski)
   270  	err = p11lib.SetAttributeValue(session, pub, setskiT)
   271  	if err != nil {
   272  		return nil, nil, fmt.Errorf("P11: set-ID-to-SKI[public] failed [%s]", err)
   273  	}
   274  
   275  	err = p11lib.SetAttributeValue(session, prv, setskiT)
   276  	if err != nil {
   277  		return nil, nil, fmt.Errorf("P11: set-ID-to-SKI[private] failed [%s]", err)
   278  	}
   279  
   280  	//Set CKA_Modifible to false for both public key and private keys
   281  	if csp.immutable {
   282  		setCKAModifiable := []*pkcs11.Attribute{
   283  			pkcs11.NewAttribute(pkcs11.CKA_MODIFIABLE, false),
   284  		}
   285  
   286  		_, pubCopyerror := p11lib.CopyObject(session, pub, setCKAModifiable)
   287  		if pubCopyerror != nil {
   288  			return nil, nil, fmt.Errorf("P11: Public Key copy failed with error [%s] . Please contact your HSM vendor", pubCopyerror)
   289  		}
   290  
   291  		pubKeyDestroyError := p11lib.DestroyObject(session, pub)
   292  		if pubKeyDestroyError != nil {
   293  			return nil, nil, fmt.Errorf("P11: Public Key destroy failed with error [%s]. Please contact your HSM vendor", pubCopyerror)
   294  		}
   295  
   296  		_, prvCopyerror := p11lib.CopyObject(session, prv, setCKAModifiable)
   297  		if prvCopyerror != nil {
   298  			return nil, nil, fmt.Errorf("P11: Private Key copy failed with error [%s]. Please contact your HSM vendor", prvCopyerror)
   299  		}
   300  		prvKeyDestroyError := p11lib.DestroyObject(session, prv)
   301  		if pubKeyDestroyError != nil {
   302  			return nil, nil, fmt.Errorf("P11: Private Key destroy failed with error [%s]. Please contact your HSM vendor", prvKeyDestroyError)
   303  		}
   304  	}
   305  
   306  	nistCurve := namedCurveFromOID(curve)
   307  	if curve == nil {
   308  		return nil, nil, fmt.Errorf("Cound not recognize Curve from OID")
   309  	}
   310  	x, y := elliptic.Unmarshal(nistCurve, ecpt)
   311  	if x == nil {
   312  		return nil, nil, fmt.Errorf("Failed Unmarshaling Public Key")
   313  	}
   314  
   315  	pubGoKey := &ecdsa.PublicKey{Curve: nistCurve, X: x, Y: y}
   316  
   317  	if logger.IsEnabledFor(zapcore.DebugLevel) {
   318  		listAttrs(p11lib, session, prv)
   319  		listAttrs(p11lib, session, pub)
   320  	}
   321  
   322  	return ski, pubGoKey, nil
   323  }
   324  
   325  func (csp *impl) signP11ECDSA(ski []byte, msg []byte) (R, S *big.Int, err error) {
   326  	p11lib := csp.ctx
   327  	session := csp.getSession()
   328  	defer csp.returnSession(session)
   329  
   330  	privateKey, err := findKeyPairFromSKI(p11lib, session, ski, privateKeyType)
   331  	if err != nil {
   332  		return nil, nil, fmt.Errorf("Private key not found [%s]", err)
   333  	}
   334  
   335  	err = p11lib.SignInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)}, *privateKey)
   336  	if err != nil {
   337  		return nil, nil, fmt.Errorf("Sign-initialize  failed [%s]", err)
   338  	}
   339  
   340  	var sig []byte
   341  
   342  	sig, err = p11lib.Sign(session, msg)
   343  	if err != nil {
   344  		return nil, nil, fmt.Errorf("P11: sign failed [%s]", err)
   345  	}
   346  
   347  	R = new(big.Int)
   348  	S = new(big.Int)
   349  	R.SetBytes(sig[0 : len(sig)/2])
   350  	S.SetBytes(sig[len(sig)/2:])
   351  
   352  	return R, S, nil
   353  }
   354  
   355  func (csp *impl) verifyP11ECDSA(ski []byte, msg []byte, R, S *big.Int, byteSize int) (bool, error) {
   356  	p11lib := csp.ctx
   357  	session := csp.getSession()
   358  	defer csp.returnSession(session)
   359  
   360  	logger.Debugf("Verify ECDSA\n")
   361  
   362  	publicKey, err := findKeyPairFromSKI(p11lib, session, ski, publicKeyType)
   363  	if err != nil {
   364  		return false, fmt.Errorf("Public key not found [%s]", err)
   365  	}
   366  
   367  	r := R.Bytes()
   368  	s := S.Bytes()
   369  
   370  	// Pad front of R and S with Zeroes if needed
   371  	sig := make([]byte, 2*byteSize)
   372  	copy(sig[byteSize-len(r):byteSize], r)
   373  	copy(sig[2*byteSize-len(s):], s)
   374  
   375  	err = p11lib.VerifyInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)},
   376  		*publicKey)
   377  	if err != nil {
   378  		return false, fmt.Errorf("PKCS11: Verify-initialize [%s]", err)
   379  	}
   380  	err = p11lib.Verify(session, msg, sig)
   381  	if err == pkcs11.Error(pkcs11.CKR_SIGNATURE_INVALID) {
   382  		return false, nil
   383  	}
   384  	if err != nil {
   385  		return false, fmt.Errorf("PKCS11: Verify failed [%s]", err)
   386  	}
   387  
   388  	return true, nil
   389  }
   390  
   391  type keyType int8
   392  
   393  const (
   394  	publicKeyType keyType = iota
   395  	privateKeyType
   396  )
   397  
   398  func findKeyPairFromSKI(mod *pkcs11.Ctx, session pkcs11.SessionHandle, ski []byte, keyType keyType) (*pkcs11.ObjectHandle, error) {
   399  	ktype := pkcs11.CKO_PUBLIC_KEY
   400  	if keyType == privateKeyType {
   401  		ktype = pkcs11.CKO_PRIVATE_KEY
   402  	}
   403  
   404  	template := []*pkcs11.Attribute{
   405  		pkcs11.NewAttribute(pkcs11.CKA_CLASS, ktype),
   406  		pkcs11.NewAttribute(pkcs11.CKA_ID, ski),
   407  	}
   408  	if err := mod.FindObjectsInit(session, template); err != nil {
   409  		return nil, err
   410  	}
   411  
   412  	// single session instance, assume one hit only
   413  	objs, _, err := mod.FindObjects(session, 1)
   414  	if err != nil {
   415  		return nil, err
   416  	}
   417  	if err = mod.FindObjectsFinal(session); err != nil {
   418  		return nil, err
   419  	}
   420  
   421  	if len(objs) == 0 {
   422  		return nil, fmt.Errorf("Key not found [%s]", hex.Dump(ski))
   423  	}
   424  
   425  	return &objs[0], nil
   426  }
   427  
   428  // Fairly straightforward EC-point query, other than opencryptoki
   429  // mis-reporting length, including the 04 Tag of the field following
   430  // the SPKI in EP11-returned MACed publickeys:
   431  //
   432  // attr type 385/x181, length 66 b  -- SHOULD be 1+64
   433  // EC point:
   434  // 00000000  04 ce 30 31 6d 5a fd d3  53 2d 54 9a 27 54 d8 7c
   435  // 00000010  d9 80 35 91 09 2d 6f 06  5a 8e e3 cb c0 01 b7 c9
   436  // 00000020  13 5d 70 d4 e5 62 f2 1b  10 93 f7 d5 77 41 ba 9d
   437  // 00000030  93 3e 18 3e 00 c6 0a 0e  d2 36 cc 7f be 50 16 ef
   438  // 00000040  06 04
   439  //
   440  // cf. correct field:
   441  //   0  89: SEQUENCE {
   442  //   2  19:   SEQUENCE {
   443  //   4   7:     OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
   444  //  13   8:     OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
   445  //        :     }
   446  //  23  66:   BIT STRING
   447  //        :     04 CE 30 31 6D 5A FD D3 53 2D 54 9A 27 54 D8 7C
   448  //        :     D9 80 35 91 09 2D 6F 06 5A 8E E3 CB C0 01 B7 C9
   449  //        :     13 5D 70 D4 E5 62 F2 1B 10 93 F7 D5 77 41 BA 9D
   450  //        :     93 3E 18 3E 00 C6 0A 0E D2 36 CC 7F BE 50 16 EF
   451  //        :     06
   452  //        :   }
   453  //
   454  // as a short-term workaround, remove the trailing byte if:
   455  //   - receiving an even number of bytes == 2*prime-coordinate +2 bytes
   456  //   - starting byte is 04: uncompressed EC point
   457  //   - trailing byte is 04: assume it belongs to the next OCTET STRING
   458  //
   459  // [mis-parsing encountered with v3.5.1, 2016-10-22]
   460  //
   461  // SoftHSM reports extra two bytes before the uncompressed point
   462  // 0x04 || <Length*2+1>
   463  //                 VV< Actual start of point
   464  // 00000000  04 41 04 6c c8 57 32 13  02 12 6a 19 23 1d 5a 64  |.A.l.W2...j.#.Zd|
   465  // 00000010  33 0c eb 75 4d e8 99 22  92 35 96 b2 39 58 14 1e  |3..uM..".5..9X..|
   466  // 00000020  19 de ef 32 46 50 68 02  24 62 36 db ed b1 84 7b  |...2FPh.$b6....{|
   467  // 00000030  93 d8 40 c3 d5 a6 b7 38  16 d2 35 0a 53 11 f9 51  |..@....8..5.S..Q|
   468  // 00000040  fc a7 16                                          |...|
   469  func ecPoint(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, key pkcs11.ObjectHandle) (ecpt, oid []byte, err error) {
   470  	template := []*pkcs11.Attribute{
   471  		pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil),
   472  		pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil),
   473  	}
   474  
   475  	attr, err := p11lib.GetAttributeValue(session, key, template)
   476  	if err != nil {
   477  		return nil, nil, fmt.Errorf("PKCS11: get(EC point) [%s]", err)
   478  	}
   479  
   480  	for _, a := range attr {
   481  		if a.Type == pkcs11.CKA_EC_POINT {
   482  			logger.Debugf("EC point: attr type %d/0x%x, len %d\n%s\n", a.Type, a.Type, len(a.Value), hex.Dump(a.Value))
   483  
   484  			// workarounds, see above
   485  			if ((len(a.Value) % 2) == 0) &&
   486  				(byte(0x04) == a.Value[0]) &&
   487  				(byte(0x04) == a.Value[len(a.Value)-1]) {
   488  				logger.Debugf("Detected opencryptoki bug, trimming trailing 0x04")
   489  				ecpt = a.Value[0 : len(a.Value)-1] // Trim trailing 0x04
   490  			} else if byte(0x04) == a.Value[0] && byte(0x04) == a.Value[2] {
   491  				logger.Debugf("Detected SoftHSM bug, trimming leading 0x04 0xXX")
   492  				ecpt = a.Value[2:len(a.Value)]
   493  			} else {
   494  				ecpt = a.Value
   495  			}
   496  		} else if a.Type == pkcs11.CKA_EC_PARAMS {
   497  			logger.Debugf("EC point: attr type %d/0x%x, len %d\n%s\n", a.Type, a.Type, len(a.Value), hex.Dump(a.Value))
   498  
   499  			oid = a.Value
   500  		}
   501  	}
   502  	if oid == nil || ecpt == nil {
   503  		return nil, nil, fmt.Errorf("CKA_EC_POINT not found, perhaps not an EC Key?")
   504  	}
   505  
   506  	return ecpt, oid, nil
   507  }
   508  
   509  func listAttrs(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, obj pkcs11.ObjectHandle) {
   510  	var cktype, ckclass uint
   511  	var ckaid, cklabel []byte
   512  
   513  	if p11lib == nil {
   514  		return
   515  	}
   516  
   517  	template := []*pkcs11.Attribute{
   518  		pkcs11.NewAttribute(pkcs11.CKA_CLASS, ckclass),
   519  		pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, cktype),
   520  		pkcs11.NewAttribute(pkcs11.CKA_ID, ckaid),
   521  		pkcs11.NewAttribute(pkcs11.CKA_LABEL, cklabel),
   522  	}
   523  
   524  	// certain errors are tolerated, if value is missing
   525  	attr, err := p11lib.GetAttributeValue(session, obj, template)
   526  	if err != nil {
   527  		logger.Debugf("P11: get(attrlist) [%s]\n", err)
   528  	}
   529  
   530  	for _, a := range attr {
   531  		// Would be friendlier if the bindings provided a way convert Attribute hex to string
   532  		logger.Debugf("ListAttr: type %d/0x%x, length %d\n%s", a.Type, a.Type, len(a.Value), hex.Dump(a.Value))
   533  	}
   534  }
   535  
   536  var (
   537  	bigone  = new(big.Int).SetInt64(1)
   538  	idCtr   = new(big.Int)
   539  	idMutex sync.Mutex
   540  )
   541  
   542  func nextIDCtr() *big.Int {
   543  	idMutex.Lock()
   544  	idCtr = new(big.Int).Add(idCtr, bigone)
   545  	idMutex.Unlock()
   546  	return idCtr
   547  }