| // 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 |