| // Copyright 2026 Google LLC | |
| // | |
| // 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. | |
| // | |
| #include "cose/ocsp_verifier.h" | |
| #include <string> | |
| #include "absl/status/status.h" | |
| #include "absl/strings/string_view.h" | |
| #include "absl/time/time.h" | |
| #include "absl/types/span.h" | |
| #include "constants/labels.h" | |
| #include "constants/status_codes.h" | |
| #include "cose/validation_status_util.h" | |
| #include "crypto/crypto_read_handler.h" | |
| #include "proto/validation_status.pb.h" | |
| namespace credentio { | |
| void RecordSkippedOcspCheck(ValidationStatusSet* status_set) { | |
| RecordStatus(status_set, | |
| InformationalStatusCode::kSigningCredentialOcspSkipped, | |
| {.url = kClaimSignatureLabel}); | |
| } | |
| bool OcspVerifier::VerifyOcspResponses( | |
| absl::Span<const std::string> ocsp_responses, | |
| absl::Span<const std::string> trust_chain, absl::Time asserted_time, | |
| ValidationStatusSet* status_set) const { | |
| bool has_good_signing_cert = false; | |
| // The manifest has an attested time provided by a valid signed | |
| // time-stamp and `rVals` header contains at least one OCSP response. | |
| for (int i = 0; i < ocsp_responses.size(); ++i) { | |
| absl::string_view ocsp_value = ocsp_responses[i]; | |
| for (int j = 1; j < trust_chain.size(); ++j) { | |
| absl::string_view certificate = trust_chain[j - 1]; | |
| // The issuer certificate is the next certificate in the chain. | |
| absl::string_view issuer_certificate = trust_chain[j]; | |
| auto revocation_status = crypto_read_handler_->VerifyOcspResponse( | |
| ocsp_value, certificate, issuer_certificate, asserted_time); | |
| if (revocation_status.ok()) { | |
| if (*revocation_status == OCSPRevocationStatus::kGood) { | |
| // According to the C2PA spec, if at least one OCSP response is | |
| // `good`, then the credential is not revoked. | |
| if (j == 1) { | |
| has_good_signing_cert = true; | |
| } | |
| break; | |
| } else if (*revocation_status == OCSPRevocationStatus::kRevoked) { | |
| // According to the C2PA spec, if at least one OCSP response is | |
| // `revoked`, then the credential is revoked. | |
| if (j == 1) { | |
| RecordStatus(status_set, | |
| FailureStatusCode::kSigningCredentialOcspRevoked, | |
| {.url = kClaimSignatureLabel}); | |
| } else { | |
| RecordStatus(status_set, | |
| FailureStatusCode::kSigningCredentialUntrusted, | |
| {.url = kClaimSignatureLabel}); | |
| } | |
| return false; | |
| } | |
| } else { | |
| if (revocation_status.status().code() == | |
| absl::StatusCode::kOutOfRange) { | |
| // OCSP response is produced at a time outside of the | |
| // corresponding certificate's validity period or the timestamp | |
| // time (i.e., the verify time) falls outside of the validity | |
| // window of the stapled OCSP response. | |
| RecordStatus( | |
| status_set, | |
| InformationalStatusCode::kSigningCredentialOcspOutsideValidity, | |
| {.url = kClaimSignatureLabel}); | |
| } | |
| } | |
| } | |
| } | |
| if (has_good_signing_cert) { | |
| RecordStatus(status_set, | |
| SuccessStatusCode::kSigningCredentialOcspNotRevoked, | |
| {.url = kClaimSignatureLabel}); | |
| } else { | |
| // None of the OCSP responses satisfied the conditions in | |
| // https://spec.c2pa.org/specifications/specifications/2.4/specs/C2PA_Specification.html#ocsp_stapled, | |
| // or no OCSP responses were provided. The validator chooses not to perform | |
| // online revocation checks so we record a `signingCredential.ocsp.skipped` | |
| // informational code per | |
| // https://spec.c2pa.org/specifications/specifications/2.4/specs/C2PA_Specification.html#ocsp_online. | |
| RecordSkippedOcspCheck(status_set); | |
| } | |
| return true; | |
| } | |
| } // namespace credentio |