diff options
author | Rob Austein <sra@hactrn.net> | 2017-04-03 01:41:35 -0400 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2017-04-03 01:41:35 -0400 |
commit | 33694de72d8a1c5714bea76ed70c755b5bb64a3e (patch) | |
tree | 0861e495196b7eff194eabd8c4b4c5401fdcc274 | |
parent | e36bfa86709e0823c2b1635afbac0bf68cb6c1cd (diff) |
PKCS #8 code for RSA and ECDSA.
Compiles, not yet tested. Existing tests need conversion to PKCS #8
before we can do anything useful with this.
Once everything uses PKCS #8 instead of algorithm-specific formats, we
can revisit API issues like whether hal_rpc_pkey_load() should still
be taking `type` and `curve` arguments.
-rw-r--r-- | asn1.c | 37 | ||||
-rw-r--r-- | asn1_internal.h | 14 | ||||
-rw-r--r-- | ecdsa.c | 164 | ||||
-rw-r--r-- | rsa.c | 54 |
4 files changed, 143 insertions, 126 deletions
@@ -58,6 +58,16 @@ #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); + +/* * Encode tag and length fields of an ASN.1 object. * * Sets *der_len to the size of of the ASN.1 header (tag and length @@ -556,8 +566,7 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size const uint8_t **privkey, size_t *privkey_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 || - privkey == NULL || privkey_len == NULL || der == NULL) + if (der == NULL) return HAL_ERROR_BAD_ARGUMENTS; const uint8_t * const der_end = der + der_len; @@ -591,12 +600,16 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size 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) { @@ -607,8 +620,10 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size 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; @@ -632,8 +647,10 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size d += hlen; if (vlen >= algid_end - d) return HAL_ERROR_ASN1_PARSE_FAILED; - *privkey = d; - *privkey_len = vlen; + if (privkey != NULL) + *privkey = d; + if (privkey_len != NULL) + *privkey_len = vlen; d += vlen; if (d != der_end) diff --git a/asn1_internal.h b/asn1_internal.h index 01ffc22..c337d4b 100644 --- a/asn1_internal.h +++ b/asn1_internal.h @@ -89,6 +89,20 @@ static inline uint8_t *unconst_uint8_t(const uint8_t * const arg) return (uint8_t *) arg; } +/* + * OIDs. + */ + +extern const uint8_t hal_asn1_oid_rsaEncryption[]; +extern const size_t hal_asn1_oid_rsaEncryption_len; + +extern const uint8_t hal_asn1_oid_ecPublicKey[]; +extern const size_t hal_asn1_oid_ecPublicKey_len; + +/* + * Transcoding functions. + */ + extern hal_error_t hal_asn1_encode_header(const uint8_t tag, const size_t value_len, uint8_t *der, size_t *der_len, const size_t der_max); @@ -833,44 +833,6 @@ static hal_error_t verilog_point_pick_random(const verilog_ecdsa_driver_t * cons #endif -static inline hal_error_t verilog_p256_point_pick_random(fp_int *k, ec_point_t *P) -{ -#if HAL_ECDSA_VERILOG_ECDSA256_MULTIPLIER - - static const verilog_ecdsa_driver_t p256_driver = { - .name = ECDSA256_NAME, - .bytes = ECDSA256_OPERAND_BITS / 8, - .k_addr = ECDSA256_ADDR_K, - .x_addr = ECDSA256_ADDR_X, - .y_addr = ECDSA256_ADDR_Y - }; - - return verilog_point_pick_random(&p256_driver, k, P); - -#endif - - return HAL_ERROR_CORE_NOT_FOUND; -} - -static inline hal_error_t verilog_p384_point_pick_random(fp_int *k, ec_point_t *P) -{ -#if HAL_ECDSA_VERILOG_ECDSA384_MULTIPLIER - - static const verilog_ecdsa_driver_t p384_driver = { - .name = ECDSA384_NAME, - .bytes = ECDSA384_OPERAND_BITS / 8, - .k_addr = ECDSA384_ADDR_K, - .x_addr = ECDSA384_ADDR_X, - .y_addr = ECDSA384_ADDR_Y - }; - - return verilog_point_pick_random(&p384_driver, k, P); - -#endif - - return HAL_ERROR_CORE_NOT_FOUND; -} - /* * Pick a random point on the curve, return random scalar and * resulting point. @@ -915,23 +877,39 @@ static hal_error_t point_pick_random(const ecdsa_curve_t * const curve, memset(k_buf, 0, sizeof(k_buf)); -#if HAL_ECDSA_VERILOG_ECDSA256_MULTIPLIER || HAL_ECDSA_VERILOG_ECDSA384_MULTIPLIER switch (curve->curve) { +#if HAL_ECDSA_VERILOG_ECDSA256_MULTIPLIER case HAL_CURVE_P256: - if ((err = verilog_p256_point_pick_random(k, P)) != HAL_ERROR_CORE_NOT_FOUND) + static const verilog_ecdsa_driver_t p256_driver = { + .name = ECDSA256_NAME, + .bytes = ECDSA256_OPERAND_BITS / 8, + .k_addr = ECDSA256_ADDR_K, + .x_addr = ECDSA256_ADDR_X, + .y_addr = ECDSA256_ADDR_Y + }; + if ((err = verilog_point_pick_random(&p256_driver, k, P)) != HAL_ERROR_CORE_NOT_FOUND) return err; - break; + break; +#endif +#if HAL_ECDSA_VERILOG_ECDSA384_MULTIPLIER case HAL_CURVE_P384: - if ((err = verilog_p384_point_pick_random(k, P)) != HAL_ERROR_CORE_NOT_FOUND) + static const verilog_ecdsa_driver_t p384_driver = { + .name = ECDSA384_NAME, + .bytes = ECDSA384_OPERAND_BITS / 8, + .k_addr = ECDSA384_ADDR_K, + .x_addr = ECDSA384_ADDR_X, + .y_addr = ECDSA384_ADDR_Y + }; + if ((err = verilog_point_pick_random(&p384_driver, k, P)) != HAL_ERROR_CORE_NOT_FOUND) return err; - break; + break; +#endif default: break; } -#endif /* * Calculate P = kG and return. @@ -1287,7 +1265,11 @@ hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_, } /* - * Write private key in RFC 5915 ASN.1 DER format. + * Write private key in PKCS #8 PrivateKeyInfo DER format (RFC 5208). + * This is basically just the PKCS #8 wrapper around the ECPrivateKey + * format from RFC 5915, except that the OID naming the curve is in + * the privateKeyAlgorithm.parameters field in the PKCS #8 wrapper and + * is therefore omitted from the ECPrivateKey. * * This is hand-coded, and is approaching the limit where one should * probably be using an ASN.1 compiler like asn1c instead. @@ -1314,27 +1296,29 @@ hal_error_t hal_ecdsa_private_key_to_der(const hal_ecdsa_key_t * const key, hal_error_t err; - size_t version_len, hlen, hlen_oct, hlen_oid, hlen_exp0, hlen_bit, hlen_exp1; + size_t version_len, hlen, hlen_oct, hlen_bit, hlen_exp1; if ((err = hal_asn1_encode_integer(version, NULL, &version_len, 0)) != HAL_OK || (err = hal_asn1_encode_header(ASN1_OCTET_STRING, q_len, NULL, &hlen_oct, 0)) != HAL_OK || - (err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, curve->oid_len, NULL, &hlen_oid, 0)) != HAL_OK || - (err = hal_asn1_encode_header(ASN1_EXPLICIT_0, hlen_oid + curve->oid_len, NULL, &hlen_exp0, 0)) != HAL_OK || (err = hal_asn1_encode_header(ASN1_BIT_STRING, (q_len + 1) * 2, NULL, &hlen_bit, 0)) != HAL_OK || (err = hal_asn1_encode_header(ASN1_EXPLICIT_1, hlen_bit + (q_len + 1) * 2, NULL, &hlen_exp1, 0)) != HAL_OK) return err; - const size_t vlen = (version_len + - hlen_oct + q_len + - hlen_oid + hlen_exp0 + curve->oid_len + - hlen_bit + hlen_exp1 + (q_len + 1) * 2); + const size_t vlen = version_len + hlen_oct + q_len + hlen_exp1 + hlen_bit + (q_len + 1) * 2; - err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max); + 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 ((err = hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_ecPublicKey, hal_asn1_oid_ecPublicKey_len, + curve->oid, curve->oid_len, + NULL, hlen + vlen, + NULL, der_len, der_max)) != HAL_OK) + return err; + + if (der == NULL) + return HAL_OK; - if (der == NULL || err != HAL_OK) + if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max)) != HAL_OK) return err; uint8_t *d = der + hlen; @@ -1350,15 +1334,6 @@ hal_error_t hal_ecdsa_private_key_to_der(const hal_ecdsa_key_t * const key, fp_to_unsigned_bin(unconst_fp_int(key->d), d + q_len - d_len); d += q_len; - if ((err = hal_asn1_encode_header(ASN1_EXPLICIT_0, hlen_oid + curve->oid_len, d, &hlen, der + der_max - d)) != HAL_OK) - return err; - d += hlen; - if ((err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, curve->oid_len, d, &hlen, der + der_max - d)) != HAL_OK) - return err; - d += hlen; - memcpy(d, curve->oid, curve->oid_len); - d += curve->oid_len; - if ((err = hal_asn1_encode_header(ASN1_EXPLICIT_1, hlen_bit + (q_len + 1) * 2, d, &hlen, der + der_max - d)) != HAL_OK) return err; d += hlen; @@ -1372,9 +1347,10 @@ hal_error_t hal_ecdsa_private_key_to_der(const hal_ecdsa_key_t * const key, fp_to_unsigned_bin(unconst_fp_int(key->Q->y), d + q_len - Qy_len); d += q_len; - assert(d <= der + der_max); - - return HAL_OK; + return hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_ecPublicKey, hal_asn1_oid_ecPublicKey_len, + curve->oid, curve->oid_len, + der, d - der, + der, der_len, der_max); } /* @@ -1389,7 +1365,7 @@ size_t hal_ecdsa_private_key_to_der_len(const hal_ecdsa_key_t * const key) } /* - * Read private key in RFC 5915 ASN.1 DER format. + * Read private key in PKCS #8 PrivateKeyInfo DER format (RFC 5208, RFC 5915). * * This is hand-coded, and is approaching the limit where one should * probably be using an ASN.1 compiler like asn1c instead. @@ -1407,48 +1383,47 @@ hal_error_t hal_ecdsa_private_key_from_der(hal_ecdsa_key_t **key_, memset(keybuf, 0, keybuf_len); key->type = HAL_KEY_TYPE_EC_PRIVATE; - size_t hlen, vlen; + size_t hlen, vlen, alg_oid_len, curve_oid_len, privkey_len; + const uint8_t *alg_oid, *curve_oid, *privkey; hal_error_t err; - if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, der, der_len, &hlen, &vlen)) != HAL_OK) + if ((err = hal_asn1_decode_pkcs8_privatekeyinfo(&alg_oid, &alg_oid_len, + &curve_oid, &curve_oid_len, + &privkey, &privkey_len, + der, der_len)) != HAL_OK) return err; - const uint8_t * const der_end = der + hlen + vlen; - const uint8_t *d = der + hlen; - const ecdsa_curve_t *curve = NULL; + if (alg_oid_len != hal_asn1_oid_ecPublicKey_len || + memcmp(alg_oid, hal_asn1_oid_ecPublicKey, alg_oid_len) != 0 || + oid_to_curve(&key->curve, curve_oid, curve_oid_len) == NULL) + return HAL_ERROR_ASN1_PARSE_FAILED; + + if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, privkey, privkey_len, &hlen, &vlen)) != HAL_OK) + return err; + + const uint8_t * const der_end = privkey + hlen + vlen; + const uint8_t *d = privkey + hlen; fp_int version[1] = INIT_FP_INT; if ((err = hal_asn1_decode_integer(version, d, &hlen, vlen)) != HAL_OK) - goto fail; + return err; if (fp_cmp_d(version, 1) != FP_EQ) - lose(HAL_ERROR_ASN1_PARSE_FAILED); + return HAL_ERROR_ASN1_PARSE_FAILED; d += hlen; if ((err = hal_asn1_decode_header(ASN1_OCTET_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK) - return err; + goto fail; d += hlen; fp_read_unsigned_bin(key->d, unconst_uint8_t(d), vlen); d += vlen; - if ((err = hal_asn1_decode_header(ASN1_EXPLICIT_0, d, der_end - d, &hlen, &vlen)) != HAL_OK) - return err; - d += hlen; - if (vlen > der_end - d) - lose(HAL_ERROR_ASN1_PARSE_FAILED); - if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, vlen, &hlen, &vlen)) != HAL_OK) - return err; - d += hlen; - if ((curve = oid_to_curve(&key->curve, d, vlen)) == NULL) - lose(HAL_ERROR_ASN1_PARSE_FAILED); - d += vlen; - if ((err = hal_asn1_decode_header(ASN1_EXPLICIT_1, d, der_end - d, &hlen, &vlen)) != HAL_OK) - return err; + goto fail; d += hlen; if (vlen > der_end - d) lose(HAL_ERROR_ASN1_PARSE_FAILED); if ((err = hal_asn1_decode_header(ASN1_BIT_STRING, d, vlen, &hlen, &vlen)) != HAL_OK) - return err; + goto fail; d += hlen; if (vlen < 4 || (vlen & 1) != 0 || *d++ != 0x00 || *d++ != 0x04) lose(HAL_ERROR_ASN1_PARSE_FAILED); @@ -1474,8 +1449,6 @@ hal_error_t hal_ecdsa_private_key_from_der(hal_ecdsa_key_t **key_, * Write public key in SubjectPublicKeyInfo format, see RFCS 5280 and 5480. */ -static const uint8_t oid_ecPublicKey[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }; - hal_error_t hal_ecdsa_public_key_to_der(const hal_ecdsa_key_t * const key, uint8_t *der, size_t *der_len, const size_t der_max) { @@ -1508,7 +1481,7 @@ hal_error_t hal_ecdsa_public_key_to_der(const hal_ecdsa_key_t * const key, assert(d < der + der_max); } - return hal_asn1_encode_spki(oid_ecPublicKey, sizeof(oid_ecPublicKey), + return hal_asn1_encode_spki(hal_asn1_oid_ecPublicKey, hal_asn1_oid_ecPublicKey_len, curve->oid, curve->oid_len, der, ecpoint_len, der, der_len, der_max); @@ -1551,7 +1524,8 @@ hal_error_t hal_ecdsa_public_key_from_der(hal_ecdsa_key_t **key_, return err; if (alg_oid == NULL || curve_oid == NULL || pubkey == NULL || - alg_oid_len != sizeof(oid_ecPublicKey) || memcmp(alg_oid, oid_ecPublicKey, alg_oid_len) != 0 || + alg_oid_len != hal_asn1_oid_ecPublicKey_len || + memcmp(alg_oid, hal_asn1_oid_ecPublicKey, alg_oid_len) != 0 || (curve = oid_to_curve(&key->curve, curve_oid, curve_oid_len)) == NULL || pubkey_len < 3 || (pubkey_len & 1) == 0 || pubkey[0] != 0x04 || pubkey_len / 2 != fp_unsigned_bin_size(unconst_fp_int(curve->q))) @@ -673,7 +673,7 @@ hal_error_t hal_rsa_key_gen(const hal_core_t *core, /* * Just enough ASN.1 to read and write PKCS #1.5 RSAPrivateKey syntax - * (RFC 2313 section 7.2). + * (RFC 2313 section 7.2) wrapped in a PKCS #8 PrivateKeyInfo (RFC 5208). * * RSAPrivateKey fields in the required order. */ @@ -709,15 +709,12 @@ hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key, RSAPrivateKey_fields; #undef _ - /* - * Encode header. - */ - - if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max)) != HAL_OK) + 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 ((err = hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_rsaEncryption, hal_asn1_oid_rsaEncryption_len, + NULL, 0, NULL, hlen + vlen, NULL, der_len, der_max)) != HAL_OK) + return err; if (der == NULL) return HAL_OK; @@ -726,13 +723,18 @@ hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key, * Encode data. */ - der += hlen; + if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max)) != HAL_OK) + return err; -#define _(x) { size_t n; if ((err = hal_asn1_encode_integer(x, der, &n, vlen)) != HAL_OK) return err; der += n; vlen -= n; } + uint8_t *d = der + hlen; + memset(d, 0, vlen); + +#define _(x) { size_t n; if ((err = hal_asn1_encode_integer(x, d, &n, vlen)) != HAL_OK) return err; d += n; vlen -= n; } RSAPrivateKey_fields; #undef _ - return HAL_OK; + return hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_rsaEncryption, hal_asn1_oid_rsaEncryption_len, + NULL, 0, der, d - der, der, der_len, der_max); } size_t hal_rsa_private_key_to_der_len(const hal_rsa_key_t * const key) @@ -754,21 +756,33 @@ hal_error_t hal_rsa_private_key_from_der(hal_rsa_key_t **key_, key->type = HAL_KEY_TYPE_RSA_PRIVATE; - hal_error_t err = HAL_OK; - size_t hlen, vlen; + size_t hlen, vlen, alg_oid_len, curve_oid_len, privkey_len; + const uint8_t *alg_oid, *curve_oid, *privkey; + hal_error_t err; - if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, der, der_len, &hlen, &vlen)) != HAL_OK) + if ((err = hal_asn1_decode_pkcs8_privatekeyinfo(&alg_oid, &alg_oid_len, + &curve_oid, &curve_oid_len, + &privkey, &privkey_len, + der, der_len)) != HAL_OK) return err; - der += hlen; + if (alg_oid_len != hal_asn1_oid_rsaEncryption_len || + memcmp(alg_oid, hal_asn1_oid_rsaEncryption, alg_oid_len) != 0 || + curve_oid_len != 0) + return HAL_ERROR_ASN1_PARSE_FAILED; + + if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, privkey, privkey_len, &hlen, &vlen)) != HAL_OK) + return err; + + const uint8_t *d = privkey + hlen; fp_int version[1] = INIT_FP_INT; -#define _(x) { size_t i; if ((err = hal_asn1_decode_integer(x, der, &i, vlen)) != HAL_OK) return err; der += i; vlen -= i; } +#define _(x) { size_t n; if ((err = hal_asn1_decode_integer(x, d, &n, vlen)) != HAL_OK) return err; d += n; vlen -= n; } RSAPrivateKey_fields; #undef _ - if (fp_cmp_d(version, 0) != FP_EQ) + if (d != privkey + privkey_len || !fp_iszero(version)) return HAL_ERROR_ASN1_PARSE_FAILED; *key_ = key; @@ -780,8 +794,6 @@ 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) { @@ -810,7 +822,7 @@ hal_error_t hal_rsa_public_key_to_der(const hal_rsa_key_t * const key, return err; } - return hal_asn1_encode_spki(oid_rsaEncryption, sizeof(oid_rsaEncryption), + return hal_asn1_encode_spki(hal_asn1_oid_rsaEncryption, hal_asn1_oid_rsaEncryption_len, NULL, 0, der, hlen + vlen, der, der_len, der_max); @@ -843,7 +855,7 @@ hal_error_t hal_rsa_public_key_from_der(hal_rsa_key_t **key_, 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) + alg_oid_len != hal_asn1_oid_rsaEncryption_len || memcmp(alg_oid, hal_asn1_oid_rsaEncryption, alg_oid_len) != 0) return HAL_ERROR_ASN1_PARSE_FAILED; size_t len, hlen, vlen; |