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