Implement the ECX Serializers
authorMatt Caswell <matt@openssl.org>
Thu, 27 Feb 2020 22:08:59 +0000 (08:08 +1000)
committerShane Lontis <shane.lontis@oracle.com>
Thu, 27 Feb 2020 22:08:59 +0000 (08:08 +1000)
Provide serializers for X25519 and X448 for text, pem and der. There are
no parameter serializers because there are no parameters for these
algorithms.

Add some documentation about the various import/export types available
Add additional testing for the serializers

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11095)

38 files changed:
doc/man3/EVP_PKEY_fromdata.pod
doc/man7/provider-keymgmt.pod
providers/defltprov.c
providers/implementations/include/prov/implementations.h
providers/implementations/keymgmt/ecx_kmgmt.c
providers/implementations/serializers/build.info
providers/implementations/serializers/serializer_common.c
providers/implementations/serializers/serializer_dh_pub.c
providers/implementations/serializers/serializer_ecx.c [new file with mode: 0644]
providers/implementations/serializers/serializer_ecx_priv.c [new file with mode: 0644]
providers/implementations/serializers/serializer_ecx_pub.c [new file with mode: 0644]
providers/implementations/serializers/serializer_local.h
test/evp_pkey_provided_test.c
test/recipes/30-test_evp_pkey_provided.t
test/recipes/30-test_evp_pkey_provided/DH.priv.der [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/DH.priv.pem [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/DH.priv.txt [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/DH.pub.der [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/DH.pub.pem [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/DH.pub.txt [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/RSA.priv.der [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/RSA.priv.pem [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/RSA.priv.txt [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/RSA.pub.der [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/RSA.pub.pem [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/RSA.pub.txt [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X25519.priv.der [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X25519.priv.pem [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X25519.priv.txt [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X25519.pub.der [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X25519.pub.pem [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X25519.pub.txt [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X448.priv.der [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X448.priv.pem [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X448.priv.txt [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X448.pub.der [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X448.pub.pem [new file with mode: 0644]
test/recipes/30-test_evp_pkey_provided/X448.pub.txt [new file with mode: 0644]

index ed8c668..2d0059d 100644 (file)
@@ -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
index 279256d..5141ffd 100644 (file)
@@ -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.
index d513dbe..9400eee 100644 (file)
@@ -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 }
 };
 
index 6d6a26d..a98d113 100644 (file)
@@ -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[];
index cbb302e..fe0193d 100644 (file)
@@ -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)
index 0ec2c54..d5873d1 100644 (file)
@@ -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
index daceb11..b1ad523 100644 (file)
@@ -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))
index 57da48c..567a0f0 100644 (file)
@@ -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 (file)
index 0000000..589c6c2
--- /dev/null
@@ -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 (file)
index 0000000..64dc594
--- /dev/null
@@ -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 (file)
index 0000000..384d75e
--- /dev/null
@@ -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)
index 801d221..ec27f14 100644 (file)
@@ -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,
index 3c1c090..c161698 100644 (file)
 #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;
 }
index 669438c..74b3664 100644 (file)
@@ -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 (file)
index 0000000..0063e62
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/DH.priv.der 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 (file)
index 0000000..73cc465
--- /dev/null
@@ -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 (file)
index 0000000..cedef99
--- /dev/null
@@ -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 (file)
index 0000000..95a3001
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/DH.pub.der 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 (file)
index 0000000..709ac89
--- /dev/null
@@ -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 (file)
index 0000000..b7b465f
--- /dev/null
@@ -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 (file)
index 0000000..08925e4
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/RSA.priv.der 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 (file)
index 0000000..548b3f5
--- /dev/null
@@ -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 (file)
index 0000000..d34e9ef
--- /dev/null
@@ -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 (file)
index 0000000..bff3252
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/RSA.pub.der 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 (file)
index 0000000..a1366b7
--- /dev/null
@@ -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 (file)
index 0000000..f6dad2a
--- /dev/null
@@ -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 (file)
index 0000000..d8d244b
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/X25519.priv.der 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 (file)
index 0000000..ff18c24
--- /dev/null
@@ -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 (file)
index 0000000..a18bc1d
--- /dev/null
@@ -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 (file)
index 0000000..4945db1
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/X25519.pub.der 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 (file)
index 0000000..4ccf960
--- /dev/null
@@ -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 (file)
index 0000000..a57851b
--- /dev/null
@@ -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 (file)
index 0000000..8875333
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/X448.priv.der 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 (file)
index 0000000..c93235c
--- /dev/null
@@ -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 (file)
index 0000000..f91620c
--- /dev/null
@@ -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 (file)
index 0000000..15da4b7
Binary files /dev/null and b/test/recipes/30-test_evp_pkey_provided/X448.pub.der 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 (file)
index 0000000..559bf68
--- /dev/null
@@ -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 (file)
index 0000000..d2b6659
--- /dev/null
@@ -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