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