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