Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validation errors inconsistent through tools #125

Open
clementh59 opened this issue Dec 5, 2023 · 26 comments
Open

Validation errors inconsistent through tools #125

clementh59 opened this issue Dec 5, 2023 · 26 comments
Assignees
Labels
accepted bug Something isn't working status: todo

Comments

@clementh59
Copy link

clementh59 commented Dec 5, 2023

Hi,

When validating the manifest of this image: https://truepic.com/wp-content/uploads/2023/03/transparency_original-capture.jpg with the library, I get this issue:

Screenshot 2023-12-05 at 12 41 33 Screenshot 2023-12-05 at 12 43 06

However, when validating with c2patool, it accepts the signature:

{
      "code": "claimSignature.validated",
      "url": "self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.signature",
      "explanation": "claim signature valid"
}

Do you know where it could come from?

Thanks,
Clément

@dkozma
Copy link
Collaborator

dkozma commented Dec 5, 2023

Hi Clément,

What signing algorithm are you using? Unfortunately the JavaScript SDK doesn't support Ed25519 at the moment due to WebCrypto's lack of support for it, so I'm wondering if this is causing the issue.

@clementh59
Copy link
Author

It's es256. Please note that I am not generating this image. I took an image sample from truepic.

"signature": {
  "alg": "es256",
  "issuer": "Truepic",
  "time": "2023-03-20T14:29:27+00:00"
}

Also, I can verify it there: https://contentcredentials.org/verify. I'm not sure which library is used there, but it seems to accept it.

@emensch
Copy link
Collaborator

emensch commented Dec 8, 2023

Hi @clementh59, what version of c2pa do you have installed?

@clementh59
Copy link
Author

Hi @emensch, that's 0.11.12 for c2pa-wc and 0.17.5 for c2pa

@dkozma
Copy link
Collaborator

dkozma commented Dec 13, 2023

@clementh59 Verify uses the open source c2pa-js under the hood. I made a minimal repro case in CodeSandbox showing the image loading from your server and showing the claim info.

What browser/version are you trying this on?

@clementh59
Copy link
Author

Thanks a lot for the answer. The issue probably comes from our end then. I am on Chrome, but that's probably not linked to my browser/version as all the people that tried our service (which is a chrome extension) had the same issue.

We'll investigate on our end to try to find the root of the issue.

Thanks.

@emensch
Copy link
Collaborator

emensch commented Dec 14, 2023

@clementh59 if you'd like to post sample code—specifically anything about reading c2pa data and passing it to the web components—we might be able to help debug. There are a couple potential pitfalls that we don't do a great job of detailing in our docs at the moment 🙂

@clementh59
Copy link
Author

clementh59 commented Dec 21, 2023

@emensch @dkozma Here is the code I tried:

const sampleImage = 'https://truepic.com/wp-content/uploads/2023/03/transparency_original-capture.jpg';

(async () => {
  const libraryUrl = './lib-temp/c2pa.esm.js';

  // Initialize the c2pa-js SDK
  const { createC2pa } = await import(libraryUrl);
  const c2pa = await createC2pa({
    wasmSrc: './lib-temp/toolkit_bg.wasm',
    workerSrc: './lib-temp/c2pa.worker.min.js',
  });

  // Read in our sample image and get a manifest store
  try {
    const { manifestStore } = await c2pa.read(sampleImage);
    console.log('errors from site reading: ', manifestStore.validationStatus);
  } catch (err) {
    console.error('Error reading image:', err);
  }
})();

This code works in a very basic web app, where I don't have any validation error. However, the same code, with the same libraries (0.17.6) does not work in a very basic chrome extension (it says one of the signature mismatches).

We'll continue to investigate on our side, but if you have any idea of what could be the issue, that would be super helpful.

Thanks a lot

@clementh59
Copy link
Author

clementh59 commented Dec 21, 2023

It seems to come from this function that returns a validation error when fetching the manifest store data:
Screenshot 2023-12-21 at 14 08 55

It might be the case only when it is run in a special environment (i.e a chrome extension). What is surprising is that it is only the case for a small set of images, most of them are validated without any issue.

@dkozma dkozma self-assigned this Jan 23, 2024
@dkozma
Copy link
Collaborator

dkozma commented Jan 23, 2024

@clementh59 I'm not sure if your browser extension also runs in a Firefox or Safari environment but if so I'm curious as to if the same problem exists in those browsers, or if this is localized to Chrome.

@clementh59
Copy link
Author

Good point. It only runs on Chrome for now, so I can't help on that point, sorry

@dkozma
Copy link
Collaborator

dkozma commented Jan 23, 2024

No problem - let us try to replicate on a minimal browser extension environment and see if there is anything we can find.

@dkozma dkozma added bug Something isn't working accepted labels Jan 23, 2024
@github-jira-sync-bot
Copy link
Collaborator

✅ Jira issue https://jira.corp.adobe.com/browse/CAI-5271 is successfully created for this GitHub issue.

@dkozma
Copy link
Collaborator

dkozma commented Jan 24, 2024

@clementh59 Are you running the c2pa-js code in a content script or a background script in your extension?

@clementh59
Copy link
Author

clementh59 commented Jan 24, 2024

@dkozma
None of them was working, we had to run it from a sandbox. You can find our implementation here:
https://github.com/digimarc-corp/c2pa-content-credentials-extension/blob/main/sandbox.js

Feel free to ask any questions or help regarding the integration into an extension, I am happy to help!

@dkozma dkozma added this to the 2024 Q1 milestone Jan 26, 2024
@clementh59
Copy link
Author

Hi @dkozma,

I created a minimalist extension that showcases the bug: https://github.com/digimarc-corp/c2pa-content-credentials-extension/tree/minimalist-extension

Here are the steps to have it work:
npm i
git clone https://github.com/contentauth/c2pa-js
mv c2pa-js c2pa
cd c2pa
Rush install
Rush build

Then, load the extension in chrome (https://developer.chrome.com/docs/extensions/get-started/tutorial/hello-world#load-unpacked)
Click on the extension icon and turn it on.
Open an image (e.g. https://truepic.com/wp-content/uploads/2023/03/transparency_original-capture.jpg) and check the console, you should see the validation status.

I hope it will make the debug as easy as possible on your side! :)

Feel free to ask if you have any questions. I'm happy to jump on a call if you think it could be valuable.

@dkozma
Copy link
Collaborator

dkozma commented Feb 2, 2024

Thanks, this is very helpful - will give this a try Monday or Tuesday.

@dkozma
Copy link
Collaborator

dkozma commented Feb 7, 2024

@clementh59 Still looking into this. Will update when I have more - the minimal repro example you provided definitely makes things easier.

@domguinard
Copy link

Hi @dkozma any news on the issue? Also do let us know if we can do anything to help, anything you'd like us to explore. The extension is gaining quite a bit of momentum and we are eager to make sure it validates things correctly.

@dkozma dkozma removed this from the 2024 Q1 milestone Feb 29, 2024
@clementh59
Copy link
Author

clementh59 commented Mar 19, 2024

Hi @dkozma,

We continued to dig on our side to make it as easy as possible for you to debug it and here are some information that might be useful:

For you to debug, it might be useful to have actual data, so here it is. That's the data I get inside verify_cose_async in cose_validator.rs:

log::info!("Current alg: {:?}", alg);
    
// build result structure
let mut result = ValidationInfo::default();

log::info!("Result: {:?}", result);

// get the cert chain
let certs = get_sign_certs(&sign1)?;

log::info!("Certs: {:?}", certs);

sign1.payload = Some(data.clone()); // restore payload

log::info!("signature payload: {:?}", sign1.payload);

let tbs = sig_structure_data(
    coset::SignatureContext::CoseSign1,
    p_header,
    None,
    &additional_data,
    sign1.payload.as_ref().unwrap_or(&vec![]),
); // get "to be signed" bytes

log::info!("TBS: {:?}", tbs);

[...]

log::info!("result2: {:?}", result);
Ok(result)

I provided a JSON with all the values printed so that you can reproduce it in
your environment easily: logs.json

Also, here is the validation log:

[
   "LogItem"{
      "label":"self#jumbf=/c2pa/adobe:urn:uuid:0ca37023-3dc5-4fee-8541-299998fb6b70/c2pa.signature",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1148",
      "description":"claim signature valid",
      "err_val":"None",
      "validation_status":"Some(""claimSignature.validated"")"
   },
   "LogItem"{
      "label":"self#jumbf=c2pa.assertions/c2pa.thumbnail.claim.jpeg",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=c2pa.assertions/c2pa.thumbnail.claim.jpeg",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=c2pa.assertions/c2pa.thumbnail.ingredient.jpeg",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=c2pa.assertions/c2pa.thumbnail.ingredient.jpeg",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=c2pa.assertions/c2pa.ingredient",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=c2pa.assertions/c2pa.ingredient",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=c2pa.assertions/stds.schema-org.CreativeWork",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=c2pa.assertions/stds.schema-org.CreativeWork",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=c2pa.assertions/c2pa.actions",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=c2pa.assertions/c2pa.actions",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=c2pa.assertions/c2pa.hash.data",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=c2pa.assertions/c2pa.hash.data",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/adobe:urn:uuid:0ca37023-3dc5-4fee-8541-299998fb6b70/c2pa.assertions/c2pa.hash.data",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1311",
      "description":"data hash valid",
      "err_val":"None",
      "validation_status":"Some(""assertion.dataHash.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.signature",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1139",
      "description":"claim signature is not valid",
      "err_val":"Some(""CoseSignature"")",
      "validation_status":"Some(""claimSignature.mismatch"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/com.truepic.libc2pa",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/com.truepic.libc2pa",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/stds.exif",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/stds.exif",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/stds.exif__1",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/stds.exif__1",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/stds.exif__2",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/stds.exif__2",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/c2pa.thumbnail.claim.jpeg",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/c2pa.thumbnail.claim.jpeg",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/com.truepic.custom.odometry",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/com.truepic.custom.odometry",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/com.truepic.custom.blur",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/com.truepic.custom.blur",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   },
   "LogItem"{
      "label":"self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/c2pa.hash.data",
      "file":"/Users/clement-hecquet-evt/Documents/clement/tempo/c2pa-rs/sdk/src/claim.rs",
      "function":"verify_internal",
      "line":"1235",
      "description":"hashed uri matched: self#jumbf=/c2pa/Truepic Lens SDK libc2pa vv1.0.0.182:urn:uuid:d6adaa79-0708-4b7a-9af0-10c7c42a21e5/c2pa.assertions/c2pa.hash.data",
      "err_val":"None",
      "validation_status":"Some(""assertion.hashedURI.match"")"
   }
]

It seems that only the COSE signature is problematic.

I hope it helps!

@dkozma
Copy link
Collaborator

dkozma commented Mar 19, 2024

@clementh59 Thank you for digging into this - I'll go over this with the Rust team shortly.

@dkozma
Copy link
Collaborator

dkozma commented Mar 19, 2024

As far as the issues you are seeing in cose_validator above, do you see it happening from within JavaScript in the extension environment as well as in a web environment or is it just in the extension environment?

Edit: Actually, I see the discrepancy in running in web via extension, and lines up with what you mentioned:

In a browser/web context, the full chain gets validated properly
Screenshot 2024-03-19 at 9 07 26 AM

In the extension code, it validates the first ps256 certificate, then stops at the es256
Screenshot 2024-03-19 at 9 08 45 AM

Continuing to look into this...

@dkozma
Copy link
Collaborator

dkozma commented Mar 19, 2024

@clementh59 Looking into this further, it looks like SubtleCrypto.importKey() cannot be found during verification:
Screenshot 2024-03-19 at 11 41 05 AM

I'm not sure if this is an issue with the extension running this in a web worker - I tried calling these functions manually in the extension console and they seem to work, so I'm not sure what is failing in this context.

@clementh59
Copy link
Author

@dkozma I tried to call this function:

async function importKey(rawKey) {
  try {
    const key = await window.crypto.subtle.importKey(
      "raw", // format of the key to import
      rawKey, // the key in ArrayBuffer format
      {   // algorithm the key will be used with
        name: "AES-CBC",
      },
      false, // whether the key is extractable
      ["encrypt", "decrypt"] // usages the key can be used for
    );

    console.log("Key imported successfully:", key);
    return key;
  } catch (error) {
    console.error("Error importing key:", error);
  }
}

In the same function as I call the c2pa verifications and the function runs correctly. So the issue doesn't seem to be linked to the fact that it is being executed in a web worker...

@clementh59
Copy link
Author

Hi @dkozma, we finally found a workaround for not using the library in a sandbox, which means we are not impacted by this bug anymore.
Thanks anyway for the time you dedicated to this!

@mauricefisher64
Copy link

Thanks for being persistent. We are a small team an do not have access to all possible build targets and platforms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted bug Something isn't working status: todo
Projects
None yet
Development

No branches or pull requests

6 participants