Add Nix flake for mciasctl and mciasgrpcctl
Vendor dependencies and expose control program binaries via nix build. Uses nixpkgs-unstable for Go 1.26 support. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
240
vendor/github.com/go-webauthn/x/revoke/revoke.go
generated
vendored
Normal file
240
vendor/github.com/go-webauthn/x/revoke/revoke.go
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
||||
// revCheck should check the certificate for any revocations. It
|
||||
// returns a pair of booleans: the first indicates whether the certificate
|
||||
// is revoked, the second indicates whether the revocations were
|
||||
// successfully checked.. This leads to the following combinations:
|
||||
//
|
||||
// false, false: an error was encountered while checking revocations.
|
||||
//
|
||||
// false, true: the certificate was checked successfully and
|
||||
// it is not revoked.
|
||||
//
|
||||
// true, true: the certificate was checked successfully and
|
||||
// it is revoked.
|
||||
//
|
||||
// true, false: failure to check revocation status causes
|
||||
// verification to fail
|
||||
func revCheck(cert *x509.Certificate) (revoked, ok bool, err error) {
|
||||
for _, uri := range cert.CRLDistributionPoints {
|
||||
if ldapURL(uri) {
|
||||
continue
|
||||
}
|
||||
|
||||
if revoked, ok, err = certIsRevokedCRL(cert, uri); !ok {
|
||||
if HardFail {
|
||||
return true, false, err
|
||||
}
|
||||
return false, false, err
|
||||
} else if revoked {
|
||||
return true, true, err
|
||||
}
|
||||
}
|
||||
|
||||
if revoked, ok, err = certIsRevokedOCSP(cert, HardFail); !ok {
|
||||
if HardFail {
|
||||
return true, false, err
|
||||
}
|
||||
|
||||
return false, false, err
|
||||
} else if revoked {
|
||||
return true, true, err
|
||||
}
|
||||
|
||||
return false, true, nil
|
||||
}
|
||||
|
||||
func getIssuer(cert *x509.Certificate) (issuer *x509.Certificate) {
|
||||
var (
|
||||
uri string
|
||||
err error
|
||||
)
|
||||
|
||||
for _, uri = range cert.IssuingCertificateURL {
|
||||
issuer, err = fetchRemote(uri)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return issuer
|
||||
}
|
||||
|
||||
// VerifyCertificate ensures that the certificate passed in hasn't
|
||||
// expired and checks the CRL for the server.
|
||||
func VerifyCertificate(cert *x509.Certificate) (revoked, ok bool) {
|
||||
revoked, ok, _ = VerifyCertificateError(cert)
|
||||
|
||||
return revoked, ok
|
||||
}
|
||||
|
||||
// VerifyCertificateError ensures that the certificate passed in hasn't
|
||||
// expired and checks the CRL for the server.
|
||||
func VerifyCertificateError(cert *x509.Certificate) (revoked, ok bool, err error) {
|
||||
if !time.Now().Before(cert.NotAfter) {
|
||||
return true, true, fmt.Errorf("Certificate expired %s\n", cert.NotAfter)
|
||||
} else if !time.Now().After(cert.NotBefore) {
|
||||
return true, true, fmt.Errorf("Certificate isn't valid until %s\n", cert.NotBefore)
|
||||
}
|
||||
return revCheck(cert)
|
||||
}
|
||||
|
||||
func fetchRemote(url string) (*x509.Certificate, error) {
|
||||
resp, err := HTTPClient.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
in, err := remoteRead(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p, _ := pem.Decode(in)
|
||||
if p != nil {
|
||||
return ParseCertificatePEM(in)
|
||||
}
|
||||
|
||||
return x509.ParseCertificate(in)
|
||||
}
|
||||
|
||||
func certIsRevokedOCSP(leaf *x509.Certificate, strict bool) (revoked, ok bool, e error) {
|
||||
var err error
|
||||
|
||||
ocspURLs := leaf.OCSPServer
|
||||
if len(ocspURLs) == 0 {
|
||||
// OCSP not enabled for this certificate.
|
||||
return false, true, nil
|
||||
}
|
||||
|
||||
issuer := getIssuer(leaf)
|
||||
|
||||
if issuer == nil {
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
ocspRequest, err := ocsp.CreateRequest(leaf, issuer, &ocspOpts)
|
||||
if err != nil {
|
||||
return revoked, ok, err
|
||||
}
|
||||
|
||||
for _, server := range ocspURLs {
|
||||
resp, err := sendOCSPRequest(server, ocspRequest, leaf, issuer)
|
||||
if err != nil {
|
||||
if strict {
|
||||
return revoked, ok, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// There wasn't an error fetching the OCSP status.
|
||||
ok = true
|
||||
|
||||
if resp.Status != ocsp.Good {
|
||||
// The certificate was revoked.
|
||||
revoked = true
|
||||
}
|
||||
|
||||
return revoked, ok, err
|
||||
}
|
||||
return revoked, ok, err
|
||||
}
|
||||
|
||||
// sendOCSPRequest attempts to request an OCSP response from the
|
||||
// server. The error only indicates a failure to *fetch* the
|
||||
// certificate, and *does not* mean the certificate is valid.
|
||||
func sendOCSPRequest(server string, req []byte, leaf, issuer *x509.Certificate) (r *ocsp.Response, err error) {
|
||||
var resp *http.Response
|
||||
|
||||
if len(req) > 256 {
|
||||
buf := bytes.NewBuffer(req)
|
||||
resp, err = HTTPClient.Post(server, "application/ocsp-request", buf)
|
||||
} else {
|
||||
reqURL := server + "/" + url.QueryEscape(base64.StdEncoding.EncodeToString(req))
|
||||
resp, err = HTTPClient.Get(reqURL)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.New("failed to retrieve OSCP")
|
||||
}
|
||||
|
||||
body, err := ocspRead(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case bytes.Equal(body, ocsp.UnauthorizedErrorResponse):
|
||||
return nil, errors.New("OSCP unauthorized")
|
||||
case bytes.Equal(body, ocsp.MalformedRequestErrorResponse):
|
||||
return nil, errors.New("OSCP malformed")
|
||||
case bytes.Equal(body, ocsp.InternalErrorErrorResponse):
|
||||
return nil, errors.New("OSCP internal error")
|
||||
case bytes.Equal(body, ocsp.TryLaterErrorResponse):
|
||||
return nil, errors.New("OSCP try later")
|
||||
case bytes.Equal(body, ocsp.SigRequredErrorResponse):
|
||||
return nil, errors.New("OSCP signature required")
|
||||
}
|
||||
|
||||
return ocsp.ParseResponseForCert(body, leaf, issuer)
|
||||
}
|
||||
|
||||
var (
|
||||
// HTTPClient is an instance of http.Client that will be used for all HTTP requests.
|
||||
HTTPClient = http.DefaultClient
|
||||
|
||||
// HardFail determines whether the failure to check the revocation
|
||||
// status of a certificate (i.e. due to network failure) causes
|
||||
// verification to fail (a hard failure).
|
||||
HardFail = false
|
||||
|
||||
crlRead = io.ReadAll
|
||||
remoteRead = io.ReadAll
|
||||
ocspRead = io.ReadAll
|
||||
|
||||
ocspOpts = ocsp.RequestOptions{
|
||||
Hash: crypto.SHA1,
|
||||
}
|
||||
|
||||
crlLock = new(sync.Mutex)
|
||||
)
|
||||
|
||||
// SetCRLFetcher sets the function to use to read from the http response body
|
||||
func SetCRLFetcher(fn func(io.Reader) ([]byte, error)) {
|
||||
crlRead = fn
|
||||
}
|
||||
|
||||
// SetRemoteFetcher sets the function to use to read from the http response body
|
||||
func SetRemoteFetcher(fn func(io.Reader) ([]byte, error)) {
|
||||
remoteRead = fn
|
||||
}
|
||||
|
||||
// SetOCSPFetcher sets the function to use to read from the http response body
|
||||
func SetOCSPFetcher(fn func(io.Reader) ([]byte, error)) {
|
||||
ocspRead = fn
|
||||
}
|
||||
Reference in New Issue
Block a user