diff --git a/go.mod b/go.mod index 801e82ebf7..bc203ac5a3 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/hyperledger-labs/fabric-token-sdk go 1.22.6 require ( - github.com/IBM/idemix v0.0.2-0.20240816143710-3dce4618d760 - github.com/IBM/idemix/bccsp/types v0.0.0-20240816143710-3dce4618d760 + github.com/IBM/idemix v0.0.2-0.20240829143510-a3d85aa69d56 + github.com/IBM/idemix/bccsp/types v0.0.0-20240829143510-a3d85aa69d56 github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da github.com/gin-gonic/gin v1.10.0 github.com/gobuffalo/packr/v2 v2.7.1 @@ -44,6 +44,13 @@ require ( modernc.org/sqlite v1.33.1 ) +require ( + github.com/alecthomas/kingpin/v2 v2.4.0 // indirect + github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 // indirect + github.com/hyperledger/aries-bbs-go v0.0.0-20240528084656-761671ea73bc // indirect + github.com/xhit/go-str2duration/v2 v2.1.0 // indirect +) + require ( cloud.google.com/go v0.115.0 // indirect cloud.google.com/go/auth v0.6.0 // indirect @@ -54,13 +61,10 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/BurntSushi/toml v1.4.0 // indirect - github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20240612072411-114d281b442d // indirect - github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240612072411-114d281b442d // indirect + github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20240820063231-23c21a416ee1 // indirect + github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240820063231-23c21a416ee1 // indirect github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20231023164747-f3f972769504 // indirect - github.com/alecthomas/kingpin/v2 v2.4.0 // indirect - github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect @@ -255,7 +259,6 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - github.com/xhit/go-str2duration/v2 v2.1.0 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect diff --git a/go.sum b/go.sum index 1cf529935d..c19c0c4c1b 100644 --- a/go.sum +++ b/go.sum @@ -626,14 +626,14 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/IBM/idemix v0.0.2-0.20240816143710-3dce4618d760 h1:KkXCAlR4QIFcDc+/PNVCzGbSGs9sunN852ob8tUwA64= -github.com/IBM/idemix v0.0.2-0.20240816143710-3dce4618d760/go.mod h1:VJKQspYKuHLuG8ukNHfFsFgD+NaJHlNO58ZWShlnPi4= -github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20240612072411-114d281b442d h1:8w1yWLIk0VzLTHFE1O8GwCaXs5hT9M7u4KsO+IwIen0= -github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20240612072411-114d281b442d/go.mod h1:vHi4fk2Im6fO0ofevbRr/EvblygatrTb1t2XlER58ik= -github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240612072411-114d281b442d h1:jIDz71083inpGWt9IPVGb0DoqyF7tQW/YH0gBLb6sKo= -github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240612072411-114d281b442d/go.mod h1:FC0vVgNI6bv8GH0VTwjup+arwJ8Tau1iEhroWZ1oPwU= -github.com/IBM/idemix/bccsp/types v0.0.0-20240816143710-3dce4618d760 h1:4tcdWj0MONt4JtiqNESWMuWSb5rDInIFzlUSbncHlCM= -github.com/IBM/idemix/bccsp/types v0.0.0-20240816143710-3dce4618d760/go.mod h1:4bYvi+a50aXxmHf1vwuvR+Wd8YXZ6AhT+0p5oK4xdOA= +github.com/IBM/idemix v0.0.2-0.20240829143510-a3d85aa69d56 h1:IeYqGz6OlwI3Q2ZcqW9Xs7qBOiiUfMWOzFRdHcNcL50= +github.com/IBM/idemix v0.0.2-0.20240829143510-a3d85aa69d56/go.mod h1:2q9dra60To5q3IC36LaiLhMGRxNRi2DC69imYf5Gse0= +github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20240820063231-23c21a416ee1 h1:ndFBLK1XEDGQA+sXVfZ1CDKWIwWvvI78NpVoy/+91qA= +github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20240820063231-23c21a416ee1/go.mod h1:QW+GptKF4HtnlVK/T6KAprnbtTDbv4ZnWJ2wm9gWUus= +github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240820063231-23c21a416ee1 h1:/LQ8oNXkaSzk+0on7Blyd9vQWi802bIwXnNmvR3srmU= +github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240820063231-23c21a416ee1/go.mod h1:OlxSkCgdOahDJzm8uyw45a9R7rehCC+0YGyh3gf0b40= +github.com/IBM/idemix/bccsp/types v0.0.0-20240829143510-a3d85aa69d56 h1:vUwF8qQzzsR/tgQVUUHce14LzXMkHY4kD3UdwkVvCAw= +github.com/IBM/idemix/bccsp/types v0.0.0-20240829143510-a3d85aa69d56/go.mod h1:4bYvi+a50aXxmHf1vwuvR+Wd8YXZ6AhT+0p5oK4xdOA= github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da h1:qqGozq4tF6EOVnWoTgBoJGudRKKZXSAYnEtDggzTnsw= github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da/go.mod h1:Tco9QzE3fQzjMS7nPbHDeFfydAzctStf1Pa8hsh6Hjs= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= @@ -654,8 +654,6 @@ github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20231023164747-f3f972769504 h1:sQyFeDcHVHWJ3IeE437NSJjv0+J/6MvGQOJew4X+Cuw= -github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20231023164747-f3f972769504/go.mod h1:z5xq4Ji1RQojJLZzKeZH5+LKCVZxgQRZpQ4xAJWi8r0= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 h1:t3eaIm0rUkzbrIewtiFmMK5RXHej2XnoXNhxVsAYUfg= @@ -1070,14 +1068,14 @@ github.com/hidal-go/hidalgo v0.0.0-20201109092204-05749a6d73df/go.mod h1:bPkrxDl github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/hyperledger-labs/fabric-smart-client v0.3.1-0.20241111074600-334cc6d09cd6 h1:muVqNcNGwDkPs6L5d/KZOSy5Y/YIwWRHCi4Ox3AbSC4= -github.com/hyperledger-labs/fabric-smart-client v0.3.1-0.20241111074600-334cc6d09cd6/go.mod h1:vZLAiVznnEdHyx1OV5nIqf34apnfdhonwJL+qEYniIQ= github.com/hyperledger-labs/fabric-smart-client v0.3.1-0.20241114072958-8bdbea854812 h1:1GGnfSHFRKfnCZtho6Ia8ZneaGsI5abKDqXsdL8hVSo= github.com/hyperledger-labs/fabric-smart-client v0.3.1-0.20241114072958-8bdbea854812/go.mod h1:vZLAiVznnEdHyx1OV5nIqf34apnfdhonwJL+qEYniIQ= github.com/hyperledger-labs/orion-sdk-go v0.2.10 h1:lFgWgxyvngIhWnIqymYGBmtmq9D6uC5d0uLG9cbyh5s= github.com/hyperledger-labs/orion-sdk-go v0.2.10/go.mod h1:iN2xZB964AqwVJwL+EnwPOs8z1EkMEbbIg/qYeC7gDY= github.com/hyperledger-labs/orion-server v0.2.10 h1:G4zbQEL5Egk0Oj+TwHCZWdTOLDBHOjaAEvYOT4G7ozw= github.com/hyperledger-labs/orion-server v0.2.10/go.mod h1:PfuEZFOxbR1o1TjdqL7gQXWD3B0WFET58u9p40rGN+Q= +github.com/hyperledger/aries-bbs-go v0.0.0-20240528084656-761671ea73bc h1:3Ykk6MtyfnlzMOQry9zkxsoLWpCWZwDPqehO/BJwArM= +github.com/hyperledger/aries-bbs-go v0.0.0-20240528084656-761671ea73bc/go.mod h1:Kofn6A6WWea1ZM8Rys5aBW9dszwJ7Ywa0kyyYL0TPYw= github.com/hyperledger/fabric v1.4.0-rc1.0.20230405174026-695dd57e01c2 h1:w5BGxCYEsc9vjdDEdZGrZ5redvs263RYsdT2tqF7cNk= github.com/hyperledger/fabric v1.4.0-rc1.0.20230405174026-695dd57e01c2/go.mod h1:LSwfuRgX/5C2uHkdT3hJtBFu/ALxuL7dFj1pmBby2R4= github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 h1:B1Nt8hKb//KvgGRprk0h1t4lCnwhE9/ryb1WqfZbV+M= diff --git a/integration/ports.go b/integration/ports.go index 148a3a3334..d7943e9147 100755 --- a/integration/ports.go +++ b/integration/ports.go @@ -37,26 +37,26 @@ var ( CommType: fsc.WebSocket, ReplicationFactor: token.None, } - LibP2PNoReplication = &InfrastructureType{ - Label: ginkgo.Label("libp2p"), - CommType: fsc.LibP2P, - ReplicationFactor: token.None, - } WebSocketWithReplication = &InfrastructureType{ Label: ginkgo.Label("replicas"), CommType: fsc.WebSocket, ReplicationFactor: 3, } + LibP2PNoReplication = &InfrastructureType{ + Label: ginkgo.Label("libp2p"), + CommType: fsc.LibP2P, + ReplicationFactor: token.None, + } WebSocketNoReplicationOnly = []*InfrastructureType{ WebSocketNoReplication, } - LibP2PNoReplicationOnly = []*InfrastructureType{ - LibP2PNoReplication, - } WebSocketWithReplicationOnly = []*InfrastructureType{ WebSocketWithReplication, } + LibP2PNoReplicationOnly = []*InfrastructureType{ + LibP2PNoReplication, + } AllTestTypes = []*InfrastructureType{ WebSocketNoReplication, diff --git a/token/core/zkatdlog/crypto/audit/auditor_test.go b/token/core/zkatdlog/crypto/audit/auditor_test.go index 11bc0e4d0e..521829f500 100644 --- a/token/core/zkatdlog/crypto/audit/auditor_test.go +++ b/token/core/zkatdlog/crypto/audit/auditor_test.go @@ -31,6 +31,7 @@ import ( "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix" msp3 "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/msp" + "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/schema" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/sig" "github.com/hyperledger-labs/fabric-token-sdk/token/services/logging" msp2 "github.com/hyperledger/fabric/msp" @@ -52,7 +53,7 @@ var _ = Describe("Auditor", func() { Expect(err).NotTo(HaveOccurred()) pp, err = crypto.Setup(32, ipk, math.FP256BN_AMCL) Expect(err).NotTo(HaveOccurred()) - des, err := idemix.NewDeserializer(pp.IdemixIssuerPK, math.FP256BN_AMCL) + des, err := idemix.NewEidNymRhNymDeserializer(&schema.DefaultManager{}, "", pp.IdemixIssuerPK, math.FP256BN_AMCL) Expect(err).NotTo(HaveOccurred()) auditor = audit.NewAuditor(logging.MustGetLogger("auditor"), &noop.Tracer{}, des, pp.PedersenGenerators, nil, fakeSigningIdentity, math.Curves[pp.Curve]) fakeSigningIdentity.SignReturns([]byte("auditor-signature"), nil) @@ -255,7 +256,7 @@ func getIdemixInfo(dir string) (driver.Identity, *msp3.AuditInfo) { Expect(err).NotTo(HaveOccurred()) cryptoProvider, err := msp3.NewBCCSP(keyStore, math.FP256BN_AMCL, false) Expect(err).NotTo(HaveOccurred()) - p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") Expect(err).NotTo(HaveOccurred()) Expect(p).NotTo(BeNil()) diff --git a/token/core/zkatdlog/crypto/validator/validator_test.go b/token/core/zkatdlog/crypto/validator/validator_test.go index bc39c87d5a..d91cb3eb06 100644 --- a/token/core/zkatdlog/crypto/validator/validator_test.go +++ b/token/core/zkatdlog/crypto/validator/validator_test.go @@ -36,6 +36,7 @@ import ( "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix" msp3 "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/msp" + "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/schema" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/sig" "github.com/hyperledger-labs/fabric-token-sdk/token/services/logging" msp2 "github.com/hyperledger/fabric/msp" @@ -75,7 +76,7 @@ var _ = Describe("validator", func() { c := math.Curves[pp.Curve] asigner, _ := prepareECDSASigner() - des, err := idemix.NewDeserializer(pp.IdemixIssuerPK, math.FP256BN_AMCL) + des, err := idemix.NewEidNymRhNymDeserializer(&schema.DefaultManager{}, "", pp.IdemixIssuerPK, math.FP256BN_AMCL) Expect(err).NotTo(HaveOccurred()) auditor = audit.NewAuditor(logging.MustGetLogger("auditor"), &noop.Tracer{}, des, pp.PedersenGenerators, pp.IdemixIssuerPK, asigner, c) araw, err := asigner.Serialize() @@ -387,7 +388,7 @@ func getIdemixInfo(dir string) (driver.Identity, *msp3.AuditInfo, driver.Signing Expect(err).NotTo(HaveOccurred()) cryptoProvider, err := msp3.NewBCCSP(keyStore, math.FP256BN_AMCL, false) Expect(err).NotTo(HaveOccurred()) - p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") Expect(err).NotTo(HaveOccurred()) Expect(p).NotTo(BeNil()) diff --git a/token/core/zkatdlog/nogh/driver/deserializer.go b/token/core/zkatdlog/nogh/driver/deserializer.go index 5c43abbbc3..5e14f39ec2 100644 --- a/token/core/zkatdlog/nogh/driver/deserializer.go +++ b/token/core/zkatdlog/nogh/driver/deserializer.go @@ -14,6 +14,7 @@ import ( "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/interop/htlc" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix" + "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/schema" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/x509" htlc2 "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/htlc" "github.com/pkg/errors" @@ -29,7 +30,12 @@ func NewDeserializer(pp *crypto.PublicParams) (*Deserializer, error) { if pp == nil { return nil, errors.New("failed to get deserializer: nil public parameters") } - idemixDes, err := idemix.NewDeserializer(pp.IdemixIssuerPK, pp.IdemixCurveID) + idemixDes, err := idemix.NewEidNymRhNymDeserializer( + &schema.DefaultManager{}, + "", + pp.IdemixIssuerPK, + pp.IdemixCurveID, + ) if err != nil { return nil, errors.Wrapf(err, "failed getting idemix deserializer for passed public params [%d]", pp.IdemixCurveID) } diff --git a/token/services/identity/msp/idemix/deserializer.go b/token/services/identity/msp/idemix/deserializer.go index 4bb509ced8..d05d360216 100644 --- a/token/services/identity/msp/idemix/deserializer.go +++ b/token/services/identity/msp/idemix/deserializer.go @@ -9,7 +9,6 @@ package idemix import ( "fmt" - msp "github.com/IBM/idemix" csp "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/hash" @@ -23,47 +22,49 @@ type Deserializer struct { *msp2.Deserializer } -// NewDeserializer returns a new deserializer for the idemix ExpectEidNymRhNym verification strategy -func NewDeserializer(ipk []byte, curveID math.CurveID) (*Deserializer, error) { - logger.Debugf("new deserialized for dlog idemix") +// NewEidNymRhNymDeserializer returns a new deserializer that expects EID and RH Nyms identities. +// The returned deserializer checks the validly of the deserialized identities. +func NewEidNymRhNymDeserializer( + sm SchemaManager, + schema string, + ipk []byte, + curveID math.CurveID, +) (*Deserializer, error) { cryptoProvider, err := msp2.NewBCCSPWithDummyKeyStore(curveID, curveID == math.BLS12_381_BBS) if err != nil { return nil, errors.WithMessagef(err, "failed to instantiate crypto provider for curve [%d]", curveID) } - return NewDeserializerWithProvider(ipk, csp.ExpectEidNymRhNym, nil, cryptoProvider) + return NewDeserializer(sm, schema, ipk, csp.ExpectEidNymRhNym, nil, cryptoProvider) } -// NewDeserializerWithProvider returns a new serialized for the passed arguments -func NewDeserializerWithProvider( +// NewDeserializer returns a new deserializer for the passed arguments. +// The returned deserializer checks the validly of the deserialized identities. +func NewDeserializer( + sm SchemaManager, + schema string, ipk []byte, verType csp.VerificationType, nymEID []byte, cryptoProvider csp.BCCSP, ) (*Deserializer, error) { - return NewDeserializerWithBCCSP(ipk, verType, nymEID, cryptoProvider) -} - -func NewDeserializerWithBCCSP(ipk []byte, verType csp.VerificationType, nymEID []byte, cryptoProvider csp.BCCSP) (*Deserializer, error) { logger.Debugf("Setting up Idemix-based MSP instance") // Import Issuer Public Key + if len(ipk) == 0 { + return nil, errors.Errorf("no issuer public key provided") + } var issuerPublicKey csp.Key - var err error - if len(ipk) != 0 { - issuerPublicKey, err = cryptoProvider.KeyImport( - ipk, - &csp.IdemixIssuerPublicKeyImportOpts{ - Temporary: true, - AttributeNames: []string{ - msp.AttributeNameOU, - msp.AttributeNameRole, - msp.AttributeNameEnrollmentId, - msp.AttributeNameRevocationHandle, - }, - }) - if err != nil { - return nil, err - } + // get the opts from the schema manager + opts, err := sm.PublicKeyImportOpts(schema) + if err != nil { + return nil, errors.Wrapf(err, "could not obtain PublicKeyImportOpts for schema '%s'", schema) + } + issuerPublicKey, err = cryptoProvider.KeyImport( + ipk, + opts, + ) + if err != nil { + return nil, err } return &Deserializer{ @@ -73,79 +74,52 @@ func NewDeserializerWithBCCSP(ipk []byte, verType csp.VerificationType, nymEID [ IssuerPublicKey: issuerPublicKey, VerType: verType, NymEID: nymEID, + SchemaManager: sm, + Schema: schema, }, }, nil } -func (i *Deserializer) DeserializeVerifier(raw driver.Identity) (driver.Verifier, error) { - identity, err := i.Deserialize(raw, true) - if err != nil { - return nil, err - } - - return &msp2.NymSignatureVerifier{ - CSP: i.Deserializer.Csp, - IPK: i.Deserializer.IssuerPublicKey, - NymPK: identity.NymPublicKey, - }, nil -} - -func (i *Deserializer) DeserializeVerifierAgainstNymEID(raw []byte, nymEID []byte) (driver.Verifier, error) { - identity, err := i.Deserializer.DeserializeAgainstNymEID(raw, true, nymEID) +func (d *Deserializer) DeserializeVerifier(raw driver.Identity) (driver.Verifier, error) { + identity, err := d.Deserialize(raw) if err != nil { return nil, err } return &msp2.NymSignatureVerifier{ - CSP: i.Deserializer.Csp, - IPK: i.Deserializer.IssuerPublicKey, - NymPK: identity.NymPublicKey, + CSP: d.Deserializer.Csp, + IPK: d.Deserializer.IssuerPublicKey, + NymPK: identity.NymPublicKey, + SchemaManager: d.SchemaManager, + Schema: d.Schema, }, nil } -func (i *Deserializer) DeserializeSigner(raw []byte) (driver.Signer, error) { - return nil, errors.New("not supported") -} - -func (i *Deserializer) DeserializeAuditInfo(raw []byte) (driver2.AuditInfo, error) { - return i.Deserializer.DeserializeAuditInfo(raw) -} - -func (i *Deserializer) GetOwnerMatcher(raw []byte) (driver.Matcher, error) { - return i.Deserializer.DeserializeAuditInfo(raw) +func (d *Deserializer) DeserializeAuditInfo(raw []byte) (driver2.AuditInfo, error) { + return d.Deserializer.DeserializeAuditInfo(raw) } -func (i *Deserializer) GetOwnerAuditInfo(raw []byte, p driver.AuditInfoProvider) ([][]byte, error) { - auditInfo, err := p.GetAuditInfo(raw) - if err != nil { - return nil, errors.Wrapf(err, "failed getting audit info for recipient identity [%s]", driver.Identity(raw).String()) - } - return [][]byte{auditInfo}, nil +func (d *Deserializer) GetOwnerMatcher(raw []byte) (driver.Matcher, error) { + return d.Deserializer.DeserializeAuditInfo(raw) } -func (i *Deserializer) Info(raw []byte, auditInfo []byte) (string, error) { - r, err := i.Deserialize(raw, false) +func (d *Deserializer) DeserializeVerifierAgainstNymEID(raw []byte, nymEID []byte) (driver.Verifier, error) { + identity, err := d.Deserializer.DeserializeAgainstNymEID(raw, nymEID) if err != nil { - return "", err - } - - eid := "" - if len(auditInfo) != 0 { - ai, err := msp2.DeserializeAuditInfo(auditInfo) - if err != nil { - return "", err - } - if err := ai.Match(raw); err != nil { - return "", err - } - eid = ai.EnrollmentID() + return nil, err } - return fmt.Sprintf("MSP.Idemix: [%s][%s][%s][%s][%s]", eid, driver.Identity(raw).UniqueID(), r.SerializedIdentity.Mspid, r.OU.OrganizationalUnitIdentifier, r.Role.Role.String()), nil + return &msp2.NymSignatureVerifier{ + CSP: d.Deserializer.Csp, + IPK: d.Deserializer.IssuerPublicKey, + NymPK: identity.NymPublicKey, + SchemaManager: d.SchemaManager, + Schema: d.Schema, + }, nil } -func (i *Deserializer) String() string { - return fmt.Sprintf("Idemix with IPK [%s]", hash.Hashable(i.Ipk).String()) +func (d *Deserializer) String() string { + return fmt.Sprintf("Idemix with IPK [%s]", hash.Hashable(d.Ipk).String()) } type AuditInfoDeserializer struct{} diff --git a/token/services/identity/msp/idemix/km.go b/token/services/identity/msp/idemix/km.go index 1582a43358..6eae206796 100644 --- a/token/services/identity/msp/idemix/km.go +++ b/token/services/identity/msp/idemix/km.go @@ -10,9 +10,8 @@ import ( "fmt" "strconv" - "github.com/IBM/idemix" bccsp "github.com/IBM/idemix/bccsp/types" - "github.com/IBM/idemix/idemixmsp" + im "github.com/IBM/idemix/idemixmsp" "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/hash" "github.com/hyperledger-labs/fabric-token-sdk/token/driver" @@ -26,6 +25,22 @@ const ( Any bccsp.SignatureType = 100 ) +// SchemaManager handles the various credential schemas. A credential schema +// contains information about the number of attributes, which attributes +// must be disclosed when creating proofs, the format of the attributes etc. +type SchemaManager interface { + // PublicKeyImportOpts returns the options that `schema` uses to import its public keys + PublicKeyImportOpts(schema string) (*bccsp.IdemixIssuerPublicKeyImportOpts, error) + // SignerOpts returns the options for the passed arguments + SignerOpts(schema string, ou *m.OrganizationUnit, role *m.MSPRole) (*bccsp.IdemixSignerOpts, error) + // NymSignerOpts returns the options that `schema` uses to verify a nym signature + NymSignerOpts(schema string) (*bccsp.IdemixNymSignerOpts, error) + // EidNymAuditOpts returns the options that `sid` must use to audit an EIDNym + EidNymAuditOpts(schema string, attrs [][]byte) (*bccsp.EidNymAuditOpts, error) + // RhNymAuditOpts returns the options that `sid` must use to audit an RhNym + RhNymAuditOpts(schema string, attrs [][]byte) (*bccsp.RhNymAuditOpts, error) +} + type SignerService interface { RegisterSigner(identity driver.Identity, signer driver.Signer, verifier driver.Verifier, info []byte) error } @@ -33,21 +48,31 @@ type SignerService interface { type KeyManager struct { *msp.Deserializer userKey bccsp.Key - conf idemixmsp.IdemixMSPConfig + conf im.IdemixMSPConfig SignerService SignerService sigType bccsp.SignatureType verType bccsp.VerificationType + + SchemaManager SchemaManager + Schema string } -func NewKeyManager(conf1 *m.MSPConfig, signerService SignerService, sigType bccsp.SignatureType, cryptoProvider bccsp.BCCSP) (*KeyManager, error) { +func NewKeyManager( + conf1 *m.MSPConfig, + signerService SignerService, + sigType bccsp.SignatureType, + cryptoProvider bccsp.BCCSP, + sm SchemaManager, + schema string, +) (*KeyManager, error) { logger.Debugf("Setting up Idemix-based MSP instance") if conf1 == nil { return nil, errors.Errorf("setup error: nil conf reference") } - var conf idemixmsp.IdemixMSPConfig + var conf im.IdemixMSPConfig err := proto.Unmarshal(conf1.Config, &conf) if err != nil { return nil, errors.Wrap(err, "failed unmarshalling idemix provider config") @@ -55,18 +80,16 @@ func NewKeyManager(conf1 *m.MSPConfig, signerService SignerService, sigType bccs logger.Debugf("Setting up Idemix MSP instance %s", conf.Name) + // get the opts from the schema manager + opts, err := sm.PublicKeyImportOpts(schema) + if err != nil { + return nil, errors.Wrapf(err, "could not obtain PublicKeyImportOpts for schema '%s'", schema) + } // Import Issuer Public Key issuerPublicKey, err := cryptoProvider.KeyImport( conf.Ipk, - &bccsp.IdemixIssuerPublicKeyImportOpts{ - Temporary: true, - AttributeNames: []string{ - idemix.AttributeNameOU, - idemix.AttributeNameRole, - idemix.AttributeNameEnrollmentId, - idemix.AttributeNameRevocationHandle, - }, - }) + opts, + ) if err != nil { return nil, err } @@ -154,12 +177,16 @@ func NewKeyManager(conf1 *m.MSPConfig, signerService SignerService, sigType bccs RevocationPK: RevocationPublicKey, Epoch: 0, VerType: verType, + SchemaManager: sm, + Schema: schema, }, userKey: userKey, conf: conf, SignerService: signerService, sigType: sigType, verType: verType, + SchemaManager: sm, + Schema: schema, }, nil } @@ -211,22 +238,16 @@ func (p *KeyManager) Identity(auditInfo []byte) (driver.Identity, []byte, error) } // Create the cryptographic evidence that this identity is valid - sigOpts := &bccsp.IdemixSignerOpts{ - Credential: p.conf.Signer.Cred, - Nym: nymKey, - IssuerPK: p.IssuerPublicKey, - Attributes: []bccsp.IdemixAttribute{ - {Type: bccsp.IdemixBytesAttribute}, - {Type: bccsp.IdemixIntAttribute}, - {Type: bccsp.IdemixHiddenAttribute}, - {Type: bccsp.IdemixHiddenAttribute}, - }, - RhIndex: msp.RHIndex, - EidIndex: msp.EIDIndex, - CRI: p.conf.Signer.CredentialRevocationInformation, - SigType: sigType, - Metadata: signerMetadata, - } + sigOpts, err := p.SchemaManager.SignerOpts(p.Schema, ou, role) + if err != nil { + return nil, nil, errors.Wrapf(err, "could obtain signer sigOpts for schema %s", p.Schema) + } + sigOpts.Credential = p.conf.Signer.Cred + sigOpts.Nym = nymKey + sigOpts.IssuerPK = p.IssuerPublicKey + sigOpts.CRI = p.conf.Signer.CredentialRevocationInformation + sigOpts.SigType = sigType + sigOpts.Metadata = signerMetadata proof, err := p.Csp.Sign( p.userKey, nil, @@ -237,7 +258,7 @@ func (p *KeyManager) Identity(auditInfo []byte) (driver.Identity, []byte, error) } // Set up default signer - id, err := msp.NewIdentity(p.Deserializer, NymPublicKey, role, ou, proof, p.verType) + id, err := msp.NewIdentity(p.Deserializer, NymPublicKey, role, ou, proof, p.verType, p.SchemaManager, p.Schema) if err != nil { return nil, nil, err } @@ -265,8 +286,6 @@ func (p *KeyManager) Identity(auditInfo []byte) (driver.Identity, []byte, error) infoRaw = nil case bccsp.EidNymRhNym: auditInfo := &msp.AuditInfo{ - Csp: p.Csp, - IssuerPublicKey: p.IssuerPublicKey, EidNymAuditData: sigOpts.Metadata.EidNymAuditData, RhNymAuditData: sigOpts.Metadata.RhNymAuditData, Attributes: [][]byte{ @@ -275,6 +294,10 @@ func (p *KeyManager) Identity(auditInfo []byte) (driver.Identity, []byte, error) []byte(enrollmentID), []byte(rh), }, + Csp: p.Csp, + IssuerPublicKey: p.IssuerPublicKey, + SchemaManager: p.SchemaManager, + Schema: p.Schema, } if logger.IsEnabledFor(zapcore.DebugLevel) { logger.Debugf("new idemix identity generated with [%s:%s]", enrollmentID, hash.Hashable(auditInfo.Attributes[3]).String()) @@ -294,7 +317,7 @@ func (p *KeyManager) IsRemote() bool { } func (p *KeyManager) DeserializeVerifier(raw []byte) (driver.Verifier, error) { - r, err := p.Deserialize(raw, true) + r, err := p.Deserialize(raw) if err != nil { return nil, err } @@ -303,7 +326,7 @@ func (p *KeyManager) DeserializeVerifier(raw []byte) (driver.Verifier, error) { } func (p *KeyManager) DeserializeSigner(raw []byte) (driver.Signer, error) { - r, err := p.Deserialize(raw, true) + r, err := p.Deserialize(raw) if err != nil { return nil, err } @@ -332,7 +355,7 @@ func (p *KeyManager) DeserializeSigner(raw []byte) (driver.Signer, error) { } func (p *KeyManager) Info(raw []byte, auditInfo []byte) (string, error) { - r, err := p.Deserialize(raw, true) + r, err := p.Deserialize(raw) if err != nil { return "", err } @@ -342,6 +365,8 @@ func (p *KeyManager) Info(raw []byte, auditInfo []byte) (string, error) { ai := &msp.AuditInfo{ Csp: p.Csp, IssuerPublicKey: p.IssuerPublicKey, + SchemaManager: p.SchemaManager, + Schema: p.Schema, } if err := ai.FromBytes(auditInfo); err != nil { return "", err @@ -374,7 +399,7 @@ func (p *KeyManager) DeserializeSigningIdentity(raw []byte) (driver.SigningIdent return nil, errors.Wrap(err, "failed to unmarshal to msp.SerializedIdentity{}") } - serialized := new(m.SerializedIdemixIdentity) + serialized := new(im.SerializedIdemixIdentity) err = proto.Unmarshal(si.IdBytes, serialized) if err != nil { return nil, errors.Wrap(err, "could not deserialize a SerializedIdemixIdentity") @@ -409,7 +434,7 @@ func (p *KeyManager) DeserializeSigningIdentity(raw []byte) (driver.SigningIdent return nil, errors.Wrap(err, "cannot deserialize the role of the identity") } - id, _ := msp.NewIdentity(p.Deserializer, NymPublicKey, role, ou, serialized.Proof, p.verType) + id, _ := msp.NewIdentity(p.Deserializer, NymPublicKey, role, ou, serialized.Proof, p.verType, p.SchemaManager, p.Schema) if err := id.Validate(); err != nil { return nil, errors.Wrap(err, "cannot deserialize, invalid identity") } diff --git a/token/services/identity/msp/idemix/km_test.go b/token/services/identity/msp/idemix/km_test.go index f7da62179a..e0667ad9dc 100644 --- a/token/services/identity/msp/idemix/km_test.go +++ b/token/services/identity/msp/idemix/km_test.go @@ -24,6 +24,7 @@ import ( kvs2 "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/kvs" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/msp" + "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/schema" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/sig" msp2 "github.com/hyperledger/fabric/msp" "github.com/stretchr/testify/assert" @@ -42,17 +43,17 @@ func TestKeyManager(t *testing.T) { cryptoProvider, err := msp.NewBCCSP(keyStore, math.FP256BN_AMCL, false) assert.NoError(t, err) - p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) assert.True(t, p.Anonymous()) - p, err = idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider) + p, err = idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) assert.True(t, p.Anonymous()) - p, err = idemix.NewKeyManager(config, sigService, bccsp.EidNymRhNym, cryptoProvider) + p, err = idemix.NewKeyManager(config, sigService, bccsp.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) assert.True(t, p.Anonymous()) @@ -74,7 +75,7 @@ func TestIdentityWithEidRhNymPolicy(t *testing.T) { assert.NoError(t, err) cryptoProvider, err := msp.NewBCCSP(keyStore, math.FP256BN_AMCL, false) assert.NoError(t, err) - p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -104,7 +105,7 @@ func TestIdentityWithEidRhNymPolicy(t *testing.T) { assert.NoError(t, err) cryptoProvider, err = msp.NewBCCSP(keyStore, math.FP256BN_AMCL, false) assert.NoError(t, err) - p, err = idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p, err = idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -147,7 +148,7 @@ func TestIdentityStandard(t *testing.T) { assert.NoError(t, err) cryptoProvider, err := msp.NewBCCSP(keyStore, math.FP256BN_AMCL, false) assert.NoError(t, err) - p, err := idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider) + p, err := idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -169,7 +170,7 @@ func TestIdentityStandard(t *testing.T) { assert.NoError(t, err) cryptoProvider, err = msp.NewBCCSP(keyStore, math.FP256BN_AMCL, false) assert.NoError(t, err) - p, err = idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider) + p, err = idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -191,7 +192,7 @@ func TestIdentityStandard(t *testing.T) { assert.NoError(t, err) cryptoProvider, err = msp.NewBCCSP(keyStore, math.FP256BN_AMCL, false) assert.NoError(t, err) - p, err = idemix.NewKeyManager(config, sigService, idemix.Any, cryptoProvider) + p, err = idemix.NewKeyManager(config, sigService, idemix.Any, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -225,7 +226,7 @@ func TestAuditWithEidRhNymPolicy(t *testing.T) { assert.NoError(t, err) cryptoProvider, err := msp.NewBCCSP(keyStore, math.FP256BN_AMCL, false) assert.NoError(t, err) - p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -235,7 +236,7 @@ func TestAuditWithEidRhNymPolicy(t *testing.T) { assert.NoError(t, err) cryptoProvider, err = msp.NewBCCSP(keyStore, math.FP256BN_AMCL, false) assert.NoError(t, err) - p2, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p2, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p2) @@ -275,13 +276,13 @@ func TestKeyManager_DeserializeSigner(t *testing.T) { assert.NoError(t, err) cryptoProvider, err := msp.NewBCCSP(keyStore, math.FP256BN_AMCL, false) assert.NoError(t, err) - p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) config, err = msp2.GetLocalMspConfigWithType("./testdata/sameissuer/idemix2", nil, "idemix", "idemix") assert.NoError(t, err) - p2, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p2, err := idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p2) @@ -338,7 +339,7 @@ func TestIdentityFromFabricCA(t *testing.T) { assert.NoError(t, err) cryptoProvider, err := msp.NewBCCSP(keyStore, math.BN254, false) assert.NoError(t, err) - p, err := idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider) + p, err := idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -360,7 +361,7 @@ func TestIdentityFromFabricCA(t *testing.T) { assert.NoError(t, err) cryptoProvider, err = msp.NewBCCSP(keyStore, math.BN254, false) assert.NoError(t, err) - p, err = idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider) + p, err = idemix.NewKeyManager(config, sigService, bccsp.Standard, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -382,7 +383,7 @@ func TestIdentityFromFabricCA(t *testing.T) { assert.NoError(t, err) cryptoProvider, err = msp.NewBCCSP(keyStore, math.BN254, false) assert.NoError(t, err) - p, err = idemix.NewKeyManager(config, sigService, idemix.Any, cryptoProvider) + p, err = idemix.NewKeyManager(config, sigService, idemix.Any, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -419,7 +420,7 @@ func TestIdentityFromFabricCAWithEidRhNymPolicy(t *testing.T) { assert.NoError(t, err) cryptoProvider, err := msp.NewBCCSP(keyStore, math.BN254, false) assert.NoError(t, err) - p, err := idemix.NewKeyManager(config, sigService, bccsp.EidNymRhNym, cryptoProvider) + p, err := idemix.NewKeyManager(config, sigService, bccsp.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) @@ -451,7 +452,7 @@ func TestIdentityFromFabricCAWithEidRhNymPolicy(t *testing.T) { assert.NoError(t, err) cryptoProvider, err = msp.NewBCCSP(keyStore, math.BN254, false) assert.NoError(t, err) - p, err = idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider) + p, err = idemix.NewKeyManager(config, sigService, types.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") assert.NoError(t, err) assert.NotNil(t, p) diff --git a/token/services/identity/msp/idemix/kmp.go b/token/services/identity/msp/idemix/kmp.go index 22e1ef1f89..a2986a7a15 100644 --- a/token/services/identity/msp/idemix/kmp.go +++ b/token/services/identity/msp/idemix/kmp.go @@ -15,6 +15,7 @@ import ( driver2 "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/driver" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/cache" msp2 "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/msp" + "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/schema" "github.com/hyperledger-labs/fabric-token-sdk/token/services/logging" "github.com/hyperledger/fabric-protos-go/msp" "github.com/pkg/errors" @@ -60,7 +61,7 @@ func (l *KeyManagerProvider) Get(identityConfig *driver.IdentityConfiguration) ( if err != nil { return nil, errors.WithMessage(err, "failed to instantiate crypto provider") } - provider, err := NewKeyManager(conf, l.signerService, bccsp.EidNymRhNym, cryptoProvider) + provider, err := NewKeyManager(conf, l.signerService, bccsp.EidNymRhNym, cryptoProvider, &schema.DefaultManager{}, "") if err != nil { return nil, errors.Wrapf(err, "failed instantiating idemix msp provider from [%s]", identityConfig.URL) } diff --git a/token/services/identity/msp/idemix/msp/audit.go b/token/services/identity/msp/idemix/msp/audit.go index a185d21e08..61b4b27b97 100644 --- a/token/services/identity/msp/idemix/msp/audit.go +++ b/token/services/identity/msp/idemix/msp/audit.go @@ -10,6 +10,7 @@ import ( "encoding/json" csp "github.com/IBM/idemix/bccsp/types" + im "github.com/IBM/idemix/idemixmsp" "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto" m "github.com/hyperledger/fabric-protos-go/msp" "github.com/pkg/errors" @@ -19,8 +20,11 @@ type AuditInfo struct { EidNymAuditData *csp.AttrNymAuditData RhNymAuditData *csp.AttrNymAuditData Attributes [][]byte - Csp csp.BCCSP `json:"-"` - IssuerPublicKey csp.Key `json:"-"` + + Csp csp.BCCSP `json:"-"` + IssuerPublicKey csp.Key `json:"-"` + SchemaManager SchemaManager `json:"-"` + Schema string } func (a *AuditInfo) Bytes() ([]byte, error) { @@ -46,22 +50,24 @@ func (a *AuditInfo) Match(id []byte) error { return errors.Wrap(err, "failed to unmarshal to msp.SerializedIdentity{}") } - serialized := new(m.SerializedIdemixIdentity) + serialized := new(im.SerializedIdemixIdentity) err = proto.Unmarshal(si.IdBytes, serialized) if err != nil { return errors.Wrap(err, "could not deserialize a SerializedIdemixIdentity") } + eidAuditOpts, err := a.SchemaManager.EidNymAuditOpts(a.Schema, a.Attributes) + if err != nil { + return errors.Wrap(err, "error while getting a RhNymAuditOpts") + } + eidAuditOpts.RNymEid = a.EidNymAuditData.Rand + // Audit EID valid, err := a.Csp.Verify( a.IssuerPublicKey, serialized.Proof, nil, - &csp.EidNymAuditOpts{ - EidIndex: EIDIndex, - EnrollmentID: string(a.Attributes[EIDIndex]), - RNymEid: a.EidNymAuditData.Rand, - }, + eidAuditOpts, ) if err != nil { return errors.Wrap(err, "error while verifying the nym eid") @@ -70,16 +76,18 @@ func (a *AuditInfo) Match(id []byte) error { return errors.New("invalid nym rh") } + rhAuditOpts, err := a.SchemaManager.RhNymAuditOpts(a.Schema, a.Attributes) + if err != nil { + return errors.Wrap(err, "error while getting a RhNymAuditOpts") + } + rhAuditOpts.RNymRh = a.RhNymAuditData.Rand + // Audit RH valid, err = a.Csp.Verify( a.IssuerPublicKey, serialized.Proof, nil, - &csp.RhNymAuditOpts{ - RhIndex: RHIndex, - RevocationHandle: string(a.Attributes[RHIndex]), - RNymRh: a.RhNymAuditData.Rand, - }, + rhAuditOpts, ) if err != nil { return errors.Wrap(err, "error while verifying the nym rh") diff --git a/token/services/identity/msp/idemix/msp/config.go b/token/services/identity/msp/idemix/msp/config.go index 758884e672..898a02aa96 100644 --- a/token/services/identity/msp/idemix/msp/config.go +++ b/token/services/identity/msp/idemix/msp/config.go @@ -30,12 +30,14 @@ type SignerConfig struct { Role int `protobuf:"varint,4,opt,name=role,json=role" json:"role,omitempty"` // EnrollmentID contains the enrollment id of this signer EnrollmentID string `protobuf:"bytes,5,opt,name=enrollment_id,json=enrollmentId" json:"enrollment_id,omitempty"` - // CRI contains a serialized Credential Revocation Information + // CRI contains a serialized CredentialRevocationInformation CredentialRevocationInformation []byte `protobuf:"bytes,6,opt,name=credential_revocation_information,json=credentialRevocationInformation,proto3" json:"credential_revocation_information,omitempty"` // RevocationHandle is the handle used to single out this credential and determine its revocation status RevocationHandle string `protobuf:"bytes,7,opt,name=revocation_handle,json=revocationHandle,proto3" json:"revocation_handle,omitempty"` // CurveID specifies the name of the Idemix curve to use, defaults to 'amcl.Fp256bn' CurveID string `protobuf:"bytes,8,opt,name=curve_id,json=curveID" json:"curveID,omitempty"` + // Schema contains the version of the schema used by this credential + Schema string `protobuf:"bytes,9,opt,name=schema,json=schema" json:"schema,omitempty"` } const ( @@ -123,6 +125,7 @@ func GetFabricCAIdemixMspConfig(issuerPublicKey []byte, dir string, ID string) ( EnrollmentId: si.EnrollmentID, CredentialRevocationInformation: si.CredentialRevocationInformation, RevocationHandle: si.RevocationHandle, + Schema: si.Schema, } } else { if !os.IsNotExist(errors.Cause(err)) { diff --git a/token/services/identity/msp/idemix/msp/deserializer.go b/token/services/identity/msp/idemix/msp/deserializer.go index 4768bc0e1f..d1d95cb6f0 100644 --- a/token/services/identity/msp/idemix/msp/deserializer.go +++ b/token/services/identity/msp/idemix/msp/deserializer.go @@ -8,6 +8,7 @@ package msp import ( bccsp "github.com/IBM/idemix/bccsp/types" + im "github.com/IBM/idemix/idemixmsp" "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto" m "github.com/hyperledger/fabric-protos-go/msp" "github.com/pkg/errors" @@ -31,20 +32,22 @@ type Deserializer struct { VerType bccsp.VerificationType NymEID []byte RhNym []byte + SchemaManager SchemaManager + Schema string } -func (c *Deserializer) Deserialize(raw []byte, checkValidity bool) (*DeserializedIdentity, error) { - return c.DeserializeAgainstNymEID(raw, checkValidity, nil) +func (d *Deserializer) Deserialize(raw []byte) (*DeserializedIdentity, error) { + return d.DeserializeAgainstNymEID(raw, nil) } -func (c *Deserializer) DeserializeAgainstNymEID(raw []byte, checkValidity bool, nymEID []byte) (*DeserializedIdentity, error) { +func (d *Deserializer) DeserializeAgainstNymEID(raw []byte, nymEID []byte) (*DeserializedIdentity, error) { si := &m.SerializedIdentity{} err := proto.Unmarshal(raw, si) if err != nil { return nil, errors.Wrap(err, "failed to unmarshal to msp.SerializedIdentity{}") } - serialized := new(m.SerializedIdemixIdentity) + serialized := new(im.SerializedIdemixIdentity) err = proto.Unmarshal(si.IdBytes, serialized) if err != nil { return nil, errors.Wrap(err, "could not deserialize a SerializedIdemixIdentity") @@ -53,11 +56,16 @@ func (c *Deserializer) DeserializeAgainstNymEID(raw []byte, checkValidity bool, return nil, errors.Errorf("unable to deserialize idemix identity: pseudonym is invalid") } + // match schema + if serialized.Schema != d.Schema { + return nil, errors.Errorf("unable to deserialize idemix identity: schema does not match [%s]!=[%s]", serialized.Schema, d.Schema) + } + // Import NymPublicKey var rawNymPublicKey []byte rawNymPublicKey = append(rawNymPublicKey, serialized.NymX...) rawNymPublicKey = append(rawNymPublicKey, serialized.NymY...) - NymPublicKey, err := c.Csp.KeyImport( + NymPublicKey, err := d.Csp.KeyImport( rawNymPublicKey, &bccsp.IdemixNymPublicKeyImportOpts{Temporary: true}, ) @@ -79,17 +87,18 @@ func (c *Deserializer) DeserializeAgainstNymEID(raw []byte, checkValidity bool, return nil, errors.Wrap(err, "cannot deserialize the role of the identity") } - idemix := c + idemix := d if len(nymEID) != 0 { idemix = &Deserializer{ - Name: c.Name, - Ipk: c.Ipk, - Csp: c.Csp, - IssuerPublicKey: c.IssuerPublicKey, - RevocationPK: c.RevocationPK, - Epoch: c.Epoch, - VerType: c.VerType, + Name: d.Name, + Ipk: d.Ipk, + Csp: d.Csp, + IssuerPublicKey: d.IssuerPublicKey, + RevocationPK: d.RevocationPK, + Epoch: d.Epoch, + VerType: d.VerType, NymEID: nymEID, + SchemaManager: d.SchemaManager, } } @@ -99,15 +108,15 @@ func (c *Deserializer) DeserializeAgainstNymEID(raw []byte, checkValidity bool, role, ou, serialized.Proof, - c.VerType, + d.VerType, + d.SchemaManager, + d.Schema, ) if err != nil { return nil, errors.Wrap(err, "cannot deserialize") } - if checkValidity { - if err := id.Validate(); err != nil { - return nil, errors.Wrap(err, "cannot deserialize, invalid identity") - } + if err := id.Validate(); err != nil { + return nil, errors.Wrap(err, "cannot deserialize, invalid identity") } return &DeserializedIdentity{ @@ -119,12 +128,14 @@ func (c *Deserializer) DeserializeAgainstNymEID(raw []byte, checkValidity bool, }, nil } -func (c *Deserializer) DeserializeAuditInfo(raw []byte) (*AuditInfo, error) { +func (d *Deserializer) DeserializeAuditInfo(raw []byte) (*AuditInfo, error) { ai, err := DeserializeAuditInfo(raw) if err != nil { return nil, errors.Wrapf(err, "failed deserializing audit info [%s]", string(raw)) } - ai.Csp = c.Csp - ai.IssuerPublicKey = c.IssuerPublicKey + ai.Csp = d.Csp + ai.IssuerPublicKey = d.IssuerPublicKey + ai.SchemaManager = d.SchemaManager + ai.Schema = d.Schema return ai, nil } diff --git a/token/services/identity/msp/idemix/msp/id.go b/token/services/identity/msp/idemix/msp/id.go index 04ac3d96cd..57661dd0ef 100644 --- a/token/services/identity/msp/idemix/msp/id.go +++ b/token/services/identity/msp/idemix/msp/id.go @@ -11,6 +11,7 @@ import ( "time" bccsp "github.com/IBM/idemix/bccsp/types" + im "github.com/IBM/idemix/idemixmsp" "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto" "github.com/hyperledger-labs/fabric-token-sdk/token/services/logging" m "github.com/hyperledger/fabric-protos-go/msp" @@ -27,9 +28,23 @@ const ( var logger = logging.MustGetLogger("token-sdk.services.identity.msp.idemix") +// SchemaManager handles the various credential schemas. A credential schema +// contains information about the number of attributes, which attributes +// must be disclosed when creating proofs, the format of the attributes etc. +type SchemaManager interface { + // SignerOpts returns the options for the passed arguments + SignerOpts(schema string, ou *m.OrganizationUnit, role *m.MSPRole) (*bccsp.IdemixSignerOpts, error) + // NymSignerOpts returns the options that `schema` uses to verify a nym signature + NymSignerOpts(schema string) (*bccsp.IdemixNymSignerOpts, error) + // EidNymAuditOpts returns the options that `sid` must use to audit an EIDNym + EidNymAuditOpts(schema string, attrs [][]byte) (*bccsp.EidNymAuditOpts, error) + // RhNymAuditOpts returns the options that `sid` must use to audit an RhNym + RhNymAuditOpts(schema string, attrs [][]byte) (*bccsp.RhNymAuditOpts, error) +} + type Identity struct { NymPublicKey bccsp.Key - Idemix *Deserializer + Deserializer *Deserializer ID *msp.IdentityIdentifier Role *m.MSPRole OU *m.OrganizationUnit @@ -38,23 +53,37 @@ type Identity struct { // is constructed from a secret key on which the CA issued a credential. AssociationProof []byte VerificationType bccsp.VerificationType + + SchemaManager SchemaManager + Schema string } -func NewIdentity(idemix *Deserializer, NymPublicKey bccsp.Key, role *m.MSPRole, ou *m.OrganizationUnit, proof []byte, verificationType bccsp.VerificationType) (*Identity, error) { +func NewIdentity( + deserializer *Deserializer, + NymPublicKey bccsp.Key, + role *m.MSPRole, + ou *m.OrganizationUnit, + proof []byte, + verificationType bccsp.VerificationType, + SchemaManager SchemaManager, + Schema string, +) (*Identity, error) { id := &Identity{} - id.Idemix = idemix + id.Deserializer = deserializer id.NymPublicKey = NymPublicKey id.Role = role id.OU = ou id.AssociationProof = proof id.VerificationType = verificationType + id.SchemaManager = SchemaManager + id.Schema = Schema raw, err := NymPublicKey.Bytes() if err != nil { return nil, errors.Wrapf(err, "failed to marshal nym public key") } id.ID = &msp.IdentityIdentifier{ - Mspid: idemix.Name, + Mspid: deserializer.Name, Id: bytes.NewBuffer(raw).String(), } @@ -76,12 +105,12 @@ func (id *Identity) GetIdentifier() *msp.IdentityIdentifier { } func (id *Identity) GetMSPIdentifier() string { - return id.Idemix.Name + return id.Deserializer.Name } func (id *Identity) GetOrganizationalUnits() []*msp.OUIdentifier { // we use the (serialized) public key of this MSP as the CertifiersIdentifier - certifiersIdentifier, err := id.Idemix.IssuerPublicKey.Bytes() + certifiersIdentifier, err := id.Deserializer.IssuerPublicKey.Bytes() if err != nil { logger.Errorf("Failed to marshal ipk in GetOrganizationalUnits: %s", err) return nil @@ -92,20 +121,24 @@ func (id *Identity) GetOrganizationalUnits() []*msp.OUIdentifier { func (id *Identity) Validate() error { // logger.Debugf("Validating identity %+v", id) - if id.GetMSPIdentifier() != id.Idemix.Name { + if id.GetMSPIdentifier() != id.Deserializer.Name { return errors.Errorf("the supplied identity does not belong to this msp") } return id.verifyProof() } func (id *Identity) Verify(msg []byte, sig []byte) error { - _, err := id.Idemix.Csp.Verify( + opts, err := id.SchemaManager.NymSignerOpts(id.Schema) + if err != nil { + return err + } + opts.IssuerPK = id.Deserializer.IssuerPublicKey + + _, err = id.Deserializer.Csp.Verify( id.NymPublicKey, sig, msg, - &bccsp.IdemixNymSignerOpts{ - IssuerPK: id.Idemix.IssuerPublicKey, - }, + opts, ) return err } @@ -115,7 +148,7 @@ func (id *Identity) SatisfiesPrincipal(principal *m.MSPPrincipal) error { } func (id *Identity) Serialize() ([]byte, error) { - serialized := &m.SerializedIdemixIdentity{} + serialized := &im.SerializedIdemixIdentity{} raw, err := id.NymPublicKey.Bytes() if err != nil { @@ -156,31 +189,27 @@ func (id *Identity) Serialize() ([]byte, error) { func (id *Identity) verifyProof() error { // Verify signature var metadata *bccsp.IdemixSignerMetadata - if len(id.Idemix.NymEID) != 0 { + if len(id.Deserializer.NymEID) != 0 { metadata = &bccsp.IdemixSignerMetadata{ - EidNym: id.Idemix.NymEID, - RhNym: id.Idemix.RhNym, + EidNym: id.Deserializer.NymEID, + RhNym: id.Deserializer.RhNym, } } - valid, err := id.Idemix.Csp.Verify( - id.Idemix.IssuerPublicKey, + opts, err := id.SchemaManager.SignerOpts(id.Schema, id.OU, id.Role) + if err != nil { + return errors.Wrapf(err, "could obtain signer opts for schema '%s'", id.Schema) + } + opts.Epoch = id.Deserializer.Epoch + opts.VerificationType = id.VerificationType + opts.Metadata = metadata + opts.RevocationPublicKey = id.Deserializer.RevocationPK + + valid, err := id.Deserializer.Csp.Verify( + id.Deserializer.IssuerPublicKey, id.AssociationProof, nil, - &bccsp.IdemixSignerOpts{ - RevocationPublicKey: id.Idemix.RevocationPK, - Attributes: []bccsp.IdemixAttribute{ - {Type: bccsp.IdemixBytesAttribute, Value: []byte(id.OU.OrganizationalUnitIdentifier)}, - {Type: bccsp.IdemixIntAttribute, Value: GetIdemixRoleFromMSPRole(id.Role)}, - {Type: bccsp.IdemixHiddenAttribute}, - {Type: bccsp.IdemixHiddenAttribute}, - }, - RhIndex: RHIndex, - EidIndex: EIDIndex, - Epoch: id.Idemix.Epoch, - VerificationType: id.VerificationType, - Metadata: metadata, - }, + opts, ) if err == nil && !valid { return errors.Errorf("unexpected condition, an error should be returned for an invalid signature") @@ -199,14 +228,17 @@ type SigningIdentity struct { func (id *SigningIdentity) Sign(msg []byte) ([]byte, error) { // logger.Debugf("Idemix identity %s is signing", id.GetIdentifier()) + opts, err := id.SchemaManager.NymSignerOpts(id.Schema) + if err != nil { + return nil, err + } + opts.Nym = id.NymKey + opts.IssuerPK = id.Deserializer.IssuerPublicKey - sig, err := id.Idemix.Csp.Sign( + sig, err := id.Deserializer.Csp.Sign( id.UserKey, msg, - &bccsp.IdemixNymSignerOpts{ - Nym: id.NymKey, - IssuerPK: id.Idemix.IssuerPublicKey, - }, + opts, ) if err != nil { return nil, err @@ -215,19 +247,25 @@ func (id *SigningIdentity) Sign(msg []byte) ([]byte, error) { } type NymSignatureVerifier struct { - CSP bccsp.BCCSP - IPK bccsp.Key - NymPK bccsp.Key + CSP bccsp.BCCSP + IPK bccsp.Key + NymPK bccsp.Key + SchemaManager SchemaManager + Schema string } func (v *NymSignatureVerifier) Verify(message, sigma []byte) error { - _, err := v.CSP.Verify( + opts, err := v.SchemaManager.NymSignerOpts(v.Schema) + if err != nil { + return err + } + opts.IssuerPK = v.IPK + + _, err = v.CSP.Verify( v.NymPK, sigma, message, - &bccsp.IdemixNymSignerOpts{ - IssuerPK: v.IPK, - }, + opts, ) return err } diff --git a/token/services/identity/msp/idemix/schema/schema.go b/token/services/identity/msp/idemix/schema/schema.go new file mode 100644 index 0000000000..bbf28cdcc2 --- /dev/null +++ b/token/services/identity/msp/idemix/schema/schema.go @@ -0,0 +1,185 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package schema + +import ( + "fmt" + + msp "github.com/IBM/idemix" + bccsp "github.com/IBM/idemix/bccsp/types" + msp2 "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity/msp/idemix/msp" + m "github.com/hyperledger/fabric-protos-go/msp" +) + +const ( + eidIdx = 2 + rhIdx = 3 + skIdx = 0 +) + +// attributeNames are the attribute names for the `w3c` schema +var attributeNames = []string{ + "_:c14n0 ", + "_:c14n0 ", +} + +// DefaultManager implements the default schema for fabric: +// - 4 attributes (OU, Role, EID, RH) +// - all in bytes format except for Role +// - fixed positions +// - no other attributes +// - a "hidden" usk attribute at position 0 +type DefaultManager struct { +} + +func (*DefaultManager) NymSignerOpts(schema string) (*bccsp.IdemixNymSignerOpts, error) { + switch schema { + case "": + return &bccsp.IdemixNymSignerOpts{}, nil + case "w3c-v0.0.1": + return &bccsp.IdemixNymSignerOpts{ + SKIndex: 24, + }, nil + } + + return nil, fmt.Errorf("unsupported schema '%s' for NymSignerOpts", schema) +} + +func (*DefaultManager) PublicKeyImportOpts(schema string) (*bccsp.IdemixIssuerPublicKeyImportOpts, error) { + switch schema { + case "": + return &bccsp.IdemixIssuerPublicKeyImportOpts{ + Temporary: true, + AttributeNames: []string{ + msp.AttributeNameOU, + msp.AttributeNameRole, + msp.AttributeNameEnrollmentId, + msp.AttributeNameRevocationHandle, + }, + }, nil + case "w3c-v0.0.1": + return &bccsp.IdemixIssuerPublicKeyImportOpts{ + Temporary: true, + AttributeNames: append([]string{""}, attributeNames...), + }, nil + } + + return nil, fmt.Errorf("unsupported schema '%s' for PublicKeyImportOpts", schema) +} + +func (*DefaultManager) SignerOpts(schema string, ou *m.OrganizationUnit, role *m.MSPRole) (*bccsp.IdemixSignerOpts, error) { + switch schema { + case "": + return &bccsp.IdemixSignerOpts{ + Attributes: []bccsp.IdemixAttribute{ + {Type: bccsp.IdemixBytesAttribute, Value: []byte(ou.OrganizationalUnitIdentifier)}, + {Type: bccsp.IdemixIntAttribute, Value: msp2.GetIdemixRoleFromMSPRole(role)}, + {Type: bccsp.IdemixHiddenAttribute}, + {Type: bccsp.IdemixHiddenAttribute}, + }, + RhIndex: rhIdx, + EidIndex: eidIdx, + }, nil + case "w3c-v0.0.1": + role_str := fmt.Sprintf( + "_:c14n0 \u003ccbdccard:3_role\u003e \"%d\"^^\u003chttp://www.w3.org/2001/XMLSchema#integer\u003e .", + msp2.GetIdemixRoleFromMSPRole(role), + ) + + idemixAttrs := []bccsp.IdemixAttribute{} + for i := range attributeNames { + if i == 25 { + idemixAttrs = append(idemixAttrs, bccsp.IdemixAttribute{ + Type: bccsp.IdemixBytesAttribute, + Value: []byte(role_str), + }) + } else if i == 24 { + idemixAttrs = append(idemixAttrs, bccsp.IdemixAttribute{ + Type: bccsp.IdemixBytesAttribute, + Value: []byte(ou.OrganizationalUnitIdentifier), + }) + } else { + idemixAttrs = append(idemixAttrs, bccsp.IdemixAttribute{ + Type: bccsp.IdemixHiddenAttribute, + }) + } + } + + return &bccsp.IdemixSignerOpts{ + Attributes: idemixAttrs, + RhIndex: 27, + EidIndex: 26, + SKIndex: 24, + VerificationType: bccsp.ExpectEidNymRhNym, + }, nil + } + + return nil, fmt.Errorf("unsupported schema '%s' for NymSignerOpts", schema) +} + +func (*DefaultManager) RhNymAuditOpts(schema string, attrs [][]byte) (*bccsp.RhNymAuditOpts, error) { + switch schema { + case "": + return &bccsp.RhNymAuditOpts{ + RhIndex: rhIdx, + SKIndex: skIdx, + RevocationHandle: string(attrs[rhIdx]), + }, nil + case "w3c-v0.0.1": + return &bccsp.RhNymAuditOpts{ + RhIndex: 27, + SKIndex: 24, + RevocationHandle: string(attrs[27]), + }, nil + } + + return nil, fmt.Errorf("unsupported schema '%s' for NymSignerOpts", schema) +} + +func (*DefaultManager) EidNymAuditOpts(schema string, attrs [][]byte) (*bccsp.EidNymAuditOpts, error) { + switch schema { + case "": + return &bccsp.EidNymAuditOpts{ + EidIndex: eidIdx, + SKIndex: skIdx, + EnrollmentID: string(attrs[eidIdx]), + }, nil + case "w3c-v0.0.1": + return &bccsp.EidNymAuditOpts{ + EidIndex: 26, + SKIndex: 24, + EnrollmentID: string(attrs[26]), + }, nil + } + + return nil, fmt.Errorf("unsupported schema '%s' for NymSignerOpts", schema) +}