mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-26 03:25:09 +00:00
code refactor
Signed-off-by: sapthasurendran <saptha.surendran@ibm.com>
This commit is contained in:
parent
90cf860e50
commit
1019c9800b
14 changed files with 909 additions and 8 deletions
|
|
@ -109,10 +109,10 @@ echo 'go install pkcs11 enabled fabric-ca-client'
|
||||||
go install -tags pkcs11 github.com/hyperledger/fabric-ca/cmd/fabric-ca-client@latest
|
go install -tags pkcs11 github.com/hyperledger/fabric-ca/cmd/fabric-ca-client@latest
|
||||||
createNetwork
|
createNetwork
|
||||||
print "Initializing Typescript HSM gateway application"
|
print "Initializing Typescript HSM gateway application"
|
||||||
pushd ../hsm-gateway-applications/scripts/
|
pushd ../hardware-security-module/scripts/
|
||||||
print "Enroll and register User in HSM"
|
print "Enroll and register User in HSM"
|
||||||
./generate-hsm-user.sh HSMUser
|
./generate-hsm-user.sh HSMUser
|
||||||
pushd ../node/
|
pushd ../application-typescript/
|
||||||
print "install dependencies and prepare for running"
|
print "install dependencies and prepare for running"
|
||||||
npm install
|
npm install
|
||||||
print "Running the output app"
|
print "Running the output app"
|
||||||
|
|
@ -124,12 +124,12 @@ stopNetwork
|
||||||
# Run Go HSM gateway application
|
# Run Go HSM gateway application
|
||||||
createNetwork
|
createNetwork
|
||||||
print "Initializing Go HSM gateway application"
|
print "Initializing Go HSM gateway application"
|
||||||
pushd ../hsm-gateway-applications/scripts/
|
pushd ../hardware-security-module/scripts/
|
||||||
print "Register and enroll user in HSM"
|
print "Register and enroll user in HSM"
|
||||||
./generate-hsm-user.sh HSMUser
|
./generate-hsm-user.sh HSMUser
|
||||||
pushd ../go
|
pushd ../application-go
|
||||||
print "Running the output app"
|
print "Running the output app"
|
||||||
go run -tags pkcs11 hsm-sample.go
|
go run -tags pkcs11 .
|
||||||
popd
|
popd
|
||||||
popd
|
popd
|
||||||
stopNetwork
|
stopNetwork
|
||||||
|
|
|
||||||
1
hardware-security-module/.gitignore
vendored
Normal file
1
hardware-security-module/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
crypto-material
|
||||||
127
hardware-security-module/README.md
Normal file
127
hardware-security-module/README.md
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
# Fabric Gateway HSM Samples
|
||||||
|
|
||||||
|
The samples show how to create client applications that invoke transactions with HSM Identities using the
|
||||||
|
new embedded Gateway in Fabric.
|
||||||
|
|
||||||
|
The samples will only run against Fabric v2.4 and higher.
|
||||||
|
|
||||||
|
Sample client applications are available to demonstrate the features of the Fabric Gateway and associated SDKs using this network.
|
||||||
|
|
||||||
|
## Installations
|
||||||
|
|
||||||
|
### C Compilers
|
||||||
|
|
||||||
|
In order for the client application to run successfully you must ensure you have C compilers and Python 3 (Note that Python 2 may still work however Python 2 is out of support and could stop working in the future) installed otherwise the node dependency `pkcs11js` will not be built and the application will fail. The failure will have an error such as
|
||||||
|
|
||||||
|
```
|
||||||
|
Error: Cannot find module 'pkcs11js'
|
||||||
|
```
|
||||||
|
|
||||||
|
how to install the required C Compilers and Python will depend on your operating system and version.
|
||||||
|
|
||||||
|
### SoftHSM
|
||||||
|
|
||||||
|
In order to run the application in the absence of a real HSM, a software
|
||||||
|
emulator of the PKCS#11 interface is required.
|
||||||
|
For more information please refer to [SoftHSM](https://www.opendnssec.org/softhsm/).
|
||||||
|
|
||||||
|
SoftHSM can either be installed using the package manager for your host system:
|
||||||
|
|
||||||
|
* Ubuntu: `sudo apt install softhsm2`
|
||||||
|
* macOS: `brew install softhsm`
|
||||||
|
* Windows: **unsupported**
|
||||||
|
|
||||||
|
Or compiled and installed from source:
|
||||||
|
|
||||||
|
1. install openssl 1.0.0+ or botan 1.10.0+
|
||||||
|
2. download the source code from <https://dist.opendnssec.org/source/softhsm-2.5.0.tar.gz>
|
||||||
|
3. `tar -xvf softhsm-2.5.0.tar.gz`
|
||||||
|
4. `cd softhsm-2.5.0`
|
||||||
|
5. `./configure --disable-gost` (would require additional libraries, turn it off unless you need 'gost' algorithm support for the Russian market)
|
||||||
|
6. `make`
|
||||||
|
7. `sudo make install`
|
||||||
|
|
||||||
|
### PKCS#11 enabled fabric-ca-client binary
|
||||||
|
To be able to register and enroll identities using an HSM you need a PKCS#11 enabled version of `fabric-ca-client`
|
||||||
|
To install this use the following command
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install -tags 'pkcs11' github.com/hyperledger/fabric-ca/cmd/fabric-ca-client@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the sample
|
||||||
|
|
||||||
|
The Fabric test network is used to deploy and run this sample. Follow these steps in order:
|
||||||
|
|
||||||
|
1. Create the test network and a channel (from the `test-network` folder).
|
||||||
|
```
|
||||||
|
./network.sh up createChannel -ca
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Deploy one of the smart contract implementations (from the `test-network` folder).
|
||||||
|
```
|
||||||
|
# To deploy the TypeScript chaincode implementation
|
||||||
|
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl typescript
|
||||||
|
|
||||||
|
# To deploy the Go chaincode implementation
|
||||||
|
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go/ -ccl go
|
||||||
|
|
||||||
|
# To deploy the Java chaincode implementation
|
||||||
|
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-java/ -ccl java
|
||||||
|
```
|
||||||
|
|
||||||
|
## Initialize a token to store keys in SoftHSM
|
||||||
|
|
||||||
|
If you have not initialized a token previously (or it has been deleted) then you will need to perform this one time operation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo directories.tokendir = /tmp > $HOME/softhsm2.conf
|
||||||
|
export SOFTHSM2_CONF=$HOME/softhsm2.conf
|
||||||
|
softhsm2-util --init-token --slot 0 --label "ForFabric" --pin 98765432 --so-pin 1234
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create a SoftHSM configuration file called `softhsm2.conf` and will be stored in the home directory. This is
|
||||||
|
where the sample expects to find a SoftHSM configuration file
|
||||||
|
|
||||||
|
The Security Officer PIN, specified with the `--so-pin` flag, can be used to re-initialize the token,
|
||||||
|
and the user PIN (see below), specified with the `--pin` flag, is used by applications to access the token for
|
||||||
|
generating and retrieving keys.
|
||||||
|
|
||||||
|
## Enroll the HSM User
|
||||||
|
|
||||||
|
A user, `HSMUser`, who is HSM managed needs to be registered then enrolled for the sample.
|
||||||
|
|
||||||
|
If the "standard" PKCS11 library locations checked for by the script don't include the library(libsofthsm2.so) location for your environment set the `PKCS11_LIB` environment variable to define the library location.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKCS11_LIB='<path to PKCS11 library location>' scripts/generate-hsm-user.sh HSMUser
|
||||||
|
```
|
||||||
|
|
||||||
|
This will register a user `HSMUser` with the CA in Org1 (if not already registered) and then enroll that user which will
|
||||||
|
generate a certificate on the file system for use by the sample. The private key is stored in SoftHSM
|
||||||
|
|
||||||
|
### Go SDK
|
||||||
|
|
||||||
|
For HSM support you need to ensure you include the `pkcs11` build tag.
|
||||||
|
Mention the PKCS11_LIB environment variable in case of a non-standard library location
|
||||||
|
|
||||||
|
```
|
||||||
|
cd hardware-security-module/application-go
|
||||||
|
go run -tags pkcs11 PKCS11_LIB=<path to PKCS11 library location> .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node SDK
|
||||||
|
|
||||||
|
Mention the PKCS11_LIB environment variable in case of a non-standard library location
|
||||||
|
```
|
||||||
|
export PKCS11_LIB=<path to PKCS11 library location>
|
||||||
|
cd hardware-security-module/application-typescript
|
||||||
|
npm install
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
When you are finished running the samples, the local test-network can be brought down with the following command (from the `test-network` folder):
|
||||||
|
|
||||||
|
```
|
||||||
|
./network.sh down
|
||||||
|
```
|
||||||
19
hardware-security-module/application-go/go.mod
Normal file
19
hardware-security-module/application-go/go.mod
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
module github.com/hyperledger/fabric-samples/asset-transfer-basic/application-gateway-hsm/go
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/hyperledger/fabric-gateway v1.1.0
|
||||||
|
google.golang.org/grpc v1.47.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/hyperledger/fabric-protos-go-apiv2 v0.0.0-20220615102044-467be1c7b2e7 // indirect
|
||||||
|
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||||
|
golang.org/x/text v0.3.7 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 // indirect
|
||||||
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
|
)
|
||||||
143
hardware-security-module/application-go/go.sum
Normal file
143
hardware-security-module/application-go/go.sum
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
|
github.com/hyperledger/fabric-gateway v1.1.0 h1:zQ6BjUCBCUUbPQNI/B/rzBD6QRvaqWxEIYAI6gtUZ14=
|
||||||
|
github.com/hyperledger/fabric-gateway v1.1.0/go.mod h1:A+MuROWOKhmUsYVO2PREggHLPgPAXaudwCoZRpuSeqs=
|
||||||
|
github.com/hyperledger/fabric-protos-go-apiv2 v0.0.0-20220615102044-467be1c7b2e7 h1:loYDK6Vrf7z3fff6YBVKFkFeCGCoKr8O2ed02CESBUQ=
|
||||||
|
github.com/hyperledger/fabric-protos-go-apiv2 v0.0.0-20220615102044-467be1c7b2e7/go.mod h1:smwq1q6eKByqQAp0SYdVvE1MvDoneF373j11XwWajgA=
|
||||||
|
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||||
|
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8=
|
||||||
|
golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 h1:a221mAAEAzq4Lz6ZWRkcS8ptb2mxoxYSt4N68aRyQHM=
|
||||||
|
google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
|
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
||||||
|
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||||
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
203
hardware-security-module/application-go/hsm-sample.go
Normal file
203
hardware-security-module/application-go/hsm-sample.go
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
//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"
|
||||||
|
"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"
|
||||||
|
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 := 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()
|
||||||
|
|
||||||
|
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 := 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",
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
env:
|
||||||
|
node: true
|
||||||
|
es2020: true
|
||||||
|
root: true
|
||||||
|
ignorePatterns:
|
||||||
|
- dist/
|
||||||
|
extends:
|
||||||
|
- eslint:recommended
|
||||||
|
rules:
|
||||||
|
indent:
|
||||||
|
- error
|
||||||
|
- 4
|
||||||
|
quotes:
|
||||||
|
- error
|
||||||
|
- single
|
||||||
|
overrides:
|
||||||
|
- files:
|
||||||
|
- "**/*.ts"
|
||||||
|
parser: "@typescript-eslint/parser"
|
||||||
|
parserOptions:
|
||||||
|
sourceType: module
|
||||||
|
ecmaFeatures:
|
||||||
|
impliedStrict: true
|
||||||
|
plugins:
|
||||||
|
- "@typescript-eslint"
|
||||||
|
extends:
|
||||||
|
- eslint:recommended
|
||||||
|
- plugin:@typescript-eslint/eslint-recommended
|
||||||
|
- plugin:@typescript-eslint/recommended
|
||||||
3
hardware-security-module/application-typescript/.gitignore
vendored
Normal file
3
hardware-security-module/application-typescript/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
35
hardware-security-module/application-typescript/package.json
Normal file
35
hardware-security-module/application-typescript/package.json
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"name": "gateway-hsm-sample",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"main": "dist/hsm-sample.js",
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.15.0 || ^16.13.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"prepare": "npm run build",
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"lint": "eslint . --ext .ts",
|
||||||
|
"start": "SOFTHSM2_CONF=${HOME}/softhsm2.conf node dist/hsm-sample.js",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@grpc/grpc-js": "~1.6.7",
|
||||||
|
"@hyperledger/fabric-gateway": "^1.1.0",
|
||||||
|
"jsrsasign": "^10.3.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tsconfig/node14": "^1.0.1",
|
||||||
|
"@types/jsrsasign": "^9.0.3",
|
||||||
|
"@types/node": "^14.17.32",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.3.0",
|
||||||
|
"@typescript-eslint/parser": "^5.3.0",
|
||||||
|
"eslint": "^8.1.0",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"typescript": "~4.5.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* Copyright IBM Corp. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as grpc from '@grpc/grpc-js';
|
||||||
|
import * as crypto from 'crypto';
|
||||||
|
import { connect, Gateway, HSMSigner, HSMSignerFactory, HSMSignerOptions, signers } from '@hyperledger/fabric-gateway';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as jsrsa from 'jsrsasign';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { TextDecoder } from 'util';
|
||||||
|
|
||||||
|
const mspId = 'Org1MSP';
|
||||||
|
const user = 'HSMUser';
|
||||||
|
const assetId = `asset${Date.now()}`;
|
||||||
|
const utf8Decoder = new TextDecoder();
|
||||||
|
|
||||||
|
// Sample uses fabric-ca-client generated HSM identities, certificate is located in the signcerts directory
|
||||||
|
// and has been stored in a directory of the name given to the identity.
|
||||||
|
|
||||||
|
const certPath = path.resolve(__dirname, '..', '..', 'crypto-material', 'hsm', user, 'signcerts', 'cert.pem');
|
||||||
|
|
||||||
|
const tlsCertPath = path.resolve('..', '..', 'test-network','organizations','peerOrganizations', 'org1.example.com', 'peers', 'peer0.org1.example.com', 'tls', 'ca.crt');
|
||||||
|
const peerEndpoint = 'localhost:7051';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log('\nRunning the Node HSM sample');
|
||||||
|
|
||||||
|
// The gRPC client connection should be shared by all Gateway connections to this endpoint
|
||||||
|
const client = await newGrpcConnection();
|
||||||
|
|
||||||
|
// get an HSMSigner Factory. You only need to do this once for the application
|
||||||
|
const hsmSignerFactory = signers.newHSMSignerFactory(findSoftHSMPKCS11Lib());
|
||||||
|
const credentials = await fs.promises.readFile(certPath);
|
||||||
|
|
||||||
|
// Get the signer function and a close function. The close function closes the signer
|
||||||
|
// once there is no further need for it.
|
||||||
|
const {signer, close} = await newHSMSigner(hsmSignerFactory, credentials.toString());
|
||||||
|
|
||||||
|
const gateway = connect({
|
||||||
|
client,
|
||||||
|
identity: {mspId, credentials},
|
||||||
|
signer,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await exampleTransaction(gateway);
|
||||||
|
console.log();
|
||||||
|
console.log('Node HSM sample completed successfully');
|
||||||
|
} finally {
|
||||||
|
gateway.close();
|
||||||
|
client.close();
|
||||||
|
|
||||||
|
// close the HSM Signer
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exampleTransaction(gateway: Gateway):Promise<void> {
|
||||||
|
const network = gateway.getNetwork('mychannel');
|
||||||
|
const contract = network.getContract('basic');
|
||||||
|
|
||||||
|
console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments');
|
||||||
|
|
||||||
|
await contract.submitTransaction(
|
||||||
|
'CreateAsset',
|
||||||
|
assetId,
|
||||||
|
'yellow',
|
||||||
|
'5',
|
||||||
|
'Tom',
|
||||||
|
'1300',
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('*** Transaction committed successfully');
|
||||||
|
|
||||||
|
console.log('\n--> Evaluate Transaction: ReadAsset, function returns asset attributes');
|
||||||
|
|
||||||
|
const resultBytes = await contract.evaluateTransaction('ReadAsset', assetId);
|
||||||
|
|
||||||
|
const resultJson = utf8Decoder.decode(resultBytes);
|
||||||
|
const result = JSON.parse(resultJson);
|
||||||
|
console.log('*** Result:', result);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function newGrpcConnection(): Promise<grpc.Client> {
|
||||||
|
const tlsRootCert = await fs.promises.readFile(tlsCertPath);
|
||||||
|
const tlsCredentials = grpc.credentials.createSsl(tlsRootCert);
|
||||||
|
|
||||||
|
return new grpc.Client(peerEndpoint, tlsCredentials, {
|
||||||
|
'grpc.ssl_target_name_override': 'peer0.org1.example.com'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new HSM Signer
|
||||||
|
async function newHSMSigner(hsmSignerFactory: HSMSignerFactory, certificatePEM: string): Promise<HSMSigner> {
|
||||||
|
const ski = getSKIFromCertificate(certificatePEM);
|
||||||
|
|
||||||
|
// Options for the signer based on using SoftHSM with Token initialized as follows
|
||||||
|
// softhsm2-util --init-token --slot 0 --label "ForFabric" --pin 98765432 --so-pin 1234
|
||||||
|
const hsmSignerOptions: HSMSignerOptions = {
|
||||||
|
label: 'ForFabric',
|
||||||
|
pin: '98765432',
|
||||||
|
identifier: ski
|
||||||
|
}
|
||||||
|
return hsmSignerFactory.newSigner(hsmSignerOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility to find the SoftHSM PKCS11 library as it's location can vary based on
|
||||||
|
// operating system and version
|
||||||
|
function findSoftHSMPKCS11Lib(): string {
|
||||||
|
const commonSoftHSMPathNames = [
|
||||||
|
'/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',
|
||||||
|
];
|
||||||
|
const pkcs11lib = process.env['PKCS11_LIB'];
|
||||||
|
if (pkcs11lib) {
|
||||||
|
commonSoftHSMPathNames.push(pkcs11lib);
|
||||||
|
}
|
||||||
|
for (const pathnameToTry of commonSoftHSMPathNames) {
|
||||||
|
if (fs.existsSync(pathnameToTry)) {
|
||||||
|
return pathnameToTry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Unable to find PKCS11 library')
|
||||||
|
}
|
||||||
|
|
||||||
|
// fabric-ca-client set's the CKA_ID of the public/private keys in the HSM to a generated SKI
|
||||||
|
// value. This function replicates that calculation from a certificate PEM so that the HSM
|
||||||
|
// object associated with the certificate can be found
|
||||||
|
function getSKIFromCertificate(certificatePEM: string): Buffer {
|
||||||
|
const key = jsrsa.KEYUTIL.getKey(certificatePEM);
|
||||||
|
const uncompressedPoint = getUncompressedPointOnCurve(key as jsrsa.KJUR.crypto.ECDSA);
|
||||||
|
const hashBuffer = crypto.createHash('sha256');
|
||||||
|
hashBuffer.update(uncompressedPoint);
|
||||||
|
|
||||||
|
const digest = hashBuffer.digest('hex');
|
||||||
|
return Buffer.from(digest, 'hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUncompressedPointOnCurve(key: jsrsa.KJUR.crypto.ECDSA): Buffer {
|
||||||
|
const xyhex = key.getPublicKeyXYHex();
|
||||||
|
const xBuffer = Buffer.from(xyhex.x, 'hex');
|
||||||
|
const yBuffer = Buffer.from(xyhex.y, 'hex');
|
||||||
|
const uncompressedPrefix = Buffer.from('04', 'hex');
|
||||||
|
const uncompressedPoint = Buffer.concat([uncompressedPrefix, xBuffer, yBuffer]);
|
||||||
|
return uncompressedPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(console.error);
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"extends": "@tsconfig/node14/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src",
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"forceConsistentCasingInFileNames": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
}
|
||||||
1
hardware-security-module/ca-client-config/.gitignore
vendored
Normal file
1
hardware-security-module/ca-client-config/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
fabric-ca-client-config.yaml
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# This is a configuration file for the fabric-ca-client command.
|
||||||
|
#
|
||||||
|
# COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES
|
||||||
|
# ------------------------------------------------
|
||||||
|
# Each configuration element can be overridden via command line
|
||||||
|
# arguments or environment variables. The precedence for determining
|
||||||
|
# the value of each element is as follows:
|
||||||
|
# 1) command line argument
|
||||||
|
# Examples:
|
||||||
|
# a) --url https://localhost:7054
|
||||||
|
# To set the fabric-ca server url
|
||||||
|
# b) --tls.client.certfile certfile.pem
|
||||||
|
# To set the client certificate for TLS
|
||||||
|
# 2) environment variable
|
||||||
|
# Examples:
|
||||||
|
# a) FABRIC_CA_CLIENT_URL=https://localhost:7054
|
||||||
|
# To set the fabric-ca server url
|
||||||
|
# b) FABRIC_CA_CLIENT_TLS_CLIENT_CERTFILE=certfile.pem
|
||||||
|
# To set the client certificate for TLS
|
||||||
|
# 3) configuration file
|
||||||
|
# 4) default value (if there is one)
|
||||||
|
# All default values are shown beside each element below.
|
||||||
|
#
|
||||||
|
# FILE NAME ELEMENTS
|
||||||
|
# ------------------
|
||||||
|
# The value of all fields whose name ends with "file" or "files" are
|
||||||
|
# name or names of other files.
|
||||||
|
# For example, see "tls.certfiles" and "tls.client.certfile".
|
||||||
|
# The value of each of these fields can be a simple filename, a
|
||||||
|
# relative path, or an absolute path. If the value is not an
|
||||||
|
# absolute path, it is interpreted as being relative to the location
|
||||||
|
# of this configuration file.
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Client Configuration
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
# URL of the Fabric-ca-server (default: http://localhost:7054)
|
||||||
|
url: http://localhost:7054
|
||||||
|
|
||||||
|
# Membership Service Provider (MSP) directory
|
||||||
|
# This is useful when the client is used to enroll a peer or orderer, so
|
||||||
|
# that the enrollment artifacts are stored in the format expected by MSP.
|
||||||
|
mspdir: caadmin
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# TLS section for secure socket connection
|
||||||
|
#
|
||||||
|
# certfiles - PEM-encoded list of trusted root certificate files
|
||||||
|
# client:
|
||||||
|
# certfile - PEM-encoded certificate file for when client authentication
|
||||||
|
# is enabled on server
|
||||||
|
# keyfile - PEM-encoded key file for when client authentication
|
||||||
|
# is enabled on server
|
||||||
|
#############################################################################
|
||||||
|
tls:
|
||||||
|
# TLS section for secure socket connection
|
||||||
|
certfiles:
|
||||||
|
client:
|
||||||
|
certfile:
|
||||||
|
keyfile:
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Certificate Signing Request section for generating the CSR for an
|
||||||
|
# enrollment certificate (ECert)
|
||||||
|
#
|
||||||
|
# cn - Used by CAs to determine which domain the certificate is to be generated for
|
||||||
|
#
|
||||||
|
# keyrequest - Properties to use when generating a private key.
|
||||||
|
# algo - key generation algorithm to use
|
||||||
|
# size - size of key to generate
|
||||||
|
# reusekey - reuse existing key during reenrollment
|
||||||
|
#
|
||||||
|
# serialnumber - The serialnumber field, if specified, becomes part of the issued
|
||||||
|
# certificate's DN (Distinguished Name). For example, one use case for this is
|
||||||
|
# a company with its own CA (Certificate Authority) which issues certificates
|
||||||
|
# to its employees and wants to include the employee's serial number in the DN
|
||||||
|
# of its issued certificates.
|
||||||
|
# WARNING: The serialnumber field should not be confused with the certificate's
|
||||||
|
# serial number which is set by the CA but is not a component of the
|
||||||
|
# certificate's DN.
|
||||||
|
#
|
||||||
|
# names - A list of name objects. Each name object should contain at least one
|
||||||
|
# "C", "L", "O", or "ST" value (or any combination of these) where these
|
||||||
|
# are abbreviations for the following:
|
||||||
|
# "C": country
|
||||||
|
# "L": locality or municipality (such as city or town name)
|
||||||
|
# "O": organization
|
||||||
|
# "OU": organizational unit, such as the department responsible for owning the key;
|
||||||
|
# it can also be used for a "Doing Business As" (DBS) name
|
||||||
|
# "ST": the state or province
|
||||||
|
#
|
||||||
|
# Note that the "OU" or organizational units of an ECert are always set according
|
||||||
|
# to the values of the identities type and affiliation. OUs are calculated for an enroll
|
||||||
|
# as OU=<type>, OU=<affiliationRoot>, ..., OU=<affiliationLeaf>. For example, an identity
|
||||||
|
# of type "client" with an affiliation of "org1.dept2.team3" would have the following
|
||||||
|
# organizational units: OU=client, OU=org1, OU=dept2, OU=team3
|
||||||
|
#
|
||||||
|
# hosts - A list of host names for which the certificate should be valid
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
csr:
|
||||||
|
cn: admin
|
||||||
|
keyrequest:
|
||||||
|
algo: ecdsa
|
||||||
|
size: 256
|
||||||
|
reusekey: false
|
||||||
|
serialnumber:
|
||||||
|
names:
|
||||||
|
- C: US
|
||||||
|
ST: North Carolina
|
||||||
|
L:
|
||||||
|
O: Hyperledger
|
||||||
|
OU: Fabric
|
||||||
|
hosts:
|
||||||
|
- tryfabric
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Registration section used to register a new identity with fabric-ca server
|
||||||
|
#
|
||||||
|
# name - Unique name of the identity
|
||||||
|
# type - Type of identity being registered (e.g. 'peer, app, user')
|
||||||
|
# affiliation - The identity's affiliation
|
||||||
|
# maxenrollments - The maximum number of times the secret can be reused to enroll.
|
||||||
|
# Specially, -1 means unlimited; 0 means to use CA's max enrollment
|
||||||
|
# value.
|
||||||
|
# attributes - List of name/value pairs of attribute for identity
|
||||||
|
#############################################################################
|
||||||
|
id:
|
||||||
|
name:
|
||||||
|
type:
|
||||||
|
affiliation:
|
||||||
|
maxenrollments: 0
|
||||||
|
attributes:
|
||||||
|
# - name:
|
||||||
|
# value:
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Enrollment section used to enroll an identity with fabric-ca server
|
||||||
|
#
|
||||||
|
# profile - Name of the signing profile to use in issuing the certificate
|
||||||
|
# label - Label to use in HSM operations
|
||||||
|
#############################################################################
|
||||||
|
enrollment:
|
||||||
|
profile:
|
||||||
|
label:
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Name of the CA to connect to within the fabric-ca server
|
||||||
|
#############################################################################
|
||||||
|
caname:
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# BCCSP (BlockChain Crypto Service Provider) section allows to select which
|
||||||
|
# crypto implementation library to use
|
||||||
|
#############################################################################
|
||||||
|
bccsp:
|
||||||
|
default: PKCS11
|
||||||
|
PKCS11:
|
||||||
|
Library: REPLACE_ME_HSMLIB
|
||||||
|
Pin: 98765432
|
||||||
|
Label: ForFabric
|
||||||
|
hash: SHA2
|
||||||
|
security: 256
|
||||||
|
|
@ -38,8 +38,8 @@ HSM2_CONF=$HOME/softhsm2.conf
|
||||||
# Update the client config file to point to the softhsm pkcs11 library
|
# Update the client config file to point to the softhsm pkcs11 library
|
||||||
# which must be in $HOME/softhsm directory
|
# which must be in $HOME/softhsm directory
|
||||||
|
|
||||||
CLIENT_CONFIG_TEMPLATE=../ca-client-config/fabric-ca-client-config-template.yaml
|
CLIENT_CONFIG_TEMPLATE=${SCRIPT_DIR}/../ca-client-config/fabric-ca-client-config-template.yaml
|
||||||
CLIENT_CONFIG=../ca-client-config/fabric-ca-client-config.yaml
|
CLIENT_CONFIG=${SCRIPT_DIR}/../ca-client-config/fabric-ca-client-config.yaml
|
||||||
cp $CLIENT_CONFIG_TEMPLATE $CLIENT_CONFIG
|
cp $CLIENT_CONFIG_TEMPLATE $CLIENT_CONFIG
|
||||||
|
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
|
|
@ -49,7 +49,7 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# create the users, remove any existing users
|
# create the users, remove any existing users
|
||||||
CRYPTO_PATH=$PWD/../crypto-material/hsm
|
CRYPTO_PATH=$SCRIPT_DIR/../crypto-material/hsm
|
||||||
[ -d "$CRYPTO_PATH" ] && rm -fr "$CRYPTO_PATH"
|
[ -d "$CRYPTO_PATH" ] && rm -fr "$CRYPTO_PATH"
|
||||||
|
|
||||||
# user passed in as parameter
|
# user passed in as parameter
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue