gitea/vendor/github.com/cloudflare/cfssl/errors/error.go

439 lines
13 KiB
Go

package errors
import (
"crypto/x509"
"encoding/json"
"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"`
}
// 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
)
// 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)
}
// New returns an error that contains an error code and message derived from
// the given category, reason. Currently, to avoid confusion, it is not
// allowed to create an error of category Success
func New(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 Wrap(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()}
}