[Cryptech-Commits] [sw/libhal] 03/13: Encode/decode uint32_t and octet strings

git at cryptech.is git at cryptech.is
Fri Apr 20 01:06:10 UTC 2018


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

paul at psgd.org pushed a commit to branch hashsig
in repository sw/libhal.

commit 67d4de2fdb0cb473e53da52b8639a27ce0dfc2b7
Author: Paul Selkirk <paul at psgd.org>
AuthorDate: Tue Feb 27 17:59:02 2018 +0100

    Encode/decode uint32_t and octet strings
---
 asn1.c          | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 asn1_internal.h |  12 +++++
 2 files changed, 156 insertions(+)

diff --git a/asn1.c b/asn1.c
index a653b45..1f4a14a 100644
--- a/asn1.c
+++ b/asn1.c
@@ -174,6 +174,88 @@ hal_error_t hal_asn1_encode_integer(const fp_int * const bn,
   return HAL_OK;
 }
 
+/*
+ * Encode an unsigned ASN.1 INTEGER from a uint32_t.  If der is
+ * NULL, just return the length of what we would have encoded.
+ */
+
+hal_error_t hal_asn1_encode_uint32(const uint32_t n,
+                                   uint8_t *der, size_t *der_len, const size_t der_max)
+{
+  /*
+   * 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.
+   */
+
+  size_t vlen;
+  hal_error_t err;
+  size_t hlen;
+
+  /* DER says to use the minimum number of octets */
+  if (n < 0x80)            vlen = 1;
+  else if (n < 0x8000)     vlen = 2;
+  else if (n < 0x800000)   vlen = 3;
+  else if (n < 0x80000000) vlen = 4;
+  else                     vlen = 5;
+
+  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;
+
+  uint32_t m = n;
+  for (size_t i = vlen; i > 0; --i) {
+    der[i - 1] = m & 0xff;
+    m >>= 8;
+  }
+
+  return HAL_OK;
+}
+
+/*
+ * Encode an ASN.1 OCTET STRING.  If der is NULL, just return the length
+ * of what we would have encoded.
+ */
+
+hal_error_t hal_asn1_encode_octet_string(const uint8_t * const data,    const size_t data_len,
+                                         uint8_t *der, size_t *der_len, const size_t der_max)
+{
+  if (data_len == 0 || (der != NULL && data == NULL))
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  size_t hlen;
+  hal_error_t err;
+
+  if ((err = hal_asn1_encode_header(ASN1_OCTET_STRING, data_len, NULL, &hlen, 0)) != HAL_OK)
+    return err;
+  
+  if (der_len != NULL)
+    *der_len = hlen + data_len;
+
+  if (der == NULL)
+    return HAL_OK;
+
+  assert(hlen + data_len <= der_max);
+
+  /*
+   * Handle data early, in case it was staged into our output buffer.
+   */
+  memmove(der + hlen, data, data_len);
+
+  if ((err = hal_asn1_encode_header(ASN1_OCTET_STRING, data_len, der, &hlen, der_max)) != HAL_OK)
+    return err;
+
+  return HAL_OK;
+}
+
 /*
  * Encode a public key into a X.509 SubjectPublicKeyInfo (RFC 5280).
  */
@@ -483,6 +565,68 @@ hal_error_t hal_asn1_decode_integer(fp_int *bn,
   return HAL_OK;
 }
 
+/*
+ * Decode an ASN.1 INTEGER into a uint32_t.  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_uint32(uint32_t *np,
+                                   const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+  if (np == 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 || vlen > 5 || (der[hlen] & 0x80) != 0x00 || (vlen == 5 && der[hlen] != 0))
+    return HAL_ERROR_ASN1_PARSE_FAILED;
+
+  uint32_t n = 0;
+  for (size_t i = 0; i < vlen; ++i) {
+    n <<= 8;		// slightly inefficient for the first octet
+    n += der[hlen + i];
+  }
+  *np = n;
+
+  return HAL_OK;
+}
+
+/*
+ * Decode an ASN.1 OCTET STRING.
+ */
+
+hal_error_t hal_asn1_decode_octet_string(uint8_t *data, const size_t data_len,
+                                         const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+  if (der == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  size_t hlen, vlen;
+  hal_error_t err;
+
+  if ((err = hal_asn1_decode_header(ASN1_OCTET_STRING, der, der_max, &hlen, &vlen)) != HAL_OK)
+    return err;
+
+  if (der_len != NULL)
+    *der_len = hlen + vlen;
+
+  if (data != NULL) {
+    if (data_len != vlen)
+      return HAL_ERROR_ASN1_PARSE_FAILED;
+    memmove(data, der + hlen, vlen);
+  }
+
+  return HAL_OK;
+}
+
 /*
  * Decode a public key from a X.509 SubjectPublicKeyInfo (RFC 5280).
  */
diff --git a/asn1_internal.h b/asn1_internal.h
index 3de8bd6..bba4503 100644
--- a/asn1_internal.h
+++ b/asn1_internal.h
@@ -117,9 +117,21 @@ extern hal_error_t hal_asn1_decode_header(const uint8_t tag,
 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_encode_uint32(const uint32_t n,
+                                          uint8_t *der, size_t *der_len, const size_t der_max);
+
+extern hal_error_t hal_asn1_encode_octet_string(const uint8_t * const data,    const size_t data_len,
+                                                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);
 
+extern hal_error_t hal_asn1_decode_uint32(uint32_t *np,
+                                          const uint8_t * const der, size_t *der_len, const size_t der_max);
+
+extern hal_error_t hal_asn1_decode_octet_string(uint8_t *data, const size_t data_len,
+                                                const uint8_t * const der, size_t *der_len, const size_t der_max);
+
 extern hal_error_t hal_asn1_encode_spki(const uint8_t * const alg_oid,   const size_t alg_oid_len,
                                         const uint8_t * const curve_oid, const size_t curve_oid_len,
                                         const uint8_t * const pubkey,    const size_t pubkey_len,



More information about the Commits mailing list