| // Copyright 2016 The Chromium Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // ---------------------------- | |
| // Overview of error design | |
| // ---------------------------- | |
| // | |
| // Certificate path building/validation/parsing may emit a sequence of errors | |
| // and warnings. | |
| // | |
| // Each individual error/warning entry (CertError) is comprised of: | |
| // | |
| // * A unique identifier. | |
| // | |
| // This serves similarly to an error code, and is used to query if a | |
| // particular error/warning occurred. | |
| // | |
| // * [optional] A parameters object. | |
| // | |
| // Nodes may attach a heap-allocated subclass of CertErrorParams to carry | |
| // extra information that is used when reporting the error. For instance | |
| // a parsing error may describe where in the DER the failure happened, or | |
| // what the unexpected value was. | |
| // | |
| // A collection of errors is represented by the CertErrors object. This may be | |
| // used to group errors that have a common context, such as all the | |
| // errors/warnings that apply to a specific certificate. | |
| // | |
| // Lastly, CertPathErrors composes multiple CertErrors -- one for each | |
| // certificate in the verified chain. | |
| // | |
| // ---------------------------- | |
| // Defining new errors | |
| // ---------------------------- | |
| // | |
| // The error IDs are extensible and do not need to be centrally defined. | |
| // | |
| // To define a new error use the macro DEFINE_CERT_ERROR_ID() in a .cc file. | |
| // If consumers are to be able to query for this error then the symbol should | |
| // also be exposed in a header file. | |
| // | |
| // Error IDs are in truth string literals, whose pointer value will be unique | |
| // per process. | |
| #ifndef BSSL_PKI_CERT_ERRORS_H_ | |
| #define BSSL_PKI_CERT_ERRORS_H_ | |
| #include <memory> | |
| #include <vector> | |
| #include <openssl/base.h> | |
| #include "cert_error_id.h" | |
| #include "parsed_certificate.h" | |
| BSSL_NAMESPACE_BEGIN | |
| class CertErrorParams; | |
| class CertPathErrors; | |
| // CertError represents either an error or a warning. | |
| struct OPENSSL_EXPORT CertError { | |
| enum Severity { | |
| SEVERITY_HIGH, | |
| SEVERITY_WARNING, | |
| }; | |
| CertError(); | |
| CertError(Severity severity, CertErrorId id, | |
| std::unique_ptr<CertErrorParams> params); | |
| CertError(CertError &&other); | |
| CertError &operator=(CertError &&); | |
| ~CertError(); | |
| // Pretty-prints the error and its parameters. | |
| std::string ToDebugString() const; | |
| Severity severity; | |
| CertErrorId id; | |
| std::unique_ptr<CertErrorParams> params; | |
| }; | |
| // CertErrors is a collection of CertError, along with convenience methods to | |
| // add and inspect errors. | |
| class OPENSSL_EXPORT CertErrors { | |
| public: | |
| CertErrors(); | |
| CertErrors(CertErrors &&other); | |
| CertErrors &operator=(CertErrors &&); | |
| ~CertErrors(); | |
| // Adds an error/warning. `params` may be null. | |
| void Add(CertError::Severity severity, CertErrorId id, | |
| std::unique_ptr<CertErrorParams> params); | |
| // Adds a high severity error. | |
| void AddError(CertErrorId id, std::unique_ptr<CertErrorParams> params); | |
| void AddError(CertErrorId id); | |
| // Adds a low severity error. | |
| void AddWarning(CertErrorId id, std::unique_ptr<CertErrorParams> params); | |
| void AddWarning(CertErrorId id); | |
| // Dumps a textual representation of the errors for debugging purposes. | |
| std::string ToDebugString() const; | |
| // Returns true if the error `id` was added to this CertErrors at | |
| // severity `severity` | |
| bool ContainsErrorWithSeverity(CertErrorId id, | |
| CertError::Severity severity) const; | |
| // Returns true if the error `id` was added to this CertErrors at | |
| // high severity. | |
| bool ContainsError(CertErrorId id) const; | |
| // Returns true if this contains any errors of the given severity level. | |
| bool ContainsAnyErrorWithSeverity(CertError::Severity severity) const; | |
| private: | |
| friend CertPathErrors; | |
| std::vector<CertError> nodes_; | |
| }; | |
| // CertPathErrors is a collection of CertErrors, to group errors into different | |
| // buckets for different certificates. The "index" should correspond with that | |
| // of the certificate relative to its chain. | |
| class OPENSSL_EXPORT CertPathErrors { | |
| public: | |
| CertPathErrors(); | |
| CertPathErrors(CertPathErrors &&other); | |
| CertPathErrors &operator=(CertPathErrors &&); | |
| ~CertPathErrors(); | |
| // Gets a bucket to put errors in for `cert_index`. This will lookup and | |
| // return the existing error bucket if one exists, or create a new one for the | |
| // specified index. It is expected that `cert_index` is the corresponding | |
| // index in a certificate chain (with 0 being the target). | |
| CertErrors *GetErrorsForCert(size_t cert_index); | |
| // Const version of the above, with the difference that if there is no | |
| // existing bucket for `cert_index` returns nullptr rather than lazyily | |
| // creating one. | |
| const CertErrors *GetErrorsForCert(size_t cert_index) const; | |
| // Returns a bucket to put errors that are not associated with a particular | |
| // certificate. | |
| CertErrors *GetOtherErrors(); | |
| const CertErrors *GetOtherErrors() const; | |
| // Returns true if CertPathErrors contains the specified error (of any | |
| // severity). | |
| bool ContainsError(CertErrorId id) const; | |
| // Returns true if this contains any errors of the given severity level. | |
| bool ContainsAnyErrorWithSeverity(CertError::Severity severity) const; | |
| // If the path contains only one unique high severity error, return the | |
| // error id and sets `out_depth` to the depth at which the error was | |
| // first seen. A depth of -1 means the error is not associated with | |
| // a single certificate of the path. | |
| std::optional<CertErrorId> FindSingleHighSeverityError( | |
| ptrdiff_t &out_depth) const; | |
| // Shortcut for ContainsAnyErrorWithSeverity(CertError::SEVERITY_HIGH). | |
| bool ContainsHighSeverityErrors() const { | |
| return ContainsAnyErrorWithSeverity(CertError::SEVERITY_HIGH); | |
| } | |
| // Pretty-prints all the errors in the CertPathErrors. If there were no | |
| // errors/warnings, returns an empty string. | |
| std::string ToDebugString(const ParsedCertificateList &certs) const; | |
| private: | |
| std::vector<CertErrors> cert_errors_; | |
| CertErrors other_errors_; | |
| }; | |
| BSSL_NAMESPACE_END | |
| #endif // BSSL_PKI_CERT_ERRORS_H_ |