From 5119e71023fdca0b867d79be677142296d9f2e47 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Fri, 24 May 2019 11:42:48 +0200 Subject: [PATCH 1/4] add x509_decode_public_key_from_certificate() --- src/headers/tomcrypt_private.h | 7 ++ .../x509_decode_public_key_from_certificate.c | 114 ++++++++++++++++++ .../x509_decode_subject_public_key_info.c | 20 +-- 3 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 src/pk/asn1/x509/x509_decode_public_key_from_certificate.c diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h index e536d579..0d4842e4 100644 --- a/src/headers/tomcrypt_private.h +++ b/src/headers/tomcrypt_private.h @@ -330,6 +330,13 @@ int der_teletex_value_decode(int v); int der_utf8_valid_char(const wchar_t c); +typedef int (*public_key_decode_cb)(const unsigned char *in, unsigned long inlen, void *ctx); + +int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen, + enum ltc_oid_id algorithm, ltc_asn1_type param_type, + ltc_asn1_list* parameters, unsigned long *parameters_len, + public_key_decode_cb callback, void *ctx); + /* SUBJECT PUBLIC KEY INFO */ int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen, unsigned int algorithm, const void* public_key, unsigned long public_key_len, diff --git a/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c b/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c new file mode 100644 index 00000000..620c129f --- /dev/null +++ b/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c @@ -0,0 +1,114 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + */ +#include "tomcrypt_private.h" + +/** + @file x509_decode_public_key_from_certificate.c + ASN.1 DER/X.509, decode a certificate +*/ + +#ifdef LTC_DER + +/* Check if it looks like a SubjectPublicKeyInfo */ +#define LOOKS_LIKE_SPKI(l) ((l) != NULL) \ +&& ((l)->type == LTC_ASN1_SEQUENCE) \ +&& ((l)->child != NULL) \ +&& ((l)->child->type == LTC_ASN1_OBJECT_IDENTIFIER) \ +&& ((l)->next != NULL) \ +&& ((l)->next->type == LTC_ASN1_BIT_STRING) + +/** + Try to decode the public key from a X.509 certificate + @param in The input buffer + @param inlen The length of the input buffer + @param algorithm One out of the enum #public_key_algorithms + @param param_type The parameters' type out of the enum ltc_asn1_type + @param parameters The parameters to include + @param parameters_len [in/out] The number of parameters to include + @param callback The callback + @param ctx The context passed to the callback + @return CRYPT_OK on success +*/ +int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen, + enum ltc_oid_id algorithm, ltc_asn1_type param_type, + ltc_asn1_list* parameters, unsigned long *parameters_len, + public_key_decode_cb callback, void *ctx) +{ + int err; + unsigned char *tmpbuf; + unsigned long tmpbuf_len, tmp_inlen; + ltc_asn1_list *decoded_list = NULL, *l; + + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(inlen != 0); + + tmpbuf_len = inlen; + tmpbuf = XCALLOC(1, tmpbuf_len); + if (tmpbuf == NULL) { + err = CRYPT_MEM; + goto LBL_OUT; + } + + tmp_inlen = inlen; + if ((err = der_decode_sequence_flexi(in, &tmp_inlen, &decoded_list)) == CRYPT_OK) { + l = decoded_list; + + err = CRYPT_INVALID_ARG; + + /* Move 2 levels up in the tree + SEQUENCE + SEQUENCE + ... + */ + if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) { + l = l->child; + if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) { + l = l->child; + + /* Move forward in the tree until we find this combination + ... + SEQUENCE + SEQUENCE + OBJECT IDENTIFIER + NULL + BIT STRING + */ + do { + /* The additional check for l->data is there to make sure + * we won't try to decode a list that has been 'shrunk' + */ + if ((l->type == LTC_ASN1_SEQUENCE) + && (l->data != NULL) + && LOOKS_LIKE_SPKI(l->child)) { + err = x509_decode_subject_public_key_info(l->data, l->size, + algorithm, tmpbuf, &tmpbuf_len, + param_type, parameters, parameters_len); + if (err == CRYPT_OK) { + err = callback(tmpbuf, tmpbuf_len, ctx); + goto LBL_OUT; + } + } + l = l->next; + } while(l); + } + } + } + +LBL_OUT: + if (decoded_list) der_free_sequence_flexi(decoded_list); + if (tmpbuf != NULL) XFREE(tmpbuf); + + return err; +} + +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/src/pk/asn1/x509/x509_decode_subject_public_key_info.c b/src/pk/asn1/x509/x509_decode_subject_public_key_info.c index bd84e7c7..2d851b56 100644 --- a/src/pk/asn1/x509/x509_decode_subject_public_key_info.c +++ b/src/pk/asn1/x509/x509_decode_subject_public_key_info.c @@ -34,7 +34,7 @@ @param public_key_len [in/out] The length of the public key buffer and the written length @param parameters_type The parameters' type out of the enum ltc_asn1_type @param parameters The parameters to include - @param parameters_len [in/out]The number of parameters to include + @param parameters_len [in/out] The number of parameters to include @return CRYPT_OK on success */ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen, @@ -42,18 +42,25 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len) { int err; - unsigned long len, alg_id_num; + unsigned long len, alg_id_num, tmplen; const char* oid; unsigned char *tmpbuf; unsigned long tmpoid[16]; + unsigned long *_parameters_len; ltc_asn1_list alg_id[2]; ltc_asn1_list subject_pubkey[2]; LTC_ARGCHK(in != NULL); LTC_ARGCHK(inlen != 0); LTC_ARGCHK(public_key_len != NULL); + if (parameters_type != LTC_ASN1_EOL) { - LTC_ARGCHK(parameters_len != NULL); + if ((parameters == NULL) || (parameters_len == NULL)) { + tmplen = 0; + _parameters_len = &tmplen; + } else { + _parameters_len = parameters_len; + } } err = pk_get_oid(algorithm, &oid); @@ -72,9 +79,8 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0])); if (parameters_type == LTC_ASN1_EOL) { alg_id_num = 1; - } - else { - LTC_SET_ASN1(alg_id, 1, parameters_type, parameters, *parameters_len); + } else { + LTC_SET_ASN1(alg_id, 1, parameters_type, parameters, *_parameters_len); alg_id_num = 2; } @@ -89,7 +95,7 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i goto LBL_ERR; } if (parameters_type != LTC_ASN1_EOL) { - *parameters_len = alg_id[1].size; + *_parameters_len = alg_id[1].size; } if ((err = pk_oid_cmp_with_asn1(oid, &alg_id[0])) != CRYPT_OK) { From dfa5258db5a8971de059af8d16d3e63de72727d1 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 23 May 2019 16:31:05 +0200 Subject: [PATCH 2/4] update rsa_import_x509() --- src/pk/rsa/rsa_import_x509.c | 86 +++++++----------------------------- 1 file changed, 16 insertions(+), 70 deletions(-) diff --git a/src/pk/rsa/rsa_import_x509.c b/src/pk/rsa/rsa_import_x509.c index c615b772..5220ae38 100644 --- a/src/pk/rsa/rsa_import_x509.c +++ b/src/pk/rsa/rsa_import_x509.c @@ -15,6 +15,15 @@ #ifdef LTC_MRSA +static int _rsa_decode(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + /* now it should be SEQUENCE { INTEGER, INTEGER } */ + return der_decode_sequence_multi(in, inlen, + LTC_ASN1_INTEGER, 1UL, key->N, + LTC_ASN1_INTEGER, 1UL, key->e, + LTC_ASN1_EOL, 0UL, NULL); +} + /** Import an RSA key from a X.509 certificate @param in The packet to import from @@ -25,9 +34,6 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) { int err; - unsigned char *tmpbuf; - unsigned long tmpbuf_len, tmp_inlen, len; - ltc_asn1_list *decoded_list = NULL, *l; LTC_ARGCHK(in != NULL); LTC_ARGCHK(key != NULL); @@ -39,75 +45,15 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) return err; } - tmpbuf_len = inlen; - tmpbuf = XCALLOC(1, tmpbuf_len); - if (tmpbuf == NULL) { - err = CRYPT_MEM; - goto LBL_ERR; + if ((err = x509_decode_public_key_from_certificate(in, inlen, + PKA_RSA, LTC_ASN1_NULL, + NULL, NULL, + (public_key_decode_cb)_rsa_decode, key)) != CRYPT_OK) { + rsa_free(key); + } else { + key->type = PK_PUBLIC; } - tmp_inlen = inlen; - if ((err = der_decode_sequence_flexi(in, &tmp_inlen, &decoded_list)) == CRYPT_OK) { - l = decoded_list; - /* Move 2 levels up in the tree - SEQUENCE - SEQUENCE - ... - */ - if (l->type == LTC_ASN1_SEQUENCE && l->child) { - l = l->child; - if (l->type == LTC_ASN1_SEQUENCE && l->child) { - l = l->child; - - err = CRYPT_ERROR; - - /* Move forward in the tree until we find this combination - ... - SEQUENCE - SEQUENCE - OBJECT IDENTIFIER 1.2.840.113549.1.1.1 - NULL - BIT STRING - */ - do { - /* The additional check for l->data is there to make sure - * we won't try to decode a list that has been 'shrunk' - */ - if (l->type == LTC_ASN1_SEQUENCE && l->data && l->child && - l->child->type == LTC_ASN1_SEQUENCE && l->child->child && - l->child->child->type == LTC_ASN1_OBJECT_IDENTIFIER && l->child->next && - l->child->next->type == LTC_ASN1_BIT_STRING) { - len = 0; - err = x509_decode_subject_public_key_info(l->data, l->size, - PKA_RSA, tmpbuf, &tmpbuf_len, - LTC_ASN1_NULL, NULL, &len); - if (err == CRYPT_OK) { - /* now it should be SEQUENCE { INTEGER, INTEGER } */ - if ((err = der_decode_sequence_multi(tmpbuf, tmpbuf_len, - LTC_ASN1_INTEGER, 1UL, key->N, - LTC_ASN1_INTEGER, 1UL, key->e, - LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { - goto LBL_ERR; - } - key->type = PK_PUBLIC; - err = CRYPT_OK; - goto LBL_FREE; - } - } - l = l->next; - } while(l); - } - } - } - - -LBL_ERR: - rsa_free(key); - -LBL_FREE: - if (decoded_list) der_free_sequence_flexi(decoded_list); - if (tmpbuf != NULL) XFREE(tmpbuf); - return err; } From 21fa9cd92ef41023a7486092cff57ad49b8b726e Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Fri, 24 May 2019 12:01:32 +0200 Subject: [PATCH 3/4] Update makefiles --- libtomcrypt_VS2008.vcproj | 4 ++++ makefile.mingw | 3 ++- makefile.msvc | 3 ++- makefile.unix | 3 ++- makefile_include.mk | 3 ++- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj index a0b5ddfc..244eb2af 100644 --- a/libtomcrypt_VS2008.vcproj +++ b/libtomcrypt_VS2008.vcproj @@ -2193,6 +2193,10 @@ + + diff --git a/makefile.mingw b/makefile.mingw index 04296fc4..aa3e7178 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -170,7 +170,8 @@ src/pk/asn1/der/utctime/der_decode_utctime.o src/pk/asn1/der/utctime/der_encode_ src/pk/asn1/der/utctime/der_length_utctime.o src/pk/asn1/der/utf8/der_decode_utf8_string.o \ src/pk/asn1/der/utf8/der_encode_utf8_string.o src/pk/asn1/der/utf8/der_length_utf8_string.o \ src/pk/asn1/oid/pk_get_oid.o src/pk/asn1/oid/pk_oid_cmp.o src/pk/asn1/oid/pk_oid_str.o \ -src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/x509/x509_decode_subject_public_key_info.o \ +src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/x509/x509_decode_public_key_from_certificate.o \ +src/pk/asn1/x509/x509_decode_subject_public_key_info.o \ src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o \ src/pk/dh/dh_export.o src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o \ src/pk/dh/dh_import.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o src/pk/dh/dh_shared_secret.o \ diff --git a/makefile.msvc b/makefile.msvc index b9bb484f..5f887ae5 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -163,7 +163,8 @@ src/pk/asn1/der/utctime/der_decode_utctime.obj src/pk/asn1/der/utctime/der_encod src/pk/asn1/der/utctime/der_length_utctime.obj src/pk/asn1/der/utf8/der_decode_utf8_string.obj \ src/pk/asn1/der/utf8/der_encode_utf8_string.obj src/pk/asn1/der/utf8/der_length_utf8_string.obj \ src/pk/asn1/oid/pk_get_oid.obj src/pk/asn1/oid/pk_oid_cmp.obj src/pk/asn1/oid/pk_oid_str.obj \ -src/pk/asn1/pkcs8/pkcs8_decode_flexi.obj src/pk/asn1/x509/x509_decode_subject_public_key_info.obj \ +src/pk/asn1/pkcs8/pkcs8_decode_flexi.obj src/pk/asn1/x509/x509_decode_public_key_from_certificate.obj \ +src/pk/asn1/x509/x509_decode_subject_public_key_info.obj \ src/pk/asn1/x509/x509_encode_subject_public_key_info.obj src/pk/dh/dh.obj src/pk/dh/dh_check_pubkey.obj \ src/pk/dh/dh_export.obj src/pk/dh/dh_export_key.obj src/pk/dh/dh_free.obj src/pk/dh/dh_generate_key.obj \ src/pk/dh/dh_import.obj src/pk/dh/dh_set.obj src/pk/dh/dh_set_pg_dhparam.obj src/pk/dh/dh_shared_secret.obj \ diff --git a/makefile.unix b/makefile.unix index b0a57b67..3e39896c 100644 --- a/makefile.unix +++ b/makefile.unix @@ -180,7 +180,8 @@ src/pk/asn1/der/utctime/der_decode_utctime.o src/pk/asn1/der/utctime/der_encode_ src/pk/asn1/der/utctime/der_length_utctime.o src/pk/asn1/der/utf8/der_decode_utf8_string.o \ src/pk/asn1/der/utf8/der_encode_utf8_string.o src/pk/asn1/der/utf8/der_length_utf8_string.o \ src/pk/asn1/oid/pk_get_oid.o src/pk/asn1/oid/pk_oid_cmp.o src/pk/asn1/oid/pk_oid_str.o \ -src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/x509/x509_decode_subject_public_key_info.o \ +src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/x509/x509_decode_public_key_from_certificate.o \ +src/pk/asn1/x509/x509_decode_subject_public_key_info.o \ src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o \ src/pk/dh/dh_export.o src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o \ src/pk/dh/dh_import.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o src/pk/dh/dh_shared_secret.o \ diff --git a/makefile_include.mk b/makefile_include.mk index 791d5cc3..d034ebea 100644 --- a/makefile_include.mk +++ b/makefile_include.mk @@ -340,7 +340,8 @@ src/pk/asn1/der/utctime/der_decode_utctime.o src/pk/asn1/der/utctime/der_encode_ src/pk/asn1/der/utctime/der_length_utctime.o src/pk/asn1/der/utf8/der_decode_utf8_string.o \ src/pk/asn1/der/utf8/der_encode_utf8_string.o src/pk/asn1/der/utf8/der_length_utf8_string.o \ src/pk/asn1/oid/pk_get_oid.o src/pk/asn1/oid/pk_oid_cmp.o src/pk/asn1/oid/pk_oid_str.o \ -src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/x509/x509_decode_subject_public_key_info.o \ +src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/x509/x509_decode_public_key_from_certificate.o \ +src/pk/asn1/x509/x509_decode_subject_public_key_info.o \ src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o \ src/pk/dh/dh_export.o src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o \ src/pk/dh/dh_import.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o src/pk/dh/dh_shared_secret.o \ From f6299995f898a85d6ab9f6d0f1cdab9b1978e06f Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Sun, 26 May 2019 02:09:12 +0200 Subject: [PATCH 4/4] update ecc_import_x509() --- .../x509_decode_public_key_from_certificate.c | 20 +++++++----- src/pk/ecc/ecc_import_x509.c | 31 +------------------ 2 files changed, 13 insertions(+), 38 deletions(-) diff --git a/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c b/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c index 620c129f..02b62ae8 100644 --- a/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c +++ b/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c @@ -33,7 +33,7 @@ @param parameters_len [in/out] The number of parameters to include @param callback The callback @param ctx The context passed to the callback - @return CRYPT_OK on success + @return CRYPT_OK on success, CRYPT_NOP if no SubjectPublicKeyInfo was found */ int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen, enum ltc_oid_id algorithm, ltc_asn1_type param_type, @@ -59,7 +59,7 @@ int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned lo if ((err = der_decode_sequence_flexi(in, &tmp_inlen, &decoded_list)) == CRYPT_OK) { l = decoded_list; - err = CRYPT_INVALID_ARG; + err = CRYPT_NOP; /* Move 2 levels up in the tree SEQUENCE @@ -86,12 +86,16 @@ int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned lo if ((l->type == LTC_ASN1_SEQUENCE) && (l->data != NULL) && LOOKS_LIKE_SPKI(l->child)) { - err = x509_decode_subject_public_key_info(l->data, l->size, - algorithm, tmpbuf, &tmpbuf_len, - param_type, parameters, parameters_len); - if (err == CRYPT_OK) { - err = callback(tmpbuf, tmpbuf_len, ctx); - goto LBL_OUT; + if (algorithm == PKA_EC) { + err = ecc_import_subject_public_key_info(l->data, l->size, ctx); + } else { + err = x509_decode_subject_public_key_info(l->data, l->size, + algorithm, tmpbuf, &tmpbuf_len, + param_type, parameters, parameters_len); + if (err == CRYPT_OK) { + err = callback(tmpbuf, tmpbuf_len, ctx); + goto LBL_OUT; + } } } l = l->next; diff --git a/src/pk/ecc/ecc_import_x509.c b/src/pk/ecc/ecc_import_x509.c index 99a27507..61ee8621 100644 --- a/src/pk/ecc/ecc_import_x509.c +++ b/src/pk/ecc/ecc_import_x509.c @@ -112,36 +112,7 @@ success: */ int ecc_import_x509(const unsigned char *in, unsigned long inlen, ecc_key *key) { - int err; - unsigned long len; - ltc_asn1_list *decoded_list = NULL, *l; - - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(key != NULL); - - len = inlen; - if ((err = der_decode_sequence_flexi(in, &len, &decoded_list)) == CRYPT_OK) { - err = CRYPT_ERROR; - l = decoded_list; - if (l->type == LTC_ASN1_SEQUENCE && - l->child && l->child->type == LTC_ASN1_SEQUENCE) { - l = l->child->child; - while (l) { - if (l->type == LTC_ASN1_SEQUENCE && l->data && - l->child && l->child->type == LTC_ASN1_SEQUENCE && - l->child->child && l->child->child->type == LTC_ASN1_OBJECT_IDENTIFIER && - l->child->next && l->child->next->type == LTC_ASN1_BIT_STRING) { - err = ecc_import_subject_public_key_info(l->data, l->size, key); - goto LBL_DONE; - } - l = l->next; - } - } - } - -LBL_DONE: - if (decoded_list) der_free_sequence_flexi(decoded_list); - return err; + return x509_decode_public_key_from_certificate(in, inlen, PKA_EC, LTC_ASN1_EOL, NULL, NULL, NULL, key); } #endif /* LTC_MECC */