Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A look inside the European Covid Green Certificate (Codemotion 2021)

A look inside the European Covid Green Certificate (Codemotion 2021)

When I saw how dense the European Covid Green Pass QR code is, I got immediately curious: "WOW, there must be a lot of interesting data in here". So, I started to dig deeper and I found that there's really a great wealth of interesting encoding and verification technologies being used in it! In this talk, I will share what I learned! We will go on a journey where we will explore Base54 encoding, COSE tokens, CBOR serialization, elliptic curve crypto, and much more! Finally, I will also show you how to write a decoder for Green Pass certificates in the most hyped language ever: Rust!

F3a6662b3cd161c3c2f13604965ed0f2?s=128

Luciano Mammino

December 01, 2021
Tweet

More Decks by Luciano Mammino

Other Decks in Technology

Transcript

  1. A look inside the European Covid Green Certificate Luciano Mammino

    ( ) @loige 2021-12-01 loige.link/green 1
  2. Get these slides! loige loige.link/green 2

  3. Let me introduce myself first... 3

  4. Let me introduce myself first... 👋 I'm Luciano ( 🍕🍝)

    3
  5. Let me introduce myself first... 👋 I'm Luciano ( 🍕🍝)

    Senior Architect @ fourTheorem (Dublin ) 3
  6. Let me introduce myself first... 👋 I'm Luciano ( 🍕🍝)

    Senior Architect @ fourTheorem (Dublin ) nodejsdp.link 📔 Co-Author of Node.js Design Patterns 👉 3
  7. Let me introduce myself first... 👋 I'm Luciano ( 🍕🍝)

    Senior Architect @ fourTheorem (Dublin ) nodejsdp.link 📔 Co-Author of Node.js Design Patterns 👉 Let's connect! (blog) (twitter) (twitch) (github) loige.co @loige loige lmammino 3
  8. We are business focused technologists that deliver. | | Accelerated

    Serverless AI as a Service Platform Modernisation We are hiring: do you want to ? work with us loige 4
  9. Disclaimers loige 5

  10. Disclaimers loige 🤓 I am not involved with the DGC

    working group 5
  11. Disclaimers loige 🤓 I am not involved with the DGC

    working group 😢 COVID has been tough on everyone, we'll try to focus only on the tech here! 5
  12. Agenda + Goals loige 6

  13. Agenda + Goals loige 1. Needs and principles 2. 🗝

    Cryptographic model 3. 📦 The data 4. 🧅 Layers of encoding 5. 🛠 Decoding in Rust 6
  14. Agenda + Goals loige 1. Needs and principles 2. 🗝

    Cryptographic model 3. 📦 The data 4. 🧅 Layers of encoding 5. 🛠 Decoding in Rust 🤨 Learn some cool technologies 🧐 Learn a tiny bit of Rust 🤓 Be nerdy and have fun! 6
  15. The need for a digital certificate in the COVID age

    loige 7
  16. The need for a digital certificate in the COVID age

    loige 8
  17. The need for a digital certificate in the COVID age

    loige 😷 We need a system to quickly provide a proof against COVID (Vaccination, negative test, proof of recovery) 8
  18. The need for a digital certificate in the COVID age

    loige 😷 We need a system to quickly provide a proof against COVID (Vaccination, negative test, proof of recovery) It needs to be personal, easy to carry around (digital), easy to issue and to validate 8
  19. The need for a digital certificate in the COVID age

    loige 😷 We need a system to quickly provide a proof against COVID (Vaccination, negative test, proof of recovery) It needs to be personal, easy to carry around (digital), easy to issue and to validate 🌎 It needs to be secure against forgery and work across countries 8
  20. The EU Covid Green Pass a.k.a. Electronic Health Certificates (HCERT)

    loige.link/hcert-spec loige 9
  21. Electronic Health Certificates (HCERT) Requirements & Guiding Principles loige 10

  22. Electronic Health Certificates (HCERT) Requirements & Guiding Principles loige ✍

    Signed data with machine readable content 10
  23. Electronic Health Certificates (HCERT) Requirements & Guiding Principles loige ✍

    Signed data with machine readable content 📃 Use compact encoding 10
  24. Electronic Health Certificates (HCERT) Requirements & Guiding Principles loige ✍

    Signed data with machine readable content 📃 Use compact encoding 🤲 Based on open standards 10
  25. Asymmetric cryptographic signatures loige 11

  26. Asymmetric cryptographic signatures loige 🤫 Private Key 101010101000101010010... 11

  27. Asymmetric cryptographic signatures loige 🤫 Private Key 📢 Public Key

    101010101000101010010... 0101010101010101010101... 11
  28. Asymmetric cryptographic signatures loige 🤫 Private Key 📢 Public Key

    🔗 101010101000101010010... 0101010101010101010101... 11
  29. Asymmetric cryptographic signatures loige 🤫 Private Key 📢 Public Key

    101010101000101010010... 0101010101010101010101... 12
  30. Asymmetric cryptographic signatures loige 🤫 Private Key 📢 Public Key

    101010101000101010010... 0101010101010101010101... 12
  31. Asymmetric cryptographic signatures loige 🤫 Private Key 📢 Public Key

    101010101000101010010... 0101010101010101010101... The owner of the private key signs the document 12
  32. Asymmetric cryptographic signatures loige 🤫 Private Key 📢 Public Key

    101010101000101010010... 0101010101010101010101... The owner of the private key signs the document 12
  33. Asymmetric cryptographic signatures loige 🤫 Private Key 📢 Public Key

    101010101000101010010... 0101010101010101010101... The owner of the private key signs the document Anyone can validate the signature using the public key 12
  34. Asymmetric cryptographic signatures loige 🤫 Private Key 📢 Public Key

    101010101000101010010... 0101010101010101010101... The owner of the private key signs the document Anyone can validate the signature using the public key 12
  35. What's inside a certificate? loige 13

  36. What's inside a certificate? loige 13

  37. What's inside a certificate? loige Cryptographic header (Key Id, Algorithm)

    13
  38. What's inside a certificate? loige DGC container Cryptographic header (Key

    Id, Algorithm) 13
  39. What's inside a certificate? loige DGC container Cryptographic header (Key

    Id, Algorithm) Cryptographic Signature 13
  40. What's inside a certificate? loige DGC container Cryptographic header (Key

    Id, Algorithm) Cryptographic Signature Header (Issuer, Issue date, expiry date) 13
  41. What's inside a certificate? loige DGC container Cryptographic header (Key

    Id, Algorithm) Cryptographic Signature Header (Issuer, Issue date, expiry date) 13 Certificates list Personal data (name, surname, DoB)
  42. What's inside a certificate? loige DGC container Cryptographic header (Key

    Id, Algorithm) Cryptographic Signature Header (Issuer, Issue date, expiry date) 13 Certificates list vaccine, test, or recovery data Personal data (name, surname, DoB)
  43. An example loige loige.link/green-examples 14

  44. An example loige loige.link/green-examples 15

  45. { "1": "DK", "4": 1625054000, "6": 1622462000, "-260": { "ver":"1.0.0",

    "nam":{ "fn":"Klaus", "fnt":"KLAUS", "gn":"Jørgensen", "gnt":"JOERGENSEN" }, "dob":"1983-01-06", "v":[ { "tg":"840539006", "vp":"1119349007", "mp":"EU/1/20/1528", "ma":"ORG-100030215", "dn":2, "sd":2, "dt":"2021-05-03", "co":"DK", "is":"Danish Health Data Authority", "ci":"URN:UVCI:01:DK:B986830007345F99AE898FB82C6C61F2#A" } ] } } An example loige loige.link/green-examples 15
  46. { "1": "DK", "4": 1625054000, "6": 1622462000, "-260": { "ver":"1.0.0",

    "nam":{ "fn":"Klaus", "fnt":"KLAUS", "gn":"Jørgensen", "gnt":"JOERGENSEN" }, "dob":"1983-01-06", "v":[ { "tg":"840539006", "vp":"1119349007", "mp":"EU/1/20/1528", "ma":"ORG-100030215", "dn":2, "sd":2, "dt":"2021-05-03", "co":"DK", "is":"Danish Health Data Authority", "ci":"URN:UVCI:01:DK:B986830007345F99AE898FB82C6C61F2#A" } ] } } An example loige loige.link/green-examples DGC Header 15
  47. { "1": "DK", "4": 1625054000, "6": 1622462000, "-260": { "ver":"1.0.0",

    "nam":{ "fn":"Klaus", "fnt":"KLAUS", "gn":"Jørgensen", "gnt":"JOERGENSEN" }, "dob":"1983-01-06", "v":[ { "tg":"840539006", "vp":"1119349007", "mp":"EU/1/20/1528", "ma":"ORG-100030215", "dn":2, "sd":2, "dt":"2021-05-03", "co":"DK", "is":"Danish Health Data Authority", "ci":"URN:UVCI:01:DK:B986830007345F99AE898FB82C6C61F2#A" } ] } } An example loige loige.link/green-examples Personal info DGC Header 15
  48. { "1": "DK", "4": 1625054000, "6": 1622462000, "-260": { "ver":"1.0.0",

    "nam":{ "fn":"Klaus", "fnt":"KLAUS", "gn":"Jørgensen", "gnt":"JOERGENSEN" }, "dob":"1983-01-06", "v":[ { "tg":"840539006", "vp":"1119349007", "mp":"EU/1/20/1528", "ma":"ORG-100030215", "dn":2, "sd":2, "dt":"2021-05-03", "co":"DK", "is":"Danish Health Data Authority", "ci":"URN:UVCI:01:DK:B986830007345F99AE898FB82C6C61F2#A" } ] } } An example loige loige.link/green-examples Personal info Vaccine info DGC Header 15
  49. Layered encoding loige 16 🧅

  50. Layered encoding loige QRCODE ASCII mode 16 🧅

  51. Layered encoding loige QRCODE ASCII mode Prefix + Base45 encoding

    16 🧅
  52. Layered encoding loige QRCODE ASCII mode Prefix + Base45 encoding

    Zlib compression 16 🧅
  53. Layered encoding loige QRCODE ASCII mode Prefix + Base45 encoding

    Zlib compression CWT signed data (COSE) 16 🧅
  54. Layered encoding loige QRCODE ASCII mode Prefix + Base45 encoding

    Zlib compression CWT signed data (COSE) CBOR document 16 🧅
  55. loige QRCode content 17

  56. loige HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-36 5KN-TMLV4.P7*ZOP-IMJTI94F/8X*G3M9JUPY0BZW4Z *AK.GNNVR*G0C7PHBO335KN/NBEDBVBJ623323EAJ7U J5PNDIB6PNS7B1DN%BBWC7WC7GB3683ML7SZ4ZI00T9 UKPSH9WC5PF6846A$Q 76QW6A/98T5WBI$E9$UPV3Q. GUQ$9WC5R7ACB97C968ELZ5$DP6PP5IL*PP:+P*.1D9 R8Q02-DE%QHOJ+PB/VSQOL9DLKWCZ3EBKDYGIZ J$XI

    4OIMEDTJCJKDLEDL9CZTAKBI/8D:8DKTDL+SQ05.$S6 ZC0JBY63-C3F+LBQ99Q9E$BDZIA9JJ-JS7BYZJ92KG0 TB9FNDA5KD9FED.B4JB3E9B9NNPCV9E6LFSD9C8J-QD SWNG4C-TLNKE$JDVPLW1KD0KCZGBKQCJE%RH5WAMSSR $F-75NXONQ84QV9/7/-LT1AIYBZGD$9RCLV-PTZ-K63 ET-D1757H3GF9MV2N7WNQSY1SBZT-:81JJLHFQ-VG$H K00XWPD2 QRCode content 17
  57. loige HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-36 5KN-TMLV4.P7*ZOP-IMJTI94F/8X*G3M9JUPY0BZW4Z *AK.GNNVR*G0C7PHBO335KN/NBEDBVBJ623323EAJ7U J5PNDIB6PNS7B1DN%BBWC7WC7GB3683ML7SZ4ZI00T9 UKPSH9WC5PF6846A$Q 76QW6A/98T5WBI$E9$UPV3Q. GUQ$9WC5R7ACB97C968ELZ5$DP6PP5IL*PP:+P*.1D9 R8Q02-DE%QHOJ+PB/VSQOL9DLKWCZ3EBKDYGIZ J$XI

    4OIMEDTJCJKDLEDL9CZTAKBI/8D:8DKTDL+SQ05.$S6 ZC0JBY63-C3F+LBQ99Q9E$BDZIA9JJ-JS7BYZJ92KG0 TB9FNDA5KD9FED.B4JB3E9B9NNPCV9E6LFSD9C8J-QD SWNG4C-TLNKE$JDVPLW1KD0KCZGBKQCJE%RH5WAMSSR $F-75NXONQ84QV9/7/-LT1AIYBZGD$9RCLV-PTZ-K63 ET-D1757H3GF9MV2N7WNQSY1SBZT-:81JJLHFQ-VG$H K00XWPD2 QRCode content "HC1:" (prefix) 17
  58. loige HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-36 5KN-TMLV4.P7*ZOP-IMJTI94F/8X*G3M9JUPY0BZW4Z *AK.GNNVR*G0C7PHBO335KN/NBEDBVBJ623323EAJ7U J5PNDIB6PNS7B1DN%BBWC7WC7GB3683ML7SZ4ZI00T9 UKPSH9WC5PF6846A$Q 76QW6A/98T5WBI$E9$UPV3Q. GUQ$9WC5R7ACB97C968ELZ5$DP6PP5IL*PP:+P*.1D9 R8Q02-DE%QHOJ+PB/VSQOL9DLKWCZ3EBKDYGIZ J$XI

    4OIMEDTJCJKDLEDL9CZTAKBI/8D:8DKTDL+SQ05.$S6 ZC0JBY63-C3F+LBQ99Q9E$BDZIA9JJ-JS7BYZJ92KG0 TB9FNDA5KD9FED.B4JB3E9B9NNPCV9E6LFSD9C8J-QD SWNG4C-TLNKE$JDVPLW1KD0KCZGBKQCJE%RH5WAMSSR $F-75NXONQ84QV9/7/-LT1AIYBZGD$9RCLV-PTZ-K63 ET-D1757H3GF9MV2N7WNQSY1SBZT-:81JJLHFQ-VG$H K00XWPD2 QRCode content "HC1:" (prefix) Binary data encoded in Base45 17
  59. Base45 loige 18

  60. loige Base45 19

  61. loige Allows to encode binary data in text format (ASCII)

    Base45 19
  62. loige Allows to encode binary data in text format (ASCII)

    Like Base64, but it uses 45 characters instead: Base45 19
  63. loige Allows to encode binary data in text format (ASCII)

    Like Base64, but it uses 45 characters instead: loige.link/base45-explained Base45 19
  64. Base45 loige 20

  65. Base45 loige 01001001 00100000 01100111 01101111 01110100 00100000 01101101 01111001

    00100000 01110011 01101000 01101111 01110100 01110011 00100000 11011000 00111101 Some binary data 20
  66. Base45 loige 01001001 00100000 01100111 01101111 01110100 00100000 01101101 01111001

    00100000 01110011 01101000 01101111 01110100 01110011 00100000 11011000 00111101 Some binary data 20
  67. Base45 loige 01001001 00100000 01100111 01101111 01110100 00100000 01101101 01111001

    00100000 01110011 01101000 01101111 01110100 01110011 00100000 11011000 00111101 UTF8 (17 bytes) I got my shots 💉 Some binary data 20
  68. Base45 loige 01001001 00100000 01100111 01101111 01110100 00100000 01101101 01111001

    00100000 01110011 01101000 01101111 01110100 01110011 00100000 11011000 00111101 UTF8 (17 bytes) I got my shots 💉 Hex (38 bytes) 49 20 67 6f 74 20 6d 79 20 73 68 6f 74 73 20 f0 9f 92 89 Some binary data 20
  69. Base45 loige 01001001 00100000 01100111 01101111 01110100 00100000 01101101 01111001

    00100000 01110011 01101000 01101111 01110100 01110011 00100000 11011000 00111101 UTF8 (17 bytes) I got my shots 💉 Hex (38 bytes) 49 20 67 6f 74 20 6d 79 20 73 68 6f 74 73 20 f0 9f 92 89 Base64 (28 bytes) SSBnb3QgbXkgc2hvdHMg8J+SiQ== Some binary data 20
  70. Base45 loige 01001001 00100000 01100111 01101111 01110100 00100000 01101101 01111001

    00100000 01110011 01101000 01101111 01110100 01110011 00100000 11011000 00111101 UTF8 (17 bytes) I got my shots 💉 Hex (38 bytes) 49 20 67 6f 74 20 6d 79 20 73 68 6f 74 73 20 f0 9f 92 89 Base64 (28 bytes) SSBnb3QgbXkgc2hvdHMg8J+SiQ== Base45 (29 bytes) 0B9J3DSUEZ$DR4459DLWEH74Z7K23 Some binary data 20
  71. loige loige.link/base45-rfc "A QR-code is used to encode text as

    a graphical image. [...] QR-codes cannot be used to encode arbitrary binary data directly. [...] Compared to already established Base64, Base32 and Base16 encoding schemes [...], the Base45 scheme described in this document offer a more compact QR-code encoding" Base45 21
  72. loige Base45 22

  73. loige Base45 NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN- TMLV4.P7*ZOP-IMJTI94F/8X*G3M9JUPY0BZW4Z*AK. GNNVR*G0C7PHBO335KN/NBEDBVBJ623323EAJ7UJ5PN DIB6PNS7B1DN%BBWC7WC7GB3683ML7SZ4ZI00T9UKPS H9WC5PF6846A$Q 76QW6A/98T5WBI$E9$UPV3Q.GUQ$ 9WC5R7ACB97C968ELZ5$DP6PP5IL*PP:+P*.1D9R8Q0 2-DE%QHOJ+PB/VSQOL9DLKWCZ3EBKDYGIZ

    J$XI4OIM EDTJCJKDLEDL9CZTAKBI/8D:8DKTDL+SQ05.$S6ZC0J BY63-C3F+LBQ99Q9E$BDZIA9JJ-JS7BYZJ92KG0TB9F NDA5KD9FED.B4JB3E9B9NNPCV9E6LFSD9C8J-QDSWNG 4C-TLNKE$JDVPLW1KD0KCZGBKQCJE%RH5WAMSSR$F-7 5NXONQ84QV9/7/-LT1AIYBZGD$9RCLV-PTZ-K63ET-D 1757H3GF9MV2N7WNQSY1SBZT-:81JJLHFQ-VG$HK00X WPD2 22
  74. loige Base45 NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN- TMLV4.P7*ZOP-IMJTI94F/8X*G3M9JUPY0BZW4Z*AK. GNNVR*G0C7PHBO335KN/NBEDBVBJ623323EAJ7UJ5PN DIB6PNS7B1DN%BBWC7WC7GB3683ML7SZ4ZI00T9UKPS H9WC5PF6846A$Q 76QW6A/98T5WBI$E9$UPV3Q.GUQ$ 9WC5R7ACB97C968ELZ5$DP6PP5IL*PP:+P*.1D9R8Q0 2-DE%QHOJ+PB/VSQOL9DLKWCZ3EBKDYGIZ

    J$XI4OIM EDTJCJKDLEDL9CZTAKBI/8D:8DKTDL+SQ05.$S6ZC0J BY63-C3F+LBQ99Q9E$BDZIA9JJ-JS7BYZJ92KG0TB9F NDA5KD9FED.B4JB3E9B9NNPCV9E6LFSD9C8J-QDSWNG 4C-TLNKE$JDVPLW1KD0KCZGBKQCJE%RH5WAMSSR$F-7 5NXONQ84QV9/7/-LT1AIYBZGD$9RCLV-PTZ-K63ET-D 1757H3GF9MV2N7WNQSY1SBZT-:81JJLHFQ-VG$HK00X WPD2 Base45 Decode 22
  75. loige Base45 NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN- TMLV4.P7*ZOP-IMJTI94F/8X*G3M9JUPY0BZW4Z*AK. GNNVR*G0C7PHBO335KN/NBEDBVBJ623323EAJ7UJ5PN DIB6PNS7B1DN%BBWC7WC7GB3683ML7SZ4ZI00T9UKPS H9WC5PF6846A$Q 76QW6A/98T5WBI$E9$UPV3Q.GUQ$ 9WC5R7ACB97C968ELZ5$DP6PP5IL*PP:+P*.1D9R8Q0 2-DE%QHOJ+PB/VSQOL9DLKWCZ3EBKDYGIZ

    J$XI4OIM EDTJCJKDLEDL9CZTAKBI/8D:8DKTDL+SQ05.$S6ZC0J BY63-C3F+LBQ99Q9E$BDZIA9JJ-JS7BYZJ92KG0TB9F NDA5KD9FED.B4JB3E9B9NNPCV9E6LFSD9C8J-QDSWNG 4C-TLNKE$JDVPLW1KD0KCZGBKQCJE%RH5WAMSSR$F-7 5NXONQ84QV9/7/-LT1AIYBZGD$9RCLV-PTZ-K63ET-D 1757H3GF9MV2N7WNQSY1SBZT-:81JJLHFQ-VG$HK00X WPD2 Base45 Decode Compressed binary data 22
  76. Zlib compression loige 23

  77. Zlib compression loige "zlib is designed to be a free,

    general-purpose, legally unencumbered -- that is, not covered by any patents -- lossless data-compression library for use on virtually any computer hardware and operating system" zlib.net 24
  78. Zlib compression loige 25

  79. Zlib compression loige Compressed binary data 25

  80. Zlib compression loige Zlib inflate Compressed binary data 25

  81. Zlib compression loige Zlib inflate Compressed binary data Decompressed binary

    data 25
  82. Zlib compression loige 26

  83. Zlib compression loige 26

  84. Zlib compression loige 👀 We start to see some "readable"

    information! 26
  85. COSE / CWT loige CBOR Object Signing and Encryption /

    CBOR Web Token 27
  86. CBOR !? 🤔 loige But wait, what the heck is

    ✋ 28
  87. CBOR loige TLDR; Like JSON but in binary! loige.link/cbor-rfc 29

  88. JSON loige A schema-less data format where a value can

    be: Null Boolean Number String Array Object null true -17.34 "A programmer walks into a bar..." ["foo", 1.23, null, false, [22]] {"foo": "bar", "manyvals": [1,2,3], "nested": {}} 30
  89. CBOR loige A schema-less binary data format where a value

    can be: Null Boolean Number String Text Array Object Map F6 F5 fbc031570a3d70a3d7 7820412070726f6772616d6d65722077616c6b7320696e746f2061206261722e2e2e 8563666f6ffb3ff3ae147ae147aef6f48116 a363666f6f63626172686d616e7976616c7383010203666e6573746564a0 31
  90. CBOR loige It also supports: Byte String (a sequence of

    raw bytes) Tags (annotations that allow to create new types) 32
  91. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 33
  92. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { } 33
  93. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { "foo": } 33
  94. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { "foo": "bar", } 33
  95. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { "foo": "bar", "manyvals": } 33
  96. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { "foo": "bar", "manyvals": [ } ], 33
  97. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { "foo": "bar", "manyvals": [ } ], 1, 33
  98. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { "foo": "bar", "manyvals": [ } ], 1, 2, 33
  99. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { "foo": "bar", "manyvals": [ } ], 1, 2, 3 33
  100. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { "foo": "bar", "manyvals": [ } ], "nested": 1, 2, 3 33
  101. CBOR loige An example: A3 63666F6F 63626172 686D616E7976616C73 83 01

    02 03 666E6573746564 A0 { "foo": "bar", "manyvals": [ } ], "nested": {} 1, 2, 3 33
  102. COSE / CWT loige CBOR Object Signing and Encryption /

    CBOR Web Token ok... again 😅 34
  103. COSE loige CBOR Object Signing and Encryption 35

  104. COSE loige CBOR Object Signing and Encryption COSE (inspired by

    ) defines CBOR-based protocols for: JOSE 35
  105. COSE loige CBOR Object Signing and Encryption COSE (inspired by

    ) defines CBOR-based protocols for: JOSE Encrypted data 35
  106. COSE loige CBOR Object Signing and Encryption COSE (inspired by

    ) defines CBOR-based protocols for: JOSE Encrypted data Cryptographic signed data 35
  107. COSE loige CBOR Object Signing and Encryption COSE (inspired by

    ) defines CBOR-based protocols for: JOSE Encrypted data Cryptographic signed data MACed data 35
  108. COSE loige loige.link/cose-rfc CBOR Object Signing and Encryption COSE (inspired

    by ) defines CBOR-based protocols for: JOSE Encrypted data Cryptographic signed data MACed data 35
  109. CWT loige CBOR Web Token 36

  110. CWT loige Like but for CBOR JWT CBOR Web Token

    36
  111. CWT loige Like but for CBOR JWT Defines a protocol

    for transferring claims between parties CBOR Web Token 36
  112. CWT loige Like but for CBOR JWT Defines a protocol

    for transferring claims between parties CBOR Web Token Claims are digitally signed for authenticity 36
  113. CWT loige Like but for CBOR JWT loige.link/cwt-rfc Defines a

    protocol for transferring claims between parties CBOR Web Token Claims are digitally signed for authenticity 36
  114. CWT loige CBOR Web Token 37

  115. CWT loige A CWT is made of 4 parts: CBOR

    Web Token 37
  116. CWT loige A CWT is made of 4 parts: Protected

    header CBOR Web Token 37
  117. CWT loige A CWT is made of 4 parts: Protected

    header CBOR Web Token Non protected header 37
  118. CWT loige A CWT is made of 4 parts: Protected

    header CBOR Web Token Non protected header Payload 37
  119. CWT loige A CWT is made of 4 parts: Protected

    header CBOR Web Token Non protected header Payload Signature 37
  120. CWT loige A CWT is encoded as a (tagged) CBOR

    array with 4 values: Protected header (binary string) CBOR Web Token Non protected header (map) Payload (binary string) Signature (binary string) 38
  121. loige 39

  122. loige 39

  123. loige CWT tag 39

  124. loige CWT tag 39

  125. loige Array (length 4) CWT tag 39

  126. loige Array (length 4) CWT tag 39

  127. Protected header Binary String loige Array (length 4) CWT tag

    39
  128. Protected header Binary String loige Array (length 4) CWT tag

    39
  129. Protected header Binary String loige Array (length 4) CWT tag

    39 Unprotected header Map (length 0)
  130. Protected header Binary String loige Array (length 4) CWT tag

    39 Unprotected header Map (length 0)
  131. Protected header Binary String loige Array (length 4) CWT tag

    39 Unprotected header Map (length 0) Payload Binary String
  132. Protected header Binary String loige Array (length 4) CWT tag

    39 Unprotected header Map (length 0) Payload Binary String
  133. Protected header Binary String loige Array (length 4) CWT tag

    39 Unprotected header Map (length 0) Payload Binary String Signature Binary String
  134. loige CWT payload 40

  135. loige CWT payload 40

  136. loige CWT payload Binary String follows (CBOR Encoded) 40

  137. loige CWT payload { "1": "DK", "4": 1625054000, "6": 1622462000,

    "-260": { "ver":"1.0.0", "nam":{ "fn":"Klaus", "fnt":"KLAUS", "gn":"Jørgensen", "gnt":"JOERGENSEN" }, "dob":"1983-01-06", "v":[ { "tg":"840539006", "vp":"1119349007", "mp":"EU/1/20/1528", "ma":"ORG-100030215", "dn":2, "sd":2, "dt":"2021-05-03", "co":"DK", "is":"Danish Health Data Authority", "ci":"URN:UVCI:01:DK:B986830007345F99AE898FB82C6C61F2#A" } ] } } Binary String follows (CBOR Encoded) CBOR decode (to JSON) 40
  138. loige CWT payload { "1": "DK", "4": 1625054000, "6": 1622462000,

    "-260": { "ver":"1.0.0", "nam":{ "fn":"Klaus", "fnt":"KLAUS", "gn":"Jørgensen", "gnt":"JOERGENSEN" }, "dob":"1983-01-06", "v":[ { "tg":"840539006", "vp":"1119349007", "mp":"EU/1/20/1528", "ma":"ORG-100030215", "dn":2, "sd":2, "dt":"2021-05-03", "co":"DK", "is":"Danish Health Data Authority", "ci":"URN:UVCI:01:DK:B986830007345F99AE898FB82C6C61F2#A" } ] } } Binary String follows (CBOR Encoded) CBOR decode (to JSON) 40
  139. How to decode - quick recap loige 41

  140. How to decode - quick recap loige 1. Remove "HC1:"

    prefix 41
  141. How to decode - quick recap loige 1. Remove "HC1:"

    prefix 2. Base45 decode 41
  142. How to decode - quick recap loige 1. Remove "HC1:"

    prefix 2. Base45 decode 3. Zlib decompress 41
  143. How to decode - quick recap loige 1. Remove "HC1:"

    prefix 2. Base45 decode 3. Zlib decompress 4. Parse CWT 41
  144. How to decode - quick recap loige 1. Remove "HC1:"

    prefix 2. Base45 decode 3. Zlib decompress 4. Parse CWT 5. Parse CWT Payload as CBOR 41
  145. How to decode - quick recap loige 1. Remove "HC1:"

    prefix 2. Base45 decode 3. Zlib decompress 4. Parse CWT 5. Parse CWT Payload as CBOR 6. Party hard! 🥳 41
  146. How to decode - quick recap loige 1. Remove "HC1:"

    prefix 2. Base45 decode 3. Zlib decompress 4. Parse CWT 5. Parse CWT Payload as CBOR 6. Party hard! 🥳 41
  147. How to decode - quick recap loige 1. Remove "HC1:"

    prefix 2. Base45 decode 3. Zlib decompress 4. Parse CWT 5. Parse CWT Payload as CBOR 6. Party hard! 🥳 Hey, let's implement this... 41
  148. How to decode - quick recap loige 1. Remove "HC1:"

    prefix 2. Base45 decode 3. Zlib decompress 4. Parse CWT 5. Parse CWT Payload as CBOR 6. Party hard! 🥳 Hey, let's implement this... in Rust! 41
  149. loige cargo new dgc-decode Project bootstrap 42

  150. // src/main.rs fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 todo!()

    // 1. Remove "HC1:" prefix // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } 1 2 3 4 5 6 7 8 9 10 11 loige 43
  151. // src/main.rs fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 todo!()

    // 1. Remove "HC1:" prefix // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } 1 2 3 4 5 6 7 8 9 10 11 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 // src/main.rs 1 2 fn main() { 3 4 todo!() 5 // 1. Remove "HC1:" prefix 6 // 2. Base45 decode 7 // 3. Zlib decompress 8 // 4. Parse CWT 9 // 5. Parse CWT Payload as CBOR 10 } 11 loige 43
  152. // src/main.rs fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 todo!()

    // 1. Remove "HC1:" prefix // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } 1 2 3 4 5 6 7 8 9 10 11 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 // src/main.rs 1 2 fn main() { 3 4 todo!() 5 // 1. Remove "HC1:" prefix 6 // 2. Base45 decode 7 // 3. Zlib decompress 8 // 4. Parse CWT 9 // 5. Parse CWT Payload as CBOR 10 } 11 todo!() // 1. Remove "HC1:" prefix // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR // src/main.rs 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 5 6 7 8 9 10 } 11 loige 43
  153. // src/main.rs fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 todo!()

    // 1. Remove "HC1:" prefix // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } 1 2 3 4 5 6 7 8 9 10 11 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 // src/main.rs 1 2 fn main() { 3 4 todo!() 5 // 1. Remove "HC1:" prefix 6 // 2. Base45 decode 7 // 3. Zlib decompress 8 // 4. Parse CWT 9 // 5. Parse CWT Payload as CBOR 10 } 11 todo!() // 1. Remove "HC1:" prefix // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR // src/main.rs 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 5 6 7 8 9 10 } 11 // src/main.rs fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 todo!() // 1. Remove "HC1:" prefix // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } 1 2 3 4 5 6 7 8 9 10 11 loige 43
  154. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); todo!(); // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn remove_prefix(data: &str) -> &str { todo!() // remove "HC1:" prefix and return remaining string } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 loige 44
  155. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); todo!(); // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn remove_prefix(data: &str) -> &str { todo!() // remove "HC1:" prefix and return remaining string } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 let no_prefix = remove_prefix(cert_data); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 3 todo!(); 4 // 2. Base45 decode 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn remove_prefix(data: &str) -> &str { 11 todo!() 12 // remove "HC1:" prefix and return remaining string 13 } 14 loige 44
  156. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); todo!(); // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn remove_prefix(data: &str) -> &str { todo!() // remove "HC1:" prefix and return remaining string } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 let no_prefix = remove_prefix(cert_data); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 3 todo!(); 4 // 2. Base45 decode 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn remove_prefix(data: &str) -> &str { 11 todo!() 12 // remove "HC1:" prefix and return remaining string 13 } 14 fn remove_prefix(data: &str) -> &str { todo!() // remove "HC1:" prefix and return remaining string } fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 todo!(); 4 // 2. Base45 decode 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 11 12 13 14 loige 44
  157. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); todo!(); // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn remove_prefix(data: &str) -> &str { todo!() // remove "HC1:" prefix and return remaining string } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 let no_prefix = remove_prefix(cert_data); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 3 todo!(); 4 // 2. Base45 decode 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn remove_prefix(data: &str) -> &str { 11 todo!() 12 // remove "HC1:" prefix and return remaining string 13 } 14 fn remove_prefix(data: &str) -> &str { todo!() // remove "HC1:" prefix and return remaining string } fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 todo!(); 4 // 2. Base45 decode 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 11 12 13 14 fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); todo!(); // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn remove_prefix(data: &str) -> &str { todo!() // remove "HC1:" prefix and return remaining string } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 loige 44
  158. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); todo!(); // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn remove_prefix(data: &str) -> &str { if data.len() < 4 || !data.starts_with("HC1:") { panic!("Invalid prefix"); // IRL use a Result! } &data[4..] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 loige 45
  159. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); todo!(); // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn remove_prefix(data: &str) -> &str { if data.len() < 4 || !data.starts_with("HC1:") { panic!("Invalid prefix"); // IRL use a Result! } &data[4..] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 if data.len() < 4 || !data.starts_with("HC1:") { panic!("Invalid prefix"); // IRL use a Result! } &data[4..] fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 todo!(); 4 // 2. Base45 decode 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn remove_prefix(data: &str) -> &str { 11 12 13 14 15 16 } 17 loige 45
  160. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); todo!(); // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn remove_prefix(data: &str) -> &str { if data.len() < 4 || !data.starts_with("HC1:") { panic!("Invalid prefix"); // IRL use a Result! } &data[4..] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 if data.len() < 4 || !data.starts_with("HC1:") { panic!("Invalid prefix"); // IRL use a Result! } &data[4..] fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 todo!(); 4 // 2. Base45 decode 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn remove_prefix(data: &str) -> &str { 11 12 13 14 15 16 } 17 fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); todo!(); // 2. Base45 decode // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn remove_prefix(data: &str) -> &str { if data.len() < 4 || !data.starts_with("HC1:") { panic!("Invalid prefix"); // IRL use a Result! } &data[4..] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 loige 45
  161. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); todo!() // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decode_base45(data: &str) -> Vec<u8> { todo!() // parse the string as base45 encoded and return the // resulting raw bytes } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 loige 46
  162. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); todo!() // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decode_base45(data: &str) -> Vec<u8> { todo!() // parse the string as base45 encoded and return the // resulting raw bytes } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let decoded = decode_base45(no_prefix); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 4 todo!() 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decode_base45(data: &str) -> Vec<u8> { 11 todo!() 12 // parse the string as base45 encoded and return the 13 // resulting raw bytes 14 } 15 16 // ... 17 loige 46
  163. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); todo!() // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decode_base45(data: &str) -> Vec<u8> { todo!() // parse the string as base45 encoded and return the // resulting raw bytes } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let decoded = decode_base45(no_prefix); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 4 todo!() 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decode_base45(data: &str) -> Vec<u8> { 11 todo!() 12 // parse the string as base45 encoded and return the 13 // resulting raw bytes 14 } 15 16 // ... 17 fn decode_base45(data: &str) -> Vec<u8> { todo!() // parse the string as base45 encoded and return the // resulting raw bytes } fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 todo!() 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 11 12 13 14 15 16 // ... 17 loige 46
  164. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); todo!() // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decode_base45(data: &str) -> Vec<u8> { todo!() // parse the string as base45 encoded and return the // resulting raw bytes } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let decoded = decode_base45(no_prefix); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 4 todo!() 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decode_base45(data: &str) -> Vec<u8> { 11 todo!() 12 // parse the string as base45 encoded and return the 13 // resulting raw bytes 14 } 15 16 // ... 17 fn decode_base45(data: &str) -> Vec<u8> { todo!() // parse the string as base45 encoded and return the // resulting raw bytes } fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 todo!() 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 11 12 13 14 15 16 // ... 17 fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); todo!() // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decode_base45(data: &str) -> Vec<u8> { todo!() // parse the string as base45 encoded and return the // resulting raw bytes } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 loige 46
  165. loige cargo add base45 47

  166. loige cargo add base45 # Cargo.toml # ... [dependencies] base45

    = "3.0.0" 47
  167. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); todo!() // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decode_base45(data: &str) -> Vec<u8> { base45::decode(data).unwrap() // IRL use a Result! } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 loige 48
  168. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); todo!() // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decode_base45(data: &str) -> Vec<u8> { base45::decode(data).unwrap() // IRL use a Result! } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 base45::decode(data).unwrap() // IRL use a Result! fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 todo!() 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decode_base45(data: &str) -> Vec<u8> { 11 12 } 13 14 // ... 15 loige 48
  169. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); todo!() // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decode_base45(data: &str) -> Vec<u8> { base45::decode(data).unwrap() // IRL use a Result! } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 base45::decode(data).unwrap() // IRL use a Result! fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 todo!() 5 // 3. Zlib decompress 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decode_base45(data: &str) -> Vec<u8> { 11 12 } 13 14 // ... 15 fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); todo!() // 3. Zlib decompress // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decode_base45(data: &str) -> Vec<u8> { base45::decode(data).unwrap() // IRL use a Result! } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 loige 48
  170. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); todo!() // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decompress(data: Vec<u8>) -> Vec<u8> { todo!() // decompress using zlib inflate } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 loige 49
  171. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); todo!() // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decompress(data: Vec<u8>) -> Vec<u8> { todo!() // decompress using zlib inflate } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let decompressed = decompress(decoded); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 5 todo!() 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decompress(data: Vec<u8>) -> Vec<u8> { 11 todo!() 12 // decompress using zlib inflate 13 } 14 15 // ... 16 loige 49
  172. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); todo!() // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decompress(data: Vec<u8>) -> Vec<u8> { todo!() // decompress using zlib inflate } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let decompressed = decompress(decoded); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 5 todo!() 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decompress(data: Vec<u8>) -> Vec<u8> { 11 todo!() 12 // decompress using zlib inflate 13 } 14 15 // ... 16 fn decompress(data: Vec<u8>) -> Vec<u8> { todo!() // decompress using zlib inflate } fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 todo!() 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 11 12 13 14 15 // ... 16 loige 49
  173. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); todo!() // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decompress(data: Vec<u8>) -> Vec<u8> { todo!() // decompress using zlib inflate } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let decompressed = decompress(decoded); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 5 todo!() 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decompress(data: Vec<u8>) -> Vec<u8> { 11 todo!() 12 // decompress using zlib inflate 13 } 14 15 // ... 16 fn decompress(data: Vec<u8>) -> Vec<u8> { todo!() // decompress using zlib inflate } fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 todo!() 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 11 12 13 14 15 // ... 16 fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); todo!() // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decompress(data: Vec<u8>) -> Vec<u8> { todo!() // decompress using zlib inflate } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 loige 49
  174. loige cargo add inflate 50

  175. loige cargo add inflate # Cargo.toml # ... [dependencies] base45

    = "3.0.0" inflate = "0.4.5" 50
  176. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); todo!() // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decompress(data: Vec<u8>) -> Vec<u8> { inflate::inflate_bytes_zlib(data.as_slice()).unwrap() // IRL use a Result! } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 loige 51
  177. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); todo!() // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decompress(data: Vec<u8>) -> Vec<u8> { inflate::inflate_bytes_zlib(data.as_slice()).unwrap() // IRL use a Result! } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 inflate::inflate_bytes_zlib(data.as_slice()).unwrap() // IRL use a Result! fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 todo!() 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decompress(data: Vec<u8>) -> Vec<u8> { 11 12 13 } 14 15 // ... 16 loige 51
  178. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); todo!() // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decompress(data: Vec<u8>) -> Vec<u8> { inflate::inflate_bytes_zlib(data.as_slice()).unwrap() // IRL use a Result! } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 inflate::inflate_bytes_zlib(data.as_slice()).unwrap() // IRL use a Result! fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 todo!() 6 // 4. Parse CWT 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn decompress(data: Vec<u8>) -> Vec<u8> { 11 12 13 } 14 15 // ... 16 fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); todo!() // 4. Parse CWT // 5. Parse CWT Payload as CBOR } fn decompress(data: Vec<u8>) -> Vec<u8> { inflate::inflate_bytes_zlib(data.as_slice()).unwrap() // IRL use a Result! } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 loige 51
  179. Are we on the right track? loige fn main() {

    let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); println!("{}", String::from_utf8_lossy(&decompressed)); } // ... 1 2 3 4 5 6 7 8 9 10 52
  180. Are we on the right track? loige fn main() {

    let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); println!("{}", String::from_utf8_lossy(&decompressed)); } // ... 1 2 3 4 5 6 7 8 9 10 println!("{}", String::from_utf8_lossy(&decompressed)); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 6 7 } 8 9 // ... 10 52
  181. Are we on the right track? loige 53

  182. Are we on the right track? loige We are starting

    to see some readable info! 🤩 53
  183. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); todo!() // 5. Parse CWT Payload as CBOR } fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { todo!() // Parse raw bytes as CBOR. // Extract and return the raw bytes representing // the CWT payload } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 loige 54
  184. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); todo!() // 5. Parse CWT Payload as CBOR } fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { todo!() // Parse raw bytes as CBOR. // Extract and return the raw bytes representing // the CWT payload } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let cwt_payload = get_cwt_payload(decompressed); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 6 todo!() 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 11 todo!() 12 // Parse raw bytes as CBOR. 13 // Extract and return the raw bytes representing 14 // the CWT payload 15 } 16 17 // ... 18 loige 54
  185. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); todo!() // 5. Parse CWT Payload as CBOR } fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { todo!() // Parse raw bytes as CBOR. // Extract and return the raw bytes representing // the CWT payload } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let cwt_payload = get_cwt_payload(decompressed); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 6 todo!() 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 11 todo!() 12 // Parse raw bytes as CBOR. 13 // Extract and return the raw bytes representing 14 // the CWT payload 15 } 16 17 // ... 18 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { todo!() // Parse raw bytes as CBOR. // Extract and return the raw bytes representing // the CWT payload } fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 let cwt_payload = get_cwt_payload(decompressed); 6 todo!() 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 11 12 13 14 15 16 17 // ... 18 loige 54
  186. fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix =

    remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); todo!() // 5. Parse CWT Payload as CBOR } fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { todo!() // Parse raw bytes as CBOR. // Extract and return the raw bytes representing // the CWT payload } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let cwt_payload = get_cwt_payload(decompressed); fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 6 todo!() 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 11 todo!() 12 // Parse raw bytes as CBOR. 13 // Extract and return the raw bytes representing 14 // the CWT payload 15 } 16 17 // ... 18 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { todo!() // Parse raw bytes as CBOR. // Extract and return the raw bytes representing // the CWT payload } fn main() { 1 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 2 let no_prefix = remove_prefix(cert_data); 3 let decoded = decode_base45(no_prefix); 4 let decompressed = decompress(decoded); 5 let cwt_payload = get_cwt_payload(decompressed); 6 todo!() 7 // 5. Parse CWT Payload as CBOR 8 } 9 10 11 12 13 14 15 16 17 // ... 18 fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); todo!() // 5. Parse CWT Payload as CBOR } fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { todo!() // Parse raw bytes as CBOR. // Extract and return the raw bytes representing // the CWT payload } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 loige 54
  187. loige cargo add ciborium 55

  188. loige cargo add ciborium # Cargo.toml # ... [dependencies] base45

    = "3.0.0" ciborium = "0.2.0" inflate = "0.4.5" 55
  189. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); todo!() // 5. Parse CWT Payload as CBOR } fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { let parsed: Value = from_reader(data.as_slice()).unwrap(); println!("{:?}", parsed); todo!() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 loige 56
  190. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); todo!() // 5. Parse CWT Payload as CBOR } fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { let parsed: Value = from_reader(data.as_slice()).unwrap(); println!("{:?}", parsed); todo!() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 todo!() 9 // 5. Parse CWT Payload as CBOR 10 } 11 12 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 13 let parsed: Value = from_reader(data.as_slice()).unwrap(); 14 println!("{:?}", parsed); 15 todo!() 16 } 17 18 // ... 19 loige 56
  191. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); todo!() // 5. Parse CWT Payload as CBOR } fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { let parsed: Value = from_reader(data.as_slice()).unwrap(); println!("{:?}", parsed); todo!() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 todo!() 9 // 5. Parse CWT Payload as CBOR 10 } 11 12 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 13 let parsed: Value = from_reader(data.as_slice()).unwrap(); 14 println!("{:?}", parsed); 15 todo!() 16 } 17 18 // ... 19 let parsed: Value = from_reader(data.as_slice()).unwrap(); println!("{:?}", parsed); use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 todo!() 9 // 5. Parse CWT Payload as CBOR 10 } 11 12 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 13 14 15 todo!() 16 } 17 18 // ... 19 loige 56
  192. 57 loige

  193. 57 loige

  194. CWT Tag (18) 57 loige

  195. The content is an array 57 loige

  196. 57 Protected header loige

  197. 57 Non protected header loige

  198. 57 Payload ✅ loige

  199. 57 Signature loige

  200. // ... fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { // IRL

    avoid .unwrap() like hell and propagate errors correctly! let parsed: Value = from_reader(data.as_slice()).unwrap(); let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); let arr = arr.as_array().unwrap(); let payload = arr[2].as_bytes().unwrap(); payload.clone() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 loige 58
  201. // ... fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { // IRL

    avoid .unwrap() like hell and propagate errors correctly! let parsed: Value = from_reader(data.as_slice()).unwrap(); let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); let arr = arr.as_array().unwrap(); let payload = arr[2].as_bytes().unwrap(); payload.clone() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 let parsed: Value = from_reader(data.as_slice()).unwrap(); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 let arr = arr.as_array().unwrap(); 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 loige 58
  202. // ... fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { // IRL

    avoid .unwrap() like hell and propagate errors correctly! let parsed: Value = from_reader(data.as_slice()).unwrap(); let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); let arr = arr.as_array().unwrap(); let payload = arr[2].as_bytes().unwrap(); payload.clone() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 let parsed: Value = from_reader(data.as_slice()).unwrap(); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 let arr = arr.as_array().unwrap(); 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 let parsed: Value = from_reader(data.as_slice()).unwrap(); 5 6 7 let arr = arr.as_array().unwrap(); 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 loige 58
  203. // ... fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { // IRL

    avoid .unwrap() like hell and propagate errors correctly! let parsed: Value = from_reader(data.as_slice()).unwrap(); let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); let arr = arr.as_array().unwrap(); let payload = arr[2].as_bytes().unwrap(); payload.clone() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 let parsed: Value = from_reader(data.as_slice()).unwrap(); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 let arr = arr.as_array().unwrap(); 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 let parsed: Value = from_reader(data.as_slice()).unwrap(); 5 6 7 let arr = arr.as_array().unwrap(); 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 let arr = arr.as_array().unwrap(); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 let parsed: Value = from_reader(data.as_slice()).unwrap(); 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 loige 58
  204. // ... fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { // IRL

    avoid .unwrap() like hell and propagate errors correctly! let parsed: Value = from_reader(data.as_slice()).unwrap(); let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); let arr = arr.as_array().unwrap(); let payload = arr[2].as_bytes().unwrap(); payload.clone() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 let parsed: Value = from_reader(data.as_slice()).unwrap(); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 let arr = arr.as_array().unwrap(); 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 let parsed: Value = from_reader(data.as_slice()).unwrap(); 5 6 7 let arr = arr.as_array().unwrap(); 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 let arr = arr.as_array().unwrap(); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 let parsed: Value = from_reader(data.as_slice()).unwrap(); 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 let payload = arr[2].as_bytes().unwrap(); payload.clone() // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 let parsed: Value = from_reader(data.as_slice()).unwrap(); 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 let arr = arr.as_array().unwrap(); 8 9 10 } 11 12 // ... 13 loige 58
  205. // ... fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { // IRL

    avoid .unwrap() like hell and propagate errors correctly! let parsed: Value = from_reader(data.as_slice()).unwrap(); let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); let arr = arr.as_array().unwrap(); let payload = arr[2].as_bytes().unwrap(); payload.clone() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 let parsed: Value = from_reader(data.as_slice()).unwrap(); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 let arr = arr.as_array().unwrap(); 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 let parsed: Value = from_reader(data.as_slice()).unwrap(); 5 6 7 let arr = arr.as_array().unwrap(); 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 let arr = arr.as_array().unwrap(); // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 let parsed: Value = from_reader(data.as_slice()).unwrap(); 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 8 let payload = arr[2].as_bytes().unwrap(); 9 payload.clone() 10 } 11 12 // ... 13 let payload = arr[2].as_bytes().unwrap(); payload.clone() // ... 1 2 fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { 3 // IRL avoid .unwrap() like hell and propagate errors correctly! 4 let parsed: Value = from_reader(data.as_slice()).unwrap(); 5 let (tag, arr) = parsed.as_tag().unwrap(); 6 assert_eq!(tag, 18); 7 let arr = arr.as_array().unwrap(); 8 9 10 } 11 12 // ... 13 // ... fn get_cwt_payload(data: Vec<u8>) -> Vec<u8> { // IRL avoid .unwrap() like hell and propagate errors correctly! let parsed: Value = from_reader(data.as_slice()).unwrap(); let (tag, arr) = parsed.as_tag().unwrap(); assert_eq!(tag, 18); let arr = arr.as_array().unwrap(); let payload = arr[2].as_bytes().unwrap(); payload.clone() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 loige 58
  206. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); } fn parse_cwt_payload(data: Vec<u8>) -> Value { // parse the binary data as CBOR todo!() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 loige 59
  207. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); } fn parse_cwt_payload(data: Vec<u8>) -> Value { // parse the binary data as CBOR todo!() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let parsed_payload = parse_cwt_payload(cwt_payload); use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 9 } 10 11 fn parse_cwt_payload(data: Vec<u8>) -> Value { 12 // parse the binary data as CBOR 13 todo!() 14 } 15 16 // ... 17 loige 59
  208. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); } fn parse_cwt_payload(data: Vec<u8>) -> Value { // parse the binary data as CBOR todo!() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let parsed_payload = parse_cwt_payload(cwt_payload); use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 9 } 10 11 fn parse_cwt_payload(data: Vec<u8>) -> Value { 12 // parse the binary data as CBOR 13 todo!() 14 } 15 16 // ... 17 fn parse_cwt_payload(data: Vec<u8>) -> Value { // parse the binary data as CBOR todo!() } use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 let parsed_payload = parse_cwt_payload(cwt_payload); 9 } 10 11 12 13 14 15 16 // ... 17 loige 59
  209. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{:#?}", parsed_payload); } fn parse_cwt_payload(data: Vec<u8>) -> Value { from_reader(data.as_slice()).unwrap() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 loige 60
  210. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{:#?}", parsed_payload); } fn parse_cwt_payload(data: Vec<u8>) -> Value { from_reader(data.as_slice()).unwrap() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from_reader(data.as_slice()).unwrap() use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 let parsed_payload = parse_cwt_payload(cwt_payload); 9 println!("{:#?}", parsed_payload); 10 } 11 12 fn parse_cwt_payload(data: Vec<u8>) -> Value { 13 14 } 15 16 // ... 17 loige 60
  211. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{:#?}", parsed_payload); } fn parse_cwt_payload(data: Vec<u8>) -> Value { from_reader(data.as_slice()).unwrap() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from_reader(data.as_slice()).unwrap() use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 let parsed_payload = parse_cwt_payload(cwt_payload); 9 println!("{:#?}", parsed_payload); 10 } 11 12 fn parse_cwt_payload(data: Vec<u8>) -> Value { 13 14 } 15 16 // ... 17 println!("{:#?}", parsed_payload); use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 let parsed_payload = parse_cwt_payload(cwt_payload); 9 10 } 11 12 fn parse_cwt_payload(data: Vec<u8>) -> Value { 13 from_reader(data.as_slice()).unwrap() 14 } 15 16 // ... 17 loige 60
  212. use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4

    let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{:#?}", parsed_payload); } fn parse_cwt_payload(data: Vec<u8>) -> Value { from_reader(data.as_slice()).unwrap() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from_reader(data.as_slice()).unwrap() use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 let parsed_payload = parse_cwt_payload(cwt_payload); 9 println!("{:#?}", parsed_payload); 10 } 11 12 fn parse_cwt_payload(data: Vec<u8>) -> Value { 13 14 } 15 16 // ... 17 println!("{:#?}", parsed_payload); use ciborium::{de::from_reader, value::Value}; 1 2 fn main() { 3 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 4 let no_prefix = remove_prefix(cert_data); 5 let decoded = decode_base45(no_prefix); 6 let decompressed = decompress(decoded); 7 let cwt_payload = get_cwt_payload(decompressed); 8 let parsed_payload = parse_cwt_payload(cwt_payload); 9 10 } 11 12 fn parse_cwt_payload(data: Vec<u8>) -> Value { 13 from_reader(data.as_slice()).unwrap() 14 } 15 16 // ... 17 use ciborium::{de::from_reader, value::Value}; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{:#?}", parsed_payload); } fn parse_cwt_payload(data: Vec<u8>) -> Value { from_reader(data.as_slice()).unwrap() } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 loige 60
  213. loige 61

  214. loige 61

  215. Ok, let's make it more readable... 😅 loige 62

  216. Ok, let's make it more readable... 😅 loige cargo add

    serde_json 62
  217. use ciborium::{de::from_reader, value::Value}; use serde_json::to_string_pretty; fn main() { let cert_data

    = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{}", to_string_pretty(&parsed_payload).unwrap()); } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 loige 63
  218. use ciborium::{de::from_reader, value::Value}; use serde_json::to_string_pretty; fn main() { let cert_data

    = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{}", to_string_pretty(&parsed_payload).unwrap()); } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 use serde_json::to_string_pretty; use ciborium::{de::from_reader, value::Value}; 1 2 3 fn main() { 4 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 5 let no_prefix = remove_prefix(cert_data); 6 let decoded = decode_base45(no_prefix); 7 let decompressed = decompress(decoded); 8 let cwt_payload = get_cwt_payload(decompressed); 9 let parsed_payload = parse_cwt_payload(cwt_payload); 10 println!("{}", to_string_pretty(&parsed_payload).unwrap()); 11 } 12 13 // ... 14 loige 63
  219. use ciborium::{de::from_reader, value::Value}; use serde_json::to_string_pretty; fn main() { let cert_data

    = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{}", to_string_pretty(&parsed_payload).unwrap()); } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 use serde_json::to_string_pretty; use ciborium::{de::from_reader, value::Value}; 1 2 3 fn main() { 4 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 5 let no_prefix = remove_prefix(cert_data); 6 let decoded = decode_base45(no_prefix); 7 let decompressed = decompress(decoded); 8 let cwt_payload = get_cwt_payload(decompressed); 9 let parsed_payload = parse_cwt_payload(cwt_payload); 10 println!("{}", to_string_pretty(&parsed_payload).unwrap()); 11 } 12 13 // ... 14 println!("{}", to_string_pretty(&parsed_payload).unwrap()); use ciborium::{de::from_reader, value::Value}; 1 use serde_json::to_string_pretty; 2 3 fn main() { 4 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 5 let no_prefix = remove_prefix(cert_data); 6 let decoded = decode_base45(no_prefix); 7 let decompressed = decompress(decoded); 8 let cwt_payload = get_cwt_payload(decompressed); 9 let parsed_payload = parse_cwt_payload(cwt_payload); 10 11 } 12 13 // ... 14 loige 63
  220. use ciborium::{de::from_reader, value::Value}; use serde_json::to_string_pretty; fn main() { let cert_data

    = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{}", to_string_pretty(&parsed_payload).unwrap()); } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 use serde_json::to_string_pretty; use ciborium::{de::from_reader, value::Value}; 1 2 3 fn main() { 4 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 5 let no_prefix = remove_prefix(cert_data); 6 let decoded = decode_base45(no_prefix); 7 let decompressed = decompress(decoded); 8 let cwt_payload = get_cwt_payload(decompressed); 9 let parsed_payload = parse_cwt_payload(cwt_payload); 10 println!("{}", to_string_pretty(&parsed_payload).unwrap()); 11 } 12 13 // ... 14 println!("{}", to_string_pretty(&parsed_payload).unwrap()); use ciborium::{de::from_reader, value::Value}; 1 use serde_json::to_string_pretty; 2 3 fn main() { 4 let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 5 let no_prefix = remove_prefix(cert_data); 6 let decoded = decode_base45(no_prefix); 7 let decompressed = decompress(decoded); 8 let cwt_payload = get_cwt_payload(decompressed); 9 let parsed_payload = parse_cwt_payload(cwt_payload); 10 11 } 12 13 // ... 14 use ciborium::{de::from_reader, value::Value}; use serde_json::to_string_pretty; fn main() { let cert_data = "HC1:NCFOXN%TSMAHN-H9QCGDSB5QPN9OO3:D4$X4-365KN-TMLV4 let no_prefix = remove_prefix(cert_data); let decoded = decode_base45(no_prefix); let decompressed = decompress(decoded); let cwt_payload = get_cwt_payload(decompressed); let parsed_payload = parse_cwt_payload(cwt_payload); println!("{}", to_string_pretty(&parsed_payload).unwrap()); } // ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 loige 63
  221. loige 64

  222. loige 64

  223. All the code: loige.link/green-code loige 65

  224. A better (& more complete) implementation as a Rust library

    loige github.com/rust-italia/dgc 66
  225. Exercise for the viewer: Try to validate the signature loige

    67
  226. Exercise for the viewer: Try to validate the signature loige

    🔑 You can get the Public Key from the certificate here: loige.link/green-examples 67
  227. Exercise for the viewer: Try to validate the signature loige

    🔑 You can get the Public Key from the certificate here: loige.link/green-examples 📑 Here you can find more about how the CoseSign1 protocol works: loige.link/cose-sign-verif 67
  228. Exercise for the viewer: Try to validate the signature loige

    🔑 You can get the Public Key from the certificate here: loige.link/green-examples 📑 Here you can find more about how the CoseSign1 protocol works: loige.link/cose-sign-verif 📦 You could use a crate like for crypto! ring 67
  229. Exercise for the viewer: Try to validate the signature loige

    🔑 You can get the Public Key from the certificate here: loige.link/green-examples 📑 Here you can find more about how the CoseSign1 protocol works: loige.link/cose-sign-verif 📦 You could use a crate like for crypto! ring (Spoiler: I implemented some of this stuff in my library!) 67
  230. Is all this stuff legal? 😰 loige 68

  231. Is all this stuff legal? 😰 loige 👀 You can

    certainly look into your certificate (and the test certificates!) 68
  232. Is all this stuff legal? 😰 loige 👀 You can

    certainly look into your certificate (and the test certificates!) 🗣 Looking into other people's certificate will disclose a lot of privacy-sensitive info (thread carefully) 68
  233. Is all this stuff legal? 😰 loige 👀 You can

    certainly look into your certificate (and the test certificates!) 🗣 Looking into other people's certificate will disclose a lot of privacy-sensitive info (thread carefully) 📲 Building a validator app? Check your country's regulation (especially if you need to store data!) 68
  234. Cover Picture by on ❤ Huge thanks to for some

    precius review sessions and many pull requests! ❤ Thanks to , , , , for reviews and suggestions. FPVmat A Unsplash rust-italia @gbinside @88_eugen @AlleviTommaso @npmccallum @pelger loige ☝ nodejsdp.link loige.link/green THANK YOU! ❤ 69