diff options
38 files changed, 1187 insertions, 44 deletions
diff --git a/doc/man3/EVP_PKEY_fromdata.pod b/doc/man3/EVP_PKEY_fromdata.pod index ed8c668..2d0059d 100644 --- a/doc/man3/EVP_PKEY_fromdata.pod +++ b/doc/man3/EVP_PKEY_fromdata.pod @@ -27,7 +27,9 @@ creating a key from user data. EVP_PKEY_fromdata() creates key parameters or a key, given data from I<params> and a context that's been initialized with EVP_PKEY_param_fromdata_init() or EVP_PKEY_key_fromdata_init(). The result is -written to I<*ppkey>. +written to I<*ppkey>. The parameters that can be used for various types of key +are as described in the "Built-in RSA Import/Export Types" section on the +L<provider-keymgmt(7)> page. EVP_PKEY_param_fromdata_settable() and EVP_PKEY_key_fromdata_settable() get a constant B<OSSL_PARAM> array that describes the settable parameters diff --git a/doc/man7/provider-keymgmt.pod b/doc/man7/provider-keymgmt.pod index 279256d..5141ffd 100644 --- a/doc/man7/provider-keymgmt.pod +++ b/doc/man7/provider-keymgmt.pod @@ -256,6 +256,87 @@ OP_keymgmt_export_types() should return a constant array of descriptor B<OSSL_PARAM> for data indicated by I<selection>, that the OP_keymgmt_export() callback can expect to receive. +=head2 Built-in RSA Import/Export Types + +The following Import/Export types are available for the built-in RSA algorithm: + +=over 4 + +=item "n" (B<OSSL_PKEY_PARAM_RSA_N>) <integer> + +The RSA "n" value. + +=item "e" (B<OSSL_PKEY_PARAM_RSA_E>) <integer> + +The RSA "e" value. + +=item "d" (B<OSSL_PKEY_PARAM_RSA_D>) <integer> + +The RSA "d" value. + +=item "rsa-factor" (B<OSSL_PKEY_PARAM_RSA_FACTOR>) <integer> + +An RSA factor. In 2 prime RSA these are often known as "p" or "q". This value +may be repeated up to 10 times in a single key. + +=item "rsa-exponent" (B<OSSL_PKEY_PARAM_RSA_EXPONENT>) <integer> + +An RSA CRT (Chinese Remainder Theorem) exponent. This value may be repeated up +to 10 times in a single key. + +=item "rsa-coefficient" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT>) <integer> + +An RSA CRT (Chinese Remainder Theorem) coefficient. This value may be repeated +up to 9 times in a single key. + +=back + +=head2 Built-in DSA and Diffie-Hellman Import/Export Types + +The following Import/Export types are available for the built-in DSA and +Diffie-Hellman algorithms: + +=over 4 + +=item "pub" (B<OSSL_PKEY_PARAM_PUB_KEY>) <integer> or <octet string> + +The public key value. + +=item "priv" (B<OSSL_PKEY_PARAM_PRIV_KEY>) <integer> or <octet string> + +The private key value. + +=item "p" (B<OSSL_PKEY_PARAM_FFC_P>) <integer> + +A DSA or Diffie-Hellman "p" value. + +=item "q" (B<OSSL_PKEY_PARAM_FFC_Q>) <integer> + +A DSA or Diffie-Hellman "q" value. + +=item "g" (B<OSSL_PKEY_PARAM_FFC_G>) <integer> + +A DSA or Diffie-Hellman "g" value. + +=back + +=head2 Built-in X25519, X448, ED25519 and ED448 Import/Export Types + +The following Import/Export types are available for the built-in X25519, X448, +ED25519 and X448 algorithms: + +=over 4 + +=item "pub" (B<OSSL_PKEY_PARAM_PUB_KEY>) <octet string> + +The public key value. + +=item "priv" (B<OSSL_PKEY_PARAM_PRIV_KEY>) <octet string> + +The private key value. + +=back + =head2 Information Parameters See L<OSSL_PARAM(3)> for further details on the parameters structure. diff --git a/providers/defltprov.c b/providers/defltprov.c index d513dbe..9400eee 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -470,6 +470,34 @@ static const OSSL_ALGORITHM deflt_serializer[] = { dsa_param_pem_serializer_functions }, #endif +#ifndef OPENSSL_NO_EC + { "X25519", "provider=default,format=text,type=private", + x25519_priv_print_serializer_functions }, + { "X25519", "provider=default,format=text,type=public", + x25519_pub_print_serializer_functions }, + { "X25519", "provider=default,format=der,type=private", + x25519_priv_der_serializer_functions }, + { "X25519", "provider=default,format=der,type=public", + x25519_pub_der_serializer_functions }, + { "X25519", "provider=default,format=pem,type=private", + x25519_priv_pem_serializer_functions }, + { "X25519", "provider=default,format=pem,type=public", + x25519_pub_pem_serializer_functions }, + + { "X448", "provider=default,format=text,type=private", + x448_priv_print_serializer_functions }, + { "X448", "provider=default,format=text,type=public", + x448_pub_print_serializer_functions }, + { "X448", "provider=default,format=der,type=private", + x448_priv_der_serializer_functions }, + { "X448", "provider=default,format=der,type=public", + x448_pub_der_serializer_functions }, + { "X448", "provider=default,format=pem,type=private", + x448_priv_pem_serializer_functions }, + { "X448", "provider=default,format=pem,type=public", + x448_pub_pem_serializer_functions }, +#endif + { NULL, NULL, NULL } }; diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index 6d6a26d..a98d113 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -281,6 +281,7 @@ extern const OSSL_DISPATCH rsa_priv_der_serializer_functions[]; extern const OSSL_DISPATCH rsa_pub_der_serializer_functions[]; extern const OSSL_DISPATCH rsa_priv_pem_serializer_functions[]; extern const OSSL_DISPATCH rsa_pub_pem_serializer_functions[]; + extern const OSSL_DISPATCH dh_priv_text_serializer_functions[]; extern const OSSL_DISPATCH dh_pub_text_serializer_functions[]; extern const OSSL_DISPATCH dh_param_text_serializer_functions[]; @@ -290,6 +291,7 @@ extern const OSSL_DISPATCH dh_param_der_serializer_functions[]; extern const OSSL_DISPATCH dh_priv_pem_serializer_functions[]; extern const OSSL_DISPATCH dh_pub_pem_serializer_functions[]; extern const OSSL_DISPATCH dh_param_pem_serializer_functions[]; + extern const OSSL_DISPATCH dsa_priv_text_serializer_functions[]; extern const OSSL_DISPATCH dsa_pub_text_serializer_functions[]; extern const OSSL_DISPATCH dsa_param_text_serializer_functions[]; @@ -299,3 +301,17 @@ extern const OSSL_DISPATCH dsa_param_der_serializer_functions[]; extern const OSSL_DISPATCH dsa_priv_pem_serializer_functions[]; extern const OSSL_DISPATCH dsa_pub_pem_serializer_functions[]; extern const OSSL_DISPATCH dsa_param_pem_serializer_functions[]; + +extern const OSSL_DISPATCH x25519_priv_print_serializer_functions[]; +extern const OSSL_DISPATCH x25519_pub_print_serializer_functions[]; +extern const OSSL_DISPATCH x25519_priv_der_serializer_functions[]; +extern const OSSL_DISPATCH x25519_pub_der_serializer_functions[]; +extern const OSSL_DISPATCH x25519_priv_pem_serializer_functions[]; +extern const OSSL_DISPATCH x25519_pub_pem_serializer_functions[]; + +extern const OSSL_DISPATCH x448_priv_print_serializer_functions[]; +extern const OSSL_DISPATCH x448_pub_print_serializer_functions[]; +extern const OSSL_DISPATCH x448_priv_der_serializer_functions[]; +extern const OSSL_DISPATCH x448_pub_der_serializer_functions[]; +extern const OSSL_DISPATCH x448_priv_pem_serializer_functions[]; +extern const OSSL_DISPATCH x448_pub_pem_serializer_functions[]; diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c index cbb302e..fe0193d 100644 --- a/providers/implementations/keymgmt/ecx_kmgmt.c +++ b/providers/implementations/keymgmt/ecx_kmgmt.c @@ -154,8 +154,8 @@ static int ecx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, } static const OSSL_PARAM ecx_key_types[] = { - OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), - OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), OSSL_PARAM_END }; static const OSSL_PARAM *ecx_imexport_types(int selection) diff --git a/providers/implementations/serializers/build.info b/providers/implementations/serializers/build.info index 0ec2c54..d5873d1 100644 --- a/providers/implementations/serializers/build.info +++ b/providers/implementations/serializers/build.info @@ -5,6 +5,7 @@ $SERIALIZER_GOAL=../../libimplementations.a $RSA_GOAL=../../libimplementations.a $DH_GOAL=../../libimplementations.a $DSA_GOAL=../../libimplementations.a +$ECX_GOAL=../../libimplementations.a SOURCE[$SERIALIZER_GOAL]=serializer_common.c SOURCE[$RSA_GOAL]=serializer_rsa.c serializer_rsa_priv.c serializer_rsa_pub.c @@ -14,3 +15,6 @@ ENDIF IF[{- !$disabled{dsa} -}] SOURCE[$DSA_GOAL]=serializer_dsa.c serializer_dsa_priv.c serializer_dsa_pub.c serializer_dsa_param.c ENDIF +IF[{- !$disabled{ec} -}] + SOURCE[$ECX_GOAL]=serializer_ecx.c serializer_ecx_priv.c serializer_ecx_pub.c +ENDIF diff --git a/providers/implementations/serializers/serializer_common.c b/providers/implementations/serializers/serializer_common.c index daceb11..b1ad523 100644 --- a/providers/implementations/serializers/serializer_common.c +++ b/providers/implementations/serializers/serializer_common.c @@ -243,6 +243,36 @@ int ossl_prov_print_labeled_bignum(BIO *out, const char *label, return 1; } +/* Number of octets per line */ +#define LABELED_BUF_PRINT_WIDTH 15 + +int ossl_prov_print_labeled_buf(BIO *out, const char *label, + const unsigned char *buf, size_t buflen) +{ + size_t i; + + if (ossl_prov_bio_printf(out, "%s\n", label) <= 0) + return 0; + + for (i = 0; i < buflen; i++) { + if ((i % LABELED_BUF_PRINT_WIDTH) == 0) { + if (i > 0 && ossl_prov_bio_printf(out, "\n") <= 0) + return 0; + if (ossl_prov_bio_printf(out, " ") <= 0) + return 0; + } + + if (ossl_prov_bio_printf(out, "%02x%s", buf[i], + (i == buflen - 1) ? "" : ":") <= 0) + return 0; + } + if (ossl_prov_bio_printf(out, "\n") <= 0) + return 0; + + return 1; +} + + /* p2s = param to asn1_string, k2d = key to der */ int ossl_prov_write_priv_der_from_obj(BIO *out, const void *obj, int obj_nid, int (*p2s)(const void *obj, int nid, @@ -254,7 +284,7 @@ int ossl_prov_write_priv_der_from_obj(BIO *out, const void *obj, int obj_nid, { int ret = 0; ASN1_STRING *str = NULL; - int strtype = 0; + int strtype = V_ASN1_UNDEF; if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype)) return 0; @@ -290,7 +320,7 @@ int ossl_prov_write_priv_pem_from_obj(BIO *out, const void *obj, int obj_nid, { int ret = 0; ASN1_STRING *str = NULL; - int strtype = 0; + int strtype = V_ASN1_UNDEF; if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype)) return 0; @@ -325,7 +355,7 @@ int ossl_prov_write_pub_der_from_obj(BIO *out, const void *obj, int obj_nid, { int ret = 0; ASN1_STRING *str = NULL; - int strtype = 0; + int strtype = V_ASN1_UNDEF; X509_PUBKEY *xpk = NULL; if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype)) @@ -350,7 +380,7 @@ int ossl_prov_write_pub_pem_from_obj(BIO *out, const void *obj, int obj_nid, { int ret = 0; ASN1_STRING *str = NULL; - int strtype = 0; + int strtype = V_ASN1_UNDEF; X509_PUBKEY *xpk = NULL; if (p2s != NULL && !p2s(obj, obj_nid, &str, &strtype)) diff --git a/providers/implementations/serializers/serializer_dh_pub.c b/providers/implementations/serializers/serializer_dh_pub.c index 57da48c..567a0f0 100644 --- a/providers/implementations/serializers/serializer_dh_pub.c +++ b/providers/implementations/serializers/serializer_dh_pub.c @@ -132,7 +132,7 @@ static int dh_pub_print_data(void *ctx, const OSSL_PARAM params[], BIO *out, static int dh_pub_print(void *ctx, void *dh, BIO *out, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { - return ossl_prov_print_dh(out, dh, 0); + return ossl_prov_print_dh(out, dh, dh_print_pub); } const OSSL_DISPATCH dh_pub_der_serializer_functions[] = { diff --git a/providers/implementations/serializers/serializer_ecx.c b/providers/implementations/serializers/serializer_ecx.c new file mode 100644 index 0000000..589c6c2 --- /dev/null +++ b/providers/implementations/serializers/serializer_ecx.c @@ -0,0 +1,125 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/err.h> +#include "crypto/ecx.h" +#include "prov/bio.h" /* ossl_prov_bio_printf() */ +#include "prov/implementations.h" /* ecx_keymgmt_functions */ +#include "serializer_local.h" + +void ecx_get_new_free_import(ECX_KEY_TYPE type, + OSSL_OP_keymgmt_new_fn **ecx_new, + OSSL_OP_keymgmt_free_fn **ecx_free, + OSSL_OP_keymgmt_import_fn **ecx_import) +{ + if (type == ECX_KEY_TYPE_X25519) { + *ecx_new = ossl_prov_get_keymgmt_new(x25519_keymgmt_functions); + *ecx_free = ossl_prov_get_keymgmt_free(x25519_keymgmt_functions); + *ecx_import = ossl_prov_get_keymgmt_import(x25519_keymgmt_functions); + } else if (type == ECX_KEY_TYPE_X448) { + *ecx_new = ossl_prov_get_keymgmt_new(x448_keymgmt_functions); + *ecx_free = ossl_prov_get_keymgmt_free(x448_keymgmt_functions); + *ecx_import = ossl_prov_get_keymgmt_import(x448_keymgmt_functions); + } else { + *ecx_new = NULL; + *ecx_free = NULL; + *ecx_import = NULL; + } +} + + +int ossl_prov_print_ecx(BIO *out, ECX_KEY *ecxkey, enum ecx_print_type type) +{ + const char *type_label = NULL; + + switch (type) { + case ecx_print_priv: + switch (ecxkey->keylen) { + case X25519_KEYLEN: + type_label = "X25519 Private-Key"; + break; + case X448_KEYLEN: + type_label = "X448 Private-Key"; + break; + } + break; + case ecx_print_pub: + switch (ecxkey->keylen) { + case X25519_KEYLEN: + type_label = "X25519 Public-Key"; + break; + case X448_KEYLEN: + type_label = "X448 Public-Key"; + break; + } + break; + } + + if (type == ecx_print_priv && ecxkey->privkey == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (ossl_prov_bio_printf(out, "%s:\n", type_label) <= 0) + return 0; + if (type == ecx_print_priv + && !ossl_prov_print_labeled_buf(out, "priv:", ecxkey->privkey, + ecxkey->keylen)) + return 0; + if (!ossl_prov_print_labeled_buf(out, "pub:", ecxkey->pubkey, + ecxkey->keylen)) + return 0; + + return 1; +} + + +int ossl_prov_ecx_pub_to_der(const void *vecxkey, unsigned char **pder) +{ + const ECX_KEY *ecxkey = vecxkey; + unsigned char *keyblob; + + if (ecxkey == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + keyblob = OPENSSL_memdup(ecxkey->pubkey, ecxkey->keylen); + if (keyblob == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + *pder = keyblob; + return ecxkey->keylen; +} + +int ossl_prov_ecx_priv_to_der(const void *vecxkey, unsigned char **pder) +{ + const ECX_KEY *ecxkey = vecxkey; + ASN1_OCTET_STRING oct; + int keybloblen; + + if (ecxkey == NULL || ecxkey->privkey == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + oct.data = ecxkey->privkey; + oct.length = ecxkey->keylen; + oct.flags = 0; + + keybloblen = i2d_ASN1_OCTET_STRING(&oct, pder); + if (keybloblen < 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; + } + + return keybloblen; +} diff --git a/providers/implementations/serializers/serializer_ecx_priv.c b/providers/implementations/serializers/serializer_ecx_priv.c new file mode 100644 index 0000000..64dc594 --- /dev/null +++ b/providers/implementations/serializers/serializer_ecx_priv.c @@ -0,0 +1,270 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/core_numbers.h> +#include <openssl/core_names.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/types.h> +#include <openssl/params.h> +#include "prov/bio.h" +#include "prov/implementations.h" +#include "serializer_local.h" + +static OSSL_OP_serializer_newctx_fn x25519_priv_newctx; +static OSSL_OP_serializer_newctx_fn x448_priv_newctx; +static OSSL_OP_serializer_freectx_fn ecx_priv_freectx; +static OSSL_OP_serializer_set_ctx_params_fn ecx_priv_set_ctx_params; +static OSSL_OP_serializer_settable_ctx_params_fn ecx_priv_settable_ctx_params; +static OSSL_OP_serializer_serialize_data_fn ecx_priv_der_data; +static OSSL_OP_serializer_serialize_object_fn ecx_priv_der; +static OSSL_OP_serializer_serialize_data_fn ecx_priv_pem_data; +static OSSL_OP_serializer_serialize_object_fn ecx_priv_pem; + +static OSSL_OP_serializer_serialize_data_fn ecx_priv_print_data; +static OSSL_OP_serializer_serialize_object_fn ecx_priv_print; + + /* + * Context used for private key serialization. + */ +struct ecx_priv_ctx_st { + void *provctx; + + struct pkcs8_encrypt_ctx_st sc; + ECX_KEY_TYPE type; +}; + +/* Private key : context */ +static void *ecx_priv_newctx(void *provctx, ECX_KEY_TYPE type) +{ + struct ecx_priv_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + + /* -1 is the "whatever" indicator, i.e. the PKCS8 library default PBE */ + ctx->sc.pbe_nid = -1; + ctx->type = type; + } + return ctx; +} + +static void *x25519_priv_newctx(void *provctx) +{ + return ecx_priv_newctx(provctx, ECX_KEY_TYPE_X25519); +} + +static void *x448_priv_newctx(void *provctx) +{ + return ecx_priv_newctx(provctx, ECX_KEY_TYPE_X448); +} + +static void ecx_priv_freectx(void *vctx) +{ + struct ecx_priv_ctx_st *ctx = vctx; + + EVP_CIPHER_free(ctx->sc.cipher); + OPENSSL_free(ctx->sc.cipher_pass); + OPENSSL_free(ctx); +} + +static const OSSL_PARAM *ecx_priv_settable_ctx_params(void) +{ + static const OSSL_PARAM settables[] = { + OSSL_PARAM_utf8_string(OSSL_SERIALIZER_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_octet_string(OSSL_SERIALIZER_PARAM_PASS, NULL, 0), + OSSL_PARAM_END, + }; + + return settables; +} + +static int ecx_priv_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct ecx_priv_ctx_st *ctx = vctx; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_CIPHER); + if (p != NULL) { + const OSSL_PARAM *propsp = + OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_PROPERTIES); + const char *props; + + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + if (propsp != NULL && propsp->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + props = (propsp != NULL ? propsp->data : NULL); + + EVP_CIPHER_free(ctx->sc.cipher); + ctx->sc.cipher_intent = p->data != NULL; + if (p->data != NULL + && ((ctx->sc.cipher = EVP_CIPHER_fetch(NULL, p->data, props)) + == NULL)) + return 0; + } + p = OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_PASS); + if (p != NULL) { + OPENSSL_free(ctx->sc.cipher_pass); + ctx->sc.cipher_pass = NULL; + if (!OSSL_PARAM_get_octet_string(p, &ctx->sc.cipher_pass, 0, + &ctx->sc.cipher_pass_length)) + return 0; + } + return 1; +} + +/* Private key : DER */ +static int ecx_priv_der_data(void *vctx, const OSSL_PARAM params[], BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_priv_ctx_st *ctx = vctx; + OSSL_OP_keymgmt_new_fn *ecx_new; + OSSL_OP_keymgmt_free_fn *ecx_free; + OSSL_OP_keymgmt_import_fn *ecx_import; + int ok = 0; + + ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import); + + if (ecx_import != NULL) { + ECX_KEY *ecxkey; + + if ((ecxkey = ecx_new(ctx->provctx)) != NULL + && ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params) + && ecx_priv_der(ctx, ecxkey, out, cb, cbarg)) + ok = 1; + ecx_free(ecxkey); + } + return ok; +} + +static int ecx_priv_der(void *vctx, void *vecxkey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_priv_ctx_st *ctx = vctx; + ECX_KEY *ecxkey = vecxkey; + int ret; + int type = (ctx->type == ECX_KEY_TYPE_X25519) ? EVP_PKEY_X25519 + : EVP_PKEY_X448; + + ctx->sc.cb = cb; + ctx->sc.cbarg = cbarg; + + ret = ossl_prov_write_priv_der_from_obj(out, ecxkey, + type, + NULL, + ossl_prov_ecx_priv_to_der, + &ctx->sc); + + return ret; +} + +/* Private key : PEM */ +static int ecx_priv_pem_data(void *vctx, const OSSL_PARAM params[], BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_priv_ctx_st *ctx = vctx; + OSSL_OP_keymgmt_new_fn *ecx_new; + OSSL_OP_keymgmt_free_fn *ecx_free; + OSSL_OP_keymgmt_import_fn *ecx_import; + int ok = 0; + + ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import); + + if (ecx_import != NULL) { + ECX_KEY *ecxkey; + + if ((ecxkey = ecx_new(ctx->provctx)) != NULL + && ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params) + && ecx_priv_pem(ctx->provctx, ecxkey, out, cb, cbarg)) + ok = 1; + ecx_free(ecxkey); + } + return ok; +} + +static int ecx_priv_pem(void *vctx, void *ecxkey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_priv_ctx_st *ctx = vctx; + int ret; + int type = (ctx->type == ECX_KEY_TYPE_X25519) ? EVP_PKEY_X25519 + : EVP_PKEY_X448; + + ctx->sc.cb = cb; + ctx->sc.cbarg = cbarg; + + ret = ossl_prov_write_priv_pem_from_obj(out, ecxkey, + type, + NULL, + ossl_prov_ecx_priv_to_der, + &ctx->sc); + + return ret; +} + +static int ecx_priv_print_data(void *vctx, const OSSL_PARAM params[], BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_priv_ctx_st *ctx = vctx; + OSSL_OP_keymgmt_new_fn *ecx_new; + OSSL_OP_keymgmt_free_fn *ecx_free; + OSSL_OP_keymgmt_import_fn *ecx_import; + int ok = 0; + + ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import); + + if (ecx_import != NULL) { + ECX_KEY *ecxkey; + + if ((ecxkey = ecx_new(ctx->provctx)) != NULL + && ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params) + && ecx_priv_print(ctx, ecxkey, out, cb, cbarg)) + ok = 1; + ecx_free(ecxkey); + } + return ok; +} + +static int ecx_priv_print(void *ctx, void *ecxkey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return ossl_prov_print_ecx(out, ecxkey, ecx_print_priv); +} + +#define MAKE_SERIALIZER_FUNCTIONS(alg, type) \ + const OSSL_DISPATCH alg##_priv_##type##_serializer_functions[] = { \ + { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))alg##_priv_newctx }, \ + { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ecx_priv_freectx }, \ + { OSSL_FUNC_SERIALIZER_SET_CTX_PARAMS, \ + (void (*)(void))ecx_priv_set_ctx_params }, \ + { OSSL_FUNC_SERIALIZER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))ecx_priv_settable_ctx_params }, \ + { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, \ + (void (*)(void))ecx_priv_##type##_data }, \ + { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, \ + (void (*)(void))ecx_priv_##type }, \ + { 0, NULL } \ + }; + +#define MAKE_SERIALIZER_FUNCTIONS_GROUP(alg) \ + MAKE_SERIALIZER_FUNCTIONS(alg, der) \ + MAKE_SERIALIZER_FUNCTIONS(alg, pem) \ + const OSSL_DISPATCH alg##_priv_print_serializer_functions[] = { \ + { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))alg##_priv_newctx }, \ + { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ecx_priv_freectx }, \ + { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, \ + (void (*)(void))ecx_priv_print }, \ + { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, \ + (void (*)(void))ecx_priv_print_data }, \ + { 0, NULL } \ + }; + +MAKE_SERIALIZER_FUNCTIONS_GROUP(x25519) +MAKE_SERIALIZER_FUNCTIONS_GROUP(x448) diff --git a/providers/implementations/serializers/serializer_ecx_pub.c b/providers/implementations/serializers/serializer_ecx_pub.c new file mode 100644 index 0000000..384d75e --- /dev/null +++ b/providers/implementations/serializers/serializer_ecx_pub.c @@ -0,0 +1,184 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/core_numbers.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/types.h> +#include <openssl/params.h> +#include "prov/bio.h" +#include "prov/implementations.h" +#include "serializer_local.h" + +static OSSL_OP_serializer_newctx_fn x25519_pub_newctx; +static OSSL_OP_serializer_newctx_fn x448_pub_newctx; +static OSSL_OP_serializer_freectx_fn ecx_pub_freectx; +static OSSL_OP_serializer_serialize_data_fn ecx_pub_der_data; +static OSSL_OP_serializer_serialize_object_fn ecx_pub_der; +static OSSL_OP_serializer_serialize_data_fn ecx_pub_pem_data; +static OSSL_OP_serializer_serialize_object_fn ecx_pub_pem; + +static OSSL_OP_serializer_serialize_data_fn ecx_pub_print_data; +static OSSL_OP_serializer_serialize_object_fn ecx_pub_print; + +/* + * Context used for public key serialization. + */ +struct ecx_pub_ctx_st { + void *provctx; + ECX_KEY_TYPE type; +}; + +/* Public key : context */ +static void *ecx_pub_newctx(void *provctx, ECX_KEY_TYPE type) +{ + struct ecx_pub_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->type = type; + } + return ctx; +} + +static void *x25519_pub_newctx(void *provctx) +{ + return ecx_pub_newctx(provctx, ECX_KEY_TYPE_X25519); +} + +static void *x448_pub_newctx(void *provctx) +{ + return ecx_pub_newctx(provctx, ECX_KEY_TYPE_X448); +} + +static void ecx_pub_freectx(void *ctx) +{ + OPENSSL_free(ctx); +} + +/* Public key : DER */ +static int ecx_pub_der_data(void *vctx, const OSSL_PARAM params[], BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_pub_ctx_st *ctx = vctx; + OSSL_OP_keymgmt_new_fn *ecx_new; + OSSL_OP_keymgmt_free_fn *ecx_free; + OSSL_OP_keymgmt_import_fn *ecx_import; + int ok = 0; + + ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import); + + if (ecx_import != NULL) { + ECX_KEY *ecxkey; + + if ((ecxkey = ecx_new(ctx->provctx)) != NULL + && ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params) + && ecx_pub_der(ctx, ecxkey, out, cb, cbarg)) + ok = 1; + ecx_free(ecxkey); + } + return ok; +} + +static int ecx_pub_der(void *vctx, void *ecxkey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_pub_ctx_st *ctx = vctx; + + return ossl_prov_write_pub_der_from_obj(out, ecxkey, + ctx->type == ECX_KEY_TYPE_X25519 + ? EVP_PKEY_X25519 : EVP_PKEY_X448, + NULL, + ossl_prov_ecx_pub_to_der); +} + +/* Public key : PEM */ +static int ecx_pub_pem_data(void *vctx, const OSSL_PARAM params[], BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_pub_ctx_st *ctx = vctx; + OSSL_OP_keymgmt_new_fn *ecx_new; + OSSL_OP_keymgmt_free_fn *ecx_free; + OSSL_OP_keymgmt_import_fn *ecx_import; + int ok = 0; + + ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import); + + if (ecx_import != NULL) { + ECX_KEY *ecxkey; + + if ((ecxkey = ecx_new(ctx->provctx)) != NULL + && ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params) + && ecx_pub_pem(ctx, ecxkey, out, cb, cbarg)) + ok = 1; + ecx_free(ecxkey); + } + return ok; +} + +static int ecx_pub_pem(void *vctx, void *ecxkey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_pub_ctx_st *ctx = vctx; + + return ossl_prov_write_pub_pem_from_obj(out, ecxkey, + ctx->type == ECX_KEY_TYPE_X25519 + ? EVP_PKEY_X25519 : EVP_PKEY_X448, + NULL, + ossl_prov_ecx_pub_to_der); + +} + +static int ecx_pub_print_data(void *vctx, const OSSL_PARAM params[], BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + struct ecx_pub_ctx_st *ctx = vctx; + OSSL_OP_keymgmt_new_fn *ecx_new; + OSSL_OP_keymgmt_free_fn *ecx_free; + OSSL_OP_keymgmt_import_fn *ecx_import; + int ok = 0; + + ecx_get_new_free_import(ctx->type, &ecx_new, &ecx_free, &ecx_import); + + if (ecx_import != NULL) { + ECX_KEY *ecxkey; + + if ((ecxkey = ecx_new(ctx)) != NULL + && ecx_import(ecxkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params) + && ecx_pub_print(ctx, ecxkey, out, cb, cbarg)) + ok = 1; + ecx_free(ecxkey); + } + return ok; +} + +static int ecx_pub_print(void *ctx, void *ecxkey, BIO *out, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return ossl_prov_print_ecx(out, ecxkey, ecx_print_pub); +} + +#define MAKE_SERIALIZER_FUNCTIONS(alg, type) \ + const OSSL_DISPATCH alg##_pub_##type##_serializer_functions[] = { \ + { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))alg##_pub_newctx }, \ + { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))ecx_pub_freectx }, \ + { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, \ + (void (*)(void))ecx_pub_##type##_data }, \ + { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, \ + (void (*)(void))ecx_pub_##type }, \ + { 0, NULL } \ + }; + +#define MAKE_SERIALIZER_FUNCTIONS_GROUP(alg) \ + MAKE_SERIALIZER_FUNCTIONS(alg, der) \ + MAKE_SERIALIZER_FUNCTIONS(alg, pem) \ + MAKE_SERIALIZER_FUNCTIONS(alg, print) + +MAKE_SERIALIZER_FUNCTIONS_GROUP(x25519) +MAKE_SERIALIZER_FUNCTIONS_GROUP(x448) diff --git a/providers/implementations/serializers/serializer_local.h b/providers/implementations/serializers/serializer_local.h index 801d221..ec27f14 100644 --- a/providers/implementations/serializers/serializer_local.h +++ b/providers/implementations/serializers/serializer_local.h @@ -13,6 +13,7 @@ #include <openssl/asn1.h> /* i2d_of_void */ #include <openssl/x509.h> /* X509_SIG */ #include <openssl/types.h> +#include <crypto/ecx.h> struct pkcs8_encrypt_ctx_st { /* Set to 1 if intending to encrypt/decrypt, otherwise 0 */ @@ -30,6 +31,11 @@ struct pkcs8_encrypt_ctx_st { void *cbarg; }; +typedef enum { + ECX_KEY_TYPE_X25519, + ECX_KEY_TYPE_X448 +} ECX_KEY_TYPE; + OSSL_OP_keymgmt_new_fn *ossl_prov_get_keymgmt_new(const OSSL_DISPATCH *fns); OSSL_OP_keymgmt_free_fn *ossl_prov_get_keymgmt_free(const OSSL_DISPATCH *fns); OSSL_OP_keymgmt_import_fn *ossl_prov_get_keymgmt_import(const OSSL_DISPATCH *fns); @@ -49,8 +55,15 @@ int ossl_prov_prepare_dh_params(const void *dh, int nid, int ossl_prov_dh_pub_to_der(const void *dh, unsigned char **pder); int ossl_prov_dh_priv_to_der(const void *dh, unsigned char **pder); +void ecx_get_new_free_import(ECX_KEY_TYPE type, + OSSL_OP_keymgmt_new_fn **ecx_new, + OSSL_OP_keymgmt_free_fn **ecx_free, + OSSL_OP_keymgmt_import_fn **ecx_import); +int ossl_prov_ecx_pub_to_der(const void *ecxkey, unsigned char **pder); +int ossl_prov_ecx_priv_to_der(const void *ecxkey, unsigned char **pder); + int ossl_prov_prepare_dsa_params(const void *dsa, int nid, - ASN1_STRING **pstr, int *pstrtype); + ASN1_STRING **pstr, int *pstrtype); /* * Special variant of ossl_prov_prepare_dsa_params() that requires all * three parameters (P, Q and G) to be set. This is used when serializing @@ -63,6 +76,8 @@ int ossl_prov_dsa_priv_to_der(const void *dsa, unsigned char **pder); int ossl_prov_print_labeled_bignum(BIO *out, const char *label, const BIGNUM *bn); +int ossl_prov_print_labeled_buf(BIO *out, const char *label, + const unsigned char *buf, size_t buflen); int ossl_prov_print_rsa(BIO *out, RSA *rsa, int priv); enum dh_print_type { @@ -81,6 +96,15 @@ enum dsa_print_type { int ossl_prov_print_dsa(BIO *out, DSA *dsa, enum dsa_print_type type); +enum ecx_print_type { + ecx_print_priv, + ecx_print_pub +}; + +#ifndef OPENSSL_NO_EC +int ossl_prov_print_ecx(BIO *out, ECX_KEY *ecxkey, enum ecx_print_type type); +#endif + int ossl_prov_write_priv_der_from_obj(BIO *out, const void *obj, int obj_nid, int (*p2s)(const void *obj, int nid, ASN1_STRING **str, diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c index 3c1c090..c161698 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; } diff --git a/test/recipes/30-test_evp_pkey_provided.t b/test/recipes/30-test_evp_pkey_provided.t index 669438c..74b3664 100644 --- a/test/recipes/30-test_evp_pkey_provided.t +++ b/test/recipes/30-test_evp_pkey_provided.t @@ -9,5 +9,12 @@ use OpenSSL::Test::Simple; +use OpenSSL::Test qw/:DEFAULT srctop_dir/; -simple_test("test_evp_pkey_provided", "evp_pkey_provided_test"); +setup("test_evp_pkey_provided"); + +plan tests => 1; + +ok(run(test(["evp_pkey_provided_test", + srctop_dir("test", "recipes", "30-test_evp_pkey_provided")])), + "running evp_pkey_provided_test"); diff --git a/test/recipes/30-test_evp_pkey_provided/DH.priv.der b/test/recipes/30-test_evp_pkey_provided/DH.priv.der Binary files differnew file mode 100644 index 0000000..0063e62 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/DH.priv.der diff --git a/test/recipes/30-test_evp_pkey_provided/DH.priv.pem b/test/recipes/30-test_evp_pkey_provided/DH.priv.pem new file mode 100644 index 0000000..73cc465 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/DH.priv.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MCQCAQAwFwYJKoZIhvcNAQMBMAoCBQCLtF9TAgECBAYCBGZsKwY= +-----END PRIVATE KEY----- diff --git a/test/recipes/30-test_evp_pkey_provided/DH.priv.txt b/test/recipes/30-test_evp_pkey_provided/DH.priv.txt new file mode 100644 index 0000000..cedef99 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/DH.priv.txt @@ -0,0 +1,5 @@ +DH Private-Key: (32 bit) + private-key: 1718364934 (0x666c2b06) + public-key: 1873206864 (0x6fa6de50) + prime: 2343853907 (0x8bb45f53) + generator: 2 (0x2) diff --git a/test/recipes/30-test_evp_pkey_provided/DH.pub.der b/test/recipes/30-test_evp_pkey_provided/DH.pub.der Binary files differnew file mode 100644 index 0000000..95a3001 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/DH.pub.der diff --git a/test/recipes/30-test_evp_pkey_provided/DH.pub.pem b/test/recipes/30-test_evp_pkey_provided/DH.pub.pem new file mode 100644 index 0000000..709ac89 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/DH.pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCIwFwYJKoZIhvcNAQMBMAoCBQCLtF9TAgECAwcAAgRvpt5Q +-----END PUBLIC KEY----- diff --git a/test/recipes/30-test_evp_pkey_provided/DH.pub.txt b/test/recipes/30-test_evp_pkey_provided/DH.pub.txt new file mode 100644 index 0000000..b7b465f --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/DH.pub.txt @@ -0,0 +1,4 @@ +DH Public-Key: (32 bit) + public-key: 1873206864 (0x6fa6de50) + prime: 2343853907 (0x8bb45f53) + generator: 2 (0x2) diff --git a/test/recipes/30-test_evp_pkey_provided/RSA.priv.der b/test/recipes/30-test_evp_pkey_provided/RSA.priv.der Binary files differnew file mode 100644 index 0000000..08925e4 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/RSA.priv.der diff --git a/test/recipes/30-test_evp_pkey_provided/RSA.priv.pem b/test/recipes/30-test_evp_pkey_provided/RSA.priv.pem new file mode 100644 index 0000000..548b3f5 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/RSA.priv.pem @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +MEQCAQAwDQYJKoZIhvcNAQEBBQAEMDAuAgEAAgUAvHR/xQIDAQABAgR7EzOZAgMA +6WMCAwDOtwIDAIWZAgMAvYcCAwDMOw== +-----END PRIVATE KEY----- diff --git a/test/recipes/30-test_evp_pkey_provided/RSA.priv.txt b/test/recipes/30-test_evp_pkey_provided/RSA.priv.txt new file mode 100644 index 0000000..d34e9ef --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/RSA.priv.txt @@ -0,0 +1,9 @@ +Private-Key: (32 bit, 2 primes) +modulus: 3161751493 (0xbc747fc5) +publicExponent: 65537 (0x10001) +privateExponent: 2064855961 (0x7b133399) +prime1: 59747 (0xe963) +prime2: 52919 (0xceb7) +exponent1: 34201 (0x8599) +exponent2: 48519 (0xbd87) +coefficient: 52283 (0xcc3b) diff --git a/test/recipes/30-test_evp_pkey_provided/RSA.pub.der b/test/recipes/30-test_evp_pkey_provided/RSA.pub.der Binary files differnew file mode 100644 index 0000000..bff3252 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/RSA.pub.der diff --git a/test/recipes/30-test_evp_pkey_provided/RSA.pub.pem b/test/recipes/30-test_evp_pkey_provided/RSA.pub.pem new file mode 100644 index 0000000..a1366b7 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/RSA.pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCAwDQYJKoZIhvcNAQEBBQADDwAwDAIFALx0f8UCAwEAAQ== +-----END PUBLIC KEY----- diff --git a/test/recipes/30-test_evp_pkey_provided/RSA.pub.txt b/test/recipes/30-test_evp_pkey_provided/RSA.pub.txt new file mode 100644 index 0000000..f6dad2a --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/RSA.pub.txt @@ -0,0 +1,3 @@ +Public-Key: (32 bit) +Modulus: 3161751493 (0xbc747fc5) +Exponent: 65537 (0x10001) diff --git a/test/recipes/30-test_evp_pkey_provided/X25519.priv.der b/test/recipes/30-test_evp_pkey_provided/X25519.priv.der Binary files differnew file mode 100644 index 0000000..d8d244b --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X25519.priv.der diff --git a/test/recipes/30-test_evp_pkey_provided/X25519.priv.pem b/test/recipes/30-test_evp_pkey_provided/X25519.priv.pem new file mode 100644 index 0000000..ff18c24 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X25519.priv.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq +-----END PRIVATE KEY----- diff --git a/test/recipes/30-test_evp_pkey_provided/X25519.priv.txt b/test/recipes/30-test_evp_pkey_provided/X25519.priv.txt new file mode 100644 index 0000000..a18bc1d --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X25519.priv.txt @@ -0,0 +1,9 @@ +X25519 Private-Key: +priv: + 77:07:6d:0a:73:18:a5:7d:3c:16:c1:72:51:b2:66: + 45:df:4c:2f:87:eb:c0:99:2a:b1:77:fb:a5:1d:b9: + 2c:2a +pub: + 85:20:f0:09:89:30:a7:54:74:8b:7d:dc:b4:3e:f7: + 5a:0d:bf:3a:0d:26:38:1a:f4:eb:a4:a9:8e:aa:9b: + 4e:6a diff --git a/test/recipes/30-test_evp_pkey_provided/X25519.pub.der b/test/recipes/30-test_evp_pkey_provided/X25519.pub.der Binary files differnew file mode 100644 index 0000000..4945db1 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X25519.pub.der diff --git a/test/recipes/30-test_evp_pkey_provided/X25519.pub.pem b/test/recipes/30-test_evp_pkey_provided/X25519.pub.pem new file mode 100644 index 0000000..4ccf960 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X25519.pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VuAyEAhSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmo= +-----END PUBLIC KEY----- diff --git a/test/recipes/30-test_evp_pkey_provided/X25519.pub.txt b/test/recipes/30-test_evp_pkey_provided/X25519.pub.txt new file mode 100644 index 0000000..a57851b --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X25519.pub.txt @@ -0,0 +1,5 @@ +X25519 Public-Key: +pub: + 85:20:f0:09:89:30:a7:54:74:8b:7d:dc:b4:3e:f7: + 5a:0d:bf:3a:0d:26:38:1a:f4:eb:a4:a9:8e:aa:9b: + 4e:6a diff --git a/test/recipes/30-test_evp_pkey_provided/X448.priv.der b/test/recipes/30-test_evp_pkey_provided/X448.priv.der Binary files differnew file mode 100644 index 0000000..8875333 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X448.priv.der diff --git a/test/recipes/30-test_evp_pkey_provided/X448.priv.pem b/test/recipes/30-test_evp_pkey_provided/X448.priv.pem new file mode 100644 index 0000000..c93235c --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X448.priv.pem @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +MEYCAQAwBQYDK2VvBDoEOJqPSSXRUZ9Xdc9GsEtYANTunui66LxVZdSYwo3Zybr1 +dKlBl0SJc5EAY4Km8SerHZrC2MClmHJr +-----END PRIVATE KEY----- diff --git a/test/recipes/30-test_evp_pkey_provided/X448.priv.txt b/test/recipes/30-test_evp_pkey_provided/X448.priv.txt new file mode 100644 index 0000000..f91620c --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X448.priv.txt @@ -0,0 +1,11 @@ +X448 Private-Key: +priv: + 9a:8f:49:25:d1:51:9f:57:75:cf:46:b0:4b:58:00: + d4:ee:9e:e8:ba:e8:bc:55:65:d4:98:c2:8d:d9:c9: + ba:f5:74:a9:41:97:44:89:73:91:00:63:82:a6:f1: + 27:ab:1d:9a:c2:d8:c0:a5:98:72:6b +pub: + 9b:08:f7:cc:31:b7:e3:e6:7d:22:d5:ae:a1:21:07: + 4a:27:3b:d2:b8:3d:e0:9c:63:fa:a7:3d:2c:22:c5: + d9:bb:c8:36:64:72:41:d9:53:d4:0c:5b:12:da:88: + 12:0d:53:17:7f:80:e5:32:c4:1f:a0 diff --git a/test/recipes/30-test_evp_pkey_provided/X448.pub.der b/test/recipes/30-test_evp_pkey_provided/X448.pub.der Binary files differnew file mode 100644 index 0000000..15da4b7 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X448.pub.der diff --git a/test/recipes/30-test_evp_pkey_provided/X448.pub.pem b/test/recipes/30-test_evp_pkey_provided/X448.pub.pem new file mode 100644 index 0000000..559bf68 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X448.pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MEIwBQYDK2VvAzkAmwj3zDG34+Z9ItWuoSEHSic70rg94Jxj+qc9LCLF2bvINmRy +QdlT1AxbEtqIEg1TF3+A5TLEH6A= +-----END PUBLIC KEY----- diff --git a/test/recipes/30-test_evp_pkey_provided/X448.pub.txt b/test/recipes/30-test_evp_pkey_provided/X448.pub.txt new file mode 100644 index 0000000..d2b6659 --- /dev/null +++ b/test/recipes/30-test_evp_pkey_provided/X448.pub.txt @@ -0,0 +1,6 @@ +X448 Public-Key: +pub: + 9b:08:f7:cc:31:b7:e3:e6:7d:22:d5:ae:a1:21:07: + 4a:27:3b:d2:b8:3d:e0:9c:63:fa:a7:3d:2c:22:c5: + d9:bb:c8:36:64:72:41:d9:53:d4:0c:5b:12:da:88: + 12:0d:53:17:7f:80:e5:32:c4:1f:a0 |