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:
24
vendor/github.com/go-webauthn/x/revoke/LICENSE
generated
vendored
Normal file
24
vendor/github.com/go-webauthn/x/revoke/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2014 CloudFlare Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
4
vendor/github.com/go-webauthn/x/revoke/README.md
generated
vendored
Normal file
4
vendor/github.com/go-webauthn/x/revoke/README.md
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# revoke
|
||||
|
||||
A fork of [github.com/cloudflare/cfssl/revoke](https://github.com/cloudflare/cfssl/tree/master/revoke) primarily intent
|
||||
on implementing functionality needed by [github.com/go-webauthn/webauthn](https://github.com/go-webauthn/webauthn).
|
||||
4
vendor/github.com/go-webauthn/x/revoke/doc.go
generated
vendored
Normal file
4
vendor/github.com/go-webauthn/x/revoke/doc.go
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package revoke provides functionality for checking the validity of a cert. Specifically, the temporal validity of the
|
||||
// certificate is checked first, then any CRL and OCSP url in the cert is checked. This is a fork of the
|
||||
// github.com/cloudflare/cfssl/revoke package. It's used to lookup the revocation status of X.509 Certificates.
|
||||
package revoke
|
||||
442
vendor/github.com/go-webauthn/x/revoke/err.go
generated
vendored
Normal file
442
vendor/github.com/go-webauthn/x/revoke/err.go
generated
vendored
Normal file
@@ -0,0 +1,442 @@
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Error is the error type usually returned by functions in CF SSL package.
|
||||
// It contains a 4-digit error code where the most significant digit
|
||||
// describes the category where the error occurred and the rest 3 digits
|
||||
// describe the specific error reason.
|
||||
type Error struct {
|
||||
ErrorCode int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// The error interface implementation, which formats to a JSON object string.
|
||||
func (e *Error) Error() string {
|
||||
marshaled, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(marshaled)
|
||||
|
||||
}
|
||||
|
||||
// Category is the most significant digit of the error code.
|
||||
type Category int
|
||||
|
||||
// Reason is the last 3 digits of the error code.
|
||||
type Reason int
|
||||
|
||||
const (
|
||||
// Success indicates no error occurred.
|
||||
Success Category = 1000 * iota // 0XXX
|
||||
|
||||
// CertificateError indicates a fault in a certificate.
|
||||
CertificateError // 1XXX
|
||||
|
||||
// PrivateKeyError indicates a fault in a private key.
|
||||
PrivateKeyError // 2XXX
|
||||
|
||||
// IntermediatesError indicates a fault in an intermediate.
|
||||
IntermediatesError // 3XXX
|
||||
|
||||
// RootError indicates a fault in a root.
|
||||
RootError // 4XXX
|
||||
|
||||
// PolicyError indicates an error arising from a malformed or
|
||||
// non-existent policy, or a breach of policy.
|
||||
PolicyError // 5XXX
|
||||
|
||||
// DialError indicates a network fault.
|
||||
DialError // 6XXX
|
||||
|
||||
// APIClientError indicates a problem with the API client.
|
||||
APIClientError // 7XXX
|
||||
|
||||
// OCSPError indicates a problem with OCSP signing
|
||||
OCSPError // 8XXX
|
||||
|
||||
// CSRError indicates a problem with CSR parsing
|
||||
CSRError // 9XXX
|
||||
|
||||
// CTError indicates a problem with the certificate transparency process
|
||||
CTError // 10XXX
|
||||
|
||||
// CertStoreError indicates a problem with the certificate store
|
||||
CertStoreError // 11XXX
|
||||
)
|
||||
|
||||
// None is a non-specified error.
|
||||
const (
|
||||
None Reason = iota
|
||||
)
|
||||
|
||||
// Warning code for a success
|
||||
const (
|
||||
BundleExpiringBit int = 1 << iota // 0x01
|
||||
BundleNotUbiquitousBit // 0x02
|
||||
)
|
||||
|
||||
// Parsing errors
|
||||
const (
|
||||
Unknown Reason = iota // X000
|
||||
ReadFailed // X001
|
||||
DecodeFailed // X002
|
||||
ParseFailed // X003
|
||||
)
|
||||
|
||||
// The following represent certificate non-parsing errors, and must be
|
||||
// specified along with CertificateError.
|
||||
const (
|
||||
// SelfSigned indicates that a certificate is self-signed and
|
||||
// cannot be used in the manner being attempted.
|
||||
SelfSigned Reason = 100 * (iota + 1) // Code 11XX
|
||||
|
||||
// VerifyFailed is an X.509 verification failure. The least two
|
||||
// significant digits of 12XX is determined as the actual x509
|
||||
// error is examined.
|
||||
VerifyFailed // Code 12XX
|
||||
|
||||
// BadRequest indicates that the certificate request is invalid.
|
||||
BadRequest // Code 13XX
|
||||
|
||||
// MissingSerial indicates that the profile specified
|
||||
// 'ClientProvidesSerialNumbers', but the SignRequest did not include a serial
|
||||
// number.
|
||||
MissingSerial // Code 14XX
|
||||
)
|
||||
|
||||
const (
|
||||
certificateInvalid = 10 * (iota + 1) //121X
|
||||
unknownAuthority //122x
|
||||
)
|
||||
|
||||
// The following represent private-key non-parsing errors, and must be
|
||||
// specified with PrivateKeyError.
|
||||
const (
|
||||
// Encrypted indicates that the private key is a PKCS #8 encrypted
|
||||
// private key. At this time, CFSSL does not support decrypting
|
||||
// these keys.
|
||||
Encrypted Reason = 100 * (iota + 1) //21XX
|
||||
|
||||
// NotRSAOrECC indicates that they key is not an RSA or ECC
|
||||
// private key; these are the only two private key types supported
|
||||
// at this time by CFSSL.
|
||||
NotRSAOrECC //22XX
|
||||
|
||||
// KeyMismatch indicates that the private key does not match
|
||||
// the public key or certificate being presented with the key.
|
||||
KeyMismatch //23XX
|
||||
|
||||
// GenerationFailed indicates that a private key could not
|
||||
// be generated.
|
||||
GenerationFailed //24XX
|
||||
|
||||
// Unavailable indicates that a private key mechanism (such as
|
||||
// PKCS #11) was requested but support for that mechanism is
|
||||
// not available.
|
||||
Unavailable
|
||||
)
|
||||
|
||||
// The following are policy-related non-parsing errors, and must be
|
||||
// specified along with PolicyError.
|
||||
const (
|
||||
// NoKeyUsages indicates that the profile does not permit any
|
||||
// key usages for the certificate.
|
||||
NoKeyUsages Reason = 100 * (iota + 1) // 51XX
|
||||
|
||||
// InvalidPolicy indicates that policy being requested is not
|
||||
// a valid policy or does not exist.
|
||||
InvalidPolicy // 52XX
|
||||
|
||||
// InvalidRequest indicates a certificate request violated the
|
||||
// constraints of the policy being applied to the request.
|
||||
InvalidRequest // 53XX
|
||||
|
||||
// UnknownProfile indicates that the profile does not exist.
|
||||
UnknownProfile // 54XX
|
||||
|
||||
UnmatchedWhitelist // 55xx
|
||||
)
|
||||
|
||||
// The following are API client related errors, and should be
|
||||
// specified with APIClientError.
|
||||
const (
|
||||
// AuthenticationFailure occurs when the client is unable
|
||||
// to obtain an authentication token for the request.
|
||||
AuthenticationFailure Reason = 100 * (iota + 1)
|
||||
|
||||
// JSONError wraps an encoding/json error.
|
||||
JSONError
|
||||
|
||||
// IOError wraps an io/ioutil error.
|
||||
IOError
|
||||
|
||||
// ClientHTTPError wraps a net/http error.
|
||||
ClientHTTPError
|
||||
|
||||
// ServerRequestFailed covers any other failures from the API
|
||||
// client.
|
||||
ServerRequestFailed
|
||||
)
|
||||
|
||||
// The following are OCSP related errors, and should be
|
||||
// specified with OCSPError
|
||||
const (
|
||||
// IssuerMismatch ocurs when the certificate in the OCSP signing
|
||||
// request was not issued by the CA that this responder responds for.
|
||||
IssuerMismatch Reason = 100 * (iota + 1) // 81XX
|
||||
|
||||
// InvalidStatus occurs when the OCSP signing requests includes an
|
||||
// invalid value for the certificate status.
|
||||
InvalidStatus
|
||||
)
|
||||
|
||||
// Certificate transparency related errors specified with CTError
|
||||
const (
|
||||
// PrecertSubmissionFailed occurs when submitting a precertificate to
|
||||
// a log server fails
|
||||
PrecertSubmissionFailed = 100 * (iota + 1)
|
||||
// CTClientConstructionFailed occurs when the construction of a new
|
||||
// github.com/google/certificate-transparency client fails.
|
||||
CTClientConstructionFailed
|
||||
// PrecertMissingPoison occurs when a precert is passed to SignFromPrecert
|
||||
// and is missing the CT poison extension.
|
||||
PrecertMissingPoison
|
||||
// PrecertInvalidPoison occurs when a precert is passed to SignFromPrecert
|
||||
// and has a invalid CT poison extension value or the extension is not
|
||||
// critical.
|
||||
PrecertInvalidPoison
|
||||
)
|
||||
|
||||
// Certificate persistence related errors specified with CertStoreError
|
||||
const (
|
||||
// InsertionFailed occurs when a SQL insert query failes to complete.
|
||||
InsertionFailed = 100 * (iota + 1)
|
||||
// RecordNotFound occurs when a SQL query targeting on one unique
|
||||
// record failes to update the specified row in the table.
|
||||
RecordNotFound
|
||||
)
|
||||
|
||||
// NewError provided the given category, reason, returns an Error.
|
||||
func NewError(category Category, reason Reason) *Error {
|
||||
errorCode := int(category) + int(reason)
|
||||
var msg string
|
||||
switch category {
|
||||
case OCSPError:
|
||||
switch reason {
|
||||
case ReadFailed:
|
||||
msg = "No certificate provided"
|
||||
case IssuerMismatch:
|
||||
msg = "Certificate not issued by this issuer"
|
||||
case InvalidStatus:
|
||||
msg = "Invalid revocation status"
|
||||
}
|
||||
case CertificateError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Unknown certificate error"
|
||||
case ReadFailed:
|
||||
msg = "Failed to read certificate"
|
||||
case DecodeFailed:
|
||||
msg = "Failed to decode certificate"
|
||||
case ParseFailed:
|
||||
msg = "Failed to parse certificate"
|
||||
case SelfSigned:
|
||||
msg = "Certificate is self signed"
|
||||
case VerifyFailed:
|
||||
msg = "Unable to verify certificate"
|
||||
case BadRequest:
|
||||
msg = "Invalid certificate request"
|
||||
case MissingSerial:
|
||||
msg = "Missing serial number in request"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category CertificateError.",
|
||||
reason))
|
||||
|
||||
}
|
||||
case PrivateKeyError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Unknown private key error"
|
||||
case ReadFailed:
|
||||
msg = "Failed to read private key"
|
||||
case DecodeFailed:
|
||||
msg = "Failed to decode private key"
|
||||
case ParseFailed:
|
||||
msg = "Failed to parse private key"
|
||||
case Encrypted:
|
||||
msg = "Private key is encrypted."
|
||||
case NotRSAOrECC:
|
||||
msg = "Private key algorithm is not RSA or ECC"
|
||||
case KeyMismatch:
|
||||
msg = "Private key does not match public key"
|
||||
case GenerationFailed:
|
||||
msg = "Failed to new private key"
|
||||
case Unavailable:
|
||||
msg = "Private key is unavailable"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PrivateKeyError.",
|
||||
reason))
|
||||
}
|
||||
case IntermediatesError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Unknown intermediate certificate error"
|
||||
case ReadFailed:
|
||||
msg = "Failed to read intermediate certificate"
|
||||
case DecodeFailed:
|
||||
msg = "Failed to decode intermediate certificate"
|
||||
case ParseFailed:
|
||||
msg = "Failed to parse intermediate certificate"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category IntermediatesError.",
|
||||
reason))
|
||||
}
|
||||
case RootError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Unknown root certificate error"
|
||||
case ReadFailed:
|
||||
msg = "Failed to read root certificate"
|
||||
case DecodeFailed:
|
||||
msg = "Failed to decode root certificate"
|
||||
case ParseFailed:
|
||||
msg = "Failed to parse root certificate"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category RootError.",
|
||||
reason))
|
||||
}
|
||||
case PolicyError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Unknown policy error"
|
||||
case NoKeyUsages:
|
||||
msg = "Invalid policy: no key usage available"
|
||||
case InvalidPolicy:
|
||||
msg = "Invalid or unknown policy"
|
||||
case InvalidRequest:
|
||||
msg = "Policy violation request"
|
||||
case UnknownProfile:
|
||||
msg = "Unknown policy profile"
|
||||
case UnmatchedWhitelist:
|
||||
msg = "Request does not match policy whitelist"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PolicyError.",
|
||||
reason))
|
||||
}
|
||||
case DialError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Failed to dial remote server"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category DialError.",
|
||||
reason))
|
||||
}
|
||||
case APIClientError:
|
||||
switch reason {
|
||||
case AuthenticationFailure:
|
||||
msg = "API client authentication failure"
|
||||
case JSONError:
|
||||
msg = "API client JSON config error"
|
||||
case ClientHTTPError:
|
||||
msg = "API client HTTP error"
|
||||
case IOError:
|
||||
msg = "API client IO error"
|
||||
case ServerRequestFailed:
|
||||
msg = "API client error: Server request failed"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category APIClientError.",
|
||||
reason))
|
||||
}
|
||||
case CSRError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "CSR parsing failed due to unknown error"
|
||||
case ReadFailed:
|
||||
msg = "CSR file read failed"
|
||||
case ParseFailed:
|
||||
msg = "CSR Parsing failed"
|
||||
case DecodeFailed:
|
||||
msg = "CSR Decode failed"
|
||||
case BadRequest:
|
||||
msg = "CSR Bad request"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category APIClientError.", reason))
|
||||
}
|
||||
case CTError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Certificate transparency parsing failed due to unknown error"
|
||||
case PrecertSubmissionFailed:
|
||||
msg = "Certificate transparency precertificate submission failed"
|
||||
case PrecertMissingPoison:
|
||||
msg = "Precertificate is missing CT poison extension"
|
||||
case PrecertInvalidPoison:
|
||||
msg = "Precertificate contains an invalid CT poison extension"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CTError.", reason))
|
||||
}
|
||||
case CertStoreError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Certificate store action failed due to unknown error"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CertStoreError.", reason))
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error type: %d.",
|
||||
category))
|
||||
}
|
||||
|
||||
return &Error{ErrorCode: errorCode, Message: msg}
|
||||
}
|
||||
|
||||
// Wrap returns an error that contains the given error and an error code derived from
|
||||
// the given category, reason and the error. Currently, to avoid confusion, it is not
|
||||
// allowed to create an error of category Success
|
||||
func WrapError(category Category, reason Reason, err error) *Error {
|
||||
errorCode := int(category) + int(reason)
|
||||
if err == nil {
|
||||
panic("Wrap needs a supplied error to initialize.")
|
||||
}
|
||||
|
||||
// do not double wrap a error
|
||||
switch err.(type) {
|
||||
case *Error:
|
||||
panic("Unable to wrap a wrapped error.")
|
||||
}
|
||||
|
||||
switch category {
|
||||
case CertificateError:
|
||||
// given VerifyFailed , report the status with more detailed status code
|
||||
// for some certificate errors we care.
|
||||
if reason == VerifyFailed {
|
||||
switch errorType := err.(type) {
|
||||
case x509.CertificateInvalidError:
|
||||
errorCode += certificateInvalid + int(errorType.Reason)
|
||||
case x509.UnknownAuthorityError:
|
||||
errorCode += unknownAuthority
|
||||
}
|
||||
}
|
||||
case PrivateKeyError, IntermediatesError, RootError, PolicyError, DialError,
|
||||
APIClientError, CSRError, CTError, CertStoreError, OCSPError:
|
||||
// no-op, just use the error
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error type: %d.",
|
||||
category))
|
||||
}
|
||||
|
||||
return &Error{ErrorCode: errorCode, Message: err.Error()}
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
ErrFailedGetCRL = errors.New("failed to retrieve CRL")
|
||||
)
|
||||
76
vendor/github.com/go-webauthn/x/revoke/helpers.go
generated
vendored
Normal file
76
vendor/github.com/go-webauthn/x/revoke/helpers.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// ParseCertificatePEM parses and returns a PEM-encoded certificate,
|
||||
// can handle PEM encoded PKCS #7 structures.
|
||||
func ParseCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
|
||||
certPEM = bytes.TrimSpace(certPEM)
|
||||
cert, rest, err := ParseOneCertificateFromPEM(certPEM)
|
||||
if err != nil {
|
||||
// Log the actual parsing error but throw a default parse error message.
|
||||
return nil, NewError(CertificateError, ParseFailed)
|
||||
} else if cert == nil {
|
||||
return nil, NewError(CertificateError, DecodeFailed)
|
||||
} else if len(rest) > 0 {
|
||||
return nil, WrapError(CertificateError, ParseFailed, errors.New("the PEM file should contain only one object"))
|
||||
} else if len(cert) > 1 {
|
||||
return nil, WrapError(CertificateError, ParseFailed, errors.New("the PKCS7 object in the PEM file should contain only one certificate"))
|
||||
}
|
||||
|
||||
return cert[0], nil
|
||||
}
|
||||
|
||||
// ParseOneCertificateFromPEM attempts to parse one PEM encoded certificate object,
|
||||
// either a raw x509 certificate or a PKCS #7 structure possibly containing
|
||||
// multiple certificates, from the top of certsPEM, which itself may
|
||||
// contain multiple PEM encoded certificate objects.
|
||||
func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, error) {
|
||||
block, rest := pem.Decode(certsPEM)
|
||||
if block == nil {
|
||||
return nil, rest, nil
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
var pkcs7data *PKCS7
|
||||
|
||||
if pkcs7data, err = ParsePKCS7(block.Bytes); err != nil {
|
||||
return nil, rest, err
|
||||
}
|
||||
|
||||
if pkcs7data.ContentInfo != "SignedData" {
|
||||
return nil, rest, errors.New("only PKCS #7 Signed Data Content Info supported for certificate parsing")
|
||||
}
|
||||
|
||||
certs := pkcs7data.Content.SignedData.Certificates
|
||||
if certs == nil {
|
||||
return nil, rest, errors.New("PKCS #7 structure contains no certificates")
|
||||
}
|
||||
|
||||
return certs, rest, nil
|
||||
}
|
||||
|
||||
return []*x509.Certificate{cert}, rest, nil
|
||||
}
|
||||
|
||||
// We can't handle LDAP certificates, so this checks to see if the
|
||||
// URL string points to an LDAP resource so that we can ignore it.
|
||||
func ldapURL(uri string) bool {
|
||||
u, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if u.Scheme == "ldap" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
185
vendor/github.com/go-webauthn/x/revoke/pkcs7.go
generated
vendored
Normal file
185
vendor/github.com/go-webauthn/x/revoke/pkcs7.go
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
// Package pkcs7 implements the subset of the CMS PKCS #7 datatype that is typically
|
||||
// used to package certificates and CRLs. Using openssl, every certificate converted
|
||||
// to PKCS #7 format from another encoding such as PEM conforms to this implementation.
|
||||
// reference: https://www.openssl.org/docs/man1.1.0/apps/crl2pkcs7.html
|
||||
//
|
||||
// PKCS #7 Data type, reference: https://tools.ietf.org/html/rfc2315
|
||||
//
|
||||
// The full pkcs#7 cryptographic message syntax allows for cryptographic enhancements,
|
||||
// for example data can be encrypted and signed and then packaged through pkcs#7 to be
|
||||
// sent over a network and then verified and decrypted. It is asn1, and the type of
|
||||
// PKCS #7 ContentInfo, which comprises the PKCS #7 structure, is:
|
||||
//
|
||||
// ContentInfo ::= SEQUENCE {
|
||||
// contentType ContentType,
|
||||
// content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
|
||||
// }
|
||||
//
|
||||
// There are 6 possible ContentTypes, data, signedData, envelopedData,
|
||||
// signedAndEnvelopedData, digestedData, and encryptedData. Here signedData, Data, and encrypted
|
||||
// Data are implemented, as the degenerate case of signedData without a signature is the typical
|
||||
// format for transferring certificates and CRLS, and Data and encryptedData are used in PKCS #12
|
||||
// formats.
|
||||
// The ContentType signedData has the form:
|
||||
//
|
||||
// signedData ::= SEQUENCE {
|
||||
// version Version,
|
||||
// digestAlgorithms DigestAlgorithmIdentifiers,
|
||||
// contentInfo ContentInfo,
|
||||
// certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL
|
||||
// crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
|
||||
// signerInfos SignerInfos
|
||||
// }
|
||||
//
|
||||
// As of yet signerInfos and digestAlgorithms are not parsed, as they are not relevant to
|
||||
// this system's use of PKCS #7 data. Version is an integer type, note that PKCS #7 is
|
||||
// recursive, this second layer of ContentInfo is similar ignored for our degenerate
|
||||
// usage. The ExtendedCertificatesAndCertificates type consists of a sequence of choices
|
||||
// between PKCS #6 extended certificates and x509 certificates. Any sequence consisting
|
||||
// of any number of extended certificates is not yet supported in this implementation.
|
||||
//
|
||||
// The ContentType Data is simply a raw octet string and is parsed directly into a Go []byte slice.
|
||||
//
|
||||
// The ContentType encryptedData is the most complicated and its form can be gathered by
|
||||
// the go type below. It essentially contains a raw octet string of encrypted data and an
|
||||
// algorithm identifier for use in decrypting this data.
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Types used for asn1 Unmarshaling.
|
||||
|
||||
type signedData struct {
|
||||
Version int
|
||||
DigestAlgorithms asn1.RawValue
|
||||
ContentInfo asn1.RawValue
|
||||
Certificates asn1.RawValue `asn1:"optional" asn1:"tag:0"`
|
||||
Crls asn1.RawValue `asn1:"optional"`
|
||||
SignerInfos asn1.RawValue
|
||||
}
|
||||
|
||||
type initPKCS7 struct {
|
||||
Raw asn1.RawContent
|
||||
ContentType asn1.ObjectIdentifier
|
||||
Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
|
||||
}
|
||||
|
||||
// Object identifier strings of the three implemented PKCS7 types.
|
||||
const (
|
||||
ObjIDData = "1.2.840.113549.1.7.1"
|
||||
ObjIDSignedData = "1.2.840.113549.1.7.2"
|
||||
ObjIDEncryptedData = "1.2.840.113549.1.7.6"
|
||||
)
|
||||
|
||||
// PKCS7 represents the ASN1 PKCS #7 Content type. It contains one of three
|
||||
// possible types of Content objects, as denoted by the object identifier in
|
||||
// the ContentInfo field, the other two being nil. SignedData
|
||||
// is the degenerate SignedData Content info without signature used
|
||||
// to hold certificates and crls. Data is raw bytes, and EncryptedData
|
||||
// is as defined in PKCS #7 standard.
|
||||
type PKCS7 struct {
|
||||
Raw asn1.RawContent
|
||||
ContentInfo string
|
||||
Content Content
|
||||
}
|
||||
|
||||
// Content implements three of the six possible PKCS7 data types. Only one is non-nil.
|
||||
type Content struct {
|
||||
Data []byte
|
||||
SignedData SignedData
|
||||
EncryptedData EncryptedData
|
||||
}
|
||||
|
||||
// SignedData defines the typical carrier of certificates and CRLs.
|
||||
type SignedData struct {
|
||||
Raw asn1.RawContent
|
||||
Version int
|
||||
Certificates []*x509.Certificate
|
||||
Crl *pkix.CertificateList
|
||||
}
|
||||
|
||||
// Data contains raw bytes. Used as a subtype in PKCS12.
|
||||
type Data struct {
|
||||
Bytes []byte
|
||||
}
|
||||
|
||||
// EncryptedData contains encrypted data. Used as a subtype in PKCS12.
|
||||
type EncryptedData struct {
|
||||
Raw asn1.RawContent
|
||||
Version int
|
||||
EncryptedContentInfo EncryptedContentInfo
|
||||
}
|
||||
|
||||
// EncryptedContentInfo is a subtype of PKCS7EncryptedData.
|
||||
type EncryptedContentInfo struct {
|
||||
Raw asn1.RawContent
|
||||
ContentType asn1.ObjectIdentifier
|
||||
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedContent []byte `asn1:"tag:0,optional"`
|
||||
}
|
||||
|
||||
// ParsePKCS7 attempts to parse the DER encoded bytes of a
|
||||
// PKCS7 structure.
|
||||
func ParsePKCS7(raw []byte) (msg *PKCS7, err error) {
|
||||
var pkcs7 initPKCS7
|
||||
|
||||
_, err = asn1.Unmarshal(raw, &pkcs7)
|
||||
if err != nil {
|
||||
return nil, WrapError(CertificateError, ParseFailed, err)
|
||||
}
|
||||
|
||||
msg = new(PKCS7)
|
||||
msg.Raw = pkcs7.Raw
|
||||
msg.ContentInfo = pkcs7.ContentType.String()
|
||||
switch {
|
||||
case msg.ContentInfo == ObjIDData:
|
||||
msg.ContentInfo = "Data"
|
||||
_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &msg.Content.Data)
|
||||
if err != nil {
|
||||
return nil, WrapError(CertificateError, ParseFailed, err)
|
||||
}
|
||||
case msg.ContentInfo == ObjIDSignedData:
|
||||
msg.ContentInfo = "SignedData"
|
||||
var signedData signedData
|
||||
_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &signedData)
|
||||
if err != nil {
|
||||
return nil, WrapError(CertificateError, ParseFailed, err)
|
||||
}
|
||||
if len(signedData.Certificates.Bytes) != 0 {
|
||||
msg.Content.SignedData.Certificates, err = x509.ParseCertificates(signedData.Certificates.Bytes)
|
||||
if err != nil {
|
||||
return nil, WrapError(CertificateError, ParseFailed, err)
|
||||
}
|
||||
}
|
||||
if len(signedData.Crls.Bytes) != 0 {
|
||||
msg.Content.SignedData.Crl, err = x509.ParseDERCRL(signedData.Crls.Bytes)
|
||||
if err != nil {
|
||||
return nil, WrapError(CertificateError, ParseFailed, err)
|
||||
}
|
||||
}
|
||||
msg.Content.SignedData.Version = signedData.Version
|
||||
msg.Content.SignedData.Raw = pkcs7.Content.Bytes
|
||||
case msg.ContentInfo == ObjIDEncryptedData:
|
||||
msg.ContentInfo = "EncryptedData"
|
||||
var encryptedData EncryptedData
|
||||
_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &encryptedData)
|
||||
if err != nil {
|
||||
return nil, WrapError(CertificateError, ParseFailed, err)
|
||||
}
|
||||
if encryptedData.Version != 0 {
|
||||
return nil, WrapError(CertificateError, ParseFailed, errors.New("Only support for PKCS #7 encryptedData version 0"))
|
||||
}
|
||||
msg.Content.EncryptedData = encryptedData
|
||||
|
||||
default:
|
||||
return nil, WrapError(CertificateError, ParseFailed, errors.New("Attempt to parse PKCS# 7 Content not of type data, signed data or encrypted data"))
|
||||
}
|
||||
|
||||
return msg, nil
|
||||
|
||||
}
|
||||
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
|
||||
}
|
||||
87
vendor/github.com/go-webauthn/x/revoke/revoke_legacy.go
generated
vendored
Normal file
87
vendor/github.com/go-webauthn/x/revoke/revoke_legacy.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
//go:build !go1.19
|
||||
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CRLSet associates a PKIX certificate list with the URL the CRL is
|
||||
// fetched from.
|
||||
var (
|
||||
CRLSet = map[string]*pkix.CertificateList{}
|
||||
)
|
||||
|
||||
// fetchCRL fetches and parses a CRL.
|
||||
func fetchCRL(url string) (*pkix.CertificateList, error) {
|
||||
resp, err := HTTPClient.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return nil, ErrFailedGetCRL
|
||||
}
|
||||
|
||||
body, err := crlRead(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return x509.ParseCRL(body)
|
||||
}
|
||||
|
||||
// check a cert against a specific CRL. Returns the same bool pair
|
||||
// as revCheck, plus an error if one occurred.
|
||||
func certIsRevokedCRL(cert *x509.Certificate, url string) (revoked, ok bool, err error) {
|
||||
var crl *pkix.CertificateList
|
||||
|
||||
crlLock.Lock()
|
||||
|
||||
if crl, ok = CRLSet[url]; ok && crl == nil {
|
||||
ok = false
|
||||
|
||||
delete(CRLSet, url)
|
||||
}
|
||||
|
||||
crlLock.Unlock()
|
||||
|
||||
var shouldFetchCRL = true
|
||||
|
||||
if ok && !crl.HasExpired(time.Now()) {
|
||||
shouldFetchCRL = false
|
||||
}
|
||||
|
||||
issuer := getIssuer(cert)
|
||||
|
||||
if shouldFetchCRL {
|
||||
if crl, err = fetchCRL(url); err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
// Check the CRL signature.
|
||||
if issuer != nil {
|
||||
if err = issuer.CheckCRLSignature(crl); err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
}
|
||||
|
||||
crlLock.Lock()
|
||||
CRLSet[url] = crl
|
||||
crlLock.Unlock()
|
||||
}
|
||||
|
||||
var rc pkix.RevokedCertificate
|
||||
|
||||
for _, rc = range crl.TBSCertList.RevokedCertificates {
|
||||
if cert.SerialNumber.Cmp(rc.SerialNumber) == 0 {
|
||||
return true, true, err
|
||||
}
|
||||
}
|
||||
|
||||
return false, true, err
|
||||
}
|
||||
84
vendor/github.com/go-webauthn/x/revoke/revoke_modern.go
generated
vendored
Normal file
84
vendor/github.com/go-webauthn/x/revoke/revoke_modern.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
//go:build go1.19
|
||||
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CRLSet associates a PKIX certificate list with the URL the CRL is
|
||||
// fetched from.
|
||||
var (
|
||||
CRLSet = map[string]*x509.RevocationList{}
|
||||
)
|
||||
|
||||
// fetchCRL fetches and parses a CRL.
|
||||
func fetchCRL(url string) (*x509.RevocationList, error) {
|
||||
resp, err := HTTPClient.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return nil, ErrFailedGetCRL
|
||||
}
|
||||
|
||||
body, err := crlRead(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return x509.ParseRevocationList(body)
|
||||
}
|
||||
|
||||
// check a cert against a specific CRL. Returns the same bool pair
|
||||
// as revCheck, plus an error if one occurred.
|
||||
func certIsRevokedCRL(cert *x509.Certificate, url string) (revoked, ok bool, err error) {
|
||||
var crl *x509.RevocationList
|
||||
|
||||
crlLock.Lock()
|
||||
|
||||
if crl, ok = CRLSet[url]; ok && crl == nil {
|
||||
ok = false
|
||||
|
||||
delete(CRLSet, url)
|
||||
}
|
||||
|
||||
crlLock.Unlock()
|
||||
|
||||
var shouldFetchCRL = true
|
||||
|
||||
if ok && time.Now().Before(crl.NextUpdate) {
|
||||
shouldFetchCRL = false
|
||||
}
|
||||
|
||||
issuer := getIssuer(cert)
|
||||
|
||||
if shouldFetchCRL {
|
||||
if crl, err = fetchCRL(url); err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
// Check the CRL signature.
|
||||
if issuer != nil {
|
||||
if err = crl.CheckSignatureFrom(issuer); err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
}
|
||||
|
||||
crlLock.Lock()
|
||||
CRLSet[url] = crl
|
||||
crlLock.Unlock()
|
||||
}
|
||||
|
||||
for _, rcert := range crl.RevokedCertificates {
|
||||
if cert.SerialNumber.Cmp(rcert.SerialNumber) == 0 {
|
||||
return true, true, err
|
||||
}
|
||||
}
|
||||
|
||||
return false, true, err
|
||||
}
|
||||
Reference in New Issue
Block a user