mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-23 01:55:10 +00:00
187 lines
4.8 KiB
Go
187 lines
4.8 KiB
Go
//go:build pkcs11
|
|
// +build pkcs11
|
|
|
|
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/sha256"
|
|
"encoding/pem"
|
|
"errors"
|
|
"os"
|
|
|
|
"crypto/x509"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"time"
|
|
|
|
"github.com/hyperledger/fabric-gateway/pkg/client"
|
|
"github.com/hyperledger/fabric-gateway/pkg/identity"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
)
|
|
|
|
const (
|
|
mspID = "Org1MSP"
|
|
cryptoPath = "../../scenario/fixtures/crypto-material/"
|
|
certPath = cryptoPath + "hsm/HSMUser/signcerts/cert.pem"
|
|
tlsCertPath = cryptoPath + "crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
|
|
peerEndpoint = "localhost:7051"
|
|
)
|
|
|
|
func main() {
|
|
fmt.Println("Running the GO HSM Sample")
|
|
|
|
// The gRPC client connection should be shared by all Gateway connections to this endpoint
|
|
clientConnection := newGrpcConnection()
|
|
defer clientConnection.Close()
|
|
|
|
hsmSignerFactory, err := identity.NewHSMSignerFactory(findSoftHSMLibrary())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer hsmSignerFactory.Dispose()
|
|
|
|
certificatePEM, err := ioutil.ReadFile(certPath)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
id := newIdentity(certificatePEM)
|
|
ski := getSKI(certificatePEM)
|
|
hsmSign, hsmSignClose := newHSMSign(hsmSignerFactory, ski)
|
|
defer hsmSignClose()
|
|
|
|
// Create a Gateway connection for a specific client identity
|
|
gateway, err := client.Connect(id, client.WithSign(hsmSign), client.WithClientConnection(clientConnection))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer gateway.Close()
|
|
|
|
exampleSubmit(gateway)
|
|
fmt.Println()
|
|
fmt.Println("Go HSM Sample Completed Successfully")
|
|
fmt.Println()
|
|
}
|
|
|
|
func exampleSubmit(gateway *client.Gateway) {
|
|
network := gateway.GetNetwork("mychannel")
|
|
contract := network.GetContract("basic")
|
|
|
|
timestamp := time.Now().String()
|
|
fmt.Printf("Submitting \"put\" transaction with arguments: time, %s\n", timestamp)
|
|
|
|
// Submit transaction, blocking until the transaction has been committed on the ledger
|
|
submitResult, err := contract.SubmitTransaction("put", "time", timestamp)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to submit transaction: %w", err))
|
|
}
|
|
|
|
fmt.Printf("Submit result: %s\n", string(submitResult))
|
|
fmt.Println("Evaluating \"get\" query with arguments: time")
|
|
|
|
evaluateResult, err := contract.EvaluateTransaction("get", "time")
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to evaluate transaction: %w", err))
|
|
}
|
|
|
|
fmt.Printf("Query result = %s\n", string(evaluateResult))
|
|
}
|
|
|
|
// newGrpcConnection creates a gRPC connection to the Gateway server.
|
|
func newGrpcConnection() *grpc.ClientConn {
|
|
certificate, err := loadCertificate(tlsCertPath)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to obtain commit status: %w", err))
|
|
}
|
|
|
|
certPool := x509.NewCertPool()
|
|
certPool.AddCert(certificate)
|
|
transportCredentials := credentials.NewClientTLSFromCert(certPool, "peer0.org1.example.com")
|
|
|
|
connection, err := grpc.Dial(peerEndpoint, grpc.WithTransportCredentials(transportCredentials))
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to evaluate transaction: %w", err))
|
|
}
|
|
|
|
return connection
|
|
}
|
|
|
|
// newIdentity creates a client identity for this Gateway connection using an X.509 certificate.
|
|
func newIdentity(certificatePEM []byte) *identity.X509Identity {
|
|
cert, err := identity.CertificateFromPEM(certificatePEM)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
id, err := identity.NewX509Identity(mspID, cert)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return id
|
|
}
|
|
|
|
// newHSMSign creates a function that generates a digital signature from a message digest using a private key.
|
|
func newHSMSign(h *identity.HSMSignerFactory, certPEM []byte) (identity.Sign, identity.HSMSignClose) {
|
|
opt := identity.HSMSignerOptions{
|
|
Label: "ForFabric",
|
|
Pin: "98765432",
|
|
Identifier: string(certPEM),
|
|
}
|
|
|
|
sign, close, err := h.NewHSMSigner(opt)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return sign, close
|
|
}
|
|
|
|
func loadCertificate(filename string) (*x509.Certificate, error) {
|
|
certificatePEM, err := ioutil.ReadFile(filename) //#nosec G304
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return identity.CertificateFromPEM(certificatePEM)
|
|
}
|
|
|
|
func getSKI(certPEM []byte) []byte {
|
|
block, _ := pem.Decode(certPEM)
|
|
|
|
x590cert, _ := x509.ParseCertificate(block.Bytes)
|
|
pk := x590cert.PublicKey
|
|
|
|
return skiForKey(pk.(*ecdsa.PublicKey))
|
|
}
|
|
|
|
func skiForKey(pk *ecdsa.PublicKey) []byte {
|
|
ski := sha256.Sum256(elliptic.Marshal(pk.Curve, pk.X, pk.Y))
|
|
return ski[:]
|
|
}
|
|
|
|
func findSoftHSMLibrary() string {
|
|
|
|
libraryLocations := []string{
|
|
"/usr/lib/softhsm/libsofthsm2.so",
|
|
"/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so",
|
|
"/usr/local/lib/softhsm/libsofthsm2.so",
|
|
"/usr/lib/libacsp-pkcs11.so",
|
|
}
|
|
|
|
for _, libraryLocation := range libraryLocations {
|
|
if _, err := os.Stat(libraryLocation); !errors.Is(err, os.ErrNotExist) {
|
|
return libraryLocation
|
|
}
|
|
}
|
|
|
|
panic("No SoftHSM library can be found. The Sample requires SoftHSM to be installed")
|
|
}
|