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