1 // Copyright 2016 The Chromium Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // ---------------------------- 16 // Overview of error design 17 // ---------------------------- 18 // 19 // Certificate path building/validation/parsing may emit a sequence of errors 20 // and warnings. 21 // 22 // Each individual error/warning entry (CertError) is comprised of: 23 // 24 // * A unique identifier. 25 // 26 // This serves similarly to an error code, and is used to query if a 27 // particular error/warning occurred. 28 // 29 // * [optional] A parameters object. 30 // 31 // Nodes may attach a heap-allocated subclass of CertErrorParams to carry 32 // extra information that is used when reporting the error. For instance 33 // a parsing error may describe where in the DER the failure happened, or 34 // what the unexpected value was. 35 // 36 // A collection of errors is represented by the CertErrors object. This may be 37 // used to group errors that have a common context, such as all the 38 // errors/warnings that apply to a specific certificate. 39 // 40 // Lastly, CertPathErrors composes multiple CertErrors -- one for each 41 // certificate in the verified chain. 42 // 43 // ---------------------------- 44 // Defining new errors 45 // ---------------------------- 46 // 47 // The error IDs are extensible and do not need to be centrally defined. 48 // 49 // To define a new error use the macro DEFINE_CERT_ERROR_ID() in a .cc file. 50 // If consumers are to be able to query for this error then the symbol should 51 // also be exposed in a header file. 52 // 53 // Error IDs are in truth string literals, whose pointer value will be unique 54 // per process. 55 56 #ifndef BSSL_PKI_CERT_ERRORS_H_ 57 #define BSSL_PKI_CERT_ERRORS_H_ 58 59 #include <memory> 60 #include <vector> 61 62 #include <openssl/base.h> 63 64 #include "cert_error_id.h" 65 #include "parsed_certificate.h" 66 67 BSSL_NAMESPACE_BEGIN 68 69 class CertErrorParams; 70 class CertPathErrors; 71 72 // CertError represents either an error or a warning. 73 struct OPENSSL_EXPORT CertError { 74 enum Severity { 75 SEVERITY_HIGH, 76 SEVERITY_WARNING, 77 }; 78 79 CertError(); 80 CertError(Severity severity, CertErrorId id, 81 std::unique_ptr<CertErrorParams> params); 82 CertError(CertError &&other); 83 CertError &operator=(CertError &&); 84 ~CertError(); 85 86 // Pretty-prints the error and its parameters. 87 std::string ToDebugString() const; 88 89 Severity severity; 90 CertErrorId id; 91 std::unique_ptr<CertErrorParams> params; 92 }; 93 94 // CertErrors is a collection of CertError, along with convenience methods to 95 // add and inspect errors. 96 class OPENSSL_EXPORT CertErrors { 97 public: 98 CertErrors(); 99 CertErrors(CertErrors &&other); 100 CertErrors &operator=(CertErrors &&); 101 ~CertErrors(); 102 103 // Adds an error/warning. |params| may be null. 104 void Add(CertError::Severity severity, CertErrorId id, 105 std::unique_ptr<CertErrorParams> params); 106 107 // Adds a high severity error. 108 void AddError(CertErrorId id, std::unique_ptr<CertErrorParams> params); 109 void AddError(CertErrorId id); 110 111 // Adds a low severity error. 112 void AddWarning(CertErrorId id, std::unique_ptr<CertErrorParams> params); 113 void AddWarning(CertErrorId id); 114 115 // Dumps a textual representation of the errors for debugging purposes. 116 std::string ToDebugString() const; 117 118 // Returns true if the error |id| was added to this CertErrors at 119 // severity |severity| 120 bool ContainsErrorWithSeverity(CertErrorId id, 121 CertError::Severity severity) const; 122 123 // Returns true if the error |id| was added to this CertErrors at 124 // high serverity. 125 bool ContainsError(CertErrorId id) const; 126 127 // Returns true if this contains any errors of the given severity level. 128 bool ContainsAnyErrorWithSeverity(CertError::Severity severity) const; 129 130 private: 131 friend CertPathErrors; 132 std::vector<CertError> nodes_; 133 }; 134 135 // CertPathErrors is a collection of CertErrors, to group errors into different 136 // buckets for different certificates. The "index" should correspond with that 137 // of the certificate relative to its chain. 138 class OPENSSL_EXPORT CertPathErrors { 139 public: 140 CertPathErrors(); 141 CertPathErrors(CertPathErrors &&other); 142 CertPathErrors &operator=(CertPathErrors &&); 143 ~CertPathErrors(); 144 145 // Gets a bucket to put errors in for |cert_index|. This will lookup and 146 // return the existing error bucket if one exists, or create a new one for the 147 // specified index. It is expected that |cert_index| is the corresponding 148 // index in a certificate chain (with 0 being the target). 149 CertErrors *GetErrorsForCert(size_t cert_index); 150 151 // Const version of the above, with the difference that if there is no 152 // existing bucket for |cert_index| returns nullptr rather than lazyily 153 // creating one. 154 const CertErrors *GetErrorsForCert(size_t cert_index) const; 155 156 // Returns a bucket to put errors that are not associated with a particular 157 // certificate. 158 CertErrors *GetOtherErrors(); 159 const CertErrors *GetOtherErrors() const; 160 161 // Returns true if CertPathErrors contains the specified error (of any 162 // severity). 163 bool ContainsError(CertErrorId id) const; 164 165 // Returns true if this contains any errors of the given severity level. 166 bool ContainsAnyErrorWithSeverity(CertError::Severity severity) const; 167 168 // If the path contains only one unique high severity error, return the 169 // error id and sets |out_depth| to the depth at which the error was 170 // first seen. A depth of -1 means the error is not associated with 171 // a single certificate of the path. 172 std::optional<CertErrorId> FindSingleHighSeverityError( 173 ptrdiff_t &out_depth) const; 174 175 // Shortcut for ContainsAnyErrorWithSeverity(CertError::SEVERITY_HIGH). ContainsHighSeverityErrors()176 bool ContainsHighSeverityErrors() const { 177 return ContainsAnyErrorWithSeverity(CertError::SEVERITY_HIGH); 178 } 179 180 // Pretty-prints all the errors in the CertPathErrors. If there were no 181 // errors/warnings, returns an empty string. 182 std::string ToDebugString(const ParsedCertificateList &certs) const; 183 184 private: 185 std::vector<CertErrors> cert_errors_; 186 CertErrors other_errors_; 187 }; 188 189 BSSL_NAMESPACE_END 190 191 #endif // BSSL_PKI_CERT_ERRORS_H_ 192