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 = "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 static const char *hamlet_2 = "And by opposing, end them, to die to sleep;\n"
32 "No more, and by a sleep, to say we end\n"
33 "The heart-ache, and the thousand natural shocks\n"
34 "That flesh is heir to? tis a consumation\n";
35
36 /*
37 * For demo_sign, load EC private key priv_key from priv_key_der[].
38 * For demo_verify, load EC public key pub_key from pub_key_der[].
39 */
get_key(OSSL_LIB_CTX * libctx,const char * propq,int public)40 static EVP_PKEY *get_key(OSSL_LIB_CTX *libctx, const char *propq, int public)
41 {
42 OSSL_DECODER_CTX *dctx = NULL;
43 EVP_PKEY *pkey = NULL;
44 int selection;
45 const unsigned char *data;
46 size_t data_len;
47
48 if (public) {
49 selection = EVP_PKEY_PUBLIC_KEY;
50 data = pub_key_der;
51 data_len = sizeof(pub_key_der);
52 } else {
53 selection = EVP_PKEY_KEYPAIR;
54 data = priv_key_der;
55 data_len = sizeof(priv_key_der);
56 }
57 dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, "EC",
58 selection, libctx, propq);
59 (void)OSSL_DECODER_from_data(dctx, &data, &data_len);
60 OSSL_DECODER_CTX_free(dctx);
61 if (pkey == NULL)
62 fprintf(stderr, "Failed to load %s key.\n", public ? "public" : "private");
63 return pkey;
64 }
65
demo_sign(OSSL_LIB_CTX * libctx,const char * sig_name,size_t * sig_out_len,unsigned char ** sig_out_value)66 static int demo_sign(OSSL_LIB_CTX *libctx, const char *sig_name,
67 size_t *sig_out_len, unsigned char **sig_out_value)
68 {
69 int ret = 0, public = 0;
70 size_t sig_len;
71 unsigned char *sig_value = NULL;
72 const char *propq = NULL;
73 EVP_MD_CTX *sign_context = NULL;
74 EVP_PKEY *priv_key = NULL;
75
76 /* Get private key */
77 priv_key = get_key(libctx, propq, public);
78 if (priv_key == NULL) {
79 fprintf(stderr, "Get private key failed.\n");
80 goto cleanup;
81 }
82 /*
83 * Make a message signature context to hold temporary state
84 * during signature creation
85 */
86 sign_context = EVP_MD_CTX_new();
87 if (sign_context == NULL) {
88 fprintf(stderr, "EVP_MD_CTX_new failed.\n");
89 goto cleanup;
90 }
91 /*
92 * Initialize the sign context to use the fetched
93 * sign provider.
94 */
95 if (!EVP_DigestSignInit_ex(sign_context, NULL, sig_name,
96 libctx, NULL, priv_key, NULL)) {
97 fprintf(stderr, "EVP_DigestSignInit_ex failed.\n");
98 goto cleanup;
99 }
100 /*
101 * EVP_DigestSignUpdate() can be called several times on the same context
102 * to include additional data.
103 */
104 if (!EVP_DigestSignUpdate(sign_context, hamlet_1, strlen(hamlet_1))) {
105 fprintf(stderr, "EVP_DigestSignUpdate(hamlet_1) failed.\n");
106 goto cleanup;
107 }
108 if (!EVP_DigestSignUpdate(sign_context, hamlet_2, strlen(hamlet_2))) {
109 fprintf(stderr, "EVP_DigestSignUpdate(hamlet_2) failed.\n");
110 goto cleanup;
111 }
112 /* Call EVP_DigestSignFinal to get signature length sig_len */
113 if (!EVP_DigestSignFinal(sign_context, NULL, &sig_len)) {
114 fprintf(stderr, "EVP_DigestSignFinal failed.\n");
115 goto cleanup;
116 }
117 if (sig_len <= 0) {
118 fprintf(stderr, "EVP_DigestSignFinal returned invalid signature length.\n");
119 goto cleanup;
120 }
121 sig_value = OPENSSL_malloc(sig_len);
122 if (sig_value == NULL) {
123 fprintf(stderr, "No memory.\n");
124 goto cleanup;
125 }
126 if (!EVP_DigestSignFinal(sign_context, sig_value, &sig_len)) {
127 fprintf(stderr, "EVP_DigestSignFinal failed.\n");
128 goto cleanup;
129 }
130 *sig_out_len = sig_len;
131 *sig_out_value = sig_value;
132 fprintf(stdout, "Generating signature:\n");
133 BIO_dump_indent_fp(stdout, sig_value, sig_len, 2);
134 fprintf(stdout, "\n");
135 ret = 1;
136
137 cleanup:
138 /* OpenSSL free functions will ignore NULL arguments */
139 if (!ret)
140 OPENSSL_free(sig_value);
141 EVP_PKEY_free(priv_key);
142 EVP_MD_CTX_free(sign_context);
143 return ret;
144 }
145
demo_verify(OSSL_LIB_CTX * libctx,const char * sig_name,size_t sig_len,unsigned char * sig_value)146 static int demo_verify(OSSL_LIB_CTX *libctx, const char *sig_name,
147 size_t sig_len, unsigned char *sig_value)
148 {
149 int ret = 0, public = 1;
150 const char *propq = NULL;
151 EVP_MD_CTX *verify_context = NULL;
152 EVP_PKEY *pub_key = NULL;
153
154 /*
155 * Make a verify signature context to hold temporary state
156 * during signature verification
157 */
158 verify_context = EVP_MD_CTX_new();
159 if (verify_context == NULL) {
160 fprintf(stderr, "EVP_MD_CTX_new failed.\n");
161 goto cleanup;
162 }
163 /* Get public key */
164 pub_key = get_key(libctx, propq, public);
165 if (pub_key == NULL) {
166 fprintf(stderr, "Get public key failed.\n");
167 goto cleanup;
168 }
169 /* Verify */
170 if (!EVP_DigestVerifyInit_ex(verify_context, NULL, sig_name,
171 libctx, NULL, pub_key, NULL)) {
172 fprintf(stderr, "EVP_DigestVerifyInit failed.\n");
173 goto cleanup;
174 }
175 /*
176 * EVP_DigestVerifyUpdate() can be called several times on the same context
177 * to include additional data.
178 */
179 if (!EVP_DigestVerifyUpdate(verify_context, hamlet_1, strlen(hamlet_1))) {
180 fprintf(stderr, "EVP_DigestVerifyUpdate(hamlet_1) failed.\n");
181 goto cleanup;
182 }
183 if (!EVP_DigestVerifyUpdate(verify_context, hamlet_2, strlen(hamlet_2))) {
184 fprintf(stderr, "EVP_DigestVerifyUpdate(hamlet_2) failed.\n");
185 goto cleanup;
186 }
187 if (EVP_DigestVerifyFinal(verify_context, sig_value, sig_len) <= 0) {
188 fprintf(stderr, "EVP_DigestVerifyFinal failed.\n");
189 goto cleanup;
190 }
191 fprintf(stdout, "Signature verified.\n");
192 ret = 1;
193
194 cleanup:
195 /* OpenSSL free functions will ignore NULL arguments */
196 EVP_PKEY_free(pub_key);
197 EVP_MD_CTX_free(verify_context);
198 return ret;
199 }
200
main(void)201 int main(void)
202 {
203 OSSL_LIB_CTX *libctx = NULL;
204 const char *sig_name = "SHA3-512";
205 size_t sig_len = 0;
206 unsigned char *sig_value = NULL;
207 int ret = EXIT_FAILURE;
208
209 libctx = OSSL_LIB_CTX_new();
210 if (libctx == NULL) {
211 fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");
212 goto cleanup;
213 }
214 if (!demo_sign(libctx, sig_name, &sig_len, &sig_value)) {
215 fprintf(stderr, "demo_sign failed.\n");
216 goto cleanup;
217 }
218 if (!demo_verify(libctx, sig_name, sig_len, sig_value)) {
219 fprintf(stderr, "demo_verify failed.\n");
220 goto cleanup;
221 }
222 ret = EXIT_SUCCESS;
223
224 cleanup:
225 if (ret != EXIT_SUCCESS)
226 ERR_print_errors_fp(stderr);
227 /* OpenSSL free functions will ignore NULL arguments */
228 OSSL_LIB_CTX_free(libctx);
229 OPENSSL_free(sig_value);
230 return ret;
231 }
232