xref: /src/crypto/openssl/demos/signature/EVP_DSA_Signature_demo.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*-
2  * Copyright 2022-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_PKEY*, EVP_DigestSign* and EVP_DigestVerify*
12  * methods to calculate public/private DSA keypair and to sign and verify
13  * two static buffers.
14  */
15 
16 #include <string.h>
17 #include <stdio.h>
18 #include <openssl/err.h>
19 #include <openssl/evp.h>
20 #include <openssl/decoder.h>
21 #include <openssl/dsa.h>
22 
23 /*
24  * This demonstration will calculate and verify a signature of data using
25  * the soliloquy from Hamlet scene 1 act 3
26  */
27 
28 static const char *hamlet_1 = "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 static const char *hamlet_2 = "And by opposing, end them, to die to sleep;\n"
33                               "No more, and by a sleep, to say we end\n"
34                               "The heart-ache, and the thousand natural shocks\n"
35                               "That flesh is heir to? tis a consumation\n";
36 
37 static const char ALG[] = "DSA";
38 static const char DIGEST[] = "SHA256";
39 static const int NUMBITS = 2048;
40 static const char *const PROPQUERY = NULL;
41 
generate_dsa_params(OSSL_LIB_CTX * libctx,EVP_PKEY ** p_params)42 static int generate_dsa_params(OSSL_LIB_CTX *libctx,
43     EVP_PKEY **p_params)
44 {
45     int ret = 0;
46 
47     EVP_PKEY_CTX *pkey_ctx = NULL;
48     EVP_PKEY *params = NULL;
49 
50     pkey_ctx = EVP_PKEY_CTX_new_from_name(libctx, ALG, PROPQUERY);
51     if (pkey_ctx == NULL)
52         goto end;
53 
54     if (EVP_PKEY_paramgen_init(pkey_ctx) <= 0)
55         goto end;
56 
57     if (EVP_PKEY_CTX_set_dsa_paramgen_bits(pkey_ctx, NUMBITS) <= 0)
58         goto end;
59     if (EVP_PKEY_paramgen(pkey_ctx, &params) <= 0)
60         goto end;
61     if (params == NULL)
62         goto end;
63 
64     ret = 1;
65 end:
66     if (ret != 1) {
67         EVP_PKEY_free(params);
68         params = NULL;
69     }
70     EVP_PKEY_CTX_free(pkey_ctx);
71     *p_params = params;
72     fprintf(stdout, "Params:\n");
73     EVP_PKEY_print_params_fp(stdout, params, 4, NULL);
74     fprintf(stdout, "\n");
75 
76     return ret;
77 }
78 
generate_dsa_key(OSSL_LIB_CTX * libctx,EVP_PKEY * params,EVP_PKEY ** p_pkey)79 static int generate_dsa_key(OSSL_LIB_CTX *libctx,
80     EVP_PKEY *params,
81     EVP_PKEY **p_pkey)
82 {
83     int ret = 0;
84 
85     EVP_PKEY_CTX *ctx = NULL;
86     EVP_PKEY *pkey = NULL;
87 
88     ctx = EVP_PKEY_CTX_new_from_pkey(libctx, params,
89         NULL);
90     if (ctx == NULL)
91         goto end;
92     if (EVP_PKEY_keygen_init(ctx) <= 0)
93         goto end;
94 
95     if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
96         goto end;
97     if (pkey == NULL)
98         goto end;
99 
100     ret = 1;
101 end:
102     if (ret != 1) {
103         EVP_PKEY_free(pkey);
104         pkey = NULL;
105     }
106     EVP_PKEY_CTX_free(ctx);
107     *p_pkey = pkey;
108     fprintf(stdout, "Generating public/private key pair:\n");
109     EVP_PKEY_print_public_fp(stdout, pkey, 4, NULL);
110     fprintf(stdout, "\n");
111     EVP_PKEY_print_private_fp(stdout, pkey, 4, NULL);
112     fprintf(stdout, "\n");
113     EVP_PKEY_print_params_fp(stdout, pkey, 4, NULL);
114     fprintf(stdout, "\n");
115 
116     return ret;
117 }
118 
extract_public_key(const EVP_PKEY * pkey,OSSL_PARAM ** p_public_key)119 static int extract_public_key(const EVP_PKEY *pkey,
120     OSSL_PARAM **p_public_key)
121 {
122     int ret = 0;
123     OSSL_PARAM *public_key = NULL;
124 
125     if (EVP_PKEY_todata(pkey, EVP_PKEY_PUBLIC_KEY, &public_key) != 1)
126         goto end;
127 
128     ret = 1;
129 end:
130     if (ret != 1) {
131         OSSL_PARAM_free(public_key);
132         public_key = NULL;
133     }
134     *p_public_key = public_key;
135 
136     return ret;
137 }
138 
extract_keypair(const EVP_PKEY * pkey,OSSL_PARAM ** p_keypair)139 static int extract_keypair(const EVP_PKEY *pkey,
140     OSSL_PARAM **p_keypair)
141 {
142     int ret = 0;
143     OSSL_PARAM *keypair = NULL;
144 
145     if (EVP_PKEY_todata(pkey, EVP_PKEY_KEYPAIR, &keypair) != 1)
146         goto end;
147 
148     ret = 1;
149 end:
150     if (ret != 1) {
151         OSSL_PARAM_free(keypair);
152         keypair = NULL;
153     }
154     *p_keypair = keypair;
155 
156     return ret;
157 }
158 
demo_sign(OSSL_LIB_CTX * libctx,size_t * p_sig_len,unsigned char ** p_sig_value,OSSL_PARAM keypair[])159 static int demo_sign(OSSL_LIB_CTX *libctx,
160     size_t *p_sig_len, unsigned char **p_sig_value,
161     OSSL_PARAM keypair[])
162 {
163     int ret = 0;
164     size_t sig_len = 0;
165     unsigned char *sig_value = NULL;
166     EVP_MD_CTX *ctx = NULL;
167     EVP_PKEY_CTX *pkey_ctx = NULL;
168     EVP_PKEY *pkey = NULL;
169 
170     pkey_ctx = EVP_PKEY_CTX_new_from_name(libctx, ALG, PROPQUERY);
171     if (pkey_ctx == NULL)
172         goto end;
173     if (EVP_PKEY_fromdata_init(pkey_ctx) != 1)
174         goto end;
175     if (EVP_PKEY_fromdata(pkey_ctx, &pkey, EVP_PKEY_KEYPAIR, keypair) != 1)
176         goto end;
177 
178     ctx = EVP_MD_CTX_create();
179     if (ctx == NULL)
180         goto end;
181 
182     if (EVP_DigestSignInit_ex(ctx, NULL, DIGEST, libctx, NULL, pkey, NULL) != 1)
183         goto end;
184 
185     if (EVP_DigestSignUpdate(ctx, hamlet_1, sizeof(hamlet_1)) != 1)
186         goto end;
187 
188     if (EVP_DigestSignUpdate(ctx, hamlet_2, sizeof(hamlet_2)) != 1)
189         goto end;
190 
191     /* Calculate the signature size */
192     if (EVP_DigestSignFinal(ctx, NULL, &sig_len) != 1)
193         goto end;
194     if (sig_len == 0)
195         goto end;
196 
197     sig_value = OPENSSL_malloc(sig_len);
198     if (sig_value == NULL)
199         goto end;
200 
201     /* Calculate the signature */
202     if (EVP_DigestSignFinal(ctx, sig_value, &sig_len) != 1)
203         goto end;
204 
205     ret = 1;
206 end:
207     EVP_MD_CTX_free(ctx);
208     if (ret != 1) {
209         OPENSSL_free(sig_value);
210         sig_len = 0;
211         sig_value = NULL;
212     }
213     *p_sig_len = sig_len;
214     *p_sig_value = sig_value;
215     EVP_PKEY_free(pkey);
216     EVP_PKEY_CTX_free(pkey_ctx);
217 
218     fprintf(stdout, "Generating signature:\n");
219     BIO_dump_indent_fp(stdout, sig_value, sig_len, 2);
220     fprintf(stdout, "\n");
221     return ret;
222 }
223 
demo_verify(OSSL_LIB_CTX * libctx,size_t sig_len,unsigned char * sig_value,OSSL_PARAM public_key[])224 static int demo_verify(OSSL_LIB_CTX *libctx,
225     size_t sig_len, unsigned char *sig_value,
226     OSSL_PARAM public_key[])
227 {
228     int ret = 0;
229     EVP_MD_CTX *ctx = NULL;
230     EVP_PKEY_CTX *pkey_ctx = NULL;
231     EVP_PKEY *pkey = NULL;
232 
233     pkey_ctx = EVP_PKEY_CTX_new_from_name(libctx, ALG, PROPQUERY);
234     if (pkey_ctx == NULL)
235         goto end;
236     if (EVP_PKEY_fromdata_init(pkey_ctx) != 1)
237         goto end;
238     if (EVP_PKEY_fromdata(pkey_ctx, &pkey, EVP_PKEY_PUBLIC_KEY, public_key) != 1)
239         goto end;
240 
241     ctx = EVP_MD_CTX_create();
242     if (ctx == NULL)
243         goto end;
244 
245     if (EVP_DigestVerifyInit_ex(ctx, NULL, DIGEST, libctx, NULL, pkey, NULL) != 1)
246         goto end;
247 
248     if (EVP_DigestVerifyUpdate(ctx, hamlet_1, sizeof(hamlet_1)) != 1)
249         goto end;
250 
251     if (EVP_DigestVerifyUpdate(ctx, hamlet_2, sizeof(hamlet_2)) != 1)
252         goto end;
253 
254     if (EVP_DigestVerifyFinal(ctx, sig_value, sig_len) != 1)
255         goto end;
256 
257     ret = 1;
258 end:
259     EVP_PKEY_free(pkey);
260     EVP_PKEY_CTX_free(pkey_ctx);
261     EVP_MD_CTX_free(ctx);
262     return ret;
263 }
264 
main(void)265 int main(void)
266 {
267     int ret = EXIT_FAILURE;
268     OSSL_LIB_CTX *libctx = NULL;
269     EVP_PKEY *params = NULL;
270     EVP_PKEY *pkey = NULL;
271     OSSL_PARAM *public_key = NULL;
272     OSSL_PARAM *keypair = NULL;
273     size_t sig_len = 0;
274     unsigned char *sig_value = NULL;
275 
276     libctx = OSSL_LIB_CTX_new();
277     if (libctx == NULL)
278         goto end;
279 
280     if (generate_dsa_params(libctx, &params) != 1)
281         goto end;
282 
283     if (generate_dsa_key(libctx, params, &pkey) != 1)
284         goto end;
285 
286     if (extract_public_key(pkey, &public_key) != 1)
287         goto end;
288 
289     if (extract_keypair(pkey, &keypair) != 1)
290         goto end;
291 
292     /* The signer signs with his private key, and distributes his public key */
293     if (demo_sign(libctx, &sig_len, &sig_value, keypair) != 1)
294         goto end;
295 
296     /* A verifier uses the signers public key to verify the signature */
297     if (demo_verify(libctx, sig_len, sig_value, public_key) != 1)
298         goto end;
299 
300     ret = EXIT_SUCCESS;
301 end:
302     if (ret != EXIT_SUCCESS)
303         ERR_print_errors_fp(stderr);
304 
305     OPENSSL_free(sig_value);
306     EVP_PKEY_free(params);
307     EVP_PKEY_free(pkey);
308     OSSL_PARAM_free(public_key);
309     OSSL_PARAM_free(keypair);
310     OSSL_LIB_CTX_free(libctx);
311 
312     return ret;
313 }
314