github.com/paul-lee-attorney/fabric-ca-1.4.7-gm@v0.0.0-20201120102036-c7ad827cf9ac/lib/servergencrl.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lib 8 9 import ( 10 "crypto/x509" 11 "crypto/x509/pkix" 12 "encoding/pem" 13 "fmt" 14 "io/ioutil" 15 "math/big" 16 "time" 17 18 "github.com/cloudflare/cfssl/crl" 19 "github.com/cloudflare/cfssl/log" 20 "github.com/hyperledger/fabric-ca/api" 21 "github.com/hyperledger/fabric-ca/util" 22 "github.com/paul-lee-attorney/fabric-ca-1.4.7-gm/lib/caerrors" 23 "github.com/pkg/errors" 24 ) 25 26 const ( 27 crlPemType = "X509 CRL" 28 ) 29 30 // The response to the POST /gencrl request 31 type genCRLResponseNet struct { 32 // Base64 encoding of PEM-encoded CRL 33 CRL string 34 } 35 36 func newGenCRLEndpoint(s *Server) *serverEndpoint { 37 return &serverEndpoint{ 38 Path: "gencrl", 39 Methods: []string{"POST"}, 40 Handler: genCRLHandler, 41 Server: s, 42 } 43 } 44 45 // Handle an generate CRL request 46 func genCRLHandler(ctx *serverRequestContextImpl) (interface{}, error) { 47 var req api.GenCRLRequest 48 err := ctx.ReadBody(&req) 49 if err != nil { 50 return nil, err 51 } 52 53 // Authenticate the invoker 54 id, err := ctx.TokenAuthentication() 55 if err != nil { 56 return nil, err 57 } 58 log.Debugf("Received gencrl request from %s: %+v", id, util.StructToString(&req)) 59 60 // Get targeted CA 61 ca, err := ctx.GetCA() 62 if err != nil { 63 return nil, err 64 } 65 66 // Make sure that the user has the "hf.GenCRL" attribute in order to be authorized 67 // to generate CRL. This attribute comes from the user registry, which 68 // is either in the DB if LDAP is not configured, or comes from LDAP if LDAP is 69 // configured. 70 err = ca.attributeIsTrue(id, "hf.GenCRL") 71 if err != nil { 72 return nil, caerrors.NewAuthorizationErr(caerrors.ErrNoGenCRLAuth, "The identity '%s' does not have authority to generate a CRL", id) 73 } 74 75 crl, err := genCRL(ca, req) 76 if err != nil { 77 return nil, err 78 } 79 log.Debugf("Successfully generated CRL") 80 81 resp := &genCRLResponseNet{CRL: util.B64Encode(crl)} 82 return resp, nil 83 } 84 85 // GenCRL will generate CRL 86 func genCRL(ca *CA, req api.GenCRLRequest) ([]byte, error) { 87 var err error 88 if !req.RevokedBefore.IsZero() && req.RevokedAfter.After(req.RevokedBefore) { 89 return nil, caerrors.NewHTTPErr(400, caerrors.ErrInvalidRevokedAfter, 90 "Invalid 'revokedafter' value. It must not be a timestamp greater than 'revokedbefore'") 91 } 92 93 if !req.ExpireBefore.IsZero() && req.ExpireAfter.After(req.ExpireBefore) { 94 return nil, caerrors.NewHTTPErr(400, caerrors.ErrInvalidExpiredAfter, 95 "Invalid 'expireafter' value. It must not be a timestamp greater than 'expirebefore'") 96 } 97 98 // Get revoked certificates from the database 99 certs, err := ca.certDBAccessor.GetRevokedCertificates(req.ExpireAfter, req.ExpireBefore, req.RevokedAfter, req.RevokedBefore) 100 if err != nil { 101 log.Errorf("Failed to get revoked certificates from the database: %s", err) 102 return nil, caerrors.NewHTTPErr(500, caerrors.ErrRevokedCertsFromDB, "Failed to get revoked certificates") 103 } 104 105 caCert, err := getCACert(ca) 106 if err != nil { 107 log.Errorf("Failed to get certficate for CA '%s': %s", ca.HomeDir, err) 108 return nil, caerrors.NewHTTPErr(500, caerrors.ErrGetCACert, "Failed to get certficate for CA '%s'", ca.HomeDir) 109 } 110 111 if !canSignCRL(caCert) { 112 return nil, caerrors.NewHTTPErr(500, caerrors.ErrNoCrlSignAuth, 113 "The CA does not have authority to generate a CRL. Its certificate does not have 'crl sign' key usage") 114 } 115 116 // Get the signer for the CA 117 _, signer, err := util.GetSignerFromCert(caCert, ca.csp) 118 if err != nil { 119 log.Errorf("Failed to get signer for CA '%s': %s", ca.HomeDir, err) 120 return nil, caerrors.NewHTTPErr(500, caerrors.ErrGetCASigner, "Failed to get signer for CA '%s'", ca.HomeDir) 121 } 122 123 expiry := time.Now().UTC().Add(ca.Config.CRL.Expiry) 124 var revokedCerts []pkix.RevokedCertificate 125 126 // For every record, create a new revokedCertificate and add it to slice 127 for _, certRecord := range certs { 128 serialInt := new(big.Int) 129 serialInt.SetString(certRecord.Serial, 16) 130 revokedCert := pkix.RevokedCertificate{ 131 SerialNumber: serialInt, 132 RevocationTime: certRecord.RevokedAt, 133 } 134 revokedCerts = append(revokedCerts, revokedCert) 135 } 136 137 crl, err := crl.CreateGenericCRL(revokedCerts, signer, caCert, expiry) 138 if err != nil { 139 log.Errorf("Failed to generate CRL for CA '%s': %s", ca.HomeDir, err) 140 return nil, caerrors.NewHTTPErr(500, caerrors.ErrGenCRL, "Failed to generate CRL for CA '%s'", ca.HomeDir) 141 } 142 blk := &pem.Block{Bytes: crl, Type: crlPemType} 143 return pem.EncodeToMemory(blk), nil 144 } 145 146 func getCACert(ca *CA) (*x509.Certificate, error) { 147 // Get CA certificate 148 caCertBytes, err := ioutil.ReadFile(ca.Config.CA.Certfile) 149 if err != nil { 150 return nil, errors.WithMessage(err, fmt.Sprintf("Failed to read certificate for the CA '%s'", ca.HomeDir)) 151 } 152 caCert, err := BytesToX509Cert(caCertBytes) 153 if err != nil { 154 return nil, errors.WithMessage(err, fmt.Sprintf("Failed to get certificate for the CA '%s'", ca.HomeDir)) 155 } 156 return caCert, nil 157 }