fabric-samples/hardware-security-module/application-go/hsm-sample.go
Mark S. Lewis 63cc77bdc3
Avoid usage of deprecated ioutil Go package (#843)
* Refactor Go files
1. replace deprecated ioutil functions (ioutil is deprecated since Go 1.16)
2. fix variable names that collide with imported package name
3. fix typos

Also update Go version specified by Go modules to ensure a Go version is used in which ioutil is deprecated and replacement functions are available in os and io packages.

Signed-off-by: Tommy TIAN <xtianae@connect.ust.hk>
Co-authored-by: Mark S. Lewis <mark_lewis@uk.ibm.com>

* Specify go 1.18 instead of go 1.19 in go.mod files

Signed-off-by: Mark S. Lewis <mark_lewis@uk.ibm.com>

Signed-off-by: Tommy TIAN <xtianae@connect.ust.hk>
Signed-off-by: Mark S. Lewis <mark_lewis@uk.ibm.com>
Co-authored-by: Tommy TIAN <xtianae@connect.ust.hk>
2022-10-25 07:04:39 -04:00

202 lines
5.2 KiB
Go

//go:build pkcs11
// +build pkcs11
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/sha256"
"encoding/json"
"encoding/pem"
"errors"
"os"
"crypto/x509"
"fmt"
"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"
certPath = "../crypto-material/hsm/HSMUser/signcerts/cert.pem"
tlsCertPath = "../../test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
peerEndpoint = "localhost:7051"
)
var now = time.Now()
var assetId = fmt.Sprintf("asset%d", now.Unix()*1e3+int64(now.Nanosecond())/1e6)
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 := os.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()
exampleTransaction(gateway)
fmt.Println()
fmt.Println("Go HSM Sample completed successfully")
fmt.Println()
}
func exampleTransaction(gateway *client.Gateway) {
network := gateway.GetNetwork("mychannel")
contract := network.GetContract("basic")
fmt.Printf("Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments \n")
_, err := contract.SubmitTransaction("CreateAsset", assetId, "yellow", "5", "Tom", "1300")
if err != nil {
panic(fmt.Errorf("failed to submit transaction: %w", err))
}
fmt.Printf("*** Transaction committed successfully\n")
fmt.Printf("Evaluate Transaction: ReadAsset, function returns asset attributes\n")
evaluateResult, err := contract.EvaluateTransaction("ReadAsset", assetId)
if err != nil {
panic(fmt.Errorf("failed to evaluate transaction: %w", err))
}
result := formatJSON(evaluateResult)
fmt.Printf("*** Result:%s\n", result)
}
// 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 := os.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",
}
pkcs11lib := os.Getenv("PKCS11_LIB")
if pkcs11lib != "" {
libraryLocations = append(libraryLocations, pkcs11lib)
}
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")
}
// Format JSON data
func formatJSON(data []byte) string {
var prettyJSON bytes.Buffer
if err := json.Indent(&prettyJSON, data, " ", ""); err != nil {
panic(fmt.Errorf("failed to parse JSON: %w", err))
}
return prettyJSON.String()
}