| 176 | } |
| 177 | |
| 178 | Status ValidatePemBundle(const string& bundle) { |
| 179 | SCOPED_OPENSSL_NO_PENDING_ERRORS; |
| 180 | |
| 181 | if (UNLIKELY(bundle.empty())) { |
| 182 | return Status("bundle is empty"); |
| 183 | } |
| 184 | |
| 185 | BIO* bio = BIO_new_mem_buf(bundle.data(), bundle.size()); |
| 186 | if (UNLIKELY(ERR_peek_error() != 0 || bio == nullptr)) { |
| 187 | Status ret = OpenSSLErr("BIO_new_mem_buf", Substitute("error '$0' creating BIO from " |
| 188 | "PEM bundle", ERR_GET_REASON(ERR_peek_error()))); |
| 189 | ERR_clear_error(); |
| 190 | return ret; |
| 191 | } |
| 192 | |
| 193 | X509* cert = nullptr; |
| 194 | int cert_count = 0; |
| 195 | int invalid_notbefore_cnt = 0; |
| 196 | int invalid_notafter_cnt = 0; |
| 197 | while ((cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) != nullptr) { |
| 198 | cert_count++; |
| 199 | // Check certificate validity (notBefore and notAfter) |
| 200 | if (UNLIKELY(X509_cmp_current_time(X509_get_notBefore(cert)) > 0)) { |
| 201 | invalid_notbefore_cnt++; |
| 202 | } |
| 203 | |
| 204 | if (UNLIKELY(X509_cmp_current_time(X509_get_notAfter(cert)) < 0)) { |
| 205 | invalid_notafter_cnt++; |
| 206 | } |
| 207 | |
| 208 | X509_free(cert); |
| 209 | } |
| 210 | BIO_free(bio); |
| 211 | |
| 212 | Status ret; |
| 213 | if (UNLIKELY(invalid_notbefore_cnt > 0 || invalid_notafter_cnt > 0)) { |
| 214 | ret = Status(Substitute( |
| 215 | "PEM bundle contains $0 invalid certificate(s) with notBefore in the future " |
| 216 | "and $1 invalid certificate(s) with notAfter in the past", |
| 217 | invalid_notbefore_cnt, invalid_notafter_cnt)); |
| 218 | } else if (UNLIKELY(cert_count == 0)) { |
| 219 | ret = Status("PEM bundle contains no valid certificates"); |
| 220 | } else if (UNLIKELY(ERR_GET_REASON(ERR_peek_error()) != PEM_R_NO_START_LINE)) { |
| 221 | // The final PEM_read_bio_X509 always sets the openssl error to PEM_R_NO_START_LINE, |
| 222 | // if the ssl error is set to anything else, return it. |
| 223 | ret = OpenSSLErr("PEM_read_bio_X509", Substitute("unexpected error '$0' while " |
| 224 | "reading PEM bundle", ERR_GET_REASON(ERR_peek_error()))); |
| 225 | } else { |
| 226 | ret = Status::OK(); |
| 227 | } |
| 228 | |
| 229 | // Clear the error left by the final PEM_read_bio_X509 call when it returns nullptr. |
| 230 | ERR_clear_error(); |
| 231 | |
| 232 | return ret; |
| 233 | } // function ValidatePemBundle |
| 234 | |
| 235 | void IntegrityHash::Compute(const uint8_t* data, int64_t len) { |