renamed 'hf mfdes readdata, writedata' to 'read/write'
[RRG-proxmark3.git] / client / src / fido / cose.c
blob9caa0f4cc9ffa03735529e806df378e27b8e97d1
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 Merlok
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // Tools for work with COSE (CBOR Object Signing and Encryption) rfc8152
9 // https://tools.ietf.org/html/rfc8152
10 //-----------------------------------------------------------------------------
13 #include "cose.h"
15 #include "cbortools.h"
16 #include "commonutil.h" // ARRAYLEN
17 #include "ui.h" // Print...
18 #include "util.h"
20 static const char COSEEmptyStr[] = "";
22 typedef struct {
23 int Value;
24 const char *Name;
25 const char *Description;
26 } COSEValueNameDesc_t;
28 typedef struct {
29 int Value;
30 const char *Type;
31 const char *Name;
32 const char *Description;
33 } COSEValueTypeNameDesc_t;
35 // kty - Key Type Values
36 COSEValueNameDesc_t COSEKeyTypeValueDesc[] = {
37 {0, "Reserved", "Reserved"},
38 {1, "OKP", "Octet Key Pair"},
39 {2, "EC2", "Elliptic Curve Key w/ x- and y-coordinate pair"},
40 {4, "Symmetric", "Symmetric Key"},
43 static COSEValueNameDesc_t *GetCOSEktyElm(int id) {
44 for (size_t i = 0; i < ARRAYLEN(COSEKeyTypeValueDesc); i++)
45 if (COSEKeyTypeValueDesc[i].Value == id)
46 return &COSEKeyTypeValueDesc[i];
47 return NULL;
50 const char *GetCOSEktyDescription(int id) {
51 COSEValueNameDesc_t *elm = GetCOSEktyElm(id);
52 if (elm)
53 return elm->Description;
54 return COSEEmptyStr;
57 // keys
58 COSEValueTypeNameDesc_t COSECurvesDesc[] = {
59 {1, "EC2", "P-256", "NIST P-256 also known as secp256r1"},
60 {2, "EC2", "P-384", "NIST P-384 also known as secp384r1"},
61 {3, "EC2", "P-521", "NIST P-521 also known as secp521r1"},
62 {4, "OKP", "X25519", "X25519 for use w/ ECDH only"},
63 {5, "OKP", "X448", "X448 for use w/ ECDH only"},
64 {6, "OKP", "Ed25519", "Ed25519 for use w/ EdDSA only"},
65 {7, "OKP", "Ed448", "Ed448 for use w/ EdDSA only"},
68 static COSEValueTypeNameDesc_t *GetCOSECurveElm(int id) {
69 for (size_t i = 0; i < ARRAYLEN(COSECurvesDesc); i++)
70 if (COSECurvesDesc[i].Value == id)
71 return &COSECurvesDesc[i];
72 return NULL;
75 const char *GetCOSECurveDescription(int id) {
76 COSEValueTypeNameDesc_t *elm = GetCOSECurveElm(id);
77 if (elm)
78 return elm->Description;
79 return COSEEmptyStr;
82 // RFC8152 https://www.iana.org/assignments/cose/cose.xhtml#algorithms
83 COSEValueNameDesc_t COSEAlg[] = {
84 { -65536, "Unassigned", "Unassigned"},
85 { -65535, "RS1", "RSASSA-PKCS1-v1_5 w/ SHA-1"},
86 { -259, "RS512", "RSASSA-PKCS1-v1_5 w/ SHA-512"},
87 { -258, "RS384", "RSASSA-PKCS1-v1_5 w/ SHA-384"},
88 { -257, "RS256", "RSASSA-PKCS1-v1_5 w/ SHA-256"},
89 { -42, "RSAES-OAEP w/ SHA-512", "RSAES-OAEP w/ SHA-512"},
90 { -41, "RSAES-OAEP w/ SHA-256", "RSAES-OAEP w/ SHA-256"},
91 { -40, "RSAES-OAEP w/ RFC 8017 def param", "RSAES-OAEP w/ SHA-1"},
92 { -39, "PS512", "RSASSA-PSS w/ SHA-512"},
93 { -38, "PS384", "RSASSA-PSS w/ SHA-384"},
94 { -37, "PS256", "RSASSA-PSS w/ SHA-256"},
95 { -36, "ES512", "ECDSA w/ SHA-512"},
96 { -35, "ES384", "ECDSA w/ SHA-384"},
97 { -34, "ECDH-SS + A256KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 256-bit key"},
98 { -33, "ECDH-SS + A192KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 192-bit key"},
99 { -32, "ECDH-SS + A128KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 128-bit key"},
100 { -31, "ECDH-ES + A256KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 256-bit key"},
101 { -30, "ECDH-ES + A192KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 192-bit key"},
102 { -29, "ECDH-ES + A128KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 128-bit key"},
103 { -28, "ECDH-SS + HKDF-512", "ECDH SS w/ HKDF - generate key directly"},
104 { -27, "ECDH-SS + HKDF-256", "ECDH SS w/ HKDF - generate key directly"},
105 { -26, "ECDH-ES + HKDF-512", "ECDH ES w/ HKDF - generate key directly"},
106 { -25, "ECDH-ES + HKDF-256", "ECDH ES w/ HKDF - generate key directly"},
107 { -13, "direct+HKDF-AES-256", "Shared secret w/ AES-MAC 256-bit key"},
108 { -12, "direct+HKDF-AES-128", "Shared secret w/ AES-MAC 128-bit key"},
109 { -11, "direct+HKDF-SHA-512", "Shared secret w/ HKDF and SHA-512"},
110 { -10, "direct+HKDF-SHA-256", "Shared secret w/ HKDF and SHA-256"},
111 { -8, "EdDSA", "EdDSA"},
112 { -7, "ES256", "ECDSA w/ SHA-256"},
113 { -6, "direct", "Direct use of CEK"},
114 { -5, "A256KW", "AES Key Wrap w/ 256-bit key"},
115 { -4, "A192KW", "AES Key Wrap w/ 192-bit key"},
116 { -3, "A128KW", "AES Key Wrap w/ 128-bit key"},
117 {0, "Reserved", "Reserved"},
118 {1, "A128GCM", "AES-GCM mode w/ 128-bit key, 128-bit tag"},
119 {2, "A192GCM", "AES-GCM mode w/ 192-bit key, 128-bit tag"},
120 {3, "A256GCM", "AES-GCM mode w/ 256-bit key, 128-bit tag"},
121 {4, "HMAC 256/64", "HMAC w/ SHA-256 truncated to 64 bits"},
122 {5, "HMAC 256/256", "HMAC w/ SHA-256"},
123 {6, "HMAC 384/384", "HMAC w/ SHA-384"},
124 {7, "HMAC 512/512", "HMAC w/ SHA-512"},
125 {10, "AES-CCM-16-64-128", "AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce"},
126 {11, "AES-CCM-16-64-256", "AES-CCM mode 256-bit key, 64-bit tag, 13-byte nonce"},
127 {12, "AES-CCM-64-64-128", "AES-CCM mode 128-bit key, 64-bit tag, 7-byte nonce"},
128 {13, "AES-CCM-64-64-256", "AES-CCM mode 256-bit key, 64-bit tag, 7-byte nonce"},
129 {14, "AES-MAC 128/64", "AES-MAC 128-bit key, 64-bit tag"},
130 {15, "AES-MAC 256/64", "AES-MAC 256-bit key, 64-bit tag"},
131 {24, "ChaCha20/Poly1305", "ChaCha20/Poly1305 w/ 256-bit key, 128-bit tag"},
132 {25, "AES-MAC 128/128", "AES-MAC 128-bit key, 128-bit tag"},
133 {26, "AES-MAC 256/128", "AES-MAC 256-bit key, 128-bit tag"},
134 {30, "AES-CCM-16-128-128", "AES-CCM mode 128-bit key, 128-bit tag, 13-byte nonce"},
135 {31, "AES-CCM-16-128-256", "AES-CCM mode 256-bit key, 128-bit tag, 13-byte nonce"},
136 {32, "AES-CCM-64-128-128", "AES-CCM mode 128-bit key, 128-bit tag, 7-byte nonce"},
137 {33, "AES-CCM-64-128-256", "AES-CCM mode 256-bit key, 128-bit tag, 7-byte nonce"}
140 static COSEValueNameDesc_t *GetCOSEAlgElm(int id) {
141 for (size_t i = 0; i < ARRAYLEN(COSEAlg); i++)
142 if (COSEAlg[i].Value == id)
143 return &COSEAlg[i];
144 return NULL;
147 const char *GetCOSEAlgName(int id) {
148 COSEValueNameDesc_t *elm = GetCOSEAlgElm(id);
149 if (elm)
150 return elm->Name;
151 return COSEEmptyStr;
154 const char *GetCOSEAlgDescription(int id) {
155 COSEValueNameDesc_t *elm = GetCOSEAlgElm(id);
156 if (elm)
157 return elm->Description;
158 return COSEEmptyStr;
161 int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public_key) {
162 CborParser parser;
163 CborValue map;
164 int64_t i64;
165 size_t len;
167 if (verbose)
168 PrintAndLogEx(NORMAL, "----------- CBOR decode ----------------");
170 // kty
171 int res = CborMapGetKeyById(&parser, &map, data, datalen, 1);
172 if (!res) {
173 cbor_value_get_int64(&map, &i64);
174 if (verbose)
175 PrintAndLogEx(SUCCESS, "kty [%lld] %s", (long long)i64, GetCOSEktyDescription(i64));
176 if (i64 != 2)
177 PrintAndLogEx(ERR, "ERROR: kty must be 2.");
180 // algorithm
181 res = CborMapGetKeyById(&parser, &map, data, datalen, 3);
182 if (!res) {
183 cbor_value_get_int64(&map, &i64);
184 if (verbose)
185 PrintAndLogEx(SUCCESS, "algorithm [%lld] %s", (long long)i64, GetCOSEAlgDescription(i64));
186 if (i64 != -7)
187 PrintAndLogEx(ERR, "ERROR: algorithm must be -7.");
190 // curve
191 res = CborMapGetKeyById(&parser, &map, data, datalen, -1);
192 if (!res) {
193 cbor_value_get_int64(&map, &i64);
194 if (verbose)
195 PrintAndLogEx(SUCCESS, "curve [%lld] %s", (long long)i64, GetCOSECurveDescription(i64));
196 if (i64 != 1)
197 PrintAndLogEx(ERR, "ERROR: curve must be 1.");
200 // plain key
201 public_key[0] = 0x04;
203 // x - coordinate
204 res = CborMapGetKeyById(&parser, &map, data, datalen, -2);
205 if (!res) {
206 res = CborGetBinStringValue(&map, &public_key[1], 32, &len);
207 cbor_check(res);
208 if (verbose)
209 PrintAndLogEx(SUCCESS, "x - coordinate [%zu]: %s", len, sprint_hex(&public_key[1], 32));
210 if (len != 32)
211 PrintAndLogEx(ERR, "ERROR: x - coordinate length must be 32.");
214 // y - coordinate
215 res = CborMapGetKeyById(&parser, &map, data, datalen, -3);
216 if (!res) {
217 res = CborGetBinStringValue(&map, &public_key[33], 32, &len);
218 cbor_check(res);
219 if (verbose)
220 PrintAndLogEx(SUCCESS, "y - coordinate [%zu]: %s", len, sprint_hex(&public_key[33], 32));
221 if (len != 32)
222 PrintAndLogEx(ERR, "ERROR: y - coordinate length must be 32.");
225 // d - private key
226 res = CborMapGetKeyById(&parser, &map, data, datalen, -4);
227 if (!res) {
228 uint8_t private_key[128] = {0};
229 res = CborGetBinStringValue(&map, private_key, sizeof(private_key), &len);
230 cbor_check(res);
231 if (verbose)
232 PrintAndLogEx(SUCCESS, "d - private key [%zu]: %s", len, sprint_hex(private_key, len));
235 if (verbose)
236 PrintAndLogEx(NORMAL, "----------- CBOR decode ----------------");
238 return 0;