Update vendored github.com/cloudflare/cfssl (#3078)

This commit is contained in:
Roland Bracewell Shoemaker 2017-09-13 12:23:38 -07:00 committed by Daniel McCarney
parent 94e4947c58
commit c03d96212b
9 changed files with 159 additions and 131 deletions

56
Godeps/Godeps.json generated
View File

@ -12,73 +12,73 @@
},
{
"ImportPath": "github.com/cloudflare/cfssl/auth",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/certdb",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/config",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs7",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/csr",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/errors",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/helpers",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/helpers/derhelpers",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/info",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/log",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/ocsp",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/ocsp/config",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/signer",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/cloudflare/cfssl/signer/local",
"Comment": "1.2.0-169-gc9a961e",
"Rev": "c9a961ed337dbde794abb97a2a302320a99869da"
"Comment": "1.2.0-195-gb92b544",
"Rev": "b92b544a91e70c91d9db888dfc9216197329df30"
},
{
"ImportPath": "github.com/davecgh/go-spew/spew",

View File

@ -69,11 +69,11 @@ type dbResponse struct {
}
// Response is called by the HTTP server to handle a new OCSP request.
func (src *DBSource) Response(req *ocsp.Request) ([]byte, bool) {
func (src *DBSource) Response(req *ocsp.Request) ([]byte, http.Header, error) {
// Check that this request is for the proper CA
if bytes.Compare(req.IssuerKeyHash, src.caKeyHash) != 0 {
src.log.Debug(fmt.Sprintf("Request intended for CA Cert ID: %s", hex.EncodeToString(req.IssuerKeyHash)))
return nil, false
return nil, nil, cfocsp.ErrNotFound
}
serialString := core.SerialToString(req.SerialNumber)
@ -94,14 +94,14 @@ func (src *DBSource) Response(req *ocsp.Request) ([]byte, bool) {
src.log.AuditErr(fmt.Sprintf("Failed to retrieve response from certificateStatus table: %s", err))
}
if err != nil {
return nil, false
return nil, nil, cfocsp.ErrNotFound
}
if response.OCSPLastUpdated.IsZero() {
src.log.Debug(fmt.Sprintf("OCSP Response not sent (ocspLastUpdated is zero) for CA=%s, Serial=%s", hex.EncodeToString(src.caKeyHash), serialString))
return nil, false
return nil, nil, cfocsp.ErrNotFound
}
return response.OCSPResponse, true
return response.OCSPResponse, nil, nil
}
func makeDBSource(dbMap dbSelector, issuerCert string, log blog.Logger) (*DBSource, error) {

View File

@ -133,8 +133,8 @@ func TestErrorLog(t *testing.T) {
ocspReq, err := ocsp.ParseRequest(req)
test.AssertNotError(t, err, "Failed to parse OCSP request")
_, found := src.Response(ocspReq)
test.Assert(t, !found, "Somehow found OCSP response")
_, _, err = src.Response(ocspReq)
test.AssertEquals(t, err, cfocsp.ErrNotFound)
test.AssertEquals(t, len(mockLog.GetAllMatching("Failed to retrieve response from certificateStatus table")), 1)
}

View File

@ -32,6 +32,7 @@ type Accessor interface {
GetCertificate(serial, aki string) ([]CertificateRecord, error)
GetUnexpiredCertificates() ([]CertificateRecord, error)
GetRevokedAndUnexpiredCertificates() ([]CertificateRecord, error)
GetRevokedAndUnexpiredCertificatesByLabel(label string) ([]CertificateRecord, error)
RevokeCertificate(serial, aki string, reasonCode int) error
InsertOCSP(rr OCSPRecord) error
GetOCSP(serial, aki string) ([]OCSPRecord, error)

View File

@ -18,7 +18,6 @@ import (
"fmt"
"io"
"io/ioutil"
"math/big"
"os"
"github.com/google/certificate-transparency-go"
@ -383,51 +382,6 @@ func GetKeyDERFromPEM(in []byte, password []byte) ([]byte, error) {
return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed)
}
// CheckSignature verifies a signature made by the key on a CSR, such
// as on the CSR itself.
func CheckSignature(csr *x509.CertificateRequest, algo x509.SignatureAlgorithm, signed, signature []byte) error {
var hashType crypto.Hash
switch algo {
case x509.SHA1WithRSA, x509.ECDSAWithSHA1:
hashType = crypto.SHA1
case x509.SHA256WithRSA, x509.ECDSAWithSHA256:
hashType = crypto.SHA256
case x509.SHA384WithRSA, x509.ECDSAWithSHA384:
hashType = crypto.SHA384
case x509.SHA512WithRSA, x509.ECDSAWithSHA512:
hashType = crypto.SHA512
default:
return x509.ErrUnsupportedAlgorithm
}
if !hashType.Available() {
return x509.ErrUnsupportedAlgorithm
}
h := hashType.New()
h.Write(signed)
digest := h.Sum(nil)
switch pub := csr.PublicKey.(type) {
case *rsa.PublicKey:
return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
case *ecdsa.PublicKey:
ecdsaSig := new(struct{ R, S *big.Int })
if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
return err
}
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
return errors.New("x509: ECDSA signature contained zero or negative values")
}
if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) {
return errors.New("x509: ECDSA verification failure")
}
return nil
}
return x509.ErrUnsupportedAlgorithm
}
// ParseCSR parses a PEM- or DER-encoded PKCS #10 certificate signing request.
func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) {
in = bytes.TrimSpace(in)
@ -446,7 +400,7 @@ func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error)
return nil, rest, err
}
err = CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature)
err = csr.CheckSignature()
if err != nil {
return nil, rest, err
}

View File

@ -58,6 +58,10 @@ type SignRequest struct {
// in the OCSP response. Valid values are crypto.SHA1, crypto.SHA256, crypto.SHA384,
// and crypto.SHA512. If zero, the default is crypto.SHA1.
IssuerHash crypto.Hash
// If provided ThisUpdate will override the default usage of time.Now().Truncate(time.Hour)
ThisUpdate *time.Time
// If provided NextUpdate will override the default usage of ThisUpdate.Add(signerInterval)
NextUpdate *time.Time
}
// Signer represents a general signer of OCSP responses. It is
@ -164,9 +168,18 @@ func (s StandardSigner) Sign(req SignRequest) ([]byte, error) {
return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch)
}
// Round thisUpdate times down to the nearest hour
thisUpdate := time.Now().Truncate(time.Hour)
nextUpdate := thisUpdate.Add(s.interval)
var thisUpdate, nextUpdate time.Time
if req.ThisUpdate != nil {
thisUpdate = *req.ThisUpdate
} else {
// Round thisUpdate times down to the nearest hour
thisUpdate = time.Now().Truncate(time.Hour)
}
if req.NextUpdate != nil {
nextUpdate = *req.NextUpdate
} else {
nextUpdate = thisUpdate.Add(s.interval)
}
status, ok := StatusCode[req.Status]
if !ok {

View File

@ -11,6 +11,7 @@ import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"net/http"
@ -30,14 +31,25 @@ var (
tryLaterErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x03}
sigRequredErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x05}
unauthorizedErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x06}
// ErrNotFound indicates the request OCSP response was not found. It is used to
// indicate that the responder should reply with unauthorizedErrorResponse.
ErrNotFound = errors.New("Request OCSP Response not found")
)
// Source represents the logical source of OCSP responses, i.e.,
// the logic that actually chooses a response based on a request. In
// order to create an actual responder, wrap one of these in a Responder
// object and pass it to http.Handle.
// object and pass it to http.Handle. By default the Responder will set
// the headers Cache-Control to "max-age=(response.NextUpdate-now), public, no-transform, must-revalidate",
// Last-Modified to response.ThisUpdate, Expires to response.NextUpdate,
// ETag to the SHA256 hash of the response, and Content-Type to
// application/ocsp-response. If you want to override these headers,
// or set extra headers, your source should return a http.Header
// with the headers you wish to set. If you don't want to set any
// extra headers you may return nil instead.
type Source interface {
Response(*ocsp.Request) ([]byte, bool)
Response(*ocsp.Request) ([]byte, http.Header, error)
}
// An InMemorySource is a map from serialNumber -> der(response)
@ -46,9 +58,12 @@ type InMemorySource map[string][]byte
// Response looks up an OCSP response to provide for a given request.
// InMemorySource looks up a response purely based on serial number,
// without regard to what issuer the request is asking for.
func (src InMemorySource) Response(request *ocsp.Request) (response []byte, present bool) {
response, present = src[request.SerialNumber.String()]
return
func (src InMemorySource) Response(request *ocsp.Request) ([]byte, http.Header, error) {
response, present := src[request.SerialNumber.String()]
if !present {
return nil, nil, ErrNotFound
}
return response, nil, nil
}
// DBSource represnts a source of OCSP responses backed by the certdb package.
@ -65,26 +80,23 @@ func NewDBSource(dbAccessor certdb.Accessor) Source {
// Response implements cfssl.ocsp.responder.Source, which returns the
// OCSP response in the Database for the given request with the expiration
// date furthest in the future. Response also returns a bool that is false
// if there were any errors obtaining the OCSP response and/or no OCSP response
// is present in the DB for the given request. Response will return a true
// bool if the byte array returned is a valid OCSP response.
func (src DBSource) Response(req *ocsp.Request) ([]byte, bool) {
// date furthest in the future.
func (src DBSource) Response(req *ocsp.Request) ([]byte, http.Header, error) {
if req == nil {
return nil, false
return nil, nil, errors.New("called with nil request")
}
aki := hex.EncodeToString(req.IssuerKeyHash)
sn := req.SerialNumber
if sn == nil {
return nil, false
return nil, nil, errors.New("request contains no serial")
}
strSN := sn.String()
if src.Accessor == nil {
log.Errorf("No DB Accessor")
return nil, false
return nil, nil, errors.New("called with nil DB accessor")
}
records, err := src.Accessor.GetOCSP(strSN, aki)
@ -92,11 +104,11 @@ func (src DBSource) Response(req *ocsp.Request) ([]byte, bool) {
// and returns nil, false.
if err != nil {
log.Errorf("Error obtaining OCSP response: %s", err)
return nil, false
return nil, nil, fmt.Errorf("failed to obtain OCSP response: %s", err)
}
if len(records) == 0 {
return nil, false
return nil, nil, ErrNotFound
}
// Response() finds the OCSPRecord with the expiration date furthest in the future.
@ -106,7 +118,7 @@ func (src DBSource) Response(req *ocsp.Request) ([]byte, bool) {
cur = rec
}
}
return []byte(cur.Body), true
return []byte(cur.Body), nil, nil
}
// NewSourceFromFile reads the named file into an InMemorySource.
@ -161,6 +173,19 @@ func NewResponder(source Source) *Responder {
}
}
func overrideHeaders(response http.ResponseWriter, headers http.Header) {
for k, v := range headers {
if len(v) == 1 {
response.Header().Set(k, v[0])
} else if len(v) > 1 {
response.Header().Del(k)
for _, e := range v {
response.Header().Add(k, e)
}
}
}
}
// A Responder can process both GET and POST requests. The mapping
// from an OCSP request to an OCSP response is done by the Source;
// the Responder simply decodes the request, and passes back whatever
@ -243,11 +268,18 @@ func (rs Responder) ServeHTTP(response http.ResponseWriter, request *http.Reques
}
// Look up OCSP response from source
ocspResponse, found := rs.Source.Response(ocspRequest)
if !found {
log.Infof("No response found for request: serial %x, request body %s",
ocspRequest.SerialNumber, b64Body)
response.Write(unauthorizedErrorResponse)
ocspResponse, headers, err := rs.Source.Response(ocspRequest)
if err != nil {
if err == ErrNotFound {
log.Infof("No response found for request: serial %x, request body %s",
ocspRequest.SerialNumber, b64Body)
response.Write(unauthorizedErrorResponse)
return
}
log.Infof("Error retrieving response for request: serial %x, request body %s, error: %s",
ocspRequest.SerialNumber, b64Body, err)
response.WriteHeader(http.StatusInternalServerError)
response.Write(internalErrorErrorResponse)
return
}
@ -281,6 +313,10 @@ func (rs Responder) ServeHTTP(response http.ResponseWriter, request *http.Reques
responseHash := sha256.Sum256(ocspResponse)
response.Header().Add("ETag", fmt.Sprintf("\"%X\"", responseHash))
if headers != nil {
overrideHeaders(response, headers)
}
// RFC 7232 says that a 304 response must contain the above
// headers if they would also be sent for a 200 for the same
// request, so we have to wait until here to do this

View File

@ -29,6 +29,7 @@ import (
"github.com/google/certificate-transparency-go/client"
"github.com/google/certificate-transparency-go/jsonclient"
"golang.org/x/net/context"
"time"
)
// Signer contains a signer that uses the standard library to
@ -96,14 +97,14 @@ func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signe
return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
}
func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) {
func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile, notBefore time.Time, notAfter time.Time) (cert []byte, err error) {
var distPoints = template.CRLDistributionPoints
err = signer.FillTemplate(template, s.policy.Default, profile)
if distPoints != nil && len(distPoints) > 0 {
template.CRLDistributionPoints = distPoints
}
err = signer.FillTemplate(template, s.policy.Default, profile, notBefore, notAfter)
if err != nil {
return
return nil, err
}
var initRoot bool
@ -342,7 +343,7 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}}
var poisonedPreCert = certTBS
poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension)
cert, err = s.sign(&poisonedPreCert, profile)
cert, err = s.sign(&poisonedPreCert, profile, req.NotBefore, req.NotAfter)
if err != nil {
return
}
@ -382,17 +383,22 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension)
}
var signedCert []byte
signedCert, err = s.sign(&certTBS, profile)
signedCert, err = s.sign(&certTBS, profile, req.NotBefore, req.NotAfter)
if err != nil {
return nil, err
}
// Get the AKI from signedCert. This is required to support Go 1.9+.
// In prior versions of Go, x509.CreateCertificate updated the
// AuthorityKeyId of certTBS.
parsedCert, _ := helpers.ParseCertificatePEM(signedCert)
if s.dbAccessor != nil {
var certRecord = certdb.CertificateRecord{
Serial: certTBS.SerialNumber.String(),
// this relies on the specific behavior of x509.CreateCertificate
// which updates certTBS AuthorityKeyId from the signer's SubjectKeyId
AKI: hex.EncodeToString(certTBS.AuthorityKeyId),
// which sets the AuthorityKeyId from the signer's SubjectKeyId
AKI: hex.EncodeToString(parsedCert.AuthorityKeyId),
CALabel: req.Label,
Status: "good",
Expiry: certTBS.NotAfter,
@ -452,6 +458,11 @@ func (s *Signer) SetDBAccessor(dba certdb.Accessor) {
s.dbAccessor = dba
}
// GetDBAccessor returns the signers' cert db accessor
func (s *Signer) GetDBAccessor() certdb.Accessor {
return s.dbAccessor
}
// SetReqModifier does nothing for local
func (s *Signer) SetReqModifier(func(*http.Request, []byte)) {
// noop

View File

@ -20,7 +20,6 @@ import (
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/csr"
cferr "github.com/cloudflare/cfssl/errors"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/info"
)
@ -56,6 +55,15 @@ type SignRequest struct {
Label string `json:"label"`
Serial *big.Int `json:"serial,omitempty"`
Extensions []Extension `json:"extensions,omitempty"`
// If provided, NotBefore will be used without modification (except
// for canonicalization) as the value of the notBefore field of the
// certificate. In particular no backdating adjustment will be made
// when NotBefore is provided.
NotBefore time.Time
// If provided, NotAfter will be used without modification (except
// for canonicalization) as the value of the notAfter field of the
// certificate.
NotAfter time.Time
}
// appendIf appends to a if s is not an empty string.
@ -97,6 +105,7 @@ type Signer interface {
Info(info.Req) (*info.Resp, error)
Policy() *config.Signing
SetDBAccessor(certdb.Accessor)
GetDBAccessor() certdb.Accessor
SetPolicy(*config.Signing)
SigAlgo() x509.SignatureAlgorithm
Sign(req SignRequest) (cert []byte, err error)
@ -163,7 +172,7 @@ func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certific
return
}
err = helpers.CheckSignature(csrv, csrv.SignatureAlgorithm, csrv.RawTBSCertificateRequest, csrv.Signature)
err = csrv.CheckSignature()
if err != nil {
err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
return
@ -231,7 +240,7 @@ func ComputeSKI(template *x509.Certificate) ([]byte, error) {
// the certificate template as possible from the profiles and current
// template. It fills in the key uses, expiration, revocation URLs
// and SKI.
func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.SigningProfile) error {
func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.SigningProfile, notBefore time.Time, notAfter time.Time) error {
ski, err := ComputeSKI(template)
if err != nil {
return err
@ -242,8 +251,6 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
ku x509.KeyUsage
backdate time.Duration
expiry time.Duration
notBefore time.Time
notAfter time.Time
crlURL, ocspURL string
issuerURL = profile.IssuerURL
)
@ -270,23 +277,29 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
if ocspURL = profile.OCSP; ocspURL == "" {
ocspURL = defaultProfile.OCSP
}
if backdate = profile.Backdate; backdate == 0 {
backdate = -5 * time.Minute
} else {
backdate = -1 * profile.Backdate
}
if !profile.NotBefore.IsZero() {
notBefore = profile.NotBefore.UTC()
} else {
notBefore = time.Now().Round(time.Minute).Add(backdate).UTC()
if notBefore.IsZero() {
if !profile.NotBefore.IsZero() {
notBefore = profile.NotBefore
} else {
if backdate = profile.Backdate; backdate == 0 {
backdate = -5 * time.Minute
} else {
backdate = -1 * profile.Backdate
}
notBefore = time.Now().Round(time.Minute).Add(backdate)
}
}
notBefore = notBefore.UTC()
if !profile.NotAfter.IsZero() {
notAfter = profile.NotAfter.UTC()
} else {
notAfter = notBefore.Add(expiry).UTC()
if notAfter.IsZero() {
if !profile.NotAfter.IsZero() {
notAfter = profile.NotAfter
} else {
notAfter = notBefore.Add(expiry)
}
}
notAfter = notAfter.UTC()
template.NotBefore = notBefore
template.NotAfter = notAfter