github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/serverrevoke.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package lib 18 19 import ( 20 "encoding/hex" 21 "strings" 22 23 "github.com/cloudflare/cfssl/log" 24 25 "github.com/hyperledger/fabric-ca/api" 26 "github.com/hyperledger/fabric-ca/util" 27 ) 28 29 type revocationResponseNet struct { 30 RevokedCerts []api.RevokedCert 31 CRL string 32 } 33 34 // CertificateStatus represents status of an enrollment certificate 35 type CertificateStatus string 36 37 const ( 38 // Revoked is the status of a revoked certificate 39 Revoked CertificateStatus = "revoked" 40 // Good is the status of a active certificate 41 Good = "good" 42 ) 43 44 func newRevokeEndpoint(s *Server) *serverEndpoint { 45 return &serverEndpoint{ 46 Methods: []string{"POST"}, 47 Handler: revokeHandler, 48 Server: s, 49 } 50 } 51 52 // Handle an revoke request 53 func revokeHandler(ctx *serverRequestContext) (interface{}, error) { 54 // Parse revoke request body 55 var req api.RevocationRequestNet 56 err := ctx.ReadBody(&req) 57 if err != nil { 58 return nil, err 59 } 60 // Authentication 61 id, err := ctx.TokenAuthentication() 62 if err != nil { 63 return nil, err 64 } 65 // Get targeted CA 66 ca, err := ctx.GetCA() 67 if err != nil { 68 return nil, err 69 } 70 // Authorization 71 // Make sure that the caller has the "hf.Revoker" attribute. 72 err = ca.attributeIsTrue(id, "hf.Revoker") 73 if err != nil { 74 return nil, newHTTPErr(401, ErrNotRevoker, "Caller does not have authority to revoke") 75 } 76 77 req.AKI = strings.TrimLeft(strings.ToLower(req.AKI), "0") 78 req.Serial = strings.TrimLeft(strings.ToLower(req.Serial), "0") 79 80 certDBAccessor := ca.certDBAccessor 81 registry := ca.registry 82 reason := util.RevocationReasonCodes[req.Reason] 83 84 result := &revocationResponseNet{} 85 if req.Serial != "" && req.AKI != "" { 86 calleraki := strings.ToLower(strings.TrimLeft(hex.EncodeToString(ctx.enrollmentCert.AuthorityKeyId), "0")) 87 callerserial := strings.ToLower(strings.TrimLeft(util.GetSerialAsHex(ctx.enrollmentCert.SerialNumber), "0")) 88 89 certificate, err := certDBAccessor.GetCertificateWithID(req.Serial, req.AKI) 90 if err != nil { 91 return nil, newHTTPErr(404, ErrRevCertNotFound, "Certificate with serial %s and AKI %s was not found: %s", 92 req.Serial, req.AKI, err) 93 } 94 95 if certificate.Status == string(Revoked) { 96 return nil, newHTTPErr(404, ErrCertAlreadyRevoked, "Certificate with serial %s and AKI %s was already revoked", 97 req.Serial, req.AKI) 98 } 99 100 if req.Name != "" && req.Name != certificate.ID { 101 return nil, newHTTPErr(400, ErrCertWrongOwner, "Certificate with serial %s and AKI %s is not owned by %s", 102 req.Serial, req.AKI, req.Name) 103 } 104 105 userInfo, err := registry.GetUser(certificate.ID, nil) 106 if err != nil { 107 return nil, newHTTPErr(404, ErrRevokeIDNotFound, "Identity %s was not found: %s", certificate.ID, err) 108 } 109 110 if !((req.AKI == calleraki) && (req.Serial == callerserial)) { 111 err = ctx.CanManageUser(userInfo) 112 if err != nil { 113 return nil, err 114 } 115 } 116 117 err = certDBAccessor.RevokeCertificate(req.Serial, req.AKI, reason) 118 if err != nil { 119 return nil, newHTTPErr(500, ErrRevokeFailure, "Revoke of certificate <%s,%s> failed: %s", req.Serial, req.AKI, err) 120 } 121 result.RevokedCerts = append(result.RevokedCerts, api.RevokedCert{Serial: req.Serial, AKI: req.AKI}) 122 } else if req.Name != "" { 123 124 user, err := registry.GetUser(req.Name, nil) 125 if err != nil { 126 return nil, newHTTPErr(404, ErrRevokeIDNotFound, "Identity %s was not found: %s", req.Name, err) 127 } 128 129 // Set user state to -1 for revoked user 130 if user != nil { 131 caller, err := ctx.GetCaller() 132 if err != nil { 133 return nil, err 134 } 135 136 if caller.GetName() != user.GetName() { 137 err = ctx.CanManageUser(user) 138 if err != nil { 139 return nil, err 140 } 141 } 142 143 err = user.Revoke() 144 if err != nil { 145 return nil, newHTTPErr(500, ErrRevokeUpdateUser, "Failed to revoke user: %s", err) 146 } 147 } 148 149 var recs []CertRecord 150 recs, err = certDBAccessor.RevokeCertificatesByID(req.Name, reason) 151 if err != nil { 152 return nil, newHTTPErr(500, ErrNoCertsRevoked, "Failed to revoke certificates for '%s': %s", 153 req.Name, err) 154 } 155 156 if len(recs) == 0 { 157 log.Warningf("No certificates were revoked for '%s' but the ID was disabled", req.Name) 158 } else { 159 log.Debugf("Revoked the following certificates owned by '%s': %+v", req.Name, recs) 160 for _, certRec := range recs { 161 result.RevokedCerts = append(result.RevokedCerts, api.RevokedCert{AKI: certRec.AKI, Serial: certRec.Serial}) 162 } 163 } 164 } else { 165 return nil, newHTTPErr(400, ErrMissingRevokeArgs, "Either Name or Serial and AKI are required for a revoke request") 166 } 167 168 log.Debugf("Revoke was successful: %+v", req) 169 170 if req.GenCRL && len(result.RevokedCerts) > 0 { 171 log.Debugf("Generating CRL") 172 crl, err := genCRL(ca, api.GenCRLRequest{CAName: ca.Config.CA.Name}) 173 if err != nil { 174 return nil, err 175 } 176 result.CRL = util.B64Encode(crl) 177 } 178 return result, nil 179 }