COSE: Full independent implementation of RFC 8152 COSE_Sign1 messages

Change-Id: Id877db5f381704f50baa9c81d1cf279181e63ab0
Signed-off-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/lib/ext/t_cose/test/keys/README.txt b/lib/ext/t_cose/test/keys/README.txt
new file mode 100644
index 0000000..6c8bd31
--- /dev/null
+++ b/lib/ext/t_cose/test/keys/README.txt
@@ -0,0 +1,15 @@
+To list curves:
+
+   openssl ecparam -list_curves
+
+To generate an ECDSA key:
+
+   openssl ecparam -genkey -name secp384r1 -out k.pem
+
+To print out the ECDSA key:
+
+   openssl ec -in k.pem -noout -text
+
+
+https://kjur.github.io/jsrsasign/sample/sample-ecdsa.html
+https://superuser.com/questions/1103401/generate-an-ecdsa-key-and-csr-with-openssl
diff --git a/lib/ext/t_cose/test/keys/prime256v1.pem b/lib/ext/t_cose/test/keys/prime256v1.pem
new file mode 100644
index 0000000..5e72622
--- /dev/null
+++ b/lib/ext/t_cose/test/keys/prime256v1.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIPG3FCNDQC87XecxXqiU+dpc9QP/eTijfKFOsDKGmIRQoAoGCCqGSM49
+AwEHoUQDQgAEN6tllV+uBGZnPDopNKNPLw7Cs+7CJBmFV5mPwEv0srSV2XmPJTnJ
+DX0QKzu72n/L2w6bWNThrS5hUI2nX4Smew==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ext/t_cose/test/keys/secp384r1.pem b/lib/ext/t_cose/test/keys/secp384r1.pem
new file mode 100644
index 0000000..eccd310
--- /dev/null
+++ b/lib/ext/t_cose/test/keys/secp384r1.pem
@@ -0,0 +1,9 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDAD3xT0uKQ/2Kt1pgRr0rXqpv0QsrID/Yp415Ft4gqiQes37D1MaT0j
+uitPbltm9X+gBwYFK4EEACKhZANiAAS92cP4GMnO8+EeLUDndb6ze8N2aY1xln+T
+M3pOAy3/sRtQUGfd20IUtW2bzsWRd+zNirBfUJdZM7mnONkMCwfrlRlWfvkHWAfP
+dxOfwf6FYIhRNhE2gGEj7cc1zloD6OQ=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ext/t_cose/test/keys/secp521r1.pem b/lib/ext/t_cose/test/keys/secp521r1.pem
new file mode 100644
index 0000000..d3aa0c7
--- /dev/null
+++ b/lib/ext/t_cose/test/keys/secp521r1.pem
@@ -0,0 +1,10 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIARdLRQ5Q1+rMzscbItTTwlpOWrWTV9TXWX2jyoWBlkLsV/VMi/Jek
+FsOVdF5yx8hRmMCSGrO46S3ZAbWkIVmtrG2gBwYFK4EEACOhgYkDgYYABADk0lMX
+WhQxH8LdSHaHcMtJsHvRXTJ765iqM+YM0BgbF/uPHL8H28hlL/W3tEUsCC4GhsD6
+uAiQccvFNxAdNEuUwgHmQk86GNpPIOyr+8hLhGfCF81nBV+l3sf7GuhwgjAsGBPK
+pLexzyjZRnfkhvtLMXCX6TB6vbnVAYd3mj0eaCwSPA==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ext/t_cose/test/run_tests.c b/lib/ext/t_cose/test/run_tests.c
new file mode 100644
index 0000000..cda62a7
--- /dev/null
+++ b/lib/ext/t_cose/test/run_tests.c
@@ -0,0 +1,294 @@
+/*==============================================================================
+ run_tests.c -- test aggregator and results reporting
+
+ Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created on 9/30/18
+ =============================================================================*/
+
+#include "run_tests.h"
+#include "UsefulBuf.h"
+#include <stdbool.h>
+
+#include "t_cose_test.h"
+#include "t_cose_sign_verify_test.h"
+
+
+/*
+ Test configuration
+ */
+
+typedef int (test_fun_t)(void);
+typedef const char * (test_fun2_t)(void);
+
+
+#define TEST_ENTRY(test_name)  {#test_name, test_name, true}
+#define TEST_ENTRY_DISABLED(test_name)  {#test_name, test_name, false}
+
+typedef struct {
+    const char  *szTestName;
+    test_fun_t  *test_fun;
+    bool         bEnabled;
+} test_entry;
+
+#ifdef STRING_RETURNING_TESTS
+typedef struct {
+    const char *szTestName;
+    test_fun2_t  *test_fun;
+    bool         bEnabled;
+} test_entry2;
+
+
+static test_entry2 s_tests2[] = {
+};
+#endif
+
+static test_entry s_tests[] = {
+#ifndef T_COSE_DISABLE_SIGN_VERIFY_TESTS
+    /* Many tests can be run without a crypto library integration and provide
+     * good test coverage of everything but the signing and verification. These
+     * tests can't be run with signing and verification short circuited */
+    TEST_ENTRY(sign_verify_basic_test),
+    TEST_ENTRY(sign_verify_make_cwt_test),
+    TEST_ENTRY(sign_verify_sig_fail_test),
+    TEST_ENTRY(sign_verify_get_size_test),
+#endif
+    TEST_ENTRY(sign1_structure_decode_test),
+    TEST_ENTRY(content_type_test),
+    TEST_ENTRY(all_header_parameters_test),
+    TEST_ENTRY(cose_example_test),
+    TEST_ENTRY(crit_parameters_test),
+    TEST_ENTRY(bad_parameters_test),
+    TEST_ENTRY(short_circuit_decode_only_test),
+    TEST_ENTRY(short_circuit_make_cwt_test),
+    TEST_ENTRY(short_circuit_signing_error_conditions_test),
+    TEST_ENTRY(short_circuit_verify_fail_test),
+    TEST_ENTRY(short_circuit_self_test),
+
+#ifdef T_COSE_ENABLE_HASH_FAIL_TEST
+    TEST_ENTRY(short_circuit_hash_fail_test),
+#endif /* T_COSE_DISABLE_HASH_FAIL_TEST */
+};
+
+
+
+/**
+  \brief Convert number to ASCII string, similar to sprint
+
+  \param [in]  nNum       The 32-bit integer to convert.
+  \param [in]  StringMem  The buffer to output to.
+
+  \return POinter to NULL-terminated string with result or "XXX" on failure.
+
+ Convert a number up to 999999999 to a string. This is so sprintf doesn't
+ have to be linked in so as to minimized dependencies even in test code.
+
+ StringMem should be 12 bytes long, 9 for digits, 1 for minus and
+ 1 for \0 termination.
+ */
+static const char *NumToString(int32_t nNum, UsefulBuf StringMem)
+{
+   const int32_t nMax = 1000000000;
+
+   UsefulOutBuf OutBuf;
+   UsefulOutBuf_Init(&OutBuf, StringMem);
+
+   if(nNum < 0) {
+      UsefulOutBuf_AppendByte(&OutBuf, '-');
+      nNum = -nNum;
+   }
+   if(nNum > nMax-1) {
+      return "XXX";
+   }
+
+   bool bDidSomeOutput = false;
+   for(int n = nMax; n > 0; n/=10) {
+      int x = nNum/n;
+      if(x || bDidSomeOutput){
+         bDidSomeOutput = true;
+         UsefulOutBuf_AppendByte(&OutBuf, '0' + x);
+         nNum -= x * n;
+      }
+   }
+   if(!bDidSomeOutput){
+      UsefulOutBuf_AppendByte(&OutBuf, '0');
+   }
+   UsefulOutBuf_AppendByte(&OutBuf, '\0');
+
+   return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr;
+}
+
+
+/*
+ Public function. See run_test.h.
+ */
+int RunTests(const char    *szTestNames[],
+             OutputStringCB pfOutput,
+             void          *poutCtx,
+             int           *pNumTestsRun)
+{
+    int nTestsFailed = 0;
+    int nTestsRun = 0;
+    UsefulBuf_MAKE_STACK_UB(StringStorage, 12);
+
+#ifdef STRING_RETURNING_TESTS
+
+    test_entry2 *t2;
+    const test_entry2 *s_tests2_end = s_tests2 + sizeof(s_tests2)/sizeof(test_entry2);
+
+    for(t2 = s_tests2; t2 < s_tests2_end; t2++) {
+        if(szTestNames[0]) {
+            // Some tests have been named
+            const char **szRequestedNames;
+            for(szRequestedNames = szTestNames; *szRequestedNames;  szRequestedNames++) {
+                if(!strcmp(t2->szTestName, *szRequestedNames)) {
+                    break; // Name matched
+                }
+            }
+            if(*szRequestedNames == NULL) {
+                // Didn't match this test
+                continue;
+            }
+        } else {
+            // no tests named, but don't run "disabled" tests
+            if(!t2->bEnabled) {
+                // Don't run disabled tests when all tests are being run
+                // as indicated by no specific test names being given
+                continue;
+            }
+        }
+        const char * szTestResult = (t2->test_fun)();
+        nTestsRun++;
+        if(pfOutput) {
+            (*pfOutput)(t2->szTestName, poutCtx, 0);
+        }
+
+        if(szTestResult) {
+            if(pfOutput) {
+                (*pfOutput)(" FAILED (returned ", poutCtx, 0);
+                (*pfOutput)(szTestResult, poutCtx, 0);
+                (*pfOutput)(")", poutCtx, 1);
+            }
+            nTestsFailed++;
+        } else {
+            if(pfOutput) {
+                (*pfOutput)( " PASSED", poutCtx, 1);
+            }
+        }
+    }
+#endif
+
+
+    test_entry *t;
+    const test_entry *s_tests_end = s_tests + sizeof(s_tests)/sizeof(test_entry);
+
+    for(t = s_tests; t < s_tests_end; t++) {
+        if(szTestNames[0]) {
+            // Some tests have been named
+            const char **szRequestedNames;
+            for(szRequestedNames = szTestNames; *szRequestedNames;  szRequestedNames++) {
+                if(!strcmp(t->szTestName, *szRequestedNames)) {
+                    break; // Name matched
+                }
+            }
+            if(*szRequestedNames == NULL) {
+                // Didn't match this test
+                continue;
+            }
+        } else {
+            // no tests named, but don't run "disabled" tests
+            if(!t->bEnabled) {
+                // Don't run disabled tests when all tests are being run
+                // as indicated by no specific test names being given
+                continue;
+            }
+        }
+
+        int nTestResult = (t->test_fun)();
+        nTestsRun++;
+        if(pfOutput) {
+            (*pfOutput)(t->szTestName, poutCtx, 0);
+        }
+
+        if(nTestResult) {
+            if(pfOutput) {
+                (*pfOutput)(" FAILED (returned ", poutCtx, 0);
+                (*pfOutput)(NumToString(nTestResult, StringStorage), poutCtx, 0);
+                (*pfOutput)(")", poutCtx, 1);
+            }
+            nTestsFailed++;
+        } else {
+            if(pfOutput) {
+                (*pfOutput)( " PASSED", poutCtx, 1);
+            }
+        }
+    }
+
+    if(pNumTestsRun) {
+        *pNumTestsRun = nTestsRun;
+    }
+
+    if(pfOutput) {
+        (*pfOutput)( "SUMMARY: ", poutCtx, 0);
+        (*pfOutput)( NumToString(nTestsRun, StringStorage), poutCtx, 0);
+        (*pfOutput)( " tests run; ", poutCtx, 0);
+        (*pfOutput)( NumToString(nTestsFailed, StringStorage), poutCtx, 0);
+        (*pfOutput)( " tests failed", poutCtx, 1);
+    }
+
+    return nTestsFailed;
+}
+
+
+/*
+ Public function. See run_test.h.
+ */
+static void PrintSize(const char *szWhat,
+                      uint32_t uSize,
+                      OutputStringCB pfOutput,
+                      void *pOutCtx)
+{
+   UsefulBuf_MAKE_STACK_UB(buffer, 20);
+
+   (*pfOutput)(szWhat, pOutCtx, 0);
+   (*pfOutput)(" ", pOutCtx, 0);
+   (*pfOutput)(NumToString(uSize, buffer), pOutCtx, 0);
+   (*pfOutput)("", pOutCtx, 1);
+}
+
+
+
+
+#include "t_cose_sign1_sign.h" /* For struct size printing */
+#include "t_cose_sign1_verify.h" /* For struct size printing */
+#include "t_cose_crypto.h" /* For struct size printing */
+
+
+/*
+ Public function. See run_test.h.
+ */
+void PrintSizes(OutputStringCB pfOutput, void *pOutCtx)
+{
+   // Type and size of return from sizeof() varies. These will never be large
+   // so cast is safe.
+    PrintSize("sizeof(struct t_cose_sign1_ctx)",
+              (uint32_t)sizeof(struct t_cose_sign1_sign_ctx),
+              pfOutput, pOutCtx);
+    PrintSize("sizeof(struct t_cose_signing_key)",
+              (uint32_t)sizeof(struct t_cose_key),
+              pfOutput, pOutCtx);
+    PrintSize("sizeof(struct t_cose_crypto_hash)",
+              (uint32_t)sizeof(struct t_cose_crypto_hash),
+              pfOutput, pOutCtx);
+    PrintSize("sizeof(struct t_cose_parameters)",
+              (uint32_t)sizeof(struct t_cose_parameters),
+              pfOutput, pOutCtx);
+    PrintSize("sizeof(struct t_cose_sign1_verify_ctx)",
+              (uint32_t)sizeof(struct t_cose_sign1_verify_ctx),
+              pfOutput, pOutCtx);
+    (*pfOutput)("", pOutCtx, 1);
+}
diff --git a/lib/ext/t_cose/test/run_tests.h b/lib/ext/t_cose/test/run_tests.h
new file mode 100644
index 0000000..ba1b682
--- /dev/null
+++ b/lib/ext/t_cose/test/run_tests.h
@@ -0,0 +1,69 @@
+/*==============================================================================
+ run_tests.h -- test aggregator and results reporting
+
+ Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ See BSD-3-Clause license in README.md
+
+ Created 9/30/18
+ =============================================================================*/
+
+/**
+ @file run_tests.h
+*/
+
+/**
+ @brief Type for function to output a text string
+
+ @param[in] szString   The string to output
+ @param[in] pOutCtx    A context pointer; NULL if not needed
+ @param[in] bNewline   If non-zero, output a newline after the string
+
+ This is a prototype of a function to be passed to RunTests() to
+ output text strings.
+
+ This can be implemented with stdio (if available) using a straight
+ call to fputs() where the FILE * is passed as the pOutCtx as shown in
+ the example code below.  This code is for Linux where the newline is
+ a \\n. Windows usually prefers \\r\\n.
+
+ @code
+    static void fputs_wrapper(const char *szString, void *pOutCtx, int bNewLine)
+    {
+        fputs(szString, (FILE *)pOutCtx);
+        if(bNewLine) {
+            fputs("\n", pOutCtx);
+        }
+     }
+ @endcode
+*/
+typedef void (*OutputStringCB)(const char *szString, void *pOutCtx, int bNewline);
+
+
+/**
+ @brief Runs the QCBOR tests.
+
+ @param[in]  szTestNames    An argv-style list of test names to run. If
+                            empty, all are run.
+ @param[in]  pfOutput       Function that is called to output text strings.
+ @param[in]  pOutCtx        Context pointer passed to output function.
+ @param[out] pNumTestsRun   Returns the number of tests run. May be NULL.
+
+ @return The number of tests that failed. Zero means overall success.
+ */
+int RunTests(const char    *szTestNames[],
+             OutputStringCB pfOutput,
+             void          *pOutCtx,
+             int           *pNumTestsRun);
+
+
+/**
+ @brief Print sizes of encoder / decoder contexts.
+
+ @param[in] pfOutput     Function that is called to output text strings.
+ @param[in] pOutCtx      Context pointer passed to output function.
+ */
+void PrintSizes(OutputStringCB pfOutput, void *pOutCtx);
+
diff --git a/lib/ext/t_cose/test/t_cose_make_openssl_test_key.c b/lib/ext/t_cose/test/t_cose_make_openssl_test_key.c
new file mode 100644
index 0000000..8137a99
--- /dev/null
+++ b/lib/ext/t_cose/test/t_cose_make_openssl_test_key.c
@@ -0,0 +1,201 @@
+/*
+ *  t_cose_make_openssl_test_key.c
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "t_cose_make_test_pub_key.h" /* The interface implemented here */
+
+#include "openssl/ecdsa.h"
+#include "openssl/obj_mac.h" /* for NID for EC curve */
+#include "openssl/err.h"
+
+
+/*
+ * Some hard coded keys for the test cases here.
+ */
+#define PUBLIC_KEY_prime256v1 \
+    "0437ab65955fae0466673c3a2934a3" \
+    "4f2f0ec2b3eec224198557998fc04b" \
+    "f4b2b495d9798f2539c90d7d102b3b" \
+    "bbda7fcbdb0e9b58d4e1ad2e61508d" \
+    "a75f84a67b"
+
+#define PRIVATE_KEY_prime256v1 \
+    "f1b7142343402f3b5de7315ea894f9" \
+    "da5cf503ff7938a37ca14eb0328698" \
+    "8450"
+
+
+#define PUBLIC_KEY_secp384r1 \
+    "04bdd9c3f818c9cef3e11e2d40e775" \
+    "beb37bc376698d71967f93337a4e03" \
+    "2dffb11b505067dddb4214b56d9bce" \
+    "c59177eccd8ab05f50975933b9a738" \
+    "d90c0b07eb9519567ef9075807cf77" \
+    "139fc1fe85608851361136806123ed" \
+    "c735ce5a03e8e4"
+
+#define PRIVATE_KEY_secp384r1 \
+    "03df14f4b8a43fd8ab75a6046bd2b5" \
+    "eaa6fd10b2b203fd8a78d7916de20a" \
+    "a241eb37ec3d4c693d23ba2b4f6e5b" \
+    "66f57f"
+
+
+#define PUBLIC_KEY_secp521r1 \
+    "0400e4d253175a14311fc2dd487687" \
+    "70cb49b07bd15d327beb98aa33e60c" \
+    "d0181b17fb8f1cbf07dbc8652ff5b7" \
+    "b4452c082e0686c0fab8089071cbc5" \
+    "37101d344b94c201e6424f3a18da4f" \
+    "20ecabfbc84b8467c217cd67055fa5" \
+    "dec7fb1ae87082302c1813caa4b7b1" \
+    "cf28d94677e486fb4b317097e9307a" \
+    "bdb9d50187779a3d1e682c123c"
+
+#define PRIVATE_KEY_secp521r1 \
+    "0045d2d1439435fab333b1c6c8b534" \
+    "f0969396ad64d5f535d65f68f2a160" \
+    "6590bb15fd5322fc97a416c395745e" \
+    "72c7c85198c0921ab3b8e92dd901b5" \
+    "a42159adac6d"
+
+/*
+ * Public function, see t_cose_make_test_pub_key.h
+ */
+/*
+ * The key object returned by this is malloced and has to be freed by
+ * by calling free_ecdsa_key_pair(). This heap use is a part of
+ * OpenSSL and not t_cose which does not use the heap
+ */
+enum t_cose_err_t make_ecdsa_key_pair(int32_t           cose_algorithm_id,
+                                      struct t_cose_key *key_pair)
+{
+    EC_GROUP          *ossl_ec_group = NULL;
+    enum t_cose_err_t  return_value;
+    BIGNUM            *ossl_private_key_bn = NULL;
+    EC_KEY            *ossl_ec_key = NULL;
+    int                ossl_result;
+    EC_POINT          *ossl_pub_key_point = NULL;
+    int                nid;
+    const char        *public_key;
+    const char        *private_key;
+
+    switch (cose_algorithm_id) {
+    case T_COSE_ALGORITHM_ES256:
+        nid         = NID_X9_62_prime256v1;
+        public_key  = PUBLIC_KEY_prime256v1;
+        private_key =  PRIVATE_KEY_prime256v1 ;
+        break;
+
+    case T_COSE_ALGORITHM_ES384:
+        nid         = NID_secp384r1;
+        public_key  = PUBLIC_KEY_secp384r1;
+        private_key = PRIVATE_KEY_secp384r1;
+        break;
+
+    case T_COSE_ALGORITHM_ES512:
+        nid         = NID_secp521r1;
+        public_key  = PUBLIC_KEY_secp521r1;
+        private_key = PRIVATE_KEY_secp521r1;
+        break;
+
+    default:
+        return -1;
+    }
+
+    /* Make a group for the particular EC algorithm */
+    ossl_ec_group = EC_GROUP_new_by_curve_name(nid);
+    if(ossl_ec_group == NULL) {
+        return_value = T_COSE_ERR_INSUFFICIENT_MEMORY;
+        goto Done;
+    }
+
+    /* Make an empty EC key object */
+    ossl_ec_key = EC_KEY_new();
+    if(ossl_ec_key == NULL) {
+        return_value = T_COSE_ERR_INSUFFICIENT_MEMORY;
+        goto Done;
+    }
+
+    /* Associate group with key object */
+    ossl_result = EC_KEY_set_group(ossl_ec_key, ossl_ec_group);
+    if (!ossl_result) {
+        return_value = T_COSE_ERR_SIG_FAIL;
+        goto Done;
+    }
+
+    /* Make an instance of a big number to store the private key */
+    ossl_private_key_bn = BN_new();
+    if(ossl_private_key_bn == NULL) {
+        return_value = T_COSE_ERR_INSUFFICIENT_MEMORY;
+        goto Done;
+    }
+    BN_zero(ossl_private_key_bn);
+
+    /* Stuff the specific private key into the big num */
+    ossl_result = BN_hex2bn(&ossl_private_key_bn, private_key);
+    if(ossl_private_key_bn == 0) {
+        return_value = T_COSE_ERR_SIG_FAIL;
+        goto Done;
+    }
+
+    /* Now associate the big num with the key object so we finally
+     * have a key set up and ready for signing */
+    ossl_result = EC_KEY_set_private_key(ossl_ec_key, ossl_private_key_bn);
+    if (!ossl_result) {
+        return_value = T_COSE_ERR_SIG_FAIL;
+        goto Done;
+    }
+
+
+    /* Make an empty EC point into which the public key gets loaded */
+    ossl_pub_key_point = EC_POINT_new(ossl_ec_group);
+    if(ossl_pub_key_point == NULL) {
+        return_value = T_COSE_ERR_INSUFFICIENT_MEMORY;
+        goto Done;
+    }
+
+    /* Turn the serialized public key into an EC point */
+    ossl_pub_key_point = EC_POINT_hex2point(ossl_ec_group,
+                                            public_key,
+                                            ossl_pub_key_point,
+                                            NULL);
+    if(ossl_pub_key_point == NULL) {
+        return_value = T_COSE_ERR_SIG_FAIL;
+        goto Done;
+    }
+
+    /* Associate the EC point with key object */
+    /* The key object has both the public and private keys in it */
+    ossl_result = EC_KEY_set_public_key(ossl_ec_key, ossl_pub_key_point);
+    if(ossl_result == 0) {
+        return_value = T_COSE_ERR_SIG_FAIL;
+        goto Done;
+    }
+
+    key_pair->k.key_ptr  = ossl_ec_key;
+    key_pair->crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL;
+    return_value         = T_COSE_SUCCESS;
+
+Done:
+    return return_value;
+}
+
+
+/*
+ * Public function, see t_cose_make_test_pub_key.h
+ */
+void free_ecdsa_key_pair(struct t_cose_key key_pair)
+{
+    EC_KEY_free(key_pair.k.key_ptr);
+}
+
+
+
+
diff --git a/lib/ext/t_cose/test/t_cose_make_psa_test_key.c b/lib/ext/t_cose/test/t_cose_make_psa_test_key.c
new file mode 100644
index 0000000..5133029
--- /dev/null
+++ b/lib/ext/t_cose/test/t_cose_make_psa_test_key.c
@@ -0,0 +1,135 @@
+/*
+ *  t_cose_make_psa_test_key.c
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+
+#include "t_cose_make_test_pub_key.h" /* The interface implemented here */
+
+#include "t_cose_standard_constants.h"
+
+#include "psa/crypto_types.h"
+#include "psa/crypto.h"
+
+
+/*
+ * Some hard coded keys for the test cases here.
+ */
+#define PRIVATE_KEY_prime256v1 \
+0xf1, 0xb7, 0x14, 0x23, 0x43, 0x40, 0x2f, 0x3b, 0x5d, 0xe7, 0x31, 0x5e, 0xa8, \
+0x94, 0xf9, 0xda, 0x5c, 0xf5, 0x03, 0xff, 0x79, 0x38, 0xa3, 0x7c, 0xa1, 0x4e, \
+0xb0, 0x32, 0x86, 0x98, 0x84, 0x50
+
+#define PRIVATE_KEY_secp384r1 \
+0x03, 0xdf, 0x14, 0xf4, 0xb8, 0xa4, 0x3f, 0xd8, 0xab, 0x75, 0xa6, 0x04, 0x6b, \
+0xd2, 0xb5, 0xea, 0xa6, 0xfd, 0x10, 0xb2, 0xb2, 0x03, 0xfd, 0x8a, 0x78, 0xd7, \
+0x91, 0x6d, 0xe2, 0x0a, 0xa2, 0x41, 0xeb, 0x37, 0xec, 0x3d, 0x4c, 0x69, 0x3d, \
+0x23, 0xba, 0x2b, 0x4f, 0x6e, 0x5b, 0x66, 0xf5, 0x7f
+
+#define PRIVATE_KEY_secp521r1 \
+0x00, 0x45, 0xd2, 0xd1, 0x43, 0x94, 0x35, 0xfa, 0xb3, 0x33, 0xb1, 0xc6, 0xc8, \
+0xb5, 0x34, 0xf0, 0x96, 0x93, 0x96, 0xad, 0x64, 0xd5, 0xf5, 0x35, 0xd6, 0x5f, \
+0x68, 0xf2, 0xa1, 0x60, 0x65, 0x90, 0xbb, 0x15, 0xfd, 0x53, 0x22, 0xfc, 0x97, \
+0xa4, 0x16, 0xc3, 0x95, 0x74, 0x5e, 0x72, 0xc7, 0xc8, 0x51, 0x98, 0xc0, 0x92, \
+0x1a, 0xb3, 0xb8, 0xe9, 0x2d, 0xd9, 0x01, 0xb5, 0xa4, 0x21, 0x59, 0xad, 0xac, \
+0x6d
+
+
+/*
+ * Public function, see t_cose_make_test_pub_key.h
+ */
+enum t_cose_err_t make_ecdsa_key_pair(int32_t            cose_algorithm_id,
+                                      struct t_cose_key *key_pair)
+{
+    psa_key_type_t      key_type;
+    psa_status_t        crypto_res;
+    psa_key_handle_t    key_handle;
+    psa_key_policy_t    policy;
+    psa_key_usage_t     key_usage;
+    const uint8_t      *private_key;
+    size_t              private_key_len;
+
+    static const uint8_t private_key_256[] = {PRIVATE_KEY_prime256v1};
+    static const uint8_t private_key_384[] = {PRIVATE_KEY_secp384r1};
+    static const uint8_t private_key_521[] = {PRIVATE_KEY_secp521r1};
+
+    /* There is not a 1:1 mapping from alg to key type, but
+     * there is usually an obvious curve for an algorithm. That
+     * is what this does.
+     */
+    switch(cose_algorithm_id) {
+    case COSE_ALGORITHM_ES256:
+        private_key     = private_key_256;
+        private_key_len = sizeof(private_key_256);
+        key_type        = PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1);
+        key_usage       = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
+        break;
+
+    case COSE_ALGORITHM_ES384:
+        private_key     = private_key_384;
+        private_key_len = sizeof(private_key_384);
+        key_type        = PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP384R1);
+        key_usage       = PSA_ALG_ECDSA(PSA_ALG_SHA_384);
+        break;
+
+    case COSE_ALGORITHM_ES512:
+        private_key     = private_key_521;
+        private_key_len = sizeof(private_key_521);
+        key_type        = PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP521R1);
+        key_usage       = PSA_ALG_ECDSA(PSA_ALG_SHA_512);
+        break;
+
+    default:
+        return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
+    }
+
+    /* Allocate for the key pair in the Crypto service */
+    crypto_res = psa_allocate_key(&key_handle);
+    if (crypto_res != PSA_SUCCESS) {
+        return T_COSE_ERR_FAIL;
+    }
+
+    /* Setup the key policy for private key */
+    policy = psa_key_policy_init();
+    psa_key_policy_set_usage(&policy,
+                             PSA_KEY_USAGE_SIGN,
+                             key_usage);
+    crypto_res = psa_set_key_policy(key_handle, &policy);
+    if (crypto_res != PSA_SUCCESS) {
+        return T_COSE_ERR_FAIL;
+    }
+
+    /* Import the private key. psa_import_key() automatically generates
+     * the public key from the private so no need to import more than
+     * the private key. (With ECDSA the public key is always
+     * deterministically derivable from the private key).
+     */
+    crypto_res = psa_import_key(key_handle,
+                                key_type,
+                                private_key,
+                                sizeof(private_key));
+
+    if (crypto_res != PSA_SUCCESS) {
+        return T_COSE_ERR_FAIL;
+    }
+
+    key_pair->k.key_handle = key_handle;
+    key_pair->crypto_lib   = T_COSE_CRYPTO_LIB_PSA;
+
+    return T_COSE_SUCCESS;
+}
+
+
+/*
+ * Public function, see t_cose_make_test_pub_key.h
+ */
+void free_ecdsa_key_pair(struct t_cose_key key_pair)
+{
+   psa_destroy_key(key_pair.k.key_handle);
+}
+
diff --git a/lib/ext/t_cose/test/t_cose_make_test_messages.c b/lib/ext/t_cose/test/t_cose_make_test_messages.c
new file mode 100644
index 0000000..9d61ade
--- /dev/null
+++ b/lib/ext/t_cose/test/t_cose_make_test_messages.c
@@ -0,0 +1,608 @@
+/*
+ * t_cose_make_test_messages.c
+ *
+ * Copyright (c) 2019-2020, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "t_cose_make_test_messages.h"
+#include "qcbor.h"
+#include "t_cose_crypto.h"
+#include "t_cose_util.h"
+
+
+/**
+ * \file t_cose_make_test_messages.c
+ *
+ * This makes \c COSE_Sign1 messages of various sorts for testing
+ * verification. Some of them are badly formed to test various
+ * verification failures.
+ *
+ * This is essentially a hacked-up version of t_cose_sign1_sign.c.
+ */
+
+
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+/**
+ * \brief Create a short-circuit signature
+ *
+ * \param[in] cose_algorithm_id Algorithm ID. This is used only to make
+ *                              the short-circuit signature the same size
+ *                              as the real signature would be for the
+ *                              particular algorithm.
+ * \param[in] hash_to_sign      The bytes to sign. Typically, a hash of
+ *                              a payload.
+ * \param[in] signature_buffer  Pointer and length of buffer into which
+ *                              the resulting signature is put.
+ * \param[in] signature         Pointer and length of the signature
+ *                              returned.
+ *
+ * \return This returns one of the error codes defined by \ref t_cose_err_t.
+ *
+ * This creates the short-circuit signature that is a concatenation of
+ * hashes up to the expected size of the signature. This is a test
+ * mode only has it has no security value. This is retained in
+ * commercial production code as a useful test or demo that can run
+ * even if key material is not set up or accessible.
+ */
+static inline enum t_cose_err_t
+short_circuit_sign(int32_t               cose_algorithm_id,
+                   struct q_useful_buf_c hash_to_sign,
+                   struct q_useful_buf   signature_buffer,
+                   struct q_useful_buf_c *signature)
+{
+    /* approximate stack use on 32-bit machine: local use: 16 bytes
+     */
+    enum t_cose_err_t return_value;
+    size_t            array_index;
+    size_t            amount_to_copy;
+    size_t            sig_size;
+
+    sig_size = cose_algorithm_id == COSE_ALGORITHM_ES256 ? T_COSE_EC_P256_SIG_SIZE :
+               cose_algorithm_id == COSE_ALGORITHM_ES384 ? T_COSE_EC_P384_SIG_SIZE :
+               cose_algorithm_id == COSE_ALGORITHM_ES512 ? T_COSE_EC_P512_SIG_SIZE :
+                                                           0;
+
+    /* Check the signature length against buffer size*/
+    if(sig_size == 0) {
+        return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
+        goto Done;
+    }
+
+    if(sig_size > signature_buffer.len) {
+        /* Buffer too small for this signature type */
+        return_value = T_COSE_ERR_SIG_BUFFER_SIZE;
+        goto Done;
+    }
+
+    /* Loop concatening copies of the hash to fill out to signature size */
+    for(array_index = 0; array_index < sig_size; array_index += hash_to_sign.len) {
+        amount_to_copy = sig_size - array_index;
+        if(amount_to_copy > hash_to_sign.len) {
+            amount_to_copy = hash_to_sign.len;
+        }
+        memcpy((uint8_t *)signature_buffer.ptr + array_index,
+               hash_to_sign.ptr,
+               amount_to_copy);
+    }
+    signature->ptr = signature_buffer.ptr;
+    signature->len = sig_size;
+    return_value   = T_COSE_SUCCESS;
+
+Done:
+    return return_value;
+}
+#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */
+
+
+/**
+ * \brief  Makes various protected parameters for various tests
+ *
+ * \param[in] test_message_options  Flags to select test modes.
+ * \param[in] cose_algorithm_id  The COSE algorithm ID to put in the parameters.
+ * \param[in] buffer_for_protected_parameters  Pointer and length into which
+ *                               the resulting encoded protected
+ *                               parameters is put.
+ *
+ * \return The pointer and length of the protected parameters is
+ * returned, or \c NULL_Q_USEFUL_BUF_C if this fails.
+ *
+ * The protected parameters are returned in fully encoded CBOR format as
+ * they are added to the \c COSE_Sign1 as a binary string. This is
+ * different from the unprotected parameters which are not handled this
+ * way.
+ *
+ * This returns \c NULL_Q_USEFUL_BUF_C if buffer_for_protected_parameters was
+ * too small. See also definition of
+ * \c T_COSE_SIGN1_MAX_SIZE_PROTECTED_PARAMETERS.
+ */
+static inline struct q_useful_buf_c
+encode_protected_parameters(int32_t             test_message_options,
+                            int32_t             cose_algorithm_id,
+                            struct q_useful_buf buffer_for_protected_parameters)
+{
+    /* approximate stack use on 32-bit machine:
+     * local use: 170
+     * with calls: 210
+     */
+    struct q_useful_buf_c protected_parameters;
+    QCBORError            qcbor_result;
+    QCBOREncodeContext    cbor_encode_ctx;
+    struct q_useful_buf_c return_value;
+
+    if(test_message_options & T_COSE_TEST_EMPTY_PROTECTED_PARAMETERS) {
+        /* An empty q_useful_buf_c */
+        return (struct q_useful_buf_c){buffer_for_protected_parameters.ptr, 0};
+    }
+
+
+    if(test_message_options & T_COSE_TEST_UNCLOSED_PROTECTED) {
+        *(uint8_t *)(buffer_for_protected_parameters.ptr) = 0xa1;
+        return (struct q_useful_buf_c){buffer_for_protected_parameters.ptr, 1};
+    }
+
+    QCBOREncode_Init(&cbor_encode_ctx, buffer_for_protected_parameters);
+
+    if(test_message_options & T_COSE_TEST_BAD_PROTECTED) {
+        QCBOREncode_OpenArray(&cbor_encode_ctx);
+        QCBOREncode_AddInt64(&cbor_encode_ctx, 42);
+        QCBOREncode_CloseArray(&cbor_encode_ctx);
+        goto Finish;
+    }
+
+    QCBOREncode_OpenMap(&cbor_encode_ctx);
+    QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
+                               COSE_HEADER_PARAM_ALG,
+                               cose_algorithm_id);
+
+    if(test_message_options & T_COSE_TEST_UNKNOWN_CRIT_UINT_PARAMETER) {
+        /* This is the parameter that will be unknown */
+        QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, 42, 43);
+        /* This is the critical labels parameter */
+        QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT);
+        QCBOREncode_AddInt64(&cbor_encode_ctx, 42);
+        QCBOREncode_AddInt64(&cbor_encode_ctx, 43);
+        QCBOREncode_AddInt64(&cbor_encode_ctx, 44);
+        QCBOREncode_CloseArray(&cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_UNKNOWN_CRIT_TSTR_PARAMETER) {
+        /* This is the parameter that will be unknown */
+        QCBOREncode_AddInt64ToMap(&cbor_encode_ctx, "hh", 43);
+        /* This is the critical labels parameter */
+        QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT);
+        QCBOREncode_AddSZString(&cbor_encode_ctx, "hh");
+        QCBOREncode_AddSZString(&cbor_encode_ctx, "h");
+        QCBOREncode_AddSZString(&cbor_encode_ctx, "hhh");
+        QCBOREncode_CloseArray(&cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_BAD_CRIT_LABEL) {
+        /* This is the critical labels parameter */
+        QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT);
+        QCBOREncode_AddBool(&cbor_encode_ctx, true);
+        QCBOREncode_CloseArray(&cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_CRIT_PARAMETER_EXIST) {
+        /* This is the critical labels parameter */
+        QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT);
+        int i;
+        /* Add the maxium */
+        for(i = 0; i < T_COSE_PARAMETER_LIST_MAX; i++) {
+            QCBOREncode_AddInt64(&cbor_encode_ctx, i + 10);
+        }
+        QCBOREncode_CloseArray(&cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_TOO_MANY_CRIT_PARAMETER_EXIST) {
+        /* This is the critical labels parameter */
+        QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT);
+        int i;
+        /* One more than the maximum */
+        for(i = 0; i < T_COSE_PARAMETER_LIST_MAX+1; i++) {
+            QCBOREncode_AddInt64(&cbor_encode_ctx, i + 10);
+        }
+        QCBOREncode_CloseArray(&cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_TOO_MANY_TSTR_CRIT_LABLELS) {
+        /* This is the critical labels parameter */
+        QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT);
+        int i;
+        /* One more than the maximum */
+        for(i = 0; i < T_COSE_PARAMETER_LIST_MAX+1; i++) {
+            QCBOREncode_AddSZString(&cbor_encode_ctx, "");
+        }
+        QCBOREncode_CloseArray(&cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_EMPTY_CRIT_PARAMETER) {
+        QCBOREncode_OpenArrayInMapN(&cbor_encode_ctx, COSE_HEADER_PARAM_CRIT);
+        QCBOREncode_CloseArray(&cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_KID_IN_PROTECTED) {
+        QCBOREncode_AddBytesToMapN(&cbor_encode_ctx,
+                                   COSE_HEADER_PARAM_KID,
+                                   Q_USEFUL_BUF_FROM_SZ_LITERAL("kid"));
+    }
+
+    if(test_message_options & T_COSE_TEST_DUP_CONTENT_ID) {
+        QCBOREncode_AddUInt64ToMapN(&cbor_encode_ctx,
+                                    COSE_HEADER_PARAM_CONTENT_TYPE,
+                                    3);
+    }
+
+
+    QCBOREncode_CloseMap(&cbor_encode_ctx);
+
+Finish:
+    qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &protected_parameters);
+
+    if(qcbor_result == QCBOR_SUCCESS) {
+        return_value = protected_parameters;
+    } else {
+        return_value = NULL_Q_USEFUL_BUF_C;
+    }
+
+    return return_value;
+}
+
+
+/**
+ * \brief Add the unprotected parameters to a CBOR encoding context
+ *
+ * \param[in] test_message_options  Flags to select test modes.
+ * \param[in] cbor_encode_ctx       CBOR encoding context to output to.
+ * \param[in] kid                   The key ID to go into the kid parameter.
+ *
+ * No error is returned. If an error occurred it will be returned when
+ * \c QCBOR_Finish() is called on \c cbor_encode_ctx.
+ *
+ * The unprotected parameters added by this are the key ID plus
+ * lots of different test parameters.
+ */
+static inline void
+add_unprotected_parameters(int32_t              test_message_options,
+                           QCBOREncodeContext   *cbor_encode_ctx,
+                           struct q_useful_buf_c kid)
+{
+    if(test_message_options & T_COSE_TEST_UNPROTECTED_NOT_MAP) {
+        QCBOREncode_OpenArray(cbor_encode_ctx);
+        QCBOREncode_AddBytes(cbor_encode_ctx, kid);
+        QCBOREncode_CloseArray(cbor_encode_ctx);
+        return; /* skip the rest for this degenerate test */
+    }
+
+    QCBOREncode_OpenMap(cbor_encode_ctx);
+
+    if(test_message_options & T_COSE_TEST_NOT_WELL_FORMED_1) {
+        QCBOREncode_AddEncoded(cbor_encode_ctx, Q_USEFUL_BUF_FROM_SZ_LITERAL("xxxxxx"));
+    }
+
+    /* Put in a byte string (not a text string) for the parameter label */
+    if(test_message_options & T_COSE_TEST_PARAMETER_LABEL) {
+        QCBOREncode_AddBytes(cbor_encode_ctx, kid);
+        QCBOREncode_AddBytes(cbor_encode_ctx, kid);
+    }
+
+    if(test_message_options & T_COSE_TEST_BAD_CRIT_PARAMETER) {
+        QCBOREncode_AddSZStringToMapN(cbor_encode_ctx,
+                                      COSE_HEADER_PARAM_CRIT, "hi");
+    }
+
+    if(test_message_options & T_COSE_TEST_EXTRA_PARAMETER) {
+        QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, 55);
+        QCBOREncode_OpenMap(cbor_encode_ctx);
+        QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 66, "hi");
+        QCBOREncode_CloseMap(cbor_encode_ctx);
+        QCBOREncode_CloseArray(cbor_encode_ctx);
+    }
+
+
+    if(test_message_options & T_COSE_TEST_NOT_WELL_FORMED_2) {
+        QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, 55);
+        QCBOREncode_OpenMap(cbor_encode_ctx);
+        QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 66, "hi");
+        /* '=' is 0x3d a reserved initial byte and thus not-well-formed */
+        QCBOREncode_AddEncoded(cbor_encode_ctx,
+                               Q_USEFUL_BUF_FROM_SZ_LITERAL("="));
+        QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 67, "bye");
+
+        QCBOREncode_CloseMap(cbor_encode_ctx);
+        QCBOREncode_CloseArray(cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_CRIT_NOT_PROTECTED) {
+        /* This is the critical labels parameter */
+        QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, COSE_HEADER_PARAM_CRIT);
+        int i;
+        /* Add the maxium */
+        for(i = 0; i < T_COSE_PARAMETER_LIST_MAX; i++) {
+            QCBOREncode_AddInt64(cbor_encode_ctx, i + 100);
+            QCBOREncode_AddSZString(cbor_encode_ctx, "xxxx");
+        }
+        QCBOREncode_CloseArray(cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_TOO_MANY_UNKNOWN) {
+        int i;
+        for(i = 0; i < T_COSE_PARAMETER_LIST_MAX + 1; i++ ) {
+            QCBOREncode_AddBoolToMapN(cbor_encode_ctx, i+10, true);
+        }
+    }
+
+    if(!q_useful_buf_c_is_null_or_empty(kid)) {
+        QCBOREncode_AddBytesToMapN(cbor_encode_ctx, COSE_HEADER_PARAM_KID, kid);
+    }
+
+    if(test_message_options & T_COSE_TEST_ALL_PARAMETERS) {
+        QCBOREncode_AddBytesToMapN(cbor_encode_ctx,
+                                   COSE_HEADER_PARAM_IV,
+                                   Q_USEFUL_BUF_FROM_SZ_LITERAL("iv"));
+        QCBOREncode_AddBytesToMapN(cbor_encode_ctx,
+                                   COSE_HEADER_PARAM_PARTIAL_IV,
+                                   Q_USEFUL_BUF_FROM_SZ_LITERAL("partial_iv"));
+        QCBOREncode_AddInt64ToMapN(cbor_encode_ctx,
+                                   COSE_HEADER_PARAM_CONTENT_TYPE,
+                                   1);
+        /* A slighly complex unknown header parameter */
+        QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, 55);
+        QCBOREncode_OpenMap(cbor_encode_ctx);
+        QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 66, "hi");
+        QCBOREncode_AddSZStringToMapN(cbor_encode_ctx, 67, "bye");
+        QCBOREncode_CloseMap(cbor_encode_ctx);
+        QCBOREncode_OpenArray(cbor_encode_ctx);
+        QCBOREncode_OpenMap(cbor_encode_ctx);
+        QCBOREncode_CloseMap(cbor_encode_ctx);
+        QCBOREncode_CloseArray(cbor_encode_ctx);
+        QCBOREncode_CloseArray(cbor_encode_ctx);
+    }
+
+    if(test_message_options & T_COSE_TEST_TOO_LARGE_CONTENT_TYPE) {
+        QCBOREncode_AddInt64ToMapN(cbor_encode_ctx,
+                                   COSE_HEADER_PARAM_CONTENT_TYPE,
+                                   UINT16_MAX+1);
+    }
+
+    if(test_message_options & T_COSE_TEST_DUP_CONTENT_ID) {
+        QCBOREncode_AddUInt64ToMapN(cbor_encode_ctx,
+                                    COSE_HEADER_PARAM_CONTENT_TYPE,
+                                    3);
+    }
+
+    QCBOREncode_CloseMap(cbor_encode_ctx);
+}
+
+
+/**
+ * Replica of t_cose_sign1_encode_parameters() with modifications to
+ * output various good and bad messages for testing verification.
+ */
+static enum t_cose_err_t
+t_cose_sign1_test_message_encode_parameters(struct t_cose_sign1_sign_ctx *me,
+                                            int32_t                       test_mess_options,
+                                            QCBOREncodeContext           *cbor_encode_ctx)
+{
+    enum t_cose_err_t      return_value;
+    struct q_useful_buf    buffer_for_protected_parameters;
+    struct q_useful_buf_c  kid;
+    int32_t                hash_alg_id;
+
+    /* Check the cose_algorithm_id now by getting the hash alg as an early
+     * error check even though it is not used until later.
+     */
+    hash_alg_id = hash_alg_id_from_sig_alg_id(me->cose_algorithm_id);
+    if(hash_alg_id == T_COSE_INVALID_ALGORITHM_ID) {
+        return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
+    }
+
+    /* Add the CBOR tag indicating COSE_Sign1 */
+    if(!(me->option_flags & T_COSE_OPT_OMIT_CBOR_TAG)) {
+        QCBOREncode_AddTag(cbor_encode_ctx, CBOR_TAG_COSE_SIGN1);
+    }
+
+    /* Get started with the tagged array that holds the four parts of
+     * a cose single signed message */
+    QCBOREncode_OpenArray(cbor_encode_ctx);
+
+    /* The protected parameters, which are added as a wrapped bstr  */
+    buffer_for_protected_parameters = Q_USEFUL_BUF_FROM_BYTE_ARRAY(me->protected_parameters_buffer);
+    me->protected_parameters = encode_protected_parameters(test_mess_options,
+                                                           me->cose_algorithm_id,
+                                                           buffer_for_protected_parameters);
+    if(q_useful_buf_c_is_null(me->protected_parameters)) {
+        /* The sizing of storage for protected parameters is
+         off (should never happen in tested, released code) */
+        return_value = T_COSE_ERR_MAKING_PROTECTED;
+        goto Done;
+    }
+    if( ! (test_mess_options & T_COSE_TEST_NO_PROTECTED_PARAMETERS)) {
+        /* The use of _AddBytes here achieves the bstr wrapping */
+        QCBOREncode_AddBytes(cbor_encode_ctx, me->protected_parameters);
+    }
+
+    /* The Unprotected parameters */
+    /* Get the key id because it goes into the parameters that are about
+     to be made. */
+    if(me->option_flags & T_COSE_OPT_SHORT_CIRCUIT_SIG) {
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+        kid = get_short_circuit_kid();
+#else
+        return_value = T_COSE_ERR_SHORT_CIRCUIT_SIG_DISABLED;
+        goto Done;
+#endif
+    } else {
+        kid = me->kid;
+    }
+
+    if( ! (test_mess_options & T_COSE_TEST_NO_UNPROTECTED_PARAMETERS)) {
+        add_unprotected_parameters(test_mess_options, cbor_encode_ctx, kid);
+    }
+
+    QCBOREncode_BstrWrap(cbor_encode_ctx);
+
+    /* Any failures in CBOR encoding will be caught in finish when the
+     * CBOR encoding is closed off. No need to track here as the CBOR
+     * encoder tracks it internally. */
+
+    return_value = T_COSE_SUCCESS;
+
+Done:
+    return return_value;
+}
+
+
+/**
+ * Replica of t_cose_sign1_output_signature() with modifications to
+ * output various good and bad messages for testing verification.
+ */
+static enum t_cose_err_t
+t_cose_sign1_test_message_output_signature(struct t_cose_sign1_sign_ctx *me,
+                                           QCBOREncodeContext *cbor_encode_ctx)
+{
+    /* approximate stack use on 32-bit machine:
+     *   32 bytes local use
+     *   220 to 434 for calls dependin on hash implementation
+     *   32 to 64 bytes depending on hash alg (SHA256, 384 or 512)
+     *   64 to 260 depending on EC alg
+     *   348 to 778 depending on hash and EC alg
+     *   Also add stack use by EC and hash functions
+     */
+    enum t_cose_err_t            return_value;
+    QCBORError                   cbor_err;
+    /* pointer and length of the completed tbs hash */
+    struct q_useful_buf_c        tbs_hash;
+    /* Pointer and length of the completed signature */
+    struct q_useful_buf_c        signature;
+    /* Buffer for the actual signature */
+    Q_USEFUL_BUF_MAKE_STACK_UB(  buffer_for_signature, T_COSE_MAX_SIG_SIZE);
+    /* Buffer for the tbs hash. */
+    Q_USEFUL_BUF_MAKE_STACK_UB(  buffer_for_tbs_hash, T_COSE_CRYPTO_MAX_HASH_SIZE);
+    struct q_useful_buf_c        signed_payload;
+
+    QCBOREncode_CloseBstrWrap(cbor_encode_ctx, &signed_payload);
+
+    /* Check there are no CBOR encoding errors before proceeding with
+     * hashing and signing. This is not actually necessary as the
+     * errors will be caught correctly later, but it does make it a
+     * bit easier for the caller to debug problems.
+     */
+    cbor_err = QCBOREncode_GetErrorState(cbor_encode_ctx);
+    if(cbor_err == QCBOR_ERR_BUFFER_TOO_SMALL) {
+        return_value = T_COSE_ERR_TOO_SMALL;
+        goto Done;
+    } else if(cbor_err != QCBOR_SUCCESS) {
+        return_value = T_COSE_ERR_CBOR_FORMATTING;
+        goto Done;
+    }
+
+    /* Create the hash of the to-be-signed bytes. Inputs to the hash
+     * are the protected parameters, the payload that is getting signed, the
+     * cose signature alg from which the hash alg is determined. The
+     * cose_algorithm_id was checked in t_cose_sign1_init() so it
+     * doesn't need to be checked here.
+     */
+    return_value = create_tbs_hash(me->cose_algorithm_id,
+                                   me->protected_parameters,
+                                   T_COSE_TBS_PAYLOAD_IS_BSTR_WRAPPED,
+                                   signed_payload,
+                                   buffer_for_tbs_hash,
+                                   &tbs_hash);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+    /* Compute the signature using public key crypto. The key selector
+     * and algorithm ID are passed in to know how and what to sign
+     * with. The hash of the TBS bytes are what is signed. A buffer in
+     * which to place the signature is passed in and the signature is
+     * returned.
+     *
+     * Short-circuit signing is invoked if requested. It does no
+     * public key operation and requires no key. It is just a test
+     * mode that always works.
+     */
+    if(!(me->option_flags & T_COSE_OPT_SHORT_CIRCUIT_SIG)) {
+        /* Normal, non-short-circuit signing */
+        return_value = t_cose_crypto_pub_key_sign(me->cose_algorithm_id,
+                                                  me->signing_key,
+                                                  tbs_hash,
+                                                  buffer_for_signature,
+                                                  &signature);
+    } else {
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+        return_value = short_circuit_sign(me->cose_algorithm_id,
+                                          tbs_hash,
+                                          buffer_for_signature,
+                                          &signature);
+#endif
+    }
+
+    if(return_value) {
+        goto Done;
+    }
+
+    /* Add signature to CBOR and close out the array */
+    QCBOREncode_AddBytes(cbor_encode_ctx, signature);
+    QCBOREncode_CloseArray(cbor_encode_ctx);
+
+    /* The layer above this must check for and handle CBOR encoding
+     * errors CBOR encoding errors.  Some are detected at the start of
+     * this function, but they cannot all be deteced there.
+     */
+Done:
+    return return_value;
+}
+
+
+/*
+ * Public function. See t_cose_make_test_messages.h
+ */
+enum t_cose_err_t
+t_cose_test_message_sign1_sign(struct t_cose_sign1_sign_ctx *me,
+                               int32_t                     test_message_options,
+                               struct q_useful_buf_c         payload,
+                               struct q_useful_buf           out_buf,
+                               struct q_useful_buf_c        *result)
+{
+    QCBOREncodeContext  encode_context;
+    enum t_cose_err_t   return_value;
+
+    /* -- Initialize CBOR encoder context with output buffer */
+    QCBOREncode_Init(&encode_context, out_buf);
+
+    /* -- Output the header parameters into the encoder context -- */
+    return_value = t_cose_sign1_test_message_encode_parameters(me, test_message_options, &encode_context);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+    /* -- Output the payload into the encoder context -- */
+    /* Payload may or may not actually be CBOR format here. This
+     * function does the job just fine because it just adds bytes to
+     * the encoded output without anything extra.
+     */
+    QCBOREncode_AddEncoded(&encode_context, payload);
+
+    /* -- Sign and put signature in the encoder context -- */
+    return_value = t_cose_sign1_test_message_output_signature(me,
+                                                              &encode_context);
+    if(return_value) {
+        goto Done;
+    }
+
+    /* -- Close off and get the resulting encoded CBOR -- */
+    if(QCBOREncode_Finish(&encode_context, result)) {
+        return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
+        goto Done;
+    }
+
+Done:
+    return return_value;
+}
+
diff --git a/lib/ext/t_cose/test/t_cose_make_test_messages.h b/lib/ext/t_cose/test/t_cose_make_test_messages.h
new file mode 100644
index 0000000..3dde9fd
--- /dev/null
+++ b/lib/ext/t_cose/test/t_cose_make_test_messages.h
@@ -0,0 +1,148 @@
+/*
+ * t_cose_make_test_messages.h
+ *
+ * Copyright (c) 2019, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#ifndef __T_COSE_MAKE_TEST_MESSAGES__
+#define __T_COSE_MAKE_TEST_MESSAGES__
+
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "qcbor.h"
+#include "t_cose_common.h"
+#include "t_cose_sign1_sign.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * \file t_cose_make_test_messages.h
+ *
+ * \brief Create a test \c COSE_Sign1 message for testing the verifier.
+ *
+ */
+
+
+/**
+ * Various flags to pass to t_cose_test_message_sign1_sign() to
+ * make different types of test messages for testing verification
+ */
+
+/** Make test message with a bstr label, which is not allowed by
+  * COSE */
+#define T_COSE_TEST_PARAMETER_LABEL 0x80000000
+
+/** Format of the crit parameter is made invalid */
+#define T_COSE_TEST_BAD_CRIT_PARAMETER   0x40000000
+
+/** An extra parameter is added. It has nested structure to be sure
+ *  such are skipped correctly */
+#define T_COSE_TEST_EXTRA_PARAMETER 0x20000000
+
+/** The protected parameters bucked is left out of the COSE_Sign1
+ *  message entirely */
+#define T_COSE_TEST_NO_PROTECTED_PARAMETERS 0x10000000
+
+/** The unprotected parameters bucked is left out of the COSE_Sign1
+ *  message entirely */
+#define T_COSE_TEST_NO_UNPROTECTED_PARAMETERS 0x08000000
+
+/** Simple not-well-formed CBOR is added to the unprotected parameters
+ *  bucket */
+#define T_COSE_TEST_NOT_WELL_FORMED_1 0x04000000
+
+/** Not-well-formed CBOR nested in a map is added to the unprotected
+ *  parameters bucket */
+#define T_COSE_TEST_NOT_WELL_FORMED_2 0x02000000
+
+/** The crit parameter lists several integer critical labels and the
+ *  labeled parameters exists and they are not understood */
+#define T_COSE_TEST_UNKNOWN_CRIT_UINT_PARAMETER 0x01000000
+
+/** The crit parameter lists critical labels, but none of them
+ *  occur */
+#define T_COSE_TEST_CRIT_PARAMETER_EXIST 0x00800000
+
+/** Exceed the limit on number of T_COSE_PARAMETER_LIST_MAX on number
+ * of crit parameters this implementation can handle */
+#define T_COSE_TEST_TOO_MANY_CRIT_PARAMETER_EXIST 0x00400000
+
+/** One of the labels in the crit parameter is of the wrong type */
+#define T_COSE_TEST_BAD_CRIT_LABEL 0x00200000
+
+/** The crit parameter is in the unprotected bucket */
+#define T_COSE_TEST_CRIT_NOT_PROTECTED 0x00100000
+
+/** More than T_COSE_PARAMETER_LIST_MAX unknown parameters occured */
+#define T_COSE_TEST_TOO_MANY_UNKNOWN 0x00080000
+
+/** The crit parameter lists several text string critical labels and
+ * the labeled parameters exists and they are not understood */
+#define T_COSE_TEST_UNKNOWN_CRIT_TSTR_PARAMETER 0x00040000
+
+/** One of each type of parameter the verify handles is added, plus
+ *  some unknown parameters */
+#define T_COSE_TEST_ALL_PARAMETERS 0x00020000
+
+/** An invalid CBOR type is in the protected bucket */
+#define T_COSE_TEST_BAD_PROTECTED 0x00010000
+
+/** The unprotected header bucket is an array, not a map */
+#define T_COSE_TEST_UNPROTECTED_NOT_MAP 0x00008000
+
+/** A kid is added to the protected parameters and is thus a duplicate
+ *  parameter in both protected and unprotected buckets */
+#define T_COSE_TEST_KID_IN_PROTECTED 0x00004000
+
+/** The integer CoAP content type is larger than UINT16_MAX, larger
+ *  than it is allowed */
+#define T_COSE_TEST_TOO_LARGE_CONTENT_TYPE 0x00002000
+
+/** The protected parameters are not a complete map. Supposed to have
+ *  1 item, but has zero */
+#define T_COSE_TEST_UNCLOSED_PROTECTED 0x00001000
+
+/** The content ID parameter occurs in both protected and unprotected
+ *  bucket */
+#define T_COSE_TEST_DUP_CONTENT_ID 0x00000800
+
+/** The bstr wrapped protected parameters is zero length */
+#define T_COSE_TEST_EMPTY_PROTECTED_PARAMETERS 0x00000400
+
+/** The list of critical labels parameter is empty. This is not
+ * allowed by COSE */
+#define T_COSE_TEST_EMPTY_CRIT_PARAMETER 0x00000200
+
+/** Exceed the limit on number of T_COSE_PARAMETER_LIST_MAX on number
+ * of crit parameters this implementation can handle */
+#define T_COSE_TEST_TOO_MANY_TSTR_CRIT_LABLELS 0x00000100
+
+
+/**
+ * Replica of t_cose_sign1_sign() with modifications to output various
+ * good and bad messages for testing of t_cose_sign1_verify() .
+ *
+ * \c test_message_options is one of \c T_COSE_TEST_XXX
+ */
+enum t_cose_err_t
+t_cose_test_message_sign1_sign(struct t_cose_sign1_sign_ctx *me,
+                               int32_t                       test_message_options,
+                               struct q_useful_buf_c         payload,
+                               struct q_useful_buf           out_buf,
+                               struct q_useful_buf_c        *result);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __T_COSE_MAKE_TEST_MESSAGES__ */
diff --git a/lib/ext/t_cose/test/t_cose_make_test_pub_key.h b/lib/ext/t_cose/test/t_cose_make_test_pub_key.h
new file mode 100644
index 0000000..585c0b2
--- /dev/null
+++ b/lib/ext/t_cose/test/t_cose_make_test_pub_key.h
@@ -0,0 +1,32 @@
+/*
+ *  t_cose_make_test_pub_key.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "t_cose_common.h"
+#include <stdint.h>
+
+/**
+ * \file t_cose_make_test_pub_key.h
+ *
+ * \brief This defines a simple interface to make keys for tests cases.
+ *
+ */
+
+
+/**
+ * \brief make an ECDSA key pair for testing suited to algorim
+ *
+ */
+enum t_cose_err_t make_ecdsa_key_pair(int32_t            cose_algorithm_id,
+                                      struct t_cose_key *key_pair);
+
+
+void free_ecdsa_key_pair(struct t_cose_key key_pair);
+
+
diff --git a/lib/ext/t_cose/test/t_cose_sign_verify_test.c b/lib/ext/t_cose/test/t_cose_sign_verify_test.c
new file mode 100644
index 0000000..8dbefb7
--- /dev/null
+++ b/lib/ext/t_cose/test/t_cose_sign_verify_test.c
@@ -0,0 +1,471 @@
+/*
+ *  t_cose_sign_verify_test.c
+ *
+ * Copyright 2019-2020, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "t_cose_sign1_sign.h"
+#include "t_cose_sign1_verify.h"
+#include "q_useful_buf.h"
+#include "t_cose_make_test_pub_key.h"
+
+#include "t_cose_crypto.h" /* Just for t_cose_crypto_sig_size() */
+
+
+/*
+ * Public function, see t_cose_sign_verify_test.h
+ */
+int_fast32_t sign_verify_basic_test_alg(int32_t cose_alg)
+{
+    struct t_cose_sign1_sign_ctx   sign_ctx;
+    enum t_cose_err_t              return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(    signed_cose_buffer, 300);
+    struct q_useful_buf_c          signed_cose;
+    struct t_cose_key              key_pair;
+    struct q_useful_buf_c          payload;
+    struct t_cose_sign1_verify_ctx verify_ctx;
+
+    /* -- Get started with context initialization, selecting the alg -- */
+    t_cose_sign1_sign_init(&sign_ctx, 0, cose_alg);
+
+    /* Make an ECDSA key pair that will be used for both signing and
+     * verification.
+     */
+    return_value = make_ecdsa_key_pair(cose_alg, &key_pair);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+    t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C);
+
+    t_cose_sign1_sign(&sign_ctx,
+                      Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                      signed_cose_buffer,
+                      &signed_cose);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+
+    /* Verification */
+    t_cose_sign1_verify_init(&verify_ctx, 0);
+
+    t_cose_sign1_set_verification_key(&verify_ctx, key_pair);
+
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                       signed_cose,         /* COSE to verify */
+                                       &payload,  /* Payload from signed_cose */
+                                       NULL);      /* Don't return parameters */
+    if(return_value) {
+        return 5000 + return_value;
+    }
+
+    /* OpenSSL uses malloc to allocate buffers for keys, so they have to
+     * be freed */
+    free_ecdsa_key_pair(key_pair);
+
+    /* compare payload output to the one expected */
+    if(q_useful_buf_compare(payload, Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"))) {
+        return 6000;
+    }
+
+    return 0;
+}
+
+
+/*
+ * Public function, see t_cose_sign_verify_test.h
+ */
+int_fast32_t sign_verify_basic_test()
+{
+    int_fast32_t return_value;
+
+    return_value  = sign_verify_basic_test_alg(T_COSE_ALGORITHM_ES256);
+    if(return_value) {
+        return 20000 + return_value;
+    }
+
+#ifndef T_COSE_DISABLE_ES384
+    return_value  = sign_verify_basic_test_alg(T_COSE_ALGORITHM_ES384);
+    if(return_value) {
+        return 30000 + return_value;
+    }
+#endif
+
+#ifndef T_COSE_DISABLE_ES512
+    return_value  = sign_verify_basic_test_alg(T_COSE_ALGORITHM_ES512);
+    if(return_value) {
+        return 50000 + return_value;
+    }
+#endif
+
+    return 0;
+
+}
+
+
+/*
+ * Public function, see t_cose_sign_verify_test.h
+ */
+int_fast32_t sign_verify_sig_fail_test()
+{
+    struct t_cose_sign1_sign_ctx   sign_ctx;
+    QCBOREncodeContext             cbor_encode;
+    enum t_cose_err_t              return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(    signed_cose_buffer, 300);
+    struct q_useful_buf_c          signed_cose;
+    struct t_cose_key              key_pair;
+    struct q_useful_buf_c          payload;
+    QCBORError                     cbor_error;
+    struct t_cose_sign1_verify_ctx verify_ctx;
+    size_t                         tamper_offset;
+
+
+    /* Make an ECDSA key pair that will be used for both signing and
+     * verification.
+     */
+    return_value = make_ecdsa_key_pair(T_COSE_ALGORITHM_ES256, &key_pair);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+
+    QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
+
+    t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_ES256);
+    t_cose_sign1_set_signing_key(&sign_ctx, key_pair, NULL_Q_USEFUL_BUF_C);
+
+    return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+
+    QCBOREncode_AddSZString(&cbor_encode, "payload");
+
+
+    return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 3000 + return_value;
+    }
+
+    cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose);
+    if(cbor_error) {
+        return 4000 + cbor_error;
+    }
+
+    /* tamper with the pay load to see that the signature verification fails */
+    tamper_offset = q_useful_buf_find_bytes(signed_cose, Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"));
+    if(tamper_offset == SIZE_MAX) {
+        return 99;
+    }
+    ((char *)signed_cose.ptr)[tamper_offset] = 'h';
+
+
+    t_cose_sign1_verify_init(&verify_ctx, 0);
+
+    t_cose_sign1_set_verification_key(&verify_ctx, key_pair);
+
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                       signed_cose,         /* COSE to verify */
+                                       &payload,  /* Payload from signed_cose */
+                                       NULL);      /* Don't return parameters */
+
+    if(return_value != T_COSE_ERR_SIG_VERIFY) {
+        return 5000 + return_value;
+    }
+
+    free_ecdsa_key_pair(key_pair);
+
+    return 0;
+}
+
+
+/*
+ * Public function, see t_cose_sign_verify_test.h
+ */
+int_fast32_t sign_verify_make_cwt_test()
+{
+    struct t_cose_sign1_sign_ctx   sign_ctx;
+    QCBOREncodeContext             cbor_encode;
+    enum t_cose_err_t              return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(    signed_cose_buffer, 300);
+    struct q_useful_buf_c          signed_cose;
+    struct t_cose_key              key_pair;
+    struct q_useful_buf_c          payload;
+    QCBORError                     cbor_error;
+    struct t_cose_sign1_verify_ctx verify_ctx;
+    struct q_useful_buf_c          expected_rfc8392_first_part;
+    struct q_useful_buf_c          expected_payload;
+    struct q_useful_buf_c          actual_rfc8392_first_part;
+
+    /* -- initialize for signing --
+     *  No special options selected
+     */
+    t_cose_sign1_sign_init(&sign_ctx, 0, T_COSE_ALGORITHM_ES256);
+
+
+    /* -- Key and kid --
+     * The ECDSA key pair made is both for signing and verification.
+     * The kid comes from RFC 8932
+     */
+    return_value = make_ecdsa_key_pair(T_COSE_ALGORITHM_ES256, &key_pair);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+    t_cose_sign1_set_signing_key(&sign_ctx,
+                                  key_pair,
+                                  Q_USEFUL_BUF_FROM_SZ_LITERAL("AsymmetricECDSA256"));
+
+
+    /* -- Encoding context and output of parameters -- */
+    QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
+    return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+
+
+    /* -- The payload as from RFC 8932 -- */
+    QCBOREncode_OpenMap(&cbor_encode);
+    QCBOREncode_AddSZStringToMapN(&cbor_encode, 1, "coap://as.example.com");
+    QCBOREncode_AddSZStringToMapN(&cbor_encode, 2, "erikw");
+    QCBOREncode_AddSZStringToMapN(&cbor_encode, 3, "coap://light.example.com");
+    QCBOREncode_AddInt64ToMapN(&cbor_encode, 4, 1444064944);
+    QCBOREncode_AddInt64ToMapN(&cbor_encode, 5, 1443944944);
+    QCBOREncode_AddInt64ToMapN(&cbor_encode, 6, 1443944944);
+    const uint8_t xx[] = {0x0b, 0x71};
+    QCBOREncode_AddBytesToMapN(&cbor_encode, 7,
+                               Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(xx));
+    QCBOREncode_CloseMap(&cbor_encode);
+
+
+    /* -- Finish up the COSE_Sign1. This is where the signing happens -- */
+    return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+
+    /* Finally close off the CBOR formatting and get the pointer and length
+     * of the resulting COSE_Sign1
+     */
+    cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose);
+    if(cbor_error) {
+        return 3000 + cbor_error;
+    }
+    /* --- Done making COSE Sign1 object  --- */
+
+
+    /* Compare to expected from CWT RFC */
+    /* The first part, the intro and protected parameters must be the same */
+    const uint8_t rfc8392_first_part_bytes[] = {
+        0xd2, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa1, 0x04, 0x52, 0x41, 0x73, 0x79,
+        0x6d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x45, 0x43, 0x44, 0x53, 0x41,
+        0x32, 0x35, 0x36, 0x58, 0x50, 0xa7, 0x01, 0x75, 0x63, 0x6f, 0x61, 0x70,
+        0x3a, 0x2f, 0x2f, 0x61, 0x73, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c,
+        0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x65, 0x65, 0x72, 0x69, 0x6b, 0x77,
+        0x03, 0x78, 0x18, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x69,
+        0x67, 0x68, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e,
+        0x63, 0x6f, 0x6d, 0x04, 0x1a, 0x56, 0x12, 0xae, 0xb0, 0x05, 0x1a, 0x56,
+        0x10, 0xd9, 0xf0, 0x06, 0x1a, 0x56, 0x10, 0xd9, 0xf0, 0x07, 0x42, 0x0b,
+        0x71};
+    expected_rfc8392_first_part = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(rfc8392_first_part_bytes);
+    actual_rfc8392_first_part = q_useful_buf_head(signed_cose, sizeof(rfc8392_first_part_bytes));
+    if(q_useful_buf_compare(actual_rfc8392_first_part, expected_rfc8392_first_part)) {
+        return -1;
+    }
+
+    /* --- Start verifying the COSE Sign1 object  --- */
+    /* Run the signature verification */
+    t_cose_sign1_verify_init(&verify_ctx, 0);
+
+    t_cose_sign1_set_verification_key(&verify_ctx, key_pair);
+
+    return_value =  t_cose_sign1_verify(&verify_ctx,
+                                        signed_cose, /* COSE to verify */
+                                       &payload, /* Payload from signed_cose */
+                                        NULL);  /* Don't return parameters */
+
+    if(return_value) {
+        return 4000 + return_value;
+    }
+
+    /* Format the expected payload CBOR fragment */
+
+    /* Skip the key id, because this has the short-circuit key id */
+    const size_t kid_encoded_len =
+      1 +
+      1 +
+      1 +
+      strlen("AsymmetricECDSA256"); // length of short-circuit key id
+
+
+    /* compare payload output to the one expected */
+    expected_payload = q_useful_buf_tail(expected_rfc8392_first_part, kid_encoded_len + 8);
+    if(q_useful_buf_compare(payload, expected_payload)) {
+        return 5000;
+    }
+    /* --- Done verifying the COSE Sign1 object  --- */
+
+    free_ecdsa_key_pair(key_pair);
+
+    return 0;
+}
+
+
+/*
+ * Public function, see t_cose_sign_verify_test.h
+ */
+static int size_test(int32_t               cose_algorithm_id,
+                     struct q_useful_buf_c kid,
+                     struct t_cose_key     key_pair)
+{
+    struct t_cose_sign1_sign_ctx   sign_ctx;
+    QCBOREncodeContext             cbor_encode;
+    enum t_cose_err_t              return_value;
+    struct q_useful_buf            nil_buf;
+    size_t                         calculated_size;
+    QCBORError                     cbor_error;
+    struct q_useful_buf_c          actual_signed_cose;
+    Q_USEFUL_BUF_MAKE_STACK_UB(    signed_cose_buffer, 300);
+    struct q_useful_buf_c          payload;
+    size_t                         sig_size;
+
+    /* ---- Common Set up ---- */
+    payload = Q_USEFUL_BUF_FROM_SZ_LITERAL("payload");
+    return_value = t_cose_crypto_sig_size(cose_algorithm_id, key_pair, &sig_size);
+
+    /* ---- First calculate the size ----- */
+    nil_buf = (struct q_useful_buf) {NULL, INT32_MAX};
+    QCBOREncode_Init(&cbor_encode, nil_buf);
+
+    t_cose_sign1_sign_init(&sign_ctx,  0,  cose_algorithm_id);
+    t_cose_sign1_set_signing_key(&sign_ctx, key_pair, kid);
+
+    return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+
+    QCBOREncode_AddEncoded(&cbor_encode, payload);
+
+    return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 3000 + return_value;
+    }
+
+    cbor_error = QCBOREncode_FinishGetSize(&cbor_encode, &calculated_size);
+    if(cbor_error) {
+        return 4000 + cbor_error;
+    }
+
+    /* ---- General sanity check ---- */
+    size_t expected_min = sig_size + payload.len + kid.len;
+
+    if(calculated_size < expected_min || calculated_size > expected_min + 30) {
+        return -1;
+    }
+
+
+
+    /* ---- Now make a real COSE_Sign1 and compare the size ---- */
+    QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
+
+    t_cose_sign1_sign_init(&sign_ctx,  0,  cose_algorithm_id);
+    t_cose_sign1_set_signing_key(&sign_ctx, key_pair, kid);
+
+    return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+
+    QCBOREncode_AddEncoded(&cbor_encode, payload);
+
+    return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 3000 + return_value;
+    }
+
+    cbor_error = QCBOREncode_Finish(&cbor_encode, &actual_signed_cose);
+    if(actual_signed_cose.len != calculated_size) {
+        return -2;
+    }
+
+    /* ---- Again with one-call API to make COSE_Sign1 ---- */\
+    t_cose_sign1_sign_init(&sign_ctx, 0, cose_algorithm_id);
+    t_cose_sign1_set_signing_key(&sign_ctx, key_pair, kid);
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     payload,
+                                     signed_cose_buffer,
+                                     &actual_signed_cose);
+    if(return_value) {
+        return 7000 + return_value;
+    }
+
+    if(actual_signed_cose.len != calculated_size) {
+        return -3;
+    }
+
+    return 0;
+}
+
+
+/*
+ * Public function, see t_cose_sign_verify_test.h
+ */
+int_fast32_t sign_verify_get_size_test()
+{
+    enum t_cose_err_t   return_value;
+    struct t_cose_key   key_pair;
+    int32_t             result;
+
+    return_value = make_ecdsa_key_pair(T_COSE_ALGORITHM_ES256, &key_pair);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+
+    result = size_test(T_COSE_ALGORITHM_ES256, NULL_Q_USEFUL_BUF_C, key_pair);
+    if(result) {
+        return result;
+    }
+
+    free_ecdsa_key_pair(key_pair);
+
+#ifndef T_COSE_DISABLE_ES384
+    return_value = make_ecdsa_key_pair(T_COSE_ALGORITHM_ES384, &key_pair);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+
+    result = size_test(T_COSE_ALGORITHM_ES384, NULL_Q_USEFUL_BUF_C, key_pair);
+    if(result) {
+        return result;
+    }
+
+    free_ecdsa_key_pair(key_pair);
+#endif
+
+#ifndef T_COSE_DISABLE_ES512
+    return_value = make_ecdsa_key_pair(T_COSE_ALGORITHM_ES512, &key_pair);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+
+    result = size_test(T_COSE_ALGORITHM_ES512, NULL_Q_USEFUL_BUF_C, key_pair);
+    if(result) {
+        return result;
+    }
+
+
+    result = size_test(T_COSE_ALGORITHM_ES512,
+                       Q_USEFUL_BUF_FROM_SZ_LITERAL("greasy kid stuff"),
+                       key_pair);
+    if(result) {
+        return result;
+    }
+
+    free_ecdsa_key_pair(key_pair);
+#endif
+
+    return 0;
+}
diff --git a/lib/ext/t_cose/test/t_cose_sign_verify_test.h b/lib/ext/t_cose/test/t_cose_sign_verify_test.h
new file mode 100644
index 0000000..4cdf7ed
--- /dev/null
+++ b/lib/ext/t_cose/test/t_cose_sign_verify_test.h
@@ -0,0 +1,49 @@
+/*
+ *  t_cose_sign_verify_test.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#ifndef t_cose_sign_verify_test_h
+#define t_cose_sign_verify_test_h
+
+#include <stdint.h>
+
+
+/**
+ * \file t_cose_sign_verify_test.h
+ *
+ * \brief Tests that need public key crypto to be implemented
+ */
+
+
+/**
+ * \brief Self test using openssl crypto.
+ *
+ * \return non-zero on failure.
+ */
+int_fast32_t sign_verify_basic_test(void);
+
+
+/*
+ * Sign some data, perturb the data and see that sig validation fails
+ */
+int_fast32_t sign_verify_sig_fail_test(void);
+
+
+/*
+ * Make a CWT and compare it to the one in the CWT RFC
+ */
+int_fast32_t sign_verify_make_cwt_test(void);
+
+
+/*
+ * Test the ability to calculate size of a COSE_Sign1
+ */
+int_fast32_t sign_verify_get_size_test(void);
+
+#endif /* t_cose_sign_verify_test_h */
diff --git a/lib/ext/t_cose/test/t_cose_test.c b/lib/ext/t_cose/test/t_cose_test.c
new file mode 100644
index 0000000..30db83d
--- /dev/null
+++ b/lib/ext/t_cose/test/t_cose_test.c
@@ -0,0 +1,1008 @@
+/*
+ *  t_cose_test.c
+ *
+ * Copyright 2019-2020, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "t_cose_test.h"
+#include "t_cose_sign1_sign.h"
+#include "t_cose_sign1_verify.h"
+#include "t_cose_make_test_messages.h"
+#include "q_useful_buf.h"
+#include "t_cose_crypto.h" /* For signature size constant */
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t short_circuit_self_test()
+{
+    struct t_cose_sign1_sign_ctx    sign_ctx;
+    struct t_cose_sign1_verify_ctx  verify_ctx;
+    enum t_cose_err_t               return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(     signed_cose_buffer, 200);
+    struct q_useful_buf_c           signed_cose;
+    struct q_useful_buf_c           payload;
+
+
+    /* --- Make COSE Sign1 object --- */
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    /* No key necessary because short-circuit test mode is used */
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                     signed_cose_buffer,
+                                     &signed_cose);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+    /* --- Done making COSE Sign1 object  --- */
+
+
+    /* --- Start verifying the COSE Sign1 object  --- */
+    /* Select short circuit signing */
+    t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
+
+    /* No key necessary with short circuit */
+
+    /* Run the signature verification */
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                       /* COSE to verify */
+                                       signed_cose,
+                                       /* The returned payload */
+                                       &payload,
+                                       /* Don't return parameters */
+                                       NULL);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+
+    /* compare payload output to the one expected */
+    if(q_useful_buf_compare(payload, Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"))) {
+        return 3000;
+    }
+    /* --- Done verifying the COSE Sign1 object  --- */
+
+    return 0;
+}
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t short_circuit_verify_fail_test()
+{
+    struct t_cose_sign1_sign_ctx    sign_ctx;
+    struct t_cose_sign1_verify_ctx  verify_ctx;
+    enum t_cose_err_t               return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(     signed_cose_buffer, 200);
+    struct q_useful_buf_c           signed_cose;
+    struct q_useful_buf_c           payload;
+    size_t                          payload_offset;
+
+    /* --- Start making COSE Sign1 object  --- */
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    /* No key necessary because short-circuit test mode is used */
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                     signed_cose_buffer,
+                                     &signed_cose);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+    /* --- Done making COSE Sign1 object  --- */
+
+
+    /* --- Start Tamper with payload  --- */
+    /* Find the offset of the payload in COSE_Sign1 */
+    payload_offset = q_useful_buf_find_bytes(signed_cose, Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"));
+    if(payload_offset == SIZE_MAX) {
+        return 6000;
+    }
+    /* Change "payload" to "hayload" */
+    ((char *)signed_cose.ptr)[payload_offset] = 'h';
+    /* --- Tamper with payload Done --- */
+
+
+    /* --- Start verifying the COSE Sign1 object  --- */
+
+    /* Select short circuit signing */
+    t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
+
+    /* No key necessary with short circuit */
+
+    /* Run the signature verification */
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                       /* COSE to verify */
+                                       signed_cose,
+                                       /* The returned payload */
+                                       &payload,
+                                       /* Don't return parameters */
+                                       NULL);
+    if(return_value != T_COSE_ERR_SIG_VERIFY) {
+        return 4000 + return_value;
+    }
+    /* --- Done verifying the COSE Sign1 object  --- */
+
+    return 0;
+}
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t short_circuit_signing_error_conditions_test()
+{
+    struct t_cose_sign1_sign_ctx sign_ctx;
+    QCBOREncodeContext           cbor_encode;
+    enum t_cose_err_t            return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(  signed_cose_buffer, 300);
+    Q_USEFUL_BUF_MAKE_STACK_UB(  small_signed_cose_buffer, 15);
+    struct q_useful_buf_c        signed_cose;
+
+
+    /* -- Test bad algorithm ID 0 -- */
+    /* Use reserved alg ID 0 to cause error. */
+    t_cose_sign1_sign_init(&sign_ctx, T_COSE_OPT_SHORT_CIRCUIT_SIG, 0);
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                     signed_cose_buffer,
+                                     &signed_cose);
+    if(return_value != T_COSE_ERR_UNSUPPORTED_SIGNING_ALG) {
+        return -1;
+    }
+
+
+    /* -- Test bad algorithm ID -4444444 -- */
+    /* Use unassigned alg ID -4444444 to cause error. */
+    t_cose_sign1_sign_init(&sign_ctx, T_COSE_OPT_SHORT_CIRCUIT_SIG, -4444444);
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                     signed_cose_buffer,
+                                     &signed_cose);
+    if(return_value != T_COSE_ERR_UNSUPPORTED_SIGNING_ALG) {
+        return -2;
+    }
+
+
+
+    /* -- Tests detection of CBOR encoding error in the payload -- */
+    QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
+
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+    return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
+
+
+    QCBOREncode_AddSZString(&cbor_encode, "payload");
+    /* Force a CBOR encoding error by closing a map that is not open */
+    QCBOREncode_CloseMap(&cbor_encode);
+
+    return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
+
+    if(return_value != T_COSE_ERR_CBOR_FORMATTING) {
+        return -3;
+    }
+
+
+    /* -- Tests the output buffer being too small -- */
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                     small_signed_cose_buffer,
+                                     &signed_cose);
+
+    if(return_value != T_COSE_ERR_TOO_SMALL) {
+        return -4;
+    }
+
+    return 0;
+}
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t short_circuit_make_cwt_test()
+{
+    struct t_cose_sign1_sign_ctx    sign_ctx;
+    struct t_cose_sign1_verify_ctx  verify_ctx;
+    QCBOREncodeContext              cbor_encode;
+    enum t_cose_err_t               return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(     signed_cose_buffer, 200);
+    struct q_useful_buf_c           signed_cose;
+    struct q_useful_buf_c           payload;
+    QCBORError                      cbor_error;
+
+    /* --- Start making COSE Sign1 object  --- */
+
+    /* The CBOR encoder instance that the COSE_Sign1 is output into */
+    QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
+
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    /* Do the first part of the the COSE_Sign1, the parameters */
+    return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+
+    QCBOREncode_OpenMap(&cbor_encode);
+    QCBOREncode_AddSZStringToMapN(&cbor_encode, 1, "coap://as.example.com");
+    QCBOREncode_AddSZStringToMapN(&cbor_encode, 2, "erikw");
+    QCBOREncode_AddSZStringToMapN(&cbor_encode, 3, "coap://light.example.com");
+    QCBOREncode_AddInt64ToMapN(&cbor_encode, 4, 1444064944);
+    QCBOREncode_AddInt64ToMapN(&cbor_encode, 5, 1443944944);
+    QCBOREncode_AddInt64ToMapN(&cbor_encode, 6, 1443944944);
+    const uint8_t xx[] = {0x0b, 0x71};
+    QCBOREncode_AddBytesToMapN(&cbor_encode, 7, Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(xx));
+    QCBOREncode_CloseMap(&cbor_encode);
+
+    /* Finish up the COSE_Sign1. This is where the signing happens */
+    return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+
+    /* Finally close off the CBOR formatting and get the pointer and length
+     * of the resulting COSE_Sign1
+     */
+    cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose);
+    if(cbor_error) {
+        return 3000 + cbor_error;
+    }
+    /* --- Done making COSE Sign1 object  --- */
+
+
+    /* --- Compare to expected from CWT RFC --- */
+    /* The first part, the intro and protected pararameters must be the same */
+    const uint8_t cwt_first_part_bytes[] = {0xd2, 0x84, 0x43, 0xa1, 0x01, 0x26};
+    struct q_useful_buf_c fp = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(cwt_first_part_bytes);
+    struct q_useful_buf_c head = q_useful_buf_head(signed_cose, sizeof(cwt_first_part_bytes));
+    if(q_useful_buf_compare(head, fp)) {
+        return -1;
+    }
+
+    /* Skip the key id, because this has the short-circuit key id */
+    const size_t kid_encoded_len =
+       1 +
+       1 +
+       2 +
+       32; // length of short-circuit key id
+
+    /* Compare the payload */
+    const uint8_t rfc8392_payload_bytes[] = {
+        0x58, 0x50, 0xa7, 0x01, 0x75, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f,
+        0x2f, 0x61, 0x73, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
+        0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x65, 0x65, 0x72, 0x69, 0x6b, 0x77,
+        0x03, 0x78, 0x18, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x6c,
+        0x69, 0x67, 0x68, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c,
+        0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x04, 0x1a, 0x56, 0x12, 0xae, 0xb0,
+        0x05, 0x1a, 0x56, 0x10, 0xd9, 0xf0, 0x06, 0x1a, 0x56, 0x10, 0xd9,
+        0xf0, 0x07, 0x42, 0x0b, 0x71};
+
+    struct q_useful_buf_c fp2 = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(rfc8392_payload_bytes);
+
+    struct q_useful_buf_c payload2 = q_useful_buf_tail(signed_cose,
+                                                       sizeof(cwt_first_part_bytes)+kid_encoded_len);
+    struct q_useful_buf_c pl3 = q_useful_buf_head(payload2,
+                                                sizeof(rfc8392_payload_bytes));
+    if(q_useful_buf_compare(pl3, fp2)) {
+        return -2;
+    }
+
+    /* Skip the signature because ECDSA signatures usually have a random
+     component */
+
+
+    /* --- Start verifying the COSE Sign1 object  --- */
+    t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
+
+    /* No key necessary with short circuit */
+
+    /* Run the signature verification */
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                       /* COSE to verify */
+                                       signed_cose,
+                                       /* The returned payload */
+                                       &payload,
+                                       /* Don't return parameters */
+                                       NULL);
+    if(return_value) {
+        return 4000 + return_value;
+    }
+
+    /* Format the expected payload CBOR fragment */
+
+    /* compare payload output to the one expected */
+    if(q_useful_buf_compare(payload, q_useful_buf_tail(fp2, 2))) {
+        return 5000;
+    }
+    /* --- Done verifying the COSE Sign1 object  --- */
+
+    return 0;
+}
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t short_circuit_decode_only_test()
+{
+    struct t_cose_sign1_sign_ctx    sign_ctx;
+    struct t_cose_sign1_verify_ctx  verify_ctx;
+    QCBOREncodeContext              cbor_encode;
+    enum t_cose_err_t               return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(     signed_cose_buffer, 200);
+    struct q_useful_buf_c           signed_cose;
+    struct q_useful_buf_c           payload;
+    Q_USEFUL_BUF_MAKE_STACK_UB(     expected_payload_buffer, 10);
+    struct q_useful_buf_c           expected_payload;
+    QCBORError                      cbor_error;
+
+    /* --- Start making COSE Sign1 object  --- */
+
+    /* The CBOR encoder instance that the COSE_Sign1 is output into */
+    QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
+
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    /* Do the first part of the the COSE_Sign1, the parameters */
+    return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 1000 + return_value;
+    }
+
+
+    QCBOREncode_AddSZString(&cbor_encode, "payload");
+
+    /* Finish up the COSE_Sign1. This is where the signing happens */
+    return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+
+    /* Finally close of the CBOR formatting and get the pointer and length
+     * of the resulting COSE_Sign1
+     */
+    cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose);
+    if(cbor_error) {
+        return 3000 + cbor_error;
+    }
+    /* --- Done making COSE Sign1 object  --- */
+
+    /* -- Tweak signature bytes -- */
+    /* The signature is the last thing so reach back that many bytes and tweak
+       so if signature verification were attempted, it would fail */
+    const size_t last_byte_offset = signed_cose.len - T_COSE_EC_P256_SIG_SIZE;
+    ((uint8_t *)signed_cose.ptr)[last_byte_offset] += 1;
+
+
+    /* --- Start verifying the COSE Sign1 object  --- */
+    t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY);
+
+    /* No key necessary with short circuit */
+
+    /* Run the signature verification */
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                       /* COSE to verify */
+                                       signed_cose,
+                                       /* The returned payload */
+                                       &payload,
+                                       /* Don't return parameters */
+                                       NULL);
+
+
+    if(return_value) {
+        return 4000 + return_value;
+    }
+
+    /* Format the expected payload CBOR fragment */
+    QCBOREncode_Init(&cbor_encode, expected_payload_buffer);
+    QCBOREncode_AddSZString(&cbor_encode, "payload");
+    QCBOREncode_Finish(&cbor_encode, &expected_payload);
+
+    /* compare payload output to the one expected */
+    if(q_useful_buf_compare(payload, expected_payload)) {
+        return 5000;
+    }
+    /* --- Done verifying the COSE Sign1 object  --- */
+
+    return 0;
+}
+
+
+/*
+ 18( [
+    / protected / h’a10126’ / {
+        \ alg \ 1:-7 \ ECDSA 256 \
+    }/ ,
+    / unprotected / {
+      / kid / 4:’11’
+    },
+    / payload / ’This is the content.’,
+
+       / signature / h’8eb33e4ca31d1c465ab05aac34cc6b23d58fef5c083106c4
+   d25a91aef0b0117e2af9a291aa32e14ab834dc56ed2a223444547e01f11d3b0916e5
+   a4c345cacb36’
+] )
+
+ */
+
+/* This comes from Appendix_C_2_1.json from COSE_C by Jim Schaad */
+static const uint8_t rfc8152_example_2_1[] = {
+    0xD2, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04,
+    0x42, 0x31, 0x31, 0x54, 0x54, 0x68, 0x69, 0x73,
+    0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+    0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2E, /* end of hdrs and payload*/
+    0x58, 0x40, 0x8E, 0xB3, 0x3E, 0x4C, 0xA3, 0x1D, /* Sig starts with 0x58 */
+    0x1C, 0x46, 0x5A, 0xB0, 0x5A, 0xAC, 0x34, 0xCC,
+    0x6B, 0x23, 0xD5, 0x8F, 0xEF, 0x5C, 0x08, 0x31,
+    0x06, 0xC4, 0xD2, 0x5A, 0x91, 0xAE, 0xF0, 0xB0,
+    0x11, 0x7E, 0x2A, 0xF9, 0xA2, 0x91, 0xAA, 0x32,
+    0xE1, 0x4A, 0xB8, 0x34, 0xDC, 0x56, 0xED, 0x2A,
+    0x22, 0x34, 0x44, 0x54, 0x7E, 0x01, 0xF1, 0x1D,
+    0x3B, 0x09, 0x16, 0xE5, 0xA4, 0xC3, 0x45, 0xCA,
+    0xCB, 0x36};
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int cose_example_test()
+{
+    enum t_cose_err_t             return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(   signed_cose_buffer, 200);
+    struct q_useful_buf_c         output;
+    struct t_cose_sign1_sign_ctx  sign_ctx;
+    struct q_useful_buf_c         head_actual;
+    struct q_useful_buf_c         head_exp;
+
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    t_cose_sign1_set_signing_key(&sign_ctx,
+                                 T_COSE_NULL_KEY,
+                                 Q_USEFUL_BUF_FROM_SZ_LITERAL("11"));
+
+    /* Make example C.2.1 from RFC 8152 */
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                      Q_USEFUL_BUF_FROM_SZ_LITERAL("This is the content."),
+                                      signed_cose_buffer,
+                                     &output);
+
+    if(return_value != T_COSE_SUCCESS) {
+        return return_value;
+    }
+
+    /* Compare only the headers and payload as this was not signed
+     * with the same key as the example. The first 32 bytes contain
+     * the header parameters and payload. */
+    head_actual = q_useful_buf_head(output, 32);
+    head_exp = q_useful_buf_head(Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(rfc8152_example_2_1), 32);
+
+    if(q_useful_buf_compare(head_actual, head_exp)) {
+        return -1000;
+    }
+
+    return return_value;
+}
+
+
+static enum t_cose_err_t run_test_sign_and_verify(int32_t test_mess_options)
+{
+    struct t_cose_sign1_sign_ctx    sign_ctx;
+    struct t_cose_sign1_verify_ctx  verify_ctx;
+    QCBOREncodeContext              cbor_encode;
+    enum t_cose_err_t               return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(     signed_cose_buffer, 200);
+    struct q_useful_buf_c           signed_cose;
+    struct q_useful_buf_c           payload;
+
+    /* --- Start making COSE Sign1 object  --- */
+
+    /* The CBOR encoder instance that the COSE_Sign1 is output into */
+    QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
+
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    return_value =
+        t_cose_test_message_sign1_sign(&sign_ctx,
+                                       test_mess_options,
+                                       Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                       signed_cose_buffer,
+                                       &signed_cose);
+    if(return_value) {
+        return 2000 + return_value;
+    }
+    /* --- Done making COSE Sign1 object  --- */
+
+
+    /* --- Start verifying the COSE Sign1 object  --- */
+    t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
+
+    /* No key necessary with short circuit */
+
+
+    /* Run the signature verification */
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                       /* COSE to verify */
+                                       signed_cose,
+                                       /* The returned payload */
+                                       &payload,
+                                       /* Don't return parameters */
+                                       NULL);
+
+    return return_value;
+}
+
+
+/* copied from t_cose_util.c */
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+/* This is a random hard coded key ID that is used to indicate
+ * short-circuit signing. It is OK to hard code this as the
+ * probability of collision with this ID is very low and the same
+ * as for collision between any two key IDs of any sort.
+ */
+
+static const uint8_t defined_short_circuit_kid[] = {
+    0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70,
+    0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a,
+    0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6,
+    0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6};
+
+static struct q_useful_buf_c ss_kid;
+
+
+/*
+ * Public function. See t_cose_util.h
+ */
+static struct q_useful_buf_c get_short_circuit_kid(void)
+{
+    ss_kid.len = sizeof(defined_short_circuit_kid);
+    ss_kid.ptr = defined_short_circuit_kid;
+
+    return ss_kid;
+}
+#endif
+
+int_fast32_t all_header_parameters_test()
+{
+    enum t_cose_err_t               return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(     signed_cose_buffer, 300);
+    struct q_useful_buf_c           output;
+    struct q_useful_buf_c           payload;
+    struct t_cose_parameters        parameters;
+    struct t_cose_sign1_sign_ctx    sign_ctx;
+    struct t_cose_sign1_verify_ctx  verify_ctx;
+
+
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    t_cose_sign1_set_signing_key(&sign_ctx,
+                                 T_COSE_NULL_KEY,
+                                 Q_USEFUL_BUF_FROM_SZ_LITERAL("11"));
+
+    return_value =
+        t_cose_test_message_sign1_sign(&sign_ctx,
+                                       T_COSE_TEST_ALL_PARAMETERS,
+                                       Q_USEFUL_BUF_FROM_SZ_LITERAL("This is the content."),
+                                       signed_cose_buffer,
+                                      &output);
+    if(return_value) {
+        return 1;
+    }
+
+    t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
+
+    /* No key necessary with short circuit */
+
+
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                       /* COSE to verify */
+                                       output,
+                                       /* The returned payload */
+                                       &payload,
+                                       /* Get parameters for checking */
+                                       &parameters);
+
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+    // Need to compare to short circuit kid
+    if(q_useful_buf_compare(parameters.kid, get_short_circuit_kid())) {
+        return 2;
+    }
+#endif
+
+    if(parameters.cose_algorithm_id != T_COSE_ALGORITHM_ES256) {
+        return 3;
+    }
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+    if(parameters.content_type_uint != 1) {
+        return 4;
+    }
+#endif
+
+    if(q_useful_buf_compare(parameters.iv, Q_USEFUL_BUF_FROM_SZ_LITERAL("iv"))) {
+        return 5;
+    }
+
+    if(q_useful_buf_compare(parameters.partial_iv, Q_USEFUL_BUF_FROM_SZ_LITERAL("partial_iv"))) {
+        return 6;
+    }
+
+    return 0;
+}
+
+struct test_case {
+    int32_t test_option;
+    int   result;
+};
+
+static struct test_case bad_parameters_tests_table[] = {
+    /* Test existance of the critical header. Also makes sure that
+     * it works with the max number of labels allowed in it.
+     */
+    {T_COSE_TEST_EMPTY_PROTECTED_PARAMETERS, T_COSE_ERR_UNSUPPORTED_HASH},
+
+    {T_COSE_TEST_DUP_CONTENT_ID, T_COSE_ERR_DUPLICATE_PARAMETER},
+
+    {T_COSE_TEST_UNCLOSED_PROTECTED, T_COSE_ERR_CBOR_NOT_WELL_FORMED},
+
+    {T_COSE_TEST_TOO_LARGE_CONTENT_TYPE, T_COSE_ERR_BAD_CONTENT_TYPE},
+
+    /* This makes consume_item() error out */
+    {T_COSE_TEST_NOT_WELL_FORMED_2, T_COSE_ERR_CBOR_NOT_WELL_FORMED},
+
+    {T_COSE_TEST_KID_IN_PROTECTED, T_COSE_ERR_DUPLICATE_PARAMETER},
+
+    {T_COSE_TEST_TOO_MANY_UNKNOWN, T_COSE_ERR_TOO_MANY_PARAMETERS},
+
+    {T_COSE_TEST_UNPROTECTED_NOT_MAP, T_COSE_ERR_PARAMETER_CBOR},
+
+    {T_COSE_TEST_BAD_CRIT_PARAMETER, T_COSE_ERR_PARAMETER_NOT_PROTECTED},
+
+    {T_COSE_TEST_BAD_CRIT_PARAMETER, T_COSE_ERR_PARAMETER_NOT_PROTECTED},
+
+    {T_COSE_TEST_NOT_WELL_FORMED_1, T_COSE_ERR_CBOR_NOT_WELL_FORMED},
+
+    {T_COSE_TEST_NO_UNPROTECTED_PARAMETERS, T_COSE_ERR_PARAMETER_CBOR},
+
+    {T_COSE_TEST_NO_PROTECTED_PARAMETERS, T_COSE_ERR_SIGN1_FORMAT},
+
+    {T_COSE_TEST_EXTRA_PARAMETER, T_COSE_SUCCESS},
+
+    {T_COSE_TEST_PARAMETER_LABEL, T_COSE_ERR_PARAMETER_CBOR},
+
+    {T_COSE_TEST_BAD_PROTECTED, T_COSE_ERR_PARAMETER_CBOR},
+
+    {0, 0}
+};
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t bad_parameters_test()
+{
+    struct test_case *test;
+
+    for(test = bad_parameters_tests_table; test->test_option; test++) {
+        if(run_test_sign_and_verify(test->test_option) != test->result) {
+            return (int)(test - bad_parameters_tests_table);
+        }
+    }
+
+    return 0;
+}
+
+
+
+
+static struct test_case crit_tests_table[] = {
+    /* Test existance of the critical header. Also makes sure that
+     * it works with the max number of labels allowed in it.
+     */
+    {T_COSE_TEST_CRIT_PARAMETER_EXIST, T_COSE_SUCCESS},
+
+    /* Exceed the max number of labels by one and get an error */
+    {T_COSE_TEST_TOO_MANY_CRIT_PARAMETER_EXIST, T_COSE_ERR_CRIT_PARAMETER},
+
+    /* A critical parameter exists in the protected section, but the
+     * format of the internals of this parameter is not the expected CBOR
+     */
+    {T_COSE_TEST_BAD_CRIT_LABEL, T_COSE_ERR_CRIT_PARAMETER},
+
+    /* A critical label is listed in the protected section, but
+     * the label doesn't exist. This works for integer-labeled header params.
+     */
+    {T_COSE_TEST_UNKNOWN_CRIT_UINT_PARAMETER, T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER},
+
+    /* A critical label is listed in the protected section, but
+     * the label doesn't exist. This works for string-labeled header params.
+     */
+    {T_COSE_TEST_UNKNOWN_CRIT_TSTR_PARAMETER, T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER},
+
+    /* The critical labels list is not protected */
+    {T_COSE_TEST_CRIT_NOT_PROTECTED, T_COSE_ERR_PARAMETER_NOT_PROTECTED},
+
+    {T_COSE_TEST_EMPTY_CRIT_PARAMETER, T_COSE_ERR_CRIT_PARAMETER},
+
+    {T_COSE_TEST_TOO_MANY_TSTR_CRIT_LABLELS, T_COSE_ERR_CRIT_PARAMETER},
+
+    {0, 0}
+};
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t crit_parameters_test()
+{
+    struct test_case *test;
+
+    for(test = crit_tests_table; test->test_option; test++) {
+        if(run_test_sign_and_verify(test->test_option) != test->result) {
+            return (int)(test - crit_tests_table);
+        }
+    }
+
+    return 0;
+}
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t content_type_test()
+{
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+
+    struct t_cose_parameters        parameters;
+    struct t_cose_sign1_sign_ctx    sign_ctx;
+    Q_USEFUL_BUF_MAKE_STACK_UB(     signed_cose_buffer, 200);
+    struct q_useful_buf_c           output;
+    struct q_useful_buf_c           payload;
+    enum t_cose_err_t               return_value;
+    struct t_cose_sign1_verify_ctx  verify_ctx;
+
+
+    /* -- integer content type -- */
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    t_cose_sign1_set_content_type_uint(&sign_ctx, 42);
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                      Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                      signed_cose_buffer,
+                                     &output);
+    if(return_value) {
+        return 1;
+    }
+
+    t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
+
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                        output,
+                                       &payload,
+                                       &parameters);
+    if(return_value) {
+        return 2;
+    }
+
+    if(parameters.content_type_uint != 42) {
+        return 5;
+    }
+
+
+    /* -- string content type -- */
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    t_cose_sign1_set_content_type_tstr(&sign_ctx, "text/plain");
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                     signed_cose_buffer,
+                                     &output);
+    if(return_value) {
+        return 1;
+    }
+
+    t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
+
+    return_value = t_cose_sign1_verify(&verify_ctx,
+                                       output,
+                                       &payload,
+                                       &parameters);
+    if(return_value) {
+        return 2;
+    }
+
+    if(q_useful_buf_compare(parameters.content_type_tstr, Q_USEFUL_BUF_FROM_SZ_LITERAL("text/plain"))) {
+        return 6;
+    }
+
+
+    /* -- content type in error -- */
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    t_cose_sign1_set_content_type_tstr(&sign_ctx, "text/plain");
+    t_cose_sign1_set_content_type_uint(&sign_ctx, 42);
+
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                     signed_cose_buffer,
+                                     &output);
+    if(return_value != T_COSE_ERR_DUPLICATE_PARAMETER) {
+        return 1;
+    }
+#endif
+    return 0;
+
+}
+
+
+struct sign1_sample {
+    struct q_useful_buf_c CBOR;
+    enum t_cose_err_t     expected_error;
+};
+
+static struct sign1_sample sign1_sample_inputs[] = {
+    /* With an indefinite length string payload */
+    { {(uint8_t[]){0x84, 0x40, 0xa0, 0x5f, 0x00, 0xff, 0x40}, 7}, T_COSE_ERR_SIGN1_FORMAT},
+    /* Too few items in unprotected header parameters bucket */
+    { {(uint8_t[]){0x84, 0x40, 0xa3, 0x40, 0x40}, 5}, T_COSE_ERR_PARAMETER_CBOR},
+    /* Too few items in definite array */
+    { {(uint8_t[]){0x83, 0x40, 0xa0, 0x40}, 4}, T_COSE_ERR_SIGN1_FORMAT},
+    /* Too-long signature */
+    { {(uint8_t[]){0x84, 0x40, 0xa0, 0x40, 0x4f}, 5}, T_COSE_ERR_SIGN1_FORMAT},
+    /* Too-long payload */
+    { {(uint8_t[]){0x84, 0x40, 0xa0, 0x4f, 0x40}, 5}, T_COSE_ERR_SIGN1_FORMAT},
+    /* Too-long protected parameters bucket */
+    { {(uint8_t[]){0x84, 0x4f, 0xa0, 0x40, 0x40}, 5}, T_COSE_ERR_SIGN1_FORMAT},
+    /* Unterminated indefinite length */
+    { {(uint8_t[]){0x9f, 0x40, 0xbf, 0xff, 0x40, 0x40}, 6}, T_COSE_ERR_CBOR_NOT_WELL_FORMED},
+    /* The smallest legal COSE_Sign1 using indefinite lengths */
+    { {(uint8_t[]){0x9f, 0x40, 0xbf, 0xff, 0x40, 0x40, 0xff}, 7}, T_COSE_SUCCESS},
+    /* The smallest legal COSE_Sign1 using definite lengths */
+    { {(uint8_t[]){0x84, 0x40, 0xa0, 0x40, 0x40}, 5}, T_COSE_SUCCESS},
+    /* Just one not-well-formed byte -- a reserved value */
+    { {(uint8_t[]){0x3c}, 1}, T_COSE_ERR_SIGN1_FORMAT },
+    /* terminate the list */
+    { {NULL, 0}, 0 },
+};
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t sign1_structure_decode_test(void)
+{
+    const struct sign1_sample      *sample;
+    struct q_useful_buf_c           payload;
+    enum t_cose_err_t               result;
+    struct t_cose_sign1_verify_ctx  verify_ctx;
+
+
+    for(sample = sign1_sample_inputs; !q_useful_buf_c_is_null(sample->CBOR); sample++) {
+        t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY);
+
+
+        result = t_cose_sign1_verify(&verify_ctx,
+                                      sample->CBOR,
+                                     &payload,
+                                      NULL);
+        if(result != sample->expected_error) {
+            /* Returns 100 * index of the input + error code not expected */
+            return (int32_t)(sample - sign1_sample_inputs+1)*100 + result;
+        }
+    }
+
+    return 0;
+}
+
+
+#ifdef T_COSE_ENABLE_HASH_FAIL_TEST
+
+/* Linkage to global variable in t_cose_test_crypto.c. This is only
+ * used for an occasional test in a non-threaded environment so a global
+ * variable is safe. This test and the hacks in the crypto code are
+ * never enabled for commercial deployments.
+ */
+extern int hash_test_mode;
+
+
+/*
+ * Public function, see t_cose_test.h
+ */
+int_fast32_t short_circuit_hash_fail_test()
+{
+    struct t_cose_sign1_sign_ctx sign_ctx;
+    enum t_cose_err_t            return_value;
+    struct q_useful_buf_c        wrapped_payload;
+    Q_USEFUL_BUF_MAKE_STACK_UB(  signed_cose_buffer, 200);
+
+    /* See test description in t_cose_test.h for a full description of
+     * what this does and what it needs to run.
+     */
+
+
+    /* Set the global variable to cause the hash implementation to
+     * error out so this test can see what happens
+     */
+    hash_test_mode = 1;
+
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                     signed_cose_buffer,
+                                     &wrapped_payload);
+
+    hash_test_mode = 0;
+
+    if(return_value != T_COSE_ERR_HASH_GENERAL_FAIL) {
+        return 2000 + return_value;
+    }
+
+
+    /* Set the global variable to cause the hash implementation to
+     * error out so this test can see what happens
+     */
+    hash_test_mode = 2;
+
+    t_cose_sign1_sign_init(&sign_ctx,
+                           T_COSE_OPT_SHORT_CIRCUIT_SIG,
+                           T_COSE_ALGORITHM_ES256);
+
+    return_value = t_cose_sign1_sign(&sign_ctx,
+                                     Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
+                                     signed_cose_buffer,
+                                     &wrapped_payload);
+
+    hash_test_mode = 0;
+
+    if(return_value != T_COSE_ERR_HASH_GENERAL_FAIL) {
+        return 2000 + return_value;
+    }
+
+    return 0;
+}
+
+#endif /* T_COSE_ENABLE_HASH_FAIL_TEST */
diff --git a/lib/ext/t_cose/test/t_cose_test.h b/lib/ext/t_cose/test/t_cose_test.h
new file mode 100644
index 0000000..4802b5d
--- /dev/null
+++ b/lib/ext/t_cose/test/t_cose_test.h
@@ -0,0 +1,126 @@
+/*
+ *  t_cose_test.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#ifndef t_cose_test_h
+#define t_cose_test_h
+
+#include <stdint.h>
+
+/**
+ * \file t_cose_test.h
+ *
+ * \brief Entry points for the basic t_cose_tests.
+ *
+ * These tests can be performed without any crypto library such as OpenSSL
+ * integrated with t_cose.
+ */
+
+
+/**
+ * \brief Minimal message creation test using a short-circuit signature.
+ *
+ * \return non-zero on failure.
+ *
+ * This test makes a simple COSE_Sign1 and verify it.  It uses
+ * short-circuit signatures so no keys or even integration with public
+ * key crypto is necessary.
+ */
+int_fast32_t short_circuit_self_test(void);
+
+
+/**
+ * \brief Test where payload bytes are corrupted and sig fails.
+ *
+ * \return non-zero on failure.
+ *
+ * This test makes a simple COSE_Sign1 modify the payload and see that
+ * verification fails.  It uses short-circuit signatures so no keys or
+ * even integration with public key crypto is necessary.
+ */
+int_fast32_t short_circuit_verify_fail_test(void);
+
+
+/**
+ * \brief Tests error condidtions for creating COSE_Sign1.
+ *
+ * \return non-zero on failure.
+ *
+ * It uses short-circuit signatures so no keys or even integration
+ * with public key crypto is necessary.
+ */
+int_fast32_t short_circuit_signing_error_conditions_test(void);
+
+
+/* Make a CWT and see that it compares to the sample in the CWT RFC
+ */
+int_fast32_t short_circuit_make_cwt_test(void);
+
+
+/*
+ * Test the decode only mode.
+ */
+int_fast32_t short_circuit_decode_only_test(void);
+
+
+/*
+- protected header parameters not well formed CBOR
+- unprotected header parameters not well formed CBOR
+- unknown algorithm ID
+- No algorithm ID parameter
+
+ */
+int_fast32_t bad_parameters_test(void);
+
+
+/* Test that makes a CWT (CBOR Web Token)
+ */
+int_fast32_t cose_example_test(void);
+
+
+/*
+ Various tests involving the crit parameter.
+ */
+int_fast32_t crit_parameters_test(void);
+
+
+/*
+ Check that all types of headers are correctly returned.
+ */
+int_fast32_t all_header_parameters_test(void);
+
+/*
+ * Check that setting the content type works
+ */
+int_fast32_t content_type_test(void);
+
+
+/*
+ * Check that setting the content type works
+ */
+int_fast32_t sign1_structure_decode_test(void);
+
+
+#ifdef T_COSE_ENABLE_HASH_FAIL_TEST
+/*
+ * This forces / simulates failures in the hash algorithm implementation
+ * to test t_cose's handling of those condidtions. This test is off
+ * by default because it needs a hacked version of a hash algorithm.
+ * It is very hard to get hash algorithms to fail, so this hacked
+ * version is necessary. This test will not run correctly with
+ * OpenSSL or PSA hashes because they aren't (and shouldn't be) hacked.
+ * It works only with the b_con hash bundled and not intended for
+ * commercial use (though it is a perfectly fine implementation).
+ */
+int_fast32_t short_circuit_hash_fail_test(void);
+
+#endif /* T_COSE_ENABLE_HASH_FAIL_TEST*/
+
+
+#endif /* t_cose_test_h */