Path: blob/main/crypto/openssl/demos/signature/EVP_EC_Signature_demo.c
111890 views
/*-1* Copyright 2021-2023 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/*10* An example that uses the EVP_MD*, EVP_DigestSign* and EVP_DigestVerify*11* methods to calculate and verify a signature of two static buffers.12*/1314#include <string.h>15#include <stdio.h>16#include <openssl/err.h>17#include <openssl/evp.h>18#include <openssl/decoder.h>19#include "EVP_EC_Signature_demo.h"2021/*22* This demonstration will calculate and verify a signature of data using23* the soliloquy from Hamlet scene 1 act 324*/2526static const char *hamlet_1 = "To be, or not to be, that is the question,\n"27"Whether tis nobler in the minde to suffer\n"28"The slings and arrowes of outragious fortune,\n"29"Or to take Armes again in a sea of troubles,\n";30static const char *hamlet_2 = "And by opposing, end them, to die to sleep;\n"31"No more, and by a sleep, to say we end\n"32"The heart-ache, and the thousand natural shocks\n"33"That flesh is heir to? tis a consumation\n";3435/*36* For demo_sign, load EC private key priv_key from priv_key_der[].37* For demo_verify, load EC public key pub_key from pub_key_der[].38*/39static EVP_PKEY *get_key(OSSL_LIB_CTX *libctx, const char *propq, int public)40{41OSSL_DECODER_CTX *dctx = NULL;42EVP_PKEY *pkey = NULL;43int selection;44const unsigned char *data;45size_t data_len;4647if (public) {48selection = EVP_PKEY_PUBLIC_KEY;49data = pub_key_der;50data_len = sizeof(pub_key_der);51} else {52selection = EVP_PKEY_KEYPAIR;53data = priv_key_der;54data_len = sizeof(priv_key_der);55}56dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, "EC",57selection, libctx, propq);58(void)OSSL_DECODER_from_data(dctx, &data, &data_len);59OSSL_DECODER_CTX_free(dctx);60if (pkey == NULL)61fprintf(stderr, "Failed to load %s key.\n", public ? "public" : "private");62return pkey;63}6465static int demo_sign(OSSL_LIB_CTX *libctx, const char *sig_name,66size_t *sig_out_len, unsigned char **sig_out_value)67{68int ret = 0, public = 0;69size_t sig_len;70unsigned char *sig_value = NULL;71const char *propq = NULL;72EVP_MD_CTX *sign_context = NULL;73EVP_PKEY *priv_key = NULL;7475/* Get private key */76priv_key = get_key(libctx, propq, public);77if (priv_key == NULL) {78fprintf(stderr, "Get private key failed.\n");79goto cleanup;80}81/*82* Make a message signature context to hold temporary state83* during signature creation84*/85sign_context = EVP_MD_CTX_new();86if (sign_context == NULL) {87fprintf(stderr, "EVP_MD_CTX_new failed.\n");88goto cleanup;89}90/*91* Initialize the sign context to use the fetched92* sign provider.93*/94if (!EVP_DigestSignInit_ex(sign_context, NULL, sig_name,95libctx, NULL, priv_key, NULL)) {96fprintf(stderr, "EVP_DigestSignInit_ex failed.\n");97goto cleanup;98}99/*100* EVP_DigestSignUpdate() can be called several times on the same context101* to include additional data.102*/103if (!EVP_DigestSignUpdate(sign_context, hamlet_1, strlen(hamlet_1))) {104fprintf(stderr, "EVP_DigestSignUpdate(hamlet_1) failed.\n");105goto cleanup;106}107if (!EVP_DigestSignUpdate(sign_context, hamlet_2, strlen(hamlet_2))) {108fprintf(stderr, "EVP_DigestSignUpdate(hamlet_2) failed.\n");109goto cleanup;110}111/* Call EVP_DigestSignFinal to get signature length sig_len */112if (!EVP_DigestSignFinal(sign_context, NULL, &sig_len)) {113fprintf(stderr, "EVP_DigestSignFinal failed.\n");114goto cleanup;115}116if (sig_len <= 0) {117fprintf(stderr, "EVP_DigestSignFinal returned invalid signature length.\n");118goto cleanup;119}120sig_value = OPENSSL_malloc(sig_len);121if (sig_value == NULL) {122fprintf(stderr, "No memory.\n");123goto cleanup;124}125if (!EVP_DigestSignFinal(sign_context, sig_value, &sig_len)) {126fprintf(stderr, "EVP_DigestSignFinal failed.\n");127goto cleanup;128}129*sig_out_len = sig_len;130*sig_out_value = sig_value;131fprintf(stdout, "Generating signature:\n");132BIO_dump_indent_fp(stdout, sig_value, sig_len, 2);133fprintf(stdout, "\n");134ret = 1;135136cleanup:137/* OpenSSL free functions will ignore NULL arguments */138if (!ret)139OPENSSL_free(sig_value);140EVP_PKEY_free(priv_key);141EVP_MD_CTX_free(sign_context);142return ret;143}144145static int demo_verify(OSSL_LIB_CTX *libctx, const char *sig_name,146size_t sig_len, unsigned char *sig_value)147{148int ret = 0, public = 1;149const char *propq = NULL;150EVP_MD_CTX *verify_context = NULL;151EVP_PKEY *pub_key = NULL;152153/*154* Make a verify signature context to hold temporary state155* during signature verification156*/157verify_context = EVP_MD_CTX_new();158if (verify_context == NULL) {159fprintf(stderr, "EVP_MD_CTX_new failed.\n");160goto cleanup;161}162/* Get public key */163pub_key = get_key(libctx, propq, public);164if (pub_key == NULL) {165fprintf(stderr, "Get public key failed.\n");166goto cleanup;167}168/* Verify */169if (!EVP_DigestVerifyInit_ex(verify_context, NULL, sig_name,170libctx, NULL, pub_key, NULL)) {171fprintf(stderr, "EVP_DigestVerifyInit failed.\n");172goto cleanup;173}174/*175* EVP_DigestVerifyUpdate() can be called several times on the same context176* to include additional data.177*/178if (!EVP_DigestVerifyUpdate(verify_context, hamlet_1, strlen(hamlet_1))) {179fprintf(stderr, "EVP_DigestVerifyUpdate(hamlet_1) failed.\n");180goto cleanup;181}182if (!EVP_DigestVerifyUpdate(verify_context, hamlet_2, strlen(hamlet_2))) {183fprintf(stderr, "EVP_DigestVerifyUpdate(hamlet_2) failed.\n");184goto cleanup;185}186if (EVP_DigestVerifyFinal(verify_context, sig_value, sig_len) <= 0) {187fprintf(stderr, "EVP_DigestVerifyFinal failed.\n");188goto cleanup;189}190fprintf(stdout, "Signature verified.\n");191ret = 1;192193cleanup:194/* OpenSSL free functions will ignore NULL arguments */195EVP_PKEY_free(pub_key);196EVP_MD_CTX_free(verify_context);197return ret;198}199200int main(void)201{202OSSL_LIB_CTX *libctx = NULL;203const char *sig_name = "SHA3-512";204size_t sig_len = 0;205unsigned char *sig_value = NULL;206int ret = EXIT_FAILURE;207208libctx = OSSL_LIB_CTX_new();209if (libctx == NULL) {210fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");211goto cleanup;212}213if (!demo_sign(libctx, sig_name, &sig_len, &sig_value)) {214fprintf(stderr, "demo_sign failed.\n");215goto cleanup;216}217if (!demo_verify(libctx, sig_name, sig_len, sig_value)) {218fprintf(stderr, "demo_verify failed.\n");219goto cleanup;220}221ret = EXIT_SUCCESS;222223cleanup:224if (ret != EXIT_SUCCESS)225ERR_print_errors_fp(stderr);226/* OpenSSL free functions will ignore NULL arguments */227OSSL_LIB_CTX_free(libctx);228OPENSSL_free(sig_value);229return ret;230}231232233