This is an automated email from the ASF dual-hosted git repository. smihaylov pushed a commit to branch create-identity in repository https://gitbox.apache.org/repos/asf/incubator-milagro-dta.git
commit 39d7cfbbc9c5ccc485aa4c664e416552fa574f7f Author: Stanislav Mihaylov <[email protected]> AuthorDate: Fri Sep 27 11:13:41 2019 +0300 Refactor identity secrets Run CreateIdentity only once on init of the node Have one seed and keys for the node Remove create and list identity endpoints --- cmd/service/commands.go | 1 + cmd/service/initnode.go | 50 ------------------ cmd/service/main.go | 49 ++++++------------ cmd/servicetester/e2e_test.sh | 112 ++++++++++++++++++++--------------------- go.sum | 9 ++++ pkg/common/common.go | 70 ++++++-------------------- pkg/defaultservice/fulfill.go | 21 ++++++-- pkg/defaultservice/identity.go | 98 ------------------------------------ pkg/defaultservice/init.go | 13 ++++- pkg/defaultservice/order.go | 49 +++++++++++------- pkg/defaultservice/service.go | 2 + pkg/endpoints/endpoints.go | 101 ++----------------------------------- pkg/identity/identity.go | 75 ++++++++++++++++----------- pkg/identity/identity_test.go | 45 +++++++++++++++++ pkg/identity/keys.go | 63 +++++++++++++++++++++++ pkg/service/service.go | 5 -- 16 files changed, 312 insertions(+), 451 deletions(-) diff --git a/cmd/service/commands.go b/cmd/service/commands.go index 2f9167e..d3d16bd 100644 --- a/cmd/service/commands.go +++ b/cmd/service/commands.go @@ -28,6 +28,7 @@ import ( const ( envMilagroHome = "MILAGRO_HOME" milagroConfigFolder = ".milagro" + keysFile = "keys" cmdInit = "init" cmdDaemon = "daemon" diff --git a/cmd/service/initnode.go b/cmd/service/initnode.go index 2760e51..ecc3b57 100644 --- a/cmd/service/initnode.go +++ b/cmd/service/initnode.go @@ -26,14 +26,6 @@ import ( "fmt" "os" "strings" - - "github.com/apache/incubator-milagro-dta/libs/datastore" - "github.com/apache/incubator-milagro-dta/libs/documents" - "github.com/apache/incubator-milagro-dta/libs/ipfs" - "github.com/apache/incubator-milagro-dta/libs/logger" - "github.com/apache/incubator-milagro-dta/pkg/api" - "github.com/apache/incubator-milagro-dta/pkg/common" - "github.com/apache/incubator-milagro-dta/pkg/service" ) type initOptions struct { @@ -115,48 +107,6 @@ func interactiveSetup(i *initOptions) error { return nil } -//checkForID - Setup a NodeID if not supplied in the config -func checkForID(logger *logger.Logger, optNodeID, optNodeName string, ipfs ipfs.Connector, store *datastore.Store, service service.Service) (nodeID string, err error) { - if optNodeID != "" { - var idSecrets = &common.IdentitySecrets{} - if err := store.Get("id-doc", optNodeID, idSecrets); err == nil { - id := &documents.IDDoc{} - rawDocI, err := ipfs.Get(optNodeID) - if err == nil { - if err := documents.DecodeIDDocument(rawDocI, optNodeID, id); err != nil { - logger.Error("Invalid ID document") - return "", err - } - return optNodeID, nil - } - logger.Error("ID not found in IPFS: %v", optNodeID) - } else { - logger.Error("ID not found in the database: %v", optNodeID) - } - } else { - logger.Error("No ID found in flags or config") - } - - if optNodeName == "" { - return "", errors.New("Please provide Node name") - } - - return createNewID(optNodeName, service) -} - -func createNewID(name string, service service.Service) (newID string, err error) { - - req := &api.CreateIdentityRequest{ - Name: strings.TrimSpace(name), - } - - resp, err := service.CreateIdentity(req) - if err != nil { - return "", err - } - return resp.IDDocumentCID, nil -} - func generateRandomName() string { b := make([]byte, 8) rand.Read(b) diff --git a/cmd/service/main.go b/cmd/service/main.go index 3953a8b..9979f83 100644 --- a/cmd/service/main.go +++ b/cmd/service/main.go @@ -30,6 +30,8 @@ import ( "strings" "syscall" + "github.com/apache/incubator-milagro-dta/libs/keystore" + "github.com/apache/incubator-milagro-dta/libs/datastore" "github.com/apache/incubator-milagro-dta/libs/ipfs" "github.com/apache/incubator-milagro-dta/libs/logger" @@ -38,6 +40,7 @@ import ( "github.com/apache/incubator-milagro-dta/pkg/config" "github.com/apache/incubator-milagro-dta/pkg/defaultservice" "github.com/apache/incubator-milagro-dta/pkg/endpoints" + "github.com/apache/incubator-milagro-dta/pkg/identity" "github.com/apache/incubator-milagro-dta/plugins" "github.com/go-kit/kit/metrics/prometheus" "github.com/pkg/errors" @@ -74,11 +77,6 @@ func initConfig(args []string) error { // Init the config folder config.Init(configFolder(), cfg) - store, err := initDataStore(cfg.Node.Datastore) - if err != nil { - return errors.Wrap(err, "init datastore") - } - logger.Info("IPFS connector type: %s", cfg.IPFS.Connector) var ipfsConnector ipfs.Connector switch cfg.IPFS.Connector { @@ -95,23 +93,11 @@ func initConfig(args []string) error { return errors.Wrap(err, "init IPFS connector") } - svcPlugin := plugins.FindServicePlugin(cfg.Plugins.Service) - if svcPlugin == nil { - return errors.Errorf("Invalid service plugin: %v", initOptions.ServicePlugin) - } - - if err := svcPlugin.Init( - svcPlugin, - defaultservice.WithLogger(logger), - defaultservice.WithRng(rand.Reader), - defaultservice.WithStore(store), - defaultservice.WithIPFS(ipfsConnector), - defaultservice.WithConfig(cfg), - ); err != nil { - return errors.Errorf("init service plugin %s", cfg.Plugins.Service) + keyStore, err := keystore.NewFileStore(filepath.Join(configFolder(), keysFile)) + if err != nil { + return err } - - newID, err := createNewID(cfg.Node.NodeName, svcPlugin) + newID, err := identity.CreateIdentity(cfg.Node.NodeName, ipfsConnector, keyStore) if err != nil { return err } @@ -175,6 +161,10 @@ func startDaemon(args []string) error { if err != nil { return errors.Wrap(err, "init IPFS connector") } + keyStore, err := keystore.NewFileStore(filepath.Join(configFolder(), keysFile)) + if err != nil { + return err + } // Setup Endpoint authorizer var authorizer transport.Authorizer @@ -208,7 +198,8 @@ func startDaemon(args []string) error { svcPlugin, defaultservice.WithLogger(logger), defaultservice.WithRng(rand.Reader), - defaultservice.WithStore(store), + defaultservice.WithDataStore(store), + defaultservice.WithKeyStore(keyStore), defaultservice.WithIPFS(ipfsConnector), defaultservice.WithMasterFiduciary(masterFiduciaryServer), defaultservice.WithConfig(cfg), @@ -217,20 +208,12 @@ func startDaemon(args []string) error { } logger.Info("Service plugin loaded: %s", svcPlugin.Name()) - nodeID, err := checkForID(logger, cfg.Node.NodeID, cfg.Node.NodeName, ipfsConnector, store, svcPlugin) - if err != nil { - return err - } - - if nodeID != cfg.Node.NodeID { - cfg.Node.NodeID = nodeID - if err := config.SaveConfig(configFolder(), cfg); err != nil { - return errors.Wrap(err, "cannot update config") - } + if err := identity.CheckIdentity(cfg.Node.NodeID, cfg.Node.NodeName, ipfsConnector, keyStore); err != nil { + return errors.Wrap(err, "Invalid node identity") } svcPlugin.SetMasterFiduciaryNodeID(cfg.Node.MasterFiduciaryNodeID) - svcPlugin.SetNodeID(nodeID) + svcPlugin.SetNodeID(cfg.Node.NodeID) // Create metrics duration := prometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ diff --git a/cmd/servicetester/e2e_test.sh b/cmd/servicetester/e2e_test.sh index 8ba4277..66c59df 100755 --- a/cmd/servicetester/e2e_test.sh +++ b/cmd/servicetester/e2e_test.sh @@ -95,63 +95,61 @@ execute_bitcoin () { #make another BeneficiaryID - output5=$(curl -s -X POST "http://localhost:5556/$apiVersion/identity" -H "accept: */*" -H "Content-Type: application/json" -d "{\"Name\":\"AA\"}") - benid=$(echo $output5 | jq -r .idDocumentCID) - - - - #Tests against the Bitcoin Extension - different befificary - output6=$(curl -s -X POST "http://localhost:5556/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"\",\"extension\":{\"coin\":\"0\"}}") - #echo $output6 - op6=$(echo $output6 | jq .orderReference) - commitment6=$(echo $output6 | jq .commitment) - address6=$(echo $output6 | jq .extension.address) - - output7=$(curl -s -X POST "http://localhost:5556/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op6,\"beneficiaryIDDocumentCID\":\"$benid\"}") - address7=$(echo $output7 | jq .extension.address) - commitment7=$(echo $output7 | jq .commitment) - - echo "Committment5 $commitment6 $address6" - echo "Committment6 $commitment7 $address7" - - if [ -z $commitment7 ]; then - echo "Failed Commitment is empty" - exit 1 - fi - - if [ $commitment6 == $commitment7 ]; then - echo "Pass - Id, Order & OrderSecret(Beneficiary)" - else - echo "Fail" - exit 1 - fi - - output8=$(curl -s -X POST "http://localhost:5556/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"$benid\",\"extension\":{\"coin\":\"0\"}}") - op8=$(echo $output8 | jq .orderReference) - commitment8=$(echo $output8 | jq .commitment) - address8=$(echo $output8 | jq .extension.address) - - - output9=$(curl -s -X POST "http://localhost:5556/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op8}") - commitment9=$(echo $output9 | jq .commitment) - address9=$(echo $output9 | jq .extension.address) - orderReference=$(echo $output9 | jq .orderReference) - orderIndex=1 - - echo "Committment7 $commitment8 $address8" - echo "Committment8 $commitment9 $address9" - - if [ -z $commitment9 ]; then - echo "Failed Commitment is empty" - exit 1 - fi - - if [ $commitment8 == $commitment9 ]; then - echo "Pass - Id, Order(Beneficiary) & OrderSecret" - else - echo "Fail" - exit 1 - fi + # output5=$(curl -s -X POST "http://localhost:5556/$apiVersion/identity" -H "accept: */*" -H "Content-Type: application/json" -d "{\"Name\":\"AA\"}") + # benid=$(echo $output5 | jq -r .idDocumentCID) + + # #Tests against the Bitcoin Extension - different befificary + # output6=$(curl -s -X POST "http://localhost:5556/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"\",\"extension\":{\"coin\":\"0\"}}") + # #echo $output6 + # op6=$(echo $output6 | jq .orderReference) + # commitment6=$(echo $output6 | jq .commitment) + # address6=$(echo $output6 | jq .extension.address) + + # output7=$(curl -s -X POST "http://localhost:5556/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op6,\"beneficiaryIDDocumentCID\":\"$benid\"}") + # address7=$(echo $output7 | jq .extension.address) + # commitment7=$(echo $output7 | jq .commitment) + + # echo "Committment5 $commitment6 $address6" + # echo "Committment6 $commitment7 $address7" + + # if [ -z $commitment7 ]; then + # echo "Failed Commitment is empty" + # exit 1 + # fi + + # if [ $commitment6 == $commitment7 ]; then + # echo "Pass - Id, Order & OrderSecret(Beneficiary)" + # else + # echo "Fail" + # exit 1 + # fi + + # output8=$(curl -s -X POST "http://localhost:5556/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"$benid\",\"extension\":{\"coin\":\"0\"}}") + # op8=$(echo $output8 | jq .orderReference) + # commitment8=$(echo $output8 | jq .commitment) + # address8=$(echo $output8 | jq .extension.address) + + + # output9=$(curl -s -X POST "http://localhost:5556/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op8}") + # commitment9=$(echo $output9 | jq .commitment) + # address9=$(echo $output9 | jq .extension.address) + # orderReference=$(echo $output9 | jq .orderReference) + # orderIndex=1 + + # echo "Committment7 $commitment8 $address8" + # echo "Committment8 $commitment9 $address9" + + # if [ -z $commitment9 ]; then + # echo "Failed Commitment is empty" + # exit 1 + # fi + + # if [ $commitment8 == $commitment9 ]; then + # echo "Pass - Id, Order(Beneficiary) & OrderSecret" + # else + # echo "Fail" + # exit 1 + # fi } diff --git a/go.sum b/go.sum index aed6fea..dfb1954 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,7 @@ github.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e/go.mod h1:3o github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -28,13 +29,18 @@ github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dm github.com/btcsuite/btcd v0.0.0-20190427004231-96897255fd17/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 h1:A/EVblehb75cUgXA5njHPn0kLAsykn6mJGz7rnmW5W0= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= @@ -283,14 +289,17 @@ github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89 h1:12K8AlpT0/6QUXSfV0yi4Q0jkbq8NDtIKFtF61AoqV0= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= diff --git a/pkg/common/common.go b/pkg/common/common.go index 6fefee7..03f815a 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -25,22 +25,15 @@ import ( "io" "time" - "github.com/apache/incubator-milagro-dta/libs/cryptowallet" "github.com/apache/incubator-milagro-dta/libs/datastore" "github.com/apache/incubator-milagro-dta/libs/documents" "github.com/apache/incubator-milagro-dta/libs/ipfs" + "github.com/apache/incubator-milagro-dta/libs/keystore" + "github.com/apache/incubator-milagro-dta/pkg/identity" "github.com/google/uuid" "github.com/pkg/errors" ) -//IdentitySecrets - keys required for decryption and signing -type IdentitySecrets struct { - Name string `json:"Name"` - Seed string `json:"Seed"` - SikeSecretKey string `json:"SikeSecretKey"` - BLSSecretKey string `json:"BlsSecretKey"` -} - // CreateNewDepositOrder - Generate an empty new Deposit Order with random reference func CreateNewDepositOrder(BeneficiaryIDDocumentCID string, nodeID string) (*documents.OrderDoc, error) { //Create a reference for this order @@ -108,7 +101,7 @@ func RetrieveSeed(store *datastore.Store, reference string) (seedHex string, err } // CreateAndStoreOrderPart2 - -func CreateAndStoreOrderPart2(ipfs ipfs.Connector, store *datastore.Store, order *documents.OrderDoc, orderPart1CID, commitmentPublicKey, nodeID string, recipients map[string]*documents.IDDoc) (orderPart2CID string, err error) { +func CreateAndStoreOrderPart2(ipfs ipfs.Connector, store *datastore.Store, keyStore keystore.Store, order *documents.OrderDoc, orderPart1CID, commitmentPublicKey, nodeID string, recipients map[string]*documents.IDDoc) (orderPart2CID string, err error) { Part2 := documents.OrderPart2{ CommitmentPublicKey: commitmentPublicKey, PreviousOrderCID: orderPart1CID, @@ -116,7 +109,7 @@ func CreateAndStoreOrderPart2(ipfs ipfs.Connector, store *datastore.Store, order } order.OrderPart2 = &Part2 //Write the updated doc back to IPFS - orderPart2CID, err = WriteOrderToIPFS(nodeID, ipfs, store, nodeID, order, recipients) + orderPart2CID, err = WriteOrderToIPFS(nodeID, ipfs, store, keyStore, nodeID, order, recipients) if err != nil { return "", err } @@ -124,7 +117,7 @@ func CreateAndStoreOrderPart2(ipfs ipfs.Connector, store *datastore.Store, order } // CreateAndStorePart3 adds part 3 "redemption request" to the order doc -func CreateAndStorePart3(ipfs ipfs.Connector, store *datastore.Store, order *documents.OrderDoc, orderPart2CID, nodeID string, beneficiaryEncryptedData []byte, recipients map[string]*documents.IDDoc) (orderPart3CID string, err error) { +func CreateAndStorePart3(ipfs ipfs.Connector, store *datastore.Store, keyStore keystore.Store, order *documents.OrderDoc, orderPart2CID, nodeID string, beneficiaryEncryptedData []byte, recipients map[string]*documents.IDDoc) (orderPart3CID string, err error) { //Add part 3 "redemption request" to the order doc redemptionRequest := documents.OrderPart3{ //TODO @@ -135,7 +128,7 @@ func CreateAndStorePart3(ipfs ipfs.Connector, store *datastore.Store, order *doc } order.OrderPart3 = &redemptionRequest //Write the updated doc back to IPFS - orderPart3CID, err = WriteOrderToIPFS(nodeID, ipfs, store, nodeID, order, recipients) + orderPart3CID, err = WriteOrderToIPFS(nodeID, ipfs, store, keyStore, nodeID, order, recipients) if err != nil { return "", nil } @@ -143,7 +136,7 @@ func CreateAndStorePart3(ipfs ipfs.Connector, store *datastore.Store, order *doc } // CreateAndStoreOrderPart4 - -func CreateAndStoreOrderPart4(ipfs ipfs.Connector, store *datastore.Store, order *documents.OrderDoc, commitmentPrivateKey, orderPart3CID, nodeID string, recipients map[string]*documents.IDDoc) (orderPart4CID string, err error) { +func CreateAndStoreOrderPart4(ipfs ipfs.Connector, store *datastore.Store, keyStore keystore.Store, order *documents.OrderDoc, commitmentPrivateKey, orderPart3CID, nodeID string, recipients map[string]*documents.IDDoc) (orderPart4CID string, err error) { Part4 := documents.OrderPart4{ Secret: commitmentPrivateKey, PreviousOrderCID: orderPart3CID, @@ -151,7 +144,7 @@ func CreateAndStoreOrderPart4(ipfs ipfs.Connector, store *datastore.Store, order } order.OrderPart4 = &Part4 //Write the updated doc back to IPFS - orderPart4CID, err = WriteOrderToIPFS(nodeID, ipfs, store, nodeID, order, recipients) + orderPart4CID, err = WriteOrderToIPFS(nodeID, ipfs, store, keyStore, nodeID, order, recipients) if err != nil { return "", nil } @@ -159,14 +152,14 @@ func CreateAndStoreOrderPart4(ipfs ipfs.Connector, store *datastore.Store, order } // WriteOrderToIPFS writes the order document to IPFS network -func WriteOrderToIPFS(nodeID string, ipfs ipfs.Connector, store *datastore.Store, id string, order *documents.OrderDoc, recipients map[string]*documents.IDDoc) (ipfsAddress string, err error) { // Get the secret keys - secrets := &IdentitySecrets{} - if err := store.Get("id-doc", nodeID, secrets); err != nil { - return "", errors.New("load secrets from store") +func WriteOrderToIPFS(nodeID string, ipfs ipfs.Connector, store *datastore.Store, keyStore keystore.Store, id string, order *documents.OrderDoc, recipients map[string]*documents.IDDoc) (ipfsAddress string, err error) { // Get the secret keys + seed, err := keyStore.Get("seed") + if err != nil { + return "", errors.New("load secrets") } - blsSecretKey, err := hex.DecodeString(secrets.BLSSecretKey) + _, blsSecretKey, err := identity.GenerateBLSKeys(seed) if err != nil { - return "", errors.Wrap(err, "Decode identity secrets") + return "", err } rawDoc, err := documents.EncodeOrderDocument(nodeID, *order, blsSecretKey, recipients) @@ -184,41 +177,6 @@ func WriteOrderToIPFS(nodeID string, ipfs ipfs.Connector, store *datastore.Store return ipfsAddress, nil } -//InitECKeys - generate EC keys using BIP44 HD Wallets (as bitcoin) from seed -func InitECKeys(seed []byte) ([]byte, error) { - //EC ADD Keypair Protocol - _, pubKeyECADD, _, err := cryptowallet.Bip44Address(seed, cryptowallet.CoinTypeBitcoinMain, 0, 0, 0) - if err != nil { - return nil, errors.Wrap(err, "Failed to derive EC HD Wallet Key") - } - return pubKeyECADD.SerializeCompressed(), nil -} - -// RetrieveIdentitySecrets gets the secrets for the node ID -func RetrieveIdentitySecrets(store *datastore.Store, nodeID string) (name string, seed []byte, blsSK []byte, sikeSK []byte, err error) { - - var idSecrets = &IdentitySecrets{} - if err := store.Get("id-doc", nodeID, idSecrets); err != nil { - return "", nil, nil, nil, err - } - - seed, err = hex.DecodeString(idSecrets.Seed) - if err != nil { - return "", nil, nil, nil, err - } - - blsSK, err = hex.DecodeString(idSecrets.BLSSecretKey) - if err != nil { - return "", nil, nil, nil, err - } - - sikeSK, err = hex.DecodeString(idSecrets.SikeSecretKey) - if err != nil { - return "", nil, nil, nil, err - } - return idSecrets.Name, seed, blsSK, sikeSK, nil -} - // BuildRecipientList builds a list of recipients who are able to decrypt the encrypted envelope func BuildRecipientList(ipfs ipfs.Connector, localNodeDocCID, remoteNodeDocCID string) (map[string]*documents.IDDoc, error) { remoteNodeDoc, err := RetrieveIDDocFromIPFS(ipfs, remoteNodeDocCID) diff --git a/pkg/defaultservice/fulfill.go b/pkg/defaultservice/fulfill.go index a45eacb..ae6e21f 100644 --- a/pkg/defaultservice/fulfill.go +++ b/pkg/defaultservice/fulfill.go @@ -21,6 +21,7 @@ import ( "github.com/apache/incubator-milagro-dta/libs/cryptowallet" "github.com/apache/incubator-milagro-dta/pkg/api" "github.com/apache/incubator-milagro-dta/pkg/common" + "github.com/apache/incubator-milagro-dta/pkg/identity" ) // FulfillOrder - @@ -28,7 +29,13 @@ func (s *Service) FulfillOrder(req *api.FulfillOrderRequest) (*api.FulfillOrderR orderPart1CID := req.OrderPart1CID nodeID := s.NodeID() remoteIDDocCID := req.DocumentCID - _, _, _, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, nodeID) + + // SIKE key + keyseed, err := s.KeyStore.Get("seed") + if err != nil { + return nil, err + } + _, sikeSK, err := identity.GenerateSIKEKeys(keyseed) if err != nil { return nil, err } @@ -62,7 +69,7 @@ func (s *Service) FulfillOrder(req *api.FulfillOrderRequest) (*api.FulfillOrderR } //Create an order response in IPFS - orderPart2CID, err := common.CreateAndStoreOrderPart2(s.Ipfs, s.Store, order, orderPart1CID, commitmentPublicKey, nodeID, recipientList) + orderPart2CID, err := common.CreateAndStoreOrderPart2(s.Ipfs, s.Store, s.KeyStore, order, orderPart1CID, commitmentPublicKey, nodeID, recipientList) if err != nil { return nil, err } @@ -78,7 +85,13 @@ func (s *Service) FulfillOrderSecret(req *api.FulfillOrderSecretRequest) (*api.F orderPart3CID := req.OrderPart3CID nodeID := s.NodeID() remoteIDDocCID := req.SenderDocumentCID - _, _, _, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, nodeID) + + // SIKE key + keyseed, err := s.KeyStore.Get("seed") + if err != nil { + return nil, err + } + _, sikeSK, err := identity.GenerateSIKEKeys(keyseed) if err != nil { return nil, err } @@ -112,7 +125,7 @@ func (s *Service) FulfillOrderSecret(req *api.FulfillOrderSecretRequest) (*api.F } //Create an order response in IPFS - orderPart4ID, err := common.CreateAndStoreOrderPart4(s.Ipfs, s.Store, order, commitmentPrivateKey, orderPart3CID, nodeID, recipientList) + orderPart4ID, err := common.CreateAndStoreOrderPart4(s.Ipfs, s.Store, s.KeyStore, order, commitmentPrivateKey, orderPart3CID, nodeID, recipientList) if err != nil { return nil, err } diff --git a/pkg/defaultservice/identity.go b/pkg/defaultservice/identity.go deleted file mode 100644 index ae256e5..0000000 --- a/pkg/defaultservice/identity.go +++ /dev/null @@ -1,98 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package defaultservice - -import ( - "encoding/hex" - - "github.com/apache/incubator-milagro-dta/libs/documents" - "github.com/apache/incubator-milagro-dta/pkg/api" - "github.com/apache/incubator-milagro-dta/pkg/common" - "github.com/apache/incubator-milagro-dta/pkg/identity" - "github.com/pkg/errors" -) - -// CreateIdentity creates a new identity -func (s *Service) CreateIdentity(req *api.CreateIdentityRequest) (*api.CreateIdentityResponse, error) { - idDocumentCID, err := identity.CreateIdentity(req.Name, s.Ipfs, s.Store) - if err != nil { - return nil, err - } - - return &api.CreateIdentityResponse{ - IDDocumentCID: idDocumentCID, - }, nil -} - -// GetIdentity retrieves an identity -func (s *Service) GetIdentity(req *api.GetIdentityRequest) (*api.GetIdentityResponse, error) { - idDocumentCID := req.IDDocumentCID - idDocument, err := common.RetrieveIDDocFromIPFS(s.Ipfs, idDocumentCID) - if err != nil { - return nil, err - } - return &api.GetIdentityResponse{ - IDDocumentCID: idDocumentCID, - AuthenticationReference: idDocument.AuthenticationReference, - BeneficiaryECPublicKey: hex.EncodeToString(idDocument.BeneficiaryECPublicKey), - SikePublicKey: hex.EncodeToString(idDocument.SikePublicKey), - BLSPublicKey: hex.EncodeToString(idDocument.BLSPublicKey), - Timestamp: idDocument.Timestamp, - }, nil -} - -// IdentityList reutrns the list of identities -func (s *Service) IdentityList(req *api.IdentityListRequest) (*api.IdentityListResponse, error) { - page := req.Page - perPage := req.PerPage - sortBy := req.SortBy - - IDDocumentCIDes, err := s.Store.ListKeys("id-doc", "time", page*perPage, perPage, sortBy != "dateCreatedAsc") - if err != nil { - return nil, err - } - - fullIDList := make([]api.GetIdentityResponse, len(IDDocumentCIDes)) - for i, idAddress := range IDDocumentCIDes { - - rawDocI, err := s.Ipfs.Get(idAddress) - if err != nil { - return nil, errors.Wrapf(err, "Read identity Doc") - } - - idDocument := &documents.IDDoc{} - if err = documents.DecodeIDDocument(rawDocI, idAddress, idDocument); err != nil { - return nil, err - } - //Need to copy the whole object so I can append the idddocadderess - idWithAddress := api.GetIdentityResponse{ - IDDocumentCID: idAddress, - AuthenticationReference: idDocument.AuthenticationReference, - BeneficiaryECPublicKey: hex.EncodeToString(idDocument.BeneficiaryECPublicKey), - SikePublicKey: hex.EncodeToString(idDocument.SikePublicKey), - BLSPublicKey: hex.EncodeToString(idDocument.BLSPublicKey), - Timestamp: idDocument.Timestamp, - } - - fullIDList[i] = idWithAddress - } - - return &api.IdentityListResponse{ - IDDocumentList: fullIDList, - }, nil -} diff --git a/pkg/defaultservice/init.go b/pkg/defaultservice/init.go index a39697a..f0c0190 100644 --- a/pkg/defaultservice/init.go +++ b/pkg/defaultservice/init.go @@ -22,6 +22,7 @@ import ( "github.com/apache/incubator-milagro-dta/libs/datastore" "github.com/apache/incubator-milagro-dta/libs/ipfs" + "github.com/apache/incubator-milagro-dta/libs/keystore" "github.com/apache/incubator-milagro-dta/libs/logger" "github.com/apache/incubator-milagro-dta/pkg/api" "github.com/apache/incubator-milagro-dta/pkg/config" @@ -59,14 +60,22 @@ func WithRng(rng io.Reader) ServiceOption { } } -// WithStore adds store to the Service -func WithStore(store *datastore.Store) ServiceOption { +// WithDataStore adds store to the Service +func WithDataStore(store *datastore.Store) ServiceOption { return func(s *Service) error { s.Store = store return nil } } +// WithKeyStore adds store to the Service +func WithKeyStore(store keystore.Store) ServiceOption { + return func(s *Service) error { + s.KeyStore = store + return nil + } +} + // WithIPFS adds ipfs connector to the Service func WithIPFS(ipfsConnector ipfs.Connector) ServiceOption { return func(s *Service) error { diff --git a/pkg/defaultservice/order.go b/pkg/defaultservice/order.go index 4326ba0..bafd24c 100644 --- a/pkg/defaultservice/order.go +++ b/pkg/defaultservice/order.go @@ -25,6 +25,7 @@ import ( "github.com/apache/incubator-milagro-dta/libs/documents" "github.com/apache/incubator-milagro-dta/pkg/api" "github.com/apache/incubator-milagro-dta/pkg/common" + "github.com/apache/incubator-milagro-dta/pkg/identity" "github.com/pkg/errors" ) @@ -42,7 +43,12 @@ func (s *Service) GetOrder(req *api.GetOrderRequest) (*api.GetOrderResponse, err return nil, err } - _, _, _, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, s.NodeID()) + // SIKE key + keyseed, err := s.KeyStore.Get("seed") + if err != nil { + return nil, err + } + _, sikeSK, err := identity.GenerateSIKEKeys(keyseed) if err != nil { return nil, err } @@ -116,6 +122,7 @@ func (s *Service) Order(req *api.OrderRequest) (*api.OrderResponse, error) { //Initialise values from Request object beneficiaryIDDocumentCID := req.BeneficiaryIDDocumentCID iDDocID := s.NodeID() + recipientList, err := common.BuildRecipientList(s.Ipfs, iDDocID, s.MasterFiduciaryNodeID()) if err != nil { return nil, err @@ -138,7 +145,7 @@ func (s *Service) Order(req *api.OrderRequest) (*api.OrderResponse, error) { } //Write Order to IPFS - orderPart1CID, err := common.WriteOrderToIPFS(iDDocID, s.Ipfs, s.Store, iDDocID, order, recipientList) + orderPart1CID, err := common.WriteOrderToIPFS(iDDocID, s.Ipfs, s.Store, s.KeyStore, iDDocID, order, recipientList) if err != nil { return nil, err } @@ -154,11 +161,16 @@ func (s *Service) Order(req *api.OrderRequest) (*api.OrderResponse, error) { return nil, errors.Wrap(err, "Contacting Fiduciary") } - //Get the updated order out of IPFS - _, _, _, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, iDDocID) + // SIKE key + keyseed, err := s.KeyStore.Get("seed") + if err != nil { + return nil, err + } + _, sikeSK, err := identity.GenerateSIKEKeys(keyseed) if err != nil { return nil, err } + updatedOrder, err := common.RetrieveOrderFromIPFS(s.Ipfs, response.OrderPart2CID, sikeSK, iDDocID, remoteIDDoc.BLSPublicKey) if err != nil { return nil, errors.Wrap(err, "Fail to retrieve Order from IPFS") @@ -208,7 +220,16 @@ func (s *Service) OrderSecret(req *api.OrderSecretRequest) (*api.OrderSecretResp return nil, err } - _, _, blsSK, sikeSK, err := common.RetrieveIdentitySecrets(s.Store, nodeID) + // SIKE and BLS keys + keyseed, err := s.KeyStore.Get("seed") + if err != nil { + return nil, err + } + _, sikeSK, err := identity.GenerateSIKEKeys(keyseed) + if err != nil { + return nil, err + } + _, blsSK, err := identity.GenerateBLSKeys(keyseed) if err != nil { return nil, err } @@ -219,19 +240,9 @@ func (s *Service) OrderSecret(req *api.OrderSecretRequest) (*api.OrderSecretResp return nil, errors.Wrap(err, "Fail to retrieve Order from IPFS") } - var beneficiariesSikeSK []byte - var beneficiaryCID string - - if req.BeneficiaryIDDocumentCID != "" { - beneficiaryCID = req.BeneficiaryIDDocumentCID - } else { - beneficiaryCID = order.BeneficiaryCID - } - - _, beneficiariesSeed, _, beneficiariesSikeSK, err := common.RetrieveIdentitySecrets(s.Store, beneficiaryCID) - if err != nil { - return nil, err - } + // TODO: Split Beneficiary and Principal + beneficiariesSeed := keyseed + beneficiariesSikeSK := sikeSK if err := s.Plugin.ValidateOrderSecretRequest(req, *order); err != nil { return nil, err @@ -245,7 +256,7 @@ func (s *Service) OrderSecret(req *api.OrderSecretRequest) (*api.OrderSecretResp } //Create a request Object in IPFS - orderPart3CID, err := common.CreateAndStorePart3(s.Ipfs, s.Store, order, orderPart2CID, nodeID, beneficiaryEncryptedData, recipientList) + orderPart3CID, err := common.CreateAndStorePart3(s.Ipfs, s.Store, s.KeyStore, order, orderPart2CID, nodeID, beneficiaryEncryptedData, recipientList) if err != nil { return nil, err } diff --git a/pkg/defaultservice/service.go b/pkg/defaultservice/service.go index f03ef54..b1787a3 100644 --- a/pkg/defaultservice/service.go +++ b/pkg/defaultservice/service.go @@ -26,6 +26,7 @@ import ( "github.com/apache/incubator-milagro-dta/libs/datastore" "github.com/apache/incubator-milagro-dta/libs/ipfs" + "github.com/apache/incubator-milagro-dta/libs/keystore" "github.com/apache/incubator-milagro-dta/libs/logger" "github.com/apache/incubator-milagro-dta/libs/transport" "github.com/apache/incubator-milagro-dta/pkg/api" @@ -43,6 +44,7 @@ type Service struct { Logger *logger.Logger Rng io.Reader Store *datastore.Store + KeyStore keystore.Store Ipfs ipfs.Connector MasterFiduciaryServer api.ClientService nodeID string diff --git a/pkg/endpoints/endpoints.go b/pkg/endpoints/endpoints.go index 1481e8f..b1f7d9d 100644 --- a/pkg/endpoints/endpoints.go +++ b/pkg/endpoints/endpoints.go @@ -46,48 +46,6 @@ var ( // Endpoints returns all the exported endpoints func Endpoints(svc service.Service, corsAllow string, authorizer transport.Authorizer, logger *logger.Logger, nodeType string, pluginEndpoints service.Endpoints) transport.HTTPEndpoints { - identityEndpoints := transport.HTTPEndpoints{ - "CreateIdentity": { - Path: "/" + apiVersion + "/identity", - Method: http.MethodPost, - Endpoint: MakeCreateIdentityEndpoint(svc), - NewRequest: func() interface{} { return &api.CreateIdentityRequest{} }, - NewResponse: func() interface{} { return &api.CreateIdentityResponse{} }, - Options: transport.ServerOptions( - transport.SetCors(corsAllow), - transport.AuthorizeOIDC(authorizer, false), - ), - ErrStatus: transport.ErrorStatus{ - transport.ErrInvalidRequest: http.StatusUnprocessableEntity, - }, - }, - "GetIdentity": { - Path: "/" + apiVersion + "/identity/{IDDocumentCID}", - Method: http.MethodGet, - Endpoint: MakeGetIdentityEndpoint(svc), - NewResponse: func() interface{} { return &api.GetIdentityResponse{} }, - Options: transport.ServerOptions( - transport.SetCors(corsAllow), - transport.AuthorizeOIDC(authorizer, false), - ), - ErrStatus: transport.ErrorStatus{ - transport.ErrInvalidRequest: http.StatusUnprocessableEntity, - }, - }, - "IdentityList": { - Path: "/" + apiVersion + "/identity", - Method: http.MethodGet, - Endpoint: MakeIdentityListEndpoint(svc), - NewResponse: func() interface{} { return &api.IdentityListResponse{} }, - Options: transport.ServerOptions( - transport.SetCors(corsAllow), - transport.AuthorizeOIDC(authorizer, false), - ), - ErrStatus: transport.ErrorStatus{ - transport.ErrInvalidRequest: http.StatusUnprocessableEntity, - }, - }, - } principalEndpoints := transport.HTTPEndpoints{ "Order": { Path: "/" + apiVersion + "/order", @@ -198,11 +156,11 @@ func Endpoints(svc service.Service, corsAllow string, authorizer transport.Autho endpoints := transport.HTTPEndpoints{} switch strings.ToLower(nodeType) { case "multi": - endpoints = concatEndpoints(masterFiduciaryEndpoints, identityEndpoints, principalEndpoints, statusEndPoints) + endpoints = concatEndpoints(masterFiduciaryEndpoints, principalEndpoints, statusEndPoints) case "principal": - endpoints = concatEndpoints(identityEndpoints, principalEndpoints, statusEndPoints) + endpoints = concatEndpoints(principalEndpoints, statusEndPoints) case "fiduciary", "masterfiduciary": - endpoints = concatEndpoints(masterFiduciaryEndpoints, identityEndpoints, statusEndPoints) + endpoints = concatEndpoints(masterFiduciaryEndpoints, statusEndPoints) } plugNamespace, plugEndpoints := pluginEndpoints.Endpoints() @@ -232,59 +190,6 @@ func concatPluginEndpoints(logger *logger.Logger, dst transport.HTTPEndpoints, n return dst } -//MakeCreateIdentityEndpoint - -func MakeCreateIdentityEndpoint(m service.Service) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (response interface{}, err error) { - req, ok := request.(*api.CreateIdentityRequest) - if !ok { - return nil, transport.ErrInvalidRequest - } - if err := validateRequest(req); err != nil { - return "", err - } - return m.CreateIdentity(req) - } -} - -//MakeGetIdentityEndpoint - -func MakeGetIdentityEndpoint(m service.Service) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (response interface{}, err error) { - params := transport.GetURLParams(ctx) - req := &api.GetIdentityRequest{ - IDDocumentCID: params.Get("IDDocumentCID"), - } - if err := validateRequest(req); err != nil { - return "", err - } - return m.GetIdentity(req) - } -} - -//MakeIdentityListEndpoint - -func MakeIdentityListEndpoint(m service.Service) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (response interface{}, err error) { - params := transport.GetParams(ctx) - sortBy := params.Get("sortBy") - perPage, err := strconv.Atoi(params.Get("perPage")) - if err != nil { - return nil, transport.ErrInvalidRequest - } - page, err := strconv.Atoi(params.Get("page")) - if err != nil { - return nil, transport.ErrInvalidRequest - } - req := &api.IdentityListRequest{ - Page: page, - PerPage: perPage, - SortBy: sortBy, - } - if err := validateRequest(req); err != nil { - return "", err - } - return m.IdentityList(req) - } -} - //MakeOrderListEndpoint - func MakeOrderListEndpoint(m service.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (response interface{}, err error) { diff --git a/pkg/identity/identity.go b/pkg/identity/identity.go index edbba97..d5e12da 100644 --- a/pkg/identity/identity.go +++ b/pkg/identity/identity.go @@ -21,21 +21,19 @@ Package identity - manage Identity document and keys package identity import ( - "encoding/hex" + "bytes" "time" - "github.com/apache/incubator-milagro-dta/libs/crypto" "github.com/apache/incubator-milagro-dta/libs/cryptowallet" - "github.com/apache/incubator-milagro-dta/libs/datastore" "github.com/apache/incubator-milagro-dta/libs/documents" "github.com/apache/incubator-milagro-dta/libs/ipfs" - "github.com/apache/incubator-milagro-dta/pkg/common" + "github.com/apache/incubator-milagro-dta/libs/keystore" "github.com/pkg/errors" ) // CreateIdentity creates a new identity // returns Identity secrets and Identity document -func CreateIdentity(name string, ipfsConn ipfs.Connector, store *datastore.Store) (idDocumentCID string, err error) { +func CreateIdentity(name string, ipfsConn ipfs.Connector, store keystore.Store) (idDocumentCID string, err error) { //generate crypto random seed seed, err := cryptowallet.RandomBytes(48) if err != nil { @@ -43,56 +41,75 @@ func CreateIdentity(name string, ipfsConn ipfs.Connector, store *datastore.Store return } - //Generate SIKE keys - rc1, sikePublicKey, sikeSecretKey := crypto.SIKEKeys(seed) - if rc1 != 0 { - err = errors.New("Failed to generate SIKE keys") + sikePublicKey, _, err := GenerateSIKEKeys(seed) + if err != nil { return } - //Generate BLS keys - rc1, blsPublicKey, blsSecretKey := crypto.BLSKeys(seed, nil) - if rc1 != 0 { - err = errors.New("Failed to generate BLS keys") + blsPublicKey, blsSecretKey, err := GenerateBLSKeys(seed) + if err != nil { return } - ecPubKey, err := common.InitECKeys(seed) + ecPublicKey, err := GenerateECPublicKey(seed) if err != nil { - err = errors.Wrap(err, "Failed to generate EC Public Key") return } - //build ID Doc + // build ID Doc idDocument := documents.NewIDDoc() idDocument.AuthenticationReference = name - idDocument.BeneficiaryECPublicKey = ecPubKey + idDocument.BeneficiaryECPublicKey = ecPublicKey idDocument.SikePublicKey = sikePublicKey idDocument.BLSPublicKey = blsPublicKey idDocument.Timestamp = time.Now().Unix() + // encode ID Doc rawIDDoc, err := documents.EncodeIDDocument(idDocument, blsSecretKey) if err != nil { err = errors.Wrap(err, "Failed to encode IDDocument") return } + // add ID Doc to IPFS idDocumentCID, err = ipfsConn.Add(rawIDDoc) - secrets := common.IdentitySecrets{ - Name: name, - Seed: hex.EncodeToString(seed), - BLSSecretKey: hex.EncodeToString(blsSecretKey), - SikeSecretKey: hex.EncodeToString(sikeSecretKey), + // store the seed + err = store.Set("seed", seed) + + return idDocumentCID, err +} + +// CheckIdentity verifies the IDDocument +func CheckIdentity(id, name string, ipfsConn ipfs.Connector, store keystore.Store) error { + + rawIDDoc, err := ipfsConn.Get(id) + if err != nil { + return errors.Wrap(err, "ID Document not found") } - if store != nil { - err = store.Set("id-doc", idDocumentCID, secrets, map[string]string{"time": time.Now().UTC().Format(time.RFC3339)}) - if err != nil { - err = errors.Wrap(err, "Failed to store ID Document") - return - } + idDoc := &documents.IDDoc{} + if err := documents.DecodeIDDocument(rawIDDoc, id, idDoc); err != nil { + return errors.Wrap(err, "Decode ID document") + } + + if idDoc.AuthenticationReference != name { + return errors.New("Name doesn't match the authentication reference") + } + + seed, err := store.Get("seed") + if err != nil { + return errors.Wrap(err, "Seed not found") + } + + sikePublic, _, err := GenerateSIKEKeys(seed) + if !bytes.Equal(idDoc.SikePublicKey, sikePublic) { + return errors.New("SIKE keys are different") + } + blsPublic, _, err := GenerateBLSKeys(seed) + if !bytes.Equal(idDoc.BLSPublicKey, blsPublic) { + return errors.New("BLS keys are different") } - return idDocumentCID, nil + return nil } diff --git a/pkg/identity/identity_test.go b/pkg/identity/identity_test.go new file mode 100644 index 0000000..fbf9281 --- /dev/null +++ b/pkg/identity/identity_test.go @@ -0,0 +1,45 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package identity + +import ( + "testing" + + "github.com/apache/incubator-milagro-dta/libs/ipfs" + "github.com/apache/incubator-milagro-dta/libs/keystore" +) + +func TestCreateIdentity(t *testing.T) { + + ipfsNode, err := ipfs.NewMemoryConnector() + if err != nil { + t.Fatal(err) + } + + store, _ := keystore.NewMemoryStore() + + idDocID, err := CreateIdentity("test", ipfsNode, store) + if err != nil { + t.Fatal(err) + } + + if err := CheckIdentity(idDocID, "test", ipfsNode, store); err != nil { + t.Fatal(err) + } + +} diff --git a/pkg/identity/keys.go b/pkg/identity/keys.go new file mode 100644 index 0000000..276b157 --- /dev/null +++ b/pkg/identity/keys.go @@ -0,0 +1,63 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package identity + +import ( + "fmt" + + "github.com/apache/incubator-milagro-dta/libs/crypto" + "github.com/apache/incubator-milagro-dta/libs/cryptowallet" + "github.com/pkg/errors" +) + +// Secrets - keys required for decryption and signing +type Secrets struct { + Seed []byte + SikeSecretKey []byte + BLSSecretKey []byte +} + +// GenerateBLSKeys generate BLS keys from seed +func GenerateBLSKeys(seed []byte) (blsPublic, blsSecret []byte, err error) { + rc1, blsPublic, blsSecret := crypto.BLSKeys(seed, nil) + if rc1 != 0 { + err = fmt.Errorf("Failed to generate BLS keys: %v", rc1) + } + return +} + +// GenerateSIKEKeys generate SIKE keys from seed +func GenerateSIKEKeys(seed []byte) (sikePublic, sikeSecret []byte, err error) { + rc1, sikePublic, sikeSecret := crypto.SIKEKeys(seed) + if rc1 != 0 { + err = fmt.Errorf("Failed to generate SIKE keys: %v", rc1) + } + return +} + +// GenerateECPublicKey - generate EC keys using BIP44 HD Wallets (as bitcoin) from seed +func GenerateECPublicKey(seed []byte) (ecPublic []byte, err error) { + //EC ADD Keypair Protocol + _, pubKeyECADD, _, err := cryptowallet.Bip44Address(seed, cryptowallet.CoinTypeBitcoinMain, 0, 0, 0) + if err != nil { + err = errors.Wrap(err, "Failed to derive EC HD Wallet Key") + return + } + + return pubKeyECADD.SerializeCompressed(), nil +} diff --git a/pkg/service/service.go b/pkg/service/service.go index 0121994..f0ed3d4 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -27,11 +27,6 @@ import ( // Service is the CustodyService interface type Service interface { - //Identity - CreateIdentity(req *api.CreateIdentityRequest) (*api.CreateIdentityResponse, error) - GetIdentity(req *api.GetIdentityRequest) (*api.GetIdentityResponse, error) - IdentityList(req *api.IdentityListRequest) (*api.IdentityListResponse, error) - //Order GetOrder(req *api.GetOrderRequest) (*api.GetOrderResponse, error) OrderList(req *api.OrderListRequest) (*api.OrderListResponse, error)
