Skip to content

Commit

Permalink
[FAB-8726] Revoke one's own certificate
Browse files Browse the repository at this point in the history
Removing the restriction of having the hf.Revoker
attribute to revoke one's own identity or certificate

Change-Id: Iccb1b0b7611324bc5a7022f35b2d277bd0bd4c87
Signed-off-by: Saad Karim <skarim@us.ibm.com>
  • Loading branch information
Saad Karim committed Jul 10, 2018
1 parent db9a6a6 commit be1b7dc
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 30 deletions.
42 changes: 19 additions & 23 deletions lib/client_test.go
Expand Up @@ -770,30 +770,26 @@ func testRevocation(c *Client, t *testing.T, user string, withPriv, ecertOnly bo
} else {
revResp, err = id.RevokeSelf()
}
if withPriv {
// Assert that there is no error revoking user/Ecert
ar := assert.NoError(t, err, "Revocation failed for user %s", user)
if !ar {
return
}
// Assert that there is no error revoking user/Ecert
ar := assert.NoError(t, err, "Revocation failed for user %s", user)
if !ar {
return
}

// Assert that the cert serial in the revocation response is same as that of user certificate
cert := id.GetECert().GetX509Cert()
if cert == nil {
t.Fatalf("Failed to get certificate for the enrolled user %s: %s", user, err)
}
assert.Equal(t, 1, len(revResp.RevokedCerts), "Expected 1 certificate to be revoked")
assert.Equal(t, util.GetSerialAsHex(cert.SerialNumber), revResp.RevokedCerts[0].Serial,
"Cert serial in revocation response does match serial number of the cert that was revoked")

eresp, err = id.Reenroll(&api.ReenrollmentRequest{})
assert.Errorf(t, err, "Enrollment of a revoked user %s cert succeeded but should have failed", user)
if !ecertOnly {
eresp, err = c.Enroll(req)
assert.Errorf(t, err, "Enrollment of a revoked user %s succeeded but should have failed", user)
}
} else {
assert.Errorf(t, err, "Revocation for user %s should have failed", user)
// Assert that the cert serial in the revocation response is same as that of user certificate
cert := id.GetECert().GetX509Cert()
if cert == nil {
t.Fatalf("Failed to get certificate for the enrolled user %s: %s", user, err)
}
assert.Equal(t, 1, len(revResp.RevokedCerts), "Expected 1 certificate to be revoked")
assert.Equal(t, util.GetSerialAsHex(cert.SerialNumber), revResp.RevokedCerts[0].Serial,
"Cert serial in revocation response does match serial number of the cert that was revoked")

eresp, err = id.Reenroll(&api.ReenrollmentRequest{})
assert.Errorf(t, err, "Enrollment of a revoked user %s cert succeeded but should have failed", user)
if !ecertOnly {
eresp, err = c.Enroll(req)
assert.Errorf(t, err, "Enrollment of a revoked user %s succeeded but should have failed", user)
}
}

Expand Down
30 changes: 23 additions & 7 deletions lib/serverrevoke.go
Expand Up @@ -48,7 +48,7 @@ func revokeHandler(ctx *serverRequestContextImpl) (interface{}, error) {
return nil, err
}
// Authentication
id, err := ctx.TokenAuthentication()
caller, err := ctx.TokenAuthentication()
if err != nil {
return nil, err
}
Expand All @@ -57,12 +57,6 @@ func revokeHandler(ctx *serverRequestContextImpl) (interface{}, error) {
if err != nil {
return nil, err
}
// Authorization
// Make sure that the caller has the "hf.Revoker" attribute.
err = ca.attributeIsTrue(id, "hf.Revoker")
if err != nil {
return nil, newAuthorizationErr(ErrNotRevoker, "Caller does not have authority to revoke")
}

req.AKI = parseInput(req.AKI)
req.Serial = parseInput(req.Serial)
Expand All @@ -82,6 +76,12 @@ func revokeHandler(ctx *serverRequestContextImpl) (interface{}, error) {
req.Serial, req.AKI, err)
}

// Authorization
err = checkAuth(caller, certificate.ID, ca)
if err != nil {
return nil, err
}

if certificate.Status == string(Revoked) {
return nil, newHTTPErr(404, ErrCertAlreadyRevoked, "Certificate with serial %s and AKI %s was already revoked",
req.Serial, req.AKI)
Expand Down Expand Up @@ -110,6 +110,11 @@ func revokeHandler(ctx *serverRequestContextImpl) (interface{}, error) {
}
result.RevokedCerts = append(result.RevokedCerts, api.RevokedCert{Serial: req.Serial, AKI: req.AKI})
} else if req.Name != "" {
// Authorization
err = checkAuth(caller, req.Name, ca)
if err != nil {
return nil, err
}

user, err := registry.GetUser(req.Name, nil)
if err != nil {
Expand Down Expand Up @@ -171,3 +176,14 @@ func revokeHandler(ctx *serverRequestContextImpl) (interface{}, error) {
func parseInput(input string) string {
return strings.Replace(strings.TrimLeft(strings.ToLower(input), "0"), ":", "", -1)
}

func checkAuth(callerName, revokeUserName string, ca *CA) error {
if callerName != revokeUserName {
// Make sure that the caller has the "hf.Revoker" attribute.
err := ca.attributeIsTrue(callerName, "hf.Revoker")
if err != nil {
return newAuthorizationErr(ErrNotRevoker, "Caller does not have authority to revoke")
}
}
return nil
}
53 changes: 53 additions & 0 deletions lib/serverrevoke_test.go
Expand Up @@ -95,3 +95,56 @@ func TestUpdatingRevocationHandleQuery(t *testing.T) {
assert.NoError(t, err, "Failed to enroll 'admin'")
}
}

func TestRevokeSelf(t *testing.T) {
var err error
srv := TestGetRootServer(t)
err = srv.Start()
util.FatalError(t, err, "Failed to start server")
defer srv.Stop()
defer os.RemoveAll("rootDir")
defer os.RemoveAll("../testdata/msp")

client := getTestClient(7075)
resp, err := client.Enroll(&api.EnrollmentRequest{
Name: "admin",
Secret: "adminpw",
})
util.FatalError(t, err, "Failed to enroll user 'admin'")

admin := resp.Identity
name := "testuser"
password := "password"
_, err = admin.Register(&api.RegistrationRequest{
Name: name,
Secret: password,
})
util.FatalError(t, err, "Failed to register user 'testuser'")

resp, err = client.Enroll(&api.EnrollmentRequest{
Name: name,
Secret: password,
})
util.FatalError(t, err, "Failed to enroll user 'testuser'")
testuser := resp.Identity

db := srv.CA.CertDBAccessor()
cert, err := db.GetCertificatesByID("testuser")
util.FatalError(t, err, "Failed to get certificvate for 'testuser'")

_, err = testuser.Revoke(&api.RevocationRequest{
Serial: cert[0].Serial,
AKI: cert[0].AKI,
})
assert.NoError(t, err, "Failed to revoke one's own certificate using serial and AKI")

resp, err = client.Enroll(&api.EnrollmentRequest{
Name: name,
Secret: password,
})
util.FatalError(t, err, "Failed to enroll user 'testuser'")
testuser = resp.Identity

_, err = testuser.RevokeSelf()
assert.NoError(t, err, "Failed to revoke one self")
}

0 comments on commit be1b7dc

Please sign in to comment.