aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/man3/EVP_PKEY_fromdata.pod4
-rw-r--r--doc/man7/provider-keymgmt.pod81
-rw-r--r--providers/defltprov.c28
-rw-r--r--providers/implementations/include/prov/implementations.h16
-rw-r--r--providers/implementations/keymgmt/ecx_kmgmt.c4
-rw-r--r--providers/implementations/serializers/build.info4
-rw-r--r--providers/implementations/serializers/serializer_common.c38
-rw-r--r--providers/implementations/serializers/serializer_dh_pub.c2
-rw-r--r--providers/implementations/serializers/serializer_ecx.c125
-rw-r--r--providers/implementations/serializers/serializer_ecx_priv.c270
-rw-r--r--providers/implementations/serializers/serializer_ecx_pub.c184
-rw-r--r--providers/implementations/serializers/serializer_local.h26
-rw-r--r--test/evp_pkey_provided_test.c361
-rw-r--r--test/recipes/30-test_evp_pkey_provided.t9
-rw-r--r--test/recipes/30-test_evp_pkey_provided/DH.priv.derbin0 -> 38 bytes
-rw-r--r--test/recipes/30-test_evp_pkey_provided/DH.priv.pem3
-rw-r--r--test/recipes/30-test_evp_pkey_provided/DH.priv.txt5
-rw-r--r--test/recipes/30-test_evp_pkey_provided/DH.pub.derbin0 -> 36 bytes
-rw-r--r--test/recipes/30-test_evp_pkey_provided/DH.pub.pem3
-rw-r--r--test/recipes/30-test_evp_pkey_provided/DH.pub.txt4
-rw-r--r--test/recipes/30-test_evp_pkey_provided/RSA.priv.derbin0 -> 70 bytes
-rw-r--r--test/recipes/30-test_evp_pkey_provided/RSA.priv.pem4
-rw-r--r--test/recipes/30-test_evp_pkey_provided/RSA.priv.txt9
-rw-r--r--test/recipes/30-test_evp_pkey_provided/RSA.pub.derbin0 -> 34 bytes
-rw-r--r--test/recipes/30-test_evp_pkey_provided/RSA.pub.pem3
-rw-r--r--test/recipes/30-test_evp_pkey_provided/RSA.pub.txt3
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X25519.priv.derbin0 -> 48 bytes
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X25519.priv.pem3
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X25519.priv.txt9
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X25519.pub.derbin0 -> 44 bytes
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X25519.pub.pem3
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X25519.pub.txt5
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X448.priv.derbin0 -> 72 bytes
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X448.priv.pem4
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X448.priv.txt11
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X448.pub.derbin0 -> 68 bytes
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X448.pub.pem4
-rw-r--r--test/recipes/30-test_evp_pkey_provided/X448.pub.txt6
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
new file mode 100644
index 0000000..0063e62
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/DH.priv.der
Binary files differ
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
new file mode 100644
index 0000000..95a3001
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/DH.pub.der
Binary files differ
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
new file mode 100644
index 0000000..08925e4
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/RSA.priv.der
Binary files differ
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
new file mode 100644
index 0000000..bff3252
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/RSA.pub.der
Binary files differ
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
new file mode 100644
index 0000000..d8d244b
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/X25519.priv.der
Binary files differ
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
new file mode 100644
index 0000000..4945db1
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/X25519.pub.der
Binary files differ
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
new file mode 100644
index 0000000..8875333
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/X448.priv.der
Binary files differ
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
new file mode 100644
index 0000000..15da4b7
--- /dev/null
+++ b/test/recipes/30-test_evp_pkey_provided/X448.pub.der
Binary files differ
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