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