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