Published August 13, 2020 | Version v1
Dataset Open

CVE-2020-12399: research data and tooling

Description

This dataset and software tools are for reproducing the research results related to CVE-2020-12399, resulting from the manuscript "Déjà vu: Side-channel analysis of Mozilla's NSS", to appear at ACM CCS 2020.

  • The data is from a remote timing attack against the NSS v3.51 implementation of DSA signing.
  • The client machine was a 3.1 GHz 64-bit Intel i5-2400 CPU (Sandy Bridge).
  • The server machine was a Raspberry Pi 3 Model B plus board containing a 1.4 GHz 64-bit quad-core Cortex-A53 processor.
  • The client and server were connected by a Cisco 9300 series enterprise switch over Gbit Ethernet.
  • The data contains pow(2,18) samples.
  • The data was used to produce Figure 1 in the paper and contains all the remote timing attack data from Section 4.

Data description

The file remote_timings.json contains a single JSON array. Each entry is a dictionary representation of one digital signature. A description of the dictionary fields follows.

  • p: prime (DSA parameter).
  • q: generator order (DSA parameter).
  • g: generator (DSA parameter).
  • x: the DSA private key.
  • y: the corresponding public key.
  • r: first component of the DSA signature.
  • s: second component of the DSA signature.
  • k: the ground truth nonce generated during DSA signing.
  • k_len: the ground truth number of bits in said nonce.
  • msg: message digitally signed.
  • h: SHA-256 hash of said message. (Truncated to the same bitlen as q.)
  • id: ignored.
  • latency: the measured wall clock time (CPU clock cycles) to produce the digital signature.

Prerequisites

sudo apt install openssl python3-ijson xxd jq

Data setup

Extract the JSON:

tar xf remote_timings_rpi.tar.gz

Key setup

Generate the public key (public.pem here) from the provided private key (private.pem here):

$ openssl pkey -in private.pem -pubout -out public.pem

Examine the keys if you want.

$ openssl pkey -in private.pem -text -noout
$ openssl pkey -in public.pem -text -noout -pubin

Example: Verify key material

$ openssl pkey -in private.pem -text -noout
Private-Key: (2048 bit)
priv:
    1f:87:68:eb:57:e1:f4:f1:29:a6:c8:ca:03:c8:db:
    49:1d:8e:2b:81:bd:72:92:64:0c:1c:d6:6d
pub: 
    00:9d:fa:bc:47:00:cb:11:fa:51:45:c1:bd:b1:88:
    2d:dd:a2:79:5b:c3:43:0a:af:bb:83:e2:d5:84:d1:
    07:01:ab:f9:ae:76:2d:dd:f2:a5:75:f5:3e:94:4d:
    3b:c6:f6:ce:17:c6:60:09:5b:49:3d:cb:a0:db:ec:
    29:91:85:8b:c3:f5:6c:6a:3c:01:87:12:85:ae:fc:
    9e:bf:67:81:1b:1d:b1:9d:12:bd:79:8c:54:08:48:
    11:13:6d:ab:b0:16:ef:11:4a:27:a7:0a:80:b3:db:
    72:c1:cc:1e:e8:4a:39:b7:00:ca:97:b7:3a:6e:e9:
    25:22:2e:5c:57:ee:62:be:23:d0:5e:53:a3:9f:05:
    d4:7d:7f:b5:b6:cb:4b:27:90:14:79:72:a5:43:97:
    c6:6a:7d:f7:32:b3:67:58:90:fc:c3:65:34:57:89:
    1b:43:28:68:43:24:12:5e:f1:43:76:3c:e9:bc:9c:
    5d:7d:ae:d6:3a:31:32:ca:df:a4:07:88:a2:55:6e:
    a4:8c:da:13:c8:30:b7:2a:1c:23:0f:32:da:9e:7f:
    e1:f7:3d:2d:1c:58:f5:1d:f2:7d:fb:67:45:8d:dd:
    84:eb:83:c4:b0:00:a6:c2:09:b0:48:48:f9:4e:a8:
    d7:ab:e1:c6:e8:bf:5c:fa:e3:f2:cd:c6:f1:e7:f2:
    2c:90
P:
    00:e5:4e:f4:32:f8:4a:ec:28:3c:dd:32:a8:05:e3:
    5a:fa:a5:81:47:98:d9:a7:94:ba:34:b0:f9:7b:20:
    c5:fb:52:12:3e:82:d7:6e:6f:f5:50:be:5e:9f:df:
    82:9b:4e:0c:9d:a2:9f:3f:0a:f3:72:c2:55:7c:46:
    6e:fe:48:00:88:b6:4e:4f:9b:19:8c:98:3b:71:42:
    56:d2:b4:1c:47:69:6e:fc:f0:e6:26:04:0e:e2:63:
    ed:06:0f:fb:a8:a9:94:73:e1:41:e0:6b:5a:b4:d9:
    86:cd:7b:46:d3:39:ba:18:13:da:f2:3a:7b:dc:41:
    21:83:e8:0d:25:13:31:90:5d:bd:82:41:9b:ea:6b:
    8a:ba:8a:48:b1:1d:d2:3d:5e:c4:1b:29:5e:7f:b6:
    56:1b:e6:91:65:ec:84:82:c2:f6:a1:b0:14:1b:0b:
    08:d8:2b:2a:06:17:d7:2a:9b:c3:aa:fb:28:26:14:
    3f:5d:0a:48:1a:48:45:c0:fd:ea:ec:90:6c:ec:93:
    c8:af:a3:31:4b:3a:d8:cd:20:ae:8f:14:58:26:49:
    18:1f:7a:99:c9:da:c3:f0:76:b8:52:8d:eb:b2:e2:
    98:6b:a5:47:15:c3:ff:c8:e7:6c:d3:db:c7:fb:4c:
    36:3e:15:eb:45:e1:4a:5d:01:ed:3b:87:f7:69:c1:
    31:59
Q:
    00:ca:6d:df:fc:7b:96:2e:35:30:27:4f:1f:cf:57:
    2f:e9:4c:40:97:53:a1:fa:d0:89:56:8d:2c:25
G:
    43:26:04:66:b3:80:c3:3f:8d:f5:5a:29:79:58:7a:
    0b:8c:72:b9:cb:23:61:5d:c1:45:c5:38:7f:33:4e:
    93:63:75:8a:b0:44:61:8f:59:df:fd:2f:3f:1f:22:
    73:66:ba:53:65:53:2a:57:5b:d9:40:34:be:4c:78:
    22:4a:bf:94:5d:23:15:65:66:e1:1f:6b:93:12:00:
    f0:ac:f5:64:0d:6d:6c:a3:eb:26:83:6d:68:95:e0:
    2c:bf:75:62:fa:5f:95:0f:b0:40:68:ce:66:3b:58:
    ed:c1:63:e3:d8:35:5c:cc:db:b8:12:e6:62:e4:63:
    b6:29:e0:86:75:79:bc:95:27:74:d1:fd:94:b9:7f:
    6e:57:b4:e5:39:a2:15:41:94:3f:47:90:43:a5:da:
    dd:08:a4:92:c5:bf:ef:34:4e:2e:7e:82:5c:07:0e:
    dc:5d:6b:79:10:04:53:cc:b2:8e:bd:65:61:80:49:
    ad:c7:dd:5f:5a:9b:74:ae:bc:e0:49:f1:ad:4c:1e:
    8f:4e:9d:39:e9:fe:57:4d:39:b7:ba:69:03:e3:7e:
    4d:0d:9b:65:c3:55:77:ff:2c:86:27:21:c7:3e:60:
    a3:23:a5:e8:7e:0d:29:15:1c:5e:04:91:91:25:03:
    f3:97:77:6c:11:24:34:58:c9:ec:b7:ca:ce:74:cd:
    a7

This shows the keys indeed match (JSON x,y, above priv,pub):

$ grep --max-count=1 '"x"' remote_timings.json
"x": "0x1F8768EB57E1F4F129A6C8CA03C8DB491D8E2B81BD7292640C1CD66D",
$ grep --max-count=1 '"y"' remote_timings.json
"y": "0x9DFABC4700CB11FA5145C1BDB1882DDDA2795BC3430AAFBB83E2D584D10701ABF9AE762DDDF2A575F53E944D3BC6F6CE17C660095B493DCBA0DBEC2991858BC3F56C6A3C01871285AEFC9EBF67811B1DB19D12BD798C54084811136DABB016EF114A27A70A80B3DB72C1CC1EE84A39B700CA97B73A6EE925222E5C57EE62BE23D05E53A39F05D47D7FB5B6CB4B2790147972A54397C66A7DF732B3675890FCC3653457891B4328684324125EF143763CE9BC9C5D7DAED63A3132CADFA40788A2556EA48CDA13C830B72A1C230F32DA9E7FE1F73D2D1C58F51DF27DFB67458DDD84EB83C4B000A6C209B04848F94EA8D7ABE1C6E8BF5CFAE3F2CDC6F1E7F22C90",

This shows the DSA parameters match (JSON p,q,g, above P,Q,G):

$ grep --max-count=1 '"p"' remote_timings.json
"p": "0xE54EF432F84AEC283CDD32A805E35AFAA5814798D9A794BA34B0F97B20C5FB52123E82D76E6FF550BE5E9FDF829B4E0C9DA29F3F0AF372C2557C466EFE480088B64E4F9B198C983B714256D2B41C47696EFCF0E626040EE263ED060FFBA8A99473E141E06B5AB4D986CD7B46D339BA1813DAF23A7BDC412183E80D251331905DBD82419BEA6B8ABA8A48B11DD23D5EC41B295E7FB6561BE69165EC8482C2F6A1B0141B0B08D82B2A0617D72A9BC3AAFB2826143F5D0A481A4845C0FDEAEC906CEC93C8AFA3314B3AD8CD20AE8F14582649181F7A99C9DAC3F076B8528DEBB2E2986BA54715C3FFC8E76CD3DBC7FB4C363E15EB45E14A5D01ED3B87F769C13159",
$ grep --max-count=1 '"q"' remote_timings.json
"q": "0xCA6DDFFC7B962E3530274F1FCF572FE94C409753A1FAD089568D2C25",
$ grep --max-count=1 '"g"' remote_timings.json
"g": "0x43260466B380C33F8DF55A2979587A0B8C72B9CB23615DC145C5387F334E9363758AB044618F59DFFD2F3F1F227366BA5365532A575BD94034BE4C78224ABF945D23156566E11F6B931200F0ACF5640D6D6CA3EB26836D6895E02CBF7562FA5F950FB04068CE663B58EDC163E3D8355CCCDBB812E662E463B629E0867579BC952774D1FD94B97F6E57B4E539A21541943F479043A5DADD08A492C5BFEF344E2E7E825C070EDC5D6B79100453CCB28EBD65618049ADC7DD5F5A9B74AEBCE049F1AD4C1E8F4E9D39E9FE574D39B7BA6903E37E4D0D9B65C35577FF2C862721C73E60A323A5E87E0D29151C5E0491912503F397776C11243458C9ECB7CACE74CDA7",

Example: Extract a single entry

Here we use the python script pickone.py to extract the entry at index 2 (starting from 0).

$ python3 pickone.py remote_timings.json 2 | jq . > 2.json
$ cat 2.json 
{
  "latency": "399901598",
  "y": "0x9DFABC4700CB11FA5145C1BDB1882DDDA2795BC3430AAFBB83E2D584D10701ABF9AE762DDDF2A575F53E944D3BC6F6CE17C660095B493DCBA0DBEC2991858BC3F56C6A3C01871285AEFC9EBF67811B1DB19D12BD798C54084811136DABB016EF114A27A70A80B3DB72C1CC1EE84A39B700CA97B73A6EE925222E5C57EE62BE23D05E53A39F05D47D7FB5B6CB4B2790147972A54397C66A7DF732B3675890FCC3653457891B4328684324125EF143763CE9BC9C5D7DAED63A3132CADFA40788A2556EA48CDA13C830B72A1C230F32DA9E7FE1F73D2D1C58F51DF27DFB67458DDD84EB83C4B000A6C209B04848F94EA8D7ABE1C6E8BF5CFAE3F2CDC6F1E7F22C90",
  "g": "0x43260466B380C33F8DF55A2979587A0B8C72B9CB23615DC145C5387F334E9363758AB044618F59DFFD2F3F1F227366BA5365532A575BD94034BE4C78224ABF945D23156566E11F6B931200F0ACF5640D6D6CA3EB26836D6895E02CBF7562FA5F950FB04068CE663B58EDC163E3D8355CCCDBB812E662E463B629E0867579BC952774D1FD94B97F6E57B4E539A21541943F479043A5DADD08A492C5BFEF344E2E7E825C070EDC5D6B79100453CCB28EBD65618049ADC7DD5F5A9B74AEBCE049F1AD4C1E8F4E9D39E9FE574D39B7BA6903E37E4D0D9B65C35577FF2C862721C73E60A323A5E87E0D29151C5E0491912503F397776C11243458C9ECB7CACE74CDA7",
  "h": "0xC7DEAC64C95157992CB0D77CF944CB107C756F3E30D1C49C0C48A6EA",
  "k": "0x742A7562E2A192996440AE2A4FDF5D37E1A532E1E6A50BCA3964BBDA",
  "q": "0xCA6DDFFC7B962E3530274F1FCF572FE94C409753A1FAD089568D2C25",
  "p": "0xE54EF432F84AEC283CDD32A805E35AFAA5814798D9A794BA34B0F97B20C5FB52123E82D76E6FF550BE5E9FDF829B4E0C9DA29F3F0AF372C2557C466EFE480088B64E4F9B198C983B714256D2B41C47696EFCF0E626040EE263ED060FFBA8A99473E141E06B5AB4D986CD7B46D339BA1813DAF23A7BDC412183E80D251331905DBD82419BEA6B8ABA8A48B11DD23D5EC41B295E7FB6561BE69165EC8482C2F6A1B0141B0B08D82B2A0617D72A9BC3AAFB2826143F5D0A481A4845C0FDEAEC906CEC93C8AFA3314B3AD8CD20AE8F14582649181F7A99C9DAC3F076B8528DEBB2E2986BA54715C3FFC8E76CD3DBC7FB4C363E15EB45E14A5D01ED3B87F769C13159",
  "s": "0x79FD73D901BB077D14334D8CC714804577515A1E0ADC9F995BB7534C",
  "r": "0x61F949D772E22EA9EFBB36442BC229767B28BE2A8061FA7339AFDDC8",
  "msg": "0x318198301A06092A864886F70D010903310D060B2A864886F70D0109100104301C06092A864886F70D010905310F170D3230303432343131333135375A302B060B2A864886F70D010910020C311C301A30183016041470AD64D33E65A855E6C332AA52736F71D58E7527302F06092A864886F70D0109043122042090C90BFC7A8C459EDB5AF58A8878EE826B6FD02A20E2BAAF2C73984FA380FDD2",
  "x": "0x1F8768EB57E1F4F129A6C8CA03C8DB491D8E2B81BD7292640C1CD66D",
  "id": "335451053151725",
  "k_len": "223"
}

Example: Dump message to binary file

Extract the msg field from the target JSON and dump it as binary.

$ sed -n 's/^  "msg": "0x\(.*\)",$/\1/p' 2.json | xxd -r -p > 2.msg
$ xxd -g1 2.msg
00000000: 31 81 98 30 1a 06 09 2a 86 48 86 f7 0d 01 09 03  1..0...*.H......
00000010: 31 0d 06 0b 2a 86 48 86 f7 0d 01 09 10 01 04 30  1...*.H........0
00000020: 1c 06 09 2a 86 48 86 f7 0d 01 09 05 31 0f 17 0d  ...*.H......1...
00000030: 32 30 30 34 32 34 31 31 33 31 35 37 5a 30 2b 06  200424113157Z0+.
00000040: 0b 2a 86 48 86 f7 0d 01 09 10 02 0c 31 1c 30 1a  .*.H........1.0.
00000050: 30 18 30 16 04 14 70 ad 64 d3 3e 65 a8 55 e6 c3  0.0...p.d.>e.U..
00000060: 32 aa 52 73 6f 71 d5 8e 75 27 30 2f 06 09 2a 86  2.Rsoq..u'0/..*.
00000070: 48 86 f7 0d 01 09 04 31 22 04 20 90 c9 0b fc 7a  H......1". ....z
00000080: 8c 45 9e db 5a f5 8a 88 78 ee 82 6b 6f d0 2a 20  .E..Z...x..ko.* 
00000090: e2 ba af 2c 73 98 4f a3 80 fd d2                 ...,s.O....

Note the xxd output matches the msg byte string from the target JSON.

Example: Dump hash to binary file

Extract the h field from the target JSON and dump it as binary.

$ sed -n 's/^  "h": "0x\(.*\)",$/\1/p' 2.json | xxd -r -p > 2.hash
$ xxd -g1 2.hash
00000000: c7 de ac 64 c9 51 57 99 2c b0 d7 7c f9 44 cb 10  ...d.QW.,..|.D..
00000010: 7c 75 6f 3e 30 d1 c4 9c 0c 48 a6 ea              |uo>0....H..

Note the xxd output matches the h byte string from the target JSON.

Example: Hash is consistent

$ sha256sum 2.msg
c7deac64c95157992cb0d77cf944cb107c756f3e30d1c49c0c48a6ea809e6d58  2.msg

Note the first 28 bytes of sha256sum output match the h byte string from the target JSON. (DSA maps to GF(q) with truncation.)

Example: Dump signature to DER

The hex2der.sh script takes as an argument the target JSON filename, and outputs the DER-encoded DSA signature to stdout by extracting the r and s fields from the target JSON.

$ ./hex2der.sh 2.json > 2.der
$ openssl asn1parse -in 2.der -inform DER
    0:d=0  hl=2 l=  60 cons: SEQUENCE
    2:d=1  hl=2 l=  28 prim: INTEGER           :61F949D772E22EA9EFBB36442BC229767B28BE2A8061FA7339AFDDC8
   32:d=1  hl=2 l=  28 prim: INTEGER           :79FD73D901BB077D14334D8CC714804577515A1E0ADC9F995BB7534C

Note the asn1parse output contains a sequence with two integers, matching the r and s fields from the target JSON.

Example: Verify the signature (post-hash)

We use pkeyutl here to verify the raw hash directly.

$ openssl pkeyutl -in 2.hash -inkey public.pem -pubin -verify -sigfile 2.der
Signature Verified Successfully

Note it fails for other hashes (messages), a fundamental security property for digital signatures:

$ dd if=/dev/urandom of=bad.hash bs=1 count=28
28+0 records in
28+0 records out
28 bytes copied, 0.000647097 s, 43.3 kB/s
$ openssl pkeyutl -in bad.hash -inkey public.pem -pubin -verify -sigfile 2.der
Signature Verification Failure

Example: Verify the signature (pre-hash)

We use dgst here to verify by recomputing the hash.

$ openssl dgst -sha256 -verify public.pem -signature 2.der 2.msg
Verified OK

Example: Message analysis

The msg JSON field is an RFC 3161 Time Stamp Request. You can examine it:

$ openssl asn1parse -in 2.msg -inform DER
    0:d=0  hl=3 l= 152 cons: SET               
    3:d=1  hl=2 l=  26 cons: SEQUENCE          
    5:d=2  hl=2 l=   9 prim: OBJECT            :contentType
   16:d=2  hl=2 l=  13 cons: SET               
   18:d=3  hl=2 l=  11 prim: OBJECT            :id-smime-ct-TSTInfo
   31:d=1  hl=2 l=  28 cons: SEQUENCE          
   33:d=2  hl=2 l=   9 prim: OBJECT            :signingTime
   44:d=2  hl=2 l=  15 cons: SET               
   46:d=3  hl=2 l=  13 prim: UTCTIME           :200424113157Z
   61:d=1  hl=2 l=  43 cons: SEQUENCE          
   63:d=2  hl=2 l=  11 prim: OBJECT            :id-smime-aa-signingCertificate
   76:d=2  hl=2 l=  28 cons: SET               
   78:d=3  hl=2 l=  26 cons: SEQUENCE          
   80:d=4  hl=2 l=  24 cons: SEQUENCE          
   82:d=5  hl=2 l=  22 cons: SEQUENCE          
   84:d=6  hl=2 l=  20 prim: OCTET STRING      [HEX DUMP]:70AD64D33E65A855E6C332AA52736F71D58E7527
  106:d=1  hl=2 l=  47 cons: SEQUENCE          
  108:d=2  hl=2 l=   9 prim: OBJECT            :messageDigest
  119:d=2  hl=2 l=  34 cons: SET               
  121:d=3  hl=2 l=  32 prim: OCTET STRING      [HEX DUMP]:90C90BFC7A8C459EDB5AF58A8878EE826B6FD02A20E2BAAF2C73984FA380FDD2

Example: Statistics

The stats.py script shows how to extract the desired fields from the JSON. It computes the median latency over each nonce bit length.

$ python3 stats.py remote_timings.json 
Len Median
205 121.2
206 121.2
207 120.6
208 138.3
209 122.9
210 123.0
211 123.0
212 123.0
213 125.0
214 125.0
215 125.0
216 125.0
217 127.1
218 127.1
219 127.1
220 127.1
221 129.1
222 129.1
223 129.1
224 129.1

You can verify these medians are consistent with Figure 1 in the paper.

The stats.py script can be easily modified for more advanced analysis.

Credits

Some parts borrowed from this artifact.

Authors

  • Sohaib ul Hassan (Tampere University, Tampere, Finland)
  • Iaroslav Gridin (Tampere University, Tampere, Finland)
  • Ignacio M. Delgado-Lozano (Tampere University, Tampere, Finland)
  • Cesar Pereida García (Tampere University, Tampere, Finland)
  • Jesús-Javier Chi-Domínguez (Tampere University, Tampere, Finland)
  • Alejandro Cabrera Aldaya (Tampere University, Tampere, Finland)
  • Billy Bob Brumley (Tampere University, Tampere, Finland)

Funding

This project has received funding from the European Research Council (ERC) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 804476).

License

This project is distributed under MIT license.

Files

README.md

Files (57.4 MB)

Name Size Download all
md5:d8e42219cd9098ac45d609b8b4d1142b
1.8 kB Download
md5:c3336167c97535efb87739e4e9f1a6df
1.4 kB Download
md5:9946de83f5ca475e97849aa51282321d
1.8 kB Download
md5:94d01431962592b511bc106377f4b294
879 Bytes Download
md5:e0f993ae357af907f71bdff439b8d116
15.6 kB Preview Download
md5:1c2eb4c8e6ae27d061ea00be6ae677bd
57.4 MB Download
md5:26e5c8ec8f62ca5d1095544fda78eeb6
2.2 kB Download

Additional details

Funding

SCARE – Side-Channel Aware Engineering 804476
European Commission