Skip to content

Commit

Permalink
[FAB-10386] Revoked ID using Idemix should fail
Browse files Browse the repository at this point in the history
When a client/identity makes a request using an
Idemix credential, a check has been added to see if
the identity has not been revoked before completing
the request.

Change-Id: I393b0413934b163534574dc95e82d3fd0f45f4b5
Signed-off-by: Saad Karim <[email protected]>
  • Loading branch information
Saad Karim committed Jul 9, 2018
1 parent 6b86289 commit 901d150
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 17 deletions.
12 changes: 10 additions & 2 deletions lib/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ type Client struct {
csp bccsp.BCCSP
// HTTP client associated with this Fabric CA client
httpClient *http.Client
// Public key of Idemix issuer
issuerPublicKey *idemix.IssuerPublicKey
}

// GetCAInfoResponse is the response from the GetCAInfo call
Expand Down Expand Up @@ -545,7 +547,8 @@ func (c *Client) getIssuerPubKey(ipkBytes []byte) (*idemix.IssuerPublicKey, erro
if err != nil {
return nil, err
}
return pubKey, nil
c.issuerPublicKey = pubKey
return c.issuerPublicKey, nil
}

// LoadMyIdentity loads the client's identity from disk
Expand Down Expand Up @@ -650,7 +653,10 @@ func (c *Client) GetCSP() bccsp.BCCSP {

// GetIssuerPubKey returns issuer public key associated with this client
func (c *Client) GetIssuerPubKey() (*idemix.IssuerPublicKey, error) {
return c.getIssuerPubKey(nil)
if c.issuerPublicKey == nil {
return c.getIssuerPubKey(nil)
}
return c.issuerPublicKey, nil
}

// newGet create a new GET request
Expand Down Expand Up @@ -852,6 +858,8 @@ func (c *Client) checkX509Enrollment() error {
// Idemix credential does not exist and if they exist and credential verification
// fails. Returns nil if the credential verification suucceeds
func (c *Client) checkIdemixEnrollment() error {
log.Debugf("CheckIdemixEnrollment - ipkFile: %s, idemixCredFrile: %s", c.ipkFile, c.idemixCredFile)

idemixIssuerPubKeyExists := util.FileExists(c.ipkFile)
idemixCredExists := util.FileExists(c.idemixCredFile)
if idemixIssuerPubKeyExists && idemixCredExists {
Expand Down
8 changes: 8 additions & 0 deletions lib/dbaccessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,14 @@ func (u *DBUser) Revoke() error {
return nil
}

// IsRevoked returns back true if user is revoked
func (u *DBUser) IsRevoked() bool {
if u.State == -1 {
return true
}
return false
}

// ModifyAttributes adds a new attribute, modifies existing attribute, or delete attribute
func (u *DBUser) ModifyAttributes(newAttrs []api.Attribute) error {
log.Debugf("Modify Attributes: %+v", newAttrs)
Expand Down
5 changes: 5 additions & 0 deletions lib/ldap/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,11 @@ func (u *user) Revoke() error {
return errNotSupported
}

// IsRevoked is not supported for LDAP
func (u *user) IsRevoked() bool {
return false
}

// ModifyAttributes adds a new attribute or modifies existing attribute
func (u *user) ModifyAttributes(attrs []api.Attribute) error {
return errNotSupported
Expand Down
22 changes: 15 additions & 7 deletions lib/server/idemix/mocks/User.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions lib/servererror.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ const (
ErrParsingIntEnvVar = 68
// CA certificate file is not found warning message
ErrCACertFileNotFound = 69
// Error occurs when invoking a request revoked enrollment ID
ErrRevokedID = 70
)

// Construct a new HTTP error.
Expand Down
24 changes: 23 additions & 1 deletion lib/serverrequestcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,34 @@ func (ctx *serverRequestContextImpl) TokenAuthentication() (string, error) {
return "", err
}
if idemix.IsToken(authHdr) {
return ctx.ca.issuer.VerifyToken(authHdr, body)
return ctx.verifyIdemixToken(authHdr, body)
}
return ctx.verifyX509Token(ca, authHdr, body)
}

func (ctx *serverRequestContextImpl) verifyIdemixToken(authHdr string, body []byte) (string, error) {
log.Debug("Caller is using Idemix credential")
var err error

ctx.enrollmentID, err = ctx.ca.issuer.VerifyToken(authHdr, body)
if err != nil {
return "", err
}

caller, err := ctx.GetCaller()
if err != nil {
return "", err
}

if caller.IsRevoked() {
return "", newAuthErr(ErrRevokedID, "Enrollment ID is revoked, unable to process request")
}

return ctx.enrollmentID, nil
}

func (ctx *serverRequestContextImpl) verifyX509Token(ca *CA, authHdr string, body []byte) (string, error) {
log.Debug("Caller is using a x509 certificate")
// Verify the token; the signature is over the header and body
cert, err2 := util.VerifyToken(ca.csp, authHdr, body)
if err2 != nil {
Expand Down
51 changes: 51 additions & 0 deletions lib/serverrevoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ SPDX-License-Identifier: Apache-2.0
package lib

import (
"os"
"testing"

"github.com/hyperledger/fabric-ca/api"
"github.com/hyperledger/fabric-ca/util"
"github.com/stretchr/testify/assert"
)

Expand All @@ -21,3 +24,51 @@ func TestParseInput(t *testing.T) {
assert.NotEqual(t, string(parsedInput[0]), "0", "failed to correctly remove leading zeros from input")
assert.NotContains(t, parsedInput, "AA", "failed to correctly lowercase capital letters")
}

func TestIdemixCredRevokedUser(t *testing.T) {
srv := TestGetRootServer(t)
err := srv.Start()
util.FatalError(t, err, "Failed to start server")
defer srv.Stop()
defer os.RemoveAll(rootDir)
defer os.RemoveAll(rootClientDir)

c := TestGetRootClient()
req := &api.EnrollmentRequest{
Name: "admin",
Secret: "adminpw",
}

enrollResp, err := c.Enroll(req)
util.FatalError(t, err, "Failed to enroll 'admin'")
admin := enrollResp.Identity

_, err = admin.Register(&api.RegistrationRequest{
Name: "user1",
Secret: "user1pw",
})
util.FatalError(t, err, "Failed to register 'user1' by 'admin' user")

// Enroll a user to get back Idemix credential
req.Name = "user1"
req.Secret = "user1pw"
req.Type = "idemix"

enrollIdmixResp, err := c.Enroll(req)
util.FatalError(t, err, "Failed to enroll 'user1'")
idemixUser := enrollIdmixResp.Identity

// Revoke the user that only posses an Idemix credential
_, err = admin.Revoke(&api.RevocationRequest{
Name: "user1",
})
util.FatalError(t, err, "Failed to revoke 'user1' by 'admin' user")

// Revoked user should not be able to make requests to the Fabric CA server
_, err = idemixUser.Register(&api.RegistrationRequest{
Name: "user2",
Secret: "user2pw",
})
t.Log("Error: ", err)
util.ErrorContains(t, err, "20", "Revoked user with only Idemix credential, should not be able to make requests to the server")
}
2 changes: 2 additions & 0 deletions lib/spi/userregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ type User interface {
LoginComplete() error
// Revoke will revoke the user, setting the state of the user to be -1
Revoke() error
// IsRevoked returns back true if user is revoked
IsRevoked() bool
// GetLevel returns the level of the user, level is used to verify if the user needs migration
GetLevel() int
// SetLevel sets the level of the user
Expand Down
20 changes: 13 additions & 7 deletions lib/test-util.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
const (
rootPort = 7075
rootDir = "rootDir"
rootClientDir = "rootClientDir"
intermediatePort = 7076
intermediateDir = "intDir"
testdataDir = "../testdata"
Expand Down Expand Up @@ -226,10 +227,15 @@ func GenerateECDSATestCert() error {
// }
// }

// // GetTestClient returns a Fabric CA client
// func GetTestClient(port int, home string) *Client {
// return &Client{
// Config: &ClientConfig{URL: fmt.Sprintf("http://localhost:%d", port)},
// HomeDir: home,
// }
// }
// TestGetRootClient returns a Fabric CA client that is meant for a root Fabric CA server
func TestGetRootClient() *Client {
return TestGetClient(rootPort, rootClientDir)
}

// TestGetClient returns a Fabric CA client
func TestGetClient(port int, home string) *Client {
return &Client{
Config: &ClientConfig{URL: fmt.Sprintf("http://localhost:%d", port)},
HomeDir: home,
}
}

0 comments on commit 901d150

Please sign in to comment.