aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--GNUmakefile8
-rw-r--r--README.md67
-rw-r--r--asn1.c227
-rw-r--r--asn1_internal.h108
-rw-r--r--csprng.c50
-rw-r--r--ecdsa.c1545
-rw-r--r--ecdsa_curves.h92
-rw-r--r--hal.h142
-rw-r--r--hal_io_eim.c6
-rw-r--r--hal_io_i2c.c6
-rw-r--r--hash.c195
-rw-r--r--novena-eim.c16
-rw-r--r--pbkdf2.c2
-rw-r--r--rsa.c353
-rw-r--r--tests/GNUmakefile2
-rw-r--r--tests/test-ecdsa.c326
-rw-r--r--tests/test-ecdsa.h329
-rw-r--r--tests/test-ecdsa.py156
-rw-r--r--tests/test-hash.c4
-rw-r--r--tests/test-pbkdf2.c2
-rw-r--r--tests/test-rsa.c4
22 files changed, 3215 insertions, 426 deletions
diff --git a/.gitignore b/.gitignore
index 137543e..7428ea1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ autom4te.cache
config.log
config.status
tests/test-aes-key-wrap
+tests/test-ecdsa
tests/test-hash
tests/test-pbkdf2
tests/test-rsa
diff --git a/GNUmakefile b/GNUmakefile
index 82ec7ec..f425c50 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -28,7 +28,7 @@
INC = hal.h
LIB = libhal.a
OBJ = ${IO_OBJ} csprng.o hash.o aes_keywrap.o pbkdf2.o \
- modexp.o rsa.o errorstrings.o
+ modexp.o rsa.o ecdsa.o asn1.o errorstrings.o
IO_OBJ_EIM = hal_io_eim.o novena-eim.o
IO_OBJ_I2C = hal_io_i2c.o
@@ -37,7 +37,7 @@ IO_OBJ_I2C = hal_io_i2c.o
IO_OBJ = ${IO_OBJ_EIM}
TFMDIR := $(abspath ../thirdparty/libtfm)
-CFLAGS := -g3 -Wall -fPIC -std=c99 -I${TFMDIR}
+CFLAGS := -g3 -Wall -fPIC -std=c99 -I${TFMDIR} -DHAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM=1
LDFLAGS := -g3 -L${TFMDIR} -ltfm
all: ${LIB}
@@ -49,6 +49,10 @@ ${OBJ}: ${INC}
${LIB}: ${OBJ}
ar rcs $@ $^
+asn1.o rsa.o ecdsa.o: asn1_internal.h
+
+ecdsa.o: ecdsa_curves.h
+
test: all
cd tests; ${MAKE} -k $@
diff --git a/README.md b/README.md
index 66669e3..71fc0a0 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
libhal
======
+## Overview ##
+
This library combines a set of low-level API functions which talk to
the Cryptech FPGA cores with a set of higher-level functions providing
various cryptographic services.
@@ -25,16 +27,21 @@ Current contents of the library:
* An implementation of RSA using the Cryptech ModExp core.
+* An implementation of ECDSA, currently entirely in software.
+
* Test code for all of the above.
Most of these are fairly well self-contained, although the PBKDF2
implementation uses the hash-core-based HMAC implementation.
-The major exception is the RSA implementation, which uses an external
-bignum implementation (libtfm) to handle a lot of the arithmetic. In
-the long run, much or all of this may end up being implemented in
-Verilog, but for the moment all of the RSA math except for modular
-exponentiation is happening in software.
+The major exceptions are the RSA and ECDSA implementations, which uses
+an external bignum implementation (libtfm) to handle a lot of the
+arithmetic. In the long run, much or all of this may end up being
+implemented in Verilog, but for the moment all of the RSA math except
+for modular exponentiation is happening in software, as is all of the
+math for ECDSA.
+
+## RSA ##
The RSA implementation includes a compile-time option to bypass the
ModExp core and do everything in software, because the ModExp core is
@@ -44,3 +51,53 @@ The RSA implementation includes optional blinding (enabled by default)
and just enough ASN.1 code to read and write private keys; the
expectation is that the latter will be used in combination with the
AES Key Wrap code.
+
+## ECDSA ##
+
+The ECDSA implementation is specific to the NIST prime curves P-256,
+P-384, and P-521.
+
+The ECDSA implementation includes a compile-time option to allow test
+code to bypass the CSPRNG in order to test against known test vectors.
+Do **NOT** enable this in production builds, as ECDSA depends on good
+random numbers not just for private keys but for individual
+signatures, and an attacker who knows the random number used for a
+particular signature can use this to recover the private key.
+Arguably, this option should be removed from the code entirely, once
+the implementation is stable.
+
+The ECDSA implementation includes enough ASN.1 to read and write ECDSA
+signatures and ECDSA private keys in RFC 5915 format; the expectation
+is that the latter will be used in combination with AES Key Wrap.
+
+The ECDSA implementation attempts to be constant-time, to reduce the
+risk of timing channel attacks. The algorithms chosen for the point
+arithmetic are a tradeoff between speed and code complexity, and can
+probably be improved upon even in software; reimplementing at least
+the field arithmetic in hardware would probably also help.
+
+The current point addition and point doubling algorithms come from the
+[EFD][]. At least at the moment, we're only interested in ECDSA with
+the NIST prime curves, so we use algorithms optimized for a=-3.
+
+The point multiplication algorithm is a Montgomery Ladder, which is
+not the fastest possible algorithm, but is relatively easy to confirm
+by inspection as constant-time. Point multiplication could probably
+be made faster by using a non-adjacent form (NAF) representation for
+the scalar, but the author doesn't yet understand that well enough to
+implement it as a constant-time algorithm. In theory, changing to a
+NAF representation could be done without any change to the public API.
+
+Points stored in keys and curve parameters are in affine format, but
+all point arithmetic is performed in Jacobian projective coordinates,
+with the coordinates in Montgomery form; final mapping back to affine
+coordinates also handles the final Montgomery reduction.
+
+## API ##
+
+Yeah, we ought to document the API, Real Soon Now, perhaps using
+[Doxygen][]. For the moment, see the function prototypes in hal.h and
+comments in the code.
+
+[EFD]: http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
+[Doxygen]: http://www.doxygen.org/
diff --git a/asn1.c b/asn1.c
new file mode 100644
index 0000000..2ea44bd
--- /dev/null
+++ b/asn1.c
@@ -0,0 +1,227 @@
+/*
+ * asn1.c
+ * ------
+ * Minimal ASN.1 implementation in support of Cryptech libhal.
+ *
+ * The functions in this module are not intended to be part of the
+ * public API. Rather, these are utility functions used by more than
+ * one module within the library, which would otherwise have to be
+ * duplicated. The main reason for keeping these private is to avoid
+ * having the public API depend on any details of the underlying
+ * bignum implementation (currently libtfm, but that might change).
+ *
+ * As of this writing, the ASN.1 support we need is quite minimal, so,
+ * rather than attempting to clean all the unecessary cruft out of a
+ * general purpose ASN.1 implementation, we hand code the very small
+ * number of data types we need. At some point this will probably
+ * become impractical, at which point we might want to look into using
+ * something like the asn1c compiler.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, SUNET
+ *
+ * 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.
+ *
+ * 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 OWNER 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include "hal.h"
+
+#include "asn1_internal.h"
+
+/*
+ * Encode tag and length fields of an ASN.1 object.
+ *
+ * Sets *der_len to the size of of the ASN.1 header (tag and length
+ * fields); caller supplied length of value field, so presumably
+ * already knows it.
+ *
+ * If der is NULL, just return the size of the header that would be
+ * encoded and returns HAL_OK.
+ *
+ * If der isn't NULL, returns HAL_ERROR_RESULT_TOO_LONG unless full
+ * header plus value will fit; this is a bit weird, but is useful when
+ * using this to construct encoders for complte ASN.1 objects.
+ */
+
+hal_error_t hal_asn1_encode_header(const uint8_t tag,
+ const size_t value_len,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ size_t header_len = 2; /* Shortest encoding is one octet each for tag and length */
+
+ if (value_len >= 128) /* Add octets for longer length encoding as needed */
+ for (size_t n = value_len; n > 0; n >>= 8)
+ ++header_len;
+
+ if (der_len != NULL)
+ *der_len = header_len;
+
+ if (der == NULL) /* If caller just wanted the length, we're done */
+ return HAL_OK;
+
+ /*
+ * Make sure there's enough room for header + value, then encode.
+ */
+
+ if (value_len + header_len > der_max)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ *der++ = tag;
+
+ if (value_len < 128) {
+ *der = (uint8_t) value_len;
+ }
+
+ else {
+ *der = 0x80 | (uint8_t) (header_len -= 2);
+ for (size_t n = value_len; n > 0 && header_len > 0; n >>= 8)
+ der[header_len--] = (uint8_t) (n & 0xFF);
+ }
+
+ return HAL_OK;
+}
+
+/*
+ * Encode an unsigned ASN.1 INTEGER from a libtfm bignum. If der is
+ * NULL, just return the length of what we would have encoded.
+ */
+
+hal_error_t hal_asn1_encode_integer(const fp_int * const bn,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (bn == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /*
+ * We only handle unsigned INTEGERs, so we need to pad data with a
+ * leading zero if the most significant bit is set, to avoid
+ * flipping the ASN.1 sign bit. Conveniently, this also handles the
+ * difference between libtfm's and ASN.1's encoding of zero.
+ */
+
+ if (fp_cmp_d(unconst_fp_int(bn), 0) == FP_LT)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const int leading_zero = fp_iszero(bn) || (fp_count_bits(unconst_fp_int(bn)) & 7) == 0;
+ const size_t vlen = fp_unsigned_bin_size(unconst_fp_int(bn)) + leading_zero;
+ hal_error_t err;
+ size_t hlen;
+
+ err = hal_asn1_encode_header(ASN1_INTEGER, vlen, der, &hlen, der_max);
+
+ if (der_len != NULL)
+ *der_len = hlen + vlen;
+
+ if (der == NULL || err != HAL_OK)
+ return err;
+
+ assert(hlen + vlen <= der_max);
+
+ der += hlen;
+ if (leading_zero)
+ *der++ = 0x00;
+ fp_to_unsigned_bin(unconst_fp_int(bn), der);
+
+ return HAL_OK;
+}
+
+/*
+ * Parse tag and length of an ASN.1 object. Tag must match value
+ * specified by the caller. On success, sets hlen and vlen to lengths
+ * of header and value, respectively.
+ */
+
+hal_error_t hal_asn1_decode_header(const uint8_t tag,
+ const uint8_t * const der, size_t der_max,
+ size_t *hlen, size_t *vlen)
+{
+ assert(der != NULL && hlen != NULL && vlen != NULL);
+
+ if (der_max < 2 || der[0] != tag)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ if ((der[1] & 0x80) == 0) {
+ *hlen = 2;
+ *vlen = der[1];
+ }
+
+ else {
+ *hlen = 2 + (der[1] & 0x7F);
+ *vlen = 0;
+
+ if (*hlen > der_max)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ for (size_t i = 2; i < *hlen; i++)
+ *vlen = (*vlen << 8) + der[i];
+ }
+
+ if (*hlen + *vlen > der_max)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ return HAL_OK;
+}
+
+/*
+ * Decode an ASN.1 INTEGER into a libtfm bignum. Since we only
+ * support (or need to support, or expect to see) unsigned integers,
+ * we return failure if the sign bit is set in the ASN.1 INTEGER.
+ */
+
+hal_error_t hal_asn1_decode_integer(fp_int *bn,
+ const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+ if (bn == NULL || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err;
+ size_t hlen, vlen;
+
+ if ((err = hal_asn1_decode_header(ASN1_INTEGER, der, der_max, &hlen, &vlen)) != HAL_OK)
+ return err;
+
+ if (der_len != NULL)
+ *der_len = hlen + vlen;
+
+ if (vlen < 1 || (der[hlen] & 0x80) != 0x00)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ fp_init(bn);
+ fp_read_unsigned_bin(bn, (uint8_t *) der + hlen, vlen);
+ return HAL_OK;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/asn1_internal.h b/asn1_internal.h
new file mode 100644
index 0000000..f6e470f
--- /dev/null
+++ b/asn1_internal.h
@@ -0,0 +1,108 @@
+/*
+ * asn1.h
+ * ------
+ * Library internal header file for ASN.1 routines.
+ *
+ * These functions are not part of the public libhal API.
+ *
+ * More than 20 years after it was written, the best simple
+ * introduction to ASN.1 is still Burt Kalski's "A Layman's Guide to a
+ * Subset of ASN.1, BER, and DER". Ask your nearest search engine.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, SUNET
+ *
+ * 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.
+ *
+ * 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 OWNER 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.
+ */
+
+#ifndef _HAL_ASN1_H_
+#define _HAL_ASN1_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <tfm.h>
+
+#define ASN1_UNIVERSAL 0x00
+#define ASN1_APPLICATION 0x40
+#define ASN1_CONTEXT_SPECIFIC 0x80
+#define ASN1_PRIVATE 0xC0
+
+#define ASN1_PRIMITIVE 0x00
+#define ASN1_CONSTRUCTED 0x20
+
+#define ASN1_TAG_MASK 0x1F
+
+#define ASN1_INTEGER (ASN1_PRIMITIVE | 0x02)
+#define ASN1_BIT_STRING (ASN1_PRIMITIVE | 0x03)
+#define ASN1_OCTET_STRING (ASN1_PRIMITIVE | 0x04)
+#define ASN1_NULL (ASN1_PRIMITIVE | 0x05)
+#define ASN1_OBJECT_IDENTIFIER (ASN1_PRIMITIVE | 0x06)
+#define ASN1_SEQUENCE (ASN1_CONSTRUCTED | 0x10)
+#define ASN1_SET (ASN1_CONSTRUCTED | 0x11)
+
+#define ASN1_EXPLICIT_CONTEXT (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED)
+#define ASN1_EXPLICIT_0 (ASN1_EXPLICIT_CONTEXT + 0)
+#define ASN1_EXPLICIT_1 (ASN1_EXPLICIT_CONTEXT + 1)
+
+/*
+ * Functions to strip const qualifiers from arguments to libtfm calls
+ * in a relatively type-safe manner. These don't really have anything
+ * to do with ASN.1 per se, but all the code that needs them reads
+ * this header file, so this is the simplest place to put them.
+ */
+
+static inline fp_int *unconst_fp_int(const fp_int * const arg)
+{
+ return (fp_int *) arg;
+}
+
+static inline uint8_t *unconst_uint8_t(const uint8_t * const arg)
+{
+ return (uint8_t *) arg;
+}
+
+extern hal_error_t hal_asn1_encode_header(const uint8_t tag,
+ const size_t value_len,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+extern hal_error_t hal_asn1_decode_header(const uint8_t tag,
+ const uint8_t * const der, size_t der_max,
+ size_t *hlen, size_t *vlen);
+
+extern hal_error_t hal_asn1_encode_integer(const fp_int * const bn,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+extern hal_error_t hal_asn1_decode_integer(fp_int *bn,
+ const uint8_t * const der, size_t *der_len, const size_t der_max);
+
+#endif /* _HAL_ASN1_H_ */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/csprng.c b/csprng.c
index 816aeae..235bd12 100644
--- a/csprng.c
+++ b/csprng.c
@@ -1,34 +1,34 @@
-/*
+/*
* csprng.c
* --------
* HAL interface to Cryptech CSPRNG.
- *
+ *
* Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein
* Copyright (c) 2014-2015, SUNET
- *
- * 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.
- *
- * 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *
+ * 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.
+ *
+ * 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 OWNER 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
+ * 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/ecdsa.c b/ecdsa.c
new file mode 100644
index 0000000..8799ece
--- /dev/null
+++ b/ecdsa.c
@@ -0,0 +1,1545 @@
+/*
+ * ecdsa.c
+ * -------
+ * Elliptic Curve Digital Signature Algorithm for NIST prime curves.
+ *
+ * At some point we may want to refactor this code to separate
+ * functionality that applies to all elliptic curve cryptography into
+ * a separate module from functions specific to ECDSA over the NIST
+ * prime curves, but it's simplest to keep this all in one place
+ * initially.
+ *
+ * Much of the code in this module is based, at least loosely, on Tom
+ * St Denis's libtomcrypt code. Algorithms for point addition and
+ * point doubling courtesy of the hyperelliptic.org formula database.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, SUNET
+ *
+ * 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.
+ *
+ * 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 OWNER 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.
+ */
+
+/*
+ * We use "Tom's Fast Math" library for our bignum implementation.
+ * This particular implementation has a couple of nice features:
+ *
+ * - The code is relatively readable, thus reviewable.
+ *
+ * - The bignum representation doesn't use dynamic memory, which
+ * simplifies things for us.
+ *
+ * The price tag for not using dynamic memory is that libtfm has to be
+ * configured to know about the largest bignum one wants it to be able
+ * to support at compile time. This should not be a serious problem.
+ *
+ * We use a lot of one-element arrays (fp_int[1] instead of plain
+ * fp_int) to avoid having to prefix every use of an fp_int with "&".
+ * Perhaps we should encapsulate this idiom in a typedef.
+ *
+ * Unfortunately, libtfm is bad about const-ification, but we want to
+ * hide that from our users, so our public API uses const as
+ * appropriate and we use inline functions to remove const constraints
+ * in a relatively type-safe manner before calling libtom.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include "hal.h"
+#include <tfm.h>
+#include "asn1_internal.h"
+
+/*
+ * Whether we're using static test vectors instead of the random
+ * number generator. Do NOT enable this in production (doh).
+ */
+
+#ifndef HAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM
+#define HAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM 0
+#endif
+
+/*
+ * Whether we want debug output.
+ */
+
+static int debug = 0;
+
+void hal_ecdsa_set_debug(const int onoff)
+{
+ debug = onoff;
+}
+
+/*
+ * ECDSA curve descriptor. We only deal with named curves; at the
+ * moment, we only deal with NIST prime curves where the elliptic
+ * curve's "a" parameter is always -3 and its "h" value (order of
+ * elliptic curve group divided by order of base point) is always 1.
+ *
+ * Since the Montgomery parameters we need for the point arithmetic
+ * depend only on the underlying field prime, we precompute them when
+ * we load the curve and store them in the field descriptor, even
+ * though they aren't really curve parameters per se.
+ *
+ * For similar reasons, we also include the ASN.1 OBJECT IDENTIFIERs
+ * used to name these curves.
+ */
+
+typedef struct {
+ fp_int q[1]; /* Modulus of underlying prime field */
+ fp_int b[1]; /* Curve's "b" parameter */
+ fp_int Gx[1]; /* x component of base point G */
+ fp_int Gy[1]; /* y component of base point G */
+ fp_int n[1]; /* Order of base point G */
+ fp_int mu[1]; /* Montgomery normalization factor */
+ fp_digit rho; /* Montgomery reduction value */
+ const uint8_t *oid; /* OBJECT IDENTIFIER */
+ size_t oid_len; /* Length of OBJECT IDENTIFIER */
+} ecdsa_curve_t;
+
+/*
+ * ECDSA key implementation. This structure type is private to this
+ * module, anything else that needs to touch one of these just gets a
+ * typed opaque pointer. We do, however, export the size, so that we
+ * can make memory allocation the caller's problem.
+ *
+ * EC points are stored in Jacobian format such that (x, y, z) =>
+ * (x/z**2, y/z**3, 1) when interpretted as affine coordinates.
+ */
+
+typedef struct {
+ fp_int x[1], y[1], z[1];
+} ec_point_t;
+
+struct hal_ecdsa_key {
+ hal_ecdsa_key_type_t type; /* Public or private is */
+ hal_ecdsa_curve_t curve; /* Curve descriptor */
+ ec_point_t Q[1]; /* Public key */
+ fp_int d[1]; /* Private key */
+};
+
+const size_t hal_ecdsa_key_t_size = sizeof(struct hal_ecdsa_key);
+
+/*
+ * Error handling.
+ */
+
+#define lose(_code_) do { err = _code_; goto fail; } while (0)
+
+/*
+ * We can't (usefully) initialize fp_int variables at compile time, so
+ * instead we load all the curve parameters the first time anything
+ * asks for any of them.
+ */
+
+static const ecdsa_curve_t * const get_curve(const hal_ecdsa_curve_t curve)
+{
+ static ecdsa_curve_t curve_p256, curve_p384, curve_p521;
+ static int initialized = 0;
+
+ if (!initialized) {
+
+#include "ecdsa_curves.h"
+
+ fp_read_unsigned_bin(curve_p256.q, unconst_uint8_t(p256_q), sizeof(p256_q));
+ fp_read_unsigned_bin(curve_p256.b, unconst_uint8_t(p256_b), sizeof(p256_b));
+ fp_read_unsigned_bin(curve_p256.Gx, unconst_uint8_t(p256_Gx), sizeof(p256_Gx));
+ fp_read_unsigned_bin(curve_p256.Gy, unconst_uint8_t(p256_Gy), sizeof(p256_Gy));
+ fp_read_unsigned_bin(curve_p256.n, unconst_uint8_t(p256_n), sizeof(p256_n));
+ if (fp_montgomery_setup(curve_p256.q, &curve_p256.rho) != FP_OKAY)
+ return NULL;
+ fp_zero(curve_p256.mu);
+ fp_montgomery_calc_normalization(curve_p256.mu, curve_p256.q);
+ curve_p256.oid = p256_oid;
+ curve_p256.oid_len = sizeof(p256_oid);
+
+ fp_read_unsigned_bin(curve_p384.q, unconst_uint8_t(p384_q), sizeof(p384_q));
+ fp_read_unsigned_bin(curve_p384.b, unconst_uint8_t(p384_b), sizeof(p384_b));
+ fp_read_unsigned_bin(curve_p384.Gx, unconst_uint8_t(p384_Gx), sizeof(p384_Gx));
+ fp_read_unsigned_bin(curve_p384.Gy, unconst_uint8_t(p384_Gy), sizeof(p384_Gy));
+ fp_read_unsigned_bin(curve_p384.n, unconst_uint8_t(p384_n), sizeof(p384_n));
+ if (fp_montgomery_setup(curve_p384.q, &curve_p384.rho) != FP_OKAY)
+ return NULL;
+ fp_zero(curve_p384.mu);
+ fp_montgomery_calc_normalization(curve_p384.mu, curve_p384.q);
+ curve_p384.oid = p384_oid;
+ curve_p384.oid_len = sizeof(p384_oid);
+
+ fp_read_unsigned_bin(curve_p521.q, unconst_uint8_t(p521_q), sizeof(p521_q));
+ fp_read_unsigned_bin(curve_p521.b, unconst_uint8_t(p521_b), sizeof(p521_b));
+ fp_read_unsigned_bin(curve_p521.Gx, unconst_uint8_t(p521_Gx), sizeof(p521_Gx));
+ fp_read_unsigned_bin(curve_p521.Gy, unconst_uint8_t(p521_Gy), sizeof(p521_Gy));
+ fp_read_unsigned_bin(curve_p521.n, unconst_uint8_t(p521_n), sizeof(p521_n));
+ if (fp_montgomery_setup(curve_p521.q, &curve_p521.rho) != FP_OKAY)
+ return NULL;
+ fp_zero(curve_p521.mu);
+ fp_montgomery_calc_normalization(curve_p521.mu, curve_p521.q);
+ curve_p521.oid = p521_oid;
+ curve_p521.oid_len = sizeof(p521_oid);
+
+ initialized = 1;
+ }
+
+ switch (curve) {
+ case HAL_ECDSA_CURVE_P256: return &curve_p256;
+ case HAL_ECDSA_CURVE_P384: return &curve_p384;
+ case HAL_ECDSA_CURVE_P521: return &curve_p521;
+ default: return NULL;
+ }
+}
+
+/*
+ * Finite field operations (hence "ff_"). These are basically just
+ * the usual bignum operations, constrained by the field modulus.
+ *
+ * All of these are operations in the field underlying the specified
+ * curve, and assume that operands are already in Montgomery form.
+ *
+ * The ff_add() and ff_sub() are written a bit oddly, in an attempt to
+ * make them run in constant time. An optimizing compiler may be
+ * clever enough to defeat this. In the long run, we probably want to
+ * perform these field operations in Verilog anyway.
+ *
+ * We might be able to squeeze a bit more speed out of the point
+ * arithmetic by making using fp_mul_2d() when multiplying by a power
+ * of two. Skipping for now as a premature optimization, but if we do
+ * need this, it'd probably be simplest to add a ff_dbl() function
+ * which handles overflow in the same way that ff_add() does.
+ */
+
+static inline void ff_add(const ecdsa_curve_t * const curve,
+ const fp_int * const a,
+ const fp_int * const b,
+ fp_int *c)
+{
+ fp_int t[2][1];
+ memset(t, 0, sizeof(t));
+
+ fp_add(unconst_fp_int(a), unconst_fp_int(b), t[0]);
+ fp_sub(t[0], unconst_fp_int(curve->q), t[1]);
+
+ fp_copy(t[fp_cmp_d(t[1], 0) != FP_LT], c);
+
+ memset(t, 0, sizeof(t));
+}
+
+static inline void ff_sub(const ecdsa_curve_t * const curve,
+ const fp_int * const a,
+ const fp_int * const b,
+ fp_int *c)
+{
+ fp_int t[2][1];
+ memset(t, 0, sizeof(t));
+
+ fp_sub(unconst_fp_int(a), unconst_fp_int(b), t[0]);
+ fp_add(t[0], unconst_fp_int(curve->q), t[1]);
+
+ fp_copy(t[fp_cmp_d(t[0], 0) == FP_LT], c);
+
+ memset(t, 0, sizeof(t));
+}
+
+static inline void ff_mul(const ecdsa_curve_t * const curve,
+ const fp_int * const a,
+ const fp_int * const b,
+ fp_int *c)
+{
+ fp_mul(unconst_fp_int(a), unconst_fp_int(b), c);
+ fp_montgomery_reduce(c, unconst_fp_int(curve->q), curve->rho);
+}
+
+static inline void ff_sqr(const ecdsa_curve_t * const curve,
+ const fp_int * const a,
+ fp_int *b)
+{
+ fp_sqr(unconst_fp_int(a), b);
+ fp_montgomery_reduce(b, unconst_fp_int(curve->q), curve->rho);
+}
+
+/*
+ * Test whether a point is the point at infinity.
+ *
+ * In Jacobian projective coordinate, any point of the form
+ *
+ * (j ** 2, j **3, 0) for j in [1..q-1]
+ *
+ * is on the line at infinity, but for practical purposes simply
+ * checking the z coordinate is probably sufficient.
+ */
+
+static inline int point_is_infinite(const ec_point_t * const P)
+{
+ assert(P != NULL);
+ return fp_iszero(P->z);
+}
+
+/*
+ * Set a point to be the point at infinity. For Jacobian projective
+ * coordinates, it's customary to use (1 : 1 : 0) as the
+ * representitive value.
+ */
+
+static inline void point_set_infinite(ec_point_t *P)
+{
+ assert(P != NULL);
+ fp_set(P->x, 1);
+ fp_set(P->y, 1);
+ fp_set(P->z, 0);
+}
+
+/*
+ * Copy a point.
+ */
+
+static inline void point_copy(const ec_point_t * const P, ec_point_t *R)
+{
+ if (P != NULL && R != NULL && P != R)
+ *R = *P;
+}
+
+/**
+ * Double an EC point.
+ * @param P The point to double
+ * @param R [out] The destination of the double
+ * @param curve The curve parameters structure
+ *
+ * Algorithm is dbl-2001-b from
+ * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
+ */
+
+static inline void point_double(const ec_point_t * const P,
+ ec_point_t *R,
+ const ecdsa_curve_t * const curve)
+{
+ assert(P != NULL && R != NULL && curve != NULL);
+
+ assert(!point_is_infinite(P));
+
+ fp_int alpha[1], beta[1], gamma[1], delta[1], t1[1], t2[1];
+
+ fp_init(alpha); fp_init(beta); fp_init(gamma); fp_init(delta); fp_init(t1); fp_init(t2);
+
+ ff_sqr (curve, P->z, delta); /* delta = Pz ** 2 */
+ ff_sqr (curve, P->y, gamma); /* gamma = Py ** 2 */
+ ff_mul (curve, P->x, gamma, beta); /* beta = Px * gamma */
+ ff_sub (curve, P->x, delta, t1); /* alpha = 3 * (Px - delta) * (Px + delta) */
+ ff_add (curve, P->x, delta, t2);
+ ff_mul (curve, t1, t2, t1);
+ ff_add (curve, t1, t1, t2);
+ ff_add (curve, t1, t2, alpha);
+
+ ff_sqr (curve, alpha, t1); /* Rx = (alpha ** 2) - (8 * beta) */
+ ff_add (curve, beta, beta, t2);
+ ff_add (curve, t2, t2, t2);
+ ff_add (curve, t2, t2, t2);
+ ff_sub (curve, t1, t2, R->x);
+
+ ff_add (curve, P->y, P->z, t1); /* Rz = ((Py + Pz) ** 2) - gamma - delta */
+ ff_sqr (curve, t1, t1);
+ ff_sub (curve, t1, gamma, t1);
+ ff_sub (curve, t1, delta, R->z);
+
+ ff_add (curve, beta, beta, t1); /* Ry = (((4 * beta) - Rx) * alpha) - (8 * (gamma ** 2)) */
+ ff_add (curve, t1, t1, t1);
+ ff_sub (curve, t1, R->x, t1);
+ ff_mul (curve, t1, alpha, t1);
+ ff_sqr (curve, gamma, t2);
+ ff_add (curve, t2, t2, t2);
+ ff_add (curve, t2, t2, t2);
+ ff_add (curve, t2, t2, t2);
+ ff_sub (curve, t1, t2, R->y);
+
+ fp_zero(alpha); fp_zero(beta); fp_zero(gamma); fp_zero(delta); fp_zero(t1); fp_zero(t2);
+}
+
+/**
+ * Add two EC points
+ * @param P The point to add
+ * @param Q The point to add
+ * @param R [out] The destination of the double
+ * @param curve The curve parameters structure
+ *
+ * Algorithm is add-2007-bl from
+ * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
+ *
+ * The special cases for P == Q and P == -Q are unfortunate, but are
+ * probably unavoidable for this type of curve.
+ */
+
+static inline void point_add(const ec_point_t * const P,
+ const ec_point_t * const Q,
+ ec_point_t *R,
+ const ecdsa_curve_t * const curve)
+{
+ assert(P != NULL && Q != NULL && R != NULL && curve != NULL);
+
+ if (fp_cmp(unconst_fp_int(P->x), unconst_fp_int(Q->x)) == FP_EQ &&
+ fp_cmp(unconst_fp_int(P->z), unconst_fp_int(Q->z)) == FP_EQ) {
+
+ /*
+ * If P == Q, we have to use the doubling algorithm instead.
+ */
+
+ if (fp_cmp(unconst_fp_int(P->y), unconst_fp_int(Q->y)) == FP_EQ)
+ return point_double(P, R, curve);
+
+ fp_int Qy_neg[1];
+ fp_sub(unconst_fp_int(curve->q), unconst_fp_int(Q->y), Qy_neg);
+ const int zero_sum = fp_cmp(unconst_fp_int(P->y), Qy_neg) == FP_EQ;
+ fp_zero(Qy_neg);
+
+ /*
+ * If P == -Q, P + Q is the point at infinity. Which can't be
+ * expressed in affine coordinates, but that's not this function's
+ * problem.
+ */
+
+ if (zero_sum)
+ return point_set_infinite(R);
+ }
+
+ fp_int Z1Z1[1], Z2Z2[1], U1[1], U2[1], S1[1], S2[1], H[1], I[1], J[1], r[1], V[1], t[1];
+
+ fp_init(Z1Z1), fp_init(Z2Z2), fp_init(U1), fp_init(U2), fp_init(S1), fp_init(S2);
+ fp_init(H), fp_init(I), fp_init(J), fp_init(r), fp_init(V), fp_init(t);
+
+ ff_sqr (curve, P->z, Z1Z1); /* Z1Z1 = Pz ** 2 */
+
+ ff_sqr (curve, Q->z, Z2Z2); /* Z2Z1 = Qz ** 2 */
+
+ ff_mul (curve, P->x, Z2Z2, U1); /* U1 = Px * Z2Z2 */
+
+ ff_mul (curve, Q->x, Z1Z1, U2); /* U2 = Qx * Z1Z1 */
+
+ ff_mul (curve, Q->z, Z2Z2, S1); /* S1 = Py * (Qz ** 3) */
+ ff_mul (curve, P->y, S1, S1);
+
+ ff_mul (curve, P->z, Z1Z1, S2); /* S2 = Qy * (Pz ** 3) */
+ ff_mul (curve, Q->y, S2, S2);
+
+ ff_sub (curve, U2, U1, H); /* H = U2 - U1 */
+
+ ff_add (curve, H, H, I); /* I = (2 * H) ** 2 */
+ ff_sqr (curve, I, I);
+
+ ff_mul (curve, H, I, J); /* J = H * I */
+
+ ff_sub (curve, S2, S1, r); /* r = 2 * (S2 - S1) */
+ ff_add (curve, r, r, r);
+
+ ff_mul (curve, U1, I, V); /* V = U1 * I */
+
+ ff_sqr (curve, r, R->x); /* Rx = (r ** 2) - J - (2 * V) */
+ ff_sub (curve, R->x, J, R->x);
+ ff_sub (curve, R->x, V, R->x);
+ ff_sub (curve, R->x, V, R->x);
+
+ ff_sub (curve, V, R->x, R->y); /* Ry = (r * (V - Rx)) - (2 * S1 * J) */
+ ff_mul (curve, r, R->y, R->y);
+ ff_mul (curve, S1, J, t);
+ ff_sub (curve, R->y, t, R->y);
+ ff_sub (curve, R->y, t, R->y);
+
+ ff_add (curve, P->z, Q->z, R->z); /* Rz = (((Pz + Qz) ** 2) - Z1Z1 - Z2Z2) * H */
+ ff_sqr (curve, R->z, R->z);
+ ff_sub (curve, R->z, Z1Z1, R->z);
+ ff_sub (curve, R->z, Z2Z2, R->z);
+ ff_mul (curve, R->z, H, R->z);
+
+ fp_zero(Z1Z1), fp_zero(Z2Z2), fp_zero(U1), fp_zero(U2), fp_zero(S1), fp_zero(S2);
+ fp_zero(H), fp_zero(I), fp_zero(J), fp_zero(r), fp_zero(V), fp_zero(t);
+}
+
+/**
+ * Map a point in projective Jacbobian coordinates back to affine space
+ * @param P [in/out] The point to map
+ * @param curve The curve parameters structure
+ *
+ * It's not possible to represent the point at infinity in affine
+ * coordinates, and the calling function will have to handle this
+ * specially in any case, so we declare this to be the calling
+ * function's problem.
+ */
+
+static inline hal_error_t point_to_affine(ec_point_t *P,
+ const ecdsa_curve_t * const curve)
+{
+ assert(P != NULL && curve != NULL);
+
+ if (point_is_infinite(P))
+ return HAL_ERROR_IMPOSSIBLE;
+
+ hal_error_t err = HAL_ERROR_IMPOSSIBLE;
+
+ fp_int t1[1]; fp_init(t1);
+ fp_int t2[1]; fp_init(t2);
+
+ fp_int * const q = unconst_fp_int(curve->q);
+
+ fp_montgomery_reduce(P->z, q, curve->rho);
+
+ if (fp_invmod (P->z, q, t1) != FP_OKAY || /* t1 = 1 / z */
+ fp_sqrmod (t1, q, t2) != FP_OKAY || /* t2 = 1 / z**2 */
+ fp_mulmod (t1, t2, q, t1) != FP_OKAY) /* t1 = 1 / z**3 */
+ goto fail;
+
+ fp_mul (P->x, t2, P->x); /* x = x / z**2 */
+ fp_mul (P->y, t1, P->y); /* y = y / z**3 */
+ fp_set (P->z, 1); /* z = 1 */
+
+ fp_montgomery_reduce(P->x, q, curve->rho);
+ fp_montgomery_reduce(P->y, q, curve->rho);
+
+ err = HAL_OK;
+
+ fail:
+ fp_zero(t1);
+ fp_zero(t2);
+ return err;
+}
+
+/**
+ * Perform a point multiplication.
+ * @param k The scalar to multiply by
+ * @param P The base point
+ * @param R [out] Destination for kP
+ * @param curve Curve parameters
+ * @param map Boolean whether to map back to affine (1: map, 0: leave projective)
+ * @return HAL_OK on success
+ *
+ * This implementation uses the "Montgomery Ladder" approach, which is
+ * relatively robust against timing channel attacks if nothing else
+ * goes wrong, but many other things can indeed go wrong.
+ */
+
+static hal_error_t point_scalar_multiply(const fp_int * const k,
+ const ec_point_t * const P,
+ ec_point_t *R,
+ const ecdsa_curve_t * const curve,
+ const int map)
+{
+ assert(k != NULL && P != NULL && R != NULL && curve != NULL);
+
+ if (fp_iszero(k))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /*
+ * Convert to Montgomery form and initialize table. Initial values:
+ *
+ * M[0] = 1P
+ * M[1] = 2P
+ * M[2] = don't care, only used for timing-attack resistance
+ */
+
+ ec_point_t M[3][1];
+ memset(M, 0, sizeof(M));
+
+ if (fp_mulmod(unconst_fp_int(P->x), unconst_fp_int(curve->mu), unconst_fp_int(curve->q), M[0]->x) != FP_OKAY ||
+ fp_mulmod(unconst_fp_int(P->y), unconst_fp_int(curve->mu), unconst_fp_int(curve->q), M[0]->y) != FP_OKAY ||
+ fp_mulmod(unconst_fp_int(P->z), unconst_fp_int(curve->mu), unconst_fp_int(curve->q), M[0]->z) != FP_OKAY) {
+ memset(M, 0, sizeof(M));
+ return HAL_ERROR_IMPOSSIBLE;
+ }
+
+ point_double(M[0], M[1], curve);
+
+ /*
+ * Walk down bits of the scalar, performing dummy operations to mask
+ * timing while hunting for the most significant bit of the scalar.
+ *
+ * Note that, in order for this timing protection to work, the
+ * number of iterations in the loop has to depend on the order of
+ * the base point rather than on the scalar.
+ */
+
+ int dummy_mode = 1;
+
+ for (int bit_index = fp_count_bits(unconst_fp_int(curve->n)) - 1; bit_index >= 0; bit_index--) {
+
+ const int digit_index = bit_index / DIGIT_BIT;
+ const fp_digit digit = digit_index < k->used ? k->dp[digit_index] : 0;
+ const fp_digit mask = ((fp_digit) 1) << (bit_index % DIGIT_BIT);
+ const int bit = (digit & mask) != 0;
+
+ if (dummy_mode) {
+ point_add (M[0], M[1], M[2], curve);
+ point_double (M[1], M[2], curve);
+ dummy_mode = !bit; /* Dummy until we find MSB */
+ }
+
+ else {
+ point_add (M[0], M[1], M[bit^1], curve);
+ point_double (M[bit], M[bit], curve);
+ }
+ }
+
+ /*
+ * Copy result out, map back to affine if requested, then done.
+ */
+
+ point_copy(M[0], R);
+ hal_error_t err = map ? point_to_affine(R, curve) : HAL_OK;
+ memset(M, 0, sizeof(M));
+ return err;
+}
+
+/*
+ * Testing only: ECDSA key generation and signature both have a
+ * critical dependency on random numbers, but we can't use the random
+ * number generator when testing against static test vectors. So add a
+ * wrapper around the random number generator calls, with a hook to
+ * let us override the generator for test purposes. Do NOT use this
+ * in production, kids.
+ */
+
+#if HAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM
+
+#warning hal_ecdsa random number generator overridden for test purposes
+#warning DO NOT USE THIS IN PRODUCTION
+
+typedef hal_error_t (*rng_override_test_function_t)(void *, const size_t);
+
+static rng_override_test_function_t rng_test_override_function = 0;
+
+rng_override_test_function_t hal_ecdsa_set_rng_override_test_function(rng_override_test_function_t new_func)
+{
+ rng_override_test_function_t old_func = rng_test_override_function;
+ rng_test_override_function = new_func;
+ return old_func;
+}
+
+static inline hal_error_t get_random(void *buffer, const size_t length)
+{
+ if (rng_test_override_function)
+ return rng_test_override_function(buffer, length);
+ else
+ return hal_get_random(buffer, length);
+}
+
+#else /* HAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM */
+
+static inline hal_error_t get_random(void *buffer, const size_t length)
+{
+ return hal_get_random(buffer, length);
+}
+
+#endif /* HAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM */
+
+/*
+ * Pick a random point on the curve, return random scalar and
+ * resulting point.
+ */
+
+static hal_error_t point_pick_random(const ecdsa_curve_t * const curve,
+ fp_int *k,
+ ec_point_t *P)
+{
+ hal_error_t err;
+
+ assert(curve != NULL && k != NULL && P != NULL);
+
+ /*
+ * Pick a random scalar corresponding to a point on the curve. Per
+ * the NSA (gulp) Suite B guidelines, we ask the CSPRNG for 64 more
+ * bits than we need, which should be enough to mask any bias
+ * induced by the modular reduction.
+ *
+ * We're picking a point out of the subgroup generated by the base
+ * point on the elliptic curve, so the modulus for this calculation
+ * is the order of the base point.
+ *
+ * Zero is an excluded value, but the chance of a non-broken CSPRNG
+ * returning zero is so low that it would almost certainly indicate
+ * an undiagnosed bug in the CSPRNG.
+ */
+
+ uint8_t k_buf[fp_unsigned_bin_size(unconst_fp_int(curve->n)) + 8];
+
+ do {
+
+ if ((err = get_random(k_buf, sizeof(k_buf))) != HAL_OK)
+ return err;
+
+ fp_read_unsigned_bin(k, k_buf, sizeof(k_buf));
+
+ if (fp_iszero(k) || fp_mod(k, unconst_fp_int(curve->n), k) != FP_OKAY)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ } while (fp_iszero(k));
+
+ memset(k_buf, 0, sizeof(k_buf));
+
+ /*
+ * Calculate P = kG and return.
+ */
+
+ fp_copy(curve->Gx, P->x);
+ fp_copy(curve->Gy, P->y);
+ fp_set(P->z, 1);
+
+ return point_scalar_multiply(k, P, P, curve, 1);
+}
+
+/*
+ * Test whether a point really is on a particular curve. This is
+ * called "validation" when applied to a public key, and is required
+ * before verifying a signature.
+ */
+
+static int point_is_on_curve(const ec_point_t * const P,
+ const ecdsa_curve_t * const curve)
+{
+ assert(P != NULL && curve != NULL);
+
+ fp_int t1[1]; fp_init(t1);
+ fp_int t2[1]; fp_init(t2);
+
+ /*
+ * Compute y**2 - x**3 + 3*x.
+ */
+
+ fp_sqr(unconst_fp_int(P->y), t1); /* t1 = y**2 */
+ fp_sqr(unconst_fp_int(P->x), t2); /* t2 = x**2 */
+ if (fp_mod(t2, unconst_fp_int(curve->q), t2) != FP_OKAY)
+ return 0;
+ fp_mul(unconst_fp_int(P->x), t2, t2); /* t2 = x**3 */
+ fp_sub(t1, t2, t1); /* t1 = y**2 - x**3 */
+ fp_add(t1, unconst_fp_int(P->x), t1); /* t1 = y**2 - x**3 + 1*x */
+ fp_add(t1, unconst_fp_int(P->x), t1); /* t1 = y**2 - x**3 + 2*x */
+ fp_add(t1, unconst_fp_int(P->x), t1); /* t1 = y**2 - x**3 + 3*x */
+
+ /*
+ * Normalize and test whether computed value matches b.
+ */
+
+ if (fp_mod(t1, unconst_fp_int(curve->q), t1) != FP_OKAY)
+ return 0;
+ while (fp_cmp_d(t1, 0) == FP_LT)
+ fp_add(t1, unconst_fp_int(curve->q), t1);
+ while (fp_cmp(t1, unconst_fp_int(curve->q)) != FP_LT)
+ fp_sub(t1, unconst_fp_int(curve->q), t1);
+
+ return fp_cmp(t1, unconst_fp_int(curve->b)) == FP_EQ;
+}
+
+/*
+ * Generate a new ECDSA key.
+ */
+
+hal_error_t hal_ecdsa_key_gen(hal_ecdsa_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const hal_ecdsa_curve_t curve_)
+{
+ const ecdsa_curve_t * const curve = get_curve(curve_);
+ hal_ecdsa_key_t *key = keybuf;
+ hal_error_t err;
+
+ if (key_ == NULL || key == NULL || keybuf_len < sizeof(*key) || curve == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ memset(keybuf, 0, keybuf_len);
+
+ key->type = HAL_ECDSA_PRIVATE;
+ key->curve = curve_;
+
+ if ((err = point_pick_random(curve, key->d, key->Q)) != HAL_OK)
+ return err;
+
+ assert(point_is_on_curve(key->Q, curve));
+
+ *key_ = key;
+ return HAL_OK;
+}
+
+/*
+ * Extract key type (public or private).
+ */
+
+hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key,
+ hal_ecdsa_key_type_t *key_type)
+{
+ if (key == NULL || key_type == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ *key_type = key->type;
+ return HAL_OK;
+}
+
+/*
+ * Extract name of curve underlying a key.
+ */
+
+hal_error_t hal_ecdsa_key_get_curve(const hal_ecdsa_key_t * const key,
+ hal_ecdsa_curve_t *curve)
+{
+ if (key == NULL || curve == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ *curve = key->curve;
+ return HAL_OK;
+}
+
+/*
+ * Extract public key components.
+ */
+
+hal_error_t hal_ecdsa_key_get_public(const hal_ecdsa_key_t * const key,
+ uint8_t *x, size_t *x_len, const size_t x_max,
+ uint8_t *y, size_t *y_len, const size_t y_max)
+{
+ if (key == NULL || (x_len == NULL && x != NULL) || (y_len == NULL && y != NULL))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (x_len != NULL)
+ *x_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->x));
+
+ if (y_len != NULL)
+ *y_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->y));
+
+ if ((x != NULL && *x_len > x_max) ||
+ (y != NULL && *y_len > y_max))
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ if (x != NULL)
+ fp_to_unsigned_bin(unconst_fp_int(key->Q->x), x);
+
+ if (y != NULL)
+ fp_to_unsigned_bin(unconst_fp_int(key->Q->y), y);
+
+ return HAL_OK;
+}
+
+/*
+ * Clear a key.
+ */
+
+void hal_ecdsa_key_clear(hal_ecdsa_key_t *key)
+{
+ if (key != NULL)
+ memset(key, 0, sizeof(*key));
+}
+
+/*
+ * Load a public key from components, and validate that the public key
+ * really is on the named curve.
+ */
+
+hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const hal_ecdsa_curve_t curve_,
+ const uint8_t * const x, const size_t x_len,
+ const uint8_t * const y, const size_t y_len)
+{
+ const ecdsa_curve_t * const curve = get_curve(curve_);
+ hal_ecdsa_key_t *key = keybuf;
+
+ if (key_ == NULL || key == NULL || keybuf_len < sizeof(*key) || curve == NULL || x == NULL || y == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ memset(keybuf, 0, keybuf_len);
+
+ key->type = HAL_ECDSA_PUBLIC;
+ key->curve = curve_;
+
+ fp_read_unsigned_bin(key->Q->x, unconst_uint8_t(x), x_len);
+ fp_read_unsigned_bin(key->Q->y, unconst_uint8_t(y), y_len);
+ fp_set(key->Q->z, 1);
+
+ if (!point_is_on_curve(key->Q, curve))
+ return HAL_ERROR_KEY_NOT_ON_CURVE;
+
+ *key_ = key;
+
+ return HAL_OK;
+}
+
+/*
+ * Load a private key from components; does all the same things as
+ * hal_ecdsa_key_load_public(), then loads the private key itself and
+ * adjusts the key type.
+ *
+ * For extra paranoia, we could check Q == dG.
+ */
+
+hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const hal_ecdsa_curve_t curve_,
+ const uint8_t * const x, const size_t x_len,
+ const uint8_t * const y, const size_t y_len,
+ const uint8_t * const d, const size_t d_len)
+{
+ hal_ecdsa_key_t *key = keybuf;
+ hal_error_t err;
+
+ if (d == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if ((err = hal_ecdsa_key_load_public(key_, keybuf, keybuf_len, curve_, x, x_len, y, y_len)) != HAL_OK)
+ return err;
+
+ key->type = HAL_ECDSA_PRIVATE;
+ fp_read_unsigned_bin(key->d, unconst_uint8_t(d), d_len);
+ return HAL_OK;
+}
+
+/*
+ * Write public key in X9.62 ECPoint format (ASN.1 OCTET STRING, first octet is compression flag).
+ */
+
+hal_error_t hal_ecdsa_key_to_ecpoint(const hal_ecdsa_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (key == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const ecdsa_curve_t * const curve = get_curve(key->curve);
+ if (curve == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ const size_t q_len = fp_unsigned_bin_size(unconst_fp_int(curve->q));
+ const size_t Qx_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->x));
+ const size_t Qy_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->y));
+ assert(q_len >= Qx_len && q_len >= Qy_len);
+
+ const size_t vlen = q_len * 2 + 1;
+ size_t hlen;
+
+ hal_error_t err = hal_asn1_encode_header(ASN1_OCTET_STRING, vlen, der, &hlen, der_max);
+
+ if (der_len != NULL)
+ *der_len = hlen + vlen;
+
+ if (der == NULL || err != HAL_OK)
+ return err;
+
+ assert(hlen + vlen <= der_max);
+
+ uint8_t *d = der + hlen;
+ memset(d, 0, vlen);
+
+ *d++ = 0x04; /* uncompressed */
+
+ fp_to_unsigned_bin(unconst_fp_int(key->Q->x), d + q_len - Qx_len);
+ d += q_len;
+
+ fp_to_unsigned_bin(unconst_fp_int(key->Q->y), d + q_len - Qy_len);
+ d += q_len;
+
+ assert(d <= der + der_max);
+
+ return HAL_OK;
+}
+
+/*
+ * Convenience wrapper to return how many bytes a key would take if
+ * encoded as an ECPoint.
+ */
+
+size_t hal_ecdsa_key_to_ecpoint_len(const hal_ecdsa_key_t * const key)
+{
+ size_t len;
+ return hal_ecdsa_key_to_ecpoint(key, NULL, &len, 0) == HAL_OK ? len : 0;
+}
+
+/*
+ * Read public key in X9.62 ECPoint format (ASN.1 OCTET STRING, first octet is compression flag).
+ * ECPoint format doesn't include a curve identifier, so caller has to supply one.
+ */
+
+hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len,
+ const hal_ecdsa_curve_t curve)
+{
+ hal_ecdsa_key_t *key = keybuf;
+
+ if (key_ == NULL || key == NULL || keybuf_len < sizeof(*key) || get_curve(curve) == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ memset(keybuf, 0, keybuf_len);
+ key->type = HAL_ECDSA_PUBLIC;
+ key->curve = curve;
+
+ size_t hlen, vlen;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_header(ASN1_OCTET_STRING, der, der_len, &hlen, &vlen)) != HAL_OK)
+ return err;
+
+ const uint8_t * const der_end = der + hlen + vlen;
+ const uint8_t *d = der + hlen;
+
+ if (vlen < 3 || (vlen & 1) == 0 || *d++ != 0x04)
+ lose(HAL_ERROR_ASN1_PARSE_FAILED);
+
+ vlen = vlen/2 - 1;
+
+ fp_read_unsigned_bin(key->Q->x, unconst_uint8_t(d), vlen);
+ d += vlen;
+
+ fp_read_unsigned_bin(key->Q->y, unconst_uint8_t(d), vlen);
+ d += vlen;
+
+ fp_set(key->Q->z, 1);
+
+ if (d != der_end)
+ lose(HAL_ERROR_ASN1_PARSE_FAILED);
+
+ *key_ = key;
+ return HAL_OK;
+
+ fail:
+ memset(keybuf, 0, keybuf_len);
+ return err;
+}
+
+/*
+ * Write private key in RFC 5915 ASN.1 DER format.
+ *
+ * This is hand-coded, and is approaching the limit where one should
+ * probably be using an ASN.1 compiler like asn1c instead.
+ */
+
+hal_error_t hal_ecdsa_key_to_der(const hal_ecdsa_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (key == NULL || key->type != HAL_ECDSA_PRIVATE)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const ecdsa_curve_t * const curve = get_curve(key->curve);
+ if (curve == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ const size_t q_len = fp_unsigned_bin_size(unconst_fp_int(curve->q));
+ const size_t d_len = fp_unsigned_bin_size(unconst_fp_int(key->d));
+ const size_t Qx_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->x));
+ const size_t Qy_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->y));
+ assert(q_len >= d_len && q_len >= Qx_len && q_len >= Qy_len);
+
+ fp_int version[1];
+ fp_set(version, 1);
+
+ hal_error_t err;
+
+ size_t version_len, hlen, hlen_oct, hlen_oid, hlen_exp0, hlen_bit, hlen_exp1;
+
+ if ((err = hal_asn1_encode_integer(version, NULL, &version_len, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_header(ASN1_OCTET_STRING, q_len, NULL, &hlen_oct, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, curve->oid_len, NULL, &hlen_oid, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_header(ASN1_EXPLICIT_0, hlen_oid + curve->oid_len, NULL, &hlen_exp0, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_header(ASN1_BIT_STRING, (q_len + 1) * 2, NULL, &hlen_bit, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_header(ASN1_EXPLICIT_1, hlen_bit + (q_len + 1) * 2, NULL, &hlen_exp1, 0)) != HAL_OK)
+ return err;
+
+ const size_t vlen = (version_len +
+ hlen_oct + q_len +
+ hlen_oid + hlen_exp0 + curve->oid_len +
+ hlen_bit + hlen_exp1 + (q_len + 1) * 2);
+
+ err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max);
+
+ if (der_len != NULL)
+ *der_len = hlen + vlen;
+
+ if (der == NULL || err != HAL_OK)
+ return err;
+
+ uint8_t *d = der + hlen;
+ memset(d, 0, vlen);
+
+ if ((err = hal_asn1_encode_integer(version, d, NULL, der + der_max - d)) != HAL_OK)
+ return err;
+ d += version_len;
+
+ if ((err = hal_asn1_encode_header(ASN1_OCTET_STRING, q_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+ fp_to_unsigned_bin(unconst_fp_int(key->d), d + q_len - d_len);
+ d += q_len;
+
+ if ((err = hal_asn1_encode_header(ASN1_EXPLICIT_0, hlen_oid + curve->oid_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+ if ((err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, curve->oid_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+ memcpy(d, curve->oid, curve->oid_len);
+ d += curve->oid_len;
+
+ if ((err = hal_asn1_encode_header(ASN1_EXPLICIT_1, hlen_bit + (q_len + 1) * 2, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+ if ((err = hal_asn1_encode_header(ASN1_BIT_STRING, (q_len + 1) * 2, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+ *d++ = 0x00;
+ *d++ = 0x04;
+ fp_to_unsigned_bin(unconst_fp_int(key->Q->x), d + q_len - Qx_len);
+ d += q_len;
+ fp_to_unsigned_bin(unconst_fp_int(key->Q->y), d + q_len - Qy_len);
+ d += q_len;
+
+ assert(d == der + der_max);
+
+ return HAL_OK;
+}
+
+/*
+ * Convenience wrapper to return how many bytes a private key would
+ * take if encoded as DER.
+ */
+
+size_t hal_ecdsa_key_to_der_len(const hal_ecdsa_key_t * const key)
+{
+ size_t len;
+ return hal_ecdsa_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
+}
+
+/*
+ * Read private key in RFC 5915 ASN.1 DER format.
+ *
+ * This is hand-coded, and is approaching the limit where one should
+ * probably be using an ASN.1 compiler like asn1c instead.
+ */
+
+hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len)
+{
+ hal_ecdsa_key_t *key = keybuf;
+
+ if (key_ == NULL || key == NULL || keybuf_len < sizeof(*key))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ memset(keybuf, 0, keybuf_len);
+ key->type = HAL_ECDSA_PRIVATE;
+
+ size_t hlen, vlen;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, der, der_len, &hlen, &vlen)) != HAL_OK)
+ return err;
+
+ const uint8_t * const der_end = der + hlen + vlen;
+ const uint8_t *d = der + hlen;
+ const ecdsa_curve_t *curve = NULL;
+ fp_int version[1];
+
+ if ((err = hal_asn1_decode_integer(version, d, &hlen, vlen)) != HAL_OK)
+ goto fail;
+ if (fp_cmp_d(version, 1) != FP_EQ)
+ lose(HAL_ERROR_ASN1_PARSE_FAILED);
+ d += hlen;
+
+ if ((err = hal_asn1_decode_header(ASN1_OCTET_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+ fp_read_unsigned_bin(key->d, unconst_uint8_t(d), vlen);
+ d += vlen;
+
+ if ((err = hal_asn1_decode_header(ASN1_EXPLICIT_0, d, der_end - d, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+ if (vlen > der_end - d)
+ lose(HAL_ERROR_ASN1_PARSE_FAILED);
+ if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, vlen, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+ for (key->curve = (hal_ecdsa_curve_t) 0; (curve = get_curve(key->curve)) != NULL; key->curve++)
+ if (vlen == curve->oid_len && memcmp(d, curve->oid, vlen) == 0)
+ break;
+ if (curve == NULL)
+ lose(HAL_ERROR_ASN1_PARSE_FAILED);
+ d += vlen;
+
+ if ((err = hal_asn1_decode_header(ASN1_EXPLICIT_1, d, der_end - d, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+ if (vlen > der_end - d)
+ lose(HAL_ERROR_ASN1_PARSE_FAILED);
+ if ((err = hal_asn1_decode_header(ASN1_BIT_STRING, d, vlen, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+ if (vlen < 4 || (vlen & 1) != 0 || *d++ != 0x00 || *d++ != 0x04)
+ lose(HAL_ERROR_ASN1_PARSE_FAILED);
+ vlen = vlen/2 - 1;
+ fp_read_unsigned_bin(key->Q->x, unconst_uint8_t(d), vlen);
+ d += vlen;
+ fp_read_unsigned_bin(key->Q->y, unconst_uint8_t(d), vlen);
+ d += vlen;
+ fp_set(key->Q->z, 1);
+
+ if (d != der_end)
+ lose(HAL_ERROR_ASN1_PARSE_FAILED);
+
+ *key_ = key;
+ return HAL_OK;
+
+ fail:
+ memset(keybuf, 0, keybuf_len);
+ return err;
+}
+
+/*
+ * Encode a signature in PKCS #11 format: an octet string consisting
+ * of concatenated values for r and s, each padded (if necessary) out
+ * to the byte length of the order of the base point.
+ */
+
+static hal_error_t encode_signature_pkcs11(const ecdsa_curve_t * const curve,
+ const fp_int * const r, const fp_int * const s,
+ uint8_t *signature, size_t *signature_len, const size_t signature_max)
+{
+ assert(curve != NULL && r != NULL && s != NULL);
+
+ const size_t n_len = fp_unsigned_bin_size(unconst_fp_int(curve->n));
+ const size_t r_len = fp_unsigned_bin_size(unconst_fp_int(r));
+ const size_t s_len = fp_unsigned_bin_size(unconst_fp_int(s));
+
+ if (n_len < r_len || n_len < s_len)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (signature_len != NULL)
+ *signature_len = n_len * 2;
+
+ if (signature == NULL)
+ return HAL_OK;
+
+ if (signature_max < n_len * 2)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ memset(signature, 0, n_len * 2);
+ fp_to_unsigned_bin(unconst_fp_int(r), signature + 1 * n_len - r_len);
+ fp_to_unsigned_bin(unconst_fp_int(s), signature + 2 * n_len - s_len);
+
+ return HAL_OK;
+}
+
+/*
+ * Decode a signature from PKCS #11 format: an octet string consisting
+ * of concatenated values for r and s, each of which occupies half of
+ * the octet string (which must therefore be of even length).
+ */
+
+static hal_error_t decode_signature_pkcs11(const ecdsa_curve_t * const curve,
+ fp_int *r, fp_int *s,
+ const uint8_t * const signature, const size_t signature_len)
+{
+ assert(curve != NULL && r != NULL && s != NULL);
+
+ if (signature == NULL || (signature_len & 1) != 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const size_t n_len = signature_len / 2;
+
+ if (n_len > fp_unsigned_bin_size(unconst_fp_int(curve->n)))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ fp_read_unsigned_bin(r, unconst_uint8_t(signature) + 0 * n_len, n_len);
+ fp_read_unsigned_bin(s, unconst_uint8_t(signature) + 1 * n_len, n_len);
+
+ return HAL_OK;
+}
+
+/*
+ * Encode a signature in ASN.1 format SEQUENCE { INTEGER r, INTEGER s }.
+ */
+
+static hal_error_t encode_signature_asn1(const ecdsa_curve_t * const curve,
+ const fp_int * const r, const fp_int * const s,
+ uint8_t *signature, size_t *signature_len, const size_t signature_max)
+{
+ assert(curve != NULL && r != NULL && s != NULL);
+
+ size_t hlen, r_len, s_len;
+ hal_error_t err;
+
+ if ((err = hal_asn1_encode_integer(r, NULL, &r_len, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_integer(s, NULL, &s_len, 0)) != HAL_OK)
+ return err;
+
+ const size_t vlen = r_len + s_len;
+
+ err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, signature, &hlen, signature_max);
+
+ if (signature_len != NULL)
+ *signature_len = hlen + vlen;
+
+ if (signature == NULL || err != HAL_OK)
+ return err;
+
+ uint8_t * const r_out = signature + hlen;
+ uint8_t * const s_out = r_out + r_len;
+
+ if ((err = hal_asn1_encode_integer(r, r_out, NULL, signature_max - (r_out - signature))) != HAL_OK ||
+ (err = hal_asn1_encode_integer(s, s_out, NULL, signature_max - (s_out - signature))) != HAL_OK)
+ return err;
+
+ return HAL_OK;
+}
+
+/*
+ * Decode a signature from ASN.1 format SEQUENCE { INTEGER r, INTEGER s }.
+ */
+
+static hal_error_t decode_signature_asn1(const ecdsa_curve_t * const curve,
+ fp_int *r, fp_int *s,
+ const uint8_t * const signature, const size_t signature_len)
+{
+ assert(curve != NULL && r != NULL && s != NULL);
+
+ if (signature == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ size_t len1, len2;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, signature, signature_len, &len1, &len2)) != HAL_OK)
+ return err;
+
+ const uint8_t * der = signature + len1;
+ const uint8_t * const der_end = der + len2;
+
+ if ((err = hal_asn1_decode_integer(r, der, &len1, der_end - der)) != HAL_OK)
+ return err;
+ der += len1;
+
+ if ((err = hal_asn1_decode_integer(s, der, &len1, der_end - der)) != HAL_OK)
+ return err;
+ der += len1;
+
+ if (der != der_end)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ return HAL_OK;
+}
+
+/*
+ * Sign a caller-supplied hash.
+ */
+
+hal_error_t hal_ecdsa_sign(const hal_ecdsa_key_t * const key,
+ const uint8_t * const hash, const size_t hash_len,
+ uint8_t *signature, size_t *signature_len, const size_t signature_max,
+ const hal_ecdsa_signature_format_t signature_format)
+{
+ if (key == NULL || hash == NULL || signature == NULL || signature_len == NULL || key->type != HAL_ECDSA_PRIVATE)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const ecdsa_curve_t * const curve = get_curve(key->curve);
+ if (curve == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ fp_int k[1]; fp_init(k);
+ fp_int r[1]; fp_init(r);
+ fp_int s[1]; fp_init(s);
+ fp_int e[1]; fp_init(e);
+
+ fp_int * const n = unconst_fp_int(curve->n);
+ fp_int * const d = unconst_fp_int(key->d);
+
+ ec_point_t R[1];
+ memset(R, 0, sizeof(R));
+
+ hal_error_t err;
+
+ fp_read_unsigned_bin(e, unconst_uint8_t(hash), hash_len);
+
+ do {
+
+ /*
+ * Pick random curve point R, then calculate r = Rx % n.
+ * If r == 0, we can't use this point, so go try again.
+ */
+
+ if ((err = point_pick_random(curve, k, R)) != HAL_OK)
+ goto fail;
+
+ assert(point_is_on_curve(R, curve));
+
+ if (fp_mod(R->x, n, r) != FP_OKAY)
+ lose(HAL_ERROR_IMPOSSIBLE);
+
+ if (fp_iszero(r))
+ continue;
+
+ /*
+ * Calculate s = ((e + dr)/k) % n.
+ * If s == 0, we can't use this point, so go try again.
+ */
+
+ if (fp_mulmod (d, r, n, s) != FP_OKAY)
+ lose(HAL_ERROR_IMPOSSIBLE);
+
+ fp_add (e, s, s);
+
+ if (fp_mod (s, n, s) != FP_OKAY ||
+ fp_invmod (k, n, k) != FP_OKAY ||
+ fp_mulmod (s, k, n, s) != FP_OKAY)
+ lose(HAL_ERROR_IMPOSSIBLE);
+
+ } while (fp_iszero(s));
+
+ /*
+ * Encode the signature, then we're done.
+ */
+
+ switch (signature_format) {
+
+ case HAL_ECDSA_SIGNATURE_FORMAT_ASN1:
+ if ((err = encode_signature_asn1(curve, r, s, signature, signature_len, signature_max)) != HAL_OK)
+ goto fail;
+ break;
+
+ case HAL_ECDSA_SIGNATURE_FORMAT_PKCS11:
+ if ((err = encode_signature_pkcs11(curve, r, s, signature, signature_len, signature_max)) != HAL_OK)
+ goto fail;
+ break;
+
+ default:
+ lose(HAL_ERROR_BAD_ARGUMENTS);
+ }
+
+ err = HAL_OK;
+
+ fail:
+ fp_zero(k); fp_zero(r); fp_zero(s); fp_zero(e);
+ memset(R, 0, sizeof(R));
+ return err;
+}
+
+/*
+ * Verify a signature using a caller-supplied hash.
+ */
+
+hal_error_t hal_ecdsa_verify(const hal_ecdsa_key_t * const key,
+ const uint8_t * const hash, const size_t hash_len,
+ const uint8_t * const signature, const size_t signature_len,
+ const hal_ecdsa_signature_format_t signature_format)
+{
+ assert(key != NULL && hash != NULL && signature != NULL);
+
+ const ecdsa_curve_t * const curve = get_curve(key->curve);
+
+ if (curve == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (!point_is_on_curve(key->Q, curve))
+ return HAL_ERROR_KEY_NOT_ON_CURVE;
+
+ fp_int * const n = unconst_fp_int(curve->n);
+
+ hal_error_t err;
+ fp_int r[1], s[1], e[1], w[1], u1[1], u2[1], v[1];
+ ec_point_t u1G[1], u2Q[1], R[1];
+
+ fp_init(w); fp_init(u1); fp_init(u2); fp_init(v);
+ memset(u1G, 0, sizeof(u1G));
+ memset(u2Q, 0, sizeof(u2Q));
+ memset(R, 0, sizeof(R));
+
+ /*
+ * Start by decoding the signature.
+ */
+
+ switch (signature_format) {
+
+ case HAL_ECDSA_SIGNATURE_FORMAT_ASN1:
+ if ((err = decode_signature_asn1(curve, r, s, signature, signature_len)) != HAL_OK)
+ return err;
+ break;
+
+ case HAL_ECDSA_SIGNATURE_FORMAT_PKCS11:
+ if ((err = decode_signature_pkcs11(curve, r, s, signature, signature_len)) != HAL_OK)
+ return err;
+ break;
+
+ default:
+ return HAL_ERROR_BAD_ARGUMENTS;
+ }
+
+ /*
+ * Check that r and s are in the allowed range, read the hash, then
+ * compute:
+ *
+ * w = 1 / s
+ * u1 = e * w
+ * u2 = r * w
+ * R = u1 * G + u2 * Q.
+ */
+
+ if (fp_cmp_d(r, 1) == FP_LT || fp_cmp(r, n) != FP_LT ||
+ fp_cmp_d(s, 1) == FP_LT || fp_cmp(s, n) != FP_LT)
+ return HAL_ERROR_INVALID_SIGNATURE;
+
+ fp_read_unsigned_bin(e, unconst_uint8_t(hash), hash_len);
+
+ if (fp_invmod(s, n, w) != FP_OKAY ||
+ fp_mulmod(e, w, n, u1) != FP_OKAY ||
+ fp_mulmod(r, w, n, u2) != FP_OKAY)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ fp_copy(unconst_fp_int(curve->Gx), u1G->x);
+ fp_copy(unconst_fp_int(curve->Gy), u1G->y);
+ fp_set(u1G->z, 1);
+
+ if ((err = point_scalar_multiply(u1, u1G, u1G, curve, 0)) != HAL_OK ||
+ (err = point_scalar_multiply(u2, key->Q, u2Q, curve, 0)) != HAL_OK)
+ return err;
+
+ if (point_is_infinite(u1G))
+ point_copy(u2Q, R);
+ else if (point_is_infinite(u2Q))
+ point_copy(u1G, R);
+ else
+ point_add(u1G, u2Q, R, curve);
+
+ /*
+ * Signature is OK if
+ * R is not the point at infinity, and
+ * Rx is congruent to r mod n.
+ */
+
+ if (point_is_infinite(R))
+ return HAL_ERROR_INVALID_SIGNATURE;
+
+ if ((err = point_to_affine(R, curve)) != HAL_OK)
+ return err;
+
+ if (fp_mod(R->x, n, v) != FP_OKAY)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ return fp_cmp(v, r) == FP_EQ ? HAL_OK : HAL_ERROR_INVALID_SIGNATURE;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ecdsa_curves.h b/ecdsa_curves.h
new file mode 100644
index 0000000..80896ec
--- /dev/null
+++ b/ecdsa_curves.h
@@ -0,0 +1,92 @@
+/*
+ * ecdsa_curves.h
+ * --------------
+ * Curve parameters for NIST P-256, P-384, and P-521 curves.
+ *
+ * At some point we may want to replace this file with one generated
+ * by a Python script, to make it easier to check the curve parameters.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, SUNET
+ *
+ * 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.
+ *
+ * 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 OWNER 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.
+ */
+
+static const uint8_t p256_q[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const uint8_t p256_b[] = { 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC,
+ 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B };
+static const uint8_t p256_Gx[] = { 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
+ 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96 };
+static const uint8_t p256_Gy[] = { 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
+ 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5 };
+static const uint8_t p256_n[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51 };
+static const uint8_t p256_oid[] = { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 };
+
+static const uint8_t p384_q[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
+static const uint8_t p384_b[] = { 0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B, 0xE3, 0xF8, 0x2D, 0x19,
+ 0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12, 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A,
+ 0xC6, 0x56, 0x39, 0x8D, 0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF };
+static const uint8_t p384_Gx[] = { 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD, 0x74,
+ 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38,
+ 0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7 };
+static const uint8_t p384_Gy[] = { 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, 0x6F, 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC, 0x29,
+ 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, 0x7C, 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, 0xC0,
+ 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81, 0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, 0x5F };
+static const uint8_t p384_n[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
+ 0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73 };
+static const uint8_t p384_oid[] = { 0x2b, 0x81, 0x04, 0x00, 0x22 };
+
+static const uint8_t p521_q[] = { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF };
+static const uint8_t p521_b[] = { 0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F, 0x92, 0x9A, 0x21, 0xA0, 0xB6, 0x85,
+ 0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3, 0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1,
+ 0x09, 0xE1, 0x56, 0x19, 0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1,
+ 0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1, 0xEF, 0x45, 0x1F, 0xD4, 0x6B, 0x50,
+ 0x3F, 0x00 };
+static const uint8_t p521_Gx[] = { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
+ 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38,
+ 0x64, 0x09 };
+static const uint8_t p521_Gy[] = { 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB, 0x66, 0x23, 0x95,
+ 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D,
+ 0x3D, 0xBA, 0xA1, 0x4B, 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF,
+ 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E, 0x31, 0xC2, 0xE5,
+ 0xBD, 0x66 };
+static const uint8_t p521_n[] = { 0x01, 0x18, 0x39, 0x29, 0x6A, 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C, 0x8A, 0x5F, 0xB4, 0x2C, 0x7D,
+ 0x1B, 0xD9, 0x98, 0xF5, 0x44, 0x49, 0x57, 0x9B, 0x44, 0x68, 0x17, 0xAF, 0xBD, 0x17, 0x27, 0x3E,
+ 0x66, 0x2C, 0x97, 0xEE, 0x72, 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5, 0x50, 0xB9, 0x01, 0x3F, 0xAD,
+ 0x07, 0x61, 0x35, 0x3C, 0x70, 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88, 0xBE, 0x94, 0x76, 0x9F, 0xD1,
+ 0x66, 0x50 };
+static const uint8_t p521_oid[] = { 0x2b, 0x81, 0x04, 0x00, 0x23 };
diff --git a/hal.h b/hal.h
index 64377b4..4a5e239 100644
--- a/hal.h
+++ b/hal.h
@@ -39,23 +39,23 @@
* 3 bits segment selector | up to 8 segments
* 5 bits core selector | up to 32 cores/segment (see note below)
* 8 bits register selector | up to 256 registers/core (see modexp below)
- *
+ *
* i.e, the address is structured as:
* sss ccccc rrrrrrrr
- *
+ *
* The I2C and UART communication channels use this 16-bit address format
* directly in their read and write commands.
- *
+ *
* The EIM communications channel translates this 16-bit address into a
* 32-bit memory-mapped address in the range 0x08000000..807FFFF:
* 00001000000000 sss 0 ccccc rrrrrrrr 00
- *
+ *
* EIM, as implemented on the Novena, uses a 19-bit address space:
* Bits 18..16 are the semgent selector.
* Bits 15..10 are the core selector.
* Bits 9..2 are the register selector.
* Bits 1..0 are zero, because reads and writes are always word aligned.
- *
+ *
* Note that EIM can support 64 cores per segment, but we sacrifice one bit
* in order to map it into a 16-bit address space.
*/
@@ -440,6 +440,8 @@
DEFINE_HAL_ERROR(HAL_ERROR_ALLOCATION_FAILURE, "Memory allocation failed") \
DEFINE_HAL_ERROR(HAL_ERROR_RESULT_TOO_LONG, "Result too long for buffer") \
DEFINE_HAL_ERROR(HAL_ERROR_ASN1_PARSE_FAILED, "ASN.1 parse failed") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KEY_NOT_ON_CURVE, "EC key is not on its purported curve") \
+ DEFINE_HAL_ERROR(HAL_ERROR_INVALID_SIGNATURE, "Invalid signature") \
END_OF_HAL_ERROR_LIST
/* Marker to forestall silly line continuation errors */
@@ -495,6 +497,12 @@ extern hal_error_t hal_get_random(void *buffer, const size_t length);
#define HAL_MAX_HASH_DIGEST_LENGTH SHA512_DIGEST_LEN
/*
+ * Opaque driver structure for digest algorithms.
+ */
+
+typedef struct hal_hash_driver hal_hash_driver_t;
+
+/*
* Public information about a digest algorithm.
*
* The _state_length values in the descriptor and the typed opaque
@@ -510,16 +518,16 @@ typedef struct {
size_t hmac_state_length;
const uint8_t * const digest_algorithm_id;
size_t digest_algorithm_id_length;
- const void *driver;
+ const hal_hash_driver_t *driver;
unsigned can_restore_state : 1;
} hal_hash_descriptor_t;
/*
- * Typed opaque pointers to internal state.
+ * Opaque pointers to internal state.
*/
-typedef struct { void *state; } hal_hash_state_t;
-typedef struct { void *state; } hal_hmac_state_t;
+typedef struct hal_hash_state hal_hash_state_t;
+typedef struct hal_hmac_state hal_hmac_state_t;
/*
* Supported digest algorithms. These are one-element arrays so that
@@ -542,28 +550,28 @@ extern void hal_hash_set_debug(int onoff);
extern hal_error_t hal_hash_core_present(const hal_hash_descriptor_t * const descriptor);
extern hal_error_t hal_hash_initialize(const hal_hash_descriptor_t * const descriptor,
- hal_hash_state_t *state,
+ hal_hash_state_t **state,
void *state_buffer, const size_t state_length);
-extern hal_error_t hal_hash_update(const hal_hash_state_t state,
+extern hal_error_t hal_hash_update(hal_hash_state_t *state,
const uint8_t * data, const size_t length);
-extern hal_error_t hal_hash_finalize(const hal_hash_state_t state,
+extern hal_error_t hal_hash_finalize(hal_hash_state_t *state,
uint8_t *digest, const size_t length);
extern hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor,
- hal_hmac_state_t *state,
+ hal_hmac_state_t **state,
void *state_buffer, const size_t state_length,
const uint8_t * const key, const size_t key_length);
-extern hal_error_t hal_hmac_update(const hal_hmac_state_t state,
+extern hal_error_t hal_hmac_update(hal_hmac_state_t *state,
const uint8_t * data, const size_t length);
-extern hal_error_t hal_hmac_finalize(const hal_hmac_state_t state,
+extern hal_error_t hal_hmac_finalize(hal_hmac_state_t *state,
uint8_t *hmac, const size_t length);
-extern void hal_hash_cleanup(hal_hash_state_t *state);
+extern void hal_hash_cleanup(hal_hash_state_t **state);
-extern void hal_hmac_cleanup(hal_hmac_state_t *state);
+extern void hal_hmac_cleanup(hal_hmac_state_t **state);
/*
* AES key wrap functions.
@@ -608,7 +616,7 @@ extern hal_error_t hal_modexp(const uint8_t * const msg, const size_t msg_len, /
typedef enum { HAL_RSA_PRIVATE, HAL_RSA_PUBLIC } hal_rsa_key_type_t;
-typedef struct { void *key; } hal_rsa_key_t;
+typedef struct hal_rsa_key hal_rsa_key_t;
extern const size_t hal_rsa_key_t_size;
@@ -616,7 +624,7 @@ extern void hal_rsa_set_debug(const int onoff);
extern void hal_rsa_set_blinding(const int onoff);
-extern hal_error_t hal_rsa_key_load_private(hal_rsa_key_t *key,
+extern hal_error_t hal_rsa_key_load_private(hal_rsa_key_t **key,
void *keybuf, const size_t keybuf_len,
const uint8_t * const n, const size_t n_len,
const uint8_t * const e, const size_t e_len,
@@ -627,48 +635,122 @@ extern hal_error_t hal_rsa_key_load_private(hal_rsa_key_t *key,
const uint8_t * const dP, const size_t dP_len,
const uint8_t * const dQ, const size_t dQ_len);
-extern hal_error_t hal_rsa_key_load_public(hal_rsa_key_t *key,
+extern hal_error_t hal_rsa_key_load_public(hal_rsa_key_t **key,
void *keybuf, const size_t keybuf_len,
const uint8_t * const n, const size_t n_len,
const uint8_t * const e, const size_t e_len);
-extern hal_error_t hal_rsa_key_get_type(hal_rsa_key_t key,
+extern hal_error_t hal_rsa_key_get_type(const hal_rsa_key_t * const key,
hal_rsa_key_type_t *key_type);
-extern hal_error_t hal_rsa_key_get_modulus(hal_rsa_key_t key,
+extern hal_error_t hal_rsa_key_get_modulus(const hal_rsa_key_t * const key,
uint8_t *modulus,
size_t *modulus_len,
const size_t modulus_max);
-extern hal_error_t hal_rsa_key_get_public_exponent(hal_rsa_key_t key,
+extern hal_error_t hal_rsa_key_get_public_exponent(const hal_rsa_key_t * const key,
uint8_t *public_exponent,
size_t *public_exponent_len,
const size_t public_exponent_max);
-extern void hal_rsa_key_clear(hal_rsa_key_t key);
+extern void hal_rsa_key_clear(hal_rsa_key_t *key);
-extern hal_error_t hal_rsa_encrypt(hal_rsa_key_t key,
+extern hal_error_t hal_rsa_encrypt(const hal_rsa_key_t * const key,
const uint8_t * const input, const size_t input_len,
uint8_t * output, const size_t output_len);
-extern hal_error_t hal_rsa_decrypt(hal_rsa_key_t key,
+extern hal_error_t hal_rsa_decrypt(const hal_rsa_key_t * const key,
const uint8_t * const input, const size_t input_len,
uint8_t * output, const size_t output_len);
-extern hal_error_t hal_rsa_key_gen(hal_rsa_key_t *key,
+extern hal_error_t hal_rsa_key_gen(hal_rsa_key_t **key,
void *keybuf, const size_t keybuf_len,
const unsigned key_length,
const uint8_t * const public_exponent, const size_t public_exponent_len);
-extern hal_error_t hal_rsa_key_to_der(hal_rsa_key_t key,
+extern hal_error_t hal_rsa_key_to_der(const hal_rsa_key_t * const key,
uint8_t *der, size_t *der_len, const size_t der_max);
-extern size_t hal_rsa_key_to_der_len(hal_rsa_key_t key);
+extern size_t hal_rsa_key_to_der_len(const hal_rsa_key_t * const key);
-extern hal_error_t hal_rsa_key_from_der(hal_rsa_key_t *key,
+extern hal_error_t hal_rsa_key_from_der(hal_rsa_key_t **key,
void *keybuf, const size_t keybuf_len,
const uint8_t * const der, const size_t der_len);
+/*
+ * ECDSA.
+ */
+
+typedef enum { HAL_ECDSA_PRIVATE, HAL_ECDSA_PUBLIC } hal_ecdsa_key_type_t;
+
+typedef enum { HAL_ECDSA_CURVE_P256, HAL_ECDSA_CURVE_P384, HAL_ECDSA_CURVE_P521 } hal_ecdsa_curve_t;
+
+typedef enum { HAL_ECDSA_SIGNATURE_FORMAT_ASN1, HAL_ECDSA_SIGNATURE_FORMAT_PKCS11 } hal_ecdsa_signature_format_t;
+
+typedef struct hal_ecdsa_key hal_ecdsa_key_t;
+
+extern const size_t hal_ecdsa_key_t_size;
+
+extern void hal_ecdsa_set_debug(const int onoff);
+
+extern hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key,
+ void *keybuf, const size_t keybuf_len,
+ const hal_ecdsa_curve_t curve,
+ const uint8_t * const x, const size_t x_len,
+ const uint8_t * const y, const size_t y_len,
+ const uint8_t * const d, const size_t d_len);
+
+extern hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key,
+ void *keybuf, const size_t keybuf_len,
+ const hal_ecdsa_curve_t curve,
+ const uint8_t * const x, const size_t x_len,
+ const uint8_t * const y, const size_t y_len);
+
+extern hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key,
+ hal_ecdsa_key_type_t *key_type);
+
+extern hal_error_t hal_ecdsa_key_get_curve(const hal_ecdsa_key_t * const key,
+ hal_ecdsa_curve_t *curve);
+
+extern hal_error_t hal_ecdsa_key_get_public(const hal_ecdsa_key_t * const key,
+ uint8_t *x, size_t *x_len, const size_t x_max,
+ uint8_t *y, size_t *y_len, const size_t y_max);
+
+extern void hal_ecdsa_key_clear(hal_ecdsa_key_t *key);
+
+extern hal_error_t hal_ecdsa_key_gen(hal_ecdsa_key_t **key,
+ void *keybuf, const size_t keybuf_len,
+ const hal_ecdsa_curve_t curve);
+
+extern hal_error_t hal_ecdsa_key_to_der(const hal_ecdsa_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+extern size_t hal_ecdsa_key_to_der_len(const hal_ecdsa_key_t * const key);
+
+extern hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len);
+
+extern hal_error_t hal_ecdsa_key_to_ecpoint(const hal_ecdsa_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+extern size_t hal_ecdsa_key_to_ecpoint_len(const hal_ecdsa_key_t * const key);
+
+extern hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len,
+ const hal_ecdsa_curve_t curve);
+
+extern hal_error_t hal_ecdsa_sign(const hal_ecdsa_key_t * const key,
+ const uint8_t * const hash, const size_t hash_len,
+ uint8_t *signature, size_t *signature_len, const size_t signature_max,
+ const hal_ecdsa_signature_format_t signature_format);
+
+extern hal_error_t hal_ecdsa_verify(const hal_ecdsa_key_t * const key,
+ const uint8_t * const hash, const size_t hash_len,
+ const uint8_t * const signature, const size_t signature_len,
+ const hal_ecdsa_signature_format_t signature_format);
+
#endif /* _HAL_H_ */
/*
diff --git a/hal_io_eim.c b/hal_io_eim.c
index bdc3171..3687b95 100644
--- a/hal_io_eim.c
+++ b/hal_io_eim.c
@@ -1,11 +1,11 @@
-/*
+/*
* hal_io_eim.c
* ------------
* This module contains common code to talk to the FPGA over the EIM bus.
- *
+ *
* Author: Paul Selkirk
* Copyright (c) 2014-2015, NORDUnet A/S All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
diff --git a/hal_io_i2c.c b/hal_io_i2c.c
index c98ea7d..9788232 100644
--- a/hal_io_i2c.c
+++ b/hal_io_i2c.c
@@ -1,11 +1,11 @@
-/*
+/*
* hal_io_i2c.c
* ------------
* This module contains common code to talk to the FPGA over the I2C bus.
- *
+ *
* Author: Paul Selkirk
* Copyright (c) 2014-2015, NORDUnet A/S All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
diff --git a/hash.c b/hash.c
index 45e2f59..e06278d 100644
--- a/hash.c
+++ b/hash.c
@@ -1,34 +1,34 @@
-/*
+/*
* hashes.c
* --------
* HAL interface to Cryptech hash cores.
- *
+ *
* Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein
* Copyright (c) 2014-2015, SUNET
- *
- * 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.
- *
- * 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *
+ * 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.
+ *
+ * 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 OWNER 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
+ * 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.
*/
@@ -64,7 +64,7 @@
* memory map, so it's not really worth overthinking at the moment.
*/
-typedef struct {
+struct hal_hash_driver {
size_t length_length; /* Length of the length field */
off_t block_addr; /* Where to write hash blocks */
off_t ctrl_addr; /* Control register */
@@ -73,16 +73,16 @@ typedef struct {
off_t name_addr; /* Where to read core name */
char core_name[8]; /* Expected name of core */
uint8_t ctrl_mode; /* Digest mode, for cores that have modes */
-} driver_t;
+};
/*
* Hash state. For now we assume that the only core state we need to
* save and restore is the current digest value.
*/
-typedef struct {
+struct hal_hash_state {
const hal_hash_descriptor_t *descriptor;
- const driver_t *driver;
+ const hal_hash_driver_t *driver;
uint64_t msg_length_high; /* Total data hashed in this message */
uint64_t msg_length_low; /* (128 bits in SHA-512 cases) */
uint8_t block[HAL_MAX_HASH_BLOCK_LENGTH], /* Block we're accumulating */
@@ -90,7 +90,7 @@ typedef struct {
size_t block_used; /* How much of the block we've used */
unsigned block_count; /* Blocks sent */
unsigned flags;
-} internal_hash_state_t;
+};
#define STATE_FLAG_STATE_ALLOCATED 0x1 /* State buffer dynamically allocated */
@@ -102,10 +102,10 @@ typedef struct {
* performance boost for things like PBKDF2.
*/
-typedef struct {
- internal_hash_state_t hash_state; /* Hash state */
+struct hal_hmac_state {
+ hal_hash_state_t hash_state; /* Hash state */
uint8_t keybuf[HAL_MAX_HASH_BLOCK_LENGTH]; /* HMAC key */
-} internal_hmac_state_t;
+};
/*
* Drivers for known digest algorithms.
@@ -115,42 +115,42 @@ typedef struct {
* whine if the resulting string doesn't fit into the field.
*/
-static const driver_t sha1_driver = {
+static const hal_hash_driver_t sha1_driver = {
SHA1_LENGTH_LEN,
SHA1_ADDR_BLOCK, SHA1_ADDR_CTRL, SHA1_ADDR_STATUS, SHA1_ADDR_DIGEST,
SHA1_ADDR_NAME0, (SHA1_NAME0 SHA1_NAME1),
0
};
-static const driver_t sha256_driver = {
+static const hal_hash_driver_t sha256_driver = {
SHA256_LENGTH_LEN,
SHA256_ADDR_BLOCK, SHA256_ADDR_CTRL, SHA256_ADDR_STATUS, SHA256_ADDR_DIGEST,
SHA256_ADDR_NAME0, (SHA256_NAME0 SHA256_NAME1),
0
};
-static const driver_t sha512_224_driver = {
+static const hal_hash_driver_t sha512_224_driver = {
SHA512_LENGTH_LEN,
SHA512_ADDR_BLOCK, SHA512_ADDR_CTRL, SHA512_ADDR_STATUS, SHA512_ADDR_DIGEST,
SHA512_ADDR_NAME0, (SHA512_NAME0 SHA512_NAME1),
MODE_SHA_512_224
};
-static const driver_t sha512_256_driver = {
+static const hal_hash_driver_t sha512_256_driver = {
SHA512_LENGTH_LEN,
SHA512_ADDR_BLOCK, SHA512_ADDR_CTRL, SHA512_ADDR_STATUS, SHA512_ADDR_DIGEST,
SHA512_ADDR_NAME0, (SHA512_NAME0 SHA512_NAME1),
MODE_SHA_512_256
};
-static const driver_t sha384_driver = {
+static const hal_hash_driver_t sha384_driver = {
SHA512_LENGTH_LEN,
SHA512_ADDR_BLOCK, SHA512_ADDR_CTRL, SHA512_ADDR_STATUS, SHA512_ADDR_DIGEST,
SHA512_ADDR_NAME0, (SHA512_NAME0 SHA512_NAME1),
MODE_SHA_384
};
-static const driver_t sha512_driver = {
+static const hal_hash_driver_t sha512_driver = {
SHA512_LENGTH_LEN,
SHA512_ADDR_BLOCK, SHA512_ADDR_CTRL, SHA512_ADDR_STATUS, SHA512_ADDR_DIGEST,
SHA512_ADDR_NAME0, (SHA512_NAME0 SHA512_NAME1),
@@ -188,42 +188,42 @@ static const uint8_t
const hal_hash_descriptor_t hal_hash_sha1[1] = {{
SHA1_BLOCK_LEN, SHA1_DIGEST_LEN,
- sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t),
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha1, sizeof(dalgid_sha1),
&sha1_driver, 0
}};
const hal_hash_descriptor_t hal_hash_sha256[1] = {{
SHA256_BLOCK_LEN, SHA256_DIGEST_LEN,
- sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t),
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha256, sizeof(dalgid_sha256),
&sha256_driver, 1
}};
const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{
SHA512_BLOCK_LEN, SHA512_224_DIGEST_LEN,
- sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t),
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha512_224, sizeof(dalgid_sha512_224),
&sha512_224_driver, 0
}};
const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{
SHA512_BLOCK_LEN, SHA512_256_DIGEST_LEN,
- sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t),
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha512_256, sizeof(dalgid_sha512_256),
&sha512_256_driver, 0
}};
const hal_hash_descriptor_t hal_hash_sha384[1] = {{
SHA512_BLOCK_LEN, SHA384_DIGEST_LEN,
- sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t),
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha384, sizeof(dalgid_sha384),
&sha384_driver, 0
}};
const hal_hash_descriptor_t hal_hash_sha512[1] = {{
SHA512_BLOCK_LEN, SHA512_DIGEST_LEN,
- sizeof(internal_hash_state_t), sizeof(internal_hmac_state_t),
+ sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha512, sizeof(dalgid_sha512),
&sha512_driver, 0
}};
@@ -247,7 +247,7 @@ void hal_hash_set_debug(int onoff)
* Returns the driver pointer on success, NULL on failure.
*/
-static const driver_t *check_driver(const hal_hash_descriptor_t * const descriptor)
+static const hal_hash_driver_t *check_driver(const hal_hash_descriptor_t * const descriptor)
{
return descriptor == NULL ? NULL : descriptor->driver;
}
@@ -258,7 +258,7 @@ static const driver_t *check_driver(const hal_hash_descriptor_t * const descript
hal_error_t hal_hash_core_present(const hal_hash_descriptor_t * const descriptor)
{
- const driver_t * const driver = check_driver(descriptor);
+ const hal_hash_driver_t * const driver = check_driver(descriptor);
if (driver == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
@@ -273,13 +273,13 @@ hal_error_t hal_hash_core_present(const hal_hash_descriptor_t * const descriptor
*/
hal_error_t hal_hash_initialize(const hal_hash_descriptor_t * const descriptor,
- hal_hash_state_t *opaque_state,
+ hal_hash_state_t **state_,
void *state_buffer, const size_t state_length)
{
- const driver_t * const driver = check_driver(descriptor);
- internal_hash_state_t *state = state_buffer;
+ const hal_hash_driver_t * const driver = check_driver(descriptor);
+ hal_hash_state_t *state = state_buffer;
- if (driver == NULL || opaque_state == NULL)
+ if (driver == NULL || state_ == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
if (state_buffer != NULL && state_length < descriptor->hash_state_length)
@@ -295,7 +295,7 @@ hal_error_t hal_hash_initialize(const hal_hash_descriptor_t * const descriptor,
if (state_buffer == NULL)
state->flags |= STATE_FLAG_STATE_ALLOCATED;
- opaque_state->state = state;
+ *state_ = state;
return HAL_OK;
}
@@ -304,19 +304,19 @@ hal_error_t hal_hash_initialize(const hal_hash_descriptor_t * const descriptor,
* Clean up hash state. No-op unless memory was dynamically allocated.
*/
-void hal_hash_cleanup(hal_hash_state_t *opaque_state)
+void hal_hash_cleanup(hal_hash_state_t **state_)
{
- if (opaque_state == NULL)
+ if (state_ == NULL)
return;
- internal_hash_state_t *state = opaque_state->state;
+ hal_hash_state_t *state = *state_;
if (state == NULL || (state->flags & STATE_FLAG_STATE_ALLOCATED) == 0)
return;
memset(state, 0, state->descriptor->hash_state_length);
free(state);
- opaque_state->state = NULL;
+ *state_ = NULL;
}
/*
@@ -324,7 +324,7 @@ void hal_hash_cleanup(hal_hash_state_t *opaque_state)
* read current hash state from core.
*/
-static hal_error_t hash_read_digest(const driver_t * const driver,
+static hal_error_t hash_read_digest(const hal_hash_driver_t * const driver,
uint8_t *digest,
const size_t digest_length)
{
@@ -342,7 +342,7 @@ static hal_error_t hash_read_digest(const driver_t * const driver,
* Write hash state back to core.
*/
-static hal_error_t hash_write_digest(const driver_t * const driver,
+static hal_error_t hash_write_digest(const hal_hash_driver_t * const driver,
const uint8_t * const digest,
const size_t digest_length)
{
@@ -360,7 +360,7 @@ static hal_error_t hash_write_digest(const driver_t * const driver,
* Send one block to a core.
*/
-static hal_error_t hash_write_block(internal_hash_state_t *state)
+static hal_error_t hash_write_block(hal_hash_state_t * const state)
{
uint8_t ctrl_cmd[4];
hal_error_t err;
@@ -388,7 +388,7 @@ static hal_error_t hash_write_block(internal_hash_state_t *state)
return err;
ctrl_cmd[0] = ctrl_cmd[1] = ctrl_cmd[2] = 0;
- ctrl_cmd[3] = state->block_count == 0 ? CTRL_INIT : CTRL_NEXT;
+ ctrl_cmd[3] = state->block_count == 0 ? CTRL_INIT : CTRL_NEXT;
ctrl_cmd[3] |= state->driver->ctrl_mode;
if ((err = hal_io_write(state->driver->ctrl_addr, ctrl_cmd, sizeof(ctrl_cmd))) != HAL_OK)
@@ -406,11 +406,10 @@ static hal_error_t hash_write_block(internal_hash_state_t *state)
* Add data to hash.
*/
-hal_error_t hal_hash_update(hal_hash_state_t opaque_state, /* Opaque state block */
+hal_error_t hal_hash_update(hal_hash_state_t *state, /* Opaque state block */
const uint8_t * const data_buffer, /* Data to be hashed */
size_t data_buffer_length) /* Length of data_buffer */
{
- internal_hash_state_t *state = opaque_state.state;
const uint8_t *p = data_buffer;
hal_error_t err;
size_t n;
@@ -463,11 +462,10 @@ hal_error_t hal_hash_update(hal_hash_state_t opaque_state, /* Opaque state
* Finish hash and return digest.
*/
-hal_error_t hal_hash_finalize(hal_hash_state_t opaque_state, /* Opaque state block */
+hal_error_t hal_hash_finalize(hal_hash_state_t *state, /* Opaque state block */
uint8_t *digest_buffer, /* Returned digest */
const size_t digest_buffer_length) /* Length of digest_buffer */
{
- internal_hash_state_t *state = opaque_state.state;
uint64_t bit_length_high, bit_length_low;
hal_error_t err;
uint8_t *p;
@@ -543,17 +541,16 @@ hal_error_t hal_hash_finalize(hal_hash_state_t opaque_state, /* Opaqu
*/
hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor,
- hal_hmac_state_t *opaque_state,
+ hal_hmac_state_t **state_,
void *state_buffer, const size_t state_length,
const uint8_t * const key, const size_t key_length)
{
- const driver_t * const driver = check_driver(descriptor);
- internal_hmac_state_t *state = state_buffer;
- hal_hash_state_t oh;
+ const hal_hash_driver_t * const driver = check_driver(descriptor);
+ hal_hmac_state_t *state = state_buffer;
hal_error_t err;
int i;
- if (driver == NULL || opaque_state == NULL)
+ if (descriptor == NULL || driver == NULL || state_ == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
if (state_buffer != NULL && state_length < descriptor->hmac_state_length)
@@ -562,7 +559,7 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor,
if (state_buffer == NULL && (state = malloc(descriptor->hmac_state_length)) == NULL)
return HAL_ERROR_ALLOCATION_FAILURE;
- internal_hash_state_t *h = &state->hash_state;
+ hal_hash_state_t *h = &state->hash_state;
assert(descriptor->block_length <= sizeof(state->keybuf));
@@ -576,7 +573,8 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor,
return HAL_ERROR_UNSUPPORTED_KEY;
#endif
- if ((err = hal_hash_initialize(descriptor, &oh, h, sizeof(*h))) != HAL_OK)
+ if ((err = hal_hash_initialize(descriptor, &h, &state->hash_state,
+ sizeof(state->hash_state))) != HAL_OK)
goto fail;
if (state_buffer == NULL)
@@ -593,9 +591,10 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor,
if (key_length <= descriptor->block_length)
memcpy(state->keybuf, key, key_length);
- else if ((err = hal_hash_update(oh, key, key_length)) != HAL_OK ||
- (err = hal_hash_finalize(oh, state->keybuf, sizeof(state->keybuf))) != HAL_OK ||
- (err = hal_hash_initialize(descriptor, &oh, h, sizeof(*h))) != HAL_OK)
+ else if ((err = hal_hash_update(h, key, key_length)) != HAL_OK ||
+ (err = hal_hash_finalize(h, state->keybuf, sizeof(state->keybuf))) != HAL_OK ||
+ (err = hal_hash_initialize(descriptor, &h, &state->hash_state,
+ sizeof(state->hash_state))) != HAL_OK)
goto fail;
/*
@@ -605,7 +604,7 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor,
for (i = 0; i < descriptor->block_length; i++)
state->keybuf[i] ^= HMAC_IPAD;
- if ((err = hal_hash_update(oh, state->keybuf, descriptor->block_length)) != HAL_OK)
+ if ((err = hal_hash_update(h, state->keybuf, descriptor->block_length)) != HAL_OK)
goto fail;
/*
@@ -624,7 +623,7 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor,
* when the hash cores support such a thing.
*/
- opaque_state->state = state;
+ *state_ = state;
return HAL_OK;
@@ -638,61 +637,54 @@ hal_error_t hal_hmac_initialize(const hal_hash_descriptor_t * const descriptor,
* Clean up HMAC state. No-op unless memory was dynamically allocated.
*/
-void hal_hmac_cleanup(hal_hmac_state_t *opaque_state)
+void hal_hmac_cleanup(hal_hmac_state_t **state_)
{
- if (opaque_state == NULL)
+ if (state_ == NULL)
return;
- internal_hmac_state_t *state = opaque_state->state;
+ hal_hmac_state_t *state = *state_;
if (state == NULL)
return;
- internal_hash_state_t *h = &state->hash_state;
+ hal_hash_state_t *h = &state->hash_state;
if ((h->flags & STATE_FLAG_STATE_ALLOCATED) == 0)
return;
memset(state, 0, h->descriptor->hmac_state_length);
free(state);
- opaque_state->state = NULL;
+ *state_ = NULL;
}
/*
* Add data to HMAC.
*/
-hal_error_t hal_hmac_update(const hal_hmac_state_t opaque_state,
+hal_error_t hal_hmac_update(hal_hmac_state_t *state,
const uint8_t * data, const size_t length)
{
- internal_hmac_state_t *state = opaque_state.state;
- internal_hash_state_t *h = &state->hash_state;
- hal_hash_state_t oh = { h };
-
if (state == NULL || data == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- return hal_hash_update(oh, data, length);
+ return hal_hash_update(&state->hash_state, data, length);
}
/*
* Finish and return HMAC.
*/
-hal_error_t hal_hmac_finalize(const hal_hmac_state_t opaque_state,
+hal_error_t hal_hmac_finalize(hal_hmac_state_t *state,
uint8_t *hmac, const size_t length)
{
- internal_hmac_state_t *state = opaque_state.state;
- internal_hash_state_t *h = &state->hash_state;
- const hal_hash_descriptor_t *descriptor;
- hal_hash_state_t oh = { h };
- uint8_t d[HAL_MAX_HASH_DIGEST_LENGTH];
- hal_error_t err;
-
if (state == NULL || hmac == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- descriptor = h->descriptor;
+ hal_hash_state_t *h = &state->hash_state;
+ const hal_hash_descriptor_t *descriptor = h->descriptor;
+ uint8_t d[HAL_MAX_HASH_DIGEST_LENGTH];
+ hal_error_t err;
+
assert(descriptor != NULL && descriptor->digest_length <= sizeof(d));
/*
@@ -700,11 +692,12 @@ hal_error_t hal_hmac_finalize(const hal_hmac_state_t opaque_state,
* to get HMAC. Key was prepared for this in hal_hmac_initialize().
*/
- if ((err = hal_hash_finalize(oh, d, sizeof(d))) != HAL_OK ||
- (err = hal_hash_initialize(descriptor, &oh, h, sizeof(*h))) != HAL_OK ||
- (err = hal_hash_update(oh, state->keybuf, descriptor->block_length)) != HAL_OK ||
- (err = hal_hash_update(oh, d, descriptor->digest_length)) != HAL_OK ||
- (err = hal_hash_finalize(oh, hmac, length)) != HAL_OK)
+ if ((err = hal_hash_finalize(h, d, sizeof(d))) != HAL_OK ||
+ (err = hal_hash_initialize(descriptor, &h, &state->hash_state,
+ sizeof(state->hash_state))) != HAL_OK ||
+ (err = hal_hash_update(h, state->keybuf, descriptor->block_length)) != HAL_OK ||
+ (err = hal_hash_update(h, d, descriptor->digest_length)) != HAL_OK ||
+ (err = hal_hash_finalize(h, hmac, length)) != HAL_OK)
return err;
return HAL_OK;
diff --git a/novena-eim.c b/novena-eim.c
index c8c47ad..b55b01c 100644
--- a/novena-eim.c
+++ b/novena-eim.c
@@ -1,12 +1,12 @@
-/*
+/*
* novena-eim.c
* ------------
* This module contains the userland magic to set up and use the EIM bus.
*
- *
+ *
* Author: Pavel Shatov
* Copyright (c) 2014-2015, NORDUnet A/S All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
@@ -118,9 +118,9 @@ enum IMX6DQ_REGISTER_OFFSET
IOMUXC_SW_PAD_CTL_PAD_EIM_AD15 = 0x020E0464,
IOMUXC_SW_PAD_CTL_PAD_EIM_WAIT_B = 0x020E0468,
IOMUXC_SW_PAD_CTL_PAD_EIM_BCLK = 0x020E046C,
-
+
CCM_CCGR6 = 0x020C4080,
-
+
EIM_CS0GCR1 = 0x021B8000,
EIM_CS0GCR2 = 0x021B8004,
EIM_CS0RCR1 = 0x021B8008,
@@ -166,17 +166,17 @@ struct CCM_CCGR6
unsigned int cg1_usdhc1 : 2;
unsigned int cg2_usdhc2 : 2;
unsigned int cg3_usdhc3 : 2;
-
+
unsigned int cg3_usdhc4 : 2;
unsigned int cg5_eim_slow : 2;
unsigned int cg6_vdoaxiclk : 2;
unsigned int cg7_vpu : 2;
-
+
unsigned int cg8_reserved : 2;
unsigned int cg9_reserved : 2;
unsigned int cg10_reserved : 2;
unsigned int cg11_reserved : 2;
-
+
unsigned int cg12_reserved : 2;
unsigned int cg13_reserved : 2;
unsigned int cg14_reserved : 2;
diff --git a/pbkdf2.c b/pbkdf2.c
index 24395e7..4ad1e3a 100644
--- a/pbkdf2.c
+++ b/pbkdf2.c
@@ -58,7 +58,7 @@ static hal_error_t do_hmac(const hal_hash_descriptor_t * const d,
assert(d != NULL && pw != NULL && data != NULL && mac != NULL);
uint8_t sb[d->hmac_state_length];
- hal_hmac_state_t s;
+ hal_hmac_state_t *s;
hal_error_t err;
if ((err = hal_hmac_initialize(d, &s, sb, sizeof(sb), pw, pw_len)) != HAL_OK)
diff --git a/rsa.c b/rsa.c
index 2e950b8..3962a74 100644
--- a/rsa.c
+++ b/rsa.c
@@ -9,7 +9,7 @@
* (but no simpler).
*
* Much of the code in this module is based, at least loosely, on Tom
- * St Denis's libtomcrypt code.
+ * St Denis's libtomcrypt code.
*
* Authors: Rob Austein
* Copyright (c) 2015, SUNET
@@ -40,6 +40,25 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/*
+ * We use "Tom's Fast Math" library for our bignum implementation.
+ * This particular implementation has a couple of nice features:
+ *
+ * - The code is relatively readable, thus reviewable.
+ *
+ * - The bignum representation doesn't use dynamic memory, which
+ * simplifies things for us.
+ *
+ * The price tag for not using dynamic memory is that libtfm has to be
+ * configured to know about the largest bignum one wants it to be able
+ * to support at compile time. This should not be a serious problem.
+ *
+ * Unfortunately, libtfm is bad about const-ification, but we want to
+ * hide that from our users, so our public API uses const as
+ * appropriate and we use inline functions to remove const constraints
+ * in a relatively type-safe manner before calling libtom.
+ */
+
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -48,6 +67,8 @@
#include <assert.h>
#include "hal.h"
+#include <tfm.h>
+#include "asn1_internal.h"
/*
* Whether to use ModExp core. It works, but at the moment it's so
@@ -59,22 +80,6 @@
#endif
/*
- * Use "Tom's Fast Math" library for our bignum implementation. This
- * particular implementation has a couple of nice features:
- *
- * - The code is relatively readable, thus reviewable.
- *
- * - The bignum representation doesn't use dynamic memory, which
- * simplifies things for us.
- *
- * The price tag for not using dynamic memory is that libtfm has to be
- * configured to know about the largest bignum one wants it to be able
- * to support at compile time. This should not be a serious problem.
- */
-
-#include <tfm.h>
-
-/*
* Whether we want debug output.
*/
@@ -103,7 +108,7 @@ void hal_rsa_set_blinding(const int onoff)
* can make memory allocation the caller's problem.
*/
-struct rsa_key {
+struct hal_rsa_key {
hal_rsa_key_type_t type; /* What kind of key this is */
fp_int n; /* The modulus */
fp_int e; /* Public exponent */
@@ -115,7 +120,7 @@ struct rsa_key {
fp_int dQ; /* d mod (q - 1) */
};
-const size_t hal_rsa_key_t_size = sizeof(struct rsa_key);
+const size_t hal_rsa_key_t_size = sizeof(hal_rsa_key_t);
/*
* Error handling.
@@ -139,19 +144,19 @@ const size_t hal_rsa_key_t_size = sizeof(struct rsa_key);
* Unpack a bignum into a byte array, with length check.
*/
-static hal_error_t unpack_fp(fp_int *bn, uint8_t *buffer, const size_t length)
+static hal_error_t unpack_fp(const fp_int * const bn, uint8_t *buffer, const size_t length)
{
hal_error_t err = HAL_OK;
assert(bn != NULL && buffer != NULL);
- const size_t bytes = fp_unsigned_bin_size(bn);
+ const size_t bytes = fp_unsigned_bin_size(unconst_fp_int(bn));
if (bytes > length)
lose(HAL_ERROR_RESULT_TOO_LONG);
memset(buffer, 0, length);
- fp_to_unsigned_bin(bn, buffer + length - bytes);
+ fp_to_unsigned_bin(unconst_fp_int(bn), buffer + length - bytes);
fail:
return err;
@@ -164,7 +169,10 @@ static hal_error_t unpack_fp(fp_int *bn, uint8_t *buffer, const size_t length)
* wrap result back up as a bignum.
*/
-static hal_error_t modexp(fp_int *msg, fp_int *exp, fp_int *mod, fp_int *res)
+static hal_error_t modexp(const fp_int * msg,
+ const fp_int * const exp,
+ const fp_int * const mod,
+ fp_int *res)
{
hal_error_t err = HAL_OK;
@@ -172,14 +180,14 @@ static hal_error_t modexp(fp_int *msg, fp_int *exp, fp_int *mod, fp_int *res)
fp_int reduced_msg;
- if (fp_cmp_mag(msg, mod) != FP_LT) {
+ if (fp_cmp_mag(unconst_fp_int(msg), unconst_fp_int(mod)) != FP_LT) {
fp_init(&reduced_msg);
- fp_mod(msg, mod, &reduced_msg);
+ fp_mod(unconst_fp_int(msg), unconst_fp_int(mod), &reduced_msg);
msg = &reduced_msg;
}
- const size_t exp_len = (fp_unsigned_bin_size(exp) + 3) & ~3;
- const size_t mod_len = (fp_unsigned_bin_size(mod) + 3) & ~3;
+ const size_t exp_len = (fp_unsigned_bin_size(unconst_fp_int(exp)) + 3) & ~3;
+ const size_t mod_len = (fp_unsigned_bin_size(unconst_fp_int(mod)) + 3) & ~3;
uint8_t msgbuf[mod_len];
uint8_t expbuf[exp_len];
@@ -227,10 +235,13 @@ int fp_exptmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
* wait for the slow FPGA implementation.
*/
-static hal_error_t modexp(fp_int *msg, fp_int *exp, fp_int *mod, fp_int *res)
+static hal_error_t modexp(const fp_int * const msg,
+ const fp_int * const exp,
+ const fp_int * const mod,
+ fp_int *res)
{
hal_error_t err = HAL_OK;
- FP_CHECK(fp_exptmod(msg, exp, mod, res));
+ FP_CHECK(fp_exptmod(unconst_fp_int(msg), unconst_fp_int(exp), unconst_fp_int(mod), res));
fail:
return err;
}
@@ -243,11 +254,11 @@ static hal_error_t modexp(fp_int *msg, fp_int *exp, fp_int *mod, fp_int *res)
* try. Come back to this if it looks like a bottleneck.
*/
-static hal_error_t create_blinding_factors(struct rsa_key *key, fp_int *bf, fp_int *ubf)
+static hal_error_t create_blinding_factors(const hal_rsa_key_t * const key, fp_int *bf, fp_int *ubf)
{
assert(key != NULL && bf != NULL && ubf != NULL);
- uint8_t rnd[fp_unsigned_bin_size(&key->n)];
+ uint8_t rnd[fp_unsigned_bin_size(unconst_fp_int(&key->n))];
hal_error_t err = HAL_OK;
if ((err = hal_get_random(rnd, sizeof(rnd))) != HAL_OK)
@@ -260,7 +271,7 @@ static hal_error_t create_blinding_factors(struct rsa_key *key, fp_int *bf, fp_i
if ((err = modexp(bf, &key->e, &key->n, bf)) != HAL_OK)
goto fail;
- FP_CHECK(fp_invmod(ubf, &key->n, ubf));
+ FP_CHECK(fp_invmod(ubf, unconst_fp_int(&key->n), ubf));
fail:
memset(rnd, 0, sizeof(rnd));
@@ -271,7 +282,7 @@ static hal_error_t create_blinding_factors(struct rsa_key *key, fp_int *bf, fp_i
* RSA decryption via Chinese Remainder Theorem (Garner's formula).
*/
-static hal_error_t rsa_crt(struct rsa_key *key, fp_int *msg, fp_int *sig)
+static hal_error_t rsa_crt(const hal_rsa_key_t * const key, fp_int *msg, fp_int *sig)
{
assert(key != NULL && msg != NULL && sig != NULL);
@@ -288,7 +299,7 @@ static hal_error_t rsa_crt(struct rsa_key *key, fp_int *msg, fp_int *sig)
if (blinding) {
if ((err = create_blinding_factors(key, &bf, &ubf)) != HAL_OK)
goto fail;
- FP_CHECK(fp_mulmod(msg, &bf, &key->n, msg));
+ FP_CHECK(fp_mulmod(msg, &bf, unconst_fp_int(&key->n), msg));
}
/*
@@ -309,24 +320,24 @@ static hal_error_t rsa_crt(struct rsa_key *key, fp_int *msg, fp_int *sig)
* once or twice doesn't help, something is very wrong.
*/
if (fp_cmp_d(&t, 0) == FP_LT)
- fp_add(&t, &key->p, &t);
+ fp_add(&t, unconst_fp_int(&key->p), &t);
if (fp_cmp_d(&t, 0) == FP_LT)
- fp_add(&t, &key->p, &t);
+ fp_add(&t, unconst_fp_int(&key->p), &t);
if (fp_cmp_d(&t, 0) == FP_LT)
lose(HAL_ERROR_IMPOSSIBLE);
/*
* sig = (t * u mod p) * q + m2
*/
- FP_CHECK(fp_mulmod(&t, &key->u, &key->p, &t));
- fp_mul(&t, &key->q, &t);
+ FP_CHECK(fp_mulmod(&t, unconst_fp_int(&key->u), unconst_fp_int(&key->p), &t));
+ fp_mul(&t, unconst_fp_int(&key->q), &t);
fp_add(&t, &m2, sig);
/*
* Unblind if necessary.
*/
if (blinding)
- FP_CHECK(fp_mulmod(sig, &ubf, &key->n, sig));
+ FP_CHECK(fp_mulmod(sig, &ubf, unconst_fp_int(&key->n), sig));
fail:
fp_zero(&t);
@@ -342,11 +353,10 @@ static hal_error_t rsa_crt(struct rsa_key *key, fp_int *msg, fp_int *sig)
* to the caller.
*/
-hal_error_t hal_rsa_encrypt(hal_rsa_key_t key_,
+hal_error_t hal_rsa_encrypt(const hal_rsa_key_t * const key,
const uint8_t * const input, const size_t input_len,
uint8_t * output, const size_t output_len)
{
- struct rsa_key *key = key_.key;
hal_error_t err = HAL_OK;
if (key == NULL || input == NULL || output == NULL || input_len > output_len)
@@ -356,7 +366,7 @@ hal_error_t hal_rsa_encrypt(hal_rsa_key_t key_,
fp_init(&i);
fp_init(&o);
- fp_read_unsigned_bin(&i, (uint8_t *) input, input_len);
+ fp_read_unsigned_bin(&i, unconst_uint8_t(input), input_len);
if ((err = modexp(&i, &key->e, &key->n, &o)) != HAL_OK ||
(err = unpack_fp(&o, output, output_len)) != HAL_OK)
@@ -368,11 +378,10 @@ hal_error_t hal_rsa_encrypt(hal_rsa_key_t key_,
return err;
}
-hal_error_t hal_rsa_decrypt(hal_rsa_key_t key_,
+hal_error_t hal_rsa_decrypt(const hal_rsa_key_t * const key,
const uint8_t * const input, const size_t input_len,
uint8_t * output, const size_t output_len)
{
- struct rsa_key *key = key_.key;
hal_error_t err = HAL_OK;
if (key == NULL || input == NULL || output == NULL || input_len > output_len)
@@ -382,7 +391,7 @@ hal_error_t hal_rsa_decrypt(hal_rsa_key_t key_,
fp_init(&i);
fp_init(&o);
- fp_read_unsigned_bin(&i, (uint8_t *) input, input_len);
+ fp_read_unsigned_bin(&i, unconst_uint8_t(input), input_len);
/*
* Do CRT if we have all the necessary key components, otherwise
@@ -393,7 +402,7 @@ hal_error_t hal_rsa_decrypt(hal_rsa_key_t key_,
err = modexp(&i, &key->d, &key->n, &o);
else
err = rsa_crt(key, &i, &o);
-
+
if (err != HAL_OK || (err = unpack_fp(&o, output, output_len)) != HAL_OK)
goto fail;
@@ -408,10 +417,10 @@ hal_error_t hal_rsa_decrypt(hal_rsa_key_t key_,
* than plain old memset() eventually.
*/
-void hal_rsa_key_clear(hal_rsa_key_t key)
+void hal_rsa_key_clear(hal_rsa_key_t *key)
{
- if (key.key != NULL)
- memset(key.key, 0, sizeof(struct rsa_key));
+ if (key != NULL)
+ memset(key, 0, sizeof(*key));
}
/*
@@ -425,7 +434,7 @@ void hal_rsa_key_clear(hal_rsa_key_t key)
*/
static hal_error_t load_key(const hal_rsa_key_type_t type,
- hal_rsa_key_t *key_,
+ hal_rsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
const uint8_t * const n, const size_t n_len,
const uint8_t * const e, const size_t e_len,
@@ -436,22 +445,22 @@ static hal_error_t load_key(const hal_rsa_key_type_t type,
const uint8_t * const dP, const size_t dP_len,
const uint8_t * const dQ, const size_t dQ_len)
{
- if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(struct rsa_key))
+ if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(hal_rsa_key_t))
return HAL_ERROR_BAD_ARGUMENTS;
memset(keybuf, 0, keybuf_len);
- struct rsa_key *key = keybuf;
+ hal_rsa_key_t *key = keybuf;
key->type = type;
-#define _(x) do { fp_init(&key->x); if (x == NULL) goto fail; fp_read_unsigned_bin(&key->x, (uint8_t *) x, x##_len); } while (0)
+#define _(x) do { fp_init(&key->x); if (x == NULL) goto fail; fp_read_unsigned_bin(&key->x, unconst_uint8_t(x), x##_len); } while (0)
switch (type) {
case HAL_RSA_PRIVATE:
_(d); _(p); _(q); _(u); _(dP); _(dQ);
case HAL_RSA_PUBLIC:
_(n); _(e);
- key_->key = key;
+ *key_ = key;
return HAL_OK;
}
#undef _
@@ -465,7 +474,7 @@ static hal_error_t load_key(const hal_rsa_key_type_t type,
* Public API to load_key().
*/
-hal_error_t hal_rsa_key_load_private(hal_rsa_key_t *key_,
+hal_error_t hal_rsa_key_load_private(hal_rsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
const uint8_t * const n, const size_t n_len,
const uint8_t * const e, const size_t e_len,
@@ -481,7 +490,7 @@ hal_error_t hal_rsa_key_load_private(hal_rsa_key_t *key_,
d, d_len, p, p_len, q, q_len, u, u_len, dP, dP_len, dQ, dQ_len);
}
-hal_error_t hal_rsa_key_load_public(hal_rsa_key_t *key_,
+hal_error_t hal_rsa_key_load_public(hal_rsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
const uint8_t * const n, const size_t n_len,
const uint8_t * const e, const size_t e_len)
@@ -495,11 +504,9 @@ hal_error_t hal_rsa_key_load_public(hal_rsa_key_t *key_,
* Extract the key type.
*/
-hal_error_t hal_rsa_key_get_type(hal_rsa_key_t key_,
+hal_error_t hal_rsa_key_get_type(const hal_rsa_key_t * const key,
hal_rsa_key_type_t *key_type)
{
- struct rsa_key *key = key_.key;
-
if (key == NULL || key_type == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
@@ -511,15 +518,16 @@ hal_error_t hal_rsa_key_get_type(hal_rsa_key_t key_,
* Extract public key components.
*/
-static hal_error_t extract_component(hal_rsa_key_t key_, const size_t offset,
+static hal_error_t extract_component(const hal_rsa_key_t * const key,
+ const size_t offset,
uint8_t *res, size_t *res_len, const size_t res_max)
{
- if (key_.key == NULL)
+ if (key == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- fp_int *bn = (fp_int *) (((uint8_t *) key_.key) + offset);
+ const fp_int * const bn = (const fp_int *) (((const uint8_t *) key) + offset);
- const size_t len = fp_unsigned_bin_size(bn);
+ const size_t len = fp_unsigned_bin_size(unconst_fp_int(bn));
if (res_len != NULL)
*res_len = len;
@@ -531,31 +539,33 @@ static hal_error_t extract_component(hal_rsa_key_t key_, const size_t offset,
return HAL_ERROR_RESULT_TOO_LONG;
memset(res, 0, res_max);
- fp_to_unsigned_bin(bn, res);
+ fp_to_unsigned_bin(unconst_fp_int(bn), res);
return HAL_OK;
}
-hal_error_t hal_rsa_key_get_modulus(hal_rsa_key_t key_,
+hal_error_t hal_rsa_key_get_modulus(const hal_rsa_key_t * const key,
uint8_t *res, size_t *res_len, const size_t res_max)
{
- return extract_component(key_, offsetof(struct rsa_key, n), res, res_len, res_max);
+ return extract_component(key, offsetof(hal_rsa_key_t, n), res, res_len, res_max);
}
-hal_error_t hal_rsa_key_get_public_exponent(hal_rsa_key_t key_,
+hal_error_t hal_rsa_key_get_public_exponent(const hal_rsa_key_t * const key,
uint8_t *res, size_t *res_len, const size_t res_max)
{
- return extract_component(key_, offsetof(struct rsa_key, e), res, res_len, res_max);
+ return extract_component(key, offsetof(hal_rsa_key_t, e), res, res_len, res_max);
}
/*
* Generate a prime factor for an RSA keypair.
- *
+ *
* Get random bytes, munge a few bits, and stuff into a bignum. Keep
* doing this until we find a result that's (probably) prime and for
* which result - 1 is relatively prime with respect to e.
*/
-static hal_error_t find_prime(unsigned prime_length, fp_int *e, fp_int *result)
+static hal_error_t find_prime(const unsigned prime_length,
+ const fp_int * const e,
+ fp_int *result)
{
uint8_t buffer[prime_length];
hal_error_t err;
@@ -571,7 +581,7 @@ static hal_error_t find_prime(unsigned prime_length, fp_int *e, fp_int *result)
fp_read_unsigned_bin(result, buffer, sizeof(buffer));
} while (!fp_isprime(result) ||
- (fp_sub_d(result, 1, &t), fp_gcd(&t, e, &t), fp_cmp_d(&t, 1) != FP_EQ));
+ (fp_sub_d(result, 1, &t), fp_gcd(&t, unconst_fp_int(e), &t), fp_cmp_d(&t, 1) != FP_EQ));
fp_zero(&t);
return HAL_OK;
@@ -581,16 +591,16 @@ static hal_error_t find_prime(unsigned prime_length, fp_int *e, fp_int *result)
* Generate a new RSA keypair.
*/
-hal_error_t hal_rsa_key_gen(hal_rsa_key_t *key_,
+hal_error_t hal_rsa_key_gen(hal_rsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
const unsigned key_length,
const uint8_t * const public_exponent, const size_t public_exponent_len)
{
- struct rsa_key *key = keybuf;
+ hal_rsa_key_t *key = keybuf;
hal_error_t err = HAL_OK;
fp_int p_1, q_1;
- if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(struct rsa_key))
+ if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(hal_rsa_key_t))
return HAL_ERROR_BAD_ARGUMENTS;
memset(keybuf, 0, keybuf_len);
@@ -624,7 +634,7 @@ hal_error_t hal_rsa_key_gen(hal_rsa_key_t *key_,
FP_CHECK(fp_mod(&key->d, &q_1, &key->dQ)); /* dQ = d % (q-1) */
FP_CHECK(fp_invmod(&key->q, &key->p, &key->u)); /* u = (1/q) % p */
- key_->key = key;
+ *key_ = key;
/* Fall through to cleanup */
@@ -637,19 +647,9 @@ hal_error_t hal_rsa_key_gen(hal_rsa_key_t *key_,
}
/*
- * Minimal ASN.1 encoding and decoding for private keys. This is NOT
- * a general-purpose ASN.1 implementation, just enough to read and
- * write PKCS #1.5 RSAPrivateKey syntax (RFC 2313 section 7.2).
+ * Just enough ASN.1 to read and write PKCS #1.5 RSAPrivateKey syntax
+ * (RFC 2313 section 7.2).
*
- * If at some later date we need a full ASN.1 implementation we'll add
- * it as (a) separate library module(s), but for now the goal is just
- * to let us serialize private keys for internal use and debugging.
- */
-
-#define ASN1_INTEGER 0x02
-#define ASN1_SEQUENCE 0x30
-
-/*
* RSAPrivateKey fields in the required order.
*/
@@ -664,139 +664,9 @@ hal_error_t hal_rsa_key_gen(hal_rsa_key_t *key_,
_(&key->dQ); \
_(&key->u);
-static size_t count_length(size_t length)
-{
- size_t result = 1;
-
- if (length >= 128)
- for (; length > 0; length >>= 8)
- result++;
-
- return result;
-}
-
-static void encode_length(size_t length, size_t length_len, uint8_t *der)
-{
- assert(der != NULL && length_len > 0 && length_len < 128);
-
- if (length < 128) {
- assert(length_len == 1);
- *der = (uint8_t) length;
- }
-
- else {
- *der = 0x80 | (uint8_t) --length_len;
- while (length > 0 && length_len > 0) {
- der[length_len--] = (uint8_t) (length & 0xFF);
- length >>= 8;
- }
- assert(length == 0 && length_len == 0);
- }
-}
-
-static hal_error_t decode_header(const uint8_t tag,
- const uint8_t * const der, size_t der_max,
- size_t *hlen, size_t *vlen)
-{
- assert(der != NULL && hlen != NULL && vlen != NULL);
-
- if (der_max < 2 || der[0] != tag)
- return HAL_ERROR_ASN1_PARSE_FAILED;
-
- if ((der[1] & 0x80) == 0) {
- *hlen = 2;
- *vlen = der[1];
- }
-
- else {
- *hlen = 2 + (der[1] & 0x7F);
- *vlen = 0;
-
- if (*hlen > der_max)
- return HAL_ERROR_ASN1_PARSE_FAILED;
-
- for (size_t i = 2; i < *hlen; i++)
- *vlen = (*vlen << 8) + der[i];
- }
-
- if (*hlen + *vlen > der_max)
- return HAL_ERROR_ASN1_PARSE_FAILED;
-
- return HAL_OK;
-}
-
-static hal_error_t encode_integer(fp_int *bn,
- uint8_t *der, size_t *der_len, const size_t der_max)
-{
- if (bn == NULL || der_len == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- /*
- * Calculate length. Need to pad data with a leading zero if most
- * significant bit is set, to avoid flipping ASN.1 sign bit. If
- * caller didn't supply a buffer, just return the total length.
- */
-
- const int cmp = fp_cmp_d(bn, 0);
-
- if (cmp != FP_EQ && cmp != FP_GT)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- const int leading_zero = (cmp == FP_EQ || (fp_count_bits(bn) & 7) == 0);
- const size_t data_len = fp_unsigned_bin_size(bn) + leading_zero;
- const size_t tag_len = 1;
- const size_t length_len = count_length(data_len);
- const size_t total_len = tag_len + length_len + data_len;
-
- *der_len = total_len;
-
- if (der == NULL)
- return HAL_OK;
-
- if (total_len > der_max)
- return HAL_ERROR_RESULT_TOO_LONG;
-
- /*
- * Now encode.
- */
-
- *der++ = ASN1_INTEGER;
- encode_length(data_len, length_len, der);
- der += length_len;
- if (leading_zero)
- *der++ = 0x00;
- fp_to_unsigned_bin(bn, der);
-
- return HAL_OK;
-}
-
-static hal_error_t decode_integer(fp_int *bn,
- const uint8_t * const der, size_t *der_len, const size_t der_max)
-{
- if (bn == NULL || der == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- hal_error_t err;
- size_t hlen, vlen;
-
- if ((err = decode_header(ASN1_INTEGER, der, der_max, &hlen, &vlen)) != HAL_OK)
- return err;
-
- if (der_len != NULL)
- *der_len = hlen + vlen;
-
- if (vlen < 1 || (der[hlen] & 0x80) != 0x00)
- return HAL_ERROR_ASN1_PARSE_FAILED;
-
- fp_init(bn);
- fp_read_unsigned_bin(bn, (uint8_t *) der + hlen, vlen);
- return HAL_OK;
-}
-
-hal_error_t hal_rsa_key_to_der(hal_rsa_key_t key_,
+hal_error_t hal_rsa_key_to_der(const hal_rsa_key_t * const key,
uint8_t *der, size_t *der_len, const size_t der_max)
{
- struct rsa_key *key = key_.key;
hal_error_t err = HAL_OK;
if (key == NULL || der_len == NULL || key->type != HAL_RSA_PRIVATE)
@@ -806,65 +676,64 @@ hal_error_t hal_rsa_key_to_der(hal_rsa_key_t key_,
fp_zero(&version);
/*
- * Calculate length.
+ * Calculate data length.
*/
- size_t data_len = 0;
+ size_t vlen = 0;
-#define _(x) { size_t i; if ((err = encode_integer(x, NULL, &i, der_max - data_len)) != HAL_OK) return err; data_len += i; }
+#define _(x) { size_t i; if ((err = hal_asn1_encode_integer(x, NULL, &i, der_max - vlen)) != HAL_OK) return err; vlen += i; }
RSAPrivateKey_fields;
#undef _
- const size_t tag_len = 1;
- const size_t length_len = count_length(data_len);
- const size_t total_len = tag_len + length_len + data_len;
+ /*
+ * Encode header.
+ */
- *der_len = total_len;
+ if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, der_len, der_max)) != HAL_OK)
+ return err;
+
+ const size_t hlen = *der_len;
+ *der_len += vlen;
if (der == NULL)
return HAL_OK;
- if (total_len > der_max)
- return HAL_ERROR_RESULT_TOO_LONG;
-
/*
- * Now encode.
+ * Encode data.
*/
- *der++ = ASN1_SEQUENCE;
- encode_length(data_len, length_len, der);
- der += length_len;
-
-#define _(x) { size_t i; if ((err = encode_integer(x, der, &i, data_len)) != HAL_OK) return err; der += i; data_len -= i; }
+ der += hlen;
+
+#define _(x) { size_t i; if ((err = hal_asn1_encode_integer(x, der, &i, vlen)) != HAL_OK) return err; der += i; vlen -= i; }
RSAPrivateKey_fields;
#undef _
return HAL_OK;
}
-size_t hal_rsa_key_to_der_len(hal_rsa_key_t key_)
+size_t hal_rsa_key_to_der_len(const hal_rsa_key_t * const key)
{
size_t len = 0;
- return hal_rsa_key_to_der(key_, NULL, &len, 0) == HAL_OK ? len : 0;
+ return hal_rsa_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
}
-hal_error_t hal_rsa_key_from_der(hal_rsa_key_t *key_,
+hal_error_t hal_rsa_key_from_der(hal_rsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
const uint8_t *der, const size_t der_len)
{
- if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(struct rsa_key) || der == NULL)
+ if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(hal_rsa_key_t) || der == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
memset(keybuf, 0, keybuf_len);
- struct rsa_key *key = keybuf;
+ hal_rsa_key_t *key = keybuf;
key->type = HAL_RSA_PRIVATE;
hal_error_t err = HAL_OK;
size_t hlen, vlen;
- if ((err = decode_header(ASN1_SEQUENCE, der, der_len, &hlen, &vlen)) != HAL_OK)
+ if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, der, der_len, &hlen, &vlen)) != HAL_OK)
return err;
der += hlen;
@@ -872,14 +741,14 @@ hal_error_t hal_rsa_key_from_der(hal_rsa_key_t *key_,
fp_int version;
fp_init(&version);
-#define _(x) { size_t i; if ((err = decode_integer(x, der, &i, vlen)) != HAL_OK) return err; der += i; vlen -= i; }
+#define _(x) { size_t i; if ((err = hal_asn1_decode_integer(x, der, &i, vlen)) != HAL_OK) return err; der += i; vlen -= i; }
RSAPrivateKey_fields;
#undef _
if (fp_cmp_d(&version, 0) != FP_EQ)
return HAL_ERROR_ASN1_PARSE_FAILED;
- key_->key = key;
+ *key_ = key;
return HAL_OK;
}
diff --git a/tests/GNUmakefile b/tests/GNUmakefile
index 307f23e..a1cd4b4 100644
--- a/tests/GNUmakefile
+++ b/tests/GNUmakefile
@@ -27,7 +27,7 @@
INC = ../hal.h
LIB = ../libhal.a
-BIN = test-aes-key-wrap test-hash test-pbkdf2 test-rsa
+BIN = test-aes-key-wrap test-hash test-pbkdf2 test-rsa test-ecdsa
CFLAGS = -g3 -Wall -fPIC -std=c99 -I..
diff --git a/tests/test-ecdsa.c b/tests/test-ecdsa.c
new file mode 100644
index 0000000..cb590e5
--- /dev/null
+++ b/tests/test-ecdsa.c
@@ -0,0 +1,326 @@
+/*
+ * test-ecdsa.c
+ * ------------
+ * Test harness for Cryptech ECDSA code.
+ *
+ * At the moment, the ECDSA code is a pure software implementation,
+ * Verilog will be along eventually.
+ *
+ * Testing ECDSA is a bit tricky because ECDSA depends heavily on
+ * using a new random secret for each signature. So we can test some
+ * things against the normal ECDSA implemenation, but some tests
+ * require a side door replacement of the random number generator so
+ * that we can use a known values from our test vector in place of the
+ * random secret that would be used in real operation. Test code for
+ * the latter mode depends on the library having been compiled with
+ * the testing hook enable, which it should not be for production use.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, SUNET
+ *
+ * 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.
+ *
+ * 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 OWNER 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/time.h>
+
+#include <hal.h>
+
+#include "test-ecdsa.h"
+
+#if HAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM
+
+/*
+ * Code to let us replace ECDSA's random numbers with test data, if
+ * the ECDSA library code has been compiled with support for this.
+ */
+
+typedef hal_error_t (*rng_override_test_function_t)(void *, const size_t);
+
+extern rng_override_test_function_t hal_ecdsa_set_rng_override_test_function(rng_override_test_function_t new_func);
+
+static const uint8_t *next_random_value = NULL;
+static size_t next_random_length = 0;
+
+static hal_error_t next_random_handler(void *data, const size_t length)
+{
+ if (data == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (next_random_value == NULL || length < next_random_length)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ memset(data, 0, length);
+ memcpy(data + length - next_random_length, next_random_value, next_random_length);
+
+ next_random_value = NULL;
+ next_random_length = 0;
+
+ (void) hal_ecdsa_set_rng_override_test_function(0);
+
+ return HAL_OK;
+}
+
+static void set_next_random(const uint8_t * const data, const size_t length)
+{
+ (void) hal_ecdsa_set_rng_override_test_function(next_random_handler);
+ next_random_value = data;
+ next_random_length = length;
+}
+
+/*
+ * Run one keygen test from test vectors.
+ */
+
+static int test_against_static_vectors(const ecdsa_tc_t * const tc)
+
+{
+ hal_error_t err;
+
+ printf("Starting static test vector tests for P-%lu\n", (unsigned long) (tc->d_len * 8));
+
+ set_next_random(tc->d, tc->d_len);
+
+ uint8_t keybuf1[hal_ecdsa_key_t_size];
+ hal_ecdsa_key_t *key1 = NULL;
+
+ if ((err = hal_ecdsa_key_gen(&key1, keybuf1, sizeof(keybuf1), tc->curve)) != HAL_OK)
+ return printf("hal_ecdsa_key_gen() failed: %s\n", hal_error_string(err)), 0;
+
+ uint8_t Qx[tc->Qx_len], Qy[tc->Qy_len];
+ size_t Qx_len, Qy_len;
+
+ if ((err = hal_ecdsa_key_get_public(key1, Qx, &Qx_len, sizeof(Qx), Qy, &Qy_len, sizeof(Qy))) != HAL_OK)
+ return printf("hal_ecdsa_key_get_public() failed: %s\n", hal_error_string(err)), 0;
+
+ if (tc->Qx_len != Qx_len || memcmp(tc->Qx, Qx, Qx_len) != 0)
+ return printf("Qx mismatch\n"), 0;
+
+ if (tc->Qy_len != Qy_len || memcmp(tc->Qy, Qy, Qy_len) != 0)
+ return printf("Qy mismatch\n"), 0;
+
+ if (hal_ecdsa_key_to_der_len(key1) != tc->key_len)
+ return printf("DER Key length mismatch\n"), 0;
+
+ uint8_t keyder[tc->key_len];
+ size_t keyder_len;
+
+ if ((err = hal_ecdsa_key_to_der(key1, keyder, &keyder_len, sizeof(keyder))) != HAL_OK)
+ return printf("hal_ecdsa_key_to_der() failed: %s\n", hal_error_string(err)), 0;
+
+ uint8_t keybuf2[hal_ecdsa_key_t_size];
+ hal_ecdsa_key_t *key2 = NULL;
+
+ if ((err = hal_ecdsa_key_from_der(&key2, keybuf2, sizeof(keybuf2), keyder, keyder_len)) != HAL_OK)
+ return printf("hal_ecdsa_key_from_der() failed: %s\n", hal_error_string(err)), 0;
+
+ if (memcmp(key1, key2, hal_ecdsa_key_t_size) != 0)
+ return printf("Key mismatch after read/write cycle\n"), 0;
+
+ set_next_random(tc->k, tc->k_len);
+
+ uint8_t sig[tc->sig_len + 4];
+ size_t sig_len;
+
+ if ((err = hal_ecdsa_sign(key1, tc->H, tc->H_len, sig, &sig_len, sizeof(sig), HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK)
+ return printf("hal_ecdsa_sign() failed: %s\n", hal_error_string(err)), 0;
+
+ if (sig_len != tc->sig_len || memcmp(sig, tc->sig, tc->sig_len) != 0)
+ return printf("Signature mismatch\n"), 0;
+
+ if ((err = hal_ecdsa_verify(key2, tc->H, tc->H_len, sig, sig_len, HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK)
+ return printf("hal_ecdsa_verify(private) failed: %s\n", hal_error_string(err)), 0;
+
+ hal_ecdsa_key_clear(key2);
+ key2 = NULL;
+
+ if ((err = hal_ecdsa_key_load_private(&key2, keybuf2, sizeof(keybuf2), tc->curve,
+ tc->Qx, tc->Qx_len, tc->Qy, tc->Qy_len, tc->d, tc->d_len)) != HAL_OK)
+ return printf("hal_ecdsa_load_private() failed: %s\n", hal_error_string(err)), 0;
+
+ if (memcmp(key1, key2, hal_ecdsa_key_t_size) != 0)
+ return printf("Key mismatch after hal_ecdsa_load_private_key()\n"), 0;
+
+ hal_ecdsa_key_clear(key2);
+ key2 = NULL;
+
+ if ((err = hal_ecdsa_key_load_public(&key2, keybuf2, sizeof(keybuf2), tc->curve,
+ tc->Qx, tc->Qx_len, tc->Qy, tc->Qy_len)) != HAL_OK)
+ return printf("hal_ecdsa_load_public() failed: %s\n", hal_error_string(err)), 0;
+
+ if ((err = hal_ecdsa_verify(key2, tc->H, tc->H_len, sig, sig_len, HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK)
+ return printf("hal_ecdsa_verify(public) failed: %s\n", hal_error_string(err)), 0;
+
+ return 1;
+}
+
+#endif /* HAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM */
+
+/*
+ * Run one keygen/sign/verify test with a newly generated key.
+ */
+
+static int test_keygen_sign_verify(const hal_ecdsa_curve_t curve)
+
+{
+ const hal_hash_descriptor_t *hash_descriptor = NULL;
+ uint8_t keybuf[hal_ecdsa_key_t_size];
+ hal_ecdsa_key_t *key = NULL;
+ hal_error_t err;
+
+ switch (curve) {
+
+ case HAL_ECDSA_CURVE_P256:
+ printf("ECDSA P-256 key generation / signature / verification test\n");
+ hash_descriptor = hal_hash_sha256;
+ break;
+
+ case HAL_ECDSA_CURVE_P384:
+ printf("ECDSA P-384 key generation / signature / verification test\n");
+ hash_descriptor = hal_hash_sha384;
+ break;
+
+ case HAL_ECDSA_CURVE_P521:
+ printf("ECDSA P-521 key generation / signature / verification test\n");
+ hash_descriptor = hal_hash_sha512;
+ break;
+
+ default:
+ printf("Unsupported ECDSA curve type\n");
+ return 0;
+ }
+
+ if ((err = hal_ecdsa_key_gen(&key, keybuf, sizeof(keybuf), curve)) != HAL_OK)
+ return printf("hal_ecdsa_key_gen() failed: %s\n", hal_error_string(err)), 0;
+
+ uint8_t hashbuf[hash_descriptor->digest_length];
+
+ {
+ const uint8_t plaintext[] = "So long, and thanks...";
+ uint8_t statebuf[hash_descriptor->hash_state_length];
+ hal_hash_state_t *state = NULL;
+
+ if ((err = hal_hash_initialize(hash_descriptor, &state, statebuf, sizeof(statebuf))) != HAL_OK ||
+ (err = hal_hash_update(state, plaintext, strlen((const char *) plaintext))) != HAL_OK ||
+ (err = hal_hash_finalize(state, hashbuf, sizeof(hashbuf))) != HAL_OK)
+ return printf("Couldn't hash plaintext: %s\n", hal_error_string(err)), 0;
+ }
+
+ /*
+ * Lazy but probably-good-enough guess on signature size -- want
+ * explicit number in ecdsa_curve_t?
+ */
+ uint8_t sigbuf[hash_descriptor->digest_length * 3];
+ size_t siglen;
+
+ if ((err = hal_ecdsa_sign(key, hashbuf, sizeof(hashbuf),
+ sigbuf, &siglen, sizeof(sigbuf), HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK)
+ return printf("hal_ecdsa_sign() failed: %s\n", hal_error_string(err)), 0;
+
+ if ((err = hal_ecdsa_verify(key, hashbuf, sizeof(hashbuf),
+ sigbuf, siglen, HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK)
+ return printf("hal_ecdsa_verify() failed: %s\n", hal_error_string(err)), 0;
+
+ return 1;
+}
+
+/*
+ * Time a test.
+ */
+
+static void _time_check(const struct timeval t0, const int ok)
+{
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ t.tv_sec -= t0.tv_sec;
+ t.tv_usec = t0.tv_usec;
+ if (t.tv_usec < 0) {
+ t.tv_usec += 1000000;
+ t.tv_sec -= 1;
+ }
+ printf("Elapsed time %lu.%06lu seconds, %s\n",
+ (unsigned long) t.tv_sec,
+ (unsigned long) t.tv_usec,
+ ok ? "OK" : "FAILED");
+}
+
+#define time_check(_expr_) \
+ do { \
+ struct timeval _t; \
+ gettimeofday(&_t, NULL); \
+ int _ok = (_expr_); \
+ _time_check(_t, _ok); \
+ ok &= _ok; \
+ } while (0)
+
+/*
+ * Run tests for one ECDSA curve.
+ */
+
+static int test_ecdsa(const ecdsa_tc_t * const tc)
+
+{
+ int ok = 1;
+ time_check(test_against_static_vectors(tc));
+ time_check(test_keygen_sign_verify(tc->curve));
+ return ok;
+}
+
+int main(int argc, char *argv[])
+{
+ uint8_t name[8], version[4];
+ hal_error_t err;
+
+ /*
+ * Initialize EIM and report what core we're running.
+ */
+
+ if ((err = hal_io_read(CSPRNG_ADDR_NAME0, name, sizeof(name))) != HAL_OK ||
+ (err = hal_io_read(CSPRNG_ADDR_VERSION, version, sizeof(version))) != HAL_OK) {
+ printf("Initialization failed: %s\n", hal_error_string(err));
+ return 1;
+ }
+
+ printf("\"%8.8s\" \"%4.4s\"\n\n", name, version);
+
+ for (int i = 0; i < sizeof(ecdsa_tc)/sizeof(*ecdsa_tc); i++)
+ if (!test_ecdsa(&ecdsa_tc[i]))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tests/test-ecdsa.h b/tests/test-ecdsa.h
new file mode 100644
index 0000000..ca51858
--- /dev/null
+++ b/tests/test-ecdsa.h
@@ -0,0 +1,329 @@
+/*
+ * ECDSA test data.
+ * File automatically generated by test-ecdsa.py
+ */
+
+static const uint8_t p256_H[] = { /* 32 bytes */
+ 0x7c, 0x3e, 0x88, 0x3d, 0xdc, 0x8b, 0xd6, 0x88, 0xf9, 0x6e, 0xac, 0x5e,
+ 0x93, 0x24, 0x22, 0x2c, 0x8f, 0x30, 0xf9, 0xd6, 0xbb, 0x59, 0xe9, 0xc5,
+ 0xf0, 0x20, 0xbd, 0x39, 0xba, 0x2b, 0x83, 0x77
+};
+
+static const uint8_t p256_M[] = { /* 48 bytes */
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x6e, 0x6c, 0x79,
+ 0x20, 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73,
+ 0x61, 0x67, 0x65, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x34,
+ 0x38, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x6c, 0x6f, 0x6e, 0x67
+};
+
+static const uint8_t p256_Qx[] = { /* 32 bytes */
+ 0x81, 0x01, 0xec, 0xe4, 0x74, 0x64, 0xa6, 0xea, 0xd7, 0x0c, 0xf6, 0x9a,
+ 0x6e, 0x2b, 0xd3, 0xd8, 0x86, 0x91, 0xa3, 0x26, 0x2d, 0x22, 0xcb, 0xa4,
+ 0xf7, 0x63, 0x5e, 0xaf, 0xf2, 0x66, 0x80, 0xa8
+};
+
+static const uint8_t p256_Qy[] = { /* 32 bytes */
+ 0xd8, 0xa1, 0x2b, 0xa6, 0x1d, 0x59, 0x92, 0x35, 0xf6, 0x7d, 0x9c, 0xb4,
+ 0xd5, 0x8f, 0x17, 0x83, 0xd3, 0xca, 0x43, 0xe7, 0x8f, 0x0a, 0x5a, 0xba,
+ 0xa6, 0x24, 0x07, 0x99, 0x36, 0xc0, 0xc3, 0xa9
+};
+
+static const uint8_t p256_Rx[] = { /* 32 bytes */
+ 0x72, 0x14, 0xbc, 0x96, 0x47, 0x16, 0x0b, 0xbd, 0x39, 0xff, 0x2f, 0x80,
+ 0x53, 0x3f, 0x5d, 0xc6, 0xdd, 0xd7, 0x0d, 0xdf, 0x86, 0xbb, 0x81, 0x56,
+ 0x61, 0xe8, 0x05, 0xd5, 0xd4, 0xe6, 0xf2, 0x7c
+};
+
+static const uint8_t p256_Ry[] = { /* 32 bytes */
+ 0x8b, 0x81, 0xe3, 0xe9, 0x77, 0x59, 0x71, 0x10, 0xc7, 0xcf, 0x26, 0x33,
+ 0x43, 0x5b, 0x22, 0x94, 0xb7, 0x26, 0x42, 0x98, 0x7d, 0xef, 0xd3, 0xd4,
+ 0x00, 0x7e, 0x1c, 0xfc, 0x5d, 0xf8, 0x45, 0x41
+};
+
+static const uint8_t p256_d[] = { /* 32 bytes */
+ 0x70, 0xa1, 0x2c, 0x2d, 0xb1, 0x68, 0x45, 0xed, 0x56, 0xff, 0x68, 0xcf,
+ 0xc2, 0x1a, 0x47, 0x2b, 0x3f, 0x04, 0xd7, 0xd6, 0x85, 0x1b, 0xf6, 0x34,
+ 0x9f, 0x2d, 0x7d, 0x5b, 0x34, 0x52, 0xb3, 0x8a
+};
+
+static const uint8_t p256_e[] = { /* 32 bytes */
+ 0x7c, 0x3e, 0x88, 0x3d, 0xdc, 0x8b, 0xd6, 0x88, 0xf9, 0x6e, 0xac, 0x5e,
+ 0x93, 0x24, 0x22, 0x2c, 0x8f, 0x30, 0xf9, 0xd6, 0xbb, 0x59, 0xe9, 0xc5,
+ 0xf0, 0x20, 0xbd, 0x39, 0xba, 0x2b, 0x83, 0x77
+};
+
+static const uint8_t p256_k[] = { /* 32 bytes */
+ 0x58, 0x0e, 0xc0, 0x0d, 0x85, 0x64, 0x34, 0x33, 0x4c, 0xef, 0x3f, 0x71,
+ 0xec, 0xae, 0xd4, 0x96, 0x5b, 0x12, 0xae, 0x37, 0xfa, 0x47, 0x05, 0x5b,
+ 0x19, 0x65, 0xc7, 0xb1, 0x34, 0xee, 0x45, 0xd0
+};
+
+static const uint8_t p256_key[] = { /* 121 bytes */
+ 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x70, 0xa1, 0x2c, 0x2d, 0xb1,
+ 0x68, 0x45, 0xed, 0x56, 0xff, 0x68, 0xcf, 0xc2, 0x1a, 0x47, 0x2b, 0x3f,
+ 0x04, 0xd7, 0xd6, 0x85, 0x1b, 0xf6, 0x34, 0x9f, 0x2d, 0x7d, 0x5b, 0x34,
+ 0x52, 0xb3, 0x8a, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+ 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x81, 0x01, 0xec,
+ 0xe4, 0x74, 0x64, 0xa6, 0xea, 0xd7, 0x0c, 0xf6, 0x9a, 0x6e, 0x2b, 0xd3,
+ 0xd8, 0x86, 0x91, 0xa3, 0x26, 0x2d, 0x22, 0xcb, 0xa4, 0xf7, 0x63, 0x5e,
+ 0xaf, 0xf2, 0x66, 0x80, 0xa8, 0xd8, 0xa1, 0x2b, 0xa6, 0x1d, 0x59, 0x92,
+ 0x35, 0xf6, 0x7d, 0x9c, 0xb4, 0xd5, 0x8f, 0x17, 0x83, 0xd3, 0xca, 0x43,
+ 0xe7, 0x8f, 0x0a, 0x5a, 0xba, 0xa6, 0x24, 0x07, 0x99, 0x36, 0xc0, 0xc3, 0xa9
+};
+
+static const uint8_t p256_kinv[] = { /* 32 bytes */
+ 0x6a, 0x66, 0x4f, 0xa1, 0x15, 0x35, 0x6d, 0x33, 0xf1, 0x63, 0x31, 0xb5,
+ 0x4c, 0x4e, 0x7c, 0xe9, 0x67, 0x96, 0x53, 0x86, 0xc7, 0xdc, 0xbf, 0x29,
+ 0x04, 0x60, 0x4d, 0x0c, 0x13, 0x2b, 0x4a, 0x74
+};
+
+static const uint8_t p256_r[] = { /* 32 bytes */
+ 0x72, 0x14, 0xbc, 0x96, 0x47, 0x16, 0x0b, 0xbd, 0x39, 0xff, 0x2f, 0x80,
+ 0x53, 0x3f, 0x5d, 0xc6, 0xdd, 0xd7, 0x0d, 0xdf, 0x86, 0xbb, 0x81, 0x56,
+ 0x61, 0xe8, 0x05, 0xd5, 0xd4, 0xe6, 0xf2, 0x7c
+};
+
+static const uint8_t p256_s[] = { /* 32 bytes */
+ 0x7d, 0x1f, 0xf9, 0x61, 0x98, 0x0f, 0x96, 0x1b, 0xda, 0xa3, 0x23, 0x3b,
+ 0x62, 0x09, 0xf4, 0x01, 0x33, 0x17, 0xd3, 0xe3, 0xf9, 0xe1, 0x49, 0x35,
+ 0x92, 0xdb, 0xea, 0xa1, 0xaf, 0x2b, 0xc3, 0x67
+};
+
+static const uint8_t p256_sig[] = { /* 70 bytes */
+ 0x30, 0x44, 0x02, 0x20, 0x72, 0x14, 0xbc, 0x96, 0x47, 0x16, 0x0b, 0xbd,
+ 0x39, 0xff, 0x2f, 0x80, 0x53, 0x3f, 0x5d, 0xc6, 0xdd, 0xd7, 0x0d, 0xdf,
+ 0x86, 0xbb, 0x81, 0x56, 0x61, 0xe8, 0x05, 0xd5, 0xd4, 0xe6, 0xf2, 0x7c,
+ 0x02, 0x20, 0x7d, 0x1f, 0xf9, 0x61, 0x98, 0x0f, 0x96, 0x1b, 0xda, 0xa3,
+ 0x23, 0x3b, 0x62, 0x09, 0xf4, 0x01, 0x33, 0x17, 0xd3, 0xe3, 0xf9, 0xe1,
+ 0x49, 0x35, 0x92, 0xdb, 0xea, 0xa1, 0xaf, 0x2b, 0xc3, 0x67
+};
+
+static const uint8_t p256_u1[] = { /* 32 bytes */
+ 0xbb, 0x25, 0x24, 0x01, 0xd6, 0xfb, 0x32, 0x2b, 0xb7, 0x47, 0x18, 0x4c,
+ 0xf2, 0xac, 0x52, 0xbf, 0x8d, 0x54, 0xb9, 0x5a, 0x15, 0x15, 0x06, 0x2a,
+ 0x2f, 0x61, 0x41, 0xf2, 0xe2, 0x09, 0x2e, 0xd8
+};
+
+static const uint8_t p256_u2[] = { /* 32 bytes */
+ 0xaa, 0xe7, 0xd1, 0xc7, 0xf2, 0xc2, 0x32, 0xdf, 0xc6, 0x41, 0x94, 0x8a,
+ 0xf3, 0xdb, 0xa1, 0x41, 0xd4, 0xde, 0x86, 0x34, 0xe5, 0x71, 0xcf, 0x84,
+ 0xc4, 0x86, 0x30, 0x1b, 0x51, 0x0c, 0xfc, 0x04
+};
+
+static const uint8_t p256_v[] = { /* 32 bytes */
+ 0x72, 0x14, 0xbc, 0x96, 0x47, 0x16, 0x0b, 0xbd, 0x39, 0xff, 0x2f, 0x80,
+ 0x53, 0x3f, 0x5d, 0xc6, 0xdd, 0xd7, 0x0d, 0xdf, 0x86, 0xbb, 0x81, 0x56,
+ 0x61, 0xe8, 0x05, 0xd5, 0xd4, 0xe6, 0xf2, 0x7c
+};
+
+static const uint8_t p256_w[] = { /* 32 bytes */
+ 0xd6, 0x9b, 0xe7, 0x5f, 0x67, 0xee, 0x53, 0x94, 0xca, 0xbb, 0x6c, 0x28,
+ 0x6f, 0x36, 0x10, 0xcf, 0x62, 0xd7, 0x22, 0xcb, 0xa9, 0xee, 0xa7, 0x0f,
+ 0xae, 0xe7, 0x70, 0xa6, 0xb2, 0xed, 0x72, 0xdc
+};
+
+static const uint8_t p384_H[] = { /* 48 bytes */
+ 0xb9, 0x21, 0x0c, 0x9d, 0x7e, 0x20, 0x89, 0x7a, 0xb8, 0x65, 0x97, 0x26,
+ 0x6a, 0x9d, 0x50, 0x77, 0xe8, 0xdb, 0x1b, 0x06, 0xf7, 0x22, 0x0e, 0xd6,
+ 0xee, 0x75, 0xbd, 0x8b, 0x45, 0xdb, 0x37, 0x89, 0x1f, 0x8b, 0xa5, 0x55,
+ 0x03, 0x04, 0x00, 0x41, 0x59, 0xf4, 0x45, 0x3d, 0xc5, 0xb3, 0xf5, 0xa1
+};
+
+static const uint8_t p384_M[] = { /* 48 bytes */
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x6e, 0x6c, 0x79,
+ 0x20, 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73,
+ 0x61, 0x67, 0x65, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x34,
+ 0x38, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x6c, 0x6f, 0x6e, 0x67
+};
+
+static const uint8_t p384_Qx[] = { /* 48 bytes */
+ 0x1f, 0xba, 0xc8, 0xee, 0xbd, 0x0c, 0xbf, 0x35, 0x64, 0x0b, 0x39, 0xef,
+ 0xe0, 0x80, 0x8d, 0xd7, 0x74, 0xde, 0xbf, 0xf2, 0x0a, 0x2a, 0x32, 0x9e,
+ 0x91, 0x71, 0x3b, 0xaf, 0x7d, 0x7f, 0x3c, 0x3e, 0x81, 0x54, 0x6d, 0x88,
+ 0x37, 0x30, 0xbe, 0xe7, 0xe4, 0x86, 0x78, 0xf8, 0x57, 0xb0, 0x2c, 0xa0
+};
+
+static const uint8_t p384_Qy[] = { /* 48 bytes */
+ 0xeb, 0x21, 0x31, 0x03, 0xbd, 0x68, 0xce, 0x34, 0x33, 0x65, 0xa8, 0xa4,
+ 0xc3, 0xd4, 0x55, 0x5f, 0xa3, 0x85, 0xf5, 0x33, 0x02, 0x03, 0xbd, 0xd7,
+ 0x6f, 0xfa, 0xd1, 0xf3, 0xaf, 0xfb, 0x95, 0x75, 0x1c, 0x13, 0x20, 0x07,
+ 0xe1, 0xb2, 0x40, 0x35, 0x3c, 0xb0, 0xa4, 0xcf, 0x16, 0x93, 0xbd, 0xf9
+};
+
+static const uint8_t p384_Rx[] = { /* 48 bytes */
+ 0xa0, 0xc2, 0x7e, 0xc8, 0x93, 0x09, 0x2d, 0xea, 0x1e, 0x1b, 0xd2, 0xcc,
+ 0xfe, 0xd3, 0xcf, 0x94, 0x5c, 0x81, 0x34, 0xed, 0x0c, 0x9f, 0x81, 0x31,
+ 0x1a, 0x0f, 0x4a, 0x05, 0x94, 0x2d, 0xb8, 0xdb, 0xed, 0x8d, 0xd5, 0x9f,
+ 0x26, 0x74, 0x71, 0xd5, 0x46, 0x2a, 0xa1, 0x4f, 0xe7, 0x2d, 0xe8, 0x56
+};
+
+static const uint8_t p384_Ry[] = { /* 48 bytes */
+ 0x85, 0x56, 0x49, 0x40, 0x98, 0x15, 0xbb, 0x91, 0x42, 0x4e, 0xac, 0xa5,
+ 0xfd, 0x76, 0xc9, 0x73, 0x75, 0xd5, 0x75, 0xd1, 0x42, 0x2e, 0xc5, 0x3d,
+ 0x34, 0x3b, 0xd3, 0x3b, 0x84, 0x7f, 0xdf, 0x0c, 0x11, 0x56, 0x96, 0x85,
+ 0xb5, 0x28, 0xab, 0x25, 0x49, 0x30, 0x15, 0x42, 0x8d, 0x7c, 0xf7, 0x2b
+};
+
+static const uint8_t p384_d[] = { /* 48 bytes */
+ 0xc8, 0x38, 0xb8, 0x52, 0x53, 0xef, 0x8d, 0xc7, 0x39, 0x4f, 0xa5, 0x80,
+ 0x8a, 0x51, 0x83, 0x98, 0x1c, 0x7d, 0xee, 0xf5, 0xa6, 0x9b, 0xa8, 0xf4,
+ 0xf2, 0x11, 0x7f, 0xfe, 0xa3, 0x9c, 0xfc, 0xd9, 0x0e, 0x95, 0xf6, 0xcb,
+ 0xc8, 0x54, 0xab, 0xac, 0xab, 0x70, 0x1d, 0x50, 0xc1, 0xf3, 0xcf, 0x24
+};
+
+static const uint8_t p384_e[] = { /* 48 bytes */
+ 0xb9, 0x21, 0x0c, 0x9d, 0x7e, 0x20, 0x89, 0x7a, 0xb8, 0x65, 0x97, 0x26,
+ 0x6a, 0x9d, 0x50, 0x77, 0xe8, 0xdb, 0x1b, 0x06, 0xf7, 0x22, 0x0e, 0xd6,
+ 0xee, 0x75, 0xbd, 0x8b, 0x45, 0xdb, 0x37, 0x89, 0x1f, 0x8b, 0xa5, 0x55,
+ 0x03, 0x04, 0x00, 0x41, 0x59, 0xf4, 0x45, 0x3d, 0xc5, 0xb3, 0xf5, 0xa1
+};
+
+static const uint8_t p384_k[] = { /* 48 bytes */
+ 0xdc, 0x6b, 0x44, 0x03, 0x69, 0x89, 0xa1, 0x96, 0xe3, 0x9d, 0x1c, 0xda,
+ 0xc0, 0x00, 0x81, 0x2f, 0x4b, 0xdd, 0x8b, 0x2d, 0xb4, 0x1b, 0xb3, 0x3a,
+ 0xf5, 0x13, 0x72, 0x58, 0x5e, 0xbd, 0x1d, 0xb6, 0x3f, 0x0c, 0xe8, 0x27,
+ 0x5a, 0xa1, 0xfd, 0x45, 0xe2, 0xd2, 0xa7, 0x35, 0xf8, 0x74, 0x93, 0x59
+};
+
+static const uint8_t p384_key[] = { /* 167 bytes */
+ 0x30, 0x81, 0xa4, 0x02, 0x01, 0x01, 0x04, 0x30, 0xc8, 0x38, 0xb8, 0x52,
+ 0x53, 0xef, 0x8d, 0xc7, 0x39, 0x4f, 0xa5, 0x80, 0x8a, 0x51, 0x83, 0x98,
+ 0x1c, 0x7d, 0xee, 0xf5, 0xa6, 0x9b, 0xa8, 0xf4, 0xf2, 0x11, 0x7f, 0xfe,
+ 0xa3, 0x9c, 0xfc, 0xd9, 0x0e, 0x95, 0xf6, 0xcb, 0xc8, 0x54, 0xab, 0xac,
+ 0xab, 0x70, 0x1d, 0x50, 0xc1, 0xf3, 0xcf, 0x24, 0xa0, 0x07, 0x06, 0x05,
+ 0x2b, 0x81, 0x04, 0x00, 0x22, 0xa1, 0x64, 0x03, 0x62, 0x00, 0x04, 0x1f,
+ 0xba, 0xc8, 0xee, 0xbd, 0x0c, 0xbf, 0x35, 0x64, 0x0b, 0x39, 0xef, 0xe0,
+ 0x80, 0x8d, 0xd7, 0x74, 0xde, 0xbf, 0xf2, 0x0a, 0x2a, 0x32, 0x9e, 0x91,
+ 0x71, 0x3b, 0xaf, 0x7d, 0x7f, 0x3c, 0x3e, 0x81, 0x54, 0x6d, 0x88, 0x37,
+ 0x30, 0xbe, 0xe7, 0xe4, 0x86, 0x78, 0xf8, 0x57, 0xb0, 0x2c, 0xa0, 0xeb,
+ 0x21, 0x31, 0x03, 0xbd, 0x68, 0xce, 0x34, 0x33, 0x65, 0xa8, 0xa4, 0xc3,
+ 0xd4, 0x55, 0x5f, 0xa3, 0x85, 0xf5, 0x33, 0x02, 0x03, 0xbd, 0xd7, 0x6f,
+ 0xfa, 0xd1, 0xf3, 0xaf, 0xfb, 0x95, 0x75, 0x1c, 0x13, 0x20, 0x07, 0xe1,
+ 0xb2, 0x40, 0x35, 0x3c, 0xb0, 0xa4, 0xcf, 0x16, 0x93, 0xbd, 0xf9
+};
+
+static const uint8_t p384_kinv[] = { /* 48 bytes */
+ 0x74, 0x36, 0xf0, 0x30, 0x88, 0xe6, 0x5c, 0x37, 0xba, 0x8e, 0x7b, 0x33,
+ 0x88, 0x7f, 0xbc, 0x87, 0x75, 0x75, 0x14, 0xd6, 0x11, 0xf7, 0xd1, 0xfb,
+ 0xdf, 0x6d, 0x21, 0x04, 0xa2, 0x97, 0xad, 0x31, 0x8c, 0xdb, 0xf7, 0x40,
+ 0x4e, 0x4b, 0xa3, 0x7e, 0x59, 0x96, 0x66, 0xdf, 0x37, 0xb8, 0xd8, 0xbe
+};
+
+static const uint8_t p384_r[] = { /* 48 bytes */
+ 0xa0, 0xc2, 0x7e, 0xc8, 0x93, 0x09, 0x2d, 0xea, 0x1e, 0x1b, 0xd2, 0xcc,
+ 0xfe, 0xd3, 0xcf, 0x94, 0x5c, 0x81, 0x34, 0xed, 0x0c, 0x9f, 0x81, 0x31,
+ 0x1a, 0x0f, 0x4a, 0x05, 0x94, 0x2d, 0xb8, 0xdb, 0xed, 0x8d, 0xd5, 0x9f,
+ 0x26, 0x74, 0x71, 0xd5, 0x46, 0x2a, 0xa1, 0x4f, 0xe7, 0x2d, 0xe8, 0x56
+};
+
+static const uint8_t p384_s[] = { /* 48 bytes */
+ 0x20, 0xab, 0x3f, 0x45, 0xb7, 0x4f, 0x10, 0xb6, 0xe1, 0x1f, 0x96, 0xa2,
+ 0xc8, 0xeb, 0x69, 0x4d, 0x20, 0x6b, 0x9d, 0xda, 0x86, 0xd3, 0xc7, 0xe3,
+ 0x31, 0xc2, 0x6b, 0x22, 0xc9, 0x87, 0xb7, 0x53, 0x77, 0x26, 0x57, 0x76,
+ 0x67, 0xad, 0xad, 0xf1, 0x68, 0xeb, 0xbe, 0x80, 0x37, 0x94, 0xa4, 0x02
+};
+
+static const uint8_t p384_sig[] = { /* 103 bytes */
+ 0x30, 0x65, 0x02, 0x31, 0x00, 0xa0, 0xc2, 0x7e, 0xc8, 0x93, 0x09, 0x2d,
+ 0xea, 0x1e, 0x1b, 0xd2, 0xcc, 0xfe, 0xd3, 0xcf, 0x94, 0x5c, 0x81, 0x34,
+ 0xed, 0x0c, 0x9f, 0x81, 0x31, 0x1a, 0x0f, 0x4a, 0x05, 0x94, 0x2d, 0xb8,
+ 0xdb, 0xed, 0x8d, 0xd5, 0x9f, 0x26, 0x74, 0x71, 0xd5, 0x46, 0x2a, 0xa1,
+ 0x4f, 0xe7, 0x2d, 0xe8, 0x56, 0x02, 0x30, 0x20, 0xab, 0x3f, 0x45, 0xb7,
+ 0x4f, 0x10, 0xb6, 0xe1, 0x1f, 0x96, 0xa2, 0xc8, 0xeb, 0x69, 0x4d, 0x20,
+ 0x6b, 0x9d, 0xda, 0x86, 0xd3, 0xc7, 0xe3, 0x31, 0xc2, 0x6b, 0x22, 0xc9,
+ 0x87, 0xb7, 0x53, 0x77, 0x26, 0x57, 0x76, 0x67, 0xad, 0xad, 0xf1, 0x68,
+ 0xeb, 0xbe, 0x80, 0x37, 0x94, 0xa4, 0x02
+};
+
+static const uint8_t p384_u1[] = { /* 48 bytes */
+ 0x6c, 0xe2, 0x56, 0x49, 0xd4, 0x2d, 0x22, 0x3e, 0x02, 0x0c, 0x11, 0x14,
+ 0x0f, 0xe7, 0x72, 0x32, 0x66, 0x12, 0xbb, 0x11, 0xb6, 0x86, 0xd3, 0x5e,
+ 0xe9, 0x8e, 0xd4, 0x55, 0x0e, 0x06, 0x35, 0xd9, 0xdd, 0x3a, 0x2a, 0xfb,
+ 0xca, 0x0c, 0xf2, 0xc4, 0xba, 0xed, 0xcd, 0x23, 0x31, 0x3b, 0x18, 0x9e
+};
+
+static const uint8_t p384_u2[] = { /* 48 bytes */
+ 0xf3, 0xb2, 0x40, 0x75, 0x1d, 0x5d, 0x8e, 0xd3, 0x94, 0xa4, 0xb5, 0xbf,
+ 0x8e, 0x2a, 0x4c, 0x0e, 0x1e, 0x21, 0xaa, 0x51, 0xf2, 0x62, 0x0a, 0x08,
+ 0xb8, 0xc5, 0x5a, 0x2b, 0xc3, 0x34, 0xc9, 0x68, 0x99, 0x23, 0x16, 0x26,
+ 0x48, 0xf0, 0x6e, 0x5f, 0x46, 0x59, 0xfc, 0x52, 0x6d, 0x9c, 0x1f, 0xd6
+};
+
+static const uint8_t p384_v[] = { /* 48 bytes */
+ 0xa0, 0xc2, 0x7e, 0xc8, 0x93, 0x09, 0x2d, 0xea, 0x1e, 0x1b, 0xd2, 0xcc,
+ 0xfe, 0xd3, 0xcf, 0x94, 0x5c, 0x81, 0x34, 0xed, 0x0c, 0x9f, 0x81, 0x31,
+ 0x1a, 0x0f, 0x4a, 0x05, 0x94, 0x2d, 0xb8, 0xdb, 0xed, 0x8d, 0xd5, 0x9f,
+ 0x26, 0x74, 0x71, 0xd5, 0x46, 0x2a, 0xa1, 0x4f, 0xe7, 0x2d, 0xe8, 0x56
+};
+
+static const uint8_t p384_w[] = { /* 48 bytes */
+ 0x17, 0x98, 0x84, 0x5c, 0xd0, 0xa6, 0xce, 0xa5, 0x32, 0x7c, 0x50, 0x1a,
+ 0x71, 0xa4, 0xba, 0xf2, 0xf7, 0xbe, 0x88, 0x2c, 0xfb, 0xc3, 0x03, 0x75,
+ 0x0a, 0x7c, 0x86, 0x1a, 0xf8, 0xfe, 0x82, 0x25, 0x46, 0x7a, 0x25, 0x7f,
+ 0x5b, 0xf9, 0x1a, 0x4a, 0xaa, 0x5a, 0x79, 0xa8, 0x63, 0x7d, 0x21, 0x8a
+};
+
+typedef struct {
+ hal_ecdsa_curve_t curve;
+ const uint8_t * H; size_t H_len;
+ const uint8_t * M; size_t M_len;
+ const uint8_t * Qx; size_t Qx_len;
+ const uint8_t * Qy; size_t Qy_len;
+ const uint8_t * Rx; size_t Rx_len;
+ const uint8_t * Ry; size_t Ry_len;
+ const uint8_t * d; size_t d_len;
+ const uint8_t * e; size_t e_len;
+ const uint8_t * k; size_t k_len;
+ const uint8_t * key; size_t key_len;
+ const uint8_t * kinv; size_t kinv_len;
+ const uint8_t * r; size_t r_len;
+ const uint8_t * s; size_t s_len;
+ const uint8_t * sig; size_t sig_len;
+ const uint8_t * u1; size_t u1_len;
+ const uint8_t * u2; size_t u2_len;
+ const uint8_t * v; size_t v_len;
+ const uint8_t * w; size_t w_len;
+} ecdsa_tc_t;
+
+static const ecdsa_tc_t ecdsa_tc[] = {
+ { HAL_ECDSA_CURVE_P256,
+ p256_H, sizeof(p256_H),
+ p256_M, sizeof(p256_M),
+ p256_Qx, sizeof(p256_Qx),
+ p256_Qy, sizeof(p256_Qy),
+ p256_Rx, sizeof(p256_Rx),
+ p256_Ry, sizeof(p256_Ry),
+ p256_d, sizeof(p256_d),
+ p256_e, sizeof(p256_e),
+ p256_k, sizeof(p256_k),
+ p256_key, sizeof(p256_key),
+ p256_kinv, sizeof(p256_kinv),
+ p256_r, sizeof(p256_r),
+ p256_s, sizeof(p256_s),
+ p256_sig, sizeof(p256_sig),
+ p256_u1, sizeof(p256_u1),
+ p256_u2, sizeof(p256_u2),
+ p256_v, sizeof(p256_v),
+ p256_w, sizeof(p256_w),
+ },
+ { HAL_ECDSA_CURVE_P384,
+ p384_H, sizeof(p384_H),
+ p384_M, sizeof(p384_M),
+ p384_Qx, sizeof(p384_Qx),
+ p384_Qy, sizeof(p384_Qy),
+ p384_Rx, sizeof(p384_Rx),
+ p384_Ry, sizeof(p384_Ry),
+ p384_d, sizeof(p384_d),
+ p384_e, sizeof(p384_e),
+ p384_k, sizeof(p384_k),
+ p384_key, sizeof(p384_key),
+ p384_kinv, sizeof(p384_kinv),
+ p384_r, sizeof(p384_r),
+ p384_s, sizeof(p384_s),
+ p384_sig, sizeof(p384_sig),
+ p384_u1, sizeof(p384_u1),
+ p384_u2, sizeof(p384_u2),
+ p384_v, sizeof(p384_v),
+ p384_w, sizeof(p384_w),
+ },
+};
diff --git a/tests/test-ecdsa.py b/tests/test-ecdsa.py
new file mode 100644
index 0000000..1ecfef9
--- /dev/null
+++ b/tests/test-ecdsa.py
@@ -0,0 +1,156 @@
+# Test vectors from "Suite B Implementer's Guide to FIPS 186-3".
+#
+# e is given in decimal, all other values are hex, because that's how
+# these were given in the paper
+
+p256_d = 0x70a12c2db16845ed56ff68cfc21a472b3f04d7d6851bf6349f2d7d5b3452b38a
+p256_Qx = 0x8101ece47464a6ead70cf69a6e2bd3d88691a3262d22cba4f7635eaff26680a8
+p256_Qy = 0xd8a12ba61d599235f67d9cb4d58f1783d3ca43e78f0a5abaa624079936c0c3a9
+p256_k = 0x580ec00d856434334cef3f71ecaed4965b12ae37fa47055b1965c7b134ee45d0
+p256_kinv = 0x6a664fa115356d33f16331b54c4e7ce967965386c7dcbf2904604d0c132b4a74
+p256_Rx = 0x7214bc9647160bbd39ff2f80533f5dc6ddd70ddf86bb815661e805d5d4e6f27c
+p256_Ry = 0x8b81e3e977597110c7cf2633435b2294b72642987defd3d4007e1cfc5df84541
+p256_r = p256_Rx
+p256_M = 0x54686973206973206f6e6c7920612074657374206d6573736167652e204974206973203438206279746573206c6f6e67
+p256_H = 0x7c3e883ddc8bd688f96eac5e9324222c8f30f9d6bb59e9c5f020bd39ba2b8377
+p256_e = 56197278047627432394583341962843287937266210957576322469816113796290471232375
+p256_s = 0x7d1ff961980f961bdaa3233b6209f4013317d3e3f9e1493592dbeaa1af2bc367
+p256_w = 0xd69be75f67ee5394cabb6c286f3610cf62d722cba9eea70faee770a6b2ed72dc
+p256_u1 = 0xbb252401d6fb322bb747184cf2ac52bf8d54b95a1515062a2f6141f2e2092ed8
+p256_u2 = 0xaae7d1c7f2c232dfc641948af3dba141d4de8634e571cf84c486301b510cfc04
+p256_v = 0x7214bc9647160bbd39ff2f80533f5dc6ddd70ddf86bb815661e805d5d4e6f27c
+
+p384_d = 0xc838b85253ef8dc7394fa5808a5183981c7deef5a69ba8f4f2117ffea39cfcd90e95f6cbc854abacab701d50c1f3cf24
+p384_Qx = 0x1fbac8eebd0cbf35640b39efe0808dd774debff20a2a329e91713baf7d7f3c3e81546d883730bee7e48678f857b02ca0
+p384_Qy = 0xeb213103bd68ce343365a8a4c3d4555fa385f5330203bdd76ffad1f3affb95751c132007e1b240353cb0a4cf1693bdf9
+p384_k = 0xdc6b44036989a196e39d1cdac000812f4bdd8b2db41bb33af51372585ebd1db63f0ce8275aa1fd45e2d2a735f8749359
+p384_kinv = 0x7436f03088e65c37ba8e7b33887fbc87757514d611f7d1fbdf6d2104a297ad318cdbf7404e4ba37e599666df37b8d8be
+p384_Rx = 0xa0c27ec893092dea1e1bd2ccfed3cf945c8134ed0c9f81311a0f4a05942db8dbed8dd59f267471d5462aa14fe72de856
+p384_Ry = 0x855649409815bb91424eaca5fd76c97375d575d1422ec53d343bd33b847fdf0c11569685b528ab25493015428d7cf72b
+p384_r = p384_Rx
+p384_M = 0x54686973206973206f6e6c7920612074657374206d6573736167652e204974206973203438206279746573206c6f6e67
+p384_H = 0xb9210c9d7e20897ab86597266a9d5077e8db1b06f7220ed6ee75bd8b45db37891f8ba5550304004159f4453dc5b3f5a1
+p384_e = 28493976155450475404302482243066463769180620629462008675793884393889401828800663731864240088367206094074919580333473
+p384_s = 0x20ab3f45b74f10b6e11f96a2c8eb694d206b9dda86d3c7e331c26b22c987b7537726577667adadf168ebbe803794a402
+p384_w = 0x1798845cd0a6cea5327c501a71a4baf2f7be882cfbc303750a7c861af8fe8225467a257f5bf91a4aaa5a79a8637d218a
+p384_u1 = 0x6ce25649d42d223e020c11140fe772326612bb11b686d35ee98ed4550e0635d9dd3a2afbca0cf2c4baedcd23313b189e
+p384_u2 = 0xf3b240751d5d8ed394a4b5bf8e2a4c0e1e21aa51f2620a08b8c55a2bc334c9689923162648f06e5f4659fc526d9c1fd6
+p384_v = 0xa0c27ec893092dea1e1bd2ccfed3cf945c8134ed0c9f81311a0f4a05942db8dbed8dd59f267471d5462aa14fe72de856
+
+from textwrap import TextWrapper
+from os.path import basename
+from sys import argv
+from pyasn1.type.univ import Sequence, Choice, Integer, OctetString, ObjectIdentifier, BitString
+from pyasn1.type.namedtype import NamedTypes, NamedType, OptionalNamedType
+from pyasn1.type.namedval import NamedValues
+from pyasn1.type.tag import Tag, tagClassContext, tagFormatSimple
+from pyasn1.type.constraint import SingleValueConstraint
+from pyasn1.codec.der.encoder import encode as DER_Encode
+from pyasn1.codec.der.decoder import decode as DER_Decode
+
+wrapper = TextWrapper(width = 78, initial_indent = " " * 2, subsequent_indent = " " * 2)
+
+def long_to_bytes(l):
+ #
+ # This is just plain nasty.
+ #
+ s = "%x" % l
+ return ("0" + s if len(s) & 1 else s).decode("hex")
+
+def bytes_to_bits(b):
+ #
+ # This, on the other hand, is not just plain nasty, this is fancy nasty.
+ # This is nasty with raisins in it.
+ #
+ bits = bin(long(b.encode("hex"), 16))[2:]
+ if len(bits) % 8:
+ bits = ("0" * (8 - len(bits) % 8)) + bits
+ return tuple(int(i) for i in bits)
+
+###
+
+class ECDSA_Sig_Value(Sequence):
+ componentType = NamedTypes(
+ NamedType("r", Integer()),
+ NamedType("s", Integer()))
+
+def encode_sig(r, s):
+ sig = ECDSA_Sig_Value()
+ sig["r"] = r
+ sig["s"] = s
+ return DER_Encode(sig)
+
+p256_sig = encode_sig(p256_r, p256_s)
+p384_sig = encode_sig(p384_r, p384_s)
+
+###
+
+class ECPrivateKey(Sequence):
+ componentType = NamedTypes(
+ NamedType("version", Integer(namedValues = NamedValues(("ecPrivkeyVer1", 1))
+ ).subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(1))),
+ NamedType("privateKey", OctetString()),
+ OptionalNamedType("parameters", ObjectIdentifier().subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 0))),
+ OptionalNamedType("publicKey", BitString().subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 1))))
+
+def encode_key(d, Qx, Qy, oid):
+ private_key = long_to_bytes(d)
+ public_key = bytes_to_bits(chr(0x04) + long_to_bytes(Qx) + long_to_bytes(Qy))
+ parameters = oid
+ key = ECPrivateKey()
+ key["version"] = 1
+ key["privateKey"] = private_key
+ key["parameters"] = parameters
+ key["publicKey"] = public_key
+ return DER_Encode(key)
+
+p256_key = encode_key(p256_d, p256_Qx, p256_Qy, "1.2.840.10045.3.1.7")
+p384_key = encode_key(p384_d, p384_Qx, p384_Qy, "1.3.132.0.34")
+
+###
+
+print "/*"
+print " * ECDSA test data."
+print " * File automatically generated by", basename(argv[0])
+print " */"
+
+curves = ("p256", "p384")
+vars = set()
+
+for name in dir():
+ head, sep, tail = name.partition("_")
+ if head in curves:
+ vars.add(tail)
+
+vars = sorted(vars)
+
+for curve in curves:
+ for var in vars:
+ name = curve + "_" + var
+ value = globals().get(name, None)
+ if isinstance(value, (int, long)):
+ value = long_to_bytes(value)
+ if value is not None:
+ print
+ print "static const uint8_t %s[] = { /* %d bytes */" % (name, len(value))
+ print wrapper.fill(", ".join("0x%02x" % ord(v) for v in value))
+ print "};"
+
+print
+print "typedef struct {"
+print " hal_ecdsa_curve_t curve;"
+for var in vars:
+ print " const uint8_t *%8s; size_t %8s_len;" % (var, var)
+print "} ecdsa_tc_t;"
+print
+print "static const ecdsa_tc_t ecdsa_tc[] = {"
+for curve in curves:
+ print " { HAL_ECDSA_CURVE_%s," % curve.upper()
+ for var in vars:
+ name = curve + "_" + var
+ if name in globals():
+ print " %-14s sizeof(%s)," % (name + ",", name)
+ else:
+ print " %-14s 0," % "NULL,"
+ print " },"
+print "};"
diff --git a/tests/test-hash.c b/tests/test-hash.c
index befdf02..144b1b9 100644
--- a/tests/test-hash.c
+++ b/tests/test-hash.c
@@ -533,7 +533,7 @@ static int _test_hash(const hal_hash_descriptor_t * const descriptor,
const char * const label)
{
uint8_t statebuf[512], digest[512];
- hal_hash_state_t state;
+ hal_hash_state_t *state = NULL;
hal_error_t err;
assert(descriptor != NULL && data != NULL && result != NULL && label != NULL);
@@ -597,7 +597,7 @@ static int _test_hmac(const hal_hash_descriptor_t * const descriptor,
const char * const label)
{
uint8_t statebuf[1024], digest[512];
- hal_hmac_state_t state;
+ hal_hmac_state_t *state = NULL;
hal_error_t err;
assert(descriptor != NULL && data != NULL && result != NULL && label != NULL);
diff --git a/tests/test-pbkdf2.c b/tests/test-pbkdf2.c
index 469b599..0688226 100644
--- a/tests/test-pbkdf2.c
+++ b/tests/test-pbkdf2.c
@@ -163,7 +163,7 @@ static int _test_pbkdf2(const uint8_t * const pwd, const size_t pwd_len,
const uint8_t * const dk, const size_t dk_len,
const unsigned count, const char * const label)
{
- printf("Starting test case %s\n", label);
+ printf("Starting PBKDF2 test case %s\n", label);
uint8_t result[dk_len];
diff --git a/tests/test-rsa.c b/tests/test-rsa.c
index f6bf55c..46afa03 100644
--- a/tests/test-rsa.c
+++ b/tests/test-rsa.c
@@ -88,7 +88,7 @@ static int test_decrypt(const char * const kind, const rsa_tc_t * const tc)
printf("%s test for %lu-bit RSA key\n", kind, (unsigned long) tc->size);
uint8_t keybuf[hal_rsa_key_t_size];
- hal_rsa_key_t key = { NULL };
+ hal_rsa_key_t *key = NULL;
hal_error_t err = HAL_OK;
if ((err = hal_rsa_key_load_private(&key,
@@ -130,7 +130,7 @@ static int test_gen(const char * const kind, const rsa_tc_t * const tc)
char fn[sizeof("test-rsa-key-xxxxxx.der")];
uint8_t keybuf1[hal_rsa_key_t_size], keybuf2[hal_rsa_key_t_size];
- hal_rsa_key_t key1 = { NULL }, key2 = { NULL };
+ hal_rsa_key_t *key1 = NULL, *key2 = NULL;
hal_error_t err = HAL_OK;
FILE *f;