diff options
author | Matt Caswell <matt@openssl.org> | 2020-02-28 08:08:59 +1000 |
---|---|---|
committer | Shane Lontis <shane.lontis@oracle.com> | 2020-02-28 08:08:59 +1000 |
commit | 8efc4a9c656b8b3eabeac64c54efdeb07dd42f8e (patch) | |
tree | b0bc5aac800d9bb912afb2dae10dd3f3bf503a08 /test/evp_pkey_provided_test.c | |
parent | 30a4cda5e0c67b4e77da4f21b7c5f27991d3367a (diff) |
Implement the ECX Serializers
Provide serializers for X25519 and X448 for text, pem and der. There are
no parameter serializers because there are no parameters for these
algorithms.
Add some documentation about the various import/export types available
Add additional testing for the serializers
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11095)
Diffstat (limited to 'test/evp_pkey_provided_test.c')
-rw-r--r-- | test/evp_pkey_provided_test.c | 361 |
1 files changed, 327 insertions, 34 deletions
diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c index 3c1c090bde..c161698505 100644 --- a/test/evp_pkey_provided_test.c +++ b/test/evp_pkey_provided_test.c @@ -13,72 +13,242 @@ #include <openssl/provider.h> #include <openssl/params.h> #include <openssl/core_names.h> +#include "crypto/ecx.h" #include "internal/nelem.h" #include "crypto/evp.h" /* For the internal API */ #include "testutil.h" -static int test_print_key_using_pem(const EVP_PKEY *pk) +static char *datadir = NULL; + +#define PRIV_TEXT 0 +#define PRIV_PEM 1 +#define PRIV_DER 2 +#define PUB_TEXT 3 +#define PUB_PEM 4 +#define PUB_DER 5 + +static void stripcr(char *buf, size_t *len) +{ + size_t i; + char *curr, *writ; + + for (i = *len, curr = buf, writ = buf; i > 0; i--, curr++) { + if (*curr == '\r') { + (*len)--; + continue; + } + if (curr != writ) + *writ = *curr; + writ++; + } +} + +static int compare_with_file(const char *alg, int type, BIO *membio) +{ + char filename[80]; + BIO *file = NULL; + char buf[1024]; + char *memdata, *fullfile = NULL; + const char *suffix; + size_t readbytes; + int ret = 0; + int len; + size_t slen; + + switch (type) { + case PRIV_TEXT: + suffix = "priv.txt"; + break; + + case PRIV_PEM: + suffix = "priv.pem"; + break; + + case PRIV_DER: + suffix = "priv.der"; + break; + + case PUB_TEXT: + suffix = "pub.txt"; + break; + + case PUB_PEM: + suffix = "pub.pem"; + break; + + case PUB_DER: + suffix = "pub.der"; + break; + + default: + TEST_error("Invalid file type"); + goto err; + } + + BIO_snprintf(filename, sizeof(filename), "%s.%s", alg, suffix); + fullfile = test_mk_file_path(datadir, filename); + if (!TEST_ptr(fullfile)) + goto err; + + file = BIO_new_file(fullfile, "rb"); + if (!TEST_ptr(file)) + goto err; + + if (!TEST_true(BIO_read_ex(file, buf, sizeof(buf), &readbytes)) + || !TEST_true(BIO_eof(file)) + || !TEST_size_t_lt(readbytes, sizeof(buf))) + goto err; + + len = BIO_get_mem_data(membio, &memdata); + if (!TEST_int_gt(len, 0)) + goto err; + + slen = len; + if (type != PRIV_DER && type != PUB_DER) { + stripcr(memdata, &slen); + stripcr(buf, &readbytes); + } + + if (!TEST_mem_eq(memdata, slen, buf, readbytes)) + goto err; + + ret = 1; + err: + OPENSSL_free(fullfile); + (void)BIO_reset(membio); + BIO_free(file); + return ret; +} + +static int test_print_key_using_pem(const char *alg, const EVP_PKEY *pk) { - if (!TEST_true(EVP_PKEY_print_private(bio_out, pk, 0, NULL)) + BIO *membio = BIO_new(BIO_s_mem()); + int ret = 0; + + if (!TEST_ptr(membio)) + goto err; + + if (!TEST_true(EVP_PKEY_print_private(membio, pk, 0, NULL)) + || !TEST_true(compare_with_file(alg, PRIV_TEXT, membio)) /* Public key in PEM form */ - || !TEST_true(PEM_write_bio_PUBKEY(bio_out, pk)) + || !TEST_true(PEM_write_bio_PUBKEY(membio, pk)) + || !TEST_true(compare_with_file(alg, PUB_PEM, membio)) /* Unencrypted private key in PEM form */ - || !TEST_true(PEM_write_bio_PrivateKey(bio_out, pk, + || !TEST_true(PEM_write_bio_PrivateKey(membio, pk, NULL, NULL, 0, NULL, NULL)) + || !TEST_true(compare_with_file(alg, PRIV_PEM, membio)) /* Encrypted private key in PEM form */ || !TEST_true(PEM_write_bio_PrivateKey(bio_out, pk, EVP_aes_256_cbc(), (unsigned char *)"pass", 4, NULL, NULL))) - return 0; + goto err; - return 1; + ret = 1; + err: + BIO_free(membio); + return ret; } -static int test_print_key_using_serializer(const EVP_PKEY *pk) +static int test_print_key_type_using_serializer(const char *alg, int type, + const EVP_PKEY *pk) { - const char *pq = OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ; + const char *pq; OSSL_SERIALIZER_CTX *ctx = NULL; + BIO *membio = BIO_new(BIO_s_mem()); int ret = 1; + switch (type) { + case PRIV_TEXT: + pq = OSSL_SERIALIZER_PrivateKey_TO_TEXT_PQ; + break; + + case PRIV_PEM: + pq = OSSL_SERIALIZER_PrivateKey_TO_PEM_PQ; + break; + + case PRIV_DER: + pq = OSSL_SERIALIZER_PrivateKey_TO_DER_PQ; + break; + + case PUB_TEXT: + pq = OSSL_SERIALIZER_PUBKEY_TO_TEXT_PQ; + break; + + case PUB_PEM: + pq = OSSL_SERIALIZER_PUBKEY_TO_PEM_PQ; + break; + + case PUB_DER: + pq = OSSL_SERIALIZER_PUBKEY_TO_DER_PQ; + break; + + default: + TEST_error("Invalid serialization type"); + goto err; + } + + if (!TEST_ptr(membio)) { + ret = 0; + goto err; + } + /* Make a context, it's valid for several prints */ TEST_note("Setting up a OSSL_SERIALIZER context with passphrase"); if (!TEST_ptr(ctx = OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(pk, pq)) /* Check that this operation is supported */ - || !TEST_ptr(OSSL_SERIALIZER_CTX_get_serializer(ctx)) - /* Set a passphrase to be used later */ - || !TEST_true(OSSL_SERIALIZER_CTX_set_passphrase(ctx, - (unsigned char *)"pass", - 4))) + || !TEST_ptr(OSSL_SERIALIZER_CTX_get_serializer(ctx))) goto err; /* Use no cipher. This should give us an unencrypted PEM */ - TEST_note("Displaying PEM with no encryption"); - if (!TEST_true(OSSL_SERIALIZER_to_bio(ctx, bio_out))) + TEST_note("Testing with no encryption"); + if (!TEST_true(OSSL_SERIALIZER_to_bio(ctx, membio)) + || !TEST_true(compare_with_file(alg, type, membio))) ret = 0; - /* Use a valid cipher name */ - TEST_note("Displaying PEM encrypted with AES-256-CBC"); - if (!TEST_true(OSSL_SERIALIZER_CTX_set_cipher(ctx, "AES-256-CBC", NULL)) - || !TEST_true(OSSL_SERIALIZER_to_bio(ctx, bio_out))) - ret = 0; + if (type == PRIV_PEM) { + /* Set a passphrase to be used later */ + if (!TEST_true(OSSL_SERIALIZER_CTX_set_passphrase(ctx, + (unsigned char *)"pass", + 4))) + goto err; - /* Use an invalid cipher name, which should generate no output */ - TEST_note("NOT Displaying PEM encrypted with (invalid) FOO"); - if (!TEST_false(OSSL_SERIALIZER_CTX_set_cipher(ctx, "FOO", NULL)) - || !TEST_false(OSSL_SERIALIZER_to_bio(ctx, bio_out))) - ret = 0; + /* Use a valid cipher name */ + TEST_note("Displaying PEM encrypted with AES-256-CBC"); + if (!TEST_true(OSSL_SERIALIZER_CTX_set_cipher(ctx, "AES-256-CBC", NULL)) + || !TEST_true(OSSL_SERIALIZER_to_bio(ctx, bio_out))) + ret = 0; - /* Clear the cipher. This should give us an unencrypted PEM again */ - TEST_note("Displaying PEM with encryption cleared (no encryption)"); - if (!TEST_true(OSSL_SERIALIZER_CTX_set_cipher(ctx, NULL, NULL)) - || !TEST_true(OSSL_SERIALIZER_to_bio(ctx, bio_out))) - ret = 0; + /* Use an invalid cipher name, which should generate no output */ + TEST_note("NOT Displaying PEM encrypted with (invalid) FOO"); + if (!TEST_false(OSSL_SERIALIZER_CTX_set_cipher(ctx, "FOO", NULL)) + || !TEST_false(OSSL_SERIALIZER_to_bio(ctx, bio_out))) + ret = 0; + + /* Clear the cipher. This should give us an unencrypted PEM again */ + TEST_note("Testing with encryption cleared (no encryption)"); + if (!TEST_true(OSSL_SERIALIZER_CTX_set_cipher(ctx, NULL, NULL)) + || !TEST_true(OSSL_SERIALIZER_to_bio(ctx, membio)) + || !TEST_true(compare_with_file(alg, type, membio))) + ret = 0; + } err: + BIO_free(membio); OSSL_SERIALIZER_CTX_free(ctx); return ret; } +static int test_print_key_using_serializer(const char *alg, const EVP_PKEY *pk) +{ + int i; + int ret = 1; + + for (i = 0; i < 6; i++) + ret = ret && test_print_key_type_using_serializer(alg, i, pk); + + return ret; +} + /* Array indexes used in test_fromdata_rsa */ #define N 0 #define E 1 @@ -141,8 +311,8 @@ static int test_fromdata_rsa(void) || !TEST_true(EVP_PKEY_pairwise_check(key_ctx))) goto err; - ret = test_print_key_using_pem(pk) - | test_print_key_using_serializer(pk); + ret = test_print_key_using_pem("RSA", pk) + && test_print_key_using_serializer("RSA", pk); err: EVP_PKEY_free(pk); @@ -195,8 +365,119 @@ static int test_fromdata_dh(void) || !TEST_int_eq(EVP_PKEY_size(pk), 4)) goto err; - ret = test_print_key_using_pem(pk) - | test_print_key_using_serializer(pk); + ret = test_print_key_using_pem("DH", pk) + && test_print_key_using_serializer("DH", pk); + + err: + EVP_PKEY_free(pk); + EVP_PKEY_CTX_free(ctx); + + return ret; +} +#endif + +#ifndef OPENSSL_NO_EC +/* Array indexes used in test_fromdata_ecx */ +# define PRIV_KEY 0 +# define PUB_KEY 1 + +# define X25519_IDX 0 +# define X448_IDX 1 + +static int test_fromdata_ecx(int tst) +{ + int ret = 0; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pk = NULL; + const char *alg = (tst == X25519_IDX) ? "X25519" : "X448"; + + /* X448_KEYLEN > X25519_KEYLEN */ + static unsigned char key_numbers[2][2][X448_KEYLEN] = { + /* X25519: Keys from RFC 7748 6.1 */ + { + /* Private Key */ + { + 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, + 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, + 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, + 0x2c, 0x2a + }, + /* Public Key */ + { + 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, + 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, + 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, + 0x4e, 0x6a + } + }, + /* X448: Keys from RFC 7748 6.2 */ + { + /* Private Key */ + { + 0x9a, 0x8f, 0x49, 0x25, 0xd1, 0x51, 0x9f, 0x57, 0x75, 0xcf, + 0x46, 0xb0, 0x4b, 0x58, 0x00, 0xd4, 0xee, 0x9e, 0xe8, 0xba, + 0xe8, 0xbc, 0x55, 0x65, 0xd4, 0x98, 0xc2, 0x8d, 0xd9, 0xc9, + 0xba, 0xf5, 0x74, 0xa9, 0x41, 0x97, 0x44, 0x89, 0x73, 0x91, + 0x00, 0x63, 0x82, 0xa6, 0xf1, 0x27, 0xab, 0x1d, 0x9a, 0xc2, + 0xd8, 0xc0, 0xa5, 0x98, 0x72, 0x6b + }, + /* Public Key */ + { + 0x9b, 0x08, 0xf7, 0xcc, 0x31, 0xb7, 0xe3, 0xe6, 0x7d, 0x22, + 0xd5, 0xae, 0xa1, 0x21, 0x07, 0x4a, 0x27, 0x3b, 0xd2, 0xb8, + 0x3d, 0xe0, 0x9c, 0x63, 0xfa, 0xa7, 0x3d, 0x2c, 0x22, 0xc5, + 0xd9, 0xbb, 0xc8, 0x36, 0x64, 0x72, 0x41, 0xd9, 0x53, 0xd4, + 0x0c, 0x5b, 0x12, 0xda, 0x88, 0x12, 0x0d, 0x53, 0x17, 0x7f, + 0x80, 0xe5, 0x32, 0xc4, 0x1f, 0xa0 + } + } + }; + OSSL_PARAM x25519_fromdata_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, + key_numbers[X25519_IDX][PRIV_KEY], + X25519_KEYLEN), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + key_numbers[X25519_IDX][PUB_KEY], + X25519_KEYLEN), + OSSL_PARAM_END + }; + OSSL_PARAM x448_fromdata_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, + key_numbers[X448_IDX][PRIV_KEY], + X448_KEYLEN), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + key_numbers[X448_IDX][PUB_KEY], + X448_KEYLEN), + OSSL_PARAM_END + }; + OSSL_PARAM *fromdata_params; + int bits, security_bits, size; + + if (tst == X25519_IDX) { + fromdata_params = x25519_fromdata_params; + bits = X25519_BITS; + security_bits = X25519_SECURITY_BITS; + size = X25519_KEYLEN; + } else { + fromdata_params = x448_fromdata_params; + bits = X448_BITS; + security_bits = X448_SECURITY_BITS; + size = X448_KEYLEN; + } + + ctx = EVP_PKEY_CTX_new_from_name(NULL, alg, NULL); + if (!TEST_ptr(ctx)) + goto err; + + if (!TEST_true(EVP_PKEY_key_fromdata_init(ctx)) + || !TEST_true(EVP_PKEY_fromdata(ctx, &pk, fromdata_params)) + || !TEST_int_eq(EVP_PKEY_bits(pk), bits) + || !TEST_int_eq(EVP_PKEY_security_bits(pk), security_bits) + || !TEST_int_eq(EVP_PKEY_size(pk), size)) + goto err; + + ret = test_print_key_using_pem(alg, pk) + && test_print_key_using_serializer(alg, pk); err: EVP_PKEY_free(pk); @@ -206,11 +487,23 @@ static int test_fromdata_dh(void) } #endif + int setup_tests(void) { + if (!test_skip_common_options()) { + TEST_error("Error parsing test options\n"); + return 0; + } + + if (!TEST_ptr(datadir = test_get_argument(0))) + return 0; + ADD_TEST(test_fromdata_rsa); #ifndef OPENSSL_NO_DH ADD_TEST(test_fromdata_dh); #endif +#ifndef OPENSSL_NO_EC + ADD_ALL_TESTS(test_fromdata_ecx, 2); +#endif return 1; } |