Vendor cfssl and cfssljson
This commit is contained in:
213
vendor/github.com/cloudflare/cfssl/ocsp/ocsp.go
generated
vendored
Normal file
213
vendor/github.com/cloudflare/cfssl/ocsp/ocsp.go
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
|
||||
Package ocsp exposes OCSP signing functionality, much like the signer
|
||||
package does for certificate signing. It also provies a basic OCSP
|
||||
responder stack for serving pre-signed OCSP responses.
|
||||
|
||||
*/
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
||||
// revocationReasonCodes is a map between string reason codes
|
||||
// to integers as defined in RFC 5280
|
||||
var revocationReasonCodes = map[string]int{
|
||||
"unspecified": ocsp.Unspecified,
|
||||
"keycompromise": ocsp.KeyCompromise,
|
||||
"cacompromise": ocsp.CACompromise,
|
||||
"affiliationchanged": ocsp.AffiliationChanged,
|
||||
"superseded": ocsp.Superseded,
|
||||
"cessationofoperation": ocsp.CessationOfOperation,
|
||||
"certificatehold": ocsp.CertificateHold,
|
||||
"removefromcrl": ocsp.RemoveFromCRL,
|
||||
"privilegewithdrawn": ocsp.PrivilegeWithdrawn,
|
||||
"aacompromise": ocsp.AACompromise,
|
||||
}
|
||||
|
||||
// StatusCode is a map between string statuses sent by cli/api
|
||||
// to ocsp int statuses
|
||||
var StatusCode = map[string]int{
|
||||
"good": ocsp.Good,
|
||||
"revoked": ocsp.Revoked,
|
||||
"unknown": ocsp.Unknown,
|
||||
}
|
||||
|
||||
// SignRequest represents the desired contents of a
|
||||
// specific OCSP response.
|
||||
type SignRequest struct {
|
||||
Certificate *x509.Certificate
|
||||
Status string
|
||||
Reason int
|
||||
RevokedAt time.Time
|
||||
Extensions []pkix.Extension
|
||||
// IssuerHash is the hashing function used to hash the issuer subject and public key
|
||||
// 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
|
||||
// responsible for populating all fields in the OCSP response that
|
||||
// are not reflected in the SignRequest.
|
||||
type Signer interface {
|
||||
Sign(req SignRequest) ([]byte, error)
|
||||
}
|
||||
|
||||
// StandardSigner is the default concrete type of OCSP signer.
|
||||
// It represents a single responder (represented by a key and certificate)
|
||||
// speaking for a single issuer (certificate). It is assumed that OCSP
|
||||
// responses are issued at a regular interval, which is used to compute
|
||||
// the nextUpdate value based on the current time.
|
||||
type StandardSigner struct {
|
||||
issuer *x509.Certificate
|
||||
responder *x509.Certificate
|
||||
key crypto.Signer
|
||||
interval time.Duration
|
||||
}
|
||||
|
||||
// ReasonStringToCode tries to convert a reason string to an integer code
|
||||
func ReasonStringToCode(reason string) (reasonCode int, err error) {
|
||||
// default to 0
|
||||
if reason == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
reasonCode, present := revocationReasonCodes[strings.ToLower(reason)]
|
||||
if !present {
|
||||
reasonCode, err = strconv.Atoi(reason)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if reasonCode >= ocsp.AACompromise || reasonCode <= ocsp.Unspecified {
|
||||
return 0, cferr.New(cferr.OCSPError, cferr.InvalidStatus)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewSignerFromFile reads the issuer cert, the responder cert and the responder key
|
||||
// from PEM files, and takes an interval in seconds
|
||||
func NewSignerFromFile(issuerFile, responderFile, keyFile string, interval time.Duration) (Signer, error) {
|
||||
log.Debug("Loading issuer cert: ", issuerFile)
|
||||
issuerBytes, err := helpers.ReadBytes(issuerFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("Loading responder cert: ", responderFile)
|
||||
responderBytes, err := ioutil.ReadFile(responderFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("Loading responder key: ", keyFile)
|
||||
keyBytes, err := ioutil.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
|
||||
}
|
||||
|
||||
issuerCert, err := helpers.ParseCertificatePEM(issuerBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responderCert, err := helpers.ParseCertificatePEM(responderBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := helpers.ParsePrivateKeyPEM(keyBytes)
|
||||
if err != nil {
|
||||
log.Debug("Malformed private key %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewSigner(issuerCert, responderCert, key, interval)
|
||||
}
|
||||
|
||||
// NewSigner simply constructs a new StandardSigner object from the inputs,
|
||||
// taking the interval in seconds
|
||||
func NewSigner(issuer, responder *x509.Certificate, key crypto.Signer, interval time.Duration) (Signer, error) {
|
||||
return &StandardSigner{
|
||||
issuer: issuer,
|
||||
responder: responder,
|
||||
key: key,
|
||||
interval: interval,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Sign is used with an OCSP signer to request the issuance of
|
||||
// an OCSP response.
|
||||
func (s StandardSigner) Sign(req SignRequest) ([]byte, error) {
|
||||
if req.Certificate == nil {
|
||||
return nil, cferr.New(cferr.OCSPError, cferr.ReadFailed)
|
||||
}
|
||||
|
||||
// Verify that req.Certificate is issued under s.issuer
|
||||
if bytes.Compare(req.Certificate.RawIssuer, s.issuer.RawSubject) != 0 {
|
||||
return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch)
|
||||
}
|
||||
if req.Certificate.CheckSignatureFrom(s.issuer) != nil {
|
||||
return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch)
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, cferr.New(cferr.OCSPError, cferr.InvalidStatus)
|
||||
}
|
||||
|
||||
// If the OCSP responder is the same as the issuer, there is no need to
|
||||
// include any certificate in the OCSP response, which decreases the byte size
|
||||
// of OCSP responses dramatically.
|
||||
certificate := s.responder
|
||||
if s.issuer == s.responder || bytes.Equal(s.issuer.Raw, s.responder.Raw) {
|
||||
certificate = nil
|
||||
}
|
||||
|
||||
template := ocsp.Response{
|
||||
Status: status,
|
||||
SerialNumber: req.Certificate.SerialNumber,
|
||||
ThisUpdate: thisUpdate,
|
||||
NextUpdate: nextUpdate,
|
||||
Certificate: certificate,
|
||||
ExtraExtensions: req.Extensions,
|
||||
IssuerHash: req.IssuerHash,
|
||||
}
|
||||
|
||||
if status == ocsp.Revoked {
|
||||
template.RevokedAt = req.RevokedAt
|
||||
template.RevocationReason = req.Reason
|
||||
}
|
||||
|
||||
return ocsp.CreateResponse(s.issuer, s.responder, template, s.key)
|
||||
}
|
Reference in New Issue
Block a user