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