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