1package errors 2 3import ( 4 "crypto/x509" 5 "encoding/json" 6 "fmt" 7) 8 9// Error is the error type usually returned by functions in CF SSL package. 10// It contains a 4-digit error code where the most significant digit 11// describes the category where the error occurred and the rest 3 digits 12// describe the specific error reason. 13type Error struct { 14 ErrorCode int `json:"code"` 15 Message string `json:"message"` 16} 17 18// Category is the most significant digit of the error code. 19type Category int 20 21// Reason is the last 3 digits of the error code. 22type Reason int 23 24const ( 25 // Success indicates no error occurred. 26 Success Category = 1000 * iota // 0XXX 27 28 // CertificateError indicates a fault in a certificate. 29 CertificateError // 1XXX 30 31 // PrivateKeyError indicates a fault in a private key. 32 PrivateKeyError // 2XXX 33 34 // IntermediatesError indicates a fault in an intermediate. 35 IntermediatesError // 3XXX 36 37 // RootError indicates a fault in a root. 38 RootError // 4XXX 39 40 // PolicyError indicates an error arising from a malformed or 41 // non-existent policy, or a breach of policy. 42 PolicyError // 5XXX 43 44 // DialError indicates a network fault. 45 DialError // 6XXX 46 47 // APIClientError indicates a problem with the API client. 48 APIClientError // 7XXX 49 50 // OCSPError indicates a problem with OCSP signing 51 OCSPError // 8XXX 52 53 // CSRError indicates a problem with CSR parsing 54 CSRError // 9XXX 55 56 // CTError indicates a problem with the certificate transparency process 57 CTError // 10XXX 58 59 // CertStoreError indicates a problem with the certificate store 60 CertStoreError // 11XXX 61) 62 63// None is a non-specified error. 64const ( 65 None Reason = iota 66) 67 68// Warning code for a success 69const ( 70 BundleExpiringBit int = 1 << iota // 0x01 71 BundleNotUbiquitousBit // 0x02 72) 73 74// Parsing errors 75const ( 76 Unknown Reason = iota // X000 77 ReadFailed // X001 78 DecodeFailed // X002 79 ParseFailed // X003 80) 81 82// The following represent certificate non-parsing errors, and must be 83// specified along with CertificateError. 84const ( 85 // SelfSigned indicates that a certificate is self-signed and 86 // cannot be used in the manner being attempted. 87 SelfSigned Reason = 100 * (iota + 1) // Code 11XX 88 89 // VerifyFailed is an X.509 verification failure. The least two 90 // significant digits of 12XX is determined as the actual x509 91 // error is examined. 92 VerifyFailed // Code 12XX 93 94 // BadRequest indicates that the certificate request is invalid. 95 BadRequest // Code 13XX 96 97 // MissingSerial indicates that the profile specified 98 // 'ClientProvidesSerialNumbers', but the SignRequest did not include a serial 99 // number. 100 MissingSerial // Code 14XX 101) 102 103const ( 104 certificateInvalid = 10 * (iota + 1) //121X 105 unknownAuthority //122x 106) 107 108// The following represent private-key non-parsing errors, and must be 109// specified with PrivateKeyError. 110const ( 111 // Encrypted indicates that the private key is a PKCS #8 encrypted 112 // private key. At this time, CFSSL does not support decrypting 113 // these keys. 114 Encrypted Reason = 100 * (iota + 1) //21XX 115 116 // NotRSAOrECC indicates that they key is not an RSA or ECC 117 // private key; these are the only two private key types supported 118 // at this time by CFSSL. 119 NotRSAOrECC //22XX 120 121 // KeyMismatch indicates that the private key does not match 122 // the public key or certificate being presented with the key. 123 KeyMismatch //23XX 124 125 // GenerationFailed indicates that a private key could not 126 // be generated. 127 GenerationFailed //24XX 128 129 // Unavailable indicates that a private key mechanism (such as 130 // PKCS #11) was requested but support for that mechanism is 131 // not available. 132 Unavailable 133) 134 135// The following are policy-related non-parsing errors, and must be 136// specified along with PolicyError. 137const ( 138 // NoKeyUsages indicates that the profile does not permit any 139 // key usages for the certificate. 140 NoKeyUsages Reason = 100 * (iota + 1) // 51XX 141 142 // InvalidPolicy indicates that policy being requested is not 143 // a valid policy or does not exist. 144 InvalidPolicy // 52XX 145 146 // InvalidRequest indicates a certificate request violated the 147 // constraints of the policy being applied to the request. 148 InvalidRequest // 53XX 149 150 // UnknownProfile indicates that the profile does not exist. 151 UnknownProfile // 54XX 152 153 UnmatchedWhitelist // 55xx 154) 155 156// The following are API client related errors, and should be 157// specified with APIClientError. 158const ( 159 // AuthenticationFailure occurs when the client is unable 160 // to obtain an authentication token for the request. 161 AuthenticationFailure Reason = 100 * (iota + 1) 162 163 // JSONError wraps an encoding/json error. 164 JSONError 165 166 // IOError wraps an io/ioutil error. 167 IOError 168 169 // ClientHTTPError wraps a net/http error. 170 ClientHTTPError 171 172 // ServerRequestFailed covers any other failures from the API 173 // client. 174 ServerRequestFailed 175) 176 177// The following are OCSP related errors, and should be 178// specified with OCSPError 179const ( 180 // IssuerMismatch ocurs when the certificate in the OCSP signing 181 // request was not issued by the CA that this responder responds for. 182 IssuerMismatch Reason = 100 * (iota + 1) // 81XX 183 184 // InvalidStatus occurs when the OCSP signing requests includes an 185 // invalid value for the certificate status. 186 InvalidStatus 187) 188 189// Certificate transparency related errors specified with CTError 190const ( 191 // PrecertSubmissionFailed occurs when submitting a precertificate to 192 // a log server fails 193 PrecertSubmissionFailed = 100 * (iota + 1) 194 // CTClientConstructionFailed occurs when the construction of a new 195 // github.com/google/certificate-transparency client fails. 196 CTClientConstructionFailed 197 // PrecertMissingPoison occurs when a precert is passed to SignFromPrecert 198 // and is missing the CT poison extension. 199 PrecertMissingPoison 200 // PrecertInvalidPoison occurs when a precert is passed to SignFromPrecert 201 // and has a invalid CT poison extension value or the extension is not 202 // critical. 203 PrecertInvalidPoison 204) 205 206// Certificate persistence related errors specified with CertStoreError 207const ( 208 // InsertionFailed occurs when a SQL insert query failes to complete. 209 InsertionFailed = 100 * (iota + 1) 210 // RecordNotFound occurs when a SQL query targeting on one unique 211 // record failes to update the specified row in the table. 212 RecordNotFound 213) 214 215// The error interface implementation, which formats to a JSON object string. 216func (e *Error) Error() string { 217 marshaled, err := json.Marshal(e) 218 if err != nil { 219 panic(err) 220 } 221 return string(marshaled) 222 223} 224 225// New returns an error that contains an error code and message derived from 226// the given category, reason. Currently, to avoid confusion, it is not 227// allowed to create an error of category Success 228func New(category Category, reason Reason) *Error { 229 errorCode := int(category) + int(reason) 230 var msg string 231 switch category { 232 case OCSPError: 233 switch reason { 234 case ReadFailed: 235 msg = "No certificate provided" 236 case IssuerMismatch: 237 msg = "Certificate not issued by this issuer" 238 case InvalidStatus: 239 msg = "Invalid revocation status" 240 } 241 case CertificateError: 242 switch reason { 243 case Unknown: 244 msg = "Unknown certificate error" 245 case ReadFailed: 246 msg = "Failed to read certificate" 247 case DecodeFailed: 248 msg = "Failed to decode certificate" 249 case ParseFailed: 250 msg = "Failed to parse certificate" 251 case SelfSigned: 252 msg = "Certificate is self signed" 253 case VerifyFailed: 254 msg = "Unable to verify certificate" 255 case BadRequest: 256 msg = "Invalid certificate request" 257 case MissingSerial: 258 msg = "Missing serial number in request" 259 default: 260 panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category CertificateError.", 261 reason)) 262 263 } 264 case PrivateKeyError: 265 switch reason { 266 case Unknown: 267 msg = "Unknown private key error" 268 case ReadFailed: 269 msg = "Failed to read private key" 270 case DecodeFailed: 271 msg = "Failed to decode private key" 272 case ParseFailed: 273 msg = "Failed to parse private key" 274 case Encrypted: 275 msg = "Private key is encrypted." 276 case NotRSAOrECC: 277 msg = "Private key algorithm is not RSA or ECC" 278 case KeyMismatch: 279 msg = "Private key does not match public key" 280 case GenerationFailed: 281 msg = "Failed to new private key" 282 case Unavailable: 283 msg = "Private key is unavailable" 284 default: 285 panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PrivateKeyError.", 286 reason)) 287 } 288 case IntermediatesError: 289 switch reason { 290 case Unknown: 291 msg = "Unknown intermediate certificate error" 292 case ReadFailed: 293 msg = "Failed to read intermediate certificate" 294 case DecodeFailed: 295 msg = "Failed to decode intermediate certificate" 296 case ParseFailed: 297 msg = "Failed to parse intermediate certificate" 298 default: 299 panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category IntermediatesError.", 300 reason)) 301 } 302 case RootError: 303 switch reason { 304 case Unknown: 305 msg = "Unknown root certificate error" 306 case ReadFailed: 307 msg = "Failed to read root certificate" 308 case DecodeFailed: 309 msg = "Failed to decode root certificate" 310 case ParseFailed: 311 msg = "Failed to parse root certificate" 312 default: 313 panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category RootError.", 314 reason)) 315 } 316 case PolicyError: 317 switch reason { 318 case Unknown: 319 msg = "Unknown policy error" 320 case NoKeyUsages: 321 msg = "Invalid policy: no key usage available" 322 case InvalidPolicy: 323 msg = "Invalid or unknown policy" 324 case InvalidRequest: 325 msg = "Policy violation request" 326 case UnknownProfile: 327 msg = "Unknown policy profile" 328 case UnmatchedWhitelist: 329 msg = "Request does not match policy whitelist" 330 default: 331 panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PolicyError.", 332 reason)) 333 } 334 case DialError: 335 switch reason { 336 case Unknown: 337 msg = "Failed to dial remote server" 338 default: 339 panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category DialError.", 340 reason)) 341 } 342 case APIClientError: 343 switch reason { 344 case AuthenticationFailure: 345 msg = "API client authentication failure" 346 case JSONError: 347 msg = "API client JSON config error" 348 case ClientHTTPError: 349 msg = "API client HTTP error" 350 case IOError: 351 msg = "API client IO error" 352 case ServerRequestFailed: 353 msg = "API client error: Server request failed" 354 default: 355 panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category APIClientError.", 356 reason)) 357 } 358 case CSRError: 359 switch reason { 360 case Unknown: 361 msg = "CSR parsing failed due to unknown error" 362 case ReadFailed: 363 msg = "CSR file read failed" 364 case ParseFailed: 365 msg = "CSR Parsing failed" 366 case DecodeFailed: 367 msg = "CSR Decode failed" 368 case BadRequest: 369 msg = "CSR Bad request" 370 default: 371 panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category APIClientError.", reason)) 372 } 373 case CTError: 374 switch reason { 375 case Unknown: 376 msg = "Certificate transparency parsing failed due to unknown error" 377 case PrecertSubmissionFailed: 378 msg = "Certificate transparency precertificate submission failed" 379 case PrecertMissingPoison: 380 msg = "Precertificate is missing CT poison extension" 381 case PrecertInvalidPoison: 382 msg = "Precertificate contains an invalid CT poison extension" 383 default: 384 panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CTError.", reason)) 385 } 386 case CertStoreError: 387 switch reason { 388 case Unknown: 389 msg = "Certificate store action failed due to unknown error" 390 default: 391 panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CertStoreError.", reason)) 392 } 393 394 default: 395 panic(fmt.Sprintf("Unsupported CFSSL error type: %d.", 396 category)) 397 } 398 return &Error{ErrorCode: errorCode, Message: msg} 399} 400 401// Wrap returns an error that contains the given error and an error code derived from 402// the given category, reason and the error. Currently, to avoid confusion, it is not 403// allowed to create an error of category Success 404func Wrap(category Category, reason Reason, err error) *Error { 405 errorCode := int(category) + int(reason) 406 if err == nil { 407 panic("Wrap needs a supplied error to initialize.") 408 } 409 410 // do not double wrap a error 411 switch err.(type) { 412 case *Error: 413 panic("Unable to wrap a wrapped error.") 414 } 415 416 switch category { 417 case CertificateError: 418 // given VerifyFailed , report the status with more detailed status code 419 // for some certificate errors we care. 420 if reason == VerifyFailed { 421 switch errorType := err.(type) { 422 case x509.CertificateInvalidError: 423 errorCode += certificateInvalid + int(errorType.Reason) 424 case x509.UnknownAuthorityError: 425 errorCode += unknownAuthority 426 } 427 } 428 case PrivateKeyError, IntermediatesError, RootError, PolicyError, DialError, 429 APIClientError, CSRError, CTError, CertStoreError, OCSPError: 430 // no-op, just use the error 431 default: 432 panic(fmt.Sprintf("Unsupported CFSSL error type: %d.", 433 category)) 434 } 435 436 return &Error{ErrorCode: errorCode, Message: err.Error()} 437 438} 439