github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/hyperledger/fabric/bccsp/pkcs11/impl.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/rsa"
    11  	"github.com/hellobchain/newcryptosm/ecdsa"
    12  	"github.com/hellobchain/newcryptosm/x509"
    13  	"github.com/hellobchain/wswlog/wlogging"
    14  	"os"
    15  
    16  	"github.com/miekg/pkcs11"
    17  	"github.com/pkg/errors"
    18  	"github.com/hellobchain/third_party/hyperledger/fabric/bccsp"
    19  	"github.com/hellobchain/third_party/hyperledger/fabric/bccsp/sw"
    20  )
    21  
    22  var (
    23  	logger           = wlogging.MustGetLoggerWithoutName()
    24  	sessionCacheSize = 10
    25  )
    26  
    27  // New WithParams returns a new instance of the software-based BCCSP
    28  // set at the passed security level, hash family and KeyStore.
    29  func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) {
    30  	// Init config
    31  	conf := &config{}
    32  	err := conf.setSecurityLevel(opts.SecLevel, opts.HashFamily)
    33  	if err != nil {
    34  		return nil, errors.Wrapf(err, "Failed initializing configuration")
    35  	}
    36  
    37  	swCSP, err := sw.NewWithParams(opts.SecLevel, opts.HashFamily, keyStore)
    38  	if err != nil {
    39  		return nil, errors.Wrapf(err, "Failed initializing fallback SW BCCSP")
    40  	}
    41  
    42  	// Check KeyStore
    43  	if keyStore == nil {
    44  		return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil")
    45  	}
    46  
    47  	lib := opts.Library
    48  	pin := opts.Pin
    49  	label := opts.Label
    50  	ctx, slot, session, err := loadLib(lib, pin, label)
    51  	if err != nil {
    52  		return nil, errors.Wrapf(err, "Failed initializing PKCS11 library %s %s",
    53  			lib, label)
    54  	}
    55  
    56  	sessions := make(chan pkcs11.SessionHandle, sessionCacheSize)
    57  	csp := &impl{swCSP, conf, keyStore, ctx, sessions, slot, pin, lib, opts.SoftVerify, opts.Immutable, opts.AltId}
    58  	csp.returnSession(*session)
    59  	return csp, nil
    60  }
    61  
    62  type impl struct {
    63  	bccsp.BCCSP
    64  
    65  	conf *config
    66  	ks   bccsp.KeyStore
    67  
    68  	ctx      *pkcs11.Ctx
    69  	sessions chan pkcs11.SessionHandle
    70  	slot     uint
    71  	pin      string
    72  
    73  	lib        string
    74  	softVerify bool
    75  	//Immutable flag makes object immutable
    76  	immutable bool
    77  	// Alternate identifier of the private key
    78  	altId string
    79  }
    80  
    81  // KeyGen generates a key using opts.
    82  func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
    83  	// Validate arguments
    84  	if opts == nil {
    85  		return nil, errors.New("Invalid Opts parameter. It must not be nil")
    86  	}
    87  
    88  	// Parse algorithm
    89  	switch opts.(type) {
    90  	case *bccsp.ECDSAKeyGenOpts:
    91  		ski, pub, err := csp.generateECKey(csp.conf.ellipticCurve, opts.Ephemeral())
    92  		if err != nil {
    93  			return nil, errors.Wrapf(err, "Failed generating ECDSA key")
    94  		}
    95  		k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}}
    96  
    97  	case *bccsp.ECDSAP256KeyGenOpts:
    98  		ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral())
    99  		if err != nil {
   100  			return nil, errors.Wrapf(err, "Failed generating ECDSA P256 key")
   101  		}
   102  
   103  		k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}}
   104  
   105  	case *bccsp.ECDSAP384KeyGenOpts:
   106  		ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral())
   107  		if err != nil {
   108  			return nil, errors.Wrapf(err, "Failed generating ECDSA P384 key")
   109  		}
   110  
   111  		k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}}
   112  
   113  	default:
   114  		return csp.BCCSP.KeyGen(opts)
   115  	}
   116  
   117  	return k, nil
   118  }
   119  
   120  // KeyImport imports a key from its raw representation using opts.
   121  // The opts argument should be appropriate for the primitive used.
   122  func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) {
   123  	// Validate arguments
   124  	if raw == nil {
   125  		return nil, errors.New("Invalid raw. Cannot be nil")
   126  	}
   127  
   128  	if opts == nil {
   129  		return nil, errors.New("Invalid Opts parameter. It must not be nil")
   130  	}
   131  
   132  	switch opts.(type) {
   133  
   134  	case *bccsp.X509PublicKeyImportOpts:
   135  		x509Cert, ok := raw.(*x509.Certificate)
   136  		if !ok {
   137  			return nil, errors.New("[X509PublicKeyImportOpts] Invalid raw material. Expected *x509.Certificate")
   138  		}
   139  
   140  		pk := x509Cert.PublicKey
   141  
   142  		switch pk.(type) {
   143  		case *ecdsa.PublicKey:
   144  			return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()})
   145  		case *rsa.PublicKey:
   146  			return csp.KeyImport(pk, &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()})
   147  		default:
   148  			return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]")
   149  		}
   150  
   151  	default:
   152  		return csp.BCCSP.KeyImport(raw, opts)
   153  
   154  	}
   155  }
   156  
   157  // GetKey returns the key this CSP associates to
   158  // the Subject Key Identifier ski.
   159  func (csp *impl) GetKey(ski []byte) (bccsp.Key, error) {
   160  	pubKey, isPriv, err := csp.getECKey(ski)
   161  	if err == nil {
   162  		if isPriv {
   163  			return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil
   164  		}
   165  		return &ecdsaPublicKey{ski, pubKey}, nil
   166  	}
   167  	return csp.BCCSP.GetKey(ski)
   168  }
   169  
   170  // Sign signs digest using key k.
   171  // The opts argument should be appropriate for the primitive used.
   172  //
   173  // Note that when a signature of a hash of a larger message is needed,
   174  // the caller is responsible for hashing the larger message and passing
   175  // the hash (as digest).
   176  func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) {
   177  	// Validate arguments
   178  	if k == nil {
   179  		return nil, errors.New("Invalid Key. It must not be nil")
   180  	}
   181  	if len(digest) == 0 {
   182  		return nil, errors.New("Invalid digest. Cannot be empty")
   183  	}
   184  
   185  	// Check key type
   186  	switch k.(type) {
   187  	case *ecdsaPrivateKey:
   188  		return csp.signECDSA(*k.(*ecdsaPrivateKey), digest, opts)
   189  	default:
   190  		return csp.BCCSP.Sign(k, digest, opts)
   191  	}
   192  }
   193  
   194  // Verify verifies signature against key k and digest
   195  func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) {
   196  	// Validate arguments
   197  	if k == nil {
   198  		return false, errors.New("Invalid Key. It must not be nil")
   199  	}
   200  	if len(signature) == 0 {
   201  		return false, errors.New("Invalid signature. Cannot be empty")
   202  	}
   203  	if len(digest) == 0 {
   204  		return false, errors.New("Invalid digest. Cannot be empty")
   205  	}
   206  
   207  	// Check key type
   208  	switch k.(type) {
   209  	case *ecdsaPrivateKey:
   210  		return csp.verifyECDSA(k.(*ecdsaPrivateKey).pub, signature, digest, opts)
   211  	case *ecdsaPublicKey:
   212  		return csp.verifyECDSA(*k.(*ecdsaPublicKey), signature, digest, opts)
   213  	default:
   214  		return csp.BCCSP.Verify(k, signature, digest, opts)
   215  	}
   216  }
   217  
   218  // Encrypt encrypts plaintext using key k.
   219  // The opts argument should be appropriate for the primitive used.
   220  func (csp *impl) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) ([]byte, error) {
   221  	// TODO: Add PKCS11 support for encryption, when fabric starts requiring it
   222  	return csp.BCCSP.Encrypt(k, plaintext, opts)
   223  }
   224  
   225  // Decrypt decrypts ciphertext using key k.
   226  // The opts argument should be appropriate for the primitive used.
   227  func (csp *impl) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) ([]byte, error) {
   228  	return csp.BCCSP.Decrypt(k, ciphertext, opts)
   229  }
   230  
   231  // FindPKCS11Lib IS ONLY USED FOR TESTING
   232  // This is a convenience function. Useful to self-configure, for tests where usual configuration is not
   233  // available
   234  func FindPKCS11Lib() (lib, pin, label string) {
   235  	//FIXME: Till we workout the configuration piece, look for the libraries in the familiar places
   236  	lib = os.Getenv("PKCS11_LIB")
   237  	if lib == "" {
   238  		pin = "98765432"
   239  		label = "ForFabric"
   240  		possibilities := []string{
   241  			"/usr/lib/softhsm/libsofthsm2.so",                            //Debian
   242  			"/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so",           //Ubuntu
   243  			"/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so",            //Ubuntu
   244  			"/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so",      //Power
   245  			"/usr/local/Cellar/softhsm/2.1.0/lib/softhsm/libsofthsm2.so", //MacOS
   246  		}
   247  		for _, path := range possibilities {
   248  			if _, err := os.Stat(path); !os.IsNotExist(err) {
   249  				lib = path
   250  				break
   251  			}
   252  		}
   253  	} else {
   254  		pin = os.Getenv("PKCS11_PIN")
   255  		label = os.Getenv("PKCS11_LABEL")
   256  	}
   257  	return lib, pin, label
   258  }