| 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 | //----------------------------------------------------------------------------- |
| 11 | // |
| 12 | |
| 13 | #include "cose.h" |
| 14 | #include <cbor.h> |
| 15 | #include "cbortools.h" |
| 16 | #include "util.h" |
| 17 | #include "ui.h" |
| 18 | |
| 19 | static const char COSEEmptyStr[] = ""; |
| 20 | |
| 21 | typedef struct { |
| 22 | int Value; |
| 23 | char *Name; |
| 24 | char *Description; |
| 25 | } COSEValueNameDesc_t; |
| 26 | |
| 27 | typedef struct { |
| 28 | int Value; |
| 29 | char *Type; |
| 30 | char *Name; |
| 31 | char *Description; |
| 32 | } COSEValueTypeNameDesc_t; |
| 33 | |
| 34 | // kty - Key Type Values |
| 35 | COSEValueNameDesc_t COSEKeyTypeValueDesc[] = { |
| 36 | {0, "Reserved", "Reserved"}, |
| 37 | {1, "OKP", "Octet Key Pair"}, |
| 38 | {2, "EC2", "Elliptic Curve Key w/ x- and y-coordinate pair"}, |
| 39 | {4, "Symmetric", "Symmetric Key"}, |
| 40 | }; |
| 41 | |
| 42 | COSEValueNameDesc_t *GetCOSEktyElm(int id) { |
| 43 | for (int i = 0; i < ARRAYLEN(COSEKeyTypeValueDesc); i++) |
| 44 | if (COSEKeyTypeValueDesc[i].Value == id) |
| 45 | return &COSEKeyTypeValueDesc[i]; |
| 46 | return NULL; |
| 47 | } |
| 48 | |
| 49 | const char *GetCOSEktyDescription(int id) { |
| 50 | COSEValueNameDesc_t *elm = GetCOSEktyElm(id); |
| 51 | if (elm) |
| 52 | return elm->Description; |
| 53 | return COSEEmptyStr; |
| 54 | } |
| 55 | |
| 56 | // keys |
| 57 | COSEValueTypeNameDesc_t COSECurvesDesc[] = { |
| 58 | {1, "EC2", "P-256", "NIST P-256 also known as secp256r1"}, |
| 59 | {2, "EC2", "P-384", "NIST P-384 also known as secp384r1"}, |
| 60 | {3, "EC2", "P-521", "NIST P-521 also known as secp521r1"}, |
| 61 | {4, "OKP", "X25519", "X25519 for use w/ ECDH only"}, |
| 62 | {5, "OKP", "X448", "X448 for use w/ ECDH only"}, |
| 63 | {6, "OKP", "Ed25519", "Ed25519 for use w/ EdDSA only"}, |
| 64 | {7, "OKP", "Ed448", "Ed448 for use w/ EdDSA only"}, |
| 65 | }; |
| 66 | |
| 67 | COSEValueTypeNameDesc_t *GetCOSECurveElm(int id) { |
| 68 | for (int i = 0; i < ARRAYLEN(COSECurvesDesc); i++) |
| 69 | if (COSECurvesDesc[i].Value == id) |
| 70 | return &COSECurvesDesc[i]; |
| 71 | return NULL; |
| 72 | } |
| 73 | |
| 74 | const char *GetCOSECurveDescription(int id) { |
| 75 | COSEValueTypeNameDesc_t *elm = GetCOSECurveElm(id); |
| 76 | if (elm) |
| 77 | return elm->Description; |
| 78 | return COSEEmptyStr; |
| 79 | } |
| 80 | |
| 81 | // RFC8152 https://www.iana.org/assignments/cose/cose.xhtml#algorithms |
| 82 | COSEValueNameDesc_t COSEAlg[] = { |
| 83 | {-65536, "Unassigned", "Unassigned"}, |
| 84 | {-65535, "RS1", "RSASSA-PKCS1-v1_5 w/ SHA-1"}, |
| 85 | {-259, "RS512", "RSASSA-PKCS1-v1_5 w/ SHA-512"}, |
| 86 | {-258, "RS384", "RSASSA-PKCS1-v1_5 w/ SHA-384"}, |
| 87 | {-257, "RS256", "RSASSA-PKCS1-v1_5 w/ SHA-256"}, |
| 88 | {-42, "RSAES-OAEP w/ SHA-512", "RSAES-OAEP w/ SHA-512"}, |
| 89 | {-41, "RSAES-OAEP w/ SHA-256", "RSAES-OAEP w/ SHA-256"}, |
| 90 | {-40, "RSAES-OAEP w/ RFC 8017 def param", "RSAES-OAEP w/ SHA-1"}, |
| 91 | {-39, "PS512", "RSASSA-PSS w/ SHA-512"}, |
| 92 | {-38, "PS384", "RSASSA-PSS w/ SHA-384"}, |
| 93 | {-37, "PS256", "RSASSA-PSS w/ SHA-256"}, |
| 94 | {-36, "ES512", "ECDSA w/ SHA-512"}, |
| 95 | {-35, "ES384", "ECDSA w/ SHA-384"}, |
| 96 | {-34, "ECDH-SS + A256KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 256-bit key"}, |
| 97 | {-33, "ECDH-SS + A192KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 192-bit key"}, |
| 98 | {-32, "ECDH-SS + A128KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 128-bit key"}, |
| 99 | {-31, "ECDH-ES + A256KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 256-bit key"}, |
| 100 | {-30, "ECDH-ES + A192KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 192-bit key"}, |
| 101 | {-29, "ECDH-ES + A128KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 128-bit key"}, |
| 102 | {-28, "ECDH-SS + HKDF-512", "ECDH SS w/ HKDF - generate key directly"}, |
| 103 | {-27, "ECDH-SS + HKDF-256", "ECDH SS w/ HKDF - generate key directly"}, |
| 104 | {-26, "ECDH-ES + HKDF-512", "ECDH ES w/ HKDF - generate key directly"}, |
| 105 | {-25, "ECDH-ES + HKDF-256", "ECDH ES w/ HKDF - generate key directly"}, |
| 106 | {-13, "direct+HKDF-AES-256", "Shared secret w/ AES-MAC 256-bit key"}, |
| 107 | {-12, "direct+HKDF-AES-128", "Shared secret w/ AES-MAC 128-bit key"}, |
| 108 | {-11, "direct+HKDF-SHA-512", "Shared secret w/ HKDF and SHA-512"}, |
| 109 | {-10, "direct+HKDF-SHA-256", "Shared secret w/ HKDF and SHA-256"}, |
| 110 | {-8, "EdDSA", "EdDSA"}, |
| 111 | {-7, "ES256", "ECDSA w/ SHA-256"}, |
| 112 | {-6, "direct", "Direct use of CEK"}, |
| 113 | {-5, "A256KW", "AES Key Wrap w/ 256-bit key"}, |
| 114 | {-4, "A192KW", "AES Key Wrap w/ 192-bit key"}, |
| 115 | {-3, "A128KW", "AES Key Wrap w/ 128-bit key"}, |
| 116 | {0, "Reserved", "Reserved"}, |
| 117 | {1, "A128GCM", "AES-GCM mode w/ 128-bit key, 128-bit tag"}, |
| 118 | {2, "A192GCM", "AES-GCM mode w/ 192-bit key, 128-bit tag"}, |
| 119 | {3, "A256GCM", "AES-GCM mode w/ 256-bit key, 128-bit tag"}, |
| 120 | {4, "HMAC 256/64", "HMAC w/ SHA-256 truncated to 64 bits"}, |
| 121 | {5, "HMAC 256/256", "HMAC w/ SHA-256"}, |
| 122 | {6, "HMAC 384/384", "HMAC w/ SHA-384"}, |
| 123 | {7, "HMAC 512/512", "HMAC w/ SHA-512"}, |
| 124 | {10, "AES-CCM-16-64-128", "AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce"}, |
| 125 | {11, "AES-CCM-16-64-256", "AES-CCM mode 256-bit key, 64-bit tag, 13-byte nonce"}, |
| 126 | {12, "AES-CCM-64-64-128", "AES-CCM mode 128-bit key, 64-bit tag, 7-byte nonce"}, |
| 127 | {13, "AES-CCM-64-64-256", "AES-CCM mode 256-bit key, 64-bit tag, 7-byte nonce"}, |
| 128 | {14, "AES-MAC 128/64", "AES-MAC 128-bit key, 64-bit tag"}, |
| 129 | {15, "AES-MAC 256/64", "AES-MAC 256-bit key, 64-bit tag"}, |
| 130 | {24, "ChaCha20/Poly1305", "ChaCha20/Poly1305 w/ 256-bit key, 128-bit tag"}, |
| 131 | {25, "AES-MAC 128/128", "AES-MAC 128-bit key, 128-bit tag"}, |
| 132 | {26, "AES-MAC 256/128", "AES-MAC 256-bit key, 128-bit tag"}, |
| 133 | {30, "AES-CCM-16-128-128", "AES-CCM mode 128-bit key, 128-bit tag, 13-byte nonce"}, |
| 134 | {31, "AES-CCM-16-128-256", "AES-CCM mode 256-bit key, 128-bit tag, 13-byte nonce"}, |
| 135 | {32, "AES-CCM-64-128-128", "AES-CCM mode 128-bit key, 128-bit tag, 7-byte nonce"}, |
| 136 | {33, "AES-CCM-64-128-256", "AES-CCM mode 256-bit key, 128-bit tag, 7-byte nonce"} |
| 137 | }; |
| 138 | |
| 139 | COSEValueNameDesc_t *GetCOSEAlgElm(int id) { |
| 140 | for (int i = 0; i < ARRAYLEN(COSEAlg); i++) |
| 141 | if (COSEAlg[i].Value == id) |
| 142 | return &COSEAlg[i]; |
| 143 | return NULL; |
| 144 | } |
| 145 | |
| 146 | const char *GetCOSEAlgName(int id) { |
| 147 | COSEValueNameDesc_t *elm = GetCOSEAlgElm(id); |
| 148 | if (elm) |
| 149 | return elm->Name; |
| 150 | return COSEEmptyStr; |
| 151 | } |
| 152 | |
| 153 | const char *GetCOSEAlgDescription(int id) { |
| 154 | COSEValueNameDesc_t *elm = GetCOSEAlgElm(id); |
| 155 | if (elm) |
| 156 | return elm->Description; |
| 157 | return COSEEmptyStr; |
| 158 | } |
| 159 | |
| 160 | int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public_key) { |
| 161 | CborParser parser; |
| 162 | CborValue map; |
| 163 | int64_t i64; |
| 164 | size_t len; |
| 165 | |
| 166 | if(verbose) |
| 167 | PrintAndLog("----------- CBOR decode ----------------"); |
| 168 | |
| 169 | // kty |
| 170 | int res = CborMapGetKeyById(&parser, &map, data, datalen, 1); |
| 171 | if(!res) { |
| 172 | cbor_value_get_int64(&map, &i64); |
| 173 | if(verbose) |
| 174 | PrintAndLog("kty [%lld] %s", (long long)i64, GetCOSEktyDescription(i64)); |
| 175 | if (i64 != 2) |
| 176 | PrintAndLog("ERROR: kty must be 2."); |
| 177 | } |
| 178 | |
| 179 | // algorithm |
| 180 | res = CborMapGetKeyById(&parser, &map, data, datalen, 3); |
| 181 | if(!res) { |
| 182 | cbor_value_get_int64(&map, &i64); |
| 183 | if(verbose) |
| 184 | PrintAndLog("algorithm [%lld] %s", (long long)i64, GetCOSEAlgDescription(i64)); |
| 185 | if (i64 != -7) |
| 186 | PrintAndLog("ERROR: algorithm must be -7."); |
| 187 | } |
| 188 | |
| 189 | // curve |
| 190 | res = CborMapGetKeyById(&parser, &map, data, datalen, -1); |
| 191 | if(!res) { |
| 192 | cbor_value_get_int64(&map, &i64); |
| 193 | if(verbose) |
| 194 | PrintAndLog("curve [%lld] %s", (long long)i64, GetCOSECurveDescription(i64)); |
| 195 | if (i64 != 1) |
| 196 | PrintAndLog("ERROR: curve must be 1."); |
| 197 | } |
| 198 | |
| 199 | // plain key |
| 200 | public_key[0] = 0x04; |
| 201 | |
| 202 | // x - coordinate |
| 203 | res = CborMapGetKeyById(&parser, &map, data, datalen, -2); |
| 204 | if(!res) { |
| 205 | res = CborGetBinStringValue(&map, &public_key[1], 32, &len); |
| 206 | cbor_check(res); |
| 207 | if(verbose) |
| 208 | PrintAndLog("x - coordinate [%d]: %s", len, sprint_hex(&public_key[1], 32)); |
| 209 | if (len != 32) |
| 210 | PrintAndLog("ERROR: x - coordinate length must be 32."); |
| 211 | } |
| 212 | |
| 213 | // y - coordinate |
| 214 | res = CborMapGetKeyById(&parser, &map, data, datalen, -3); |
| 215 | if(!res) { |
| 216 | res = CborGetBinStringValue(&map, &public_key[33], 32, &len); |
| 217 | cbor_check(res); |
| 218 | if(verbose) |
| 219 | PrintAndLog("y - coordinate [%d]: %s", len, sprint_hex(&public_key[33], 32)); |
| 220 | if (len != 32) |
| 221 | PrintAndLog("ERROR: y - coordinate length must be 32."); |
| 222 | } |
| 223 | |
| 224 | // d - private key |
| 225 | uint8_t private_key[128] = {0}; |
| 226 | res = CborMapGetKeyById(&parser, &map, data, datalen, -4); |
| 227 | if(!res) { |
| 228 | res = CborGetBinStringValue(&map, private_key, sizeof(private_key), &len); |
| 229 | cbor_check(res); |
| 230 | if(verbose) |
| 231 | PrintAndLog("d - private key [%d]: %s", len, sprint_hex(private_key, len)); |
| 232 | } |
| 233 | |
| 234 | if(verbose) |
| 235 | PrintAndLog("----------- CBOR decode ----------------"); |
| 236 | |
| 237 | return 0; |
| 238 | } |
| 239 | |
| 240 | |