Path: blob/main/crypto/openssl/demos/signature/EVP_EC_Signature_demo.c
34869 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 =27"To be, or not to be, that is the question,\n"28"Whether tis nobler in the minde to suffer\n"29"The slings and arrowes of outragious fortune,\n"30"Or to take Armes again in a sea of troubles,\n"31;32static const char *hamlet_2 =33"And by opposing, end them, to die to sleep;\n"34"No more, and by a sleep, to say we end\n"35"The heart-ache, and the thousand natural shocks\n"36"That flesh is heir to? tis a consumation\n"37;3839/*40* For demo_sign, load EC private key priv_key from priv_key_der[].41* For demo_verify, load EC public key pub_key from pub_key_der[].42*/43static EVP_PKEY *get_key(OSSL_LIB_CTX *libctx, const char *propq, int public)44{45OSSL_DECODER_CTX *dctx = NULL;46EVP_PKEY *pkey = NULL;47int selection;48const unsigned char *data;49size_t data_len;5051if (public) {52selection = EVP_PKEY_PUBLIC_KEY;53data = pub_key_der;54data_len = sizeof(pub_key_der);55} else {56selection = EVP_PKEY_KEYPAIR;57data = priv_key_der;58data_len = sizeof(priv_key_der);59}60dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, "EC",61selection, libctx, propq);62(void)OSSL_DECODER_from_data(dctx, &data, &data_len);63OSSL_DECODER_CTX_free(dctx);64if (pkey == NULL)65fprintf(stderr, "Failed to load %s key.\n", public ? "public" : "private");66return pkey;67}6869static int demo_sign(OSSL_LIB_CTX *libctx, const char *sig_name,70size_t *sig_out_len, unsigned char **sig_out_value)71{72int ret = 0, public = 0;73size_t sig_len;74unsigned char *sig_value = NULL;75const char *propq = NULL;76EVP_MD_CTX *sign_context = NULL;77EVP_PKEY *priv_key = NULL;7879/* Get private key */80priv_key = get_key(libctx, propq, public);81if (priv_key == NULL) {82fprintf(stderr, "Get private key failed.\n");83goto cleanup;84}85/*86* Make a message signature context to hold temporary state87* during signature creation88*/89sign_context = EVP_MD_CTX_new();90if (sign_context == NULL) {91fprintf(stderr, "EVP_MD_CTX_new failed.\n");92goto cleanup;93}94/*95* Initialize the sign context to use the fetched96* sign provider.97*/98if (!EVP_DigestSignInit_ex(sign_context, NULL, sig_name,99libctx, NULL, priv_key, NULL)) {100fprintf(stderr, "EVP_DigestSignInit_ex failed.\n");101goto cleanup;102}103/*104* EVP_DigestSignUpdate() can be called several times on the same context105* to include additional data.106*/107if (!EVP_DigestSignUpdate(sign_context, hamlet_1, strlen(hamlet_1))) {108fprintf(stderr, "EVP_DigestSignUpdate(hamlet_1) failed.\n");109goto cleanup;110}111if (!EVP_DigestSignUpdate(sign_context, hamlet_2, strlen(hamlet_2))) {112fprintf(stderr, "EVP_DigestSignUpdate(hamlet_2) failed.\n");113goto cleanup;114}115/* Call EVP_DigestSignFinal to get signature length sig_len */116if (!EVP_DigestSignFinal(sign_context, NULL, &sig_len)) {117fprintf(stderr, "EVP_DigestSignFinal failed.\n");118goto cleanup;119}120if (sig_len <= 0) {121fprintf(stderr, "EVP_DigestSignFinal returned invalid signature length.\n");122goto cleanup;123}124sig_value = OPENSSL_malloc(sig_len);125if (sig_value == NULL) {126fprintf(stderr, "No memory.\n");127goto cleanup;128}129if (!EVP_DigestSignFinal(sign_context, sig_value, &sig_len)) {130fprintf(stderr, "EVP_DigestSignFinal failed.\n");131goto cleanup;132}133*sig_out_len = sig_len;134*sig_out_value = sig_value;135fprintf(stdout, "Generating signature:\n");136BIO_dump_indent_fp(stdout, sig_value, sig_len, 2);137fprintf(stdout, "\n");138ret = 1;139140cleanup:141/* OpenSSL free functions will ignore NULL arguments */142if (!ret)143OPENSSL_free(sig_value);144EVP_PKEY_free(priv_key);145EVP_MD_CTX_free(sign_context);146return ret;147}148149static int demo_verify(OSSL_LIB_CTX *libctx, const char *sig_name,150size_t sig_len, unsigned char *sig_value)151{152int ret = 0, public = 1;153const char *propq = NULL;154EVP_MD_CTX *verify_context = NULL;155EVP_PKEY *pub_key = NULL;156157/*158* Make a verify signature context to hold temporary state159* during signature verification160*/161verify_context = EVP_MD_CTX_new();162if (verify_context == NULL) {163fprintf(stderr, "EVP_MD_CTX_new failed.\n");164goto cleanup;165}166/* Get public key */167pub_key = get_key(libctx, propq, public);168if (pub_key == NULL) {169fprintf(stderr, "Get public key failed.\n");170goto cleanup;171}172/* Verify */173if (!EVP_DigestVerifyInit_ex(verify_context, NULL, sig_name,174libctx, NULL, pub_key, NULL)) {175fprintf(stderr, "EVP_DigestVerifyInit failed.\n");176goto cleanup;177}178/*179* EVP_DigestVerifyUpdate() can be called several times on the same context180* to include additional data.181*/182if (!EVP_DigestVerifyUpdate(verify_context, hamlet_1, strlen(hamlet_1))) {183fprintf(stderr, "EVP_DigestVerifyUpdate(hamlet_1) failed.\n");184goto cleanup;185}186if (!EVP_DigestVerifyUpdate(verify_context, hamlet_2, strlen(hamlet_2))) {187fprintf(stderr, "EVP_DigestVerifyUpdate(hamlet_2) failed.\n");188goto cleanup;189}190if (EVP_DigestVerifyFinal(verify_context, sig_value, sig_len) <= 0) {191fprintf(stderr, "EVP_DigestVerifyFinal failed.\n");192goto cleanup;193}194fprintf(stdout, "Signature verified.\n");195ret = 1;196197cleanup:198/* OpenSSL free functions will ignore NULL arguments */199EVP_PKEY_free(pub_key);200EVP_MD_CTX_free(verify_context);201return ret;202}203204int main(void)205{206OSSL_LIB_CTX *libctx = NULL;207const char *sig_name = "SHA3-512";208size_t sig_len = 0;209unsigned char *sig_value = NULL;210int ret = EXIT_FAILURE;211212libctx = OSSL_LIB_CTX_new();213if (libctx == NULL) {214fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");215goto cleanup;216}217if (!demo_sign(libctx, sig_name, &sig_len, &sig_value)) {218fprintf(stderr, "demo_sign failed.\n");219goto cleanup;220}221if (!demo_verify(libctx, sig_name, sig_len, sig_value)) {222fprintf(stderr, "demo_verify failed.\n");223goto cleanup;224}225ret = EXIT_SUCCESS;226227cleanup:228if (ret != EXIT_SUCCESS)229ERR_print_errors_fp(stderr);230/* OpenSSL free functions will ignore NULL arguments */231OSSL_LIB_CTX_free(libctx);232OPENSSL_free(sig_value);233return ret;234}235236237