--- /dev/null
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 Merlok
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Tools for work with COSE (CBOR Object Signing and Encryption) rfc8152
+// https://tools.ietf.org/html/rfc8152
+//-----------------------------------------------------------------------------
+//
+
+#include "cose.h"
+#include <cbor.h>
+#include "cbortools.h"
+#include "util.h"
+#include "ui.h"
+
+static const char COSEEmptyStr[] = "";
+
+typedef struct {
+ int Value;
+ char *Name;
+ char *Description;
+} COSEValueNameDesc_t;
+
+typedef struct {
+ int Value;
+ char *Type;
+ char *Name;
+ char *Description;
+} COSEValueTypeNameDesc_t;
+
+// kty - Key Type Values
+COSEValueNameDesc_t COSEKeyTypeValueDesc[] = {
+ {0, "Reserved", "Reserved"},
+ {1, "OKP", "Octet Key Pair"},
+ {2, "EC2", "Elliptic Curve Key w/ x- and y-coordinate pair"},
+ {4, "Symmetric", "Symmetric Key"},
+};
+
+COSEValueNameDesc_t *GetCOSEktyElm(int id) {
+ for (int i = 0; i < ARRAYLEN(COSEKeyTypeValueDesc); i++)
+ if (COSEKeyTypeValueDesc[i].Value == id)
+ return &COSEKeyTypeValueDesc[i];
+ return NULL;
+}
+
+const char *GetCOSEktyDescription(int id) {
+ COSEValueNameDesc_t *elm = GetCOSEktyElm(id);
+ if (elm)
+ return elm->Description;
+ return COSEEmptyStr;
+}
+
+// keys
+COSEValueTypeNameDesc_t COSECurvesDesc[] = {
+ {1, "EC2", "P-256", "NIST P-256 also known as secp256r1"},
+ {2, "EC2", "P-384", "NIST P-384 also known as secp384r1"},
+ {3, "EC2", "P-521", "NIST P-521 also known as secp521r1"},
+ {4, "OKP", "X25519", "X25519 for use w/ ECDH only"},
+ {5, "OKP", "X448", "X448 for use w/ ECDH only"},
+ {6, "OKP", "Ed25519", "Ed25519 for use w/ EdDSA only"},
+ {7, "OKP", "Ed448", "Ed448 for use w/ EdDSA only"},
+};
+
+COSEValueTypeNameDesc_t *GetCOSECurveElm(int id) {
+ for (int i = 0; i < ARRAYLEN(COSECurvesDesc); i++)
+ if (COSECurvesDesc[i].Value == id)
+ return &COSECurvesDesc[i];
+ return NULL;
+}
+
+const char *GetCOSECurveDescription(int id) {
+ COSEValueTypeNameDesc_t *elm = GetCOSECurveElm(id);
+ if (elm)
+ return elm->Description;
+ return COSEEmptyStr;
+}
+
+// RFC8152 https://www.iana.org/assignments/cose/cose.xhtml#algorithms
+COSEValueNameDesc_t COSEAlg[] = {
+ {-65536, "Unassigned", "Unassigned"},
+ {-65535, "RS1", "RSASSA-PKCS1-v1_5 w/ SHA-1"},
+ {-259, "RS512", "RSASSA-PKCS1-v1_5 w/ SHA-512"},
+ {-258, "RS384", "RSASSA-PKCS1-v1_5 w/ SHA-384"},
+ {-257, "RS256", "RSASSA-PKCS1-v1_5 w/ SHA-256"},
+ {-42, "RSAES-OAEP w/ SHA-512", "RSAES-OAEP w/ SHA-512"},
+ {-41, "RSAES-OAEP w/ SHA-256", "RSAES-OAEP w/ SHA-256"},
+ {-40, "RSAES-OAEP w/ RFC 8017 def param", "RSAES-OAEP w/ SHA-1"},
+ {-39, "PS512", "RSASSA-PSS w/ SHA-512"},
+ {-38, "PS384", "RSASSA-PSS w/ SHA-384"},
+ {-37, "PS256", "RSASSA-PSS w/ SHA-256"},
+ {-36, "ES512", "ECDSA w/ SHA-512"},
+ {-35, "ES384", "ECDSA w/ SHA-384"},
+ {-34, "ECDH-SS + A256KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 256-bit key"},
+ {-33, "ECDH-SS + A192KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 192-bit key"},
+ {-32, "ECDH-SS + A128KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 128-bit key"},
+ {-31, "ECDH-ES + A256KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 256-bit key"},
+ {-30, "ECDH-ES + A192KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 192-bit key"},
+ {-29, "ECDH-ES + A128KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 128-bit key"},
+ {-28, "ECDH-SS + HKDF-512", "ECDH SS w/ HKDF - generate key directly"},
+ {-27, "ECDH-SS + HKDF-256", "ECDH SS w/ HKDF - generate key directly"},
+ {-26, "ECDH-ES + HKDF-512", "ECDH ES w/ HKDF - generate key directly"},
+ {-25, "ECDH-ES + HKDF-256", "ECDH ES w/ HKDF - generate key directly"},
+ {-13, "direct+HKDF-AES-256", "Shared secret w/ AES-MAC 256-bit key"},
+ {-12, "direct+HKDF-AES-128", "Shared secret w/ AES-MAC 128-bit key"},
+ {-11, "direct+HKDF-SHA-512", "Shared secret w/ HKDF and SHA-512"},
+ {-10, "direct+HKDF-SHA-256", "Shared secret w/ HKDF and SHA-256"},
+ {-8, "EdDSA", "EdDSA"},
+ {-7, "ES256", "ECDSA w/ SHA-256"},
+ {-6, "direct", "Direct use of CEK"},
+ {-5, "A256KW", "AES Key Wrap w/ 256-bit key"},
+ {-4, "A192KW", "AES Key Wrap w/ 192-bit key"},
+ {-3, "A128KW", "AES Key Wrap w/ 128-bit key"},
+ {0, "Reserved", "Reserved"},
+ {1, "A128GCM", "AES-GCM mode w/ 128-bit key, 128-bit tag"},
+ {2, "A192GCM", "AES-GCM mode w/ 192-bit key, 128-bit tag"},
+ {3, "A256GCM", "AES-GCM mode w/ 256-bit key, 128-bit tag"},
+ {4, "HMAC 256/64", "HMAC w/ SHA-256 truncated to 64 bits"},
+ {5, "HMAC 256/256", "HMAC w/ SHA-256"},
+ {6, "HMAC 384/384", "HMAC w/ SHA-384"},
+ {7, "HMAC 512/512", "HMAC w/ SHA-512"},
+ {10, "AES-CCM-16-64-128", "AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce"},
+ {11, "AES-CCM-16-64-256", "AES-CCM mode 256-bit key, 64-bit tag, 13-byte nonce"},
+ {12, "AES-CCM-64-64-128", "AES-CCM mode 128-bit key, 64-bit tag, 7-byte nonce"},
+ {13, "AES-CCM-64-64-256", "AES-CCM mode 256-bit key, 64-bit tag, 7-byte nonce"},
+ {14, "AES-MAC 128/64", "AES-MAC 128-bit key, 64-bit tag"},
+ {15, "AES-MAC 256/64", "AES-MAC 256-bit key, 64-bit tag"},
+ {24, "ChaCha20/Poly1305", "ChaCha20/Poly1305 w/ 256-bit key, 128-bit tag"},
+ {25, "AES-MAC 128/128", "AES-MAC 128-bit key, 128-bit tag"},
+ {26, "AES-MAC 256/128", "AES-MAC 256-bit key, 128-bit tag"},
+ {30, "AES-CCM-16-128-128", "AES-CCM mode 128-bit key, 128-bit tag, 13-byte nonce"},
+ {31, "AES-CCM-16-128-256", "AES-CCM mode 256-bit key, 128-bit tag, 13-byte nonce"},
+ {32, "AES-CCM-64-128-128", "AES-CCM mode 128-bit key, 128-bit tag, 7-byte nonce"},
+ {33, "AES-CCM-64-128-256", "AES-CCM mode 256-bit key, 128-bit tag, 7-byte nonce"}
+};
+
+COSEValueNameDesc_t *GetCOSEAlgElm(int id) {
+ for (int i = 0; i < ARRAYLEN(COSEAlg); i++)
+ if (COSEAlg[i].Value == id)
+ return &COSEAlg[i];
+ return NULL;
+}
+
+const char *GetCOSEAlgName(int id) {
+ COSEValueNameDesc_t *elm = GetCOSEAlgElm(id);
+ if (elm)
+ return elm->Name;
+ return COSEEmptyStr;
+}
+
+const char *GetCOSEAlgDescription(int id) {
+ COSEValueNameDesc_t *elm = GetCOSEAlgElm(id);
+ if (elm)
+ return elm->Description;
+ return COSEEmptyStr;
+}
+
+int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public_key) {
+ CborParser parser;
+ CborValue map;
+ int64_t i64;
+ size_t len;
+
+ if(verbose)
+ PrintAndLog("----------- CBOR decode ----------------");
+
+ // kty
+ int res = CborMapGetKeyById(&parser, &map, data, datalen, 1);
+ if(!res) {
+ cbor_value_get_int64(&map, &i64);
+ if(verbose)
+ PrintAndLog("kty [%lld] %s", (long long)i64, GetCOSEktyDescription(i64));
+ if (i64 != 2)
+ PrintAndLog("ERROR: kty must be 2.");
+ }
+
+ // algorithm
+ res = CborMapGetKeyById(&parser, &map, data, datalen, 3);
+ if(!res) {
+ cbor_value_get_int64(&map, &i64);
+ if(verbose)
+ PrintAndLog("algorithm [%lld] %s", (long long)i64, GetCOSEAlgDescription(i64));
+ if (i64 != -7)
+ PrintAndLog("ERROR: algorithm must be -7.");
+ }
+
+ // curve
+ res = CborMapGetKeyById(&parser, &map, data, datalen, -1);
+ if(!res) {
+ cbor_value_get_int64(&map, &i64);
+ if(verbose)
+ PrintAndLog("curve [%lld] %s", (long long)i64, GetCOSECurveDescription(i64));
+ if (i64 != 1)
+ PrintAndLog("ERROR: curve must be 1.");
+ }
+
+ // plain key
+ public_key[0] = 0x04;
+
+ // x - coordinate
+ res = CborMapGetKeyById(&parser, &map, data, datalen, -2);
+ if(!res) {
+ res = CborGetBinStringValue(&map, &public_key[1], 32, &len);
+ cbor_check(res);
+ if(verbose)
+ PrintAndLog("x - coordinate [%d]: %s", len, sprint_hex(&public_key[1], 32));
+ if (len != 32)
+ PrintAndLog("ERROR: x - coordinate length must be 32.");
+ }
+
+ // y - coordinate
+ res = CborMapGetKeyById(&parser, &map, data, datalen, -3);
+ if(!res) {
+ res = CborGetBinStringValue(&map, &public_key[33], 32, &len);
+ cbor_check(res);
+ if(verbose)
+ PrintAndLog("y - coordinate [%d]: %s", len, sprint_hex(&public_key[33], 32));
+ if (len != 32)
+ PrintAndLog("ERROR: y - coordinate length must be 32.");
+ }
+
+ // d - private key
+ uint8_t private_key[128] = {0};
+ res = CborMapGetKeyById(&parser, &map, data, datalen, -4);
+ if(!res) {
+ res = CborGetBinStringValue(&map, private_key, sizeof(private_key), &len);
+ cbor_check(res);
+ if(verbose)
+ PrintAndLog("d - private key [%d]: %s", len, sprint_hex(private_key, len));
+ }
+
+ if(verbose)
+ PrintAndLog("----------- CBOR decode ----------------");
+
+ return 0;
+}
+
+