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