Skip to content

Conversation

ChrisMattew
Copy link
Collaborator

@ChrisMattew ChrisMattew commented Jul 29, 2025

List of Changes

  • Added the @pagopa/io-react-native-iso18013 and jsrsasign packages
  • Upgraded the @pagopa/io-react-native-crypto package
  • Restricted the format type returned by obtainCredential to a union of string literals (dc+sd-jwt and mso_mdoc)
  • Added the x5chain verification and the signature validation for the credentials in mdoc format
  • Added the parsing function for credentials in mdoc format, preserving the namespace while keeping the structure of ParsedCredential unchanged compared to the dc+sd-jwt format
  • Updated the example app and documentation accordingly, based on the changes made in the core library

Motivation and Context

This PR adds support for credentials in mdoc format, integrating the verification and parsing mechanisms for the credential

How to test it?

From the example app, once you have obtained what is needed to request credentials, request the MDL in mdoc format.
The credential verification must succeed (using a proxy tool, verify that after the /credential call, the /pki/ta-sub.crl endpoint is also called).
Once the credential has been obtained, using the debug interface available in the app, make sure that the structure of the parsedCredential matches the example below:

{
 // ...
 "org.iso.18013.5.1:claim_name": {
    "value": "...",
    "name": {
        "it-IT": "...",
        "en-EN": "...",
     }
  }
 // ...
}

Note

The test can be performed in both the PRE and PROD environments.

Demo:

PRE PROD
PRE_mdl_mdoc.mov
PROD_mdl_mdoc.mov

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

@ChrisMattew ChrisMattew self-assigned this Aug 1, 2025
@ChrisMattew ChrisMattew added documentation Improvements or additions to documentation enhancement New feature or request labels Aug 1, 2025
@ChrisMattew ChrisMattew marked this pull request as ready for review August 1, 2025 09:18
@ChrisMattew ChrisMattew requested a review from a team as a code owner August 1, 2025 09:18
@ChrisMattew ChrisMattew requested review from grausof and manuraf August 1, 2025 09:18
Copy link
Contributor

@grausof grausof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work 🎉

Comment on lines 66 to 91
/**
* This function verifies that the signature is valid for all certificates in the x5c chain.
* If not, it throws an error
*
* @param issuerSigned The decoded mdoc
*/
const verifySignatures = async (issuerSigned: CBOR.IssuerSigned) => {
await Promise.all(
issuerSigned.issuerAuth.unprotectedHeader.x5chain!.map(async (cert) => {
const pemcert = convertBase64DerToPem(b64utob64(cert));
const jwk = getSigninJwkFromCert(pemcert);

jwk.x = b64utob64(jwk.x!);
jwk.y = b64utob64(jwk.y!);

console.info(b64utob64(issuerSigned.issuerAuth.rawValue!));

const signatureCorrect = await COSE.verify(
b64utob64(issuerSigned.issuerAuth.rawValue!),
jwk as PublicKey
).catch((e: any) => console.error(e));

if (!signatureCorrect) throw new Error("Invalid mDoc signature");
})
);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The credential is signed only with the public key of the leaf certificate in the chain. Here, we're iterating through all the certificates, verifying the signature with all the public keys (this probably works now because there's only one certificate in the chain). My suggestion is to have a function that verifies the signature, like verifyMdocSignature(token, publicKey), and pass the public key from the caller, which in the example can be retrieved from the leaf certificate (usually the first in the X5c array).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I applied your suggestion! It’s actually working now because there’s only one certificate in the chain.

Let me know if it's ok now

Comment on lines 99 to 114
* This function takes two {@link PublicKey} and evaluates and compares their thumbprints
* @param key1 The first key
* @param key2 The second key
* @returns true if the keys' thumbprints are equal, false otherwise
*/
export const compareKeysByThumbprint = async (
key1: PublicKey,
key2: PublicKey
) => {
//Parallel for optimization
const [thumbprint1, thumbprint2] = await Promise.all([
thumbprint(key1),
thumbprint(key2),
]);
return thumbprint1 === thumbprint2;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already have isSameThumbprint from utils/jwks.ts

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I hadn't noticed there was already a function for that

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed here

const key =
decodedCredential.issuerSigned.issuerAuth.payload.deviceKeyInfo.deviceKey;

if (!isSameThumbprint(key, holderBindingKey as PublicKey)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!isSameThumbprint(key, holderBindingKey as PublicKey)) {
if (!(await isSameThumbprint(key, holderBindingKey as PublicKey))) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Thank you!

@ChrisMattew ChrisMattew merged commit bb499b9 into master Aug 1, 2025
7 checks passed
@ChrisMattew ChrisMattew deleted the SIW-2740-verify-and-parse-mdoc branch August 1, 2025 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request example feat
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants