xref: /freebsd/crypto/openssl/demos/signature/EVP_ED_Signature_demo.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre Pronchery /*-
2*e7be843bSPierre Pronchery  * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery  *
4*e7be843bSPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*e7be843bSPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6*e7be843bSPierre Pronchery  * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery  * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery  */
9*e7be843bSPierre Pronchery 
10*e7be843bSPierre Pronchery /*
11*e7be843bSPierre Pronchery  * This demonstration will calculate and verify an ED25519 signature of
12*e7be843bSPierre Pronchery  * a message using  EVP_DigestSign() and EVP_DigestVerify().
13*e7be843bSPierre Pronchery  */
14*e7be843bSPierre Pronchery 
15*e7be843bSPierre Pronchery #include <string.h>
16*e7be843bSPierre Pronchery #include <stdio.h>
17*e7be843bSPierre Pronchery #include <openssl/err.h>
18*e7be843bSPierre Pronchery #include <openssl/evp.h>
19*e7be843bSPierre Pronchery #include <openssl/core_names.h>
20*e7be843bSPierre Pronchery 
21*e7be843bSPierre Pronchery /* A test message to be signed (TBS) */
22*e7be843bSPierre Pronchery static const unsigned char hamlet[] =
23*e7be843bSPierre Pronchery     "To be, or not to be, that is the question,\n"
24*e7be843bSPierre Pronchery     "Whether tis nobler in the minde to suffer\n"
25*e7be843bSPierre Pronchery     "The slings and arrowes of outragious fortune,\n"
26*e7be843bSPierre Pronchery     "Or to take Armes again in a sea of troubles,\n";
27*e7be843bSPierre Pronchery 
demo_sign(EVP_PKEY * priv,const unsigned char * tbs,size_t tbs_len,OSSL_LIB_CTX * libctx,unsigned char ** sig_out_value,size_t * sig_out_len)28*e7be843bSPierre Pronchery static int demo_sign(EVP_PKEY *priv,
29*e7be843bSPierre Pronchery                      const unsigned char *tbs, size_t tbs_len,
30*e7be843bSPierre Pronchery                      OSSL_LIB_CTX *libctx,
31*e7be843bSPierre Pronchery                      unsigned char **sig_out_value,
32*e7be843bSPierre Pronchery                      size_t *sig_out_len)
33*e7be843bSPierre Pronchery {
34*e7be843bSPierre Pronchery     int ret = 0;
35*e7be843bSPierre Pronchery     size_t sig_len;
36*e7be843bSPierre Pronchery     unsigned char *sig_value = NULL;
37*e7be843bSPierre Pronchery     EVP_MD_CTX *sign_context = NULL;
38*e7be843bSPierre Pronchery 
39*e7be843bSPierre Pronchery     /* Create a signature context */
40*e7be843bSPierre Pronchery     sign_context = EVP_MD_CTX_new();
41*e7be843bSPierre Pronchery     if (sign_context == NULL) {
42*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_MD_CTX_new failed.\n");
43*e7be843bSPierre Pronchery         goto cleanup;
44*e7be843bSPierre Pronchery     }
45*e7be843bSPierre Pronchery 
46*e7be843bSPierre Pronchery     /*
47*e7be843bSPierre Pronchery      * Initialize the sign context using an ED25519 private key
48*e7be843bSPierre Pronchery      * Notice that the digest name must NOT be used.
49*e7be843bSPierre Pronchery      * In this demo we don't specify any additional parameters via
50*e7be843bSPierre Pronchery      * OSSL_PARAM, which means it will use default values.
51*e7be843bSPierre Pronchery      * For more information, refer to doc/man7/EVP_SIGNATURE-ED25519.pod
52*e7be843bSPierre Pronchery      * "ED25519 and ED448 Signature Parameters"
53*e7be843bSPierre Pronchery      */
54*e7be843bSPierre Pronchery     if (!EVP_DigestSignInit_ex(sign_context, NULL, NULL, libctx, NULL, priv, NULL)) {
55*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_DigestSignInit_ex failed.\n");
56*e7be843bSPierre Pronchery         goto cleanup;
57*e7be843bSPierre Pronchery     }
58*e7be843bSPierre Pronchery 
59*e7be843bSPierre Pronchery     /* Calculate the required size for the signature by passing a NULL buffer. */
60*e7be843bSPierre Pronchery     if (!EVP_DigestSign(sign_context, NULL, &sig_len, tbs, tbs_len)) {
61*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_DigestSign using NULL buffer failed.\n");
62*e7be843bSPierre Pronchery         goto cleanup;
63*e7be843bSPierre Pronchery     }
64*e7be843bSPierre Pronchery     sig_value = OPENSSL_malloc(sig_len);
65*e7be843bSPierre Pronchery     if (sig_value == NULL) {
66*e7be843bSPierre Pronchery         fprintf(stderr, "OPENSSL_malloc failed.\n");
67*e7be843bSPierre Pronchery         goto cleanup;
68*e7be843bSPierre Pronchery     }
69*e7be843bSPierre Pronchery     fprintf(stdout, "Generating signature:\n");
70*e7be843bSPierre Pronchery     if (!EVP_DigestSign(sign_context, sig_value, &sig_len, tbs, tbs_len)) {
71*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_DigestSign failed.\n");
72*e7be843bSPierre Pronchery         goto cleanup;
73*e7be843bSPierre Pronchery     }
74*e7be843bSPierre Pronchery     *sig_out_len = sig_len;
75*e7be843bSPierre Pronchery     *sig_out_value = sig_value;
76*e7be843bSPierre Pronchery     BIO_dump_indent_fp(stdout, sig_value, sig_len, 2);
77*e7be843bSPierre Pronchery     fprintf(stdout, "\n");
78*e7be843bSPierre Pronchery     ret = 1;
79*e7be843bSPierre Pronchery 
80*e7be843bSPierre Pronchery cleanup:
81*e7be843bSPierre Pronchery     if (!ret)
82*e7be843bSPierre Pronchery         OPENSSL_free(sig_value);
83*e7be843bSPierre Pronchery     EVP_MD_CTX_free(sign_context);
84*e7be843bSPierre Pronchery     return ret;
85*e7be843bSPierre Pronchery }
86*e7be843bSPierre Pronchery 
demo_verify(EVP_PKEY * pub,const unsigned char * tbs,size_t tbs_len,const unsigned char * sig_value,size_t sig_len,OSSL_LIB_CTX * libctx)87*e7be843bSPierre Pronchery static int demo_verify(EVP_PKEY *pub,
88*e7be843bSPierre Pronchery                        const unsigned char *tbs, size_t tbs_len,
89*e7be843bSPierre Pronchery                        const unsigned char *sig_value, size_t sig_len,
90*e7be843bSPierre Pronchery                        OSSL_LIB_CTX *libctx)
91*e7be843bSPierre Pronchery {
92*e7be843bSPierre Pronchery     int ret = 0;
93*e7be843bSPierre Pronchery     EVP_MD_CTX *verify_context = NULL;
94*e7be843bSPierre Pronchery 
95*e7be843bSPierre Pronchery     /*
96*e7be843bSPierre Pronchery      * Make a verify signature context to hold temporary state
97*e7be843bSPierre Pronchery      * during signature verification
98*e7be843bSPierre Pronchery      */
99*e7be843bSPierre Pronchery     verify_context = EVP_MD_CTX_new();
100*e7be843bSPierre Pronchery     if (verify_context == NULL) {
101*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_MD_CTX_new failed.\n");
102*e7be843bSPierre Pronchery         goto cleanup;
103*e7be843bSPierre Pronchery     }
104*e7be843bSPierre Pronchery     /* Initialize the verify context with a ED25519 public key */
105*e7be843bSPierre Pronchery     if (!EVP_DigestVerifyInit_ex(verify_context, NULL, NULL,
106*e7be843bSPierre Pronchery                                  libctx, NULL, pub, NULL)) {
107*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_DigestVerifyInit_ex failed.\n");
108*e7be843bSPierre Pronchery         goto cleanup;
109*e7be843bSPierre Pronchery     }
110*e7be843bSPierre Pronchery     /*
111*e7be843bSPierre Pronchery      * ED25519 only supports the one shot interface using EVP_DigestVerify()
112*e7be843bSPierre Pronchery      * The streaming EVP_DigestVerifyUpdate() API is not supported.
113*e7be843bSPierre Pronchery      */
114*e7be843bSPierre Pronchery     if (!EVP_DigestVerify(verify_context, sig_value, sig_len,
115*e7be843bSPierre Pronchery                           tbs, tbs_len)) {
116*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_DigestVerify() failed.\n");
117*e7be843bSPierre Pronchery         goto cleanup;
118*e7be843bSPierre Pronchery     }
119*e7be843bSPierre Pronchery     fprintf(stdout, "Signature verified.\n");
120*e7be843bSPierre Pronchery     ret = 1;
121*e7be843bSPierre Pronchery 
122*e7be843bSPierre Pronchery cleanup:
123*e7be843bSPierre Pronchery     EVP_MD_CTX_free(verify_context);
124*e7be843bSPierre Pronchery     return ret;
125*e7be843bSPierre Pronchery }
126*e7be843bSPierre Pronchery 
create_key(OSSL_LIB_CTX * libctx,EVP_PKEY ** privout,EVP_PKEY ** pubout)127*e7be843bSPierre Pronchery static int create_key(OSSL_LIB_CTX *libctx,
128*e7be843bSPierre Pronchery                       EVP_PKEY **privout, EVP_PKEY **pubout)
129*e7be843bSPierre Pronchery {
130*e7be843bSPierre Pronchery     int ret = 0;
131*e7be843bSPierre Pronchery     EVP_PKEY *priv = NULL, *pub = NULL;
132*e7be843bSPierre Pronchery     unsigned char pubdata[32];
133*e7be843bSPierre Pronchery     size_t pubdata_len = 0;
134*e7be843bSPierre Pronchery 
135*e7be843bSPierre Pronchery     /*
136*e7be843bSPierre Pronchery      * In this demo we just create a keypair, and extract the
137*e7be843bSPierre Pronchery      * public key. We could also use EVP_PKEY_new_raw_private_key_ex()
138*e7be843bSPierre Pronchery      * to create a key from raw data.
139*e7be843bSPierre Pronchery      */
140*e7be843bSPierre Pronchery     priv = EVP_PKEY_Q_keygen(libctx, NULL, "ED25519");
141*e7be843bSPierre Pronchery     if (priv == NULL) {
142*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_PKEY_Q_keygen() failed\n");
143*e7be843bSPierre Pronchery         goto end;
144*e7be843bSPierre Pronchery     }
145*e7be843bSPierre Pronchery 
146*e7be843bSPierre Pronchery     if (!EVP_PKEY_get_octet_string_param(priv,
147*e7be843bSPierre Pronchery                                          OSSL_PKEY_PARAM_PUB_KEY,
148*e7be843bSPierre Pronchery                                          pubdata,
149*e7be843bSPierre Pronchery                                          sizeof(pubdata),
150*e7be843bSPierre Pronchery                                          &pubdata_len)) {
151*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_PKEY_get_octet_string_param() failed\n");
152*e7be843bSPierre Pronchery         goto end;
153*e7be843bSPierre Pronchery     }
154*e7be843bSPierre Pronchery     pub = EVP_PKEY_new_raw_public_key_ex(libctx, "ED25519", NULL, pubdata, pubdata_len);
155*e7be843bSPierre Pronchery     if (pub == NULL) {
156*e7be843bSPierre Pronchery         fprintf(stderr, "EVP_PKEY_new_raw_public_key_ex() failed\n");
157*e7be843bSPierre Pronchery         goto end;
158*e7be843bSPierre Pronchery     }
159*e7be843bSPierre Pronchery     ret = 1;
160*e7be843bSPierre Pronchery end:
161*e7be843bSPierre Pronchery     if (ret) {
162*e7be843bSPierre Pronchery         *pubout = pub;
163*e7be843bSPierre Pronchery         *privout = priv;
164*e7be843bSPierre Pronchery     } else {
165*e7be843bSPierre Pronchery         EVP_PKEY_free(priv);
166*e7be843bSPierre Pronchery     }
167*e7be843bSPierre Pronchery     return ret;
168*e7be843bSPierre Pronchery }
169*e7be843bSPierre Pronchery 
main(void)170*e7be843bSPierre Pronchery int main(void)
171*e7be843bSPierre Pronchery {
172*e7be843bSPierre Pronchery     OSSL_LIB_CTX *libctx = NULL;
173*e7be843bSPierre Pronchery     size_t sig_len = 0;
174*e7be843bSPierre Pronchery     unsigned char *sig_value = NULL;
175*e7be843bSPierre Pronchery     int ret = EXIT_FAILURE;
176*e7be843bSPierre Pronchery     EVP_PKEY *priv = NULL, *pub = NULL;
177*e7be843bSPierre Pronchery 
178*e7be843bSPierre Pronchery     libctx = OSSL_LIB_CTX_new();
179*e7be843bSPierre Pronchery     if (libctx == NULL) {
180*e7be843bSPierre Pronchery         fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");
181*e7be843bSPierre Pronchery         goto cleanup;
182*e7be843bSPierre Pronchery     }
183*e7be843bSPierre Pronchery     if (!create_key(libctx, &priv, &pub)) {
184*e7be843bSPierre Pronchery         fprintf(stderr, "Failed to create key.\n");
185*e7be843bSPierre Pronchery         goto cleanup;
186*e7be843bSPierre Pronchery     }
187*e7be843bSPierre Pronchery 
188*e7be843bSPierre Pronchery     if (!demo_sign(priv, hamlet, sizeof(hamlet), libctx,
189*e7be843bSPierre Pronchery                    &sig_value, &sig_len)) {
190*e7be843bSPierre Pronchery         fprintf(stderr, "demo_sign failed.\n");
191*e7be843bSPierre Pronchery         goto cleanup;
192*e7be843bSPierre Pronchery     }
193*e7be843bSPierre Pronchery     if (!demo_verify(pub, hamlet, sizeof(hamlet),
194*e7be843bSPierre Pronchery                      sig_value, sig_len, libctx)) {
195*e7be843bSPierre Pronchery         fprintf(stderr, "demo_verify failed.\n");
196*e7be843bSPierre Pronchery         goto cleanup;
197*e7be843bSPierre Pronchery     }
198*e7be843bSPierre Pronchery     ret = EXIT_SUCCESS;
199*e7be843bSPierre Pronchery 
200*e7be843bSPierre Pronchery cleanup:
201*e7be843bSPierre Pronchery     if (ret != EXIT_SUCCESS)
202*e7be843bSPierre Pronchery         ERR_print_errors_fp(stderr);
203*e7be843bSPierre Pronchery     EVP_PKEY_free(pub);
204*e7be843bSPierre Pronchery     EVP_PKEY_free(priv);
205*e7be843bSPierre Pronchery     OSSL_LIB_CTX_free(libctx);
206*e7be843bSPierre Pronchery     OPENSSL_free(sig_value);
207*e7be843bSPierre Pronchery     return ret;
208*e7be843bSPierre Pronchery }
209