diff --git a/.ci/coverage_more.sh b/.ci/coverage_more.sh index c0681275b..40fbe4cea 100755 --- a/.ci/coverage_more.sh +++ b/.ci/coverage_more.sh @@ -2,14 +2,26 @@ set -e +function pdiv() { + printf "\n====== %s ======\n" "$*" +} + if [ "$#" = "1" -a "$(echo $1 | grep 'gmp')" != "" ]; then + pdiv "Test GMP" ./test t gmp fi +pdiv "Sizes" ./sizes +pdiv "Constants" ./constants -for i in $(for j in $(echo $(./hashsum -h | awk '/Algorithms/,EOF' | tail -n +2)); do echo $j; done | sort); do echo -n "$i: " && ./hashsum -a $i tests/test.key ; done > hashsum_tv.txt +pdiv "Generate hashsum_tv.txt" +for i in $(for j in $(echo $(./hashsum -h | awk '/Algorithms/,EOF' | tail -n +2)); do echo $j; done | sort); do + echo -n "$i: " && ./hashsum -a $i tests/test.key +done > hashsum_tv.txt + +pdiv "Compare hashsum_tv.txt" difftroubles=$(diff -i -w -B hashsum_tv.txt notes/hashsum_tv.txt | grep '^<') || true if [ -n "$difftroubles" ]; then echo "FAILURE: hashsum_tv.tx" diff --git a/.gitignore b/.gitignore index a57d76466..1b22e33d8 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,8 @@ constants constants.exe crypt crypt.exe +der_print_flexi +der_print_flexi.exe hashsum hashsum.exe multi @@ -107,7 +109,7 @@ doxygen/ *.lof *.bak -coverage/ +coverage*/ coverage*.info # coverity intermediate directory etc. diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 6450935a1..4ef462c15 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -28,7 +28,7 @@ endif() # # Demos that are usable but only rarely make sense to be installed # -# USEABLE_DEMOS = aesgcm constants crypt openssh-privkey openssl-enc pem-info sizes timing +# USEABLE_DEMOS = aesgcm constants crypt der_print_flexi openssh-privkey openssl-enc pem-info sizes timing # ----------------------------------------------------------------------------- if(BUILD_USABLE_DEMOS) @@ -38,6 +38,7 @@ if(BUILD_USABLE_DEMOS) aesgcm constants crypt + der_print_flexi openssh-privkey openssl-enc pem-info diff --git a/demos/der_print_flexi.c b/demos/der_print_flexi.c new file mode 100644 index 000000000..392e98bf2 --- /dev/null +++ b/demos/der_print_flexi.c @@ -0,0 +1,327 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ +/* DER flexi-decode a certificate */ +#include "tomcrypt_private.h" +#include + +#define ASN1_FMTSTRING_FMT "line: %d, type=%d, size=%lu, data=%p, self=%p, next=%p, prev=%p, parent=%p, child=%p" +#define ASN1_FMTSTRING_VAL(l) __LINE__, (l)->type, (l)->size, (l)->data, (l), (l)->next, (l)->prev, (l)->parent, (l)->child + +static void* s_xmalloc(int l) +{ + void *r = XCALLOC(1, l); + +#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 3 + fprintf(stderr, "ALLOC %9d to %p\n", l, r); +#endif + if (!r) { + fprintf(stderr, "Could not allocate %d bytes of memory\n", l); + exit(EXIT_FAILURE); + } + return r; +} + +#ifndef S_FREE +static void s_free(void *p) +{ +#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 3 + fprintf(stderr, "FREE %p\n", p); +#endif + XFREE(p); +} +#endif + +static void s_der_print_flexi_i(const ltc_asn1_list* l, unsigned int level) +{ + char *buf = NULL; + const char *name = NULL; + const char *text = NULL; + ltc_asn1_list *ostring = NULL; + unsigned int n; + int slen; + const wchar_t *wtmp; + + switch (l->type) + { + case LTC_ASN1_EOL: + name = "EOL"; + slen = snprintf(NULL, 0, ASN1_FMTSTRING_FMT "\n", ASN1_FMTSTRING_VAL(l)); + buf = s_xmalloc(slen); + snprintf(buf, slen, ASN1_FMTSTRING_FMT "\n", ASN1_FMTSTRING_VAL(l)); + text = buf; + break; + case LTC_ASN1_BOOLEAN: + name = "BOOLEAN"; + { + if (*(int*) l->data) + text = "true"; + else + text = "false"; + } + break; + case LTC_ASN1_INTEGER: + name = "INTEGER"; + buf = s_xmalloc(((ltc_mp_get_digit_count(l->data) + 1) * ltc_mp.bits_per_digit) / 3); + ltc_mp_toradix(l->data, buf, 10); + text = buf; + break; + case LTC_ASN1_SHORT_INTEGER: + name = "SHORT INTEGER"; + break; + case LTC_ASN1_BIT_STRING: + name = "BIT STRING"; + if (l->size <= 16) { + int r; + int sz = l->size + 1; + char *s = buf = s_xmalloc(sz); + for (n = 0; n < l->size; ++n) { + r = snprintf(s, sz, "%c", ((unsigned char*) l->data)[n] ? '1' : '0'); + if (r < 0 || r >= sz) { + fprintf(stderr, "%s boom\n", name); + exit(EXIT_FAILURE); + } + s += r; + sz -= r; + } + } else { + slen = snprintf(NULL, 0, "Length %lu", l->size); + buf = s_xmalloc(slen); + snprintf(buf, slen, "Length %lu", l->size); + } + text = buf; + break; + case LTC_ASN1_OCTET_STRING: + name = "OCTET STRING"; + { + unsigned long ostring_l = l->size; + /* sometimes there's another sequence in an octet string... + * try to decode that... if it fails print out the octet string + */ + if (der_decode_sequence_flexi(l->data, &ostring_l, &ostring) == CRYPT_OK) { + text = ""; + } else { + int r; + int sz = l->size * 2 + 1; + char *s = buf = s_xmalloc(sz); + for (n = 0; n < l->size; ++n) { + r = snprintf(s, sz, "%02X", ((unsigned char*) l->data)[n]); + if (r < 0 || r >= sz) { + fprintf(stderr, "%s boom\n", name); + exit(EXIT_FAILURE); + } + s += r; + sz -= r; + } + text = buf; + } + } + break; + case LTC_ASN1_NULL: + name = "NULL"; + text = ""; + break; + case LTC_ASN1_OBJECT_IDENTIFIER: + name = "OBJECT IDENTIFIER"; + { + unsigned long len = 0; + if (pk_oid_num_to_str(l->data, l->size, buf, &len) != CRYPT_BUFFER_OVERFLOW) { + fprintf(stderr, "%s WTF\n", name); + exit(EXIT_FAILURE); + } + buf = s_xmalloc(len); + if (pk_oid_num_to_str(l->data, l->size, buf, &len) != CRYPT_OK) { + fprintf(stderr, "%s boom\n", name); + exit(EXIT_FAILURE); + } + text = buf; + } + break; + case LTC_ASN1_IA5_STRING: + name = "IA5 STRING"; + text = l->data; + break; + case LTC_ASN1_PRINTABLE_STRING: + name = "PRINTABLE STRING"; + text = l->data; + break; + case LTC_ASN1_UTF8_STRING: + name = "UTF8 STRING"; + wtmp = l->data; + slen = wcsrtombs(NULL, &wtmp, 0, NULL); + if (slen != -1) { + slen++; + buf = s_xmalloc(slen); + if (wcsrtombs(buf, &wtmp, slen, NULL) == (size_t)-1) { + fprintf(stderr, "%s boom\n", name); + exit(EXIT_FAILURE); + } + text = buf; + } + break; + case LTC_ASN1_UTCTIME: + name = "UTCTIME"; + { + ltc_utctime *ut = l->data; + slen = 32; + buf = s_xmalloc(slen); + snprintf(buf, slen, "%02d-%02d-%02d %02d:%02d:%02d %c%02d:%02d", ut->YY, ut->MM, ut->DD, ut->hh, ut->mm, + ut->ss, ut->off_dir ? '-' : '+', ut->off_hh, ut->off_mm); + text = buf; + } + break; + case LTC_ASN1_GENERALIZEDTIME: + name = "GENERALIZED TIME"; + { + ltc_generalizedtime *gt = l->data; + slen = 32; + buf = s_xmalloc(slen); + if (gt->fs) + snprintf(buf, slen, "%04d-%02d-%02d %02d:%02d:%02d.%02dZ", gt->YYYY, gt->MM, gt->DD, gt->hh, gt->mm, + gt->ss, gt->fs); + else + snprintf(buf, slen, "%04d-%02d-%02d %02d:%02d:%02dZ", gt->YYYY, gt->MM, gt->DD, gt->hh, gt->mm, gt->ss); + text = buf; + } + break; + case LTC_ASN1_CHOICE: + name = "CHOICE"; + break; + case LTC_ASN1_SEQUENCE: + name = "SEQUENCE"; + text = ""; + break; + case LTC_ASN1_SET: + name = "SET"; + text = ""; + break; + case LTC_ASN1_SETOF: + name = "SETOF"; + text = ""; + break; + case LTC_ASN1_RAW_BIT_STRING: + name = "RAW BIT STRING"; + break; + case LTC_ASN1_TELETEX_STRING: + name = "TELETEX STRING"; + text = l->data; + break; + case LTC_ASN1_CUSTOM_TYPE: + name = "NON STANDARD"; + { + int r; + int sz = 128; + char *s = buf = s_xmalloc(sz); + + r = snprintf(s, sz, "[%s %s %llu]", der_asn1_class_to_string_map[l->klass], + der_asn1_pc_to_string_map[l->pc], l->tag); + if (r < 0 || r >= sz) { + fprintf(stderr, "%s boom\n", name); + exit(EXIT_FAILURE); + } + + text = buf; + } + break; + } + + for (n = 0; n < level; ++n) { + fprintf(stderr, " "); + } + if (name) { + if (text) + fprintf(stderr, "%s %s\n", name, text); + else + fprintf(stderr, "%s \n", name); + } else + fprintf(stderr, "WTF type=%i\n", l->type); + + if (buf) { + s_free(buf); + buf = NULL; + } + + if (ostring) { + s_der_print_flexi_i(ostring, level + 1); + der_free_sequence_flexi(ostring); + } + + if (l->child) s_der_print_flexi_i(l->child, level + 1); + + if (l->next) s_der_print_flexi_i(l->next, level); +} + +#ifndef LTC_DER_PRINT_FLEXI_NO_MAIN + +static void s_der_print_flexi(const ltc_asn1_list* l) +{ + fprintf(stderr, "\n\n"); + s_der_print_flexi_i(l, 0); + fprintf(stderr, "\n\n"); +} + +#include +#include +#include +#include +#include +#include + +static int fd; +static ltc_asn1_list *l; + +static void print_err(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +static void die_(int err, int line) +{ + print_err("%3d: LTC sez %s\n", line, error_to_string(err)); + der_free_sequence_flexi(l); + close(fd); + exit(EXIT_FAILURE); +} + +#define die(i) do { die_(i, __LINE__); } while(0) +#define DIE(s, ...) do { print_err("%3d: " s "\n", __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); } while(0) + +int main(int argc, char **argv) +{ + void *addr; + int err, argn = 1; + struct stat sb; + unsigned long len; + + if ((err = register_all_hashes()) != CRYPT_OK) { + die(err); + } + if ((err = crypt_mp_init("ltm")) != CRYPT_OK) { + die(err); + } + if (argc > argn) fd = open(argv[argn], O_RDONLY); + else fd = STDIN_FILENO; + if (fd == -1) DIE("open sez no"); + if (fstat(fd, &sb) == -1) DIE("fstat"); + + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) DIE("mmap"); + + len = sb.st_size; + + if ((err = der_decode_sequence_flexi(addr, &len, &l)) != CRYPT_OK) { + die(err); + } + + s_der_print_flexi(l); + + der_free_sequence_flexi(l); + close(fd); + + return 0; +} + +#endif /* LTC_DER_PRINT_FLEXI_NO_MAIN */ diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj index 72d7fb779..cef8f84e1 100644 --- a/libtomcrypt_VS2008.vcproj +++ b/libtomcrypt_VS2008.vcproj @@ -2277,6 +2277,14 @@ RelativePath="src\pk\asn1\x509\x509_encode_subject_public_key_info.c" > + + + + PKCS #1 v1.5, 1 -> PSS/OAEP */ + int pss_oaep; + /** saltLength is only defined for PSS + * If saltLength == 0 -> OAEP, else -> PSS */ + unsigned long saltlen; + /** hash and MGF hash algorithms */ + const char *hash_alg, *mgf1_hash_alg; +} ltc_rsa_parameters; + +/** RSA key */ typedef struct Rsa_key { /** Type of key, PK_PRIVATE or PK_PUBLIC */ int type; @@ -82,6 +94,8 @@ typedef struct Rsa_key { void *dP; /** The d mod (q - 1) CRT param */ void *dQ; + /** Further parameters of the RSA key */ + ltc_rsa_parameters params; } rsa_key; int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key); @@ -103,10 +117,10 @@ void rsa_free(rsa_key *key); rsa_decrypt_key_ex(in, inlen, out, outlen, lparam, lparamlen, hash_idx, -1, LTC_PKCS_1_OAEP, stat, key) #define rsa_sign_hash(in, inlen, out, outlen, prng, prng_idx, hash_idx, saltlen, key) \ - rsa_sign_hash_ex(in, inlen, out, outlen, LTC_PKCS_1_PSS, prng, prng_idx, hash_idx, saltlen, key) + rsa_sign_hash_ex(in, inlen, out, outlen, LTC_PKCS_1_PSS, prng, prng_idx, hash_idx, hash_idx, saltlen, key) #define rsa_verify_hash(sig, siglen, hash, hashlen, hash_idx, saltlen, stat, key) \ - rsa_verify_hash_ex(sig, siglen, hash, hashlen, LTC_PKCS_1_PSS, hash_idx, saltlen, stat, key) + rsa_verify_hash_ex(sig, siglen, hash, hashlen, LTC_PKCS_1_PSS, hash_idx, hash_idx, saltlen, stat, key) #define rsa_sign_saltlen_get_max(hash_idx, key) \ rsa_sign_saltlen_get_max_ex(LTC_PKCS_1_PSS, hash_idx, key) @@ -130,14 +144,16 @@ int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, int padding, - prng_state *prng, int prng_idx, - int hash_idx, unsigned long saltlen, + prng_state *prng, int prng_idx, + int hash_idx, int mgf_hash_idx, + unsigned long saltlen, const rsa_key *key); int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int padding, - int hash_idx, unsigned long saltlen, + int hash_idx, int mgf_hash_idx, + unsigned long saltlen, int *stat, const rsa_key *key); int rsa_sign_saltlen_get_max_ex(int padding, int hash_idx, const rsa_key *key); @@ -723,9 +739,10 @@ typedef struct ltc_asn1_list_ { #define LTC_SET_ASN1_CUSTOM_PRIMITIVE(list, index, Class, Tag, Type, Data, Size) \ do { \ int LTC_TMPVAR(SACP) = (index); \ + ltc_asn1_list *LTC_TMPVAR(SACP_list) = (list); \ LTC_SET_ASN1(list, LTC_TMPVAR(SACP), LTC_ASN1_CUSTOM_TYPE, Data, Size); \ LTC_SET_ASN1_IDENTIFIER(list, LTC_TMPVAR(SACP), Class, LTC_ASN1_PC_PRIMITIVE, Tag); \ - list[LTC_TMPVAR(SACP)].used = (int)(Type); \ + LTC_TMPVAR(SACP_list)[LTC_TMPVAR(SACP)].used = (int)(Type); \ } while (0) extern const char* der_asn1_class_to_string_map[]; diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h index 7069b1652..d8444e0bd 100644 --- a/src/headers/tomcrypt_private.h +++ b/src/headers/tomcrypt_private.h @@ -60,6 +60,9 @@ enum ltc_oid_id { LTC_OID_X25519, LTC_OID_ED25519, LTC_OID_DH, + LTC_OID_RSA_OAEP, + LTC_OID_RSA_MGF1, + LTC_OID_RSA_PSS, LTC_OID_NUM }; @@ -352,19 +355,40 @@ struct bufp { }; #define SET_BUFP(n, d, l) n.start = (char*)d, n.work = (char*)d, n.end = (char*)d + l + 1 +#define UPDATE_BUFP(n, d, w, l) n.start = (char*)d, n.work = (char*)d + w, n.end = (char*)d + l + 1 -struct get_char { +struct get_char; +struct get_char_api { int (*get)(struct get_char*); +}; + +struct get_char { + struct get_char_api api; union { #ifndef LTC_NO_FILE - FILE *f; + struct { + FILE *f; + } f; #endif /* LTC_NO_FILE */ struct bufp buf; } data; struct str unget_buf; char unget_buf_[LTC_PEM_DECODE_BUFSZ]; int prev_get; + unsigned long total_read; }; + +#define pem_get_char_init(b, l) { \ + .api = get_char_buffer_api, \ + SET_BUFP(.data.buf, (b), (l)), \ + .total_read = 0, \ +} + +#define pem_get_char_init_filehandle(fi) { \ + .api = get_char_filehandle_api, \ + .data.f.f = (fi), \ + .total_read = 0, \ +} #endif /* others */ @@ -387,10 +411,10 @@ int pem_decrypt(unsigned char *data, unsigned long *datalen, const struct blockcipher_info *info, enum padding_type padding); #ifndef LTC_NO_FILE -int pem_get_char_from_file(struct get_char *g); +extern const struct get_char_api get_char_filehandle_api; #endif /* LTC_NO_FILE */ -int pem_get_char_from_buf(struct get_char *g); -int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, struct get_char *g); +extern const struct get_char_api get_char_buffer_api; +int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g); #endif /* tomcrypt_pk.h */ @@ -411,12 +435,20 @@ int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long /* ---- DH Routines ---- */ #ifdef LTC_MRSA +typedef enum ltc_rsa_op { + LTC_RSA_CRYPT, + LTC_RSA_SIGN +} ltc_rsa_op; int rsa_init(rsa_key *key); void rsa_shrink_key(rsa_key *key); +int rsa_key_valid_op(const rsa_key *key, ltc_rsa_op op, int padding, int hash_idx); +int rsa_params_equal(const ltc_rsa_parameters *a, const ltc_rsa_parameters *b); int rsa_make_key_bn_e(prng_state *prng, int wprng, int size, void *e, rsa_key *key); /* used by op-tee */ int rsa_import_pkcs1(const unsigned char *in, unsigned long inlen, rsa_key *key); int rsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, rsa_key *key); +int rsa_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key); +int rsa_decode_parameters(const ltc_asn1_list *parameters, ltc_rsa_parameters *rsa_params); #endif /* LTC_MRSA */ /* ---- DH Routines ---- */ @@ -524,8 +556,8 @@ int dsa_int_validate(const dsa_key *key, int *stat); int dsa_int_validate_xy(const dsa_key *key, int *stat); int dsa_int_validate_pqg(const dsa_key *key, int *stat); int dsa_int_validate_primes(const dsa_key *key, int *stat); -int dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key); int dsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, dsa_key *key); +int dsa_import_spki(const unsigned char *in, unsigned long inlen, dsa_key *key); #endif /* LTC_MDSA */ @@ -599,17 +631,29 @@ int der_printable_value_decode(int v); unsigned long der_utf8_charsize(const wchar_t c); -typedef struct { +typedef int (*der_flexi_handler)(const ltc_asn1_list*, void*); + +typedef struct der_flexi_check { ltc_asn1_type t; + int optional; ltc_asn1_list **pp; + der_flexi_handler handler; + void *userdata; } der_flexi_check; -#define LTC_SET_DER_FLEXI_CHECK(list, index, Type, P) \ - do { \ - int LTC_SDFC_temp##__LINE__ = (index); \ - list[LTC_SDFC_temp##__LINE__].t = Type; \ - list[LTC_SDFC_temp##__LINE__].pp = P; \ +#define LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, P, Opt, Hndl, Udata) \ + do { \ + int LTC_SDFC_temp##__LINE__ = (index); \ + list[LTC_SDFC_temp##__LINE__].t = Type; \ + list[LTC_SDFC_temp##__LINE__].pp = P; \ + list[LTC_SDFC_temp##__LINE__].optional = Opt; \ + list[LTC_SDFC_temp##__LINE__].handler = (der_flexi_handler)Hndl; \ + list[LTC_SDFC_temp##__LINE__].userdata = Udata; \ } while (0) +#define LTC_SET_DER_FLEXI_CHECK(list, index, Type, P) LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, P, 0, NULL, NULL) +#define LTC_SET_DER_FLEXI_CHECK_OPT(list, index, Type, P) LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, P, 1, NULL, NULL) +#define LTC_SET_DER_FLEXI_HANDLER(list, index, Type, Hndl, Udata) LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, NULL, 0, Hndl, Udata) +#define LTC_SET_DER_FLEXI_HANDLER_OPT(list, index, Type, Hndl, Udata) LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, NULL, 1, Hndl, Udata) extern const ltc_asn1_type der_asn1_tag_to_type_map[]; @@ -628,13 +672,17 @@ 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); +typedef int (*public_key_decode_cb)(const unsigned char *in, unsigned long inlen, void *key); 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 x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, ltc_asn1_list **spki); + public_key_decode_cb callback, void *key); +int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, const ltc_asn1_list **spki); +int x509_process_public_key_from_spki(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 *key); /* SUBJECT PUBLIC KEY INFO */ int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen, @@ -645,12 +693,31 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i enum ltc_oid_id algorithm, void *public_key, unsigned long *public_key_len, ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len); +int x509_get_pka(const ltc_asn1_list *pub, enum ltc_pka_id *pka); +int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root); + int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2); #endif /* LTC_DER */ /* tomcrypt_pkcs.h */ +#ifdef LTC_PKCS_1 + +int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, + prng_state *prng, int prng_idx, + int hash_idx, int mgf_hash_idx, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen); +int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, + int hash_idx, int mgf_hash_idx, + unsigned long modulus_bitlen, int *res); + +#endif /* LTC_PKCS_1 */ + #ifdef LTC_PKCS_8 /* Public-Key Cryptography Standards (PKCS) #8: diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c index 61b5cd050..b16d6318a 100644 --- a/src/misc/crypt/crypt.c +++ b/src/misc/crypt/crypt.c @@ -455,6 +455,7 @@ const char *crypt_build_settings = #if defined(LTC_DER) " DER " " " NAME_VALUE(LTC_DER_MAX_RECURSION) " " + " " NAME_VALUE(LTC_DER_OID_DEFAULT_NODES) " " #endif #if defined(LTC_PKCS_1) " PKCS#1 " diff --git a/src/misc/crypt/crypt_register_all_hashes.c b/src/misc/crypt/crypt_register_all_hashes.c index 362205f9d..93d32fc34 100644 --- a/src/misc/crypt/crypt_register_all_hashes.c +++ b/src/misc/crypt/crypt_register_all_hashes.c @@ -15,45 +15,47 @@ int register_all_hashes(void) { -#ifdef LTC_TIGER - REGISTER_HASH(&tiger_desc); - REGISTER_HASH(&tiger2_desc); +#ifdef LTC_SHA512 + REGISTER_HASH(&sha512_desc); #endif -#ifdef LTC_MD2 - REGISTER_HASH(&md2_desc); +#ifdef LTC_SHA256 + REGISTER_HASH(&sha256_desc); #endif -#ifdef LTC_MD4 - REGISTER_HASH(&md4_desc); +#ifdef LTC_SHA3 + REGISTER_HASH(&sha3_512_desc); + REGISTER_HASH(&sha3_384_desc); + REGISTER_HASH(&sha3_256_desc); + REGISTER_HASH(&sha3_224_desc); #endif -#ifdef LTC_MD5 - REGISTER_HASH(&md5_desc); +#ifdef LTC_SHA512_256 + REGISTER_HASH(&sha512_256_desc); #endif -#ifdef LTC_SHA1 - REGISTER_HASH(&sha1_desc); +#ifdef LTC_SHA512_224 + REGISTER_HASH(&sha512_224_desc); #endif #ifdef LTC_SHA224 REGISTER_HASH(&sha224_desc); #endif -#ifdef LTC_SHA256 - REGISTER_HASH(&sha256_desc); -#endif #ifdef LTC_SHA384 REGISTER_HASH(&sha384_desc); #endif -#ifdef LTC_SHA512 - REGISTER_HASH(&sha512_desc); +#ifdef LTC_SHA1 + REGISTER_HASH(&sha1_desc); #endif -#ifdef LTC_SHA512_224 - REGISTER_HASH(&sha512_224_desc); +#ifdef LTC_MD5 + REGISTER_HASH(&md5_desc); #endif -#ifdef LTC_SHA512_256 - REGISTER_HASH(&sha512_256_desc); +#ifdef LTC_BLAKE2S + REGISTER_HASH(&blake2s_128_desc); + REGISTER_HASH(&blake2s_160_desc); + REGISTER_HASH(&blake2s_224_desc); + REGISTER_HASH(&blake2s_256_desc); #endif -#ifdef LTC_SHA3 - REGISTER_HASH(&sha3_224_desc); - REGISTER_HASH(&sha3_256_desc); - REGISTER_HASH(&sha3_384_desc); - REGISTER_HASH(&sha3_512_desc); +#ifdef LTC_BLAKE2S + REGISTER_HASH(&blake2b_160_desc); + REGISTER_HASH(&blake2b_256_desc); + REGISTER_HASH(&blake2b_384_desc); + REGISTER_HASH(&blake2b_512_desc); #endif #ifdef LTC_KECCAK REGISTER_HASH(&keccak_224_desc); @@ -76,17 +78,15 @@ int register_all_hashes(void) #ifdef LTC_WHIRLPOOL REGISTER_HASH(&whirlpool_desc); #endif -#ifdef LTC_BLAKE2S - REGISTER_HASH(&blake2s_128_desc); - REGISTER_HASH(&blake2s_160_desc); - REGISTER_HASH(&blake2s_224_desc); - REGISTER_HASH(&blake2s_256_desc); +#ifdef LTC_TIGER + REGISTER_HASH(&tiger_desc); + REGISTER_HASH(&tiger2_desc); #endif -#ifdef LTC_BLAKE2S - REGISTER_HASH(&blake2b_160_desc); - REGISTER_HASH(&blake2b_256_desc); - REGISTER_HASH(&blake2b_384_desc); - REGISTER_HASH(&blake2b_512_desc); +#ifdef LTC_MD2 + REGISTER_HASH(&md2_desc); +#endif +#ifdef LTC_MD4 + REGISTER_HASH(&md4_desc); #endif #ifdef LTC_CHC_HASH { diff --git a/src/misc/crypt/crypt_register_hash.c b/src/misc/crypt/crypt_register_hash.c index 1668de392..b5a479deb 100644 --- a/src/misc/crypt/crypt_register_hash.c +++ b/src/misc/crypt/crypt_register_hash.c @@ -14,10 +14,13 @@ */ int register_hash(const struct ltc_hash_descriptor *hash) { - int x; + int x, blank = -1; LTC_ARGCHK(hash != NULL); + if (hash->name == NULL) + return -1; + /* is it already registered? */ LTC_MUTEX_LOCK(<c_hash_mutex); for (x = 0; x < TAB_SIZE; x++) { @@ -25,15 +28,16 @@ int register_hash(const struct ltc_hash_descriptor *hash) LTC_MUTEX_UNLOCK(<c_hash_mutex); return x; } + if (hash_descriptor[x].name == NULL && blank == -1) { + blank = x; + } } - /* find a blank spot */ - for (x = 0; x < TAB_SIZE; x++) { - if (hash_descriptor[x].name == NULL) { - XMEMCPY(&hash_descriptor[x], hash, sizeof(struct ltc_hash_descriptor)); - LTC_MUTEX_UNLOCK(<c_hash_mutex); - return x; - } + /* fill in blank spot */ + if (blank != -1) { + XMEMCPY(&hash_descriptor[blank], hash, sizeof(struct ltc_hash_descriptor)); + LTC_MUTEX_UNLOCK(<c_hash_mutex); + return x; } /* no spot */ diff --git a/src/misc/pem/pem.c b/src/misc/pem/pem.c index 632515914..1e8cc0132 100644 --- a/src/misc/pem/pem.c +++ b/src/misc/pem/pem.c @@ -10,6 +10,13 @@ #ifdef LTC_PEM const struct pem_header_id pem_std_headers[] = { + { + /* X.509 Certificates */ + SET_CSTR(.start, "-----BEGIN CERTIFICATE-----"), + SET_CSTR(.end, "-----END CERTIFICATE-----"), + .has_more_headers = no, + .flags = pf_x509, + }, { /* PKCS#8 encrypted */ SET_CSTR(.start, "-----BEGIN ENCRYPTED PRIVATE KEY-----"), @@ -24,13 +31,6 @@ const struct pem_header_id pem_std_headers[] = { .has_more_headers = no, .flags = pf_pkcs8, }, - { - /* X.509 Certificates */ - SET_CSTR(.start, "-----BEGIN CERTIFICATE-----"), - SET_CSTR(.end, "-----END CERTIFICATE-----"), - .has_more_headers = no, - .flags = pf_x509, - }, { /* Regular (plain) public keys */ SET_CSTR(.start, "-----BEGIN PUBLIC KEY-----"), diff --git a/src/misc/pem/pem_pkcs.c b/src/misc/pem/pem_pkcs.c index e99f29ea0..17aa47705 100644 --- a/src/misc/pem/pem_pkcs.c +++ b/src/misc/pem/pem_pkcs.c @@ -41,120 +41,50 @@ static int s_decrypt_pem(unsigned char *asn1_cert, unsigned long *asn1_len, cons return err; } -static int s_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka) -{ - der_flexi_check flexi_should[4]; - ltc_asn1_list *seqid, *id; - enum ltc_oid_id oid_id; - int err; - unsigned long n = 0; - LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seqid); - LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL); - LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL); - if ((err = der_flexi_sequence_cmp(pub, flexi_should)) != CRYPT_OK) { - return err; - } - n = 0; - LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OBJECT_IDENTIFIER, &id); - LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL); - err = der_flexi_sequence_cmp(seqid, flexi_should); - if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) { - return err; - } - if ((err = pk_get_oid_from_asn1(id, &oid_id)) != CRYPT_OK) { - return err; - } - return pk_get_pka_id(oid_id, pka); -} +typedef int (*pkcs8_import_fn)(ltc_asn1_list *, ltc_asn1_list *, void*); -typedef int (*import_fn)(const unsigned char *, unsigned long, void*); - -static const import_fn s_import_x509_fns[LTC_PKA_NUM] = { +static const struct { + enum ltc_pka_id id; + pkcs8_import_fn fn; +} s_import_pkcs8_map[LTC_OID_NUM] = { +#ifdef LTC_MDH + [LTC_OID_DH] = { LTC_PKA_DH, (pkcs8_import_fn)dh_import_pkcs8_asn1 }, +#endif +#ifdef LTC_MDSA + [LTC_OID_DSA] = { LTC_PKA_DSA, (pkcs8_import_fn)dsa_import_pkcs8_asn1 }, +#endif #ifdef LTC_MRSA - [LTC_PKA_RSA] = (import_fn)rsa_import_x509, + [LTC_OID_RSA] = { LTC_PKA_RSA, (pkcs8_import_fn)rsa_import_pkcs8_asn1 }, #endif #ifdef LTC_MECC - [LTC_PKA_EC] = (import_fn)ecc_import_x509, + [LTC_OID_EC] = { LTC_PKA_EC, (pkcs8_import_fn)ecc_import_pkcs8_asn1 }, #endif #ifdef LTC_CURVE25519 - [LTC_PKA_X25519] = (import_fn)x25519_import_x509, - [LTC_PKA_ED25519] = (import_fn)ed25519_import_x509, + [LTC_OID_X25519] = { LTC_PKA_X25519, (pkcs8_import_fn)x25519_import_pkcs8_asn1 }, + [LTC_OID_ED25519] = { LTC_PKA_ED25519, (pkcs8_import_fn)ed25519_import_pkcs8_asn1 }, #endif }; -static int s_import_x509(unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k) -{ - enum ltc_pka_id pka = LTC_PKA_UNDEF; - ltc_asn1_list *d, *spki; - int err; - if ((err = x509_decode_spki(asn1_cert, asn1_len, &d, &spki)) != CRYPT_OK) { - return err; - } - err = s_get_pka(spki, &pka); - der_free_sequence_flexi(d); - if (err != CRYPT_OK) { - return err; - } - if (pka < 0 - || pka > LTC_ARRAY_SIZE(s_import_x509_fns) - || s_import_x509_fns[pka] == NULL) { - return CRYPT_PK_INVALID_TYPE; - } - if ((err = s_import_x509_fns[pka](asn1_cert, asn1_len, &k->u)) == CRYPT_OK) { - k->id = pka; - } - return err; -} - static int s_import_pkcs8(unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, const password_ctx *pw_ctx) { int err; - enum ltc_oid_id pka; + enum ltc_oid_id oid_id; ltc_asn1_list *alg_id, *priv_key; ltc_asn1_list *p8_asn1 = NULL; if ((err = pkcs8_decode_flexi(asn1_cert, asn1_len, pw_ctx, &p8_asn1)) != CRYPT_OK) { goto cleanup; } - if ((err = pkcs8_get_children(p8_asn1, &pka, &alg_id, &priv_key)) != CRYPT_OK) { + if ((err = pkcs8_get_children(p8_asn1, &oid_id, &alg_id, &priv_key)) != CRYPT_OK) { goto cleanup; } - switch (pka) { -#ifdef LTC_MDH - case LTC_OID_DH: - err = dh_import_pkcs8_asn1(alg_id, priv_key, &k->u.dh); - k->id = LTC_PKA_DH; - break; -#endif -#ifdef LTC_MDSA - case LTC_OID_DSA: - err = dsa_import_pkcs8_asn1(alg_id, priv_key, &k->u.dsa); - k->id = LTC_PKA_DSA; - break; -#endif -#ifdef LTC_MRSA - case LTC_OID_RSA: - err = rsa_import_pkcs8_asn1(alg_id, priv_key, &k->u.rsa); - k->id = LTC_PKA_RSA; - break; -#endif -#ifdef LTC_MECC - case LTC_OID_EC: - err = ecc_import_pkcs8_asn1(alg_id, priv_key, &k->u.ecc); - k->id = LTC_PKA_EC; - break; -#endif -#ifdef LTC_CURVE25519 - case LTC_OID_X25519: - err = x25519_import_pkcs8_asn1(alg_id, priv_key, &k->u.x25519); - k->id = LTC_PKA_X25519; - break; - case LTC_OID_ED25519: - err = ed25519_import_pkcs8_asn1(alg_id, priv_key, &k->u.ed25519); - k->id = LTC_PKA_ED25519; - break; -#endif - default: - err = CRYPT_PK_INVALID_TYPE; + if (oid_id < 0 + || oid_id > LTC_ARRAY_SIZE(s_import_pkcs8_map) + || s_import_pkcs8_map[oid_id].fn == NULL) { + err = CRYPT_PK_INVALID_TYPE; + goto cleanup; + } + if ((err = s_import_pkcs8_map[oid_id].fn(alg_id, priv_key, &k->u)) == CRYPT_OK) { + k->id = s_import_pkcs8_map[oid_id].id; } cleanup: @@ -171,11 +101,13 @@ static int s_extract_pka(unsigned char *asn1_cert, unsigned long asn1_len, enum if ((err = der_decode_sequence_flexi(asn1_cert, &asn1_len, &pub)) != CRYPT_OK) { return err; } - err = s_get_pka(pub, pka); + err = x509_get_pka(pub, pka); der_sequence_free(pub); return err; } +typedef int (*import_fn)(const unsigned char *, unsigned long, void*); + static const import_fn s_import_openssl_fns[LTC_PKA_NUM] = { #ifdef LTC_MRSA [LTC_PKA_RSA] = (import_fn)rsa_import, @@ -195,21 +127,16 @@ static const import_fn s_import_openssl_fns[LTC_PKA_NUM] = { static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx) { unsigned char *asn1_cert = NULL; - unsigned long w, asn1_len, n; + unsigned long w = 0, asn1_len, n; int err = CRYPT_ERROR; struct pem_headers hdr = { 0 }; struct password pw = { 0 }; enum ltc_pka_id pka; XMEMSET(k, 0, sizeof(*k)); - w = LTC_PEM_READ_BUFSIZE * 2; -retry: - asn1_cert = XREALLOC(asn1_cert, w); for (n = 0; n < pem_std_headers_num; ++n) { hdr.id = &pem_std_headers[n]; - err = pem_read(asn1_cert, &w, &hdr, g); - if (err == CRYPT_BUFFER_OVERFLOW) { - goto retry; - } else if (err == CRYPT_OK) { + err = pem_read((void**)&asn1_cert, &w, &hdr, g); + if (err == CRYPT_OK) { break; } else if (err != CRYPT_UNKNOWN_PEM) { goto cleanup; @@ -224,7 +151,7 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c err = s_import_pkcs8(asn1_cert, asn1_len, k, pw_ctx); goto cleanup; } else if (hdr.id->flags == pf_x509) { - err = s_import_x509(asn1_cert, asn1_len, k); + err = x509_import_spki(asn1_cert, asn1_len, k, NULL); goto cleanup; } else if ((hdr.id->flags & pf_public) && hdr.id->pka == LTC_PKA_UNDEF) { if ((err = s_extract_pka(asn1_cert, asn1_len, &pka)) != CRYPT_OK) { @@ -272,7 +199,7 @@ int pem_decode_pkcs_filehandle(FILE *f, ltc_pka_key *k, const password_ctx *pw_c LTC_ARGCHK(f != NULL); LTC_ARGCHK(k != NULL); { - struct get_char g = { .get = pem_get_char_from_file, .data.f = f }; + struct get_char g = pem_get_char_init_filehandle(f); return s_decode(&g, k, pw_ctx); } } @@ -284,7 +211,7 @@ int pem_decode_pkcs(const void *buf, unsigned long len, ltc_pka_key *k, const pa LTC_ARGCHK(len != 0); LTC_ARGCHK(k != NULL); { - struct get_char g = { .get = pem_get_char_from_buf, SET_BUFP(.data.buf, buf, len) }; + struct get_char g = pem_get_char_init(buf, len); return s_decode(&g, k, pw_ctx); } } diff --git a/src/misc/pem/pem_read.c b/src/misc/pem/pem_read.c index abefff924..bbc61cb0d 100644 --- a/src/misc/pem/pem_read.c +++ b/src/misc/pem/pem_read.c @@ -17,14 +17,76 @@ extern const struct str pem_dek_info_start; extern const struct blockcipher_info pem_dek_infos[]; extern const unsigned long pem_dek_infos_num; +static LTC_INLINE unsigned long s_bufp_alloc_len(struct bufp *buf) +{ + if (buf->start == NULL || buf->end == NULL) + return 0; + return buf->end - buf->start - 1; +} + +static LTC_INLINE unsigned long s_bufp_used_len(struct bufp *buf) +{ + if (buf->start == NULL || buf->end == NULL) + return 0; + return buf->work - buf->start; +} + +static LTC_INLINE int s_bufp_grow(struct bufp *buf) +{ + int err = CRYPT_OK; + void *ret; + unsigned long alloc_len = s_bufp_alloc_len(buf), realloc_len; + unsigned long work_offset = s_bufp_used_len(buf); + if (alloc_len == 0) + realloc_len = LTC_PEM_READ_BUFSIZE; + else + realloc_len = alloc_len * 2; + if (realloc_len < alloc_len) + return CRYPT_OVERFLOW; + ret = XREALLOC(buf->start, realloc_len); + if (ret == NULL) { + err = CRYPT_MEM; + } else { + UPDATE_BUFP((*buf), ret, work_offset, realloc_len); + } + return err; +} + +static LTC_INLINE int s_bufp_fits(struct bufp *buf, unsigned long to_write) +{ + char *d = buf->work; + char *e = buf->end; + char *w = d + to_write; + if (d == NULL || w < d || w > e) + return 0; + return 1; +} + +static LTC_INLINE int s_bufp_add(struct bufp *buf, const void *src, unsigned long len) +{ + int err; + if (!s_bufp_fits(buf, len)) { + if ((err = s_bufp_grow(buf)) != CRYPT_OK) { + return err; + } + } + XMEMCPY(buf->work, src, len); + buf->work += len; + return CRYPT_OK; +} + #ifndef LTC_NO_FILE -int pem_get_char_from_file(struct get_char *g) +static int s_pem_get_char_from_file(struct get_char *g) { - return getc(g->data.f); + return getc(g->data.f.f); } + +const struct get_char_api get_char_filehandle_api = { + .get = s_pem_get_char_from_file, +}; #endif /* LTC_NO_FILE */ -int pem_get_char_from_buf(struct get_char *g) +static int s_pem_get_char_from_buf(struct get_char *g) { int ret; if (g->data.buf.work == g->data.buf.end) { @@ -35,6 +97,10 @@ int pem_get_char_from_buf(struct get_char *g) return ret; } +const struct get_char_api get_char_buffer_api = { + .get = s_pem_get_char_from_buf, +}; + static void s_unget_line(char *buf, unsigned long buflen, struct get_char *g) { if (buflen > sizeof(g->unget_buf_)) @@ -81,7 +147,7 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g, while(blen < *buflen || search_for_start) { wr = blen < *buflen ? blen : *buflen - 1; c_ = g->prev_get; - g->prev_get = g->get(g); + g->prev_get = g->api.get(g); if (g->prev_get == '\n') { buf[wr] = '\0'; if (c_ == '\r') { @@ -89,6 +155,7 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g, } s_tts(buf, &wr); *buflen = wr; + g->total_read++; return buf; } if (g->prev_get == -1 || g->prev_get == '\0') { @@ -99,30 +166,21 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g, } buf[wr] = g->prev_get; blen++; + g->total_read++; } return NULL; } -LTC_INLINE static char* s_get_first_line(char *buf, unsigned long *buflen, struct get_char *g) +static LTC_INLINE char* s_get_first_line(char *buf, unsigned long *buflen, struct get_char *g) { return s_get_line_i(buf, buflen, g, 1); } -LTC_INLINE static char* s_get_line(char *buf, unsigned long *buflen, struct get_char *g) +static LTC_INLINE char* s_get_line(char *buf, unsigned long *buflen, struct get_char *g) { return s_get_line_i(buf, buflen, g, 0); } -static LTC_INLINE int s_fits_buf(void *dest, unsigned long to_write, void *end) -{ - unsigned char *d = dest; - unsigned char *e = end; - unsigned char *w = d + to_write; - if (w < d || w > e) - return 0; - return 1; -} - static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g) { char buf[LTC_PEM_DECODE_BUFSZ], *alg_start; @@ -190,31 +248,29 @@ static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g) return CRYPT_OK; } -int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, struct get_char *g) +int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g) { - char buf[LTC_PEM_DECODE_BUFSZ]; - char *wpem = asn1_cert; - char *end = wpem + *asn1_len; + char line[LTC_PEM_DECODE_BUFSZ]; + struct bufp b_ = {0}, *b = &b_; const char pem_start[] = "----"; - unsigned long slen, linelen; + unsigned long slen; int err, hdr_ok = 0; - int would_overflow = 0; unsigned char empty_lines = 0; g->prev_get = 0; do { - linelen = sizeof(buf); - if (s_get_first_line(buf, &linelen, g) == NULL) { + slen = sizeof(line); + if (s_get_first_line(line, &slen, g) == NULL) { if (g->prev_get == -1) return CRYPT_NOP; else return CRYPT_INVALID_PACKET; } - if (linelen < sizeof(pem_start) - 1) + if (slen < sizeof(pem_start) - 1) continue; - } while(XMEMCMP(buf, pem_start, sizeof(pem_start) - 1) != 0); - if (hdr->id->start.len != linelen || XMEMCMP(buf, hdr->id->start.p, hdr->id->start.len)) { - s_unget_line(buf, linelen, g); + } while(XMEMCMP(line, pem_start, sizeof(pem_start) - 1) != 0); + if (hdr->id->start.len != slen || XMEMCMP(line, hdr->id->start.p, hdr->id->start.len)) { + s_unget_line(line, slen, g); return CRYPT_UNKNOWN_PEM; } @@ -223,9 +279,9 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, return err; /* Read the base64 encoded part of the PEM */ - slen = sizeof(buf); - while (s_get_line(buf, &slen, g)) { - if (slen == hdr->id->end.len && !XMEMCMP(buf, hdr->id->end.p, slen)) { + slen = sizeof(line); + while (s_get_line(line, &slen, g)) { + if (slen == hdr->id->end.len && !XMEMCMP(line, hdr->id->end.p, slen)) { hdr_ok = 1; break; } @@ -234,34 +290,26 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, break; empty_lines++; } - if (!would_overflow && s_fits_buf(wpem, slen, end)) { - XMEMCPY(wpem, buf, slen); - } else { - would_overflow = 1; + if ((err = s_bufp_add(b, line, slen)) != CRYPT_OK) { + goto error_out; } - wpem += slen; - slen = sizeof(buf); + slen = sizeof(line); } - if (!hdr_ok) - return CRYPT_INVALID_PACKET; - - if (would_overflow || !s_fits_buf(wpem, 1, end)) { - /* NUL termination */ - wpem++; - /* prevent a wrap-around */ - if (wpem < (char*)asn1_cert) - return CRYPT_OVERFLOW; - *asn1_len = wpem - (char*)asn1_cert; - return CRYPT_BUFFER_OVERFLOW; + if (!hdr_ok) { + err = CRYPT_INVALID_PACKET; + } else { + slen = s_bufp_alloc_len(b); + err = base64_strict_decode(b->start, s_bufp_used_len(b), (void*)b->start, &slen); } + if (err == CRYPT_OK) { + *dest = b->start; + *len = slen; - *asn1_len = wpem - (char*)asn1_cert; - *wpem++ = '\0'; - - if ((err = base64_strict_decode(asn1_cert, *asn1_len, asn1_cert, asn1_len)) != CRYPT_OK) { - return err; + } else { +error_out: + XFREE(b->start); } - return CRYPT_OK; + return err; } #endif /* LTC_PEM */ diff --git a/src/misc/pem/pem_ssh.c b/src/misc/pem/pem_ssh.c index 0117dbf3a..eb8f419f7 100644 --- a/src/misc/pem/pem_ssh.c +++ b/src/misc/pem/pem_ssh.c @@ -712,20 +712,15 @@ static const unsigned long pem_openssh_num = LTC_ARRAY_SIZE(pem_openssh); static int s_decode_openssh(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx) { unsigned char *pem = NULL, *p, *privkey = NULL, *tag; - unsigned long n, w, l, privkey_len, taglen; + unsigned long n, w = 0, l, privkey_len, taglen; int err; struct pem_headers hdr; struct kdf_options opts = { 0 }; XMEMSET(k, 0, sizeof(*k)); - w = LTC_PEM_READ_BUFSIZE * 2; -retry: - pem = XREALLOC(pem, w); for (n = 0; n < pem_openssh_num; ++n) { hdr.id = &pem_openssh[n]; - err = pem_read(pem, &w, &hdr, g); - if (err == CRYPT_BUFFER_OVERFLOW) { - goto retry; - } else if (err == CRYPT_OK) { + err = pem_read((void**)&pem, &w, &hdr, g); + if (err == CRYPT_OK) { break; } else if (err != CRYPT_UNKNOWN_PEM) { goto cleanup; @@ -791,7 +786,9 @@ static int s_decode_openssh(struct get_char *g, ltc_pka_key *k, const password_c zeromem(privkey, privkey_len); XFREE(privkey); } - XFREE(pem); + if (pem) { + XFREE(pem); + } return err; } @@ -801,7 +798,7 @@ int pem_decode_openssh_filehandle(FILE *f, ltc_pka_key *k, const password_ctx *p LTC_ARGCHK(f != NULL); LTC_ARGCHK(k != NULL); { - struct get_char g = { .get = pem_get_char_from_file, .data.f = f }; + struct get_char g = pem_get_char_init_filehandle(f); return s_decode_openssh(&g, k, pw_ctx); } } @@ -841,7 +838,7 @@ int pem_decode_openssh(const void *buf, unsigned long len, ltc_pka_key *k, const LTC_ARGCHK(len != 0); LTC_ARGCHK(k != NULL); { - struct get_char g = { .get = pem_get_char_from_buf, SET_BUFP(.data.buf, buf, len) }; + struct get_char g = pem_get_char_init(buf, len); return s_decode_openssh(&g, k, pw_ctx); } } diff --git a/src/pk/asn1/der/bit/der_decode_bit_string.c b/src/pk/asn1/der/bit/der_decode_bit_string.c index 83c915dc4..3e6de501c 100644 --- a/src/pk/asn1/der/bit/der_decode_bit_string.c +++ b/src/pk/asn1/der/bit/der_decode_bit_string.c @@ -28,8 +28,8 @@ int der_decode_bit_string(const unsigned char *in, unsigned long inlen, LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); - /* packet must be at least 4 bytes */ - if (inlen < 4) { + /* packet must be at least 3 bytes */ + if (inlen < 3) { return CRYPT_INVALID_ARG; } diff --git a/src/pk/asn1/der/bit/der_decode_raw_bit_string.c b/src/pk/asn1/der/bit/der_decode_raw_bit_string.c index 1bc74f60a..d23c89788 100644 --- a/src/pk/asn1/der/bit/der_decode_raw_bit_string.c +++ b/src/pk/asn1/der/bit/der_decode_raw_bit_string.c @@ -31,8 +31,8 @@ int der_decode_raw_bit_string(const unsigned char *in, unsigned long inlen, LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); - /* packet must be at least 4 bytes */ - if (inlen < 4) { + /* packet must be at least 3 bytes */ + if (inlen < 3) { return CRYPT_INVALID_ARG; } diff --git a/src/pk/asn1/der/sequence/der_flexi_sequence_cmp.c b/src/pk/asn1/der/sequence/der_flexi_sequence_cmp.c index 026eb504a..535483f59 100644 --- a/src/pk/asn1/der/sequence/der_flexi_sequence_cmp.c +++ b/src/pk/asn1/der/sequence/der_flexi_sequence_cmp.c @@ -24,11 +24,20 @@ int der_flexi_sequence_cmp(const ltc_asn1_list *flexi, der_flexi_check *check) return CRYPT_INVALID_PACKET; } cur = flexi->child; - while(check->t != LTC_ASN1_EOL) { + while(check->t != LTC_ASN1_EOL && cur) { if (!LTC_ASN1_IS_TYPE(cur, check->t)) { + if (check->optional) { + check++; + continue; + } return CRYPT_INVALID_PACKET; } if (check->pp != NULL) *check->pp = cur; + else if (check->handler) { + int err = check->handler(cur, check->userdata); + if (err != CRYPT_OK) + return err; + } cur = cur->next; check++; } diff --git a/src/pk/asn1/oid/pk_get.c b/src/pk/asn1/oid/pk_get.c index 1fd5872e2..81a1b2f3e 100644 --- a/src/pk/asn1/oid/pk_get.c +++ b/src/pk/asn1/oid/pk_get.c @@ -7,18 +7,22 @@ typedef struct { enum ltc_oid_id id; enum ltc_pka_id pka; - const char* oid; + const char *hash; + const char *oid; } oid_table_entry; static const oid_table_entry pka_oids[] = { - { LTC_OID_UNDEF, LTC_PKA_UNDEF, NULL }, - { LTC_OID_RSA, LTC_PKA_RSA, "1.2.840.113549.1.1.1" }, - { LTC_OID_DSA, LTC_PKA_DSA, "1.2.840.10040.4.1" }, - { LTC_OID_EC, LTC_PKA_EC, "1.2.840.10045.2.1" }, - { LTC_OID_EC_PRIMEF, LTC_PKA_EC, "1.2.840.10045.1.1" }, - { LTC_OID_X25519, LTC_PKA_X25519, "1.3.101.110" }, - { LTC_OID_ED25519, LTC_PKA_ED25519, "1.3.101.112" }, - { LTC_OID_DH, LTC_PKA_DH, "1.2.840.113549.1.3.1" }, + { LTC_OID_UNDEF, LTC_PKA_UNDEF, NULL, NULL }, + { LTC_OID_RSA, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.1" }, + { LTC_OID_DSA, LTC_PKA_DSA, NULL, "1.2.840.10040.4.1" }, + { LTC_OID_EC, LTC_PKA_EC, NULL, "1.2.840.10045.2.1" }, + { LTC_OID_EC_PRIMEF, LTC_PKA_EC, NULL, "1.2.840.10045.1.1" }, + { LTC_OID_X25519, LTC_PKA_X25519, NULL, "1.3.101.110" }, + { LTC_OID_ED25519, LTC_PKA_ED25519, NULL, "1.3.101.112" }, + { LTC_OID_DH, LTC_PKA_DH, NULL, "1.2.840.113549.1.3.1" }, + { LTC_OID_RSA_OAEP, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.7" }, + { LTC_OID_RSA_MGF1, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.8" }, + { LTC_OID_RSA_PSS, LTC_PKA_RSA_PSS, NULL, "1.2.840.113549.1.1.10" }, }; static LTC_INLINE const oid_table_entry* s_get_entry(enum ltc_oid_id id) @@ -43,21 +47,35 @@ int pk_get_oid(enum ltc_oid_id id, const char **st) return CRYPT_INVALID_ARG; } -/* - Returns the PKA ID requested. - @return CRYPT_OK if valid -*/ -int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka) +static LTC_INLINE int s_get_values(enum ltc_oid_id id, enum ltc_pka_id *pka, const char **hash) { const oid_table_entry* e = s_get_entry(id); LTC_ARGCHK(pka != NULL); if (e != NULL) { *pka = e->pka; + if (hash) { + *hash = e->hash; + } else if (e->hash) { + /* If we don't want the hash result, but the entry has a hash, we're most likely + * confused and we prefer to stop processing then, instead of continuing with a + * maybe wrong assumption. + */ + return CRYPT_INVALID_ARG; + } return CRYPT_OK; } return CRYPT_INVALID_ARG; } +/* + Returns the PKA ID requested. + @return CRYPT_OK if valid +*/ +int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka) +{ + return s_get_values(id, pka, NULL); +} + /* Returns the OID ID requested. @return CRYPT_OK if valid 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 45a1c6f60..b96db4438 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 @@ -10,7 +10,7 @@ #ifdef LTC_DER /** - Try to decode the public key from a X.509 certificate + Process the public key from the SubjectPublicKeyInfo of 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 @@ -19,53 +19,82 @@ @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, - CRYPT_NOP if no SubjectPublicKeyInfo was found, - another error if decoding or memory allocation failed + @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 x509_process_public_key_from_spki(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 *key) { int err; unsigned char *tmpbuf = NULL; unsigned long tmpbuf_len; - ltc_asn1_list *decoded_list = NULL, *spki; - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(inlen != 0); - LTC_ARGCHK(callback != NULL); - - if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) { - return err; - } + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(callback != NULL); if (algorithm == LTC_OID_EC) { - err = callback(spki->data, spki->size, ctx); + err = callback(in, inlen, key); } else { tmpbuf_len = inlen; tmpbuf = XCALLOC(1, tmpbuf_len); if (tmpbuf == NULL) { - err = CRYPT_MEM; - goto LBL_OUT; + return CRYPT_MEM; } - err = x509_decode_subject_public_key_info(spki->data, spki->size, + err = x509_decode_subject_public_key_info(in, inlen, algorithm, tmpbuf, &tmpbuf_len, param_type, parameters, parameters_len); if (err == CRYPT_OK) { - err = callback(tmpbuf, tmpbuf_len, ctx); - goto LBL_OUT; + err = callback(tmpbuf, tmpbuf_len, key); } } -LBL_OUT: - if (decoded_list) der_free_sequence_flexi(decoded_list); if (tmpbuf != NULL) XFREE(tmpbuf); return err; } +/** + 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, + CRYPT_NOP if no SubjectPublicKeyInfo was found, + another error if decoding or memory allocation failed +*/ +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 *key) +{ + int err; + ltc_asn1_list *decoded_list; + const ltc_asn1_list *spki; + + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(inlen != 0); + LTC_ARGCHK(callback != NULL); + + if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) { + return err; + } + + err = x509_process_public_key_from_spki(spki->data, spki->size, + algorithm, param_type, + parameters, parameters_len, + callback, key); + + if (decoded_list) der_free_sequence_flexi(decoded_list); + + return err; +} + #endif diff --git a/src/pk/asn1/x509/x509_decode_spki.c b/src/pk/asn1/x509/x509_decode_spki.c index 147aaf1c6..144441cd2 100644 --- a/src/pk/asn1/x509/x509_decode_spki.c +++ b/src/pk/asn1/x509/x509_decode_spki.c @@ -26,10 +26,10 @@ @param spki [out] A pointer to the SubjectPublicKeyInfo @return CRYPT_OK on success, CRYPT_NOP if no SubjectPublicKeyInfo was found, another error if decoding failed */ -int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, ltc_asn1_list **spki) +int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, const ltc_asn1_list **spki) { int err; - unsigned long tmp_inlen; + unsigned long tmp_inlen, n, element_is_spki; ltc_asn1_list *decoded_list = NULL, *l; LTC_ARGCHK(in != NULL); @@ -49,29 +49,49 @@ int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) { l = l->child; if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) { + /* TBSCertificate ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version MUST be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version MUST be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version MUST be v3 + * } + */ l = l->child; - /* Move forward in the tree until we find this combination - ... - SEQUENCE - SEQUENCE - OBJECT IDENTIFIER - NULL - BIT STRING + /* `l` points now either to 'version' or 'serialNumber', depending on + * whether 'version' is included or defaults to 'v1'. + * 'version' is represented as a LTC_ASN1_CUSTOM_TYPE + * 'serialNumber' is represented as an LTC_ASN1_INTEGER + * Decide now whether to move 5 or 6 elements forward until + * `l` should point to subjectPublicKeyInfo. */ - 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)) { - *out = decoded_list; - *spki = l; - return CRYPT_OK; - } + if (l->type == LTC_ASN1_CUSTOM_TYPE) + element_is_spki = 6; + else + element_is_spki = 5; + for (n = 0; n < element_is_spki && l; ++n) { l = l->next; - } while(l); + } + /* 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 != NULL) + && (l->type == LTC_ASN1_SEQUENCE) + && (l->data != NULL) + && LOOKS_LIKE_SPKI(l->child)) { + *out = decoded_list; + *spki = l; + return CRYPT_OK; + } } } } 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 072561112..34c8eac7f 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 @@ -75,6 +75,8 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i alg_id_num = 1; } else { LTC_SET_ASN1(alg_id, 1, parameters_type, parameters, *_parameters_len); + if (parameters_type == LTC_ASN1_NULL) + alg_id[1].optional = 1; alg_id_num = 2; } diff --git a/src/pk/asn1/x509/x509_get_pka.c b/src/pk/asn1/x509/x509_get_pka.c new file mode 100644 index 000000000..d71231aaf --- /dev/null +++ b/src/pk/asn1/x509/x509_get_pka.c @@ -0,0 +1,38 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ +#include "tomcrypt_private.h" + +/** + @file x509_get_pka.c + Extract the PKA from an X.509 cert, Steffen Jaeckel +*/ + +#ifdef LTC_DER + +int x509_get_pka(const ltc_asn1_list *pub, enum ltc_pka_id *pka) +{ + der_flexi_check flexi_should[4]; + ltc_asn1_list *seqid, *id; + enum ltc_oid_id oid_id; + int err; + unsigned long n = 0; + LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seqid); + LTC_SET_DER_FLEXI_CHECK_OPT(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL); + LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL); + if ((err = der_flexi_sequence_cmp(pub, flexi_should)) != CRYPT_OK) { + return err; + } + n = 0; + LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OBJECT_IDENTIFIER, &id); + LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL); + err = der_flexi_sequence_cmp(seqid, flexi_should); + if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) { + return err; + } + if ((err = pk_get_oid_from_asn1(id, &oid_id)) != CRYPT_OK) { + return err; + } + return pk_get_pka_id(oid_id, pka); +} + +#endif /* LTC_DER */ diff --git a/src/pk/asn1/x509/x509_import_spki.c b/src/pk/asn1/x509/x509_import_spki.c new file mode 100644 index 000000000..13057bd31 --- /dev/null +++ b/src/pk/asn1/x509/x509_import_spki.c @@ -0,0 +1,87 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis */ +/* SPDX-License-Identifier: Unlicense */ +#include "tomcrypt_private.h" + +/** + @file x509_import_spki.c + Import the SubjectPublicKeyInfo of an X.509 cert, Steffen Jaeckel +*/ + +#ifdef LTC_DER + +typedef int (*import_fn)(const unsigned char *, unsigned long, void *); + +#ifdef LTC_CURVE25519 +static int s_x25519_import_pub(const unsigned char *in, unsigned long inlen, void *key) +{ + return x25519_import_raw(in, inlen, PK_PUBLIC, key); +} +static int s_x25519_import_spki(const unsigned char *in, unsigned long inlen, void *key) +{ + return x509_process_public_key_from_spki(in, inlen, + LTC_OID_X25519, + LTC_ASN1_EOL, NULL, NULL, + s_x25519_import_pub, key); +} + +static int s_ed25519_import_pub(const unsigned char *in, unsigned long inlen, void *key) +{ + return ed25519_import_raw(in, inlen, PK_PUBLIC, key); +} +static int s_ed25519_import_spki(const unsigned char *in, unsigned long inlen, void *key) +{ + return x509_process_public_key_from_spki(in, inlen, + LTC_OID_ED25519, + LTC_ASN1_EOL, NULL, NULL, + s_ed25519_import_pub, key); +} +#endif + +static const import_fn s_import_spki_fns[LTC_PKA_NUM] = { +#ifdef LTC_MRSA + [LTC_PKA_RSA] = (import_fn)rsa_import_spki, + [LTC_PKA_RSA_PSS] = (import_fn)rsa_import_spki, +#endif +#ifdef LTC_MDSA + [LTC_PKA_DSA] = (import_fn)dsa_import_spki, +#endif +#ifdef LTC_MECC + [LTC_PKA_EC] = (import_fn)ecc_import_subject_public_key_info, +#endif +#ifdef LTC_CURVE25519 + [LTC_PKA_X25519] = (import_fn)s_x25519_import_spki, + [LTC_PKA_ED25519] = (import_fn)s_ed25519_import_spki, +#endif +}; + +int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root) +{ + enum ltc_pka_id pka = LTC_PKA_UNDEF; + ltc_asn1_list *d; + const ltc_asn1_list *spki; + int err; + if ((err = x509_decode_spki(asn1_cert, asn1_len, &d, &spki)) != CRYPT_OK) { + return err; + } + if ((err = x509_get_pka(spki, &pka)) != CRYPT_OK) { + goto err_out; + } + if (pka < 0 + || pka > LTC_ARRAY_SIZE(s_import_spki_fns) + || s_import_spki_fns[pka] == NULL) { + err = CRYPT_PK_INVALID_TYPE; + goto err_out; + } + if ((err = s_import_spki_fns[pka](spki->data, spki->size, &k->u)) == CRYPT_OK) { + k->id = pka; + } +err_out: + if (err == CRYPT_OK && root) { + *root = d; + d = NULL; + } + der_free_sequence_flexi(d); + return err; +} + +#endif /* LTC_DER */ diff --git a/src/pk/dsa/dsa_import.c b/src/pk/dsa/dsa_import.c index d2c2d49ec..91ddcc2be 100644 --- a/src/pk/dsa/dsa_import.c +++ b/src/pk/dsa/dsa_import.c @@ -9,7 +9,7 @@ #ifdef LTC_MDSA -int dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key) +static int s_dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key) { int err; unsigned long zero = 0; @@ -28,6 +28,109 @@ int dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key) return err; } +static int s_dsa_import_y(const unsigned char *in, unsigned long inlen, dsa_key *key) +{ + return der_decode_integer(in, inlen, key->y); +} + +static LTC_INLINE int s_dsa_set_params(dsa_key *key, ltc_asn1_list *params) +{ + LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, key->p, 1UL); + LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, key->q, 1UL); + LTC_SET_ASN1(params, 2, LTC_ASN1_INTEGER, key->g, 1UL); + return 3; +} + +static LTC_INLINE int s_dsa_validate(dsa_key *key) +{ + int err, stat; + key->qord = ltc_mp_unsigned_bin_size(key->q); + + /* quick p, q, g validation, without primality testing + * + x, y validation */ + if ((err = dsa_int_validate(key, &stat)) != CRYPT_OK) { + return err; + } + + if (stat == 0) { + return CRYPT_INVALID_PACKET; + } + + return CRYPT_OK; +} + +static int s_dsa_import_spki(const unsigned char *in, unsigned long inlen, dsa_key *key) +{ + int err; + unsigned char* tmpbuf = NULL; + ltc_asn1_list params[3]; + unsigned long tmpbuf_len = inlen, len; + + len = s_dsa_set_params(key, params); + + tmpbuf = XCALLOC(1, tmpbuf_len); + if (tmpbuf == NULL) { + return CRYPT_MEM; + } + + err = x509_decode_subject_public_key_info(in, inlen, + LTC_OID_DSA, tmpbuf, &tmpbuf_len, + LTC_ASN1_SEQUENCE, params, &len); + if (err != CRYPT_OK) { + goto LBL_ERR; + } + + if ((err = s_dsa_import_y(tmpbuf, tmpbuf_len, key)) != CRYPT_OK) { + goto LBL_ERR; + } + + key->type = PK_PUBLIC; +LBL_ERR: + XFREE(tmpbuf); + return err; +} + +int dsa_import_spki(const unsigned char *in, unsigned long inlen, dsa_key *key) +{ + int err; + + LTC_ARGCHK(in != NULL); + + /* init key */ + if ((err = dsa_int_init(key)) != CRYPT_OK) return err; + + if ((err = s_dsa_import_spki(in, inlen, key)) != CRYPT_OK) { + goto LBL_ERR; + } + if ((err = s_dsa_validate(key)) != CRYPT_OK) { + goto LBL_ERR; + } + + return CRYPT_OK; +LBL_ERR: + dsa_free(key); + return err; +} + +static int s_dsa_import_x509(const unsigned char *in, unsigned long inlen, dsa_key *key) +{ + int err; + ltc_asn1_list params[3]; + unsigned long len; + + len = s_dsa_set_params(key, params); + + if ((err = x509_decode_public_key_from_certificate(in, inlen, + LTC_OID_DSA, + LTC_ASN1_SEQUENCE, params, &len, + (public_key_decode_cb)s_dsa_import_y, key)) == CRYPT_OK) { + key->type = PK_PUBLIC; + return CRYPT_OK; + } + + return err; +} + /** Import a DSA key @param in The binary packet to import from @@ -37,8 +140,7 @@ int dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key) */ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) { - int err, stat; - unsigned char* tmpbuf = NULL; + int err; unsigned char flags[1]; LTC_ARGCHK(in != NULL); @@ -86,47 +188,18 @@ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) } } - if (dsa_import_pkcs1(in, inlen, key) != CRYPT_OK) { - ltc_asn1_list params[3]; - unsigned long tmpbuf_len = inlen, len; - - LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, key->p, 1UL); - LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, key->q, 1UL); - LTC_SET_ASN1(params, 2, LTC_ASN1_INTEGER, key->g, 1UL); - len = 3; - - tmpbuf = XCALLOC(1, tmpbuf_len); - if (tmpbuf == NULL) { - return CRYPT_MEM; - } - - err = x509_decode_subject_public_key_info(in, inlen, - LTC_OID_DSA, tmpbuf, &tmpbuf_len, - LTC_ASN1_SEQUENCE, params, &len); - if (err != CRYPT_OK) { - XFREE(tmpbuf); - goto LBL_ERR; - } - - if ((err = der_decode_integer(tmpbuf, tmpbuf_len, key->y)) != CRYPT_OK) { - XFREE(tmpbuf); - goto LBL_ERR; - } - - key->type = PK_PUBLIC; - XFREE(tmpbuf); + if (s_dsa_import_pkcs1(in, inlen, key) == CRYPT_OK) { + goto LBL_OK; } - -LBL_OK: - key->qord = ltc_mp_unsigned_bin_size(key->q); - - /* quick p, q, g validation, without primality testing - * + x, y validation */ - if ((err = dsa_int_validate(key, &stat)) != CRYPT_OK) { + if (s_dsa_import_spki(in, inlen, key) == CRYPT_OK) { + goto LBL_OK; + } + if ((err = s_dsa_import_x509(in, inlen, key)) != CRYPT_OK) { goto LBL_ERR; } - if (stat == 0) { - err = CRYPT_INVALID_PACKET; + +LBL_OK: + if ((err = s_dsa_validate(key)) != CRYPT_OK) { goto LBL_ERR; } diff --git a/src/pk/ec25519/tweetnacl.c b/src/pk/ec25519/tweetnacl.c index eb35d2fff..37a915c57 100644 --- a/src/pk/ec25519/tweetnacl.c +++ b/src/pk/ec25519/tweetnacl.c @@ -312,6 +312,7 @@ int tweetnacl_crypto_sk_to_pk(u8 *pk, const u8 *sk) { u8 d[64]; gf p[4]; + if (find_hash("sha512") == -1) return CRYPT_INVALID_HASH; tweetnacl_crypto_hash(d, sk, 32); d[0] &= 248; d[31] &= 127; @@ -387,6 +388,8 @@ int tweetnacl_crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 mlen,const u8 *sk,co i64 i,j,x[64]; gf p[4]; + if (find_hash("sha512") == -1) return CRYPT_INVALID_HASH; + tweetnacl_crypto_hash(d, sk, 32); d[0] &= 248; d[31] &= 127; @@ -456,6 +459,7 @@ int tweetnacl_crypto_sign_open(int *stat, u8 *m,u64 *mlen,const u8 *sm,u64 smlen gf p[4],q[4]; *stat = 0; + if (find_hash("sha512") == -1) return CRYPT_INVALID_HASH; if (*mlen < smlen) return CRYPT_BUFFER_OVERFLOW; *mlen = -1; if (smlen < 64) return CRYPT_INVALID_ARG; diff --git a/src/pk/ed25519/ed25519_sign.c b/src/pk/ed25519/ed25519_sign.c index 33c240566..193bfcdb7 100644 --- a/src/pk/ed25519/ed25519_sign.c +++ b/src/pk/ed25519/ed25519_sign.c @@ -23,6 +23,7 @@ static int s_ed25519_sign(const unsigned char *msg, unsigned long msglen, LTC_ARGCHK(siglen != NULL); LTC_ARGCHK(private_key != NULL); + if (find_hash("sha512") == -1) return CRYPT_INVALID_HASH; if (private_key->pka != LTC_PKA_ED25519) return CRYPT_PK_INVALID_TYPE; if (private_key->type != PK_PRIVATE) return CRYPT_PK_INVALID_TYPE; diff --git a/src/pk/ed25519/ed25519_verify.c b/src/pk/ed25519/ed25519_verify.c index 7afab7cab..2a16e30c5 100644 --- a/src/pk/ed25519/ed25519_verify.c +++ b/src/pk/ed25519/ed25519_verify.c @@ -26,6 +26,7 @@ static int s_ed25519_verify(const unsigned char *msg, unsigned long msglen, *stat = 0; + if (find_hash("sha512") == -1) return CRYPT_INVALID_HASH; if (siglen != 64uL) return CRYPT_INVALID_ARG; if (public_key->pka != LTC_PKA_ED25519) return CRYPT_PK_INVALID_TYPE; diff --git a/src/pk/pka_key.c b/src/pk/pka_key.c index d88ee3d30..c682cfcbf 100644 --- a/src/pk/pka_key.c +++ b/src/pk/pka_key.c @@ -30,6 +30,7 @@ void pka_key_free(ltc_pka_key *key) #endif break; case LTC_PKA_RSA: + case LTC_PKA_RSA_PSS: #if defined(LTC_MRSA) rsa_free(&key->u.rsa); #endif diff --git a/src/pk/pkcs1/pkcs_1_pss_decode.c b/src/pk/pkcs1/pkcs_1_pss_decode.c index fad401d1b..fc258ea4f 100644 --- a/src/pk/pkcs1/pkcs_1_pss_decode.c +++ b/src/pk/pkcs1/pkcs_1_pss_decode.c @@ -17,14 +17,16 @@ @param siglen The length of the signature data (octets) @param saltlen The length of the salt used (octets) @param hash_idx The index of the hash desired + @param mgf_hash_idx The index of the hash desired for MGF1 @param modulus_bitlen The bit length of the RSA modulus @param res [out] The result of the comparison, 1==valid, 0==invalid @return CRYPT_OK if successful (even if the comparison failed) */ -int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, - const unsigned char *sig, unsigned long siglen, - unsigned long saltlen, int hash_idx, - unsigned long modulus_bitlen, int *res) +int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, + int hash_idx, int mgf_hash_idx, + unsigned long modulus_bitlen, int *res) { unsigned char *DB, *mask, *salt, *hash; unsigned long x, y, hLen, modulus_len; @@ -41,6 +43,11 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { return err; } + if (hash_idx != mgf_hash_idx) { + if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) { + return err; + } + } hLen = hash_descriptor[hash_idx].hashsize; modulus_bitlen--; @@ -95,7 +102,7 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, } /* generate mask of length modulus_len - hLen - 1 from hash */ - if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { goto LBL_ERR; } @@ -163,4 +170,25 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, return err; } + +/** + PKCS #1 v2.00 PSS decode + @param msghash The hash to verify + @param msghashlen The length of the hash (octets) + @param sig The signature data (encoded data) + @param siglen The length of the signature data (octets) + @param saltlen The length of the salt used (octets) + @param hash_idx The index of the hash desired + @param modulus_bitlen The bit length of the RSA modulus + @param res [out] The result of the comparison, 1==valid, 0==invalid + @return CRYPT_OK if successful (even if the comparison failed) +*/ +int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, int hash_idx, + unsigned long modulus_bitlen, int *res) +{ + return pkcs_1_pss_decode_mgf1(msghash, msghashlen, sig, siglen, saltlen, hash_idx, hash_idx, modulus_bitlen, res); +} + #endif /* LTC_PKCS_1 */ diff --git a/src/pk/pkcs1/pkcs_1_pss_encode.c b/src/pk/pkcs1/pkcs_1_pss_encode.c index 2a4e3728a..01d9636f9 100644 --- a/src/pk/pkcs1/pkcs_1_pss_encode.c +++ b/src/pk/pkcs1/pkcs_1_pss_encode.c @@ -17,16 +17,18 @@ @param prng An active PRNG context @param prng_idx The index of the PRNG desired @param hash_idx The index of the hash desired + @param mgf_hash_idx The index of the hash desired for MGF1 @param modulus_bitlen The bit length of the RSA modulus @param out [out] The destination of the encoding @param outlen [in/out] The max size and resulting size of the encoded data @return CRYPT_OK if successful */ -int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, - unsigned long saltlen, prng_state *prng, - int prng_idx, int hash_idx, - unsigned long modulus_bitlen, - unsigned char *out, unsigned long *outlen) +int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, + prng_state *prng, int prng_idx, + int hash_idx, int mgf_hash_idx, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen) { unsigned char *DB, *mask, *salt, *hash; unsigned long x, y, hLen, modulus_len; @@ -37,10 +39,15 @@ int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); - /* ensure hash and PRNG are valid */ + /* ensure hashes and PRNG are valid */ if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { return err; } + if (hash_idx != mgf_hash_idx) { + if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) { + return err; + } + } if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { return err; } @@ -111,7 +118,7 @@ int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, /* x += saltlen; */ /* generate mask of length modulus_len - hLen - 1 from hash */ - if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { goto LBL_ERR; } @@ -161,4 +168,27 @@ int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, return err; } + +/** + PKCS #1 v2.00 Signature Encoding using MGF1 and both hashes are the same + @param msghash The hash to encode + @param msghashlen The length of the hash (octets) + @param saltlen The length of the salt desired (octets) + @param prng An active PRNG context + @param prng_idx The index of the PRNG desired + @param hash_idx The index of the hash desired + @param modulus_bitlen The bit length of the RSA modulus + @param out [out] The destination of the encoding + @param outlen [in/out] The max size and resulting size of the encoded data + @return CRYPT_OK if successful +*/ +int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, prng_state *prng, + int prng_idx, int hash_idx, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen) +{ + return pkcs_1_pss_encode_mgf1(msghash, msghashlen, saltlen, prng, prng_idx, hash_idx, hash_idx, modulus_bitlen, out, outlen); +} + #endif /* LTC_PKCS_1 */ diff --git a/src/pk/rsa/rsa_decrypt_key.c b/src/pk/rsa/rsa_decrypt_key.c index d8e7a546f..a36ecb021 100644 --- a/src/pk/rsa/rsa_decrypt_key.c +++ b/src/pk/rsa/rsa_decrypt_key.c @@ -45,16 +45,8 @@ int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen *stat = 0; /* valid padding? */ - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_OAEP)) { - return CRYPT_PK_INVALID_PADDING; - } - - if (padding == LTC_PKCS_1_OAEP) { - /* valid hash ? */ - if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) { - return err; - } + if ((err = rsa_key_valid_op(key, LTC_RSA_CRYPT, padding, mgf_hash)) != CRYPT_OK) { + return err; } /* get modulus len in bits */ diff --git a/src/pk/rsa/rsa_encrypt_key.c b/src/pk/rsa/rsa_encrypt_key.c index 17dd1af5d..83fb2c5a6 100644 --- a/src/pk/rsa/rsa_encrypt_key.c +++ b/src/pk/rsa/rsa_encrypt_key.c @@ -41,9 +41,8 @@ int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen, LTC_ARGCHK(key != NULL); /* valid padding? */ - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_OAEP)) { - return CRYPT_PK_INVALID_PADDING; + if ((err = rsa_key_valid_op(key, LTC_RSA_CRYPT, padding, mgf_hash)) != CRYPT_OK) { + return err; } /* valid prng? */ @@ -51,13 +50,6 @@ int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen, return err; } - if (padding == LTC_PKCS_1_OAEP) { - /* valid hash? */ - if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) { - return err; - } - } - /* get modulus len in bits */ modulus_bitlen = ltc_mp_count_bits( (key->N)); diff --git a/src/pk/rsa/rsa_import.c b/src/pk/rsa/rsa_import.c index 1240a77e7..bc201ad97 100644 --- a/src/pk/rsa/rsa_import.c +++ b/src/pk/rsa/rsa_import.c @@ -9,6 +9,18 @@ #ifdef LTC_MRSA +#ifndef S_RSA_DECODE +#define S_RSA_DECODE +static int s_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); +} +#endif + /** Import an RSAPublicKey or RSAPrivateKey as defined in PKCS #1 v2.1 [two-prime only] @@ -33,10 +45,7 @@ int rsa_import_pkcs1(const unsigned char *in, unsigned long inlen, rsa_key *key) /* the version would fit into an LTC_ASN1_SHORT_INTEGER * so we try to decode as a public key */ - if ((err = der_decode_sequence_multi(in, inlen, - LTC_ASN1_INTEGER, 1UL, key->N, - LTC_ASN1_INTEGER, 1UL, key->e, - LTC_ASN1_EOL, 0UL, NULL)) == CRYPT_OK) { + if ((err = s_rsa_decode(in, inlen, key)) == CRYPT_OK) { key->type = PK_PUBLIC; } goto LBL_OUT; @@ -85,57 +94,25 @@ int rsa_import_pkcs1(const unsigned char *in, unsigned long inlen, rsa_key *key) int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) { int err; - unsigned char *tmpbuf=NULL; - unsigned long tmpbuf_len, len; LTC_ARGCHK(in != NULL); LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); + /* SubjectPublicKeyInfo or X.509 certificate format */ + if (rsa_import_x509(in, inlen, key) == CRYPT_OK) { + return CRYPT_OK; + } + /* init key */ if ((err = rsa_init(key)) != CRYPT_OK) { return err; } - - /* see if the OpenSSL DER format RSA public key will work */ - tmpbuf_len = inlen; - tmpbuf = XCALLOC(1, tmpbuf_len); - if (tmpbuf == NULL) { - err = CRYPT_MEM; - goto LBL_ERR; - } - - len = 0; - err = x509_decode_subject_public_key_info(in, inlen, - LTC_OID_RSA, tmpbuf, &tmpbuf_len, - LTC_ASN1_NULL, NULL, &len); - - if (err == CRYPT_OK) { /* SubjectPublicKeyInfo format */ - - /* 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; + /* Try to match against PKCS #1 standards */ + if ((err = rsa_import_pkcs1(in, inlen, key)) != CRYPT_OK) { + rsa_free(key); } - /* not SSL public key, try to match against PKCS #1 standards */ - if ((err = rsa_import_pkcs1(in, inlen, key)) == CRYPT_OK) { - goto LBL_FREE; - } - -LBL_ERR: - rsa_free(key); - -LBL_FREE: - if (tmpbuf != NULL) { - XFREE(tmpbuf); - } return err; } diff --git a/src/pk/rsa/rsa_import_x509.c b/src/pk/rsa/rsa_import_x509.c index 4d157ead4..6ebe55669 100644 --- a/src/pk/rsa/rsa_import_x509.c +++ b/src/pk/rsa/rsa_import_x509.c @@ -9,6 +9,8 @@ #ifdef LTC_MRSA +#ifndef S_RSA_DECODE +#define S_RSA_DECODE static int s_rsa_decode(const unsigned char *in, unsigned long inlen, rsa_key *key) { /* now it should be SEQUENCE { INTEGER, INTEGER } */ @@ -17,6 +19,201 @@ static int s_rsa_decode(const unsigned char *in, unsigned long inlen, rsa_key *k LTC_ASN1_INTEGER, 1UL, key->e, LTC_ASN1_EOL, 0UL, NULL); } +#endif + +typedef struct rsa_pss_parameters_data { + ltc_asn1_list params[4], inner[4], hash_alg[2], mgf[2], mgf_hash_alg[2]; + unsigned long hash_alg_oid[LTC_DER_OID_DEFAULT_NODES]; + unsigned long mgf_alg_oid[LTC_DER_OID_DEFAULT_NODES]; + unsigned long mgf1_hash_alg_oid[LTC_DER_OID_DEFAULT_NODES]; + unsigned long salt_length, trailer_field; +} rsa_pss_parameters_data; + +static LTC_INLINE void s_rsa_pss_parameters_data_setup(rsa_pss_parameters_data *d) +{ + unsigned long n; + /* RSASSA-PSS + * + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] TrailerField DEFAULT trailerFieldBC + * } + */ + + /* HashAlgorithm ::= AlgorithmIdentifier { + * {OAEP-PSSDigestAlgorithms} + * } + */ + LTC_SET_ASN1(d->hash_alg, 0, LTC_ASN1_OBJECT_IDENTIFIER, d->hash_alg_oid, LTC_ARRAY_SIZE(d->hash_alg_oid)); + LTC_SET_ASN1(d->hash_alg, 1, LTC_ASN1_NULL, NULL, 0); + d->hash_alg[1].optional = 1; + + /* MaskGenAlgorithm ::= AlgorithmIdentifier { {PKCS1MGFAlgorithms} } */ + LTC_SET_ASN1(d->mgf_hash_alg, 0, LTC_ASN1_OBJECT_IDENTIFIER, d->mgf1_hash_alg_oid, LTC_ARRAY_SIZE(d->mgf1_hash_alg_oid)); + LTC_SET_ASN1(d->mgf_hash_alg, 1, LTC_ASN1_NULL, NULL, 0); + d->mgf_hash_alg[1].optional = 1; + + /* PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-mgf1 PARAMETERS HashAlgorithm }, + * ... -- Allows for future expansion -- + * } + */ + LTC_SET_ASN1(d->mgf, 0, LTC_ASN1_OBJECT_IDENTIFIER, d->mgf_alg_oid, LTC_ARRAY_SIZE(d->mgf_alg_oid)); + LTC_SET_ASN1(d->mgf, 1, LTC_ASN1_SEQUENCE, d->mgf_hash_alg, LTC_ARRAY_SIZE(d->mgf_hash_alg)); + + LTC_SET_ASN1(d->inner, 0, LTC_ASN1_SEQUENCE, d->hash_alg, LTC_ARRAY_SIZE(d->hash_alg)); + LTC_SET_ASN1(d->inner, 1, LTC_ASN1_SEQUENCE, d->mgf, LTC_ARRAY_SIZE(d->mgf)); + LTC_SET_ASN1(d->inner, 2, LTC_ASN1_SHORT_INTEGER, &d->salt_length, 1UL); + LTC_SET_ASN1(d->inner, 3, LTC_ASN1_SHORT_INTEGER, &d->trailer_field, 1UL); + + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(d->params, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0, d->inner); /* context specific 0 */ + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(d->params, 1, LTC_ASN1_CL_CONTEXT_SPECIFIC, 1, d->inner + 1); /* context specific 1 */ + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(d->params, 2, LTC_ASN1_CL_CONTEXT_SPECIFIC, 2, d->inner + 2); /* context specific 2 */ + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(d->params, 3, LTC_ASN1_CL_CONTEXT_SPECIFIC, 3, d->inner + 3); /* context specific 3 */ + for (n = 0; n < 4; ++n) { + d->params[n].optional = 1; + } +} + +static int s_rsa_decode_parameters(const rsa_pss_parameters_data *d, ltc_rsa_parameters *rsa_params) +{ + unsigned long n; + enum ltc_oid_id oid_id; + int err, idx; + + rsa_params->saltlen = 20; + rsa_params->hash_alg = rsa_params->mgf1_hash_alg = "sha1"; + + for (n = 0; n < 4; ++n) { + if (d->params[n].used == 0) + continue; + switch (n) { + case 0: + idx = find_hash_oid(d->hash_alg->data, d->hash_alg->size); + if (idx == -1) { + return CRYPT_INVALID_HASH; + } + rsa_params->hash_alg = hash_descriptor[idx].name; + break; + case 1: + if ((err = pk_get_oid_from_asn1(&d->mgf[0], &oid_id)) != CRYPT_OK) { + return err; + } + if (oid_id != LTC_OID_RSA_MGF1) { + return CRYPT_PK_ASN1_ERROR; + } + idx = find_hash_oid(d->mgf_hash_alg->data, d->mgf_hash_alg->size); + if (idx == -1) { + return CRYPT_INVALID_HASH; + } + rsa_params->mgf1_hash_alg = hash_descriptor[idx].name; + break; + case 2: + rsa_params->saltlen = d->salt_length; + break; + case 3: + if (d->trailer_field != 1) { + return CRYPT_PK_ASN1_ERROR; + } + break; + default: + return CRYPT_PK_ASN1_ERROR; + } + } + + rsa_params->pss_oaep = 1; + + return CRYPT_OK; +} + +int rsa_decode_parameters(const ltc_asn1_list *parameters, ltc_rsa_parameters *rsa_params) +{ + int err; + rsa_pss_parameters_data d; + + s_rsa_pss_parameters_data_setup(&d); + + if ((err = der_decode_sequence(parameters->data, parameters->size, d.params, 4)) != CRYPT_OK) { + return err; + } + + return s_rsa_decode_parameters(&d, rsa_params); +} + +static LTC_INLINE int s_rsa_1_5_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + return x509_process_public_key_from_spki(in, inlen, + LTC_OID_RSA, + LTC_ASN1_NULL, NULL, NULL, + (public_key_decode_cb)s_rsa_decode, key); +} + +static LTC_INLINE int s_rsa_pss_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + int err; + rsa_pss_parameters_data d; + unsigned long n_params = LTC_ARRAY_SIZE(d.params); + + if (x509_process_public_key_from_spki(in, inlen, + LTC_OID_RSA_PSS, + LTC_ASN1_NULL, NULL, NULL, + (public_key_decode_cb)s_rsa_decode, key) == CRYPT_OK) { + return CRYPT_OK; + } + s_rsa_pss_parameters_data_setup(&d); + if ((err = x509_process_public_key_from_spki(in, inlen, + LTC_OID_RSA_PSS, + LTC_ASN1_SEQUENCE, d.params, &n_params, + (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { + return err; + } + return s_rsa_decode_parameters(&d, &key->params); +} + +static LTC_INLINE int s_rsa_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + int err; + if (s_rsa_1_5_import_spki(in, inlen, key) == CRYPT_OK) { + return CRYPT_OK; + } + + if ((err = s_rsa_pss_import_spki(in, inlen, key)) == CRYPT_OK) { + return CRYPT_OK; + } + return err; +} + +/** + Import an RSA key from SubjectPublicKeyInfo + @param in The packet to import from + @param inlen It's length (octets) + @param key [out] Destination for newly imported key + @return CRYPT_OK if successful, upon error allocated memory is freed +*/ +int rsa_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + int err; + + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(key != NULL); + LTC_ARGCHK(ltc_mp.name != NULL); + + /* init key */ + if ((err = rsa_init(key)) != CRYPT_OK) { + return err; + } + + if ((err = s_rsa_import_spki(in, inlen, key)) == CRYPT_OK) { + key->type = PK_PUBLIC; + return CRYPT_OK; + } + + rsa_free(key); + + return err; +} /** Import an RSA key from a X.509 certificate @@ -27,6 +224,8 @@ static int s_rsa_decode(const unsigned char *in, unsigned long inlen, rsa_key *k */ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) { + ltc_asn1_list *decoded_list; + const ltc_asn1_list *spki; int err; LTC_ARGCHK(in != NULL); @@ -38,16 +237,26 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) return err; } - if ((err = x509_decode_public_key_from_certificate(in, inlen, - LTC_OID_RSA, - LTC_ASN1_NULL, NULL, NULL, - (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { - rsa_free(key); - } else { + /* First try to decode as SubjectPublicKeyInfo */ + if (s_rsa_import_spki(in, inlen, key) == CRYPT_OK) { key->type = PK_PUBLIC; + return CRYPT_OK; } - return err; + /* Now try to extract the SubjectPublicKeyInfo from the Certificate */ + if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) { + rsa_free(key); + return err; + } + err = s_rsa_import_spki(spki->data, spki->size, key); + + der_free_sequence_flexi(decoded_list); + if (err != CRYPT_OK) { + rsa_free(key); + return err; + } + key->type = PK_PUBLIC; + return CRYPT_OK; } #endif /* LTC_MRSA */ diff --git a/src/pk/rsa/rsa_key.c b/src/pk/rsa/rsa_key.c index 7eb21b843..5bb37f7fb 100644 --- a/src/pk/rsa/rsa_key.c +++ b/src/pk/rsa/rsa_key.c @@ -85,6 +85,7 @@ void rsa_shrink_key(rsa_key *key) int rsa_init(rsa_key *key) { LTC_ARGCHK(key != NULL); + XMEMSET(&key->params, 0, sizeof(key->params)); return ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, LTC_NULL); } @@ -96,6 +97,90 @@ void rsa_free(rsa_key *key) { LTC_ARGCHKVD(key != NULL); ltc_mp_cleanup_multi(&key->q, &key->p, &key->qP, &key->dP, &key->dQ, &key->N, &key->d, &key->e, LTC_NULL); + XMEMSET(&key->params, 0, sizeof(key->params)); +} + +static LTC_INLINE int s_rsa_key_valid_pss_algs(const rsa_key *key, int padding, int hash_idx) +{ + if (!key->params.pss_oaep) { + return CRYPT_OK; + } + if (padding != LTC_PKCS_1_PSS) { + return CRYPT_PK_TYPE_MISMATCH; + } + if (key->params.hash_alg == NULL || find_hash(key->params.hash_alg) != hash_idx) { + return CRYPT_INVALID_HASH; + } + if (key->params.mgf1_hash_alg == NULL) { + return CRYPT_INVALID_HASH; + } + return hash_is_valid(find_hash(key->params.mgf1_hash_alg)); +} + +static LTC_INLINE int s_rsa_key_valid_sign(const rsa_key *key, int padding, int hash_idx) +{ + if ((padding != LTC_PKCS_1_V1_5) && + (padding != LTC_PKCS_1_PSS) && + (padding != LTC_PKCS_1_V1_5_NA1)) { + return CRYPT_PK_INVALID_PADDING; + } + + if (padding != LTC_PKCS_1_V1_5_NA1) { + int err; + /* valid hash ? */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + } + return s_rsa_key_valid_pss_algs(key, padding, hash_idx); +} + +static LTC_INLINE int s_rsa_key_valid_crypt(const rsa_key *key, int padding, int hash_idx) +{ + if ((padding != LTC_PKCS_1_V1_5) && + (padding != LTC_PKCS_1_OAEP)) { + return CRYPT_PK_INVALID_PADDING; + } + + if (padding == LTC_PKCS_1_OAEP) { + int err; + /* valid hash? */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + } + return s_rsa_key_valid_pss_algs(key, padding, hash_idx); +} + +int rsa_key_valid_op(const rsa_key *key, ltc_rsa_op op, int padding, int hash_idx) +{ + switch (op) { + case LTC_RSA_SIGN: + return s_rsa_key_valid_sign(key, padding, hash_idx); + case LTC_RSA_CRYPT: + return s_rsa_key_valid_crypt(key, padding, hash_idx); + default: + return CRYPT_ERROR; + } +} + +int rsa_params_equal(const ltc_rsa_parameters *a, const ltc_rsa_parameters *b) +{ + if (!a->pss_oaep) + return 0; + if (a->pss_oaep != b->pss_oaep) + return 0; + if (a->saltlen != b->saltlen) + return 0; + if (!a->hash_alg || !b->hash_alg) + return 0; + if (XSTRCMP(a->hash_alg, b->hash_alg)) + return 0; + if (!a->mgf1_hash_alg || !b->mgf1_hash_alg) + return 0; + if (XSTRCMP(a->mgf1_hash_alg, b->mgf1_hash_alg)) + return 0; + return 1; } #endif diff --git a/src/pk/rsa/rsa_sign_hash.c b/src/pk/rsa/rsa_sign_hash.c index bc5e0a89f..4445f712b 100644 --- a/src/pk/rsa/rsa_sign_hash.c +++ b/src/pk/rsa/rsa_sign_hash.c @@ -26,9 +26,10 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, int padding, - prng_state *prng, int prng_idx, - int hash_idx, unsigned long saltlen, - const rsa_key *key) + prng_state *prng, int prng_idx, + int hash_idx, int mgf_hash_idx, + unsigned long saltlen, + const rsa_key *key) { unsigned long modulus_bitlen, modulus_bytelen, x, y; int err; @@ -39,10 +40,8 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, LTC_ARGCHK(key != NULL); /* valid padding? */ - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_PSS) && - (padding != LTC_PKCS_1_V1_5_NA1)) { - return CRYPT_PK_INVALID_PADDING; + if ((err = rsa_key_valid_op(key, LTC_RSA_SIGN, padding, hash_idx)) != CRYPT_OK) { + return err; } if (padding == LTC_PKCS_1_PSS) { @@ -52,13 +51,6 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, } } - if (padding != LTC_PKCS_1_V1_5_NA1) { - /* valid hash ? */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { - return err; - } - } - /* get modulus len in bits */ modulus_bitlen = ltc_mp_count_bits((key->N)); @@ -72,8 +64,8 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, if (padding == LTC_PKCS_1_PSS) { /* PSS pad the key */ x = *outlen; - if ((err = pkcs_1_pss_encode(in, inlen, saltlen, prng, prng_idx, - hash_idx, modulus_bitlen, out, &x)) != CRYPT_OK) { + if ((err = pkcs_1_pss_encode_mgf1(in, inlen, saltlen, prng, prng_idx, + hash_idx, mgf_hash_idx, modulus_bitlen, out, &x)) != CRYPT_OK) { return err; } } else { diff --git a/src/pk/rsa/rsa_verify_hash.c b/src/pk/rsa/rsa_verify_hash.c index 9ca1641a6..ede234497 100644 --- a/src/pk/rsa/rsa_verify_hash.c +++ b/src/pk/rsa/rsa_verify_hash.c @@ -25,7 +25,8 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int padding, - int hash_idx, unsigned long saltlen, + int hash_idx, int mgf_hash_idx, + unsigned long saltlen, int *stat, const rsa_key *key) { unsigned long modulus_bitlen, modulus_bytelen, x; @@ -41,18 +42,8 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle *stat = 0; /* valid padding? */ - - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_PSS) && - (padding != LTC_PKCS_1_V1_5_NA1)) { - return CRYPT_PK_INVALID_PADDING; - } - - if (padding != LTC_PKCS_1_V1_5_NA1) { - /* valid hash ? */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { - return err; - } + if ((err = rsa_key_valid_op(key, LTC_RSA_SIGN, padding, hash_idx)) != CRYPT_OK) { + return err; } /* get modulus len in bits */ @@ -87,10 +78,10 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle /* PSS decode and verify it */ if(modulus_bitlen%8 == 1){ - err = pkcs_1_pss_decode(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, modulus_bitlen, stat); + err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat); } else{ - err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_idx, modulus_bitlen, stat); + err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf, x, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat); } } else { diff --git a/tests/der_test.c b/tests/der_test.c index a7dee0a2b..791dccf49 100644 --- a/tests/der_test.c +++ b/tests/der_test.c @@ -88,125 +88,29 @@ const char ltc_der_tests_cacert_root_cert[] = "omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD"; const unsigned long ltc_der_tests_cacert_root_cert_size = sizeof(ltc_der_tests_cacert_root_cert); -/* -SEQUENCE(3 elem) - SEQUENCE(8 elem) - [0](1) - INTEGER 2 - INTEGER 0 - SEQUENCE(2 elem) - OBJECT IDENTIFIER 1.2.840.113549.1.1.4 - NULL - SEQUENCE(4 elem) - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.4.10 - PrintableString Root CA - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.4.11 - PrintableString http://www.cacert.org - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.4.3 - PrintableString CA Cert Signing Authority - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 1.2.840.113549.1.9.1 - IA5String support@cacert.org - SEQUENCE(2 elem) - UTCTime03-03-30 12:29:49 UTC - UTCTime33-03-29 12:29:49 UTC - SEQUENCE(4 elem) - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.4.10 - PrintableString Root CA - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.4.11 - PrintableString http://www.cacert.org - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.4.3 - PrintableString CA Cert Signing Authority - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 1.2.840.113549.1.9.1 - IA5String support@cacert.org - SEQUENCE(2 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 1.2.840.113549.1.1.1 - NULL - BIT STRING(1 elem) - SEQUENCE(2 elem) - INTEGER (4096 bit) - INTEGER 65537 - [3](1) - SEQUENCE(7 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.29.14 - OCTET STRING(1 elem) - OCTET STRING(20 byte) 16B5321BD4C7F3E0E68EF3BDD2B03AEEB23918D1 - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.29.35 - OCTET STRING(1 elem) - SEQUENCE(3 elem) - [0] - [1](1) - [4](1) - SEQUENCE(4 elem) - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.4.10 - PrintableString Root CA - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.4.11 - PrintableString http://www.cacert.org - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.4.3 - PrintableString CA Cert Signing Authority - SET(1 elem) - SEQUENCE(2 elem) - OBJECT IDENTIFIER 1.2.840.113549.1.9.1 - IA5String support@cacert.org - [2] - SEQUENCE(3 elem) - OBJECT IDENTIFIER 2.5.29.19 - BOOLEAN true - OCTET STRING(1 elem) - SEQUENCE(1 elem) - BOOLEAN true - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.5.29.31 - OCTET STRING(1 elem) - SEQUENCE(1 elem) - SEQUENCE(1 elem) - [0](1) - [0](1) - [6] - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.16.840.1.113730.1.4 - OCTET STRING(1 elem) - IA5String https://www.cacert.org/revoke.crl - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.16.840.1.113730.1.8 - OCTET STRING(1 elem) - IA5String http://www.cacert.org/index.php?id=10 - SEQUENCE(2 elem) - OBJECT IDENTIFIER 2.16.840.1.113730.1.13 - OCTET STRING(1 elem) - IA5String To get your own certificate for FREE head over to http://www.cacert.org - SEQUENCE(2 elem) - OBJECT IDENTIFIER 1.2.840.113549.1.1.4 - NULL - BIT STRING(4096 bit) - */ +#ifdef LTC_DER_TESTS_PRINT_FLEXI + +#define LTC_DER_PRINT_FLEXI_NO_MAIN +#include "../demos/der_print_flexi.c" +static void s_der_tests_print_flexi(ltc_asn1_list* l) +{ + fprintf(stderr, "\n\n"); + s_der_print_flexi_i(l, 0); + fprintf(stderr, "\n\n"); +} + +#else +static void s_der_tests_print_flexi(ltc_asn1_list* l) +{ + LTC_UNUSED_PARAM(l); +} +#endif + +#ifndef ASN1_FMTSTRING_FMT #define ASN1_FMTSTRING_FMT "line: %d, type=%d, size=%lu, data=%p, self=%p, next=%p, prev=%p, parent=%p, child=%p" #define ASN1_FMTSTRING_VAL(l) __LINE__, (l)->type, (l)->size, (l)->data, (l), (l)->next, (l)->prev, (l)->parent, (l)->child +#endif #define ASN1_ERR(l) fprintf(stderr, ASN1_FMTSTRING_FMT "\n", ASN1_FMTSTRING_VAL(l)); \ exit(EXIT_FAILURE) @@ -230,238 +134,6 @@ SEQUENCE(3 elem) #define CHECK_ASN1_HAS_DATA(l) CHECK_ASN1_HAS(l, data) #define CHECK_ASN1_HAS_NO_DATA(l) CHECK_ASN1_HAS_NO(l, data) -#ifdef LTC_DER_TESTS_PRINT_FLEXI - -static void* s_xmalloc(int l) -{ - void *r = XMALLOC(l); - -#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 3 - fprintf(stderr, "ALLOC %9d to %p\n", l, r); -#endif - if (!r) { - fprintf(stderr, "Could not allocate %d bytes of memory\n", l); - exit(EXIT_FAILURE); - } - return r; -} - -static void s_free(void *p) -{ -#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 3 - fprintf(stderr, "FREE %p\n", p); -#endif - XFREE(p); -} - -static void s_der_tests_print_flexi_i(ltc_asn1_list* l, unsigned int level) -{ - char *buf = NULL; - const char* name = NULL; - const char* text = NULL; - ltc_asn1_list* ostring = NULL; - unsigned int n; - int slen; - - switch (l->type) - { - case LTC_ASN1_EOL: - name = "EOL"; - slen = snprintf(NULL, 0, ASN1_FMTSTRING_FMT "\n", ASN1_FMTSTRING_VAL(l)); - buf = s_xmalloc(slen); - slen = snprintf(buf, slen, ASN1_FMTSTRING_FMT "\n", ASN1_FMTSTRING_VAL(l)); - text = buf; - break; - case LTC_ASN1_BOOLEAN: - name = "BOOLEAN"; - { - if (*(int*)l->data) - text = "true"; - else - text = "false"; - } - break; - case LTC_ASN1_INTEGER: - name = "INTEGER"; - buf = s_xmalloc(((ltc_mp_get_digit_count(l->data) + 1) * ltc_mp.bits_per_digit) / 3); - ltc_mp_toradix(l->data, buf, 10); - text = buf; - break; - case LTC_ASN1_SHORT_INTEGER: - name = "SHORT INTEGER"; - break; - case LTC_ASN1_BIT_STRING: - name = "BIT STRING"; - break; - case LTC_ASN1_OCTET_STRING: - name = "OCTET STRING"; - { - unsigned long ostring_l = l->size; - /* sometimes there's another sequence in an octet string... - * try to decode that... if it fails print out the octet string - */ - if (der_decode_sequence_flexi(l->data, &ostring_l, &ostring) == CRYPT_OK) { - text = ""; - } else { - int r; - int sz = l->size * 2 + 1; - char* s = buf = s_xmalloc(sz); - for (n = 0; n < l->size; ++n) { - r = snprintf(s, sz, "%02X", ((unsigned char*)l->data)[n]); - if (r < 0 || r >= sz) { - fprintf(stderr, "%s boom\n", name); - exit(EXIT_FAILURE); - } - s += r; - sz -= r; - } - text = buf; - } - } - break; - case LTC_ASN1_NULL: - name = "NULL"; - text = ""; - break; - case LTC_ASN1_OBJECT_IDENTIFIER: - name = "OBJECT IDENTIFIER"; - { - unsigned long len = 0; - if (pk_oid_num_to_str(l->data, l->size, buf, &len) != CRYPT_BUFFER_OVERFLOW) { - fprintf(stderr, "%s WTF\n", name); - exit(EXIT_FAILURE); - } - buf = s_xmalloc(len); - if (pk_oid_num_to_str(l->data, l->size, buf, &len) != CRYPT_OK) { - fprintf(stderr, "%s boom\n", name); - exit(EXIT_FAILURE); - } - text = buf; - } - break; - case LTC_ASN1_IA5_STRING: - name = "IA5 STRING"; - text = l->data; - break; - case LTC_ASN1_PRINTABLE_STRING: - name = "PRINTABLE STRING"; - text = l->data; - break; - case LTC_ASN1_UTF8_STRING: - name = "UTF8 STRING"; - break; - case LTC_ASN1_UTCTIME: - name = "UTCTIME"; - { - ltc_utctime* ut = l->data; - slen = 32; - buf = s_xmalloc(slen); - snprintf(buf, slen, "%02d-%02d-%02d %02d:%02d:%02d %c%02d:%02d", - ut->YY, ut->MM, ut->DD, ut->hh, ut->mm, ut->ss, - ut->off_dir ? '-' : '+', ut->off_hh, ut->off_mm); - text = buf; - } - break; - case LTC_ASN1_GENERALIZEDTIME: - name = "GENERALIZED TIME"; - { - ltc_generalizedtime* gt = l->data; - slen = 32; - buf = s_xmalloc(slen); - if(gt->fs) - snprintf(buf, slen, "%04d-%02d-%02d %02d:%02d:%02d.%02dZ", - gt->YYYY, gt->MM, gt->DD, gt->hh, gt->mm, gt->ss, gt->fs); - else - snprintf(buf, slen, "%04d-%02d-%02d %02d:%02d:%02dZ", - gt->YYYY, gt->MM, gt->DD, gt->hh, gt->mm, gt->ss); - text = buf; - } - break; - case LTC_ASN1_CHOICE: - name = "CHOICE"; - break; - case LTC_ASN1_SEQUENCE: - name = "SEQUENCE"; - text = ""; - break; - case LTC_ASN1_SET: - name = "SET"; - text = ""; - break; - case LTC_ASN1_SETOF: - name = "SETOF"; - text = ""; - break; - case LTC_ASN1_RAW_BIT_STRING: - name = "RAW BIT STRING"; - break; - case LTC_ASN1_TELETEX_STRING: - name = "TELETEX STRING"; - text = l->data; - break; - case LTC_ASN1_CUSTOM_TYPE: - name = "NON STANDARD"; - { - int r; - int sz = 128; - char* s = buf = s_xmalloc(sz); - - r = snprintf(s, sz, "[%s %s %llu]", der_asn1_class_to_string_map[l->klass], der_asn1_pc_to_string_map[l->pc], l->tag); - if (r < 0 || r >= sz) { - fprintf(stderr, "%s boom\n", name); - exit(EXIT_FAILURE); - } - s += r; - sz -= r; - - text = buf; - } - break; - } - - for (n = 0; n < level; ++n) { - fprintf(stderr, " "); - } - if (name) { - if (text) - fprintf(stderr, "%s %s\n", name, text); - else - fprintf(stderr, "%s \n", name); - } - else - fprintf(stderr, "WTF type=%i\n", l->type); - - if (buf) { - s_free(buf); - buf = NULL; - } - - if (ostring) { - s_der_tests_print_flexi_i(ostring, level + 1); - der_free_sequence_flexi(ostring); - } - - if (l->child) - s_der_tests_print_flexi_i(l->child, level + 1); - - if (l->next) - s_der_tests_print_flexi_i(l->next, level); -} - -static void s_der_tests_print_flexi(ltc_asn1_list* l) -{ - fprintf(stderr, "\n\n"); - s_der_tests_print_flexi_i(l, 0); - fprintf(stderr, "\n\n"); -} - -#else -static void s_der_tests_print_flexi(ltc_asn1_list* l) -{ - LTC_UNUSED_PARAM(l); -} -#endif - static void der_cacert_test(void) { unsigned char buf[sizeof(ltc_der_tests_cacert_root_cert)]; diff --git a/tests/pkcs_1_eme_test.c b/tests/pkcs_1_eme_test.c index ca540360b..9e818ace6 100644 --- a/tests/pkcs_1_eme_test.c +++ b/tests/pkcs_1_eme_test.c @@ -24,8 +24,7 @@ int pkcs_1_eme_test(void) for (i = 0; i < LTC_ARRAY_SIZE(testcases_eme); ++i) { testcase_t* t = &testcases_eme[i]; rsa_key k, *key = &k; - DOX(ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, - &key->dP, &key->qP, &key->p, &key->q, NULL), t->name); + DOX(rsa_init(key), t->name); DOX(ltc_mp_read_unsigned_bin(key->e, t->rsa.e, t->rsa.e_l), t->name); DOX(ltc_mp_read_unsigned_bin(key->d, t->rsa.d, t->rsa.d_l), t->name); diff --git a/tests/pkcs_1_emsa_test.c b/tests/pkcs_1_emsa_test.c index ba66f079a..327f2b5df 100644 --- a/tests/pkcs_1_emsa_test.c +++ b/tests/pkcs_1_emsa_test.c @@ -21,8 +21,7 @@ int pkcs_1_emsa_test(void) for (i = 0; i < LTC_ARRAY_SIZE(testcases_emsa); ++i) { testcase_t* t = &testcases_emsa[i]; rsa_key k, *key = &k; - DOX(ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, - &key->dP, &key->qP, &key->p, &key->q, NULL), t->name); + DOX(rsa_init(key), t->name); DOX(ltc_mp_read_unsigned_bin(key->e, t->rsa.e, t->rsa.e_l), t->name); DOX(ltc_mp_read_unsigned_bin(key->d, t->rsa.d, t->rsa.d_l), t->name); @@ -40,9 +39,9 @@ int pkcs_1_emsa_test(void) unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf); int stat; DOX(hash_memory(hash_idx, s->o1, s->o1_l, buf, &buflen), s->name); - DOX(rsa_sign_hash_ex(buf, buflen, obuf, &obuflen, LTC_PKCS_1_V1_5, NULL, -1, hash_idx, 0, key), s->name); + DOX(rsa_sign_hash_ex(buf, buflen, obuf, &obuflen, LTC_PKCS_1_V1_5, NULL, -1, hash_idx, -1, 0, key), s->name); COMPARE_TESTVECTOR(obuf, obuflen, s->o2, s->o2_l,s->name, j); - DOX(rsa_verify_hash_ex(obuf, obuflen, buf, buflen, LTC_PKCS_1_V1_5, hash_idx, 0, &stat, key), s->name); + DOX(rsa_verify_hash_ex(obuf, obuflen, buf, buflen, LTC_PKCS_1_V1_5, hash_idx, -1, 0, &stat, key), s->name); DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name); } /* for */ diff --git a/tests/pkcs_1_oaep_test.c b/tests/pkcs_1_oaep_test.c index 1cb6ca128..76157c2c0 100644 --- a/tests/pkcs_1_oaep_test.c +++ b/tests/pkcs_1_oaep_test.c @@ -24,8 +24,7 @@ int pkcs_1_oaep_test(void) for (i = 0; i < LTC_ARRAY_SIZE(testcases_oaep); ++i) { testcase_t* t = &testcases_oaep[i]; rsa_key k, *key = &k; - DOX(ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, - &key->dP, &key->qP, &key->p, &key->q, NULL), t->name); + DOX(rsa_init(key), t->name); DOX(ltc_mp_read_unsigned_bin(key->e, t->rsa.e, t->rsa.e_l), t->name); DOX(ltc_mp_read_unsigned_bin(key->d, t->rsa.d, t->rsa.d_l), t->name); diff --git a/tests/pkcs_1_pss_test.c b/tests/pkcs_1_pss_test.c index a62e53ff0..a86e473ac 100644 --- a/tests/pkcs_1_pss_test.c +++ b/tests/pkcs_1_pss_test.c @@ -24,8 +24,7 @@ int pkcs_1_pss_test(void) for (i = 0; i < LTC_ARRAY_SIZE(testcases_pss); ++i) { testcase_t* t = &testcases_pss[i]; rsa_key k, *key = &k; - DOX(ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, - &key->dP, &key->qP, &key->p, &key->q, NULL), t->name); + DOX(rsa_init(key), t->name); DOX(ltc_mp_read_unsigned_bin(key->e, t->rsa.e, t->rsa.e_l), t->name); DOX(ltc_mp_read_unsigned_bin(key->d, t->rsa.d, t->rsa.d_l), t->name); diff --git a/tests/rsa_test.c b/tests/rsa_test.c index 568e70fce..15343c9a1 100644 --- a/tests/rsa_test.c +++ b/tests/rsa_test.c @@ -191,13 +191,13 @@ static int rsa_compat_test(void) /* sign-verify a message with PKCS #1 v1.5 no ASN.1 */ len = sizeof(buf); - DO(rsa_sign_hash_ex((unsigned char*)"test", 4, buf, &len, LTC_PKCS_1_V1_5_NA1, NULL, 0, 0, 0, &key)); + DO(rsa_sign_hash_ex((unsigned char*)"test", 4, buf, &len, LTC_PKCS_1_V1_5_NA1, NULL, 0, 0, 0, 0, &key)); if (len != sizeof(openssl_rsautl_pkcs) || memcmp(buf, openssl_rsautl_pkcs, len)) { fprintf(stderr, "RSA rsa_sign_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n"); return 1; } stat = 0; - DO(rsa_verify_hash_ex(openssl_rsautl_pkcs, sizeof(openssl_rsautl_pkcs), (unsigned char*)"test", 4, LTC_PKCS_1_V1_5_NA1, 0, 0, &stat, &pubkey)); + DO(rsa_verify_hash_ex(openssl_rsautl_pkcs, sizeof(openssl_rsautl_pkcs), (unsigned char*)"test", 4, LTC_PKCS_1_V1_5_NA1, 0, 0, 0, &stat, &pubkey)); if (stat != 1) { fprintf(stderr, "RSA rsa_verify_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n"); return 1; @@ -331,9 +331,9 @@ static int s_rsa_cryptx_issue_69(void) l1 = sizeof(buf1); DO(radix_to_bin(sig1, 16, buf0, &l0)); DO(radix_to_bin(hash, 16, buf1, &l1)); - SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, &stat, &key)); + SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key)); DO(radix_to_bin(sig2, 16, buf0, &l0)); - SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, &stat, &key)); + SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key)); rsa_free(&key); return CRYPT_OK; } @@ -683,11 +683,11 @@ print_hex("q", tmp, len); /* sign a message with PKCS #1 v1.5 */ len = sizeof(out); - DO(rsa_sign_hash_ex(in, 20, out, &len, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 8, &privKey)); - DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 8, &stat, &pubKey)); + DO(rsa_sign_hash_ex(in, 20, out, &len, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey)); + DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat, &pubKey)); /* change a byte */ in[0] ^= 1; - DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 8, &stat2, &pubKey)); + DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat2, &pubKey)); if (!(stat == 1 && stat2 == 0)) { fprintf(stderr, "rsa_verify_hash_ex failed, %d, %d", stat, stat2); @@ -720,9 +720,9 @@ print_hex("q", tmp, len); len = sizeof(in); len2 = sizeof(out); /* (1) */ - DO(rsa_sign_hash_ex(p, 20, p2, &len2, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 8, &privKey)); + DO(rsa_sign_hash_ex(p, 20, p2, &len2, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey)); /* (2) */ - DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey), "should succeed"); + DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, 0, -1, &stat, &pubKey), "should succeed"); DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should succeed"); len3 = sizeof(tmp); /* (3) */ @@ -756,7 +756,7 @@ print_hex("q", tmp, len); len3 = sizeof(tmp); /* (6) */ - SHOULD_FAIL(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey)); + SHOULD_FAIL(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, -1, &stat, &pubKey)); DOX(stat == 0?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should fail"); } rsa_free(&key);