aboutsummaryrefslogtreecommitdiff
path: root/asn1.c
diff options
context:
space:
mode:
Diffstat (limited to 'asn1.c')
-rw-r--r--asn1.c441
1 files changed, 425 insertions, 16 deletions
diff --git a/asn1.c b/asn1.c
index bbb049f..73e34b6 100644
--- a/asn1.c
+++ b/asn1.c
@@ -52,9 +52,31 @@
#include <assert.h>
#include "hal.h"
-
+#include "hal_internal.h"
#include "asn1_internal.h"
+#define INIT_FP_INT {{{0}}}
+
+/*
+ * Algorithm OIDs used in SPKI and PKCS #8.
+ */
+
+const uint8_t hal_asn1_oid_rsaEncryption[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
+const size_t hal_asn1_oid_rsaEncryption_len = sizeof(hal_asn1_oid_rsaEncryption);
+
+const uint8_t hal_asn1_oid_ecPublicKey[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 };
+const size_t hal_asn1_oid_ecPublicKey_len = sizeof(hal_asn1_oid_ecPublicKey);
+
+#if KEK_LENGTH == (bitsToBytes(128))
+const uint8_t hal_asn1_oid_aesKeyWrap[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x08 };
+const size_t hal_asn1_oid_aesKeyWrap_len = sizeof(hal_asn1_oid_aesKeyWrap);
+#endif
+
+#if KEK_LENGTH == (bitsToBytes(256))
+const uint8_t hal_asn1_oid_aesKeyWrap[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x30 };
+const size_t hal_asn1_oid_aesKeyWrap_len = sizeof(hal_asn1_oid_aesKeyWrap);
+#endif
+
/*
* Encode tag and length fields of an ASN.1 object.
*
@@ -153,7 +175,7 @@ hal_error_t hal_asn1_encode_integer(const fp_int * const bn,
}
/*
- * Encode a public key into an RFC 5280 SubjectPublicKeyInfo.
+ * Encode a public key into a X.509 SubjectPublicKeyInfo (RFC 5280).
*/
hal_error_t hal_asn1_encode_spki(const uint8_t * const alg_oid, const size_t alg_oid_len,
@@ -176,12 +198,14 @@ hal_error_t hal_asn1_encode_spki(const uint8_t * const alg_oid, const size_t a
(err = hal_asn1_encode_header(ASN1_BIT_STRING, 1 + pubkey_len, NULL, &hlen_bit, 0)) != HAL_OK)
return err;
- const size_t algid_len = hlen_alg + alg_oid_len + hlen_curve + curve_oid_len;
+ const size_t algid_len =
+ hlen_alg + alg_oid_len + hlen_curve + curve_oid_len;
if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, algid_len, NULL, &hlen_algid, 0)) != HAL_OK)
return err;
- const size_t vlen = hlen_algid + hlen_alg + alg_oid_len + hlen_curve + curve_oid_len + hlen_bit + 1 + pubkey_len;
+ const size_t vlen =
+ hlen_algid + hlen_alg + alg_oid_len + hlen_curve + curve_oid_len + hlen_bit + 1 + pubkey_len;
if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen_spki, 0)) != HAL_OK)
return err;
@@ -224,7 +248,6 @@ hal_error_t hal_asn1_encode_spki(const uint8_t * const alg_oid, const size_t a
return err;
d += hlen;
*d++ = 0x00;
-
d += pubkey_len; /* pubkey handled early, above. */
assert(d == der + hlen_spki + vlen);
@@ -234,6 +257,167 @@ hal_error_t hal_asn1_encode_spki(const uint8_t * const alg_oid, const size_t a
}
/*
+ * Encode a PKCS #8 PrivateKeyInfo (RFC 5208).
+ */
+
+hal_error_t hal_asn1_encode_pkcs8_privatekeyinfo(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 privkey, const size_t privkey_len,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (alg_oid == NULL || alg_oid_len == 0 || privkey_len == 0 ||
+ (der != NULL && privkey == NULL) || (curve_oid == NULL && curve_oid_len != 0))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const uint8_t curve_oid_tag = curve_oid == NULL ? ASN1_NULL : ASN1_OBJECT_IDENTIFIER;
+
+ fp_int version[1] = INIT_FP_INT;
+
+ hal_error_t err;
+
+ size_t version_len, hlen, hlen_algid, hlen_alg, hlen_curve, hlen_oct;
+
+ if ((err = hal_asn1_encode_integer(version, NULL, &version_len, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, alg_oid_len, NULL, &hlen_alg, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_header(curve_oid_tag, curve_oid_len, NULL, &hlen_curve, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_header(ASN1_OCTET_STRING, privkey_len, NULL, &hlen_oct, 0)) != HAL_OK)
+ return err;
+
+ const size_t algid_len =
+ hlen_alg + alg_oid_len + hlen_curve + curve_oid_len;
+
+ if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, algid_len, NULL, &hlen_algid, 0)) != HAL_OK)
+ return err;
+
+ const size_t vlen =
+ version_len + hlen_algid + hlen_alg + alg_oid_len + hlen_curve + curve_oid_len + hlen_oct + privkey_len;
+
+ if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen, 0)) != HAL_OK)
+ return err;
+
+ if (der_len != NULL)
+ *der_len = hlen + vlen;
+
+ if (der == NULL)
+ return HAL_OK;
+
+ uint8_t * const der_end = der + hlen + vlen;
+
+ /*
+ * Handle privkey early, in case it was staged into our output buffer.
+ */
+ if (der_end <= der + der_max)
+ memmove(der_end - privkey_len, privkey, privkey_len);
+
+ uint8_t *d = der;
+ memset(d, 0, hlen + vlen - privkey_len);
+
+ if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+
+ 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_SEQUENCE, algid_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+
+ if ((err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, alg_oid_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+ memcpy(d, alg_oid, alg_oid_len);
+ d += alg_oid_len;
+
+ if ((err = hal_asn1_encode_header(curve_oid_tag, curve_oid_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+ if (curve_oid != NULL)
+ memcpy(d, curve_oid, curve_oid_len);
+ d += curve_oid_len;
+
+ if ((err = hal_asn1_encode_header(ASN1_OCTET_STRING, privkey_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+ d += privkey_len; /* privkey handled early, above. */
+
+ assert(d == der_end);
+ assert(d <= der + der_max);
+
+ return HAL_OK;
+}
+
+/*
+ * Encode a PKCS #8 EncryptedPrivateKeyInfo (RFC 5208).
+ */
+
+hal_error_t hal_asn1_encode_pkcs8_encryptedprivatekeyinfo(const uint8_t * const alg_oid, const size_t alg_oid_len,
+ const uint8_t * const data, const size_t data_len,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (alg_oid == NULL || alg_oid_len == 0 || data_len == 0 || (der != NULL && data == NULL))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err;
+
+ size_t hlen, hlen_pkcs8, hlen_algid, hlen_alg, hlen_oct;
+
+ if ((err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, alg_oid_len, NULL, &hlen_alg, 0)) != HAL_OK ||
+ (err = hal_asn1_encode_header(ASN1_OCTET_STRING, data_len, NULL, &hlen_oct, 0)) != HAL_OK)
+ return err;
+
+ const size_t algid_len = hlen_alg + alg_oid_len;
+
+ if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, algid_len, NULL, &hlen_algid, 0)) != HAL_OK)
+ return err;
+
+ const size_t vlen = hlen_algid + hlen_alg + alg_oid_len + hlen_oct + data_len;
+
+ if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen_pkcs8, 0)) != HAL_OK)
+ return err;
+
+ /*
+ * Handle data early, in case it was staged into our output buffer.
+ */
+ if (der != NULL && hlen_pkcs8 + vlen <= der_max)
+ memmove(der + hlen_pkcs8 + vlen - data_len, data, data_len);
+
+ 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 - data_len);
+
+ if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, algid_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+
+ if ((err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, alg_oid_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+ memcpy(d, alg_oid, alg_oid_len);
+ d += alg_oid_len;
+
+ if ((err = hal_asn1_encode_header(ASN1_OCTET_STRING, data_len, d, &hlen, der + der_max - d)) != HAL_OK)
+ return err;
+ d += hlen;
+
+ d += data_len; /* data handled early, above. */
+
+ assert(d == der + hlen_pkcs8 + vlen);
+ assert(d <= der + der_max);
+
+ 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.
@@ -300,7 +484,7 @@ hal_error_t hal_asn1_decode_integer(fp_int *bn,
}
/*
- * Decode a public key from an RFC 5280 SubjectPublicKeyInfo.
+ * Decode a public key from a X.509 SubjectPublicKeyInfo (RFC 5280).
*/
hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
@@ -308,8 +492,7 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
const uint8_t **pubkey, size_t *pubkey_len,
const uint8_t *const der, const size_t der_len)
{
- if (alg_oid == NULL || alg_oid_len == NULL || curve_oid == NULL || curve_oid_len == NULL ||
- pubkey == NULL || pubkey_len == NULL || der == NULL)
+ if (der == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
const uint8_t * const der_end = der + der_len;
@@ -322,6 +505,9 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
return err;
d += hlen;
+ if (hlen + vlen != der_len)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, d, der_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
@@ -333,12 +519,16 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
d += hlen;
if (vlen > algid_end - d)
return HAL_ERROR_ASN1_PARSE_FAILED;
- *alg_oid = d;
- *alg_oid_len = vlen;
+ if (alg_oid != NULL)
+ *alg_oid = d;
+ if (alg_oid_len != NULL)
+ *alg_oid_len = vlen;
d += vlen;
- *curve_oid = NULL;
- *curve_oid_len = 0;
+ if (curve_oid != NULL)
+ *curve_oid = NULL;
+ if (curve_oid_len != NULL)
+ *curve_oid_len = 0;
if (d < algid_end) {
switch (*d) {
@@ -349,8 +539,10 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
d += hlen;
if (vlen > algid_end - d)
return HAL_ERROR_ASN1_PARSE_FAILED;
- *curve_oid = d;
- *curve_oid_len = vlen;
+ if (curve_oid != NULL)
+ *curve_oid = d;
+ if (curve_oid_len != NULL)
+ *curve_oid_len = vlen;
d += vlen;
break;
@@ -374,8 +566,11 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
d += hlen;
if (vlen >= algid_end - d || vlen == 0 || *d != 0x00)
return HAL_ERROR_ASN1_PARSE_FAILED;
- *pubkey = ++d;
- *pubkey_len = --vlen;
+ ++d; --vlen;
+ if (pubkey != NULL)
+ *pubkey = d;
+ if (pubkey_len != NULL)
+ *pubkey_len = vlen;
d += vlen;
if (d != der_end)
@@ -385,6 +580,220 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
}
/*
+ * Decode a private key from a PKCS #8 PrivateKeyInfo (RFC 5208).
+ */
+
+hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size_t *alg_oid_len,
+ const uint8_t **curve_oid, size_t *curve_oid_len,
+ const uint8_t **privkey, size_t *privkey_len,
+ const uint8_t *const der, const size_t der_len)
+{
+ if (der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const uint8_t * const der_end = der + der_len;
+ const uint8_t *d = der;
+
+ fp_int version[1] = INIT_FP_INT;
+ size_t hlen, vlen;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, d, der_end - d, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+
+ if (hlen + vlen != der_len)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ if ((err = hal_asn1_decode_integer(version, d, &hlen, der_end - d)) != HAL_OK)
+ return err;
+ if (!fp_iszero(version))
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ d += hlen;
+
+ if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, d, der_end - d, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+
+ const uint8_t * const algid_end = d + vlen;
+
+ 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)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ if (alg_oid != NULL)
+ *alg_oid = d;
+ if (alg_oid_len != NULL)
+ *alg_oid_len = vlen;
+ d += vlen;
+
+ if (curve_oid != NULL)
+ *curve_oid = NULL;
+ if (curve_oid_len != NULL)
+ *curve_oid_len = 0;
+
+ if (d < algid_end) {
+ switch (*d) {
+
+ case ASN1_OBJECT_IDENTIFIER:
+ 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)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ if (curve_oid != NULL)
+ *curve_oid = d;
+ if (curve_oid_len != NULL)
+ *curve_oid_len = vlen;
+ d += vlen;
+ break;
+
+ case ASN1_NULL:
+ if ((err = hal_asn1_decode_header(ASN1_NULL, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+ if (vlen == 0)
+ break;
+
+ default:
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ }
+ }
+
+ if (d != algid_end)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ 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)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ if (privkey != NULL)
+ *privkey = d;
+ if (privkey_len != NULL)
+ *privkey_len = vlen;
+ d += vlen;
+
+ if (d != der_end)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ return HAL_OK;
+}
+
+/*
+ * Decode a private key from a PKCS #8 EncryptedPrivateKeyInfo (RFC 5208).
+ */
+
+hal_error_t hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(const uint8_t **alg_oid, size_t *alg_oid_len,
+ const uint8_t **data, size_t *data_len,
+ const uint8_t *const der, const size_t der_len)
+{
+ if (alg_oid == NULL || alg_oid_len == NULL || data == NULL || data_len == NULL || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const uint8_t * const der_end = der + der_len;
+ const uint8_t *d = der;
+
+ size_t hlen, vlen;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, d, der_end - d, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+
+ if (hlen + vlen != der_len)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, d, der_end - d, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+
+ const uint8_t * const algid_end = d + vlen;
+
+ 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)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ if (alg_oid != NULL)
+ *alg_oid = d;
+ if (alg_oid_len != NULL)
+ *alg_oid_len = vlen;
+ d += vlen;
+
+ if (d < algid_end) {
+ if ((err = hal_asn1_decode_header(ASN1_NULL, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
+ return err;
+ d += hlen;
+ if (vlen != 0)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ }
+
+ if (d != algid_end)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ 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)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ if (data != NULL)
+ *data = d;
+ if (data_len != NULL)
+ *data_len = vlen;
+ d += vlen;
+
+ if (d != der_end)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ return HAL_OK;
+}
+
+/*
+ * Attempt to guess what kind of key we're looking at.
+ */
+
+hal_error_t hal_asn1_guess_key_type(hal_key_type_t *type,
+ hal_curve_name_t *curve,
+ const uint8_t *const der, const size_t der_len)
+{
+ if (type == NULL || curve == NULL || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const uint8_t *alg_oid, *curve_oid;
+ size_t alg_oid_len, curve_oid_len;
+ hal_error_t err;
+ int public = 0;
+
+ err = hal_asn1_decode_pkcs8_privatekeyinfo(&alg_oid, &alg_oid_len, &curve_oid, &curve_oid_len, NULL, 0, der, der_len);
+
+ if (err == HAL_ERROR_ASN1_PARSE_FAILED &&
+ (err = hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &curve_oid, &curve_oid_len, NULL, 0, der, der_len)) == HAL_OK)
+ public = 1;
+
+ if (err != HAL_OK)
+ return err;
+
+ if (alg_oid_len == hal_asn1_oid_rsaEncryption_len && memcmp(alg_oid, hal_asn1_oid_rsaEncryption, alg_oid_len) == 0) {
+ *type = public ? HAL_KEY_TYPE_RSA_PUBLIC : HAL_KEY_TYPE_RSA_PRIVATE;
+ *curve = HAL_CURVE_NONE;
+ return HAL_OK;
+ }
+
+ if (alg_oid_len == hal_asn1_oid_ecPublicKey_len && memcmp(alg_oid, hal_asn1_oid_ecPublicKey, alg_oid_len) == 0) {
+ *type = public ? HAL_KEY_TYPE_EC_PUBLIC : HAL_KEY_TYPE_EC_PRIVATE;
+ if ((err = hal_ecdsa_oid_to_curve(curve, curve_oid, curve_oid_len)) != HAL_OK)
+ *curve = HAL_CURVE_NONE;
+ return err;
+ }
+
+ *type = HAL_KEY_TYPE_NONE;
+ *curve = HAL_CURVE_NONE;
+ return HAL_ERROR_UNSUPPORTED_KEY;
+}
+
+/*
* Local variables:
* indent-tabs-mode: nil
* End: