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