diff --git a/include/wolfprovider/wp_params.h b/include/wolfprovider/wp_params.h index bb534c2d..c056c498 100644 --- a/include/wolfprovider/wp_params.h +++ b/include/wolfprovider/wp_params.h @@ -73,6 +73,6 @@ int wp_params_get_uint(const OSSL_PARAM* params, const char* key, int wp_params_set_mp(OSSL_PARAM params[], const char* key, mp_int* mp); int wp_params_set_octet_string_be(OSSL_PARAM params[], const char* key, unsigned char* data, size_t len); - +int wp_params_count(const OSSL_PARAM *p); #endif /* WP_PARAMS_H */ diff --git a/scripts/utils-wolfssl.sh b/scripts/utils-wolfssl.sh index f4161815..ece33439 100755 --- a/scripts/utils-wolfssl.sh +++ b/scripts/utils-wolfssl.sh @@ -81,7 +81,11 @@ install_wolfssl() { CONF_ARGS="-prefix=${WOLFSSL_INSTALL_DIR}" if [ "$WOLFPROV_DEBUG" = "1" ]; then - CONF_ARGS+=" --enable-debug --enable-debug-trace-errcodes=backtrace --enable-keylog-export" + CONF_ARGS+=" --enable-debug --enable-keylog-export" + if [[ "$OSTYPE" != "darwin"* ]]; then + # macOS doesn't support backtrace + CONF_ARGS+=" --enable-debug-trace-errcodes=backtrace" + fi WOLFSSL_CONFIG_CFLAGS+=" -DWOLFSSL_LOGGINGENABLED_DEFAULT=1" fi if [ -n "$WOLFSSL_FIPS_BUNDLE" ]; then diff --git a/src/wp_params.c b/src/wp_params.c index 3eeaf1eb..8f462523 100644 --- a/src/wp_params.c +++ b/src/wp_params.c @@ -645,3 +645,18 @@ int wp_params_set_octet_string_be(OSSL_PARAM params[], const char* key, return ok; } +/** + * Count the number of parameters in the array, not including the end marker. + * + * @param [in] params Array of parameters. + * @return number of parameters in the array. + */ +int wp_params_count(const OSSL_PARAM *p) +{ + int cnt = 0; + while ((p != NULL) && (p->key != NULL)) { + cnt++; + p++; + } + return cnt; +} diff --git a/src/wp_rsa_kmgmt.c b/src/wp_rsa_kmgmt.c index 555b67fc..cbd560bf 100644 --- a/src/wp_rsa_kmgmt.c +++ b/src/wp_rsa_kmgmt.c @@ -77,6 +77,9 @@ OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT1, NULL, 0) #define OFFSETOF(type, field) ((size_t)&(((type *)0)->field)) #endif +#ifndef ARRAY_SIZE + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif /** SHA-256 Algorithm ID DER encoding in PSS parameters. */ static const byte sha256AlgId[] = { @@ -1064,16 +1067,6 @@ static int wp_rsa_validate(const wp_Rsa* rsa, int selection, int checkType) return ok; } -static int wp_params_count(const OSSL_PARAM *p) -{ - int cnt = 0; - while ((p != NULL) && (p->key != NULL)) { - cnt++; - p++; - } - return cnt; -} - /** * Import the key data into RSA key object from parameters. * @@ -1087,28 +1080,48 @@ static int wp_rsa_import_key_data(wp_Rsa* rsa, const OSSL_PARAM params[], int priv) { int ok = 1; - int i; - int cnt; - - if (priv && (wp_params_count(params) > 2)) { - cnt = WP_RSA_PARAM_NUMS_CNT; - rsa->key.type = RSA_PRIVATE; - } - else { - cnt = WP_RSA_PARAM_PUB_NUMS_CNT; - rsa->key.type = RSA_PUBLIC; + int i, j, index = -1; + int cnt = 0; + mp_int* mp = NULL; + const OSSL_PARAM* p = NULL; + + /* N and E params are the only ones required by OSSL, so match that. + * See ossl_rsa_fromdata() and RSA_set0_key() in OpenSSL. */ + if (OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N) == NULL || + OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E) == NULL) { + WOLFPROV_MSG(WP_LOG_PK, "Param N or E is missing"); + ok = 0; } - for (i = 0; ok && (i < cnt); i++) { - const OSSL_PARAM* p = OSSL_PARAM_locate_const(params, - wp_rsa_param_key[i]); - if (p == NULL) { - ok = 0; - } - if (ok) { - mp_int* mp = (mp_int*)(((byte*)&rsa->key) + wp_rsa_offset[i]); - if (!wp_mp_read_unsigned_bin_le(mp, p->data, p->data_size)) { - ok = 0; + if (ok) { + cnt = wp_params_count(params); + rsa->key.type = priv ? RSA_PRIVATE : RSA_PUBLIC; + + for (i = 0; i < cnt; i++) { + /* Use the table to look up the offset in the rsa struct */ + p = ¶ms[i]; + index = -1; + for (j = 0; j < (int)ARRAY_SIZE(wp_rsa_param_key); j++) { + if (XSTRNCMP(p->key, wp_rsa_param_key[j], p->data_size) == 0) { + index = j; + break; + } + } + if (index < 0) { + /* Follow OSSL implementation and ignore irrelevant fields. */ + WOLFPROV_MSG(WP_LOG_PK, "Unexpected param %s, skipping.", + p->key); + continue; + } + + /* Read the value into the rsa struct */ + if (ok) { + mp = (mp_int*)(((byte*)&rsa->key) + wp_rsa_offset[index]); + if (!wp_mp_read_unsigned_bin_le(mp, p->data, p->data_size)) { + WOLFPROV_MSG(WP_LOG_PK, + "Failed to read %s from parameters", p->key); + ok = 0; + } } } } diff --git a/test/test_rsa.c b/test/test_rsa.c index 510ffc87..f7bb25a0 100644 --- a/test/test_rsa.c +++ b/test/test_rsa.c @@ -26,6 +26,10 @@ #ifdef WP_HAVE_RSA +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + static const unsigned char rsa_key_der_256[] = { 0x30, 0x81, 0xC1, 0x02, 0x01, 0x00, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, @@ -1004,4 +1008,154 @@ int test_rsa_load_cert(void* data) OSSL_STORE_close(ctx); return err; } + +int test_rsa_fromdata(void* data) +{ + (void)data; + int err = 0; + EVP_PKEY_CTX *ctx_wolf = NULL; + EVP_PKEY_CTX *ctx_ossl = NULL; + + PRINT_MSG("Testing EVP_PKEY_fromdata"); + + ctx_wolf = EVP_PKEY_CTX_new_from_name(wpLibCtx, "RSA", NULL); + ctx_ossl = EVP_PKEY_CTX_new_from_name(osslLibCtx, "RSA", NULL); + if (ctx_wolf == NULL || ctx_ossl == NULL) { + err = 1; + } + + if (err == 0) { + /* EVP_PKEY_fromdata_init returns 1 on success */ + err |= EVP_PKEY_fromdata_init(ctx_wolf) != 1; + err |= EVP_PKEY_fromdata_init(ctx_ossl) != 1; + } + + if (err == 0) { + EVP_PKEY *pkey_wolf = NULL; + EVP_PKEY *pkey_ossl = NULL; + + /* Permutations of the selection field to test */ + static const int selections[] = { + EVP_PKEY_KEYPAIR, + EVP_PKEY_PUBLIC_KEY, + EVP_PKEY_PRIVATE_KEY, + }; + + /* Parameter data fields */ + unsigned long rsa_n = 0xbc747fc5; + unsigned long rsa_e = 0x10001; + unsigned long rsa_d = 0x7b133399; + const char *foo = "some string"; + size_t foo_l = strlen(foo); + const char bar[] = "some other string"; + + /* Permutations of the params field to test */ + OSSL_PARAM params_none[] = { + OSSL_PARAM_END + }; + OSSL_PARAM params_n[] = { + OSSL_PARAM_ulong("n", &rsa_n), + OSSL_PARAM_END + }; + OSSL_PARAM params_e[] = { + OSSL_PARAM_ulong("e", &rsa_e), + OSSL_PARAM_END + }; + OSSL_PARAM params_d[] = { + OSSL_PARAM_ulong("d", &rsa_d), + OSSL_PARAM_END + }; + OSSL_PARAM params_ne[] = { + OSSL_PARAM_ulong("n", &rsa_n), + OSSL_PARAM_ulong("e", &rsa_e), + OSSL_PARAM_END + }; + OSSL_PARAM params_nd[] = { + OSSL_PARAM_ulong("n", &rsa_n), + OSSL_PARAM_ulong("d", &rsa_d), + OSSL_PARAM_END + }; + OSSL_PARAM params_ed[] = { + OSSL_PARAM_ulong("e", &rsa_e), + OSSL_PARAM_ulong("d", &rsa_d), + OSSL_PARAM_END + }; + OSSL_PARAM params_ned[] = { + OSSL_PARAM_ulong("n", &rsa_n), + OSSL_PARAM_ulong("e", &rsa_e), + OSSL_PARAM_ulong("d", &rsa_d), + OSSL_PARAM_END + }; + OSSL_PARAM params_extra_ulong[] = { + OSSL_PARAM_ulong("n", &rsa_n), + OSSL_PARAM_ulong("e", &rsa_e), + OSSL_PARAM_ulong("d", &rsa_d), + OSSL_PARAM_ulong("asdf", &rsa_d), + OSSL_PARAM_END + }; + OSSL_PARAM params_extra_str[] = { + OSSL_PARAM_ulong("n", &rsa_n), + OSSL_PARAM_ulong("e", &rsa_e), + OSSL_PARAM_ulong("d", &rsa_d), + { "foo", OSSL_PARAM_UTF8_PTR, &foo, foo_l, 0 }, + { "bar", OSSL_PARAM_UTF8_STRING, (void *)&bar, sizeof(bar) - 1, 0 }, + OSSL_PARAM_END + }; + OSSL_PARAM* params_table[] = { + params_none, + params_n, + params_e, + params_d, + params_ne, + params_nd, + params_ed, + params_ned, + params_extra_ulong, + params_extra_str, + }; + + for (unsigned i = 0; i < ARRAY_SIZE(selections); i++) { + for (unsigned j = 0; j < ARRAY_SIZE(params_table); j++) { + int status_wolf = EVP_PKEY_fromdata(ctx_wolf, &pkey_wolf, + selections[i], ¶ms_table[j][0]); + int status_ossl = EVP_PKEY_fromdata(ctx_ossl, &pkey_ossl, + selections[i], ¶ms_table[j][0]); + + if (status_wolf != status_ossl) { + PRINT_MSG("EVP_PKEY_fromdata (wolf=%d) and (ossl=%d) status " + "mismatch for selection %d (0x%08X) and params %d", + status_wolf, status_ossl, i, selections[i], j); + err = 1; + } + else if (status_wolf == 1) { + PRINT_MSG("EVP_PKEY_fromdata (wolf) succeeded for " + "selection %d (0x%08X) and params %d", + i, selections[i], j); + + if (EVP_PKEY_cmp(pkey_wolf, pkey_ossl) != 1) { + PRINT_MSG("EVP_PKEY_cmp failed for selection %d " + "(0x%08X)", i, selections[i]); + err = 1; + } + if (EVP_PKEY_cmp_parameters(pkey_wolf, pkey_ossl) != 1) { + PRINT_MSG("EVP_PKEY_cmp_parameters failed for " + "selection %d (0x%08X)", i, selections[i]); + err = 1; + } + } + + EVP_PKEY_free(pkey_wolf); + EVP_PKEY_free(pkey_ossl); + pkey_wolf = NULL; + pkey_ossl = NULL; + } + } + } + + EVP_PKEY_CTX_free(ctx_wolf); + EVP_PKEY_CTX_free(ctx_ossl); + + return err; +} + #endif /* WP_HAVE_RSA */ diff --git a/test/unit.c b/test/unit.c index b2b710cb..6bd66612 100644 --- a/test/unit.c +++ b/test/unit.c @@ -164,6 +164,7 @@ TEST_CASE test_case[] = { TEST_DECL(test_rsa_get_params, NULL), TEST_DECL(test_rsa_load_key, NULL), TEST_DECL(test_rsa_load_cert, NULL), + TEST_DECL(test_rsa_fromdata, NULL), #endif /* WP_HAVE_RSA */ #ifdef WP_HAVE_EC_P192 #ifdef WP_HAVE_ECKEYGEN diff --git a/test/unit.h b/test/unit.h index cf33f4fa..98be6bcf 100644 --- a/test/unit.h +++ b/test/unit.h @@ -47,8 +47,8 @@ #define PRINT_MSG(str) #define PRINT_ERR_MSG(str) #else -#define PRINT_MSG(str) printf("MSG: %s\n", str) -#define PRINT_ERR_MSG(str) printf("ERR: %s\n", str) +#define PRINT_MSG(str, ...) printf("MSG: " str "\n", ##__VA_ARGS__) +#define PRINT_ERR_MSG(str, ...) printf("ERR: " str "\n", ##__VA_ARGS__) #endif #ifdef WOLFPROV_DEBUG void print_buffer(const char *desc, const unsigned char *buffer, size_t len); @@ -243,6 +243,7 @@ int test_rsa_get_params(void *data); int test_rsa_load_key(void* data); int test_rsa_load_cert(void* data); +int test_rsa_fromdata(void* data); #endif /* WP_HAVE_RSA */ #ifdef WP_HAVE_DH