rust-italia / dgc

A parser and validator for the EU Digital Green Certificate (dgc) a.k.a. greenpass
https://github.com/rust-italia/dgc
MIT License
26 stars 11 forks source link

Support kid in unprotected header #1

Closed lmammino closed 2 years ago

lmammino commented 2 years ago

Test file common/2DCode/raw/CO20.json fails because the KID is saved in the unprotected header rather than in the protected header of the COSE payload.

Apparently this is perfectly valid behaviour and the signature should use the KID in the unprotected header (if there is none in the protected header).

test data:

{
    "CBOR": "bf6376657265312e322e31636e616dbf62666e754d7573746572667261752d47c3b6c39f696e67657263666e74754d5553544552465241553c474f455353494e47455262676e684761627269656c6563676e74684741425249454c45ff63646f626a313939382d30322d3236617481bf62746769383430353339303036627474684c50363436342d34626e6d76526f636865204c696768744379636c6572207150435262736374323032312d30322d32305431323a33343a35365a627472693236303431353030306274637754657374696e672063656e746572205669656e6e61203162636f624154626973781b4d696e6973747279206f66204865616c74682c2041757374726961626369783155524e3a555643493a30313a41543a42353932314133354436413044363936343231423345323436323137383239372349ffff",
    "COSE": "d28440a204483248bc38d9547e630126590154a4041a6092dd20061a60903a2001624154390103a101a4617481a962736374323032312d30322d32305431323a33343a35365a627474684c50363436342d34626e6d76526f636865204c696768744379636c657220715043526274637754657374696e672063656e746572205669656e6e61203162636f624154626369783155524e3a555643493a30313a41543a42353932314133354436413044363936343231423345323436323137383239372349626973781b4d696e6973747279206f66204865616c74682c20417573747269616274676938343035333930303662747269323630343135303030636e616da463666e74754d5553544552465241553c474f455353494e47455262666e754d7573746572667261752d47c3b6c39f696e67657263676e74684741425249454c4562676e684761627269656c656376657265312e322e3163646f626a313939382d30322d323658405272eaa283596735aac167d1f8ae95253c70cbcb60c98006514ee02ca315f83a35dd2b7983b7980ecec645cef705b1913aac525034db103e2668d1c6f31e5ee8",
    "PREFIX": "HC1:NCFRY37C8OJ2500S6C+QDGTSB4J7F6T6VKOA7+4RZQY8AGTJF.R5LIE05*ICA79*5PB7UQYES-DT$D+95E:V5E5D7S8OJEG4203+AF-G8%E1LJF-A5UR2-+3GNQOYT:CFBPU5Y74-76RLFVT7UQI8DNH7KPDAT6GQJ1*7YL0AXM6.4+77%4IKDT-L5CH2H19  OCHBV96668FDO%I8UT2ITE8Y74$DC3E4H82EGBWMH-PFG64EK:UIT/ANQMGI6N0RE9EM:S/ZKV.AGO0: CW5QPHB7I2*T4434AE2BDU5$19RMVLD52PEKCN*O*2M0HI%VE3BLU3B5:8E/8GKCQA1QAD6ZG4/O4Z677HN0BFURLKKO3PGDQ1YAQCVDF7I+V:$5G 2 JQDG0YLK984QJN4C1CJERZGSZO-M2YM69-QS$M6DGMSS*1D7ZN*%M/-M1435KQ%SKJ2KWOMF%2+G1JOSVWO7OV5.I$*OBV61YP**2DK0*AJ:WHB1L-4CI%DBC5V8G/BIJ36F T2YUPEWBOKW6J2AV/8CNX5JBS1C9PCQT28+4O5GF8.RWTV/SVO$U$/V/HJ/6TZ.RLCUPLFQPT 35COVGPUTRA+1I/FP3VP DT:XQF08EFUHRVZ$2Y%I",
    "TESTCTX": {
        "VERSION": 1,
        "SCHEMA": "1.0.0",
        "CERTIFICATE": "MIIBVzCB/6ADAgECAgRzLoFUMAoGCCqGSM49BAMCMBAxDjAMBgNVBAMMBUVDLU1lMB4XDTIxMDUwMzE4MDAwMFoXDTIxMDYwMjE4MDAwMFowEDEOMAwGA1UEAwwFRUMtTWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQkI7eQFjMDlzlZE76ey3MxeRRXqe19Gz5zI534UOGwz0uk3rC1lzMRKFjlMYqi/vEbZerv5xjysRnzhyo1P/P9o0cwRTAOBgNVHQ8BAf8EBAMCBaAwMwYDVR0lBCwwKgYMKwYBBAEAjjePZQEBBgwrBgEEAQCON49lAQIGDCsGAQQBAI43j2UBAzAKBggqhkjOPQQDAgNHADBEAiBS0ew1ZTfhrMdiOqGuSiRAe9kpg9jNZoHBICd0rAEjvQIgeFUhq00LEJHST3StBaww1NrZpEyYgh7XeC5ZK7UbRDE=",
        "VALIDATIONCLOCK": "2021-05-03T18:00:00Z",
        "DESCRIPTION": "VALID: KID in protected header correct, KID in unprotected header correct"
    },
    "EXPECTEDRESULTS": {
        "EXPECTEDVERIFY": true
    }
}
lmammino commented 2 years ago

NOTE: This should be done also for alg

lmammino commented 2 years ago

I had a quick stab at this one and I bumped into this other test case:

tests/data/common/2DCode/raw/CO22.json

{
    "CBOR": "bf6376657265312e322e31636e616dbf62666e754d7573746572667261752d47c3b6c39f696e67657263666e74754d5553544552465241553c474f455353494e47455262676e684761627269656c6563676e74684741425249454c45ff63646f626a313939382d30322d3236617481bf62746769383430353339303036627474684c50363436342d34626e6d76526f636865204c696768744379636c6572207150435262736374323032312d30322d32305431323a33343a35365a627472693236303431353030306274637754657374696e672063656e746572205669656e6e61203162636f624154626973781b4d696e6973747279206f66204865616c74682c2041757374726961626369783155524e3a555643493a30313a41543a42353932314133354436413044363936343231423345323436323137383239372349ffff",
    "COSE": "d28446a10443666f6fa20448f818bebd44ff0fb60126590154a4041a6092dd20061a60903a2001624154390103a101a4617481a962736374323032312d30322d32305431323a33343a35365a627474684c50363436342d34626e6d76526f636865204c696768744379636c657220715043526274637754657374696e672063656e746572205669656e6e61203162636f624154626369783155524e3a555643493a30313a41543a42353932314133354436413044363936343231423345323436323137383239372349626973781b4d696e6973747279206f66204865616c74682c20417573747269616274676938343035333930303662747269323630343135303030636e616da463666e74754d5553544552465241553c474f455353494e47455262666e754d7573746572667261752d47c3b6c39f696e67657263676e74684741425249454c4562676e684761627269656c656376657265312e322e3163646f626a313939382d30322d323658409617cd3bd816b1a1c7ecc170e7d7f36329ffc44de58d99770b525f4ce6ff72141335804df3f1ecd0c17bae2af2931ee318eb3009e19310cf36eade63a79da093",
    "PREFIX": "HC1:NCFOXNXTSQDICA7A18 92J7P7HH QFHAWU3E/UA7TCSFBXG4B86-:LTSJXNOXJ592PK7PAN9I6T5XH3E2%E3T 4A05423423ZQTW63LD3LVG+E3UA319BSMJ X48YI.FV5DJ5DJBIT+T441TOX07:4-XK3IVT1L9XIZ0BZCT3 2-N2X37 X47S4T6HN%20YCS*KNS4Y6T/20KUOQRA5RUXT2NTICZU:Z2ZW4Z*AK.GNNVR*G0C7PHBO33BC7+6BIHJLD3OF7-UJ:AJ0H3VBJMOJ423NF7ITNZIJZ735NJN332MJQPF3ZCO1B8ZVV5TN%2UP20J5/5LEBFD-48YIWFT-67-C0*E6-RI PQVW5/O16%HAT1Z%P.8GM+8:Y001HCY0R%0IGF5JNCPIGSUYI93O89N86UG8KGQN88.R: BRQG84W: BBPIGSU:%F-/C$%2DU2O3J$NNP5S29FPIQ/HLTNP8EFNC3P:HDD8B1MM1M9NTNC30GH.Z8VHL+KLF%CD 810H.+8Z1HZD5CC9T0H$/I*HSOH6OAE:%4:7R52HG4P2CPCP3LAF%1WXRMKBWT2O1RF+0J9:0BYV1ZVPP4BYD+JSQQV1RJS/0KARO*F U5TABW*MLDTNIPVDTU:BYN9G+78KOT50SDVV0",
    "TESTCTX": {
        "VERSION": 1,
        "SCHEMA": "1.0.0",
        "CERTIFICATE": "MIIBWDCB/6ADAgECAgQkAvVZMAoGCCqGSM49BAMCMBAxDjAMBgNVBAMMBUVDLU1lMB4XDTIxMDUwMzE4MDAwMFoXDTIxMDYwMjE4MDAwMFowEDEOMAwGA1UEAwwFRUMtTWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATBI2PXG75hBJ/waeZPXCStOm1AB5VTB2rsKEz7kgrlYNWgJqV9LJzVB+moIrGZqmhmcWXGXzc+YwWb4TBNk7reo0cwRTAOBgNVHQ8BAf8EBAMCBaAwMwYDVR0lBCwwKgYMKwYBBAEAjjePZQEBBgwrBgEEAQCON49lAQIGDCsGAQQBAI43j2UBAzAKBggqhkjOPQQDAgNIADBFAiEAv7k643O/MebICElvO9Ke2Q/ECEvuoyZ6G2qfexoWnUkCIBUzkfOv8LyYaB/bBQwISRUo9aFotPeaULaLbO6wX1sF",
        "VALIDATIONCLOCK": "2021-05-03T18:00:00Z",
        "DESCRIPTION": "INVALID: KID in protected header not correct, KID in unprotected header correct"
    },
    "EXPECTEDRESULTS": {
        "EXPECTEDVERIFY": false
    }
}

Note the DESCRIPTION:

INVALID: KID in protected header not correct, KID in unprotected header correct

And the EXPECTEDVERIFY (false).

In my initial draft implementation i was overriding the kid from the protected header, with the kid in the unprotected header.

I guess this logic should be reversed....

lmammino commented 2 years ago

I also realised that this last case is a bit hard to test. There is no explicit KID in the test data, so the current implementation assigned to the test public key certificate is the one found in the CWT header.

I found this interesting comment:

[...] The kid is defined as the first 8 bytes of the SHA256 hash of the certificate.

This should allow us to pre-compute the test KID and this way we don't have to guess what that is. This way we should be in a position to test against invalid KIDs.