From 1019c9800b0597bffcb2848e09b06d5ca44d3897 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Thu, 7 Jul 2022 14:58:14 +0530 Subject: [PATCH] code refactor Signed-off-by: sapthasurendran --- ci/scripts/run-test-network-basic.sh | 10 +- hardware-security-module/.gitignore | 1 + hardware-security-module/README.md | 127 +++++++++++ .../application-go/go.mod | 19 ++ .../application-go/go.sum | 143 ++++++++++++ .../application-go/hsm-sample.go | 203 ++++++++++++++++++ .../application-typescript/.eslintrc.yaml | 29 +++ .../application-typescript/.gitignore | 3 + .../application-typescript/package.json | 35 +++ .../application-typescript/src/hsm-sample.ts | 154 +++++++++++++ .../application-typescript/tsconfig.json | 18 ++ .../ca-client-config/.gitignore | 1 + .../fabric-ca-client-config-template.yaml | 168 +++++++++++++++ .../scripts/generate-hsm-user.sh | 6 +- 14 files changed, 909 insertions(+), 8 deletions(-) create mode 100644 hardware-security-module/.gitignore create mode 100644 hardware-security-module/README.md create mode 100644 hardware-security-module/application-go/go.mod create mode 100644 hardware-security-module/application-go/go.sum create mode 100644 hardware-security-module/application-go/hsm-sample.go create mode 100644 hardware-security-module/application-typescript/.eslintrc.yaml create mode 100644 hardware-security-module/application-typescript/.gitignore create mode 100644 hardware-security-module/application-typescript/package.json create mode 100644 hardware-security-module/application-typescript/src/hsm-sample.ts create mode 100644 hardware-security-module/application-typescript/tsconfig.json create mode 100644 hardware-security-module/ca-client-config/.gitignore create mode 100644 hardware-security-module/ca-client-config/fabric-ca-client-config-template.yaml diff --git a/ci/scripts/run-test-network-basic.sh b/ci/scripts/run-test-network-basic.sh index 22cc70ad..5194fbd0 100755 --- a/ci/scripts/run-test-network-basic.sh +++ b/ci/scripts/run-test-network-basic.sh @@ -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 createNetwork print "Initializing Typescript HSM gateway application" -pushd ../hsm-gateway-applications/scripts/ +pushd ../hardware-security-module/scripts/ print "Enroll and register User in HSM" ./generate-hsm-user.sh HSMUser -pushd ../node/ +pushd ../application-typescript/ print "install dependencies and prepare for running" npm install print "Running the output app" @@ -124,12 +124,12 @@ stopNetwork # Run Go HSM gateway application createNetwork print "Initializing Go HSM gateway application" -pushd ../hsm-gateway-applications/scripts/ +pushd ../hardware-security-module/scripts/ print "Register and enroll user in HSM" ./generate-hsm-user.sh HSMUser -pushd ../go +pushd ../application-go print "Running the output app" -go run -tags pkcs11 hsm-sample.go +go run -tags pkcs11 . popd popd stopNetwork diff --git a/hardware-security-module/.gitignore b/hardware-security-module/.gitignore new file mode 100644 index 00000000..3916f359 --- /dev/null +++ b/hardware-security-module/.gitignore @@ -0,0 +1 @@ +crypto-material \ No newline at end of file diff --git a/hardware-security-module/README.md b/hardware-security-module/README.md new file mode 100644 index 00000000..ac54caa9 --- /dev/null +++ b/hardware-security-module/README.md @@ -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 +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='' 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= . +``` + +### Node SDK + +Mention the PKCS11_LIB environment variable in case of a non-standard library location +``` +export PKCS11_LIB= +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 +``` \ No newline at end of file diff --git a/hardware-security-module/application-go/go.mod b/hardware-security-module/application-go/go.mod new file mode 100644 index 00000000..ba63ab72 --- /dev/null +++ b/hardware-security-module/application-go/go.mod @@ -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 +) diff --git a/hardware-security-module/application-go/go.sum b/hardware-security-module/application-go/go.sum new file mode 100644 index 00000000..163653f3 --- /dev/null +++ b/hardware-security-module/application-go/go.sum @@ -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= diff --git a/hardware-security-module/application-go/hsm-sample.go b/hardware-security-module/application-go/hsm-sample.go new file mode 100644 index 00000000..f8c04c81 --- /dev/null +++ b/hardware-security-module/application-go/hsm-sample.go @@ -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() +} diff --git a/hardware-security-module/application-typescript/.eslintrc.yaml b/hardware-security-module/application-typescript/.eslintrc.yaml new file mode 100644 index 00000000..79614105 --- /dev/null +++ b/hardware-security-module/application-typescript/.eslintrc.yaml @@ -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 diff --git a/hardware-security-module/application-typescript/.gitignore b/hardware-security-module/application-typescript/.gitignore new file mode 100644 index 00000000..1a993212 --- /dev/null +++ b/hardware-security-module/application-typescript/.gitignore @@ -0,0 +1,3 @@ +dist/ +node_modules/ +package-lock.json diff --git a/hardware-security-module/application-typescript/package.json b/hardware-security-module/application-typescript/package.json new file mode 100644 index 00000000..e35ee892 --- /dev/null +++ b/hardware-security-module/application-typescript/package.json @@ -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" + } +} diff --git a/hardware-security-module/application-typescript/src/hsm-sample.ts b/hardware-security-module/application-typescript/src/hsm-sample.ts new file mode 100644 index 00000000..920ae56e --- /dev/null +++ b/hardware-security-module/application-typescript/src/hsm-sample.ts @@ -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 { + 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 { + 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 { + 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); diff --git a/hardware-security-module/application-typescript/tsconfig.json b/hardware-security-module/application-typescript/tsconfig.json new file mode 100644 index 00000000..ce5ff5ab --- /dev/null +++ b/hardware-security-module/application-typescript/tsconfig.json @@ -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/" + ] +} diff --git a/hardware-security-module/ca-client-config/.gitignore b/hardware-security-module/ca-client-config/.gitignore new file mode 100644 index 00000000..09146f84 --- /dev/null +++ b/hardware-security-module/ca-client-config/.gitignore @@ -0,0 +1 @@ +fabric-ca-client-config.yaml \ No newline at end of file diff --git a/hardware-security-module/ca-client-config/fabric-ca-client-config-template.yaml b/hardware-security-module/ca-client-config/fabric-ca-client-config-template.yaml new file mode 100644 index 00000000..b721fbe8 --- /dev/null +++ b/hardware-security-module/ca-client-config/fabric-ca-client-config-template.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=, OU=, ..., OU=. 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 \ No newline at end of file diff --git a/hardware-security-module/scripts/generate-hsm-user.sh b/hardware-security-module/scripts/generate-hsm-user.sh index 0e892557..52f123b4 100755 --- a/hardware-security-module/scripts/generate-hsm-user.sh +++ b/hardware-security-module/scripts/generate-hsm-user.sh @@ -38,8 +38,8 @@ HSM2_CONF=$HOME/softhsm2.conf # Update the client config file to point to the softhsm pkcs11 library # which must be in $HOME/softhsm directory -CLIENT_CONFIG_TEMPLATE=../ca-client-config/fabric-ca-client-config-template.yaml -CLIENT_CONFIG=../ca-client-config/fabric-ca-client-config.yaml +CLIENT_CONFIG_TEMPLATE=${SCRIPT_DIR}/../ca-client-config/fabric-ca-client-config-template.yaml +CLIENT_CONFIG=${SCRIPT_DIR}/../ca-client-config/fabric-ca-client-config.yaml cp $CLIENT_CONFIG_TEMPLATE $CLIENT_CONFIG if [[ "$OSTYPE" == "darwin"* ]]; then @@ -49,7 +49,7 @@ else fi # 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" # user passed in as parameter