From b544c72f3755c0ea51408d3118821a1ac126c070 Mon Sep 17 00:00:00 2001 From: slontis Date: Tue, 29 Aug 2023 18:02:14 +1000 Subject: Add ED25519 Signature demo. Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell Reviewed-by: Tom Cosgrove Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/21883) --- demos/README.txt | 8 +- demos/signature/EVP_ED_Signature_demo.c | 208 ++++++++++++++++++++++++++++++++ demos/signature/Makefile | 11 +- 3 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 demos/signature/EVP_ED_Signature_demo.c diff --git a/demos/README.txt b/demos/README.txt index cc72721fbe..32c15cd394 100644 --- a/demos/README.txt +++ b/demos/README.txt @@ -51,9 +51,11 @@ pkread.c Print out a description of a PKCS12 file. pkwrite.c Add a password to an existing PKCS12 file. signature: -EVP_Signature_demo.c Compute and verify a signature from multiple buffers -rsa_pss_direct.c Compute and verify an RSA-PSS signature from a hash -rsa_pss_hash.c Compute and verify an RSA-PSS signature over a buffer +EVP_EC_Signature_demo.c Compute and verify an EC signature. +EVP_DSA_Signature_demo.c Compute and verify a DSA signature. +EVP_ED_Signature_demo.c Compute and verify an ED25519 signature. +rsa_pss_direct.c Compute and verify an RSA-PSS signature from a hash +rsa_pss_hash.c Compute and verify an RSA-PSS signature over a buffer sslecho: main.c Simple SSL echo client/server. diff --git a/demos/signature/EVP_ED_Signature_demo.c b/demos/signature/EVP_ED_Signature_demo.c new file mode 100644 index 0000000000..e5cb6f4de1 --- /dev/null +++ b/demos/signature/EVP_ED_Signature_demo.c @@ -0,0 +1,208 @@ +/*- + * Copyright 2023 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 + */ + +/* + * This demonstration will calculate and verify an ED25519 signature of + * a message using EVP_DigestSign() and EVP_DigestVerify(). + */ + +#include +#include +#include +#include +#include + +/* A test message to be signed (TBS) */ +static const unsigned char hamlet[] = + "To be, or not to be, that is the question,\n" + "Whether tis nobler in the minde to suffer\n" + "The slings and arrowes of outragious fortune,\n" + "Or to take Armes again in a sea of troubles,\n"; + +static int demo_sign(EVP_PKEY *priv, + const unsigned char *tbs, size_t tbs_len, + OSSL_LIB_CTX *libctx, + unsigned char **sig_out_value, + size_t *sig_out_len) +{ + int ret = 0; + size_t sig_len; + unsigned char *sig_value = NULL; + EVP_MD_CTX *sign_context = NULL; + + /* Create a signature context */ + sign_context = EVP_MD_CTX_new(); + if (sign_context == NULL) { + fprintf(stderr, "EVP_MD_CTX_new failed.\n"); + goto cleanup; + } + + /* + * Initialize the sign context using an ED25519 private key + * Notice that the digest name must NOT be used. + * In this demo we don't specify any additional parameters via + * OSSL_PARAM, which means it will use default values. + * For more information, refer to doc/man7/EVP_SIGNATURE-ED25519.pod + * "ED25519 and ED448 Signature Parameters" + */ + if (!EVP_DigestSignInit_ex(sign_context, NULL, NULL, libctx, NULL, priv, NULL)) { + fprintf(stderr, "EVP_DigestSignInit_ex failed.\n"); + goto cleanup; + } + + /* Calculate the required size for the signature by passing a NULL buffer. */ + if (!EVP_DigestSign(sign_context, NULL, &sig_len, tbs, tbs_len)) { + fprintf(stderr, "EVP_DigestSign using NULL buffer failed.\n"); + goto cleanup; + } + sig_value = OPENSSL_malloc(sig_len); + if (sig_value == NULL) { + fprintf(stderr, "OPENSSL_malloc failed.\n"); + goto cleanup; + } + fprintf(stdout, "Generating signature:\n"); + if (!EVP_DigestSign(sign_context, sig_value, &sig_len, tbs, tbs_len)) { + fprintf(stderr, "EVP_DigestSign failed.\n"); + goto cleanup; + } + *sig_out_len = sig_len; + *sig_out_value = sig_value; + BIO_dump_indent_fp(stdout, sig_value, sig_len, 2); + fprintf(stdout, "\n"); + ret = 1; + +cleanup: + if (!ret) + OPENSSL_free(sig_value); + EVP_MD_CTX_free(sign_context); + return ret; +} + +static int demo_verify(EVP_PKEY *pub, + const unsigned char *tbs, size_t tbs_len, + const unsigned char *sig_value, size_t sig_len, + OSSL_LIB_CTX *libctx) +{ + int ret = 0; + EVP_MD_CTX *verify_context = NULL; + + /* + * Make a verify signature context to hold temporary state + * during signature verification + */ + verify_context = EVP_MD_CTX_new(); + if (verify_context == NULL) { + fprintf(stderr, "EVP_MD_CTX_new failed.\n"); + goto cleanup; + } + /* Initialize the verify context with a ED25519 public key */ + if (!EVP_DigestVerifyInit_ex(verify_context, NULL, NULL, + libctx, NULL, pub, NULL)) { + fprintf(stderr, "EVP_DigestVerifyInit_ex failed.\n"); + goto cleanup; + } + /* + * ED25519 only supports the one shot interface using EVP_DigestVerify() + * The streaming EVP_DigestVerifyUpdate() API is not supported. + */ + if (!EVP_DigestVerify(verify_context, sig_value, sig_len, + tbs, tbs_len)) { + fprintf(stderr, "EVP_DigestVerify() failed.\n"); + goto cleanup; + } + fprintf(stdout, "Signature verified.\n"); + ret = 1; + +cleanup: + EVP_MD_CTX_free(verify_context); + return ret; +} + +static int create_key(OSSL_LIB_CTX *libctx, + EVP_PKEY **privout, EVP_PKEY **pubout) +{ + int ret = 0; + EVP_PKEY *priv = NULL, *pub = NULL; + unsigned char pubdata[32]; + size_t pubdata_len = 0; + + /* + * In this demo we just create a keypair, and extract the + * public key. We could also use EVP_PKEY_new_raw_private_key_ex() + * to create a key from raw data. + */ + priv = EVP_PKEY_Q_keygen(libctx, NULL, "ED25519"); + if (priv == NULL) { + fprintf(stderr, "EVP_PKEY_Q_keygen() failed\n"); + goto end; + } + + if (!EVP_PKEY_get_octet_string_param(priv, + OSSL_PKEY_PARAM_PUB_KEY, + pubdata, + sizeof(pubdata), + &pubdata_len)) { + fprintf(stderr, "EVP_PKEY_get_octet_string_param() failed\n"); + goto end; + } + pub = EVP_PKEY_new_raw_public_key_ex(libctx, "ED25519", NULL, pubdata, pubdata_len); + if (pub == NULL) { + fprintf(stderr, "EVP_PKEY_new_raw_public_key_ex() failed\n"); + goto end; + } + ret = 1; +end: + if (ret) { + *pubout = pub; + *privout = priv; + } else { + EVP_PKEY_free(priv); + } + return ret; +} + +int main(void) +{ + OSSL_LIB_CTX *libctx = NULL; + size_t sig_len = 0; + unsigned char *sig_value = NULL; + int ret = EXIT_FAILURE; + EVP_PKEY *priv = NULL, *pub = NULL; + + libctx = OSSL_LIB_CTX_new(); + if (libctx == NULL) { + fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n"); + goto cleanup; + } + if (!create_key(libctx, &priv, &pub)) { + fprintf(stderr, "Failed to create key.\n"); + goto cleanup; + } + + if (!demo_sign(priv, hamlet, sizeof(hamlet), libctx, + &sig_value, &sig_len)) { + fprintf(stderr, "demo_sign failed.\n"); + goto cleanup; + } + if (!demo_verify(pub, hamlet, sizeof(hamlet), + sig_value, sig_len, libctx)) { + fprintf(stderr, "demo_verify failed.\n"); + goto cleanup; + } + ret = EXIT_SUCCESS; + +cleanup: + if (ret != EXIT_SUCCESS) + ERR_print_errors_fp(stderr); + EVP_PKEY_free(pub); + EVP_PKEY_free(priv); + OSSL_LIB_CTX_free(libctx); + OPENSSL_free(sig_value); + return ret; +} diff --git a/demos/signature/Makefile b/demos/signature/Makefile index 394eef6d42..2a7c196007 100644 --- a/demos/signature/Makefile +++ b/demos/signature/Makefile @@ -1,23 +1,28 @@ # # To run the demos when linked with a shared library (default): # -# LD_LIBRARY_PATH=../.. ./EVP_Signature_demo +# LD_LIBRARY_PATH=../.. ./EVP_EC_Signature_demo +# LD_LIBRARY_PATH=../.. ./EVP_DSA_Signature_demo +# LD_LIBRARY_PATH=../.. ./EVP_ED_Signature_demo +# LD_LIBRARY_PATH=../.. ./rsa_pss_direct +# LD_LIBRARY_PATH=../.. ./rsa_pss_hash CFLAGS = -I../../include -g -Wall LDFLAGS = -L../.. LDLIBS = -lcrypto -all: EVP_EC_Signature_demo EVP_DSA_Signature_demo rsa_pss_direct rsa_pss_hash +all: EVP_EC_Signature_demo EVP_DSA_Signature_demo EVP_ED_Signature_demo rsa_pss_direct rsa_pss_hash %.o: %.c $(CC) $(CFLAGS) -c $< EVP_EC_Signature_demo: EVP_EC_Signature_demo.o EVP_DSA_Signature_demo: EVP_DSA_Signature_demo.o +EVP_ED_Signature_demo: EVP_ED_Signature_demo.o rsa_pss_direct: rsa_pss_direct.o rsa_pss_hash: rsa_pss_hash.o test: ; clean: - $(RM) *.o EVP_EC_Signature_demo EVP_DSA_Signature_demo rsa_pss_direct rsa_pss_hash + $(RM) *.o EVP_EC_Signature_demo EVP_DSA_Signature_demo EVP_ED_Signature_demo rsa_pss_direct rsa_pss_hash -- cgit v1.2.3