[Cryptech-Commits] [sw/libhal] 03/12: Add PKCS11 ECDSA signature format.

git at cryptech.is git at cryptech.is
Mon Sep 14 21:43:20 UTC 2015


This is an automated email from the git hooks/post-receive script.

sra at hactrn.net pushed a commit to branch ecdsa
in repository sw/libhal.

commit ed1608dd6bc38f2e2f1c905a54f01531acddcf25
Author: Rob Austein <sra at hactrn.net>
Date:   Wed Sep 2 22:16:33 2015 -0400

    Add PKCS11 ECDSA signature format.
---
 ecdsa.c            | 195 ++++++++++++++++++++++++++++++++++++++++++++---------
 hal.h              |   8 ++-
 tests/test-ecdsa.c |  12 ++--
 3 files changed, 176 insertions(+), 39 deletions(-)

diff --git a/ecdsa.c b/ecdsa.c
index 610c3de..8d9beb0 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -1097,12 +1097,145 @@ hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_,
 }
 
 /*
+ * 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.
+ */
+
+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);
+
+  if (signature == NULL || signature_len == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  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_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);
+  *signature_len = n_len * 2;
+
+  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).
+ */
+
+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 }.
+ */
+
+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);
+
+  if (signature == NULL || signature_len == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  hal_error_t err = HAL_ERROR_IMPOSSIBLE;
+  size_t r_len, s_len;
+
+  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 ||
+      (err = hal_asn1_encode_header(ASN1_SEQUENCE, r_len + s_len,
+                                    signature, signature_len, signature_max)) != HAL_OK)
+    goto fail;
+
+  uint8_t * const r_out = signature + *signature_len;
+  uint8_t * const s_out = r_out + r_len;
+  *signature_len += r_len + s_len;
+  assert(*signature_len <= signature_max);
+
+  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)
+    goto fail;
+
+  err = HAL_OK;
+
+ fail:
+  return err;
+}
+
+/*
+ * Decode a signature from ASN.1 format SEQUENCE { INTEGER r, INTEGER s }.
+ */
+
+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)
+                           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;
@@ -1162,25 +1295,24 @@ hal_error_t hal_ecdsa_sign(const hal_ecdsa_key_t * const key,
   } while (fp_iszero(s));
 
   /*
-   * Final signature is ASN.1 DER encoding of SEQUENCE { INTEGER r, INTEGER s }.
+   * Encode the signature, then we're done.
    */
 
-  size_t r_len, s_len;
+  switch (signature_format) {
 
-  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 ||
-      (err = hal_asn1_encode_header(ASN1_SEQUENCE, r_len + s_len,
-                                    signature, signature_len, signature_max)) != HAL_OK)
-    goto fail;
+  case HAL_ECDSA_SIGNATURE_FORMAT_ASN1:
+    if ((err = encode_signature_asn1(curve, r, s, signature, signature_len, signature_max)) != HAL_OK)
+      goto fail;
+    break;
 
-  uint8_t * const r_out = signature + *signature_len;
-  uint8_t * const s_out = r_out + r_len;
-  *signature_len += r_len + s_len;
-  assert(*signature_len <= signature_max);
+  case HAL_ECDSA_SIGNATURE_FORMAT_PKCS11:
+    if ((err = encode_signature_pkcs11(curve, r, s, signature, signature_len, signature_max)) != HAL_OK)
+      goto fail;
+    break;
 
-  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)
-    goto fail;
+  default:
+    lose(HAL_ERROR_BAD_ARGUMENTS);
+  }
 
   err = HAL_OK;
 
@@ -1195,8 +1327,9 @@ hal_error_t hal_ecdsa_sign(const hal_ecdsa_key_t * const key,
  */
 
 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 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);
 
@@ -1210,7 +1343,6 @@ hal_error_t hal_ecdsa_verify(const hal_ecdsa_key_t * const key,
 
   fp_int * const n = unconst_fp_int(curve->n);
 
-  size_t len1, len2;
   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];
@@ -1221,25 +1353,24 @@ hal_error_t hal_ecdsa_verify(const hal_ecdsa_key_t * const key,
   memset(R,   0, sizeof(R));
 
   /*
-   * Parse the ASN.1 SEQUENCE { INTEGER r, INTEGER s }.
+   * Start by decoding the signature.
    */
 
-  if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, signature, signature_len, &len1, &len2)) != HAL_OK)
-    return err;
+  switch (signature_format) {
 
-  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;
+  case HAL_ECDSA_SIGNATURE_FORMAT_ASN1:
+    if ((err = decode_signature_asn1(curve, r, s, signature, signature_len)) != HAL_OK)
+      return err;
+    break;
 
-  if ((err = hal_asn1_decode_integer(s, der, &len1, der_end - der)) != HAL_OK)
-    return err;
-  der += len1;
+  case HAL_ECDSA_SIGNATURE_FORMAT_PKCS11:
+    if ((err = decode_signature_pkcs11(curve, r, s, signature, signature_len)) != HAL_OK)
+      return err;
+    break;
 
-  if (der != der_end)
-    return HAL_ERROR_ASN1_PARSE_FAILED;
+  default:
+    return HAL_ERROR_BAD_ARGUMENTS;
+  }
 
   /*
    * Check that r and s are in the allowed range, read the hash, then
diff --git a/hal.h b/hal.h
index 42012f1..6430cdb 100644
--- a/hal.h
+++ b/hal.h
@@ -687,6 +687,8 @@ 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;
@@ -733,11 +735,13 @@ extern hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key,
 
 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);
+                                  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 uint8_t * const signature, const size_t signature_len,
+                                  const hal_ecdsa_signature_format_t signature_format);
 
 #endif /* _HAL_H_ */
 
diff --git a/tests/test-ecdsa.c b/tests/test-ecdsa.c
index d41a54d..cb590e5 100644
--- a/tests/test-ecdsa.c
+++ b/tests/test-ecdsa.c
@@ -151,13 +151,13 @@ static int test_against_static_vectors(const ecdsa_tc_t * const tc)
   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_OK)
+  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_OK)
+  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);
@@ -177,7 +177,7 @@ static int test_against_static_vectors(const ecdsa_tc_t * const tc)
                                        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_OK)
+  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;
@@ -242,10 +242,12 @@ static int test_keygen_sign_verify(const hal_ecdsa_curve_t curve)
   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_OK)
+  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_OK)
+  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;



More information about the Commits mailing list