aboutsummaryrefslogtreecommitdiff
path: root/asn1.c
diff options
context:
space:
mode:
Diffstat (limited to 'asn1.c')
-rw-r--r--asn1.c170
1 files changed, 162 insertions, 8 deletions
diff --git a/asn1.c b/asn1.c
index 73e34b6..37318a9 100644
--- a/asn1.c
+++ b/asn1.c
@@ -77,6 +77,10 @@ const uint8_t hal_asn1_oid_aesKeyWrap[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
const size_t hal_asn1_oid_aesKeyWrap_len = sizeof(hal_asn1_oid_aesKeyWrap);
#endif
+/* from draft-housley-cms-mts-hash-sig-07.txt */
+const uint8_t hal_asn1_oid_mts_hashsig[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x10, 0x03, 0x11 };
+const size_t hal_asn1_oid_mts_hashsig_len = sizeof(hal_asn1_oid_mts_hashsig);
+
/*
* Encode tag and length fields of an ASN.1 object.
*
@@ -175,6 +179,88 @@ hal_error_t hal_asn1_encode_integer(const fp_int * const bn,
}
/*
+ * 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).
*/
@@ -484,6 +570,68 @@ hal_error_t hal_asn1_decode_integer(fp_int *bn,
}
/*
+ * 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).
*/
@@ -517,7 +665,7 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (alg_oid != NULL)
*alg_oid = d;
@@ -537,7 +685,7 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (curve_oid != NULL)
*curve_oid = d;
@@ -564,7 +712,7 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
if ((err = hal_asn1_decode_header(ASN1_BIT_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen >= algid_end - d || vlen == 0 || *d != 0x00)
+ if (vlen >= (size_t)(algid_end - d) || vlen == 0 || *d != 0x00)
return HAL_ERROR_ASN1_PARSE_FAILED;
++d; --vlen;
if (pubkey != NULL)
@@ -620,7 +768,7 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (alg_oid != NULL)
*alg_oid = d;
@@ -640,7 +788,7 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (curve_oid != NULL)
*curve_oid = d;
@@ -667,7 +815,7 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size
if ((err = hal_asn1_decode_header(ASN1_OCTET_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen >= algid_end - d)
+ if (vlen >= (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (privkey != NULL)
*privkey = d;
@@ -714,7 +862,7 @@ hal_error_t hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(const uint8_t **alg_oi
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (alg_oid != NULL)
*alg_oid = d;
@@ -736,7 +884,7 @@ hal_error_t hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(const uint8_t **alg_oi
if ((err = hal_asn1_decode_header(ASN1_OCTET_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen >= algid_end - d)
+ if (vlen >= (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (data != NULL)
*data = d;
@@ -788,6 +936,12 @@ hal_error_t hal_asn1_guess_key_type(hal_key_type_t *type,
return err;
}
+ if (alg_oid_len == hal_asn1_oid_mts_hashsig_len && memcmp(alg_oid, hal_asn1_oid_mts_hashsig, alg_oid_len) == 0) {
+ *type = public ? HAL_KEY_TYPE_HASHSIG_PUBLIC : HAL_KEY_TYPE_HASHSIG_PRIVATE;
+ *curve = HAL_CURVE_NONE;
+ return HAL_OK;
+ }
+
*type = HAL_KEY_TYPE_NONE;
*curve = HAL_CURVE_NONE;
return HAL_ERROR_UNSUPPORTED_KEY;