diff options
author | Rob Austein <sra@hactrn.net> | 2015-12-22 18:55:11 -0500 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2015-12-22 18:55:11 -0500 |
commit | 17da006ef0dcb18bf8da6ab6b90446c43a10c790 (patch) | |
tree | f6cef3ed996b6e452e18bfc2c1af350e3434185d /rsa.c | |
parent | 36f9b6627d41f72af38be1d819f37c20a11f43c5 (diff) |
Add ASN.1 support for public keys (X.509 SubjectPublicKeyInfo format).
Diffstat (limited to 'rsa.c')
-rw-r--r-- | rsa.c | 96 |
1 files changed, 95 insertions, 1 deletions
@@ -733,7 +733,7 @@ hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key, return HAL_OK; } -size_t hal_rsa_key_to_der_len(const hal_rsa_key_t * const key) +size_t hal_rsa_private_key_to_der_len(const hal_rsa_key_t * const key) { size_t len = 0; return hal_rsa_private_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0; @@ -775,6 +775,100 @@ hal_error_t hal_rsa_private_key_from_der(hal_rsa_key_t **key_, } /* + * ASN.1 public keys in SubjectPublicKeyInfo form, see RFCs 2313, 4055, and 5280. + */ + +static const uint8_t oid_rsaEncryption[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }; + +hal_error_t hal_rsa_public_key_to_der(const hal_rsa_key_t * const key, + uint8_t *der, size_t *der_len, const size_t der_max) +{ + if (key == NULL || (key->type != HAL_KEY_TYPE_RSA_PRIVATE && + key->type != HAL_KEY_TYPE_RSA_PUBLIC)) + return HAL_ERROR_BAD_ARGUMENTS; + + size_t hlen, n_len, e_len; + hal_error_t err; + + if ((err = hal_asn1_encode_integer(key->n, NULL, &n_len, 0)) != HAL_OK || + (err = hal_asn1_encode_integer(key->e, NULL, &e_len, 0)) != HAL_OK) + return err; + + const size_t vlen = n_len + e_len; + + if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max)) != HAL_OK) + return err; + + if (der != NULL) { + uint8_t * const n_out = der + hlen; + uint8_t * const e_out = n_out + n_len; + + if ((err = hal_asn1_encode_integer(key->n, n_out, NULL, der + der_max - n_out)) != HAL_OK || + (err = hal_asn1_encode_integer(key->e, e_out, NULL, der + der_max - e_out)) != HAL_OK) + return err; + } + + return hal_asn1_encode_spki(oid_rsaEncryption, sizeof(oid_rsaEncryption), + NULL, 0, der, hlen + vlen, + der, der_len, der_max); + +} + +size_t hal_rsa_public_key_to_der_len(const hal_rsa_key_t * const key) +{ + size_t len = 0; + return hal_rsa_public_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0; +} + +hal_error_t hal_rsa_public_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) +{ + hal_rsa_key_t *key = keybuf; + + if (key_ == NULL || key == NULL || keybuf_len < sizeof(*key) || der == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + memset(keybuf, 0, keybuf_len); + + key->type = HAL_KEY_TYPE_RSA_PUBLIC; + + const uint8_t *alg_oid = NULL, *null = NULL, *pubkey = NULL; + size_t alg_oid_len, null_len, pubkey_len; + hal_error_t err; + + if ((err = hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &null, &null_len, &pubkey, &pubkey_len, der, der_len)) != HAL_OK) + return err; + + if (null != NULL || null_len != 0 || alg_oid == NULL || + alg_oid_len != sizeof(oid_rsaEncryption) || memcmp(alg_oid, oid_rsaEncryption, alg_oid_len) != 0) + return HAL_ERROR_ASN1_PARSE_FAILED; + + size_t len, hlen, vlen; + + if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, pubkey, pubkey_len, &hlen, &vlen)) != HAL_OK) + return err; + + const uint8_t * const pubkey_end = pubkey + hlen + vlen; + const uint8_t *d = pubkey + hlen; + + if ((err = hal_asn1_decode_integer(key->n, d, &len, pubkey_end - d)) != HAL_OK) + return err; + d += len; + + if ((err = hal_asn1_decode_integer(key->e, d, &len, pubkey_end - d)) != HAL_OK) + return err; + d += len; + + if (d != pubkey_end) + return HAL_ERROR_ASN1_PARSE_FAILED; + + *key_ = key; + + return HAL_OK; +} + +/* * Local variables: * indent-tabs-mode: nil * End: |