SlideShare ist ein Scribd-Unternehmen logo
1 von 234
Downloaden Sie, um offline zu lesen
A look inside the
European Covid Green Certificate
Luciano Mammino ( )
@loige
2021-12-01
loige.link/green
1
Get these slides!
loige
loige.link/green
2
Let me introduce myself first...
3
Let me introduce myself first...
👋I'm Luciano ( 🍕🍝 )
3
Let me introduce myself first...
👋I'm Luciano ( 🍕🍝 )
Senior Architect @ fourTheorem (Dublin )
3
Let me introduce myself first...
👋I'm Luciano ( 🍕🍝 )
Senior Architect @ fourTheorem (Dublin )
nodejsdp.link
📔Co-Author of Node.js Design Patterns  👉
3
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
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
Disclaimers
loige 5
Disclaimers
loige
🤓I am not involved with the DGC working group
 
5
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
Agenda + Goals
loige 6
Agenda + Goals
loige
1. Needs and principles
2. 🗝Cryptographic model
3. 📦The data
4. 🧅Layers of encoding
5. 🛠Decoding in Rust
6
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
The need for a digital certificate in
the COVID age
loige 7
The need for a digital certificate in
the COVID age
loige 8
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
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
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
The EU Covid Green Pass
a.k.a. 
Electronic Health Certificates
(HCERT)
 
loige.link/hcert-spec
loige 9
Electronic Health Certificates (HCERT)
Requirements & Guiding Principles
loige 10
Electronic Health Certificates (HCERT)
Requirements & Guiding Principles
loige
✍Signed data with machine readable content
10
Electronic Health Certificates (HCERT)
Requirements & Guiding Principles
loige
✍Signed data with machine readable content
📃Use compact encoding
10
Electronic Health Certificates (HCERT)
Requirements & Guiding Principles
loige
✍Signed data with machine readable content
📃Use compact encoding
🤲Based on open standards
10
Asymmetric cryptographic signatures
loige 11
Asymmetric cryptographic signatures
loige
🤫Private Key
101010101000101010010...
11
Asymmetric cryptographic signatures
loige
🤫Private Key 📢Public Key
101010101000101010010... 0101010101010101010101...
11
Asymmetric cryptographic signatures
loige
🤫Private Key 📢Public Key
🔗
101010101000101010010... 0101010101010101010101...
11
Asymmetric cryptographic signatures
loige
🤫Private Key 📢Public Key
101010101000101010010... 0101010101010101010101...
12
Asymmetric cryptographic signatures
loige
🤫Private Key 📢Public Key
101010101000101010010... 0101010101010101010101...
12
Asymmetric cryptographic signatures
loige
🤫Private Key 📢Public Key
101010101000101010010... 0101010101010101010101...
The owner of the private
key signs the document
12
Asymmetric cryptographic signatures
loige
🤫Private Key 📢Public Key
101010101000101010010... 0101010101010101010101...
The owner of the private
key signs the document
12
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
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
What's inside a certificate?
loige 13
What's inside a certificate?
loige 13
What's inside a certificate?
loige
Cryptographic header (Key Id, Algorithm)
13
What's inside a certificate?
loige
DGC container
Cryptographic header (Key Id, Algorithm)
13
What's inside a certificate?
loige
DGC container
Cryptographic header (Key Id, Algorithm)
Cryptographic Signature
13
What's inside a certificate?
loige
DGC container
Cryptographic header (Key Id, Algorithm)
Cryptographic Signature
Header (Issuer, Issue date, expiry date)
13
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)
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)
An example
loige loige.link/green-examples 14
An example
loige loige.link/green-examples 15
{
"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
{
"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
{
"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
{
"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
Layered
encoding
loige 16
🧅
Layered
encoding
loige
QRCODE ASCII mode
16
🧅
Layered
encoding
loige
QRCODE ASCII mode
Prefix + Base45 encoding
16
🧅
Layered
encoding
loige
QRCODE ASCII mode
Prefix + Base45 encoding
Zlib compression
16
🧅
Layered
encoding
loige
QRCODE ASCII mode
Prefix + Base45 encoding
Zlib compression
CWT signed data (COSE)
16
🧅
Layered
encoding
loige
QRCODE ASCII mode
Prefix + Base45 encoding
Zlib compression
CWT signed data (COSE)
CBOR document
16
🧅
loige
QRCode content
17
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
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
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
Base45
loige 18
loige
Base45
19
loige
Allows to encode binary data in text format (ASCII)
Base45
19
loige
Allows to encode binary data in text format (ASCII)
Like Base64, but it uses 45 characters instead:
Base45
19
loige
Allows to encode binary data in text format (ASCII)
Like Base64, but it uses 45 characters instead:
loige.link/base45-explained
Base45
19
Base45
loige 20
Base45
loige
01001001 00100000 01100111
01101111 01110100 00100000
01101101 01111001 00100000
01110011 01101000 01101111
01110100 01110011 00100000
11011000 00111101
Some binary data
20
Base45
loige
01001001 00100000 01100111
01101111 01110100 00100000
01101101 01111001 00100000
01110011 01101000 01101111
01110100 01110011 00100000
11011000 00111101
Some binary data
20
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
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
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
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
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
loige
Base45
22
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
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
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
Zlib compression
loige 23
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
Zlib compression
loige 25
Zlib compression
loige
Compressed binary data
25
Zlib compression
loige
Zlib inflate
Compressed binary data
25
Zlib compression
loige
Zlib inflate
Compressed binary data Decompressed binary data
25
Zlib compression
loige 26
Zlib compression
loige 26
Zlib compression
loige
👀We start to see
some "readable"
information!
26
COSE / CWT
loige
CBOR Object Signing and Encryption / CBOR Web Token
27
CBOR !? 🤔
loige
But wait, what the heck is
✋
28
CBOR
loige
TLDR; Like JSON but in binary!
loige.link/cbor-rfc
29
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
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
CBOR
loige
It also supports:
Byte String (a sequence of raw bytes)
Tags (annotations that allow to create new types)
32
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
}
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
"foo":
}
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
"foo": "bar",
}
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
"foo": "bar",
"manyvals":
}
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
"foo": "bar",
"manyvals": [
}
],
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
"foo": "bar",
"manyvals": [
}
],
1,
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
"foo": "bar",
"manyvals": [
}
],
1, 2,
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
"foo": "bar",
"manyvals": [
}
],
1, 2, 3
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
"foo": "bar",
"manyvals": [
}
],
"nested":
1, 2, 3
33
CBOR
loige
An example:
A3 63666F6F 63626172 686D616E7976616C73 83 01 02 03 666E6573746564 A0
{
"foo": "bar",
"manyvals": [
}
],
"nested": {}
1, 2, 3
33
COSE / CWT
loige
CBOR Object Signing and Encryption / CBOR Web Token
ok... again 😅
34
COSE
loige
CBOR Object Signing and Encryption
35
COSE
loige
CBOR Object Signing and Encryption
COSE (inspired by ) defines CBOR-based protocols for:
JOSE
35
COSE
loige
CBOR Object Signing and Encryption
COSE (inspired by ) defines CBOR-based protocols for:
JOSE
Encrypted data
35
COSE
loige
CBOR Object Signing and Encryption
COSE (inspired by ) defines CBOR-based protocols for:
JOSE
Encrypted data
Cryptographic signed data
35
COSE
loige
CBOR Object Signing and Encryption
COSE (inspired by ) defines CBOR-based protocols for:
JOSE
Encrypted data
Cryptographic signed data
MACed data
35
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
CWT
loige
CBOR Web Token
36
CWT
loige
Like but for CBOR
JWT
CBOR Web Token
36
CWT
loige
Like but for CBOR
JWT
Defines a protocol for transferring claims between parties
CBOR Web Token
36
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
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
CWT
loige
CBOR Web Token
37
CWT
loige
A CWT is made of 4 parts:
CBOR Web Token
37
CWT
loige
A CWT is made of 4 parts:
Protected header
CBOR Web Token
37
CWT
loige
A CWT is made of 4 parts:
Protected header
CBOR Web Token
Non protected header
37
CWT
loige
A CWT is made of 4 parts:
Protected header
CBOR Web Token
Non protected header
Payload
37
CWT
loige
A CWT is made of 4 parts:
Protected header
CBOR Web Token
Non protected header
Payload
Signature
37
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
loige 39
loige 39
loige
CWT tag
39
loige
CWT tag
39
loige
Array (length 4)
CWT tag
39
loige
Array (length 4)
CWT tag
39
Protected
header
Binary String
loige
Array (length 4)
CWT tag
39
Protected
header
Binary String
loige
Array (length 4)
CWT tag
39
Protected
header
Binary String
loige
Array (length 4)
CWT tag
39
Unprotected header
Map (length 0)
Protected
header
Binary String
loige
Array (length 4)
CWT tag
39
Unprotected header
Map (length 0)
Protected
header
Binary String
loige
Array (length 4)
CWT tag
39
Unprotected header
Map (length 0)
Payload
Binary String
Protected
header
Binary String
loige
Array (length 4)
CWT tag
39
Unprotected header
Map (length 0)
Payload
Binary String
Protected
header
Binary String
loige
Array (length 4)
CWT tag
39
Unprotected header
Map (length 0)
Payload
Binary String
Signature
Binary String
loige
CWT payload
40
loige
CWT payload
40
loige
CWT payload
Binary String follows (CBOR Encoded)
40
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
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
How to decode - quick recap
loige 41
How to decode - quick recap
loige
1. Remove "HC1:" prefix
41
How to decode - quick recap
loige
1. Remove "HC1:" prefix
2. Base45 decode
41
How to decode - quick recap
loige
1. Remove "HC1:" prefix
2. Base45 decode
3. Zlib decompress
41
How to decode - quick recap
loige
1. Remove "HC1:" prefix
2. Base45 decode
3. Zlib decompress
4. Parse CWT
41
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
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
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
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
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
loige
cargo new dgc-decode
Project bootstrap
42
// 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
// 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
// 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
// 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
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
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
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
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
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
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
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
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
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
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
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
loige
cargo add base45
47
loige
cargo add base45
# Cargo.toml
# ...
[dependencies]
base45 = "3.0.0"
47
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
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
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
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
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
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
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
loige
cargo add inflate
50
loige
cargo add inflate
# Cargo.toml
# ...
[dependencies]
base45 = "3.0.0"
inflate = "0.4.5"
50
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
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
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
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
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
Are we on the right track?
loige 53
Are we on the right track?
loige
We are starting to see some
readable info! 🤩 53
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
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
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
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
loige
cargo add ciborium
55
loige
cargo add ciborium
# Cargo.toml
# ...
[dependencies]
base45 = "3.0.0"
ciborium = "0.2.0"
inflate = "0.4.5"
55
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
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
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
57
loige
57
loige
CWT Tag (18)
57
loige
The content is an array
57
loige
57
Protected header
loige
57
Non protected header
loige
57
Payload  ✅
loige
57
Signature
loige
// ...
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
// ...
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
// ...
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
// ...
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
// ...
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
// ...
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
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
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
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
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
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
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
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
loige 61
loige 61
Ok, let's make it more readable... 😅
loige 62
Ok, let's make it more readable... 😅
loige
cargo add serde_json
62
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
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
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
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
loige 64
loige 64
All the code:
loige.link/green-code
loige 65
A better (& more complete) implementation
as a Rust library
loige
github.com/rust-italia/dgc
66
Exercise for the viewer:
Try to validate the signature
loige 67
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
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
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
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
Is all this stuff legal? 😰
loige 68
Is all this stuff legal? 😰
loige
👀You can certainly look into your certificate (and the
test certificates!)
68
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
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
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

Weitere ähnliche Inhalte

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

6DCP Presentation 2016
6DCP Presentation 20166DCP Presentation 2016
6DCP Presentation 2016
Eddie Cohen
 
Ceh v8-course-outline
Ceh v8-course-outlineCeh v8-course-outline
Ceh v8-course-outline
Ayhan Gasanly
 
Certified ethicalhacking classroom_1382954076
Certified ethicalhacking classroom_1382954076Certified ethicalhacking classroom_1382954076
Certified ethicalhacking classroom_1382954076
sunil kumar
 

Ähnlich wie A look inside the European Covid Green Certificate (Codemotion 2021) (20)

Open Compliance Summit 2022 – State of the Union from Mike Dolan, SVP and GM ...
Open Compliance Summit 2022 – State of the Union from Mike Dolan, SVP and GM ...Open Compliance Summit 2022 – State of the Union from Mike Dolan, SVP and GM ...
Open Compliance Summit 2022 – State of the Union from Mike Dolan, SVP and GM ...
 
Handle your Lambdas - From event-based processing to Continuous Integration /...
Handle your Lambdas - From event-based processing to Continuous Integration /...Handle your Lambdas - From event-based processing to Continuous Integration /...
Handle your Lambdas - From event-based processing to Continuous Integration /...
 
STARTHUB CONNECT 2018 - Blockchain Zoo_Pandu Sastrowardoyo
STARTHUB CONNECT 2018 - Blockchain Zoo_Pandu SastrowardoyoSTARTHUB CONNECT 2018 - Blockchain Zoo_Pandu Sastrowardoyo
STARTHUB CONNECT 2018 - Blockchain Zoo_Pandu Sastrowardoyo
 
DevSecOps - Colocando segurança na esteira
DevSecOps - Colocando segurança na esteiraDevSecOps - Colocando segurança na esteira
DevSecOps - Colocando segurança na esteira
 
6DCP Presentation 2016
6DCP Presentation 20166DCP Presentation 2016
6DCP Presentation 2016
 
Blockchain v Cryptocurrency: Talk for BridgeSF
Blockchain v Cryptocurrency: Talk for BridgeSF Blockchain v Cryptocurrency: Talk for BridgeSF
Blockchain v Cryptocurrency: Talk for BridgeSF
 
Preventing Code Leaks & Other Critical Security Risks from Code
Preventing Code Leaks & Other Critical Security Risks from CodePreventing Code Leaks & Other Critical Security Risks from Code
Preventing Code Leaks & Other Critical Security Risks from Code
 
Secure pl-sql-coding
Secure pl-sql-codingSecure pl-sql-coding
Secure pl-sql-coding
 
Pymnts BlueFin Webinar
Pymnts BlueFin WebinarPymnts BlueFin Webinar
Pymnts BlueFin Webinar
 
Ceh v8-course-outline
Ceh v8-course-outlineCeh v8-course-outline
Ceh v8-course-outline
 
Certified ethicalhacking classroom_1382954076
Certified ethicalhacking classroom_1382954076Certified ethicalhacking classroom_1382954076
Certified ethicalhacking classroom_1382954076
 
Collective Authorities
Collective AuthoritiesCollective Authorities
Collective Authorities
 
Best training blockchain for colleges- https://diyblockchain.co
Best training blockchain for colleges- https://diyblockchain.coBest training blockchain for colleges- https://diyblockchain.co
Best training blockchain for colleges- https://diyblockchain.co
 
Diyblockchain 9jan2019 https://diyblockchain.co/
Diyblockchain 9jan2019 https://diyblockchain.co/Diyblockchain 9jan2019 https://diyblockchain.co/
Diyblockchain 9jan2019 https://diyblockchain.co/
 
Diyblockchain -best blockchain institute for corporate training -diyblockchai...
Diyblockchain -best blockchain institute for corporate training -diyblockchai...Diyblockchain -best blockchain institute for corporate training -diyblockchai...
Diyblockchain -best blockchain institute for corporate training -diyblockchai...
 
BEST CRYPTOCURRENCY TRAINING
BEST CRYPTOCURRENCY TRAININGBEST CRYPTOCURRENCY TRAINING
BEST CRYPTOCURRENCY TRAINING
 
Diyblockchain -Best blockchain academy- diyblockchain.co
Diyblockchain -Best blockchain academy- diyblockchain.coDiyblockchain -Best blockchain academy- diyblockchain.co
Diyblockchain -Best blockchain academy- diyblockchain.co
 
BEST BLOCKCHAIN CERTIFICATION COURSE
BEST BLOCKCHAIN CERTIFICATION COURSEBEST BLOCKCHAIN CERTIFICATION COURSE
BEST BLOCKCHAIN CERTIFICATION COURSE
 
BEST BLOCK CHAIN COURSES
 BEST BLOCK CHAIN COURSES BEST BLOCK CHAIN COURSES
BEST BLOCK CHAIN COURSES
 
BLOCKCHAIN AND CRYPTOCURRENCY COURSES
BLOCKCHAIN AND CRYPTOCURRENCY COURSESBLOCKCHAIN AND CRYPTOCURRENCY COURSES
BLOCKCHAIN AND CRYPTOCURRENCY COURSES
 

Mehr von Luciano Mammino

Mehr von Luciano Mammino (20)

Did you know JavaScript has iterators? DublinJS
Did you know JavaScript has iterators? DublinJSDid you know JavaScript has iterators? DublinJS
Did you know JavaScript has iterators? DublinJS
 
What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...
What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...
What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...
 
Building an invite-only microsite with Next.js & Airtable - ReactJS Milano
Building an invite-only microsite with Next.js & Airtable - ReactJS MilanoBuilding an invite-only microsite with Next.js & Airtable - ReactJS Milano
Building an invite-only microsite with Next.js & Airtable - ReactJS Milano
 
From Node.js to Design Patterns - BuildPiper
From Node.js to Design Patterns - BuildPiperFrom Node.js to Design Patterns - BuildPiper
From Node.js to Design Patterns - BuildPiper
 
Let's build a 0-cost invite-only website with Next.js and Airtable!
Let's build a 0-cost invite-only website with Next.js and Airtable!Let's build a 0-cost invite-only website with Next.js and Airtable!
Let's build a 0-cost invite-only website with Next.js and Airtable!
 
Everything I know about S3 pre-signed URLs
Everything I know about S3 pre-signed URLsEverything I know about S3 pre-signed URLs
Everything I know about S3 pre-signed URLs
 
Serverless for High Performance Computing
Serverless for High Performance ComputingServerless for High Performance Computing
Serverless for High Performance Computing
 
Serverless for High Performance Computing
Serverless for High Performance ComputingServerless for High Performance Computing
Serverless for High Performance Computing
 
JavaScript Iteration Protocols - Workshop NodeConf EU 2022
JavaScript Iteration Protocols - Workshop NodeConf EU 2022JavaScript Iteration Protocols - Workshop NodeConf EU 2022
JavaScript Iteration Protocols - Workshop NodeConf EU 2022
 
Building an invite-only microsite with Next.js & Airtable
Building an invite-only microsite with Next.js & AirtableBuilding an invite-only microsite with Next.js & Airtable
Building an invite-only microsite with Next.js & Airtable
 
Let's take the monolith to the cloud 🚀
Let's take the monolith to the cloud 🚀Let's take the monolith to the cloud 🚀
Let's take the monolith to the cloud 🚀
 
A look inside the European Covid Green Certificate - Rust Dublin
A look inside the European Covid Green Certificate - Rust DublinA look inside the European Covid Green Certificate - Rust Dublin
A look inside the European Covid Green Certificate - Rust Dublin
 
Monoliths to the cloud!
Monoliths to the cloud!Monoliths to the cloud!
Monoliths to the cloud!
 
The senior dev
The senior devThe senior dev
The senior dev
 
Node.js: scalability tips - Azure Dev Community Vijayawada
Node.js: scalability tips - Azure Dev Community VijayawadaNode.js: scalability tips - Azure Dev Community Vijayawada
Node.js: scalability tips - Azure Dev Community Vijayawada
 
AWS Observability Made Simple
AWS Observability Made SimpleAWS Observability Made Simple
AWS Observability Made Simple
 
Semplificare l'observability per progetti Serverless
Semplificare l'observability per progetti ServerlessSemplificare l'observability per progetti Serverless
Semplificare l'observability per progetti Serverless
 
Finding a lost song with Node.js and async iterators - NodeConf Remote 2021
Finding a lost song with Node.js and async iterators - NodeConf Remote 2021Finding a lost song with Node.js and async iterators - NodeConf Remote 2021
Finding a lost song with Node.js and async iterators - NodeConf Remote 2021
 
Finding a lost song with Node.js and async iterators - EnterJS 2021
Finding a lost song with Node.js and async iterators - EnterJS 2021Finding a lost song with Node.js and async iterators - EnterJS 2021
Finding a lost song with Node.js and async iterators - EnterJS 2021
 
How to send gzipped requests with boto3
How to send gzipped requests with boto3How to send gzipped requests with boto3
How to send gzipped requests with boto3
 

Kürzlich hochgeladen

Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
panagenda
 
Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for Success
UXDXConf
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
FIDO Alliance
 

Kürzlich hochgeladen (20)

The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfThe Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
 
Collecting & Temporal Analysis of Behavioral Web Data - Tales From The Inside
Collecting & Temporal Analysis of Behavioral Web Data - Tales From The InsideCollecting & Temporal Analysis of Behavioral Web Data - Tales From The Inside
Collecting & Temporal Analysis of Behavioral Web Data - Tales From The Inside
 
State of the Smart Building Startup Landscape 2024!
State of the Smart Building Startup Landscape 2024!State of the Smart Building Startup Landscape 2024!
State of the Smart Building Startup Landscape 2024!
 
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsContinuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
 
Introduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxIntroduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptx
 
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
 
Using IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & IrelandUsing IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & Ireland
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024
 
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdfWhere to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
 
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
 
Microsoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - QuestionnaireMicrosoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - Questionnaire
 
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
 
The Metaverse: Are We There Yet?
The  Metaverse:    Are   We  There  Yet?The  Metaverse:    Are   We  There  Yet?
The Metaverse: Are We There Yet?
 
ADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptxADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptx
 
Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for Success
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
 
Design Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptxDesign Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptx
 
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
 
Intro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptxIntro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptx
 

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

  • 1. A look inside the European Covid Green Certificate Luciano Mammino ( ) @loige 2021-12-01 loige.link/green 1
  • 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
  • 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
  • 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
  • 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)
  • 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
  • 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 🧅
  • 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
  • 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
  • 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
  • 81. Zlib compression loige Zlib inflate Compressed binary data Decompressed binary data 25
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 195. The content is an array 57 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
  • 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
  • 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