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/LICENSE b/lib/ext/t_cose/LICENSE
new file mode 100644
index 0000000..8b79741
--- /dev/null
+++ b/lib/ext/t_cose/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2019, Laurence Lundblade
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/lib/ext/t_cose/Makefile.psa_off_target b/lib/ext/t_cose/Makefile.psa_off_target
new file mode 100644
index 0000000..2e674c2
--- /dev/null
+++ b/lib/ext/t_cose/Makefile.psa_off_target
@@ -0,0 +1,74 @@
+# Makefile -- UNIX-style make for t_cose simulating PSA crypto 
+#
+# Copyright (c) 2019, Laurence Lundblade. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# See BSD-3-Clause license in README.md
+#
+
+# ---- comment ----
+# This is for PSA Crypto. Adjust CRYPTO_INC and CRYPTO_LIB for the location of
+# the PSA libraries on your build machine.
+
+
+# ---- QCBOR location ----
+# Adjust this to the location of QCBOR in your build environment
+QCBOR_INC= -I ../../QCBOR/master/inc
+QCBOR_LIB=../../QCBOR/master/libqcbor.a
+
+
+# ---- crypto configuration -----
+# Set up for PSA + OpenSSL. This may have to be adjusted for your build environment.
+CRYPTO_INC= -I ../../TF-M/trusted-firmware-m/interface/include/ 
+CRYPTO_OBJ=crypto_adapters/t_cose_psa_crypto.o 
+CRYPTO_LIB=
+
+
+# ---- compiler configuration -----
+C_OPTS=-Os -Wall -pedantic-errors -Wextra -Wshadow -Wparentheses -xc -std=c99
+
+
+# ---- T_COSE Config and test options ----
+CONFIG_OPTS=
+CRYPTO_TEST_OBJ=test/t_cose_make_psa_test_key.o
+TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_sign_verify_test.o test/t_cose_make_test_messages.o $(CRYPTO_TEST_OBJ)
+
+
+# ---- the main body that is invariant ----
+INC=-I inc -I Test  -I src
+ALL_INC=$(CRYPTO_INC) $(QCBOR_INC) $(INC) 
+CFLAGS=$(ALL_INC) $(C_OPTS) $(CONFIG_OPTS)
+
+SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o
+
+all: t_cose_test libt_cose.a
+
+
+libt_cose.a: $(SRC_OBJ) $(CRYPTO_OBJ)
+	ar -r $@ $^
+
+
+t_cose_test: main.o $(SRC_OBJ) $(CRYPTO_OBJ) $(TEST_OBJ)
+	cc -o $@ $^ $(QCBOR_LIB) $(CRYPTO_LIB)
+
+
+clean:
+	rm -f $(SRC_OBJ) $(TEST_OBJ) $(CRYPTO_OBJ) t_cose_test libt_cose.a main.o
+
+
+# ---- source dependecies -----
+src/t_cose_util.o:	src/t_cose_util.h src/t_cose_standard_constants.h inc/t_cose_common.h src/t_cose_crypto.h
+src/t_cose_sign1_verify.o:	inc/t_cose_sign1_verify.h src/t_cose_crypto.h src/t_cose_util.h src/t_cose_parameters.h inc/t_cose_common.h src/t_cose_standard_constants.h
+src/t_cose_parameters.o: src/t_cose_parameters.h src/t_cose_standard_constants.h inc/t_cose_sign1_verify.h inc/t_cose_common.h
+src/t_cose_sign1_sign.o: inc/t_cose_sign1_sign.h src/t_cose_standard_constants.h src/t_cose_crypto.h src/t_cose_util.h inc/t_cose_common.h 
+
+
+# ---- test dependencies -----
+test/t_cose_test.o: test/t_cose_test.h inc/t_cose_sign1_sign.h inc/t_cose_sign1_verify.h inc/t_cose_common.h test/t_cose_make_test_messages.h src/t_cose_crypto.h
+test/t_cose_make_test_messages.o: test/t_cose_make_test_messages.h inc/t_cose_sign1_sign.h inc/t_cose_common.h src/t_cose_standard_constants.h src/t_cose_crypto.h src/t_cose_util.h
+test/run_test.o: test/run_test.h test/t_cose_test.h test/t_cose_hash_fail_test.h
+test/t_cose_make_psa_test_key.o:	test/t_cose_make_test_pub_key.h  src/t_cose_standard_constants.h 
+
+# ---- crypto dependencies ----
+crypto_adapters/t_cose_psa_crypto.o:	src/t_cose_crypto.h inc/t_cose_common.h src/t_cose_standard_constants.h inc/q_useful_buf.h 
diff --git a/lib/ext/t_cose/README.md b/lib/ext/t_cose/README.md
new file mode 100644
index 0000000..57d9f71
--- /dev/null
+++ b/lib/ext/t_cose/README.md
@@ -0,0 +1,138 @@
+
+
+#  t_cose
+
+t_cose implements enough of COSE to support [CBOR Web Token, RFC 8392](https://tools.ietf.org/html/rfc8392)  
+and [Entity Attestation Token (EAT)](https://tools.ietf.org/html/draft-ietf-rats-eat-01). 
+This is the COSE_Sign1 part of [COSE, RFC 8152](https://tools.ietf.org/html/rfc8152). 
+
+## Characteristics
+
+**Implemented in C with minimal dependency** – There are three main 
+dependencies: 1) [QCBOR](https://github.com/laurencelundblade/QCBOR), 2) A 
+cryptographic library for ECDSA and SHA-2, 3)  C99, <stdint.h>, <stddef.h>,
+<stdbool.h> and <string.h>.  It is intended to be highly portable to different HW, OS's and 
+cryptographic libraries. No #ifdefs or compiler options  need to be set for it to run correctly.
+
+**Crypto Library Integration Layer** – t_cose can work with different cryptographic
+libraries via a simple integration layer. The integration layer is kept small and simple, 
+just enough for the use cases, so that integration is simpler. An integration layer for 
+Openssl is included (not complete yet).
+
+**Secure coding style** – Uses a construct called UsefulBuf / q_useful_buf as a
+discipline for very safe coding and handling of binary data.
+
+**Small simple memory model** – Malloc is not needed. The signing
+context is less than 100 bytes. Stack use is light and
+there is no recursion. The caller supplies the memory to hold the
+completed COSE_Sign1 and encode/decode contexts so caller has full control
+of memory usage making it good for embedded implementations that
+have to run in small fixed memory.
+
+## Code Status
+
+As of October 2019, the code is in reasonable working order and the public interface is 
+fairly stable. There is a crypto adaptaion layer for [OpenSSL](https://www.openssl.org).
+
+### The to-do list:
+* Add some more tests, particular test vectors from C_COSE or such
+* General documentation clean up, spelling checks and formatting.
+
+## Building and Dependencies
+
+There is a simple makefile.
+
+[QCBOR](https://github.com/laurencelundblade/QCBOR) is required
+
+### Crypto Library
+Some cryptographic library that supports ECDSA and at least SHA-256 is required.
+
+#### Test Crypto
+Out of the box, this compiles, links and runs with no additional crypto library, but only in
+a test mode. This allows for quickly geting started. This mode allows more than half the tests to run.
+It is however not good for real commercial use as it doesn't do real public key signing and
+verification.
+
+For this test mode a bundled SHA-256 hash implementation is used, the ECDSA signing
+is stubbed to do nothing and the test short-circuit signing is used.
+
+#### OpenSSL Crypto
+This OpenSSL integration supports SHA-256, SHA-384 and SHA-512 with ECDSA to support
+the COSE algorithms ES256, ES384 and ES512. 
+
+To enable this:
+* #define T_COSE_USE_OPENSSL_CRYPTO 
+* Make with crypto_adapters/t_cose_openssl_crypto.c
+* Define the include path to OpenSSL headers in your build environment
+* Link with the OpenSSL libary
+
+#### PSA Crypto
+
+
+
+## Memory Usage
+
+### Code 
+
+These are approximate numbers for 64-bit x86 code optimized for size
+
+* Common to signing and verifying:  515
+* Signing: 920 (742)
+* Verify: 1596
+* OpenSSL adaptor layer: 609
+* Total: 3710
+* Signing only total: 1813
+* Verify only total: 2509
+
+### Heap and stack
+Malloc is not used.
+
+Stack usage is less than 1KB for signing and for encryption.
+
+The design is such that only one copy of the COSE_Sign1 need be in memory. It makes
+use of special features in QCBOR to accomplish this.
+
+The payload to sign must be in one contiguous buffer and be passed in. It can be allocated
+however the caller wishes, even in ROM, since it is only read.
+
+A buffer to hold the signed COSE result must be passed in. It must be about 100 bytes 
+larger than the combined size of the payload and key id for ECDSA 256. It can be 
+allocated however the caller wishes.
+
+### Crypto library memory usage
+In addition to the above memory usage, the crypto library will use some stack and / or
+heap memory. This will vary quite a bit by crypto library. Some may use malloc. Some may
+not. 
+
+So far no support for RSA is available, but since the keys and signatures are much bigger,
+it will up the memory usage a lot and may require use of malloc. 
+
+The OpenSSL library does use malloc, even with ECDSA. Another implementation of ECDSA
+might not use malloc, as the keys are small enough.
+
+### Mixed code style
+QCBOR uses camelCase and t_cose follows 
+[Arm's coding guidelines](https://git.trustedfirmware.org/trusted-firmware-m.git/tree/docs/coding_guide.rst)
+resulting in code with mixed styles. For better or worse, an Arm-style version of UsefulBuf
+is created and used and so there is a duplicate of UsefulBuf. The two are identical. They
+just have different names.
+
+## Limitations
+* The payload input and output and the signed structure input and output must be in 
+contiguous memory.
+* Doesn't handle COSE string algorithm IDs. Only COSE integer algorithm IDs are handled. 
+Thus far no string algorithm IDs have been assigned by IANA.
+* No way to add custom headers when creating signed messages or process them during 
+verification.
+* Only ECDSA is supported so far (facilities are available to add others).
+* Does not handle CBOR indefinite length strings (indefinite length maps and arrays are handled).
+* Counter signatures are not supported.
+
+## Credit
+
+* Tamas Ban for lots code review comments, design ideas and porting to ARM PSA.
+* Rob Coombs, Shebu Varghese Kuriakose and other ARM folks for sponsorship.
+
+## Copyright and License
+
+t_cose is available under the 3-Clause BSD License.
diff --git a/lib/ext/t_cose/crypto_adapters/t_cose_psa_crypto.c b/lib/ext/t_cose/crypto_adapters/t_cose_psa_crypto.c
new file mode 100644
index 0000000..5fc8fba
--- /dev/null
+++ b/lib/ext/t_cose/crypto_adapters/t_cose_psa_crypto.c
@@ -0,0 +1,417 @@
+/*
+ * t_cose_psa_crypto.c
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.mdE.
+ */
+
+
+/**
+ * \file t_cose_psa_crypto.c
+ *
+ * \brief Crypto Adaptation for t_cose to use ARM's PSA ECDSA and hashes.
+ *
+ * This connects up the abstract interface in t_cose_crypto.h to the
+ * implementations of ECDSA signing and hashing in ARM's PSA crypto
+ * library.
+ *
+ * This adapter layer doesn't bloat the implementation as everything
+ * here had to be done anyway -- the mapping of algorithm IDs, the
+ * data format rearranging, the error code translation.
+ *
+ * This code should just work out of the box if compiled and linked
+ * against ARM's PSA crypto. No preprocessor #defines are needed.
+ *
+ * You can disable SHA-384 and SHA-512 to save code and space by
+ * defining T_COSE_DISABLE_ES384 or T_COSE_DISABLE_ES512. This saving
+ * is most in stack space in the main t_cose implementation. (It seems
+ * likely that changes to PSA itself would be needed to remove the
+ * SHA-384 and SHA-512 implementations to save that code. Lack of
+ * reference and dead stripping the executable won't do it).
+ */
+
+
+#include "t_cose_crypto.h"  /* The interface this implements */
+#include "psa/crypto.h"         /* PSA / TF_M crypto */
+
+
+/* Avoid compiler warning due to unused argument */
+#define ARG_UNUSED(arg) (void)(arg)
+
+
+/**
+ * \brief Map a COSE signing algorithm ID to a PSA signing algorithm ID
+ *
+ * \param[in] cose_alg_id  The COSE algorithm ID.
+ *
+ * \return The PSA algorithm ID or 0 if this doesn't map the COSE ID.
+ */
+static psa_algorithm_t cose_alg_id_to_psa_alg_id(int32_t cose_alg_id)
+{
+    /* The #ifdefs save a little code when algorithms are disabled */
+
+    return cose_alg_id == COSE_ALGORITHM_ES256 ? PSA_ALG_ECDSA(PSA_ALG_SHA_256) :
+#ifndef T_COSE_DISABLE_ES384
+           cose_alg_id == COSE_ALGORITHM_ES384 ? PSA_ALG_ECDSA(PSA_ALG_SHA_384) :
+#endif
+#ifndef T_COSE_DISABLE_ES512
+           cose_alg_id == COSE_ALGORITHM_ES512 ? PSA_ALG_ECDSA(PSA_ALG_SHA_512) :
+#endif
+                                                 0;
+    /* psa/crypto_values.h doesn't seem to define a "no alg" value,
+     * but zero seems OK for that use in the ECDSA context. */
+}
+
+
+/**
+ * \brief Map a PSA error into a t_cose error for signing.
+ *
+ * \param[in] err   The PSA status.
+ *
+ * \return The \ref t_cose_err_t.
+ */
+static enum t_cose_err_t psa_status_to_t_cose_error_signing(psa_status_t err)
+{
+    /* Intentionally keeping to fewer mapped errors to save object code */
+    return err == PSA_SUCCESS                   ? T_COSE_SUCCESS :
+           err == PSA_ERROR_INVALID_SIGNATURE   ? T_COSE_ERR_SIG_VERIFY :
+           err == PSA_ERROR_NOT_SUPPORTED       ? T_COSE_ERR_UNSUPPORTED_SIGNING_ALG:
+           err == PSA_ERROR_INSUFFICIENT_MEMORY ? T_COSE_ERR_INSUFFICIENT_MEMORY :
+           err == PSA_ERROR_TAMPERING_DETECTED  ? T_COSE_ERR_TAMPERING_DETECTED :
+                                                  T_COSE_ERR_FAIL;
+}
+
+
+/*
+ * See documentation in t_cose_crypto.h
+ */
+enum t_cose_err_t
+t_cose_crypto_pub_key_verify(int32_t               cose_algorithm_id,
+                             struct t_cose_key     verification_key,
+                             struct q_useful_buf_c kid,
+                             struct q_useful_buf_c hash_to_verify,
+                             struct q_useful_buf_c signature)
+{
+    psa_algorithm_t   psa_alg_id;
+    psa_status_t      psa_result;
+    enum t_cose_err_t return_value;
+    psa_key_handle_t  verification_key_psa;
+
+    /* This implementation does no look up keys by kid in the key
+     * store */
+    ARG_UNUSED(kid);
+
+    /* Convert to PSA algorithm ID scheme */
+    psa_alg_id = cose_alg_id_to_psa_alg_id(cose_algorithm_id);
+
+    /* This implementation supports ECDSA and only ECDSA. The
+     * interface allows it to support other, but none are implemented.
+     * This implementation works for different keys lengths and
+     * curves. That is the curve and key length as associated with the
+     * signing_key passed in, not the cose_algorithm_id This check
+     * looks for ECDSA signing as indicated by COSE and rejects what
+     * is not. (Perhaps this check can be removed to save object code
+     * if it is the case that psa_asymmetric_verify() does the right
+     * checks).
+     */
+    if(!PSA_ALG_IS_ECDSA(psa_alg_id)) {
+        return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
+        goto Done;
+    }
+
+    verification_key_psa = (psa_key_handle_t)verification_key.k.key_handle;
+
+    psa_result = psa_asymmetric_verify(verification_key_psa,
+                                       psa_alg_id,
+                                       hash_to_verify.ptr,
+                                       hash_to_verify.len,
+                                       signature.ptr,
+                                       signature.len);
+
+    return_value = psa_status_to_t_cose_error_signing(psa_result);
+
+  Done:
+    return return_value;
+}
+
+
+/*
+ * See documentation in t_cose_crypto.h
+ */
+enum t_cose_err_t
+t_cose_crypto_pub_key_sign(int32_t                cose_algorithm_id,
+                           struct t_cose_key      signing_key,
+                           struct q_useful_buf_c  hash_to_sign,
+                           struct q_useful_buf    signature_buffer,
+                           struct q_useful_buf_c *signature)
+{
+    enum t_cose_err_t return_value;
+    psa_status_t      psa_result;
+    psa_algorithm_t   psa_alg_id;
+    psa_key_handle_t  signing_key_psa;
+    size_t            signature_len;
+
+    psa_alg_id = cose_alg_id_to_psa_alg_id(cose_algorithm_id);
+
+    /* This implementation supports ECDSA and only ECDSA. The
+     * interface allows it to support other, but none are implemented.
+     * This implementation works for different keys lengths and
+     * curves. That is the curve and key length as associated with the
+     * signing_key passed in, not the cose_algorithm_id This check
+     * looks for ECDSA signing as indicated by COSE and rejects what
+     * is not. (Perhaps this check can be removed to save object code
+     * if it is the case that psa_asymmetric_verify() does the right
+     * checks).
+     */
+    if(!PSA_ALG_IS_ECDSA(psa_alg_id)) {
+        return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
+        goto Done;
+    }
+
+    signing_key_psa = (psa_key_handle_t)signing_key.k.key_handle;
+
+    /* It is assumed that psa_asymmetric_sign() is checking
+     * signature_buffer length and won't write off the end of it.
+     */
+    psa_result = psa_asymmetric_sign(signing_key_psa,
+                                     psa_alg_id,
+                                     hash_to_sign.ptr,
+                                     hash_to_sign.len,
+                                     signature_buffer.ptr, /* Sig buf */
+                                     signature_buffer.len, /* Sig buf size */
+                                    &signature_len);       /* Sig length */
+
+    return_value = psa_status_to_t_cose_error_signing(psa_result);
+
+    if(return_value == T_COSE_SUCCESS) {
+        /* Success, fill in the return useful_buf */
+        signature->ptr = signature_buffer.ptr;
+        signature->len = signature_len;
+    }
+
+  Done:
+     return return_value;
+}
+
+
+/*
+ * See documentation in t_cose_crypto.h
+ */
+enum t_cose_err_t t_cose_crypto_sig_size(int32_t           cose_algorithm_id,
+                                         struct t_cose_key signing_key,
+                                         size_t           *sig_size)
+{
+    enum t_cose_err_t return_value;
+    psa_key_handle_t  signing_key_psa;
+    psa_key_type_t    key_type;
+    size_t            key_len_bits;
+    size_t            key_len_bytes;
+
+    /* If desperate to save code, this can return the constant
+     * T_COSE_MAX_SIG_SIZE instead of doing an exact calculation.  The
+     * buffer size calculation will return too large of a value and
+     * waste a little heap / stack, but everything will still work
+     * (except the tests that test for exact values will fail). This
+     * will save 100 bytes or so of obejct code.
+     */
+
+    if(!t_cose_algorithm_is_ecdsa(cose_algorithm_id)) {
+        return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
+        goto Done;
+    }
+
+    signing_key_psa = (psa_key_handle_t)signing_key.k.key_handle;
+
+    psa_status_t status = psa_get_key_information(signing_key_psa,
+                                                  &key_type,
+                                                  &key_len_bits);
+
+    (void)key_type; /* Avoid unused parameter error */
+
+    return_value = psa_status_to_t_cose_error_signing(status);
+    if(return_value == T_COSE_SUCCESS) {
+        /* Calculation of size per RFC 8152 section 8.1 -- round up to
+         * number of bytes. */
+        key_len_bytes = key_len_bits / 8;
+        if(key_len_bits % 8) {
+            key_len_bytes++;
+        }
+        /* Double because signature is made of up r and s values */
+        *sig_size = key_len_bytes * 2;
+    }
+
+    return_value = T_COSE_SUCCESS;
+Done:
+    return return_value;
+}
+
+
+
+
+/**
+ * \brief Convert COSE hash algorithm ID to a PSA hash algorithm ID
+ *
+ * \param[in] cose_hash_alg_id   The COSE-based ID for the
+ *
+ * \return PSA-based hash algorithm ID, or USHRT_MAX on error.
+ *
+ */
+static inline psa_algorithm_t
+cose_hash_alg_id_to_psa(int32_t cose_hash_alg_id)
+{
+    return cose_hash_alg_id == COSE_ALGORITHM_SHA_256 ? PSA_ALG_SHA_256 :
+#ifndef T_COSE_DISABLE_ES384
+           cose_hash_alg_id == COSE_ALGORITHM_SHA_384 ? PSA_ALG_SHA_384 :
+#endif
+#ifndef T_COSE_DISABLE_ES512
+           cose_hash_alg_id == COSE_ALGORITHM_SHA_512 ? PSA_ALG_SHA_512 :
+#endif
+                                                        UINT16_MAX;
+}
+
+
+/**
+ * \brief Map a PSA error into a t_cose error for hashes.
+ *
+ * \param[in] status   The PSA status.
+ *
+ * \return The \ref t_cose_err_t.
+ */
+static enum t_cose_err_t
+psa_status_to_t_cose_error_hash(psa_status_t status)
+{
+    /* Intentionally limited to just this minimum set of errors to
+     * save object code as hashes don't really fail much
+     */
+    return status == PSA_SUCCESS                ? T_COSE_SUCCESS :
+           status == PSA_ERROR_NOT_SUPPORTED    ? T_COSE_ERR_UNSUPPORTED_HASH :
+           status == PSA_ERROR_BUFFER_TOO_SMALL ? T_COSE_ERR_HASH_BUFFER_SIZE :
+                                                  T_COSE_ERR_HASH_GENERAL_FAIL;
+}
+
+
+/*
+ * See documentation in t_cose_crypto.h
+ */
+enum t_cose_err_t t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx,
+                                           int32_t cose_hash_alg_id)
+{
+    /* Here's how t_cose_crypto_hash is used with PSA hashes.
+     *
+     * If you look inside psa_hash.handle is just a uint32_t that is
+     * used as a handle. To avoid modifying t_cose_crypto.h in a
+     * PSA-specific way, this implementation just copies the PSA
+     * handle from the generic t_cose_crypto_hash on entry to a hash
+     * function, and back on exit.
+     *
+     * This could have been implemented by modifying t_cose_crypto.h
+     * so that psa_hash_operation_t is a member of t_cose_crypto_hash.
+     * It's nice to not have to modify t_cose_crypto.h.
+     *
+     * This would have been cleaner if psa_hash_operation_t didn't
+     * exist and the PSA crypto just used a plain pointer or integer
+     * handle.  If psa_hash_operation_t is changed to be different
+     * than just the single uint32_t, then this code has to change.
+     *
+     * The status member of t_cose_crypto_hash is used to hold a
+     * psa_status_t error code.
+     */
+    psa_hash_operation_t psa_hash;
+    psa_algorithm_t      psa_alg;
+
+    /* Map the algorithm ID */
+    psa_alg = cose_hash_alg_id_to_psa(cose_hash_alg_id);
+
+    /* initialize PSA hash context */
+    psa_hash = (psa_hash_operation_t){0};
+
+    /* Actually do the hash set up */
+    hash_ctx->status = psa_hash_setup(&psa_hash, psa_alg);
+
+    /* Copy the PSA handle back into the context */
+    hash_ctx->context.handle = psa_hash.handle;
+
+    /* Map errors and return */
+    return psa_status_to_t_cose_error_hash((psa_status_t)hash_ctx->status);
+}
+
+
+/*
+ * See documentation in t_cose_crypto.h
+ */
+void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx,
+                               struct q_useful_buf_c      data_to_hash)
+{
+    /* See t_cose_crypto_hash_start() for context handling details */
+    psa_hash_operation_t psa_hash;
+
+    /* Copy the PSA handle out of the generic context */
+    psa_hash.handle = (uint32_t)hash_ctx->context.handle;
+
+    if(hash_ctx->status != PSA_SUCCESS) {
+        /* In error state. Nothing to do. */
+        return;
+    }
+
+    if(data_to_hash.ptr == NULL) {
+        /* This allows for NULL buffers to be passed in all the way at
+         * the top of signer or message creator when all that is
+         * happening is the size of the result is being computed.
+         */
+        return;
+    }
+
+    /* Actually hash the data */
+    hash_ctx->status = psa_hash_update(&psa_hash,
+                                       data_to_hash.ptr,
+                                       data_to_hash.len);
+
+    /* Copy the PSA handle back into the context because a non const
+     * reference is passed to psa_hash_update(). If it was const, this
+     * line of code could be deleted.
+     */
+    hash_ctx->context.handle = psa_hash.handle;
+}
+
+
+/*
+ * See documentation in t_cose_crypto.h
+ */
+enum t_cose_err_t
+t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx,
+                          struct q_useful_buf        buffer_to_hold_result,
+                          struct q_useful_buf_c     *hash_result)
+{
+    /* See t_cose_crypto_hash_start() for context handling details */
+    psa_hash_operation_t psa_hash;
+    psa_status_t         status;
+
+    /* Copy the PSA handle out of the generic context */
+    psa_hash.handle = (uint32_t)hash_ctx->context.handle;
+    status = (psa_status_t)hash_ctx->status;
+
+    if(status != PSA_SUCCESS) {
+        /* Error state. Nothing to do */
+        goto Done;
+    }
+
+    /* Actually finish up the hash */
+    status = psa_hash_finish(&psa_hash,
+                              buffer_to_hold_result.ptr,
+                              buffer_to_hold_result.len,
+                            &(hash_result->len));
+
+    hash_result->ptr = buffer_to_hold_result.ptr;
+
+    /* Copy the PSA handle back into the context because a non const
+     * reference is passed to psa_hash_finish(). If it was const, this
+     * line of code could be deleted.
+     */
+    hash_ctx->context.handle = psa_hash.handle;
+
+Done:
+    return psa_status_to_t_cose_error_hash(status);
+}
diff --git a/lib/ext/t_cose/inc/q_useful_buf.h b/lib/ext/t_cose/inc/q_useful_buf.h
new file mode 100644
index 0000000..98ac62e
--- /dev/null
+++ b/lib/ext/t_cose/inc/q_useful_buf.h
@@ -0,0 +1,157 @@
+/*
+ * q_useful_buf.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+
+#ifndef __Q_USEFUL_BUF_H__
+#define __Q_USEFUL_BUF_H__
+
+#include "UsefulBuf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * \file q_useful_buf.h
+ *
+ * \brief This is a TF-M coding style version of UsefulBuf.
+ *        See UsefulBuf for documentation of these functions.
+ */
+
+
+#define NULL_Q_USEFUL_BUF_C  NULLUsefulBufC
+
+#define NULL_Q_USEFUL_BUF    NULLUsefulBuf
+
+
+static inline int q_useful_buf_c_is_null(struct q_useful_buf_c in)
+{
+    return UsefulBuf_IsNULLC(in);
+}
+
+
+static inline int q_useful_buf_is_null(struct q_useful_buf in)
+{
+    return UsefulBuf_IsNULL(in);
+}
+
+
+static inline int q_useful_buf_c_is_empty(struct q_useful_buf_c in)
+{
+    return UsefulBuf_IsEmptyC(in);
+}
+
+static inline int q_useful_buf_is_empty(struct q_useful_buf in)
+{
+    return UsefulBuf_IsEmpty(in);
+}
+
+
+static inline int q_useful_buf_is_null_or_empty(struct q_useful_buf in)
+{
+    return UsefulBuf_IsNULLOrEmpty(in);
+}
+
+
+static inline int q_useful_buf_c_is_null_or_empty(struct q_useful_buf_c in)
+{
+    return UsefulBuf_IsNULLOrEmptyC(in);
+}
+
+
+static inline struct q_useful_buf q_useful_buf_unconst(struct q_useful_buf_c in)
+{
+    return UsefulBuf_Unconst(in);
+}
+
+#define Q_USEFUL_BUF_FROM_SZ_LITERAL UsefulBuf_FROM_SZ_LITERAL
+
+#define Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL  UsefulBuf_FROM_BYTE_ARRAY_LITERAL
+
+#define Q_USEFUL_BUF_MAKE_STACK_UB UsefulBuf_MAKE_STACK_UB
+
+#define Q_USEFUL_BUF_FROM_BYTE_ARRAY UsefulBuf_FROM_BYTE_ARRAY
+
+
+static inline struct q_useful_buf_c q_useful_buf_from_sz(const char *string)
+{
+    return UsefulBuf_FromSZ(string);
+}
+
+static inline struct q_useful_buf_c
+useful_buf_copy_offset(struct q_useful_buf dest,
+                       size_t offset,
+                       struct q_useful_buf_c src)
+{
+    return UsefulBuf_CopyOffset(dest, offset, src);
+}
+
+
+
+static inline struct q_useful_buf_c q_useful_buf_copy(struct q_useful_buf dest,
+                                                     struct q_useful_buf_c src)
+{
+    return UsefulBuf_Copy(dest, src);
+}
+
+
+static inline struct q_useful_buf_c q_useful_buf_set(struct q_useful_buf dest,
+                                                     uint8_t value)
+{
+    return UsefulBuf_Set(dest, value);
+}
+
+
+static inline struct q_useful_buf_c q_useful_buf_copy_ptr(struct q_useful_buf d,
+                                                          const void *ptr,
+                                                          size_t len)
+{
+    return UsefulBuf_CopyPtr(d, ptr, len);
+}
+
+
+static inline struct q_useful_buf_c q_useful_buf_head(struct q_useful_buf_c buf,
+                                                      size_t amount)
+{
+    return UsefulBuf_Head(buf, amount);
+}
+
+static inline struct q_useful_buf_c q_useful_buf_tail(struct q_useful_buf_c buf,
+                                                      size_t amount)
+{
+    return UsefulBuf_Tail(buf, amount);
+}
+
+static inline int q_useful_buf_compare(const struct q_useful_buf_c buf1,
+                                       const struct q_useful_buf_c buf2)
+{
+    return UsefulBuf_Compare(buf1, buf2);
+}
+
+static inline size_t q_useful_buf_is_value(const struct q_useful_buf_c buf,
+                                           uint8_t uValue)
+{
+    return UsefulBuf_IsValue(buf, uValue);
+}
+
+static inline size_t
+q_useful_buf_find_bytes(const struct q_useful_buf_c bytes_to_search,
+                      const struct q_useful_buf_c bytes_to_find)
+{
+    return UsefulBuf_FindBytes(bytes_to_search, bytes_to_find);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __Q_USEFUL_BUF_H__ */
diff --git a/lib/ext/t_cose/inc/t_cose_common.h b/lib/ext/t_cose/inc/t_cose_common.h
new file mode 100644
index 0000000..17ca21a
--- /dev/null
+++ b/lib/ext/t_cose/inc/t_cose_common.h
@@ -0,0 +1,355 @@
+/*
+ * t_cose_common.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+
+#ifndef __T_COSE_COMMON_H__
+#define __T_COSE_COMMON_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file t_cose_common.h
+ *
+ * \brief This file contains definitions common to all public t_cose
+ * interfaces.
+ *
+ * t_cose_common.h contains the definitions common to all public
+ * t_cose interfaces, particularly the error codes, algorithm
+ * identification constants and the structure containing a key.
+ *
+ * **Compile Time Configuration Options**
+ *
+ * \c T_COSE_DISABLE_SHORT_CIRCUIT_SIGN -- This disables short-circuit
+ * signing test mode. This saves a small amount of object code
+ *
+ * \c T_COSE_DISABLE_ES512 -- Disables the COSE algorithm ES512
+ * algorithm. This saves a tiny amount of code and a few hundred bytes
+ * of stack. It saves more than \c T_COSE_DISABLE_ES384.
+ *
+ * \c T_COSE_DISABLE_ES384 -- Disables the COSE algorithm ES384
+ * algorithm. This saves a tiny amount of code and a few hundred bytes
+ * of stack. No stack will be saved if \c T_COSE_DISABLE_ES512 is not
+ * also defined.
+ *
+ * \c T_COSE_DISABLE_CONTENT_TYPE -- Disables the content type
+ * parameters for both signing and verifying.
+ */
+
+
+
+
+/**
+ * \def T_COSE_ALGORITHM_ES256
+ *
+ * \brief Indicates ECDSA with SHA-256.
+ *
+ * This value comes from the
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ *
+ * The COSE standard recommends a key using the secp256r1 curve with
+ * this algorithm. This curve is also known as prime256v1 and P-256.
+ */
+#define T_COSE_ALGORITHM_ES256 -7
+
+/**
+ * \def T_COSE_ALGORITHM_ES384
+ *
+ * \brief Indicates ECDSA with SHA-384.
+ *
+ * This value comes from the
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ *
+ * The COSE standard recommends a key using the secp384r1 curve with
+ * this algorithm. This curve is also known as P-384.
+ */
+#define T_COSE_ALGORITHM_ES384 -35
+
+/**
+ * \def T_COSE_ALGORITHM_ES512
+ *
+ * \brief Indicates ECDSA with SHA-512.
+ *
+ * This value comes from the
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ *
+ * The COSE standard recommends a key using the secp521r1 curve with
+ * this algorithm. This curve is also known as P-521.
+ */
+#define T_COSE_ALGORITHM_ES512 -36
+
+
+
+
+/**
+ * Indicates the cryptographic library the \ref t_cose_key is intended
+ * for. Usually only one cryptographic library is integrated so this
+ * serves as a cross-check.
+ */
+enum t_cose_crypto_lib_t {
+    /** can be used for integrations
+     * that don't have or don't want to have any cross-check.
+     */
+    T_COSE_CRYPTO_LIB_UNIDENTIFIED = 0,
+    /** \c key_ptr points to a malloced OpenSSL EC_KEY. The caller
+     * needs to free it after the operation is done. */
+    T_COSE_CRYPTO_LIB_OPENSSL = 1,
+     /** \c key_handle is a \c psa_key_handle_t in Arm's Platform Security
+      * Architecture */
+    T_COSE_CRYPTO_LIB_PSA = 2
+};
+
+
+/**
+ * This structure is used to indicate or pass a key through the t_cose
+ * implementation to the underlying, platform-specific cryptography
+ * libraries for signing and verifying signature. You must know the
+ * cryptographic library that is integrated with t_cose to know how to
+ * fill in this data structure.
+ *
+ * For example, in the OpenSSL integration, \ref key_ptr should point
+ * to an OpenSSL \c EC_KEY type.
+ */
+struct t_cose_key {
+    /** Identifies the crypto library this key was created for.  The
+     * crypto library knows if it uses the handle or the pointer so
+     * this indirectly selects the union member. */
+    enum t_cose_crypto_lib_t crypto_lib;
+    union {
+        /** For libraries that use a pointer to the key or key
+         * handle. \c NULL indicates empty. */
+        void *key_ptr;
+        /** For libraries that use an integer handle to the key */
+        uint64_t key_handle;
+    } k;
+};
+
+/** An empty or \c NULL \c t_cose_key */
+#define T_COSE_NULL_KEY \
+    ((struct t_cose_key){T_COSE_CRYPTO_LIB_UNIDENTIFIED, {0}})
+
+
+/* Private value. Intentionally not documented for Doxygen.  This is
+ * the size allocated for the encoded protected header parameters.  It
+ * needs to be big enough for encode_protected_parameters() to
+ * succeed. It currently sized for one parameter with an algorithm ID
+ * up to 32 bits long -- one byte for the wrapping map, one byte for
+ * the label, 5 bytes for the ID. If this is made accidentially too
+ * small, QCBOR will only return an error, and not overrun any
+ * buffers.
+ *
+ * 17 extra bytes are added, rounding it up to 24 total, in case some
+ * other protected header parameter is to be added and so the test
+ * using T_COSE_TEST_CRIT_PARAMETER_EXIST can work.
+ */
+#define T_COSE_SIGN1_MAX_SIZE_PROTECTED_PARAMETERS (1+1+5+17)
+
+
+/**
+ * Error codes return by t_cose.
+ */
+/*
+ * Do not reorder these. It is OK to add new ones at the end.
+ *
+ * Explicit values are included because some tools like debuggers show
+ * only the value, not the symbol, and it is hard to count up through
+ * 35 lines to figure out the actual value.
+ */
+enum t_cose_err_t {
+    /** Operation completed successfully. */
+    T_COSE_SUCCESS = 0,
+
+    /** The requested signing algorithm is not supported.  */
+    T_COSE_ERR_UNSUPPORTED_SIGNING_ALG = 1,
+
+    /** Internal error when encoding protected parameters, usually
+     * because they are too big. It is internal because the caller
+     * can't really affect the size of the protected parameters. */
+    T_COSE_ERR_MAKING_PROTECTED = 2,
+
+    /** The hash algorithm needed is not supported. Note that the
+     * signing algorithm identifier identifies the hash algorithm. */
+    T_COSE_ERR_UNSUPPORTED_HASH = 3,
+
+    /** Some system failure when running the hash algorithm. */
+    T_COSE_ERR_HASH_GENERAL_FAIL = 4,
+
+    /** The buffer to receive a hash result is too small. */
+    T_COSE_ERR_HASH_BUFFER_SIZE = 5,
+
+    /** The buffer to receive result of a signing operation is too
+     * small. */
+    T_COSE_ERR_SIG_BUFFER_SIZE = 6,
+
+    /** When verifying a \c COSE_Sign1, the CBOR is "well-formed", but
+     * something is wrong with the format of the CBOR outside of the
+     * header parameters. For example, it is missing something like
+     * the payload or something is of an unexpected type. */
+    T_COSE_ERR_SIGN1_FORMAT = 8,
+
+    /** When decoding some CBOR like a \c COSE_Sign1, the CBOR was not
+     * "well-formed". Most likely what was supposed to be CBOR is
+     * either not or is corrupted. The CBOR is can't be decoded. */
+    T_COSE_ERR_CBOR_NOT_WELL_FORMED = 9,
+
+    /** The CBOR is "well-formed", but something is wrong with format
+     * in the header parameters.  For example, a parameter is labeled
+     * with other than an integer or string or the value is an integer
+     * when a byte string is expected. */
+    T_COSE_ERR_PARAMETER_CBOR = 10,
+
+    /** No algorithm ID was found when one is needed. For example,
+     * when verifying a \c COSE_Sign1. */
+    T_COSE_ERR_NO_ALG_ID = 11,
+
+    /** No kid (key ID) was found when one is needed. For example,
+     * when verifying a \c COSE_Sign1. */
+    T_COSE_ERR_NO_KID = 12,
+
+    /** Signature verification failed. For example, the cryptographic
+     * operations completed successfully but hash wasn't as
+     * expected. */
+    T_COSE_ERR_SIG_VERIFY = 13,
+
+    /** Verification of a short-circuit signature failed. */
+    T_COSE_ERR_BAD_SHORT_CIRCUIT_KID = 14,
+
+    /** Some (unspecified) argument was not valid. */
+    T_COSE_ERR_INVALID_ARGUMENT = 15,
+
+    /** Out of heap memory. This originates in crypto library as
+     * t_cose does not use malloc. */
+    T_COSE_ERR_INSUFFICIENT_MEMORY = 16,
+
+    /** General unspecific failure. */
+    T_COSE_ERR_FAIL = 17,
+
+    /** Equivalent to \c PSA_ERROR_TAMPERING_DETECTED. */
+    T_COSE_ERR_TAMPERING_DETECTED = 18,
+
+    /** The key identified by a \ref t_cose_key or a key ID was not
+     * found. */
+    T_COSE_ERR_UNKNOWN_KEY = 19,
+
+    /** The key was found, but it was the wrong type for the
+      * operation. */
+    T_COSE_ERR_WRONG_TYPE_OF_KEY = 20,
+
+    /** Error constructing the COSE \c Sig_structure when signing or
+     *  verify. */
+    T_COSE_ERR_SIG_STRUCT = 21,
+
+    /** Signature was short-circuit. The option \ref
+     * T_COSE_OPT_ALLOW_SHORT_CIRCUIT to allow verification of
+     * short-circuit signatures was not set.  */
+    T_COSE_ERR_SHORT_CIRCUIT_SIG = 22,
+
+    /** Something generally went wrong in the crypto adaptor when
+      * signing or verifying. */
+    T_COSE_ERR_SIG_FAIL = 23,
+
+    /** Something went wrong formatting the CBOR.  Possibly the
+     * payload has maps or arrays that are not closed when using
+     * t_cose_sign1_encode_parameters() and
+     * t_cose_sign1_encode_signature() to sign a \c COSE_Sign1. */
+    T_COSE_ERR_CBOR_FORMATTING = 24,
+
+     /** The buffer passed in to receive the output is too small. */
+    T_COSE_ERR_TOO_SMALL = 25,
+
+    /** More parameters (more than \ref T_COSE_PARAMETER_LIST_MAX)
+     * than this implementation can handle. Note that all parameters
+     * need to be checked for criticality so all parameters need to be
+     * examined. */
+    T_COSE_ERR_TOO_MANY_PARAMETERS = 26,
+
+    /** A parameter was encountered that was unknown and also listed in
+      * the crit labels parameter. */
+    T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER = 27,
+
+    /** A request was made to signed with a short-circuit sig, \ref
+     * T_COSE_OPT_SHORT_CIRCUIT_SIG, but short circuit signature are
+     * disabled (compiled out) for this implementation.  */
+    T_COSE_ERR_SHORT_CIRCUIT_SIG_DISABLED = 28,
+
+    /** The key type in a \ref t_cose_key is wrong for the
+     * cryptographic library used by this integration of t_cose.
+     */
+    T_COSE_ERR_INCORRECT_KEY_FOR_LIB = 29,
+    /** This implementation only handles integer COSE algorithm IDs with
+     * values less than \c INT32_MAX. */
+
+    T_COSE_ERR_NON_INTEGER_ALG_ID = 30,
+    /** The content type parameter contains a content type that is
+     * neither integer or text string or it is an integer not in the
+     * range of 0 to \c UINT16_MAX. */
+    T_COSE_ERR_BAD_CONTENT_TYPE = 31,
+
+    /** If the option \ref T_COSE_OPT_TAG_REQUIRED is set for
+     * t_cose_sign1_verify() and the tag is absent, this error is
+     * returned. */
+    T_COSE_ERR_INCORRECTLY_TAGGED = 32,
+
+    /** The signing or verification key given is empty. */
+    T_COSE_ERR_EMPTY_KEY = 33,
+
+    /** A header parameter occurs twice, perhaps once in protected and
+     * once in unprotected. Duplicate header parameters are not
+     * allowed in COSE.
+     */
+    T_COSE_ERR_DUPLICATE_PARAMETER = 34,
+
+    /** A header parameter that should be protected (alg id or crit)
+     * is not. This occurs when verifying a \c COSE_Sign1 that is
+     * improperly constructed. */
+    T_COSE_ERR_PARAMETER_NOT_PROTECTED = 35,
+
+    /** Something is wrong with the crit parameter. */
+    T_COSE_ERR_CRIT_PARAMETER = 36,
+
+};
+
+
+
+
+/**
+ * The maximum number of header parameters that can be handled during
+ * verification of a \c COSE_Sign1 message. \ref
+ * T_COSE_ERR_TOO_MANY_PARAMETERS will be returned by
+ * t_cose_sign1_verify() if the input message has more.
+ *
+ * There can be both \ref T_COSE_PARAMETER_LIST_MAX integer-labeled
+ * parameters and \ref T_COSE_PARAMETER_LIST_MAX string-labeled
+ * parameters.
+ *
+ * This is a hard maximum so the implementation doesn't need
+ * malloc. This constant can be increased if needed. Doing so will
+ * increase stack usage.
+ */
+#define T_COSE_PARAMETER_LIST_MAX 10
+
+
+
+/**
+ * The value of an unsigned integer content type indicating no content
+ * type.  See \ref t_cose_parameters.
+ */
+#define T_COSE_EMPTY_UINT_CONTENT_TYPE UINT16_MAX+1
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __T_COSE_COMMON_H__ */
diff --git a/lib/ext/t_cose/inc/t_cose_sign1_sign.h b/lib/ext/t_cose/inc/t_cose_sign1_sign.h
new file mode 100644
index 0000000..fcb3fbe
--- /dev/null
+++ b/lib/ext/t_cose/inc/t_cose_sign1_sign.h
@@ -0,0 +1,382 @@
+/*
+ * t_cose_sign1_sign.h
+ *
+ * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#ifndef __T_COSE_SIGN1_H__
+#define __T_COSE_SIGN1_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "qcbor.h"
+#include "t_cose_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * \file t_cose_sign1_sign.h
+ *
+ * \brief Create a \c COSE_Sign1 message, usually for EAT or CWT Token.
+ *
+ * This creates a \c COSE_Sign1 message in compliance with
+ * [COSE (RFC 8152)](https://tools.ietf.org/html/rfc8152).
+ * A \c COSE_Sign1 message is a CBOR encoded binary blob that contains
+ * header parameters, a payload and a signature. Usually the signature is made
+ * with an EC signing algorithm like ECDSA.
+ *
+ * This implementation is intended to be small and portable to
+ * different OS's and platforms. Its dependencies are:
+ * - [QCBOR](https://github.com/laurencelundblade/QCBOR)
+ * - <stdint.h>, <string.h>, <stddef.h>
+ * - Hash functions like SHA-256
+ * - Signing functions like ECDSA
+ *
+ * There is a cryptographic adaptation layer defined in
+ * t_cose_crypto.h.  An implementation can be made of the functions in
+ * it for different cryptographic libraries. This means that different
+ * integrations with different cryptographic libraries may support
+ * only signing with a particular set of algorithms. Integration with
+ * [OpenSSL](https://www.openssl.org) is supported.  Key ID look up
+ * also varies by different cryptographic library integrations.
+ *
+ * This implementation has a mode where a CBOR-format payload can be
+ * output directly into the output buffer. This saves having two
+ * copies of the payload in memory. For this mode use
+ * t_cose_sign1_encode_parameters() and
+ * t_cose_sign1_encode_signature(). For a simpler API that just takes
+ * the payload as an input buffer use t_cose_sign1_sign().
+ *
+ * See t_cose_common.h for preprocessor defines to reduce object code
+ * and stack use by disabling features.
+ */
+
+
+/**
+ * This is the context for creating a \c COSE_Sign1 structure. The
+ * caller should allocate it and pass it to the functions here.  This
+ * is about 100 bytes so it fits easily on the stack.
+ */
+struct t_cose_sign1_sign_ctx {
+    /* Private data structure */
+    uint8_t               protected_parameters_buffer[T_COSE_SIGN1_MAX_SIZE_PROTECTED_PARAMETERS];
+    struct q_useful_buf_c protected_parameters; /* The encoded protected parameters */
+    int32_t               cose_algorithm_id;
+    struct t_cose_key     signing_key;
+    int32_t               option_flags;
+    struct q_useful_buf_c kid;
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+    uint32_t              content_type_uint;
+    const char *          content_type_tstr;
+#endif
+};
+
+
+/**
+ * This selects a signing test mode called _short_ _circuit_
+ * _signing_. This mode is useful when there is no signing key
+ * available, perhaps because it has not been provisioned or
+ * configured for the particular device. It may also be because the
+ * public key cryptographic functions have not been connected up in
+ * the cryptographic adaptation layer.
+ *
+ * It has no value for security at all. Data signed this way MUST NOT
+ * be trusted as anyone can sign like this.
+ *
+ * In this mode, the signature is the hash of that which would
+ * normally be signed by the public key algorithm. To make the
+ * signature the correct size for the particular algorithm, instances
+ * of the hash are concatenated to pad it out.
+ *
+ * This mode is very useful for testing because all the code except
+ * the actual signing algorithm is run exactly as it would if a proper
+ * signing algorithm was run. This can be used for end-end system
+ * testing all the way to a server or relying party, not just for
+ * testing device code as t_cose_sign1_verify() supports it too.
+ */
+#define T_COSE_OPT_SHORT_CIRCUIT_SIG 0x00000001
+
+
+/**
+ * An \c option_flag for t_cose_sign1_sign_init() to not add the CBOR
+ * type 6 tag for \c COSE_Sign1 whose value is 18. Some uses of COSE
+ * may require this tag be absent because it is known that it is a \c
+ * COSE_Sign1 from surrounding context.
+ *
+ * Or said another way, per the COSE RFC, this code produces a \c
+ * COSE_Sign1_Tagged by default and a \c COSE_Sign1 when this flag is
+ * set.  The only difference between these two is the CBOR tag.
+ */
+#define T_COSE_OPT_OMIT_CBOR_TAG 0x00000002
+
+
+
+
+/**
+ * \brief  Initialize to start creating a \c COSE_Sign1.
+ *
+ * \param[in] context            The t_cose signing context.
+ * \param[in] option_flags       One of \c T_COSE_OPT_XXXX.
+ * \param[in] cose_algorithm_id  The algorithm to sign with, for example
+ *                               \ref T_COSE_ALGORITHM_ES256.
+ *
+ * Initialize the \ref t_cose_sign1_ctx context. Typically, no
+ * \c option_flags are needed and 0 is passed. A \c cose_algorithm_id
+ * must always be given. See \ref T_COSE_OPT_SHORT_CIRCUIT_SIG and
+ * related for possible option flags.
+ *
+ * The algorithm ID space is from
+ * [COSE (RFC8152)](https://tools.ietf.org/html/rfc8152) and the
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ * \ref T_COSE_ALGORITHM_ES256 and a few others are defined here for
+ * convenience. The signing algorithms supported depends on the
+ * cryptographic library that t_cose is integrated with.
+ *
+ * Errors such as the passing of an unsupported \c cose_algorithm_id
+ * are reported when t_cose_sign1_sign() or
+ * t_cose_sign1_encode_parameters() is called.
+ */
+static void
+t_cose_sign1_sign_init(struct t_cose_sign1_sign_ctx *context,
+                       int32_t                       option_flags,
+                       int32_t                       cose_algorithm_id);
+
+
+/**
+ * \brief  Set the key and kid (key ID) for signing.
+ *
+ * \param[in] context      The t_cose signing context.
+ * \param[in] signing_key  The signing key to use or \ref T_COSE_NULL_KEY.
+ * \param[in] kid          COSE kid (key ID) parameter or \c NULL_Q_USEFUL_BUF_C.
+ *
+ * This needs to be called to set the signing key to use. The \c kid
+ * may be omitted by giving \c NULL_Q_USEFUL_BUF_C.
+ *
+ * If short-circuit signing is used,
+ * \ref T_COSE_OPT_SHORT_CIRCUIT_SIG, then this does not need to be
+ * called. If it is called the \c kid given will be used, but the \c
+ * signing_key is never used. When the \c kid is given with a
+ * short-circuit signature, the internally fixed kid for short circuit
+ * will not be used and this \c COSE_Sign1 message can not be verified
+ * by t_cose_sign1_verify().
+ */
+static void
+t_cose_sign1_set_signing_key(struct t_cose_sign1_sign_ctx *context,
+                             struct t_cose_key             signing_key,
+                             struct q_useful_buf_c         kid);
+
+
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+/**
+ * \brief Set the payload content type using CoAP content types.
+ *
+ * \param[in] context      The t_cose signing context.
+ * \param[in] content_type The content type of the payload as defined
+ *                         in the IANA CoAP Content-Formats registry.
+ *
+ * It is not allowed to have both a CoAP and MIME content type. This
+ * error will show up when t_cose_sign1_sign() or
+ * t_cose_sign1_encode_parameters() is called as no error is returned by
+ * this function.
+ *
+ * The IANA CoAP Content-Formats registry is found
+ * [here](https://www.iana.org/assignments/core-parameters/core-parameters.xhtml#content-formats).
+ */
+static inline void
+t_cose_sign1_set_content_type_uint(struct t_cose_sign1_sign_ctx *context,
+                                   uint16_t                      content_type);
+
+/**
+ * \brief Set the payload content type using MIME content types.
+ *
+ * \param[in] context      The t_cose signing context.
+ * \param[in] content_type The content type of the payload as defined
+ *                         in the IANA Media Types registry.
+
+ *
+ * It is not allowed to have both a CoAP and MIME content type. This
+ * error will show up when t_cose_sign1_sign() or
+ * t_cose_sign1_encode_parameters() is called.
+ *
+ * The IANA Media Types registry can be found
+ * [here](https://www.iana.org/assignments/media-types/media-types.xhtml).
+ * These have been known as MIME types in the past.
+ */
+static inline void
+t_cose_sign1_set_content_type_tstr(struct t_cose_sign1_sign_ctx *context,
+                                   const char                   *content_type);
+#endif /* T_COSE_DISABLE_CONTENT_TYPE */
+
+
+
+/**
+ * \brief  Create and sign a \c COSE_Sign1 message with a payload.
+ *
+ * \param[in] context  The t_cose signing context.
+ * \param[in] payload  Pointer and length of payload to sign.
+ * \param[in] out_buf  Pointer and length of buffer to output to.
+ * \param[out] result  Pointer and length of the resulting \c COSE_Sign1.
+ *
+ * The \c context must have been initialized with
+ * t_cose_sign1_sign_init() and the key set with
+ * t_cose_sign1_set_signing_key() before this is called.
+ *
+ * This creates the COSE header parameter, hashes and signs the
+ * payload and creates the signature. \c out_buf gives the pointer and
+ * length memory into which the output is written. The pointer and
+ * length of the actual \c COSE_Sign1 is returned in \c result.
+ *
+ * Typically, the required size of \c out_buf is about 30 bytes plus
+ * the size of the signature and the size of the key ID. This is about
+ * 150 bytes for ECDSA 256 with a 32-byte key ID.
+ *
+ * To compute the size of the buffer needed before it is allocated
+ * call this with \c out_buf containing a \c NULL pointer and large
+ * length like \c UINT32_MAX.  The algorithm and key, kid and such
+ * must be set up just as if the real \c COSE_Sign1 were to be created
+ * as these values are needed to compute the size correctly.  The
+ * contents of \c result will be a \c NULL pointer and the length of
+ * the \c COSE_Sign1. When this is run like this, the cryptographic
+ * functions will not actually run, but the size of their output will
+ * be taken into account to give an exact size.
+ *
+ * This function requires the payload be complete and formatted in a
+ * contiguous buffer. The resulting \c COSE_Sign1 message also
+ * contains the payload preceded by the header parameters and followed
+ * by the signature, all CBOR formatted. This function thus requires
+ * two copies of the payload to be in memory.  Alternatively
+ * t_cose_sign1_encode_parameters() and
+ * t_cose_sign1_encode_signature() can be used. They are more complex
+ * to use, but avoid the two copies of the payload.
+ */
+enum t_cose_err_t
+t_cose_sign1_sign(struct t_cose_sign1_sign_ctx *context,
+                  struct q_useful_buf_c         payload,
+                  struct q_useful_buf           out_buf,
+                  struct q_useful_buf_c        *result);
+
+
+/**
+ * \brief  Output first part and parameters for a \c COSE_Sign1 message.
+ *
+ * \param[in] context          The t_cose signing context.
+ * \param[in] cbor_encode_ctx  Encoding context to output to.
+ *
+ * This is the more complex and more memory efficient alternative to
+ * t_cose_sign1_sign(). Like t_cose_sign1_sign(),
+ * t_cose_sign1_sign_init() and t_cose_sign1_set_signing_key() must be
+ * called before calling this.
+ *
+ * When this is called, the opening parts of the \c COSE_Sign1 message
+ * are output to the \c cbor_encode_ctx.
+ *
+ * After this is called, the CBOR-formatted payload must be written to
+ * the \c cbor_encode_ctx by calling all the various
+ * \c QCBOREncode_AddXxx calls. It can be as simple or complex as needed.
+ *
+ * To complete the \c COSE_Sign1 call t_cose_sign1_encode_signature().
+ *
+ * The \c cbor_encode_ctx must have been initialized with an output
+ * buffer to hold the \c COSE_Sign1 header parameters, the payload and the
+ * signature.
+ *
+ * This and t_cose_sign1_encode_signature() can be used to calculate
+ * the size of the \c COSE_Sign1 in the way \c QCBOREncode is usually
+ * used to calculate sizes. In this case the \c t_cose_sign1_ctx must
+ * be initialized with the options, algorithm, key and kid just as
+ * normal as these are needed to calculate the size. Then set up the
+ * QCBOR encoder context with a \c NULL pointer and large length like
+ * \c UINT32_MAX.  Call t_cose_sign1_encode_parameters(), then format
+ * the payload into the encoder context, then call
+ * t_cose_sign1_encode_signature().  Finally call \c
+ * QCBOREncode_FinishGetSize() to get the length.
+ */
+enum t_cose_err_t
+t_cose_sign1_encode_parameters(struct t_cose_sign1_sign_ctx *context,
+                               QCBOREncodeContext           *cbor_encode_ctx);
+
+
+/**
+ * \brief Finish a \c COSE_Sign1 message by outputting the signature.
+ *
+ * \param[in] context          The t_cose signing context.
+ * \param[in] cbor_encode_ctx  Encoding context to output to.
+ *
+ * \return This returns one of the error codes defined by \ref t_cose_err_t.
+ *
+ * Call this to complete creation of a signed \c COSE_Sign1 started
+ * with t_cose_sign1_encode_parameters().
+ *
+ * This is when the cryptographic signature algorithm is run.
+ *
+ * The completed \c COSE_Sign1 message is retrieved from the
+ * \c cbor_encode_ctx by calling \c QCBOREncode_Finish().
+ */
+enum t_cose_err_t
+t_cose_sign1_encode_signature(struct t_cose_sign1_sign_ctx *context,
+                              QCBOREncodeContext           *cbor_encode_ctx);
+
+
+
+
+
+
+/* ------------------------------------------------------------------------
+ * Inline implementations of public functions defined above.
+ */
+static inline void
+t_cose_sign1_sign_init(struct t_cose_sign1_sign_ctx *me,
+                       int32_t                       option_flags,
+                       int32_t                       cose_algorithm_id)
+{
+    memset(me, 0, sizeof(*me));
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+    /* Only member for which 0 is not the empty state */
+    me->content_type_uint = T_COSE_EMPTY_UINT_CONTENT_TYPE;
+#endif
+
+    me->cose_algorithm_id = cose_algorithm_id;
+    me->option_flags      = option_flags;
+}
+
+
+static inline void
+t_cose_sign1_set_signing_key(struct t_cose_sign1_sign_ctx *me,
+                             struct t_cose_key             signing_key,
+                             struct q_useful_buf_c         kid)
+{
+    me->kid         = kid;
+    me->signing_key = signing_key;
+}
+
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+static inline void
+t_cose_sign1_set_content_type_uint(struct t_cose_sign1_sign_ctx *me,
+                                   uint16_t                     content_type)
+{
+    me->content_type_uint = content_type;
+}
+
+
+static inline void
+t_cose_sign1_set_content_type_tstr(struct t_cose_sign1_sign_ctx *me,
+                                   const char                   *content_type)
+{
+    me->content_type_tstr = content_type;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __T_COSE_SIGN1_H__ */
diff --git a/lib/ext/t_cose/inc/t_cose_sign1_verify.h b/lib/ext/t_cose/inc/t_cose_sign1_verify.h
new file mode 100644
index 0000000..11555d7
--- /dev/null
+++ b/lib/ext/t_cose/inc/t_cose_sign1_verify.h
@@ -0,0 +1,296 @@
+/*
+ *  t_cose_sign1_verify.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+
+#ifndef __T_COSE_SIGN1_VERIFY_H__
+#define __T_COSE_SIGN1_VERIFY_H__
+
+#include <stdint.h>
+#include "q_useful_buf.h"
+#include "t_cose_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file t_cose_sign1_verify.h
+ *
+ * \brief Verify a COSE_Sign1 Message
+ *
+ * This verifies a \c COSE_Sign1 message in compliance with [COSE (RFC 8152)]
+ * (https://tools.ietf.org/html/rfc8152). A \c COSE_Sign1 message is a CBOR
+ * encoded binary blob that contains header parameters, a payload and a
+ * signature. Usually the signature is made with an EC signing
+ * algorithm like ECDSA.
+ *
+ * This implementation is intended to be small and portable to
+ * different OS's and platforms. Its dependencies are:
+ * - [QCBOR](https://github.com/laurencelundblade/QCBOR)
+ * - <stdint.h>, <string.h>, <stddef.h>
+ * - Hash functions like SHA-256
+ * - Signing functions like ECDSA
+ *
+ * There is a cryptographic adaptation layer defined in
+ * t_cose_crypto.h.  An implementation can be made of the functions in
+ * it for different cryptographic libraries. This means that different
+ * integrations with different cryptographic libraries may support
+ * only signing with a particular set of algorithms. Integration with
+ * [OpenSSL](https://www.openssl.org) is supported.  Key ID look up
+ * also varies by different cryptographic library integrations.
+ *
+ * See t_cose_common.h for preprocessor defines to reduce object code
+ * and stack use by disabling features.
+ */
+
+
+/**
+ * The result of parsing a set of COSE header parameters. The pointers
+ * are all back into the \c COSE_Sign1 blob passed in.
+ *
+ * Approximate size on a 64-bit machine is 80 bytes and on a 32-bit
+ * machine is 40.
+ */
+struct t_cose_parameters {
+    /** The algorithm ID. \ref T_COSE_UNSET_ALGORITHM_ID if the algorithm ID
+     * parameter is not present. String type algorithm IDs are not
+     * supported.  See the
+     * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml)
+     * for the algorithms corresponding to the integer values.
+     */
+    int32_t               cose_algorithm_id;
+    /** The COSE key ID. \c NULL_Q_USEFUL_BUF_C if parameter is not
+     * present */
+    struct q_useful_buf_c kid;
+    /** The initialization vector. \c NULL_Q_USEFUL_BUF_C if parameter
+     * is not present */
+    struct q_useful_buf_c iv;
+    /** The partial initialization vector. \c NULL_Q_USEFUL_BUF_C if
+     * parameter is not present */
+    struct q_useful_buf_c partial_iv;
+    /** The content type as a MIME type like
+     * "text/plain". \c NULL_Q_USEFUL_BUF_C if parameter is not present */
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+    struct q_useful_buf_c content_type_tstr;
+    /** The content type as a CoAP Content-Format
+     * integer. \ref T_COSE_EMPTY_UINT_CONTENT_TYPE if parameter is not
+     * present. Allowed range is 0 to UINT16_MAX per RFC 7252. */
+    uint32_t              content_type_uint;
+#endif /* T_COSE_DISABLE_CONTENT_TYPE */
+};
+
+
+/**
+ * A special COSE algorithm ID that indicates no COSE algorithm ID or an unset
+ * COSE algorithm ID.
+ */
+#define T_COSE_UNSET_ALGORITHM_ID 0
+
+
+
+
+/**
+ * Pass this as \c option_flags to allow verification of short-circuit
+ * signatures. This should only be used as a test mode as
+ * short-circuit signatures are not secure.
+ *
+ * See also \ref T_COSE_OPT_SHORT_CIRCUIT_SIG.
+ */
+#define T_COSE_OPT_ALLOW_SHORT_CIRCUIT 0x00000001
+
+
+/**
+ * The error \ref T_COSE_ERR_NO_KID is returned if the kid parameter
+ * is missing. Note that the kid parameter is primarily passed on to
+ * the crypto layer so the crypto layer can look up the key. If the
+ * verification key is determined by other than the kid, then it is
+ * fine if there is no kid.
+ */
+#define T_COSE_OPT_REQUIRE_KID 0x00000002
+
+
+/**
+ * Normally this will decode the CBOR presented as a \c COSE_Sign1
+ * message whether it is tagged using QCBOR tagging as such or not.
+ * If this option is set, then \ref T_COSE_ERR_INCORRECTLY_TAGGED is
+ * returned if it is not tagged.
+ */
+#define T_COSE_OPT_TAG_REQUIRED  0x00000004
+
+
+/**
+ * See t_cose_sign1_set_verification_key().
+ *
+ * This option disables cryptographic signature verification.  With
+ * this option the \c verification_key is not needed.  This is useful
+ * to decode the \c COSE_Sign1 message to get the kid (key ID).  The
+ * verification key can be looked up or otherwise obtained by the
+ * caller. Once the key in in hand, t_cose_sign1_verify() can be
+ * called again to perform the full verification.
+ *
+ * The payload will always be returned whether this is option is given
+ * or not, but it should not be considered secure when this option is
+ * given.
+ *
+ */
+#define T_COSE_OPT_DECODE_ONLY  0x00000008
+
+
+
+/**
+ * Context for signature verification.  It is about 24 bytes on a
+ * 64-bit machine and 12 bytes on a 32-bit machine.
+ */
+struct t_cose_sign1_verify_ctx {
+    /* Private data structure */
+    struct t_cose_key     verification_key;
+    int32_t               option_flags;
+};
+
+
+/**
+ * \brief Initialize for \c COSE_Sign1 message verification.
+ *
+ * \param[in,out]  context       The context to initialize.
+ * \param[in]      option_flags  Options controlling the verification.
+ *
+ * This must be called before using the verification context.
+ */
+static void
+t_cose_sign1_verify_init(struct t_cose_sign1_verify_ctx *context,
+                         int32_t                         option_flags);
+
+
+/**
+ * \brief Set key for \c COSE_Sign1 message verification.
+ *
+ * \param[in] verification_key  The verification key to use.
+ *
+ * There are four main ways that the verification key is found and
+ * supplied to t_cose so that t_cose_sign1_verify() succeeds.
+ *
+ * -# Look up by kid parameter and set by t_cose_sign1_set_verification_key()
+ * -# Look up by other and set by t_cose_sign1_set_verification_key()
+ * -# Determination by kid that short circuit signing is used (test only)
+ * -# Look up by kid parameter in cryptographic adaptation  layer
+ *
+ * Note that there is no means where certificates, like X.509
+ * certificates, are provided in the COSE parameters. Perhaps there
+ * will be in the future but that is not in common use or supported by
+ * this implementation.
+ *
+ * To use 1 it is necessary to call t_cose_sign1_verify_init() and
+ * t_cose_sign1_verify() twice.  The first time
+ * t_cose_sign1_verify_init() is called, give the \ref
+ * T_COSE_OPT_DECODE_ONLY option.  Then call t_cose_sign1_verify() and
+ * the kid will be returned in \c parameters. The caller finds the kid on
+ * their own. Then call this to set the key. Last call
+ * t_cose_sign1_verify(), again without the \ref T_COSE_OPT_DECODE_ONLY
+ * option.
+ *
+ * To use 2 the key is somehow determined without the kid and
+ * t_cose_sign1_set_verification_key() is called with it. Then
+ * t_cose_sign1_verify() is called. Note that this implementation
+ * cannot return non-standard header parameters, at least not yet.
+ *
+ * To use 3, initialize with \ref T_COSE_OPT_ALLOW_SHORT_CIRCUIT.  No
+ * call to t_cose_sign1_set_verification_key() is necessary. If you do
+ * call t_cose_sign1_set_verification_key(), the kid for short circuit
+ * signing will be recognized and the set key will be ignored.
+ *
+ * To use 4, first be sure that the cryptographic adapter supports
+ * look up by kid.  There's no API to determine this, so it is
+ * probably determined by other system documentation (aka source
+ * code).  In this mode, all that is necessary is to call
+ * t_cose_sign1_verify().
+ *
+ * 3 always works no matter what is done in the cryptographic
+ * adaptation layer because it never calls out to it. The OpenSSL
+ * adaptor supports 1 and 2.
+ */
+static void
+t_cose_sign1_set_verification_key(struct t_cose_sign1_verify_ctx *context,
+                                  struct t_cose_key               verification_key);
+
+
+/**
+ * \brief Verify a COSE_Sign1
+ *
+ * \param[in] sign1         Pointer and length of CBOR encoded \c COSE_Sign1
+ *                          message that is to be verified.
+ * \param[out] payload      Pointer and length of the payload.
+ * \param[out] parameters   Place to return parsed parameters. Maybe be \c NULL.
+ *
+ * \return This returns one of the error codes defined by \ref t_cose_err_t.
+ *
+ * See t_cose_sign1_set_verification_key() for discussion on where
+ * the verification key comes from.
+ *
+ * Verification involves the following steps.
+ *
+ * - The CBOR-format COSE_Sign1 structure is parsed. It makes sure \c sign1
+ * is valid CBOR and follows the required structure for \c COSE_Sign1.
+ *
+ * - The protected header parameters are parsed, particular the algorithm id.
+ *
+ * - The unprotected headers parameters are parsed, particularly the kid.
+ *
+ * - The payload is identified. The internals of the payload are not parsed.
+ *
+ * - The expected hash, the "to-be-signed" bytes are computed. The hash
+ * algorithm to use comes from the signing algorithm. If the algorithm is
+ * not known or not supported this will error out.
+ *
+ * - Finally, the signature verification is performed.
+ *
+ * If it is successful, the pointer to the CBOR-encoded payload is
+ * returned. The parameters are returned if requested. All pointers
+ * returned are to memory in the \c sign1 passed in.
+ *
+ * Note that this only handles standard COSE header parameters. There are no
+ * facilities for custom header parameters, even though they are allowed by
+ * the COSE standard.
+ *
+ * This will recognize the special key ID for short-circuit signing
+ * and verify it if the \ref T_COSE_OPT_ALLOW_SHORT_CIRCUIT is set.
+ *
+ * Indefinite length CBOR strings are not supported by this
+ * implementation.  \ref T_COSE_ERR_SIGN1_FORMAT will be returned if
+ * they are in the input \c COSE_Sign1 messages. For example, if the
+ * payload is an indefinite length byte string, this error will be
+ * returned.
+ */
+enum t_cose_err_t t_cose_sign1_verify(struct t_cose_sign1_verify_ctx *context,
+                                      struct q_useful_buf_c           sign1,
+                                      struct q_useful_buf_c          *payload,
+                                      struct t_cose_parameters       *parameters);
+
+
+
+
+/* ------------------------------------------------------------------------
+ * Inline implementations of public functions defined above.
+ */
+static inline void
+t_cose_sign1_verify_init(struct t_cose_sign1_verify_ctx *me,
+                         int32_t                option_flags)
+{
+    me->option_flags = option_flags;
+    me->verification_key = T_COSE_NULL_KEY;
+}
+
+
+static inline void
+t_cose_sign1_set_verification_key(struct t_cose_sign1_verify_ctx *me,
+                                  struct t_cose_key               verification_key)
+{
+    me->verification_key = verification_key;
+}
+#endif /* __T_COSE_SIGN1_VERIFY_H__ */
diff --git a/lib/ext/t_cose/src/t_cose_crypto.h b/lib/ext/t_cose/src/t_cose_crypto.h
new file mode 100644
index 0000000..458d8dd
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_crypto.h
@@ -0,0 +1,563 @@
+/*
+ * t_cose_crypto.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+
+#ifndef __T_COSE_CRYPTO_H__
+#define __T_COSE_CRYPTO_H__
+
+#include "t_cose_common.h"
+#include "q_useful_buf.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include "t_cose_standard_constants.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+/**
+ * \file t_cose_crypto.h
+ *
+ * \brief This defines the adaptation layer for cryptographic
+ * functions needed by t_cose.
+ *
+ * This is  small wrapper around the cryptographic functions to:
+ * - Map COSE algorithm IDs to cryptographic library IDs
+ * - Map cryptographic library errors to \ref t_cose_err_t errors
+ * - Have inputs and outputs be \c struct \c q_useful_buf_c and
+ *   \c struct \c q_useful_buf
+ * - Handle key selection
+ *
+ * An implementation must be made of these functions
+ * for the various cryptographic libraries that are used on
+ * various platforms and OSs. The functions are:
+ *   - t_cose_t_crypto_sig_size()
+ *   - t_cose_crypto_pub_key_sign()
+ *   - t_cose_crypto_pub_key_verify()
+ *   - t_cose_crypto_hash_start()
+ *   - t_cose_crypto_hash_update()
+ *   - t_cose_crypto_hash_finish()
+ *
+ * This runs entirely off of COSE-style algorithm identifiers.  They
+ * are simple integers and thus work nice as function parameters. An
+ * initial set is defined by [COSE (RFC 8152)]
+ * (https://tools.ietf.org/html/rfc8152). New ones can be registered
+ * in the [IANA COSE Registry]
+ * (https://www.iana.org/assignments/cose/cose.xhtml). Local use new
+ * ones can also be defined (\c \#define) if what is needed is not in
+ * the IANA registry.
+ *
+ * \anchor useful_buf_use
+ * Binary data is returned to the caller using a \c struct \c
+ * q_useful_buf to pass the buffer to receive the data and its length in
+ * and a \c q_useful_buf_c to return the pointer and length of the
+ * returned data. The point of this is coding hygiene. The buffer
+ * passed in is not const as it is to be modified.  The \c
+ * q_useful_buf_c returned is const. The lengths of buffers are
+ * handled in a clear, consistent and enforced manner.
+ *
+ * The pointer in the \c q_useful_buf_c will always point to the
+ * buffer passed in via the \c q_useful_buf so the lifetime of the
+ * data is under control of the caller.
+ *
+ * This is not intended as any sort of general cryptographic API. It
+ * is just the functions needed by t_cose in the form that is most
+ * useful for t_cose.
+ *
+ * No other file in t_cose should need modification for new algorithms,
+ * new key types and sizes or the integration of cryptographic libraries
+ * except on some occasions, this file as follows:
+ *
+ * - Support for a new COSE_ALGORITHM_XXX signature algorithm
+ *    - See t_cose_algorithm_is_ecdsa()
+ *    - If not ECDSA add another function like t_cose_algorithm_is_ecdsa()
+ * - Support for a new COSE_ALGORITHM_XXX signature algorithm is added
+ *    - See \ref T_COSE_CRYPTO_MAX_HASH_SIZE for additional hashes
+ * - Support larger key sizes (and thus signature sizes)
+ *    - See \ref T_COSE_MAX_SIG_SIZE
+ * - Support another hash implementation that is not a service
+ *    - See struct \ref t_cose_crypto_hash
+ *
+ * To reduce stack usage and save a little code these can be defined.
+ *    - T_COSE_DISABLE_ES384
+ *    - T_COSE_DISABLE_ES512
+ *
+ * The actual code that implements these hashes in the crypto library may
+ * or may not be saved with these defines depending on how the library
+ * works, whether dead stripping of object code is on and such.
+ */
+
+
+
+
+#define T_COSE_EC_P256_SIG_SIZE 64  /* size for secp256r1 */
+#define T_COSE_EC_P384_SIG_SIZE 96  /* size for secp384r1 */
+#define T_COSE_EC_P512_SIG_SIZE 132 /* size for secp521r1 */
+
+
+/**
+ * There is a stack variable to hold the output of the signing
+ * operation.  This sets the maximum signature size this code can
+ * handle based on the COSE algorithms configured. The size of the
+ * signature goes with the size of the key, not the algorithm, so a
+ * key could be given for signing or verification that is larger than
+ * this. However, it is not typical to do so. If the key or signature
+ * is too large the failure will be graceful with an error.
+ *
+ * For ECDSA the signature format used is defined in RFC 8152 section
+ * 8.1. It is the concatenation of r and s, each of which is the key
+ * size in bits rounded up to the nearest byte.  That is twice the key
+ * size in bytes.
+ */
+#ifndef T_COSE_DISABLE_ES512
+    #define T_COSE_MAX_SIG_SIZE T_COSE_EC_P512_SIG_SIZE
+#else
+    #ifndef T_COSE_DISABLE_ES384
+        #define T_COSE_MAX_SIG_SIZE T_COSE_EC_P384_SIG_SIZE
+    #else
+        #define T_COSE_MAX_SIG_SIZE T_COSE_EC_P256_SIG_SIZE
+    #endif
+#endif
+
+
+
+
+/**
+ * \brief Returns the size of a signature given the key and algorithm.
+ *
+ * \param[in] cose_algorithm_id  The algorithm ID
+ * \param[in] signing_key        Key to compute size of
+ * \param[out] sig_size          The returned size in bytes.
+ *
+ * \return An error code or \ref T_COSE_SUCCESS.
+ *
+ * This is used the caller wishes to compute the size of a token in
+ * order to allocate memory for it.
+ *
+ * The size of a signature depends primarily on the key size but it is
+ * usually necessary to know the algorithm too.
+ *
+ * This always returns the exact size of the signature.
+ */
+enum t_cose_err_t
+t_cose_crypto_sig_size(int32_t            cose_algorithm_id,
+                       struct t_cose_key  signing_key,
+                       size_t            *sig_size);
+
+
+/**
+ * \brief Perform public key signing. Part of the t_cose crypto
+ * adaptation layer.
+ *
+ * \param[in] cose_algorithm_id The algorithm to sign with. The IDs are
+ *                              defined in [COSE (RFC 8152)]
+ *                              (https://tools.ietf.org/html/rfc8152) or
+ *                              in the [IANA COSE Registry]
+ *                              (https://www.iana.org/assignments/cose/cose.xhtml).
+ *                              A proprietary ID can also be defined
+ *                              locally (\c \#define) if the needed
+ *                              one hasn't been registered.
+ * \param[in] signing_key       Indicates or contains key to sign with.
+ * \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.
+ *
+ * \retval T_COSE_SUCCESS
+ *         Successfully created the signature.
+ * \retval T_COSE_ERR_SIG_BUFFER_SIZE
+ *         The \c signature_buffer too small.
+ * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG
+ *         The requested signing algorithm, \c cose_algorithm_id, is not
+ *         supported.
+ * \retval T_COSE_ERR_UNKNOWN_KEY
+ *         The key identified by \c key_select was not found.
+ * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY
+ *         The key was found, but it was the wrong type.
+ * \retval T_COSE_ERR_INVALID_ARGUMENT
+ *         Some (unspecified) argument was not valid.
+ * \retval T_COSE_ERR_INSUFFICIENT_MEMORY
+ *         Insufficient heap memory.
+ * \retval T_COSE_ERR_FAIL
+ *         General unspecific failure.
+ * \retval T_COSE_ERR_TAMPERING_DETECTED
+ *         Equivalent to \c PSA_ERROR_TAMPERING_DETECTED.
+ *
+ * This is called to do public key signing. The implementation will
+ * vary from one platform / OS to another but should conform to the
+ * description here.
+ *
+ * The contents of signing_key is usually the type that holds
+ * a key for the cryptographic library.
+ *
+ * See the note in the Detailed Description (the \\file comment block)
+ * for details on how \c q_useful_buf and \c q_useful_buf_c are used
+ * to return the signature.
+ *
+ * To find out the size of the signature buffer needed, call this with
+ * \c signature_buffer->ptr \c NULL and \c signature_buffer->len a
+ * very large number like \c UINT32_MAX. The size will be returned in
+ * \c signature->len.
+ */
+enum t_cose_err_t
+t_cose_crypto_pub_key_sign(int32_t                cose_algorithm_id,
+                           struct t_cose_key      signing_key,
+                           struct q_useful_buf_c  hash_to_sign,
+                           struct q_useful_buf    signature_buffer,
+                           struct q_useful_buf_c *signature);
+
+
+/**
+ * \brief Perform public key signature verification. Part of the
+ * t_cose crypto adaptation layer.
+ *
+ * \param[in] cose_algorithm_id The algorithm to use for verification.
+ *                              The IDs are defined in [COSE (RFC 8152)]
+ *                              (https://tools.ietf.org/html/rfc8152)
+ *                              or in the [IANA COSE Registry]
+ *                       (https://www.iana.org/assignments/cose/cose.xhtml).
+ *                              A proprietary ID can also be defined
+ *                              locally (\c \#define) if the needed one
+ *                              hasn't been registered.
+ * \param[in] verification_key  The verification key to use.
+ * \param[in] kid               The COSE kid (key ID) or \c NULL_Q_USEFUL_BUF_C.
+ * \param[in] hash_to_verify    The data or hash that is to be verified.
+ * \param[in] signature         The signature.
+ *
+ * This verifies that the \c signature passed in was over the \c
+ * hash_to_verify passed in.
+ *
+ * The public key used to verify the signature is selected by the \c
+ * kid if it is not \c NULL_Q_USEFUL_BUF_C or the \c key_select if it
+ * is.
+ *
+ * The key selected must be, or include, a public key of the correct
+ * type for \c cose_algorithm_id.
+ *
+ * \retval T_COSE_SUCCESS
+ *         The signature is valid
+ * \retval T_COSE_ERR_SIG_VERIFY
+ *         Signature verification failed. For example, the
+ *         cryptographic operations completed successfully but hash
+ *         wasn't as expected.
+ * \retval T_COSE_ERR_UNKNOWN_KEY
+ *         The key identified by \c key_select or a \c kid was
+ *         not found.
+ * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY
+ *         The key was found, but it was the wrong type
+ *         for the operation.
+ * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG
+ *         The requested signing algorithm is not supported.
+ * \retval T_COSE_ERR_INVALID_ARGUMENT
+ *         Some (unspecified) argument was not valid.
+ * \retval T_COSE_ERR_INSUFFICIENT_MEMORY
+ *         Out of heap memory.
+ * \retval T_COSE_ERR_FAIL
+ *         General unspecific failure.
+ * \retval T_COSE_ERR_TAMPERING_DETECTED
+ *         Equivalent to \c PSA_ERROR_TAMPERING_DETECTED.
+ */
+enum t_cose_err_t
+t_cose_crypto_pub_key_verify(int32_t               cose_algorithm_id,
+                             struct t_cose_key     verification_key,
+                             struct q_useful_buf_c kid,
+                             struct q_useful_buf_c hash_to_verify,
+                             struct q_useful_buf_c signature);
+
+
+
+
+#ifdef T_COSE_USE_B_CON_SHA256
+/* This is code for use with Brad Conte's crypto.  See
+ * https://github.com/B-Con/crypto-algorithms and see the description
+ * of t_cose_crypto_hash
+ */
+#include "sha256.h"
+#endif
+
+#ifdef T_COSE_USE_OPENSSL_CRYPTO
+#include "openssl/sha.h"
+#endif
+
+
+/**
+ * The context for use with the hash adaptation layer here.
+ *
+ * Hash implementations for this porting layer are put into two
+ * different categories.
+ *
+ * The first can be supported generically without any dependency on
+ * the actual hash implementation in this header. These only need a
+ * pointer or handle for the hash context.  Usually these are
+ * implemented by a service, system API or crypto HW that runs in a
+ * separate context or process. They probably allocate memory
+ * internally. These can use context.ptr or context.handle to hold the
+ * pointer or handle to the hash context.
+ *
+ * The second sort of hash implementations need more than just a
+ * pointer or handle. Typically these are libraries that are linked
+ * with this code and run in the same process / context / thread as
+ * this code. These can be efficient requiring no context switches or
+ * memory allocations. These type require this header be modified for
+ * the #include which defines the hash context and so this struct
+ * includes that context as a member. This context is allocated on the
+ * stack, so any members added here should be small enough to go on
+ * the stack. USE_B_CON_SHA256 is an example of this type.
+ *
+ * The actual implementation of the hash is in a separate .c file
+ * that will be specific to the particular platform, library,
+ * service or such used.
+ */
+struct t_cose_crypto_hash {
+
+#ifdef T_COSE_USE_OPENSSL_CRYPTO
+    /* What is needed for a full proper integration of OpenSSL's hashes */
+    /* The hash context goes on the stack. This is 224 bytes on 64-bit x86 */
+    union {
+        SHA256_CTX sha_256;
+#if !defined T_COSE_DISABLE_ES512 || !defined T_COSE_DISABLE_ES384
+        /* SHA 384 uses the sha_512 context
+         * This uses about 100 bytes above SHA-256  */
+        SHA512_CTX sha_512;
+#endif
+    } ctx;
+
+    int     update_error; /* Used to track error return by SHAXXX_Upate() */
+    int32_t cose_hash_alg_id; /* COSE integer ID for the hash alg */
+
+#else
+#ifdef T_COSE_USE_B_CON_SHA256
+    /* Specific context for Brad Conte's sha256.c */
+    SHA256_CTX b_con_hash_context;
+#else
+    /*
+     *  Generic pointer / handle that can work for many
+     *  hash implementations.
+     */
+    union {
+        void    *ptr;
+        uint64_t handle;
+    } context;
+    int64_t status;
+#endif
+#endif
+
+};
+
+
+/**
+ * The size of the output of SHA-256.
+ *
+ * (It is safe to define these independently here as they are
+ * well-known and fixed. There is no need to reference
+ * platform-specific headers and incur messy dependence.)
+ */
+#define T_COSE_CRYPTO_SHA256_SIZE 32
+
+/**
+ * The size of the output of SHA-384 in bytes.
+ */
+#define T_COSE_CRYPTO_SHA384_SIZE 48
+
+/**
+ * The size of the output of SHA-512 in bytes.
+ */
+#define T_COSE_CRYPTO_SHA512_SIZE 64
+
+
+/**
+ * The maximum needed to hold a hash. It is smaller and less stack is used
+ * if the larger hashes are disabled.
+ */
+#ifndef T_COSE_DISABLE_ES512
+    #define T_COSE_CRYPTO_MAX_HASH_SIZE T_COSE_CRYPTO_SHA512_SIZE
+#else
+    #ifndef T_COSE_DISABLE_ES384
+        #define T_COSE_CRYPTO_MAX_HASH_SIZE T_COSE_CRYPTO_SHA384_SIZE
+    #else
+        #define T_COSE_CRYPTO_MAX_HASH_SIZE T_COSE_CRYPTO_SHA256_SIZE
+    #endif
+#endif
+
+
+/**
+ * \brief Start cryptographic hash. Part of the t_cose crypto
+ * adaptation layer.
+ *
+ * \param[in,out] hash_ctx      Pointer to the hash context that
+ *                              will be initialized.
+ * \param[in] cose_hash_alg_id  Algorithm ID that identifies the
+ *                              hash to use. This is from the
+ *                              [IANA COSE Registry]
+ *                          (https://www.iana.org/assignments/cose/cose.xhtml)
+ *
+ * \retval T_COSE_ERR_UNSUPPORTED_HASH
+ *         The requested algorithm is unknown or unsupported.
+ *
+ * \retval T_COSE_ERR_HASH_GENERAL_FAIL
+ *         Some general failure of the hash function
+ *
+ * \retval T_COSE_SUCCESS
+ *         Success.
+ *
+ * This initializes the hash context for the particular algorithm. It
+ * must be called first. A \c hash_ctx can be reused if it is
+ * reinitialized.
+ *
+ * \ref T_COSE_INVALID_ALGORITHM_ID may be passed to this function, in which
+ * case \ref T_COSE_ERR_UNSUPPORTED_HASH must be returned.
+ *
+ * Other errors can be returned and will usually be propagated up, but hashes
+ * generally don't fail so it is suggested not to bother (and to reduce
+ * object code size for mapping errors).
+ */
+enum t_cose_err_t
+t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx,
+                         int32_t                    cose_hash_alg_id);
+
+
+/**
+ * \brief Feed data into a cryptographic hash. Part of the t_cose
+ * crypto adaptation layer.
+ *
+ * \param[in,out] hash_ctx  Pointer to the hash context in which
+ *                          accumulate the hash.
+ * \param[in]  data_to_hash Pointer and length of data to feed into
+ *                          hash. The pointer may by \c NULL in which
+ *                          case no hashing is performed.
+ *
+ * There is no return value. If an error occurs it is remembered in \c
+ * hash_ctx and returned when t_cose_crypto_hash_finish() is called.
+ * Once in the error state, this function may be called, but it will
+ * not do anything.
+ *
+ * This function can be called with \c data_to_hash.ptr NULL and it
+ * will pretend to hash. This allows the same code that is used to
+ * produce the real hash to be used to return a length of the would-be
+ * hash for encoded data structure size calculations.
+ */
+void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx,
+                               struct q_useful_buf_c      data_to_hash);
+
+
+/**
+ * \brief Finish a cryptographic hash. Part of the t_cose crypto
+ * adaptation layer.
+ *
+ * \param[in,out] hash_ctx           Pointer to the hash context.
+ * \param[in] buffer_to_hold_result  Pointer and length into which
+ *                                   the resulting hash is put.
+ * \param[out] hash_result           Pointer and length of the
+ *                                   resulting hash.
+ *
+ * \retval T_COSE_ERR_HASH_GENERAL_FAIL
+ *         Some general failure of the hash function.
+ * \retval T_COSE_ERR_HASH_BUFFER_SIZE
+ *         The size of the buffer to hold the hash result was
+ *         too small.
+ * \retval T_COSE_SUCCESS
+ *         Success.
+ *
+ * Call this to complete the hashing operation. If the everything
+ * completed correctly, the resulting hash is returned. Note that any
+ * errors that occurred during t_cose_crypto_hash_update() are
+ * returned here.
+ *
+ * See \ref useful_buf_use for details on how \c q_useful_buf and
+ * \c q_useful_buf_c are used to return the hash.
+ *
+ * Other errors can be returned and will usually be propagated up, but
+ * hashes generally don't fail so it is suggested not to bother (and
+ * to reduce object code size for mapping errors).
+ */
+enum t_cose_err_t
+t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx,
+                          struct q_useful_buf        buffer_to_hold_result,
+                          struct q_useful_buf_c     *hash_result);
+
+
+
+/**
+ * \brief Indicate whether a COSE algorithm is ECDSA or not.
+ *
+ * \param[in] cose_algorithm_id    The algorithm ID to check.
+ *
+ * \returns This returns \c true if the algorithm is ECDSA and \c false if not.
+ *
+ * This is a convenience function to check whether a given
+ * integer COSE algorithm ID uses the ECDSA signing algorithm
+ * or not.
+ *
+ * (As other types of signing algorithms are added, RSA for example,
+ * a similar function can be added for them.)
+ */
+static bool t_cose_algorithm_is_ecdsa(int32_t cose_algorithm_id);
+
+
+
+
+/*
+ * Inline implementations. See documentation above.
+ */
+
+/**
+ * \brief Look for an integer in a zero-terminated list of integers.
+ *
+ * \param[in] cose_algorithm_id    The algorithm ID to check.
+ * \param[in] list                 zero-terminated list of algorithm IDs.
+ *
+ * \returns This returns \c true if an integer is in the list, \c false if not.
+ *
+ * Used to implement t_cose_algorithm_is_ecdsa() and in the future
+ * _is_rsa() and such.
+ *
+ * Typically used once in the crypto adaptation layer, so defining it
+ * inline rather than in a .c file is OK and saves creating a whole
+ * new .c file just for this.
+ */
+static inline bool
+t_cose_check_list(int32_t cose_algorithm_id, const int32_t *list)
+{
+    while(*list) {
+        if(*list == cose_algorithm_id) {
+            return true;
+        }
+        list++;
+    }
+
+    return false;
+}
+
+static inline bool t_cose_algorithm_is_ecdsa(int32_t cose_algorithm_id)
+{
+    /* The simple list of COSE alg IDs that use ECDSA */
+    static const int32_t ecdsa_list[] = {
+        COSE_ALGORITHM_ES256,
+#ifndef T_COSE_DISABLE_ES384
+        COSE_ALGORITHM_ES384,
+#endif
+#ifndef T_COSE_DISABLE_ES512
+        COSE_ALGORITHM_ES512,
+#endif
+        0}; /* 0 is a reserved COSE alg ID ans will never be used */
+
+    return t_cose_check_list(cose_algorithm_id, ecdsa_list);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __T_COSE_CRYPTO_H__ */
diff --git a/lib/ext/t_cose/src/t_cose_parameters.c b/lib/ext/t_cose/src/t_cose_parameters.c
new file mode 100644
index 0000000..a2a5cf4
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_parameters.c
@@ -0,0 +1,707 @@
+/*
+ * t_cose_parameters.c
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+
+#include "t_cose_parameters.h"
+#include "t_cose_standard_constants.h"
+
+
+/**
+ * \file t_cose_headers.c
+ *
+ * \brief Implementation of the header parsing functions.
+ *
+ */
+
+
+/**
+ * \brief Consume a CBOR item, particularly a map or array.
+ *
+ * \param[in] decode_context   Context to read data items from.
+ * \param[in] item_to_consume  The already-read item that is being consumed.
+ * \param[out] next_nest_level Nesting level of the next item that will be read.
+ *
+ * \returns A CBOR decoding error or QCBOR_SUCCESS.
+ *
+ * The primary purpose of this is to consume (read) all the members of
+ * a map or an array, however deeply nested it is.
+ *
+ * This doesn't do much work for non-nested data items.
+ */
+static inline QCBORError
+consume_item(QCBORDecodeContext *decode_context,
+             const QCBORItem    *item_to_consume,
+             uint_fast8_t       *next_nest_level)
+{
+    /* Stack use: 4 + 56 = 60 */
+    QCBORError return_value;
+    QCBORItem  item;
+
+    if(item_to_consume->uDataType == QCBOR_TYPE_MAP || item_to_consume->uDataType == QCBOR_TYPE_ARRAY) {
+        /* There is only real work to do for maps and arrays */
+
+        /* This works for definite and indefinite length maps and
+         * arrays by using the nesting level
+         */
+        do {
+            return_value = QCBORDecode_GetNext(decode_context, &item);
+            if(return_value != QCBOR_SUCCESS) {
+                goto Done;
+            }
+        } while(item.uNextNestLevel >= item_to_consume->uNextNestLevel);
+
+        *next_nest_level = item.uNextNestLevel;
+        return_value = QCBOR_SUCCESS;
+
+    } else {
+        /* item_to_consume is not a map or array.  Just pass the
+         * nesting level through */
+        *next_nest_level = item_to_consume->uNextNestLevel;
+        return_value = QCBOR_SUCCESS;
+    }
+
+Done:
+    return return_value;
+}
+
+
+
+
+/**
+ * \brief Add a new label to the end of the label list.
+ *
+ * \param[in] item             Data item to add to the label list.
+ * \param[in,out] label_list   The list to add to.
+ *
+ * \retval T_COSE_SUCCESS                  If added correctly.
+ * \retval T_COSE_ERR_TOO_MANY_PARAMETERS  Label list is full.
+ * \retval T_COSE_ERR_PARAMETER_CBOR       The item to add doesn't have a label
+ *                                         type that is understood
+ *
+ * The label / key from \c item is added to \c label_list.
+ */
+static inline enum t_cose_err_t
+add_label_to_list(const QCBORItem          *item,
+                  struct t_cose_label_list *label_list)
+{
+    enum t_cose_err_t return_value;
+    uint_fast8_t      n;
+
+    /* Assume success until an error adding is encountered. */
+    return_value = T_COSE_SUCCESS;
+
+    if(item->uLabelType == QCBOR_TYPE_INT64) {
+        /* Add an integer-labeled parameter to the end of the list */
+        for(n = 0; label_list->int_labels[n] != LABEL_LIST_TERMINATOR; n++);
+        if(n == T_COSE_PARAMETER_LIST_MAX) {
+            /* List is full -- error out */
+            return_value = T_COSE_ERR_TOO_MANY_PARAMETERS;
+            goto Done;
+        }
+        label_list->int_labels[n] = item->label.int64;
+
+    } else if(item->uLabelType == QCBOR_TYPE_TEXT_STRING) {
+        /* Add a string-labeled parameter to the end of the list */
+        for(n = 0; !q_useful_buf_c_is_null(label_list->tstr_labels[n]); n++);
+        if(n == T_COSE_PARAMETER_LIST_MAX) {
+            /* List is full -- error out */
+            return_value = T_COSE_ERR_TOO_MANY_PARAMETERS;
+            goto Done;
+        }
+        label_list->tstr_labels[n] = item->label.string;
+    } else {
+        /* error because label is neither integer or string */
+        /* Should never occur because this is caught earlier, but
+         * leave it to be safe and because inlining and optimization
+         * should take out any unneeded code
+         */
+        return_value = T_COSE_ERR_PARAMETER_CBOR;
+    }
+
+Done:
+    return return_value;
+}
+
+
+
+
+/**
+ * \brief Decode the parameter containing the labels of parameters considered
+ *        critical.
+ *
+ * \param[in,out]  decode_context          Decode context to read critical
+ *                                         parameter list from.
+ * \param[in]      crit_parameter_item     Data item of array holding critical
+ *                                         labels.
+ * \param[out]     critical_labels         List of labels of critical
+ *                                         parameters.
+ * \param[out]     return_next_nest_level  Place to return nesting level of
+ *                                         next data item.
+ *
+ * \retval T_COSE_ERR_CBOR_NOT_WELL_FORMED  Undecodable CBOR.
+ * \retval T_COSE_ERR_TOO_MANY_PARAMETERS   More critical labels than this
+ *                                          implementation can handle.
+ * \retval T_COSE_ERR_PARAMETER_CBOR        Unexpected CBOR data type.
+ */
+static inline enum t_cose_err_t
+decode_critical_parameter(QCBORDecodeContext       *decode_context,
+                          const QCBORItem          *crit_parameter_item,
+                          struct t_cose_label_list *critical_labels,
+                          uint_fast8_t             *return_next_nest_level)
+{
+    /* Stack use 64-bit: 56 + 40 = 96
+     *           32-bit: 52 + 20 = 72
+     */
+    QCBORItem         item;
+    uint_fast8_t      num_int_labels;
+    uint_fast8_t      num_tstr_labels;
+    enum t_cose_err_t return_value;
+    QCBORError        cbor_result;
+    uint_fast8_t      next_nest_level;
+    uint_fast8_t      array_nest_level;
+
+    num_int_labels  = 0;
+    num_tstr_labels = 0;
+
+    array_nest_level = crit_parameter_item->uNestingLevel;
+    next_nest_level  = crit_parameter_item->uNextNestLevel;
+
+    if(crit_parameter_item->uDataType != QCBOR_TYPE_ARRAY) {
+        return_value = T_COSE_ERR_CRIT_PARAMETER;
+        goto Done;
+    }
+
+    while(next_nest_level > array_nest_level) {
+        cbor_result = QCBORDecode_GetNext(decode_context, &item);
+        if(cbor_result != QCBOR_SUCCESS) {
+            return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
+            goto Done;
+        }
+
+        if(item.uDataType == QCBOR_TYPE_INT64) {
+            if(num_int_labels >= T_COSE_PARAMETER_LIST_MAX) {
+                return_value = T_COSE_ERR_CRIT_PARAMETER;
+                goto Done;
+            }
+            critical_labels->int_labels[num_int_labels++] = item.val.int64;
+        } else if(item.uDataType == QCBOR_TYPE_TEXT_STRING) {
+            if(num_tstr_labels >= T_COSE_PARAMETER_LIST_MAX) {
+                return_value = T_COSE_ERR_CRIT_PARAMETER;
+                goto Done;
+            }
+            critical_labels->tstr_labels[num_tstr_labels++] = item.val.string;
+        } else {
+            return_value = T_COSE_ERR_CRIT_PARAMETER;
+            goto Done;
+        }
+        next_nest_level = item.uNextNestLevel;
+    }
+
+    if(is_label_list_clear(critical_labels)) {
+        /* Per RFC 8152 crit parameter can't be empty */
+        return_value = T_COSE_ERR_CRIT_PARAMETER;
+        goto Done;
+    }
+
+    return_value = T_COSE_SUCCESS;
+
+Done:
+    *return_next_nest_level = next_nest_level;
+    return return_value;
+}
+
+
+/**
+ * Public function. See t_cose_parameters.h
+ */
+enum t_cose_err_t
+check_critical_labels(const struct t_cose_label_list *critical_labels,
+                      const struct t_cose_label_list *unknown_labels)
+{
+    enum t_cose_err_t return_value;
+    uint_fast8_t      num_unknown;
+    uint_fast8_t      num_critical;
+
+    /* Assume success until an unhandled critical label is found */
+    return_value = T_COSE_SUCCESS;
+
+    /* Iterate over unknown integer parameters */
+    for(num_unknown = 0; unknown_labels->int_labels[num_unknown]; num_unknown++) {
+        /* Iterate over critical int labels looking for the unknown label */
+        for(num_critical = 0;
+            critical_labels->int_labels[num_critical];
+            num_critical++) {
+            if(critical_labels->int_labels[num_critical] == unknown_labels->int_labels[num_unknown]) {
+                /* Found a critical label that is unknown to us */
+                return_value = T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER;
+                goto Done;
+            }
+        }
+        /* Exit from loop here means all no unknown label was critical */
+    }
+
+    /* Iterate over unknown string labels */
+    for(num_unknown = 0; !q_useful_buf_c_is_null(unknown_labels->tstr_labels[num_unknown]); num_unknown++) {
+        /* iterate over critical string labels looking for the unknown param */
+        for(num_critical = 0; !q_useful_buf_c_is_null(critical_labels->tstr_labels[num_critical]); num_critical++) {
+            if(!q_useful_buf_compare(critical_labels->tstr_labels[num_critical],
+                                     unknown_labels->tstr_labels[num_unknown])){
+                /* Found a critical label that is unknown to us */
+                return_value = T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER;
+                goto Done;
+            }
+        }
+        /* Exit from loop here means all no unknown label was critical */
+    }
+
+Done:
+    return return_value;
+}
+
+
+
+
+/**
+ * \brief Add unknown parameter to unknown labels list and fully consume it
+ *
+ * \param[in] decode_context       CBOR decode context to read from.
+ * \param[in] unknown_parameter    The data item for the unknown parameter.
+ * \param[in,out] unknown_labels   The list of unknown labels to which to add
+ *                                 this new unknown label to.
+ * \param[out] next_nest_level     The nest level of the next item that will be
+ *                                 fetched. Helps to know if at end of list.
+ *
+ * \retval T_COSE_ERR_CBOR_NOT_WELL_FORMED  The CBOR is not well-formed.
+ * \retval T_COSE_ERR_TOO_MANY_PARAMETERS   The unknown labels list is full.
+ * \retval T_COSE_ERR_CBOR_STRUCTURE        The CBOR structure not as expected.
+ */
+static enum t_cose_err_t
+process_unknown_parameter(QCBORDecodeContext        *decode_context,
+                          const QCBORItem           *unknown_parameter,
+                          struct t_cose_label_list *unknown_labels,
+                          uint_fast8_t              *next_nest_level)
+{
+    enum t_cose_err_t return_value;
+
+    return_value = add_label_to_list(unknown_parameter, unknown_labels);
+    if(return_value) {
+        goto Done;
+    }
+
+    /* The full unknown parameter must be consumed. It could be
+     complex deeply-nested CBOR */
+    if(consume_item(decode_context, unknown_parameter, next_nest_level)) {
+        return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
+    }
+
+Done:
+    return return_value;
+}
+
+
+
+
+/**
+ * \brief Clear a struct t_cose_parameters to empty
+ *
+ * \param[in,out] parameters   Parameter list to clear.
+ */
+static inline void clear_cose_parameters(struct t_cose_parameters *parameters)
+{
+#if COSE_ALGORITHM_RESERVED != 0
+#error Invalid algorithm designator not 0. Parameter list initialization fails.
+#endif
+
+#if T_COSE_UNSET_ALGORITHM_ID != COSE_ALGORITHM_RESERVED
+#error Constant for unset algorithm ID not aligned with COSE_ALGORITHM_RESERVED
+#endif
+
+    /* This clears all the useful_bufs to NULL_Q_USEFUL_BUF_C
+     * and the cose_algorithm_id to COSE_ALGORITHM_RESERVED
+     */
+    memset(parameters, 0, sizeof(struct t_cose_parameters));
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+    /* The only non-zero clear-state value. (0 is plain text in CoAP
+     * content format) */
+    parameters->content_type_uint =  T_COSE_EMPTY_UINT_CONTENT_TYPE;
+#endif
+}
+
+
+/**
+ * \brief Parse some COSE header parameters.
+ *
+ * \param[in] decode_context        The QCBOR decode context to read from.
+ * \param[out] returned_parameters  The parsed parameters being returned.
+ *
+ * \retval T_COSE_SUCCESS                     The parameters were decoded
+ *                                            correctly.
+ * \retval T_COSE_ERR_PARAMETER_CBOR          CBOR is parsable, but not the
+ *                                            right structure (e.g. array
+ *                                            instead of a map)
+ * \retval T_COSE_ERR_TOO_MANY_PARAMETERS     More than
+ *                                            \ref T_COSE_PARAMETER_LIST_MAX
+ *                                            parameters.
+ * \retval T_COSE_ERR_CBOR_NOT_WELL_FORMED    The CBOR is not parsable.
+ * \retval T_COSE_ERR_NON_INTEGER_ALG_ID      The algorithm ID is not an
+ *                                            integer. This implementation
+ *                                            doesn't support string algorithm
+ *                                            IDs.
+ * \retval T_COSE_ERR_BAD_CONTENT_TYPE        Error in content type parameter.
+ * \retval T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER   A label marked critical is
+ *                                                 present and not understood.
+ *
+ * No parameters are mandatory. Which parameters were present or not
+ * is indicated in \c returned_parameters.  It is OK for there to be
+ * no parameters at all.
+ *
+ * The first item to be read from the decode_context must be the map
+ * data item that contains the parameters.
+ */
+static enum t_cose_err_t
+parse_cose_header_parameters(QCBORDecodeContext        *decode_context,
+                             struct t_cose_parameters  *returned_parameters,
+                             struct t_cose_label_list  *critical_labels,
+                             struct t_cose_label_list  *unknown_labels)
+{
+    /* Local stack use 64-bit: 56 + 24 + 488 = 568
+     * Local stack use 32-bit: 52 + 12 + 352 = 414
+     * Total stack use 64-bit: 568 + 96 + 50 = 694
+     * Total stack use 32-bit: 414 + 72 + 25 = 501
+     */
+    QCBORItem          item;
+    enum t_cose_err_t  return_value;
+    uint_fast8_t       map_nest_level;
+    uint_fast8_t       next_nest_level;
+    QCBORError         qcbor_result;
+
+    clear_cose_parameters(returned_parameters);
+
+    if(critical_labels != NULL) {
+        clear_label_list(critical_labels);
+    }
+
+    /* Get the data item that is the map that is being searched */
+    qcbor_result = QCBORDecode_GetNext(decode_context, &item);
+    if(qcbor_result == QCBOR_ERR_NO_MORE_ITEMS) {
+        return_value = T_COSE_SUCCESS;
+        goto Done;
+    }
+    if(qcbor_result != QCBOR_SUCCESS) {
+        return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
+        goto Done;
+    }
+    if(item.uDataType != QCBOR_TYPE_MAP) {
+        return_value = T_COSE_ERR_PARAMETER_CBOR;
+        goto Done;
+    }
+
+    /* Loop over all the items in the map. The map may contain further
+     * maps and arrays. This also needs to handle definite and
+     * indefinite length maps and array.
+     *
+     * map_nest_level is the nesting level of the data item opening
+     * the map that is being scanned. All data items inside this map
+     * have a nesting level greater than it. The data item following
+     * the map being scanned has a nesting level that is equal to or
+     * higher than map_nest_level.
+     */
+    map_nest_level  = item.uNestingLevel;
+    next_nest_level = item.uNextNestLevel;
+    while(next_nest_level > map_nest_level) {
+
+        if(QCBORDecode_GetNext(decode_context, &item) != QCBOR_SUCCESS) {
+            /* Got not-well-formed CBOR */
+            return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
+            goto Done;
+        }
+
+        if(item.uLabelType != QCBOR_TYPE_INT64) {
+            /* Non integer label. We don't handle those. */
+            return_value = process_unknown_parameter(decode_context,
+                                                  &item,
+                                                  unknown_labels,
+                                                  &next_nest_level);
+            if(return_value) {
+                goto Done;
+            }
+
+        } else {
+            next_nest_level = item.uNextNestLevel;
+            switch(item.label.int64) {
+
+            case COSE_HEADER_PARAM_ALG:
+                if(critical_labels == NULL) {
+                    return_value = T_COSE_ERR_PARAMETER_NOT_PROTECTED;
+                    goto Done;
+                }
+                if(item.uDataType != QCBOR_TYPE_INT64) {
+                    return_value = T_COSE_ERR_NON_INTEGER_ALG_ID;
+                    goto Done;
+                }
+                if(item.val.int64 == COSE_ALGORITHM_RESERVED || item.val.int64 > INT32_MAX) {
+                    return_value = T_COSE_ERR_NON_INTEGER_ALG_ID;
+                    goto Done;
+                }
+                if(returned_parameters->cose_algorithm_id != COSE_ALGORITHM_RESERVED) {
+                    return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+                    goto Done;
+                }
+                returned_parameters->cose_algorithm_id = (int32_t)item.val.int64;
+                break;
+
+            case COSE_HEADER_PARAM_KID:
+                if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+                    return_value = T_COSE_ERR_PARAMETER_CBOR;
+                    goto Done;
+                }
+                if(!q_useful_buf_c_is_null_or_empty(returned_parameters->kid)) {
+                    return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+                    goto Done;
+                }
+                returned_parameters->kid = item.val.string;
+                break;
+
+            case COSE_HEADER_PARAM_IV:
+                if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+                    return_value = T_COSE_ERR_PARAMETER_CBOR;
+                    goto Done;
+                }
+                if(!q_useful_buf_c_is_null_or_empty(returned_parameters->iv)) {
+                    return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+                    goto Done;
+                }
+                returned_parameters->iv = item.val.string;
+                break;
+
+            case COSE_HEADER_PARAM_PARTIAL_IV:
+                if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+                    return_value = T_COSE_ERR_PARAMETER_CBOR;
+                    goto Done;
+                }
+                if(!q_useful_buf_c_is_null_or_empty(returned_parameters->partial_iv)) {
+                    return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+                    goto Done;
+                }
+                returned_parameters->partial_iv = item.val.string;
+                break;
+
+            case COSE_HEADER_PARAM_CRIT:
+                if(critical_labels == NULL) {
+                    /* crit parameter occuring in non-protected bucket */
+                    return_value = T_COSE_ERR_PARAMETER_NOT_PROTECTED;
+                    goto Done;
+                }
+                if(!is_label_list_clear(critical_labels)) {
+                    /* Duplicate detection must be here because it is not
+                     * done in check_and_copy_parameters()
+                     */
+                    return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+                    goto Done;
+                }
+                /* decode_critical_parameter() consumes all the items in the
+                 * crit parameter array */
+                return_value = decode_critical_parameter(decode_context,
+                                                        &item,
+                                                         critical_labels,
+                                                        &next_nest_level);
+                if(return_value) {
+                    goto Done;
+                }
+                break;
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+            case COSE_HEADER_PARAM_CONTENT_TYPE:
+                if(item.uDataType == QCBOR_TYPE_TEXT_STRING) {
+                    if(!q_useful_buf_c_is_null_or_empty(returned_parameters->content_type_tstr)) {
+                        return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+                        goto Done;
+                    }
+                    returned_parameters->content_type_tstr = item.val.string;
+                } else if(item.uDataType == QCBOR_TYPE_INT64) {
+                    if(item.val.int64 < 0 || item.val.int64 > UINT16_MAX) {
+                        return_value = T_COSE_ERR_BAD_CONTENT_TYPE;
+                        goto Done;
+                    }
+                    if(returned_parameters->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) {
+                        return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+                        goto Done;
+                    }
+                    returned_parameters->content_type_uint = (uint32_t)item.val.int64;
+                } else {
+                    return_value = T_COSE_ERR_BAD_CONTENT_TYPE;
+                    goto Done;
+                }
+                break;
+#endif
+
+            default:
+                /* The parameter is not recognized. Its label has to
+                 * be added to the the list of unknown labels so it
+                 * can be checked against the list of critical labels.
+                 */
+                return_value = process_unknown_parameter(decode_context,
+                                                        &item,
+                                                         unknown_labels,
+                                                        &next_nest_level);
+                if(return_value) {
+                    goto Done;
+                }
+                break;
+            }
+        }
+    }
+    return_value = T_COSE_SUCCESS;
+
+Done:
+    return return_value;
+}
+
+
+/**
+ * Public function. See t_cose_parameters.h
+ */
+enum t_cose_err_t
+parse_protected_header_parameters(const struct q_useful_buf_c encoded_protected_parameters,
+                                  struct t_cose_parameters   *returned_params,
+                                  struct t_cose_label_list   *critical_labels,
+                                  struct t_cose_label_list   *unknown)
+{
+    /* Local stack use 64-bit: 144 + 8 = 152
+     * Local stack use 32-bit: 108 + 4 = 112
+     * Total stack use 64-bit: 694 + 144 = 838
+     * Total stack use 32-bit: 501 + 112 = 613
+     */
+    QCBORDecodeContext decode_context;
+    enum t_cose_err_t  return_value;
+
+    QCBORDecode_Init(&decode_context, encoded_protected_parameters, 0);
+
+    return_value = parse_cose_header_parameters(&decode_context,
+                                                 returned_params,
+                                                 critical_labels,
+                                                 unknown);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+    if(QCBORDecode_Finish(&decode_context)) {
+        /* A CBOR error here is always not-well-formed */
+        return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
+    }
+
+Done:
+    return return_value;
+}
+
+
+/*
+ * Static inline implementation. See documentation above.
+ */
+enum t_cose_err_t
+parse_unprotected_header_parameters(QCBORDecodeContext *decode_context,
+                                    struct t_cose_parameters *returned_params,
+                                    struct t_cose_label_list *unknown_labels)
+{
+    return parse_cose_header_parameters(decode_context,
+                                        returned_params,
+                                        NULL,
+                                        unknown_labels);
+}
+
+
+/**
+ * Public function. See t_cose_parameters.h
+ */
+enum t_cose_err_t
+check_and_copy_parameters(const struct t_cose_parameters  *protected,
+                          const struct t_cose_parameters  *unprotected,
+                          struct t_cose_parameters        *returned_params)
+{
+    enum t_cose_err_t return_value;
+
+    /* -- Copy all the unprotected parameters -- */
+    if(returned_params) {
+        *returned_params = *unprotected;
+    }
+
+    /* Go one at at time and check the protected parameters. If the
+     * parameter is not NULL and there is the same un protected
+     * parameter error out. If it is not NULL and there is no
+     * unprotected parameter, copy it */
+    if(protected->cose_algorithm_id != COSE_ALGORITHM_RESERVED) {
+        if(unprotected->cose_algorithm_id != COSE_ALGORITHM_RESERVED) {
+            return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+            goto Done;
+        }
+        if(returned_params) {
+            returned_params->cose_algorithm_id = protected->cose_algorithm_id;
+        }
+    }
+
+    if(!q_useful_buf_c_is_null_or_empty(protected->kid)) {
+        if(!q_useful_buf_c_is_null_or_empty(unprotected->kid)) {
+            return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+            goto Done;
+        }
+        if(returned_params) {
+            returned_params->kid = protected->kid;
+        }
+    }
+
+    if(!q_useful_buf_c_is_null_or_empty(protected->iv)) {
+        if( !q_useful_buf_c_is_null_or_empty(unprotected->iv)) {
+            return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+            goto Done;
+        }
+        if(returned_params) {
+            returned_params->iv = protected->iv;
+        }
+    }
+
+    if(!q_useful_buf_c_is_null_or_empty(protected->partial_iv)) {
+        if( !q_useful_buf_c_is_null_or_empty(unprotected->partial_iv)) {
+            return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+            goto Done;
+        }
+        if(returned_params) {
+            returned_params->partial_iv = protected->partial_iv;
+        }
+    }
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+    if(!q_useful_buf_c_is_null_or_empty(protected->content_type_tstr)) {
+        if( !q_useful_buf_c_is_null_or_empty(unprotected->content_type_tstr)) {
+            return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+            goto Done;
+        }
+        if(returned_params) {
+            returned_params->content_type_tstr = protected->content_type_tstr;
+        }
+    }
+
+    if(protected->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) {
+        if(unprotected->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) {
+            return_value = T_COSE_ERR_DUPLICATE_PARAMETER;
+            goto Done;
+        }
+        if(returned_params) {
+            returned_params->content_type_uint = protected->content_type_uint;
+        }
+    }
+#endif
+
+    return_value = T_COSE_SUCCESS;
+
+Done:
+    return return_value;
+}
+
diff --git a/lib/ext/t_cose/src/t_cose_parameters.h b/lib/ext/t_cose/src/t_cose_parameters.h
new file mode 100644
index 0000000..8a17cd2
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_parameters.h
@@ -0,0 +1,186 @@
+/*
+ * t_cose_parameters.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+
+#ifndef t_cose_parameters_h
+#define t_cose_parameters_h
+
+#include "t_cose_sign1_verify.h"
+#include "q_useful_buf.h"
+#include "t_cose_common.h"
+#include <stdint.h>
+#include "qcbor.h"
+
+
+/**
+ * \file t_cose_parameters.h
+ *
+ * \brief A list of COSE parameter labels, both integer and string.
+ *
+ * It is fixed size to avoid the complexity of memory management and
+ * because the number of parameters is assumed to be small.
+ *
+ * On a 64-bit machine it is 24 * PARAMETER_LIST_MAX which is 244
+ * bytes. That accommodates 10 string parameters and 10 integer parameters
+ * and is small enough to go on the stack.
+ *
+ * On a 32-bit machine: 16 * PARAMETER_LIST_MAX = 176
+ *
+ * This is a big consumer of stack in this implementation.  Some
+ * cleverness with a union could save almost 200 bytes of stack, as
+ * this is on the stack twice.
+ */
+struct t_cose_label_list {
+    /* Terminated by value LABEL_LIST_TERMINATOR */
+    int64_t int_labels[T_COSE_PARAMETER_LIST_MAX+1];
+    /*  Terminated by a NULL_Q_USEFUL_BUF_C */
+    struct q_useful_buf_c tstr_labels[T_COSE_PARAMETER_LIST_MAX+1];
+};
+
+
+/*
+ * The IANA COSE Header Parameters registry lists label 0 as
+ * "reserved". This means it can be used, but only by a revision of
+ * the COSE standard if it is deemed necessary for some large and good
+ * reason. It cannot just be allocated by IANA as any normal
+ * assignment. See [IANA COSE Registry]
+ * (https://www.iana.org/assignments/cose/cose.xhtml).  It is thus
+ * considered safe to use as the list terminator.
+ */
+#define LABEL_LIST_TERMINATOR 0
+
+
+/**
+ * \brief Clear a label list to empty.
+ *
+ * \param[in,out] list The list to clear.
+ */
+static void
+clear_label_list(struct t_cose_label_list *list);
+
+
+/**
+ * \brief Indicate whether label list is clear or not.
+ *
+ * \param[in,out] list  The list to check.
+ *
+ * \return true if the list is clear.
+ */
+static bool
+is_label_list_clear(const struct t_cose_label_list *list);
+
+
+/**
+ * \brief Check the unknown parameters against the critical labels list.
+ *
+ * \param[in] critical_labels  The list of critical labels.
+ * \param[in] unknown_labels   The parameter labels that occurred.
+ *
+ * \retval T_COSE_SUCCESS                         None of the unknown labels
+ *                                                are critical.
+ * \retval T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER  At least one of the unknown
+ *                                                labels is critical.
+ *
+ * Both lists are of parameter labels (CBOR keys). Check to see none of
+ * the parameter labels in the unknown list occur in the critical list.
+ */
+enum t_cose_err_t
+check_critical_labels(const struct t_cose_label_list *critical_labels,
+                      const struct t_cose_label_list *unknown_labels);
+
+
+
+/**
+ * \brief Parse the unprotected COSE header parameters.
+ *
+ * \param[in] decode_context        Decode context to read the parameters from.
+ * \param[out] returned_parameters  The parsed parameters.
+ *
+ * \returns The same as parse_cose_header_parameters().
+ *
+ * No parameters are mandatory. Which parameters were present or not is
+ * indicated in \c returned_parameters.  It is OK for there to be no
+ * parameters at all.
+ *
+ * The first item to be read from the decode_context must be the map
+ * data item that contains the parameters.
+ */
+enum t_cose_err_t
+parse_unprotected_header_parameters(QCBORDecodeContext       *decode_context,
+                                    struct t_cose_parameters *returned_parameters,
+                                    struct t_cose_label_list *unknown);
+
+
+/**
+ * \brief Parse the protected header parameters.
+ *
+ * \param[in] protected_parameters  Pointer and length of CBOR-encoded
+ *                                  protected parameters to parse.
+ * \param[out] returned_parameters  The parsed parameters that are returned.
+ *
+ * \retval T_COSE_SUCCESS                  Protected parameters were parsed.
+ * \retval T_COSE_ERR_CBOR_NOT_WELL_FORMED The CBOR formatting of the protected
+ *                                         parameters is unparsable.
+ *
+ * This parses the contents of the protected header parameters after the bstr
+ * wrapping is removed.
+ *
+ * This will error out if the CBOR is not well-formed, the protected
+ * header parameters are not a map, the algorithm ID is not found, or the
+ * algorithm ID is larger than \c INT32_MAX or smaller than \c
+ * INT32_MIN.
+ */
+enum t_cose_err_t
+parse_protected_header_parameters(const struct q_useful_buf_c protected_parameters,
+                                  struct t_cose_parameters   *returned_parameters,
+                                  struct t_cose_label_list   *critical,
+                                  struct t_cose_label_list   *unknown);
+
+
+/**
+ * \brief Copy and combine protected and unprotected parameters.
+ *
+ * \param[in] protected             The protected header parameters to copy.
+ * \param[in] unprotected           The unprotected header parameters to copy.
+ * \param[out] returned_parameters  Destination for copy.
+ *
+ * \retval T_COSE_ERR_DUPLICATE_PARAMETER  If the same parameter occurs in both
+ *                                         protected and unprotected.
+ * \retval T_COSE_SUCCESS                  If there were no duplicates and the
+ *                                         copy and combine succeeded.
+ *
+ * This merges the protected and unprotected parameters. The COSE standard
+ * does not allow a parameter to be duplicated in protected and unprotected so
+ * this checks and returns an error if so.
+ */
+enum t_cose_err_t
+check_and_copy_parameters(const struct t_cose_parameters  *protected,
+                          const struct t_cose_parameters  *unprotected,
+                          struct t_cose_parameters        *returned_parameters);
+
+
+
+/* ------------------------------------------------------------------------
+ * Inline implementations of public functions defined above.
+ */
+inline static void clear_label_list(struct t_cose_label_list *list)
+{
+    memset(list, 0, sizeof(struct t_cose_label_list));
+}
+
+
+inline static bool
+is_label_list_clear(const struct t_cose_label_list *list)
+{
+    return list->int_labels[0] == 0 &&
+           q_useful_buf_c_is_null_or_empty(list->tstr_labels[0]);
+}
+
+#endif /* t_cose_parameters_h */
diff --git a/lib/ext/t_cose/src/t_cose_sign1_sign.c b/lib/ext/t_cose/src/t_cose_sign1_sign.c
new file mode 100644
index 0000000..0169c83
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_sign1_sign.c
@@ -0,0 +1,467 @@
+/*
+ * t_cose_sign1_sign.c
+ *
+ * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "t_cose_sign1_sign.h"
+#include "qcbor.h"
+#include "t_cose_standard_constants.h"
+#include "t_cose_crypto.h"
+#include "t_cose_util.h"
+
+
+/**
+ * \file t_cose_sign1_sign.c
+ *
+ * \brief This implements t_cose signing
+ *
+ * Stack usage to sign is dependent on the signing alg and key size
+ * and type of hash implementation. t_cose_sign1_finish() is the main
+ * user of stack It is 384 for \ref COSE_ALGORITHM_ES256 and 778 for
+ * \ref COSE_ALGORITHM_ES512.
+ */
+
+
+/*
+ * Cross-check to make sure public definition of algorithm
+ * IDs matches the internal ones.
+ */
+#if T_COSE_ALGORITHM_ES256 != COSE_ALGORITHM_ES256
+#error COSE algorithm identifier definitions are in error
+#endif
+
+#if T_COSE_ALGORITHM_ES384 != COSE_ALGORITHM_ES384
+#error COSE algorithm identifier definitions are in error
+#endif
+
+#if T_COSE_ALGORITHM_ES512 != COSE_ALGORITHM_ES512
+#error COSE algorithm identifier definitions are in error
+#endif
+
+
+#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_indx;
+    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_indx = 0; array_indx < sig_size; array_indx += hash_to_sign.len) {
+        amount_to_copy = sig_size - array_indx;
+        if(amount_to_copy > hash_to_sign.len) {
+            amount_to_copy = hash_to_sign.len;
+        }
+        memcpy((uint8_t *)signature_buffer.ptr + array_indx,
+               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 the protected header parameters for COSE.
+ *
+ * \param[in] cose_algorithm_id      The COSE algorithm ID to put in the
+ *                                   header parameters.
+ * \param[in] buffer_for_parameters  Pointer and length of buffer into which
+ *                                   the resulting encoded protected
+ *                                   parameters is put. See return value.
+ *
+ * \return   The pointer and length of the encoded protected
+ *           parameters is returned, or \c NULL_Q_USEFUL_BUF_C if this fails.
+ *           This will have the same pointer as \c buffer_for_parameters,
+ *           but the pointer is conts and the length is that of the valid
+ *           data, not of the size of the buffer.
+ *
+ * The protected parameters are returned in fully encoded CBOR format as
+ * they are added to the \c COSE_Sign1 message 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_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             cose_algorithm_id,
+                            struct q_useful_buf buffer_for_parameters)
+{
+    /* approximate stack use on 32-bit machine:
+     *   CBOR encode context 148
+     *   local use: 20
+     *   total: 168
+     */
+    struct q_useful_buf_c protected_parameters;
+    QCBORError            qcbor_result;
+    QCBOREncodeContext    cbor_encode_ctx;
+    struct q_useful_buf_c return_value;
+
+    QCBOREncode_Init(&cbor_encode_ctx, buffer_for_parameters);
+    QCBOREncode_OpenMap(&cbor_encode_ctx);
+    QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
+                               COSE_HEADER_PARAM_ALG,
+                               cose_algorithm_id);
+    QCBOREncode_CloseMap(&cbor_encode_ctx);
+    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] me               The t_cose signing context.
+ * \param[in] kid              The key ID.
+ * \param[in] cbor_encode_ctx  CBOR encoding context to output to
+ *
+ * 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 kid and content type.
+ */
+static inline enum t_cose_err_t
+add_unprotected_parameters(const struct t_cose_sign1_sign_ctx *me,
+                           const struct q_useful_buf_c         kid,
+                           QCBOREncodeContext                 *cbor_encode_ctx)
+{
+    QCBOREncode_OpenMap(cbor_encode_ctx);
+
+    if(!q_useful_buf_c_is_null_or_empty(kid)) {
+        QCBOREncode_AddBytesToMapN(cbor_encode_ctx,
+                                   COSE_HEADER_PARAM_KID,
+                                   kid);
+    }
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+    if(me->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE &&
+       me->content_type_tstr != NULL) {
+        /* Both the string and int content types are not allowed */
+        return T_COSE_ERR_DUPLICATE_PARAMETER;
+    }
+
+
+    if(me->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) {
+        QCBOREncode_AddUInt64ToMapN(cbor_encode_ctx,
+                                    COSE_HEADER_PARAM_CONTENT_TYPE,
+                                    me->content_type_uint);
+    }
+
+    if(me->content_type_tstr != NULL) {
+        QCBOREncode_AddSZStringToMapN(cbor_encode_ctx,
+                                      COSE_HEADER_PARAM_CONTENT_TYPE,
+                                      me->content_type_tstr);
+    }
+#else
+    (void)me; /* avoid unused parameter warning */
+#endif
+
+    QCBOREncode_CloseMap(cbor_encode_ctx);
+
+    return T_COSE_SUCCESS;
+}
+
+
+/*
+ * Public function. See t_cose_sign1_sign.h
+ */
+enum t_cose_err_t
+t_cose_sign1_encode_parameters(struct t_cose_sign1_sign_ctx *me,
+                               QCBOREncodeContext           *cbor_encode_ctx)
+{
+    /* approximate stack use on 32-bit machine:
+     *    48 bytes local use
+     *   168 call to make_protected
+     *   216 total
+     */
+    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(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;
+    }
+    /* The use of _AddBytes here achieves the bstr wrapping */
+    QCBOREncode_AddBytes(cbor_encode_ctx, me->protected_parameters);
+
+    /* The Unprotected parameters */
+    /* Get the kid because it goes into the parameters that are about
+     * to be made. */
+    kid = me->kid;
+
+    if(me->option_flags & T_COSE_OPT_SHORT_CIRCUIT_SIG) {
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+        if(q_useful_buf_c_is_null_or_empty(kid)) {
+            /* No kid passed in, Use the short-circuit kid */
+            kid = get_short_circuit_kid();
+        }
+#else
+        return_value = T_COSE_ERR_SHORT_CIRCUIT_SIG_DISABLED;
+        goto Done;
+#endif
+    }
+
+    return_value = add_unprotected_parameters(me, kid, cbor_encode_ctx);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+    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.
+     */
+
+Done:
+    return return_value;
+}
+
+
+/*
+ * Public function. See t_cose_sign1_sign.h
+ */
+enum t_cose_err_t
+t_cose_sign1_encode_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 depending 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 total 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 that 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;
+    }
+
+    if (QCBOREncode_IsBufferNULL(cbor_encode_ctx)) {
+        /* Just calculating sizes. All that is needed is the signature
+         * size.
+         */
+        signature.ptr = NULL;
+        return_value  = t_cose_crypto_sig_size(me->cose_algorithm_id,
+                                               me->signing_key,
+                                              &signature.len);
+     } else {
+
+        /* 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) {
+            goto Done;
+        }
+
+        /* Compute the signature using public key crypto. The key and
+         * algorithm ID are passed in to know how and what to sign
+         * with. The hash of the TBS bytes is 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 works even if no public key algorithm is
+         * integrated.
+         */
+        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
+            /* Short-circuit signing */
+            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_sign1_sign.h
+ */
+enum t_cose_err_t
+t_cose_sign1_sign(struct t_cose_sign1_sign_ctx *me,
+                  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_encode_parameters(me, &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_encode_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/src/t_cose_sign1_verify.c b/lib/ext/t_cose/src/t_cose_sign1_verify.c
new file mode 100644
index 0000000..69404f3
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_sign1_verify.c
@@ -0,0 +1,239 @@
+/*
+ *  t_cose_sign1_verify.c
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+
+#include "t_cose_sign1_verify.h"
+#include "qcbor.h"
+#include "t_cose_crypto.h"
+#include "q_useful_buf.h"
+#include "t_cose_util.h"
+#include "t_cose_parameters.h"
+
+
+/**
+ * \file t_cose_sign1_verify.c
+ *
+ * \brief \c COSE_Sign1 verification implementation.
+ */
+
+
+
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+/**
+ *  \brief Verify a short-circuit signature
+ *
+ * \param[in] hash_to_verify  Pointer and length of hash to verify.
+ * \param[in] signature       Pointer and length of signature.
+ *
+ * \return This returns one of the error codes defined by \ref
+ *         t_cose_err_t.
+ *
+ * See t_cose_sign1_sign_init() for description of the short-circuit
+ * signature.
+ */
+static inline enum t_cose_err_t
+t_cose_crypto_short_circuit_verify(struct q_useful_buf_c hash_to_verify,
+                                   struct q_useful_buf_c signature)
+{
+    struct q_useful_buf_c hash_from_sig;
+    enum t_cose_err_t     return_value;
+
+    hash_from_sig = q_useful_buf_head(signature, hash_to_verify.len);
+    if(q_useful_buf_c_is_null(hash_from_sig)) {
+        return_value = T_COSE_ERR_SIG_VERIFY;
+        goto Done;
+    }
+
+    if(q_useful_buf_compare(hash_from_sig, hash_to_verify)) {
+        return_value = T_COSE_ERR_SIG_VERIFY;
+    } else {
+        return_value = T_COSE_SUCCESS;
+    }
+
+Done:
+    return return_value;
+}
+#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */
+
+
+/*
+ * Public function. See t_cose_sign1_verify.h
+ */
+enum t_cose_err_t
+t_cose_sign1_verify(struct t_cose_sign1_verify_ctx *me,
+                    struct q_useful_buf_c           cose_sign1,
+                    struct q_useful_buf_c          *payload,
+                    struct t_cose_parameters       *parameters)
+{
+    /* Stack use for 32-bit CPUs:
+     *   268 for local except hash output
+     *   32 to 64 local for hash output
+     *   220 to 434 to make TBS hash
+     * Total 420 to 768 depending on hash and EC alg.
+     * Stack used internally by hash and crypto is extra.
+     */
+    QCBORDecodeContext            decode_context;
+    QCBORItem                     item;
+    struct q_useful_buf_c         protected_parameters;
+    enum t_cose_err_t             return_value;
+    Q_USEFUL_BUF_MAKE_STACK_UB(   buffer_for_tbs_hash, T_COSE_CRYPTO_MAX_HASH_SIZE);
+    struct q_useful_buf_c         tbs_hash;
+    struct q_useful_buf_c         signature;
+    struct t_cose_parameters      unprotected_parameters;
+    struct t_cose_parameters      parsed_protected_parameters;
+    struct t_cose_label_list      critical_labels;
+    struct t_cose_label_list      unknown_labels;
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+    struct q_useful_buf_c         short_circuit_kid;
+#endif
+
+    *payload = NULL_Q_USEFUL_BUF_C;
+
+    QCBORDecode_Init(&decode_context, cose_sign1, QCBOR_DECODE_MODE_NORMAL);
+    /* Calls to QCBORDecode_GetNext() rely on item.uDataType != QCBOR_TYPE_ARRAY
+     * to detect decoding errors rather than checking the return code.
+     */
+
+    /* --  The array of four -- */
+    (void)QCBORDecode_GetNext(&decode_context, &item);
+    if(item.uDataType != QCBOR_TYPE_ARRAY) {
+        return_value = T_COSE_ERR_SIGN1_FORMAT;
+        goto Done;
+    }
+
+    if((me->option_flags & T_COSE_OPT_TAG_REQUIRED) &&
+       !QCBORDecode_IsTagged(&decode_context, &item, CBOR_TAG_COSE_SIGN1)) {
+        return_value = T_COSE_ERR_INCORRECTLY_TAGGED;
+        goto Done;
+    }
+
+    /* -- Clear list where uknown labels are accumulated -- */
+    clear_label_list(&unknown_labels);
+
+
+    /* --  Get the protected header parameters -- */
+    (void)QCBORDecode_GetNext(&decode_context, &item);
+    if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+        return_value = T_COSE_ERR_SIGN1_FORMAT;
+        goto Done;
+    }
+
+    protected_parameters = item.val.string;
+
+    return_value = parse_protected_header_parameters(protected_parameters,
+                                                    &parsed_protected_parameters,
+                                                    &critical_labels,
+                                                    &unknown_labels);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+
+    /* --  Get the unprotected parameters -- */
+    return_value = parse_unprotected_header_parameters(&decode_context,
+                                                       &unprotected_parameters,
+                                                       &unknown_labels);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+    if((me->option_flags & T_COSE_OPT_REQUIRE_KID) &&
+       q_useful_buf_c_is_null(unprotected_parameters.kid)) {
+        return_value = T_COSE_ERR_NO_KID;
+        goto Done;
+    }
+
+
+    /* -- Check critical parameter labels -- */
+    return_value = check_critical_labels(&unknown_labels, &critical_labels);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+    /* -- Check for duplicate parameters and copy to returned parameters -- */
+    return_value = check_and_copy_parameters(&parsed_protected_parameters,
+                                             &unprotected_parameters,
+                                              parameters);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+
+    /* -- Get the payload -- */
+    (void)QCBORDecode_GetNext(&decode_context, &item);
+    if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+        return_value = T_COSE_ERR_SIGN1_FORMAT;
+        goto Done;
+    }
+    *payload = item.val.string;
+
+
+    /* -- Get the signature -- */
+    (void)QCBORDecode_GetNext(&decode_context, &item);
+    if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+        return_value = T_COSE_ERR_SIGN1_FORMAT;
+        goto Done;
+    }
+    signature = item.val.string;
+
+
+    /* -- Finish up the CBOR decode -- */
+    /* This check make sure the array only had the expected four
+     * items. Works for definite and indefinte length arrays. Also
+     * make sure there were no extra bytes. */
+    if(QCBORDecode_Finish(&decode_context) != QCBOR_SUCCESS) {
+        return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
+        goto Done;
+    }
+
+
+    /* -- Skip signature verification if such is requested --*/
+    if(me->option_flags & T_COSE_OPT_DECODE_ONLY) {
+        return_value = T_COSE_SUCCESS;
+        goto Done;
+    }
+
+
+    /* -- Compute the TBS bytes -- */
+    return_value = create_tbs_hash(parsed_protected_parameters.cose_algorithm_id,
+                                   protected_parameters,
+                                   T_COSE_TBS_BARE_PAYLOAD,
+                                   *payload,
+                                   buffer_for_tbs_hash,
+                                   &tbs_hash);
+    if(return_value) {
+        goto Done;
+    }
+
+
+    /* -- Check for short-circuit signature and verify if it exists -- */
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+    short_circuit_kid = get_short_circuit_kid();
+    if(!q_useful_buf_compare(unprotected_parameters.kid, short_circuit_kid)) {
+        if(!(me->option_flags & T_COSE_OPT_ALLOW_SHORT_CIRCUIT)) {
+            return_value = T_COSE_ERR_SHORT_CIRCUIT_SIG;
+            goto Done;
+        }
+
+        return_value = t_cose_crypto_short_circuit_verify(tbs_hash, signature);
+        goto Done;
+    }
+#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */
+
+
+    /* -- Verify the signature (if it wasn't short-circuit) -- */
+    return_value = t_cose_crypto_pub_key_verify(parsed_protected_parameters.cose_algorithm_id,
+                                                me->verification_key,
+                                                unprotected_parameters.kid,
+                                                tbs_hash,
+                                                signature);
+
+Done:
+    return return_value;
+}
diff --git a/lib/ext/t_cose/src/t_cose_standard_constants.h b/lib/ext/t_cose/src/t_cose_standard_constants.h
new file mode 100644
index 0000000..886dc1f
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_standard_constants.h
@@ -0,0 +1,405 @@
+/*
+ * t_cose_standard_constants.h
+ *
+ * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#ifndef __T_COSE_STANDARD_CONSTANTS_H__
+#define __T_COSE_STANDARD_CONSTANTS_H__
+
+/**
+ * \file t_cose_standard_constants.h
+ *
+ * \brief Constants from COSE standard and IANA registry.
+ *
+ * This file contains constants identifiers defined in
+ * [COSE (RFC 8152)](https://tools.ietf.org/html/rfc8152) and
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ * They include algorithm IDs and other constants.
+ *
+ * Many constants in the IANA registry are not included here yet as
+ * they are not needed by t_cose. They can be added if they become
+ * needed.
+ *
+ * This file is not part of the t_cose public interface as it contains
+ * lots of stuff not needed in the public interface. The parts that
+ * are needed in the public interface are also defined as \ref
+ * T_COSE_ALGORITHM_ES256 and related (there is a pre processor cross
+ * check to make sure they don't get defined differently in
+ * t_cose_sign1_sign.c).
+ */
+
+
+/* --------------- COSE Header parameters -----------
+ * https://www.iana.org/assignments/cose/cose.xhtml#header-parameters
+ */
+
+/**
+ * \def COSE_HEADER_PARAM_ALG
+ *
+ * \brief Label of COSE parameter that indicates an algorithm.
+ *
+ * The algorithm assignments are found in the IANA registry here
+ * https://www.iana.org/assignments/cose/cose.xhtml#algorithms
+ * Signing algorithms are identified as combinations of the
+ * public key algorithm, padding mode and hash. This must be
+ * a protected header. They may be string or integers. This
+ * implementation only support integer IDs.
+ */
+#define COSE_HEADER_PARAM_ALG 1
+
+
+/**
+ * \def COSE_HEADER_PARAM_CRIT
+ *
+ * \brief Label of COSE parameter listing critical header parameters
+ *
+ * The contents is an array of header parameter labels, either string or
+ * integer. The implementation must know how to process them or it is
+ * an error.
+ */
+#define COSE_HEADER_PARAM_CRIT 2
+
+
+/**
+ * \def COSE_HEADER_PARAM_CONTENT_TYPE
+ *
+ * \brief Label of COSE parameter with the content type
+ *
+ * Either an integer CoAP content type or a string MIME type. This is
+ * the type of the data in the payload.
+ */
+#define COSE_HEADER_PARAM_CONTENT_TYPE 3
+
+
+/**
+ * \def COSE_HEADER_PARAM_KID
+ *
+ * \brief CBOR map label of COSE parameter that contains a kid (key ID).
+ *
+ * The kid is a byte string identifying the key. It is optional and
+ * there is no required format. They are not even required to be
+ * unique.
+ */
+#define COSE_HEADER_PARAM_KID 4
+
+
+/**
+ * \def COSE_HEADER_PARAM_IV
+ *
+ * \brief CBOR map label of parameter that contains an initialization
+ * vector.
+ *
+ * A binary string initialization vector.
+ *
+ * This implementation only parses this.
+ */
+#define COSE_HEADER_PARAM_IV 5
+
+
+/**
+ * \def COSE_HEADER_PARAM_PARTIAL_IV
+ *
+ * \brief CBOR map label of parameter containing partial
+ * initialization vector.
+ *
+ * A binary string partial initialization vector.
+ *
+ * This implementation only parses this.
+ */
+#define COSE_HEADER_PARAM_PARTIAL_IV 6
+
+
+/**
+ * \def COSE_HEADER_PARAM_COUNTER_SIGNATURE
+ *
+ * \brief CBOR map label of parameter that holds one or more counter signature.
+ *
+ * Counter signatures can be full \c COSE_Sign1, \c COSE_Signature and
+ * such messages.  This implementation doesn't support them.
+ */
+#define COSE_HEADER_PARAM_COUNTER_SIGNATURE 6
+
+
+
+
+
+/* ------------ COSE Header Algorithm Parameters --------------
+ * https://www.iana.org/assignments/cose/cose.xhtml#header-algorithm-parameters
+ *
+ * None of these are defined here yet, as they are not needed by t_cose yet.
+ */
+
+
+
+
+/* ------------- COSE Algorithms ----------------------------
+ * https://www.iana.org/assignments/cose/cose.xhtml#algorithms
+ */
+
+/**
+ * This is defined as reserved by IANA. This implementation uses it to
+ * mean the end of a list of algorithm IDs or an unset algorithm ID.
+ */
+#define COSE_ALGORITHM_RESERVED 0
+
+
+/**
+ * \def COSE_ALGORITHM_ES256
+ *
+ * \brief Indicates ECDSA with SHA-256.
+ *
+ * Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA with SHA-256.
+ *
+ * RFC 8152 section 8.1 suggests, but does not require, that this
+ * algorithm identifier only be used with keys based on the P-256
+ * curve (also known as prime256v1 or secp256r1).
+ *
+ * See https://tools.ietf.org/search/rfc4492 and https://tools.ietf.org/html/rfc8152
+ */
+#define COSE_ALGORITHM_ES256 -7
+
+/**
+ * \def COSE_ALGORITHM_ES384
+ *
+ * \brief Indicates ECDSA with SHA-384.
+ *
+ * See discussion on \ref COSE_ALGORITHM_ES256.
+ *
+ * RFC 8152 section 8.1 suggests, but does not require, that this
+ * algorithm identifier be used only with keys based on the P-384
+ * curve (also known as secp384r1).
+ */
+#define COSE_ALGORITHM_ES384 -35
+
+/**
+ * \def COSE_ALGORITHM_ES512
+ *
+ * \brief Indicates ECDSA with SHA-512.
+ *
+ * See discussion on \ref COSE_ALGORITHM_ES256.
+ *
+ * RFC 8152 section 8.1 suggests, but does not require, that this
+ * algorithm identifier be used only with keys based on the P-521
+ * curve (also known as secp521r1)
+ */
+#define COSE_ALGORITHM_ES512 -36
+
+
+/**
+ * \def COSE_ALGORITHM_SHA_256
+ *
+ * \brief Indicates simple SHA-256 hash.
+ *
+ * This is not used in the t_cose interface, just used internally.
+ */
+#define COSE_ALGORITHM_SHA_256 -16
+
+/**
+ * \def COSE_ALGORITHM_SHA_384
+ *
+ * \brief Indicates simple SHA-384 hash.
+ *
+ * This is not used in the t_cose interface, just used internally.
+ */
+#define COSE_ALGORITHM_SHA_384 -43
+
+/**
+ * \def COSE_ALGORITHM_SHA_512
+ *
+ * \brief Indicates simple SHA-512 hash.
+ *
+ * This is not used in the t_cose interface, just used internally.
+ */
+#define COSE_ALGORITHM_SHA_512 -44
+
+
+
+
+/* ---------- COSE Key Common Parameters --------------
+ * https://www.iana.org/assignments/cose/cose.xhtml#key-common-parameters
+ */
+
+/**
+ * \def COSE_KEY_COMMON_KTY
+ *
+ * \brief Label for data item containing the key type.
+ *
+ * In a \c COSE_Key, label that indicates the data item containing the
+ * key type.
+ */
+#define COSE_KEY_COMMON_KTY  1
+
+/**
+ * \def COSE_KEY_COMMON_KID
+ *
+ * \brief Label for data item containing the key's kid.
+ *
+ * In a \c COSE_Key, label that indicates the data item containing the
+ * kid of this key.
+ */
+#define COSE_KEY_COMMON_KID  2
+
+
+
+
+/* ---------- COSE Key Type Parameters --------------------
+ * https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters
+ *
+ * These are not used by this implementation.
+ */
+
+/**
+ * \def COSE_KEY_PARAM_CRV
+ *
+ * \brief Label for data item indicating EC curve.
+ *
+ * In a \c COSE_Key that holds an EC key of either type \ref
+ * COSE_KEY_TYPE_EC2 or \ref COSE_KEY_TYPE_OKP this labels the data
+ * item with the EC curve for the key.
+ */
+#define COSE_KEY_PARAM_CRV           -1
+
+/**
+ * \def COSE_KEY_PARAM_X_COORDINATE
+ *
+ * \brief Label for data item that is an X coordinate of an EC key.
+ *
+ * In a \c COSE_Key that holds an EC key, this is label that indicates
+ * the data item containing the X coordinate.
+ *
+ * This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref
+ * COSE_KEY_TYPE_OKP.
+ */
+#define COSE_KEY_PARAM_X_COORDINATE  -2
+
+/**
+ * \def COSE_KEY_PARAM_Y_COORDINATE
+ *
+ * \brief Label for data item that is a y coordinate of an EC key.
+ *
+ * In a COSE_Key that holds an EC key, this is label that indicates
+ * the data item containing the Y coordinate.
+ *
+ * This is used only for key type \ref COSE_KEY_TYPE_EC2.
+ */
+#define COSE_KEY_PARAM_Y_COORDINATE  -3
+
+/**
+ * \def COSE_KEY_PARAM_PRIVATE_D
+ *
+ * \brief Label for data item that is d, the private part of EC key.
+ *
+ * In a \c COSE_Key that holds an EC key, this is label that indicates
+ * the data item containing the Y coordinate.
+ *
+ * This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref
+ * COSE_KEY_TYPE_OKP.
+ */
+#define COSE_KEY_PARAM_PRIVATE_D  -4
+
+
+
+
+/* ---------- COSE Key Types --------------------------------
+ * https://www.iana.org/assignments/cose/cose.xhtml#key-type
+ */
+
+/**
+ * \def COSE_KEY_TYPE_OKP
+ *
+ * \brief Key type is Octet Key Pair
+ *
+ * In a \c COSE_Key, this is a value of the data item labeled \ref
+ * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is some sort of
+ * key pair represented by some octets. It may or may not be an EC
+ * key.
+ */
+#define COSE_KEY_TYPE_OKP       1
+
+/**
+ * \def COSE_KEY_TYPE_EC2
+ *
+ * \brief Key is a 2-parameter EC key.
+ *
+ * In a \c COSE_Key, this is a value of the data item labeled \ref
+ * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is an EC key
+ * specified with two coordinates, X and Y.
+ */
+#define COSE_KEY_TYPE_EC2       2
+
+/**
+ * \def COSE_KEY_TYPE_SYMMETRIC
+ *
+ * \brief Key is a symmetric key.
+ *
+ * In a \c COSE_Key, this is a value of the data item labeled \ref
+ * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is a symmetric
+ * key.
+ */
+#define COSE_KEY_TYPE_SYMMETRIC  4
+
+
+
+
+/* ----------- COSE Elliptic Curves ---------------------
+ * https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves
+ */
+
+/**
+ * \def COSE_ELLIPTIC_CURVE_P_256
+ *
+ * \brief Key type for NIST P-256 key
+ *
+ * In a \c COSE_Key, this is a value of the data item labeled \ref
+ * COSE_KEY_PARAM_CRV to indicate the NIST P-256 curve, also known as
+ * secp256r1.
+ *
+ * This key type is always \ref COSE_KEY_TYPE_EC2.
+ */
+#define COSE_ELLIPTIC_CURVE_P_256 1
+
+/**
+ * \def COSE_ELLIPTIC_CURVE_P_384
+ *
+ * \brief Key type for NIST P-384 key
+ *
+ * In a \c COSE_Key, this is a value of the data item labeled \ref
+ * COSE_KEY_PARAM_CRV to indicate the NIST P-384 curve, also known as
+ * secp384r1.
+ *
+ * This key type is always \ref COSE_KEY_TYPE_EC2.
+ */
+#define COSE_ELLIPTIC_CURVE_P_384 2
+
+/**
+ * \def COSE_ELLIPTIC_CURVE_P_521
+ *
+ * \brief Key type for NIST P-521 key
+ *
+ * In a \c COSE_Key, this is a value of the data item labeled \ref
+ * COSE_KEY_PARAM_CRV to indicate the NIST P-521 curve, also known as
+ * secp521r1.
+ */
+#define COSE_ELLIPTIC_CURVE_P_521 3
+
+
+
+
+/* ------- Constants from RFC 8152 ---------
+ */
+
+/**
+ * \def COSE_SIG_CONTEXT_STRING_SIGNATURE1
+ *
+ * \brief This is a string constant used by COSE to label \c
+ * COSE_Sign1 structures. See RFC 8152, section 4.4.
+ */
+#define COSE_SIG_CONTEXT_STRING_SIGNATURE1 "Signature1"
+
+
+#endif /* __T_COSE_STANDARD_CONSTANTS_H__ */
diff --git a/lib/ext/t_cose/src/t_cose_util.c b/lib/ext/t_cose/src/t_cose_util.c
new file mode 100644
index 0000000..a0fae2d
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_util.c
@@ -0,0 +1,228 @@
+/*
+ *  t_cose_util.c
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "t_cose_util.h"
+#include "qcbor.h"
+#include "t_cose_standard_constants.h"
+#include "t_cose_common.h"
+#include "t_cose_crypto.h"
+
+
+/**
+ * \file t_cose_util.c
+ *
+ * \brief Implementation of t_cose utility functions.
+ *
+ * These are some functions common to signing and verification,
+ * primarily the to-be-signed bytes hashing.
+ */
+
+
+/*
+ * Public function. See t_cose_util.h
+ */
+int32_t hash_alg_id_from_sig_alg_id(int32_t cose_algorithm_id)
+{
+    /* If other hashes, particularly those that output bigger hashes
+     * are added here, various other parts of this code have to be
+     * changed to have larger buffers, in particular
+     * \ref T_COSE_CRYPTO_MAX_HASH_SIZE.
+     */
+    /* ? : operator precedence is correct here. This makes smaller
+     * code than a switch statement and is easier to read.
+     */
+    return cose_algorithm_id == COSE_ALGORITHM_ES256 ? COSE_ALGORITHM_SHA_256 :
+#ifndef T_COSE_DISABLE_ES384
+           cose_algorithm_id == COSE_ALGORITHM_ES384 ? COSE_ALGORITHM_SHA_384 :
+#endif
+#ifndef T_COSE_DISABLE_ES512
+           cose_algorithm_id == COSE_ALGORITHM_ES512 ? COSE_ALGORITHM_SHA_512 :
+#endif
+                                                       T_COSE_INVALID_ALGORITHM_ID;
+}
+
+
+/*
+ * Format of to-be-signed bytes used by create_tbs_hash().  This is
+ * defined in COSE (RFC 8152) section 4.4. It is the input to the
+ * hash.
+ *
+ * Sig_structure = [
+ *    context : "Signature" / "Signature1" / "CounterSignature",
+ *    body_protected : empty_or_serialized_map,
+ *    ? sign_protected : empty_or_serialized_map,
+ *    external_aad : bstr,
+ *    payload : bstr
+ * ]
+ *
+ * body_protected refers to the protected parameters from the
+ * main COSE_Sign1 structure. This is a little hard to
+ * to understand in the spec.
+ *
+ * sign_protected is not used with COSE_Sign1 since there is no signer
+ * chunk.
+ *
+ * external_aad allows external data to be covered by the hash, but is
+ * not supported by this implementation.
+ */
+
+
+/**
+ * This is the size of the first part of the CBOR encoded TBS
+ * bytes. It is around 30 bytes. See create_tbs_hash().
+ */
+#define T_COSE_SIZE_OF_TBS \
+    1 + /* For opening the array */ \
+    sizeof(COSE_SIG_CONTEXT_STRING_SIGNATURE1) + /* "Signature1" */ \
+    2 + /* Overhead for encoding string */ \
+    T_COSE_SIGN1_MAX_SIZE_PROTECTED_PARAMETERS + /* entire protected params */ \
+    1 + /* Empty bstr for absent external_aad */ \
+    9 /* The max CBOR length encoding for start of payload */
+
+
+/*
+ * Public function. See t_cose_util.h
+ */
+enum t_cose_err_t create_tbs_hash(int32_t                     cose_algorithm_id,
+                                  struct q_useful_buf_c       protected_parameters,
+                                  enum t_cose_tbs_hash_mode_t payload_mode,
+                                  struct q_useful_buf_c       payload,
+                                  struct q_useful_buf         buffer_for_hash,
+                                  struct q_useful_buf_c      *hash)
+{
+    /* approximate stack use on 32-bit machine:
+     *    210 bytes for all but hash context
+     *    8 to 224 of hash context depending on hash implementation
+     *    220 to 434 bytes total
+     */
+    enum t_cose_err_t           return_value;
+    QCBOREncodeContext          cbor_encode_ctx;
+    UsefulBuf_MAKE_STACK_UB(    buffer_for_TBS_first_part, T_COSE_SIZE_OF_TBS);
+    struct q_useful_buf_c       tbs_first_part;
+    QCBORError                  qcbor_result;
+    struct t_cose_crypto_hash   hash_ctx;
+    int32_t                     hash_alg_id;
+    size_t                      bytes_to_omit;
+
+    /* This builds the CBOR-format to-be-signed bytes */
+    QCBOREncode_Init(&cbor_encode_ctx, buffer_for_TBS_first_part);
+    QCBOREncode_OpenArray(&cbor_encode_ctx);
+
+    /* context */
+    QCBOREncode_AddSZString(&cbor_encode_ctx, COSE_SIG_CONTEXT_STRING_SIGNATURE1);
+    /* body_protected */
+    QCBOREncode_AddBytes(&cbor_encode_ctx, protected_parameters);
+
+    /* sign_protected is not used for COSE_Sign1 */
+
+    /* external_aad. There is none so an empty bstr */
+    QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_Q_USEFUL_BUF_C);
+
+    /* The short fake payload */
+    if(payload_mode == T_COSE_TBS_PAYLOAD_IS_BSTR_WRAPPED) {
+        /* Fake payload is just an empty bstr. It is here only
+         * to make the array count right. It must be ommitted
+         * in the actual hashing below.
+         */
+        bytes_to_omit = 1;
+        QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_Q_USEFUL_BUF_C);
+    } else {
+        /* Fake payload is the type and length of the wrapping
+         * bstr. It gets hashed with the first part, so no bytes to
+         * omit.
+         */
+        bytes_to_omit = 0;
+        QCBOREncode_AddBytesLenOnly(&cbor_encode_ctx, payload);
+    }
+    /* Cleverness only works because the payload is last in the array */
+
+    /* Close off the array */
+    QCBOREncode_CloseArray(&cbor_encode_ctx);
+
+    /* get the encoded results, except for payload */
+    qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &tbs_first_part);
+    if(qcbor_result) {
+        /* Mainly means that the protected_parameters were too big
+         * (which should never happen) */
+        return_value = T_COSE_ERR_SIG_STRUCT;
+        goto Done;
+    }
+
+    /* Start the hashing */
+    hash_alg_id = hash_alg_id_from_sig_alg_id(cose_algorithm_id);
+    /* Don't check hash_alg_id for failure. t_cose_crypto_hash_start()
+     * will handle error properly. It was also checked earlier.
+     */
+    return_value = t_cose_crypto_hash_start(&hash_ctx, hash_alg_id);
+    if(return_value) {
+        goto Done;
+    }
+
+    /* This structure is hashed in two parts. The first part is
+     * the CBOR-formatted array with protected parameters and such.
+     * The last part is the actual bytes of the payload. Doing it
+     * this way avoids having to allocate a big buffer to hold
+     * these two parts together.  It avoids having two copies of
+     * the payload in the implementaiton as the payload as formatted
+     * in the output buffer can be what is hashed. They payload
+     * is the largest memory use, so this saves a lot.
+     *
+     * This is further complicated because the the payload does have
+     * to be wrapped in a bstr. It is done one way when signing and
+     * another when verifying.
+     */
+
+    /* This is the hashing of the first part, all the CBOR except the
+     * payload.
+     */
+    t_cose_crypto_hash_update(&hash_ctx,
+                              q_useful_buf_head(tbs_first_part,
+                                                tbs_first_part.len - bytes_to_omit));
+
+    /* Hash the payload, the second part. This may or may not have the
+     * bstr wrapping. If not, it was hashed above.
+     */
+    t_cose_crypto_hash_update(&hash_ctx, payload);
+
+    /* Finish the hash and set up to return it */
+    return_value = t_cose_crypto_hash_finish(&hash_ctx,
+                                             buffer_for_hash,
+                                             hash);
+Done:
+    return return_value;
+}
+
+
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+/* This is a random hard coded kid (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 short_circuit_kid;
+
+/*
+ * Public function. See t_cose_util.h
+ */
+struct q_useful_buf_c get_short_circuit_kid(void)
+{
+    short_circuit_kid.len = sizeof(defined_short_circuit_kid);
+    short_circuit_kid.ptr = defined_short_circuit_kid;
+
+    return short_circuit_kid;
+}
+#endif
diff --git a/lib/ext/t_cose/src/t_cose_util.h b/lib/ext/t_cose/src/t_cose_util.h
new file mode 100644
index 0000000..b171d03
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_util.h
@@ -0,0 +1,166 @@
+/*
+ *  t_cose_util.h
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+
+#ifndef __T_COSE_UTIL_H__
+#define __T_COSE_UTIL_H__
+
+#include <stdint.h>
+#include "q_useful_buf.h"
+#include "t_cose_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file t_cose_util.h
+ *
+ * \brief Utility functions used internally by the t_cose implementation.
+ *
+ */
+
+
+/**
+ * The modes in which the payload is passed to create_tbs_hash().
+ * This exists so the TBS bytes can be hashed in two separate chunks
+ * and avoids needing a second buffer the size of the payload in the
+ * t_cose implementation.
+ */
+enum t_cose_tbs_hash_mode_t {
+    /** The bytes passed for the payload include a wrapping bstr so
+     * one does not need to be added.
+     */
+    T_COSE_TBS_PAYLOAD_IS_BSTR_WRAPPED,
+    /** The bytes passed for the payload do NOT have a wrapping bstr
+     * so one must be added.
+     */
+    T_COSE_TBS_BARE_PAYLOAD
+};
+
+
+
+/**
+ * This value represents an invalid or in-error algorithm ID.  The
+ * value selected is 0 as this is reserved in the IANA COSE algorithm
+ * registry and is very unlikely to ever be used.  (It would take am
+ * IETF standards-action to put it to use).
+ */
+#define T_COSE_INVALID_ALGORITHM_ID COSE_ALGORITHM_RESERVED
+
+
+/**
+ * \brief Return hash algorithm ID from a signature algorithm ID
+ *
+ * \param[in] cose_algorithm_id  A COSE signature algorithm identifier.
+ *
+ * \return \c T_COSE_INVALID_ALGORITHM_ID when the signature algorithm ID
+              is not known.
+ *
+ * This works off of algorithm identifiers defined in the
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ * Corresponding local integer constants are defined in
+ * t_cose_standard_constants.h.
+ *
+ * COSE signing algorithms are the combination of public key
+ * algorithm, hash algorithm and hash size and imply an appropriate
+ * key size.  They are simple integers making them convenient for
+ * direct use in code.
+ *
+ * This function returns an identifier for only the hash algorithm
+ * from the combined identifier.
+ *
+ * If the needed algorithm identifiers are not in the IANA registry,
+ * they can be added to it. This will take some time and work.  It is
+ * also fine to use algorithms in the COSE proprietary space.
+ */
+int32_t hash_alg_id_from_sig_alg_id(int32_t cose_algorithm_id);
+
+
+/**
+ * \brief Create the hash of the to-be-signed (TBS) bytes for COSE.
+ *
+ * \param[in] cose_algorithm_id     The COSE signing algorithm ID. Used to
+ *                                  determine which hash function to use.
+ * \param[in] protected_parameters  Full, CBOR encoded, protected parameters.
+ * \param[in] payload_mode          See \ref t_cose_tbs_hash_mode_t.
+ * \param[in] payload               The CBOR encoded payload. It may or may
+ *                                  not have a wrapping bstr per
+ *                                  \c payload_mode.
+ * \param[in] buffer_for_hash       Pointer and length of buffer into which
+ *                                  the resulting hash is put.
+ * \param[out] hash                 Pointer and length of the
+ *                                  resulting hash.
+ *
+ * \return This returns one of the error codes defined by \ref t_cose_err_t.
+ *
+ * \retval T_COSE_ERR_SIG_STRUCT
+ *         Most likely this is because the protected_parameters passed in
+ *         is larger than \c T_COSE_SIGN1_MAX_SIZE_PROTECTED_PARAMETERS.
+ * \retval T_COSE_ERR_UNSUPPORTED_HASH
+ *         If the hash algorithm is not known.
+ * \retval T_COSE_ERR_HASH_GENERAL_FAIL
+ *         In case of some general hash failure.
+ *
+ * The input to the public key signature algorithm in COSE is the hash
+ * of a CBOR encoded structure containing the protected parameters
+ * algorithm ID and a few other things. This formats that structure
+ * and computes the hash of it. These are known as the to-be-signed or
+ * "TBS" bytes. The exact specification is in
+ * [RFC 8152 section 4.4](https://tools.ietf.org/html/rfc8152#section-4.4).
+ */
+enum t_cose_err_t create_tbs_hash(int32_t                     cose_algorithm_id,
+                                  struct q_useful_buf_c       protected_parameters,
+                                  enum t_cose_tbs_hash_mode_t payload_mode,
+                                  struct q_useful_buf_c       payload,
+                                  struct q_useful_buf         buffer_for_hash,
+                                  struct q_useful_buf_c      *hash);
+
+
+
+
+#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
+
+/**
+ * Size of the key returned by get_short_circuit_kid(). It is always
+ * this size.
+ */
+#define T_COSE_SHORT_CIRCUIT_KID_SIZE 32
+
+
+/**
+ * \brief Get the special kid for short-circuit signing.
+ *
+ * \returns Buffer with the kid.
+ *
+ * This always returns the same kid. It always indicates short-circuit
+ * signing. It is OK to hard code this kid value as the probability of
+ * collision with this ID is extremely low and the same as for
+ * collision between any two key IDs (kids) of any sort.
+ *
+ * This always returns a pointer to the same memory as the result
+ * returned by this never changes.
+ *
+ * This is the value of the 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
+ *
+ */
+struct q_useful_buf_c get_short_circuit_kid(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __T_COSE_UTIL_H__ */
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 */