OpenVPN
pkey_test_utils.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2023-2025 Selva Nair <selva.nair@gmail.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by the
12 * Free Software Foundation, either version 2 of the License,
13 * or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, see <https://www.gnu.org/licenses/>.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28
29#include "syshead.h"
30#include "xkey_common.h"
31#include <setjmp.h>
32#include <cmocka.h>
33
34#ifdef HAVE_XKEY_PROVIDER
35
36#include <openssl/core_names.h>
37#include <openssl/evp.h>
38
40
41/* A message for signing */
42static const char *test_msg = "Lorem ipsum dolor sit amet, consectetur "
43 "adipisici elit, sed eiusmod tempor incidunt "
44 "ut labore et dolore magna aliqua.";
45
52int
53digest_sign_verify(EVP_PKEY *privkey, EVP_PKEY *pubkey)
54{
55 uint8_t *sig = NULL;
56 size_t siglen = 0;
57 int ret = 0;
58
59 OSSL_PARAM params[2] = { OSSL_PARAM_END };
60 const char *mdname = "SHA256";
61
62 if (EVP_PKEY_get_id(privkey) == EVP_PKEY_RSA)
63 {
64 const char *padmode = "pss"; /* RSA_PSS: for all other params, use defaults */
65 params[0] =
66 OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, (char *)padmode, 0);
67 params[1] = OSSL_PARAM_construct_end();
68 }
69 else if (EVP_PKEY_get_id(privkey) == EVP_PKEY_EC)
70 {
71 params[0] = OSSL_PARAM_construct_end();
72 }
73 else
74 {
75 print_error("Unknown key type in digest_sign_verify()");
76 return ret;
77 }
78
79 EVP_PKEY_CTX *pctx = NULL;
80 EVP_MD_CTX *mctx = EVP_MD_CTX_new();
81
82 if (!mctx || EVP_DigestSignInit_ex(mctx, &pctx, mdname, tls_libctx, NULL, privkey, params) <= 0)
83 {
84 /* cmocka assert output for these kinds of failures is hardly explanatory,
85 * print a message and assert in caller. */
86 print_error("Failed to initialize EVP_DigestSignInit_ex()\n");
87 goto done;
88 }
89
90 /* sign with sig = NULL to get required siglen */
91 if (EVP_DigestSign(mctx, sig, &siglen, (uint8_t *)test_msg, strlen(test_msg)) != 1)
92 {
93 print_error("EVP_DigestSign: failed to get required signature size");
94 goto done;
95 }
96 assert_true(siglen > 0);
97
98 if ((sig = test_calloc(1, siglen)) == NULL)
99 {
100 print_error("Out of memory");
101 goto done;
102 }
103 if (EVP_DigestSign(mctx, sig, &siglen, (uint8_t *)test_msg, strlen(test_msg)) != 1)
104 {
105 print_error("EVP_DigestSign: signing failed");
106 goto done;
107 }
108
109 /*
110 * Now validate the signature using OpenSSL. Just use the public key
111 * which is a native OpenSSL key.
112 */
113 EVP_MD_CTX_free(mctx); /* this also frees pctx */
114 mctx = EVP_MD_CTX_new();
115 pctx = NULL;
116 if (!mctx
117 || EVP_DigestVerifyInit_ex(mctx, &pctx, mdname, tls_libctx, NULL, pubkey, params) <= 0)
118 {
119 print_error("Failed to initialize EVP_DigestVerifyInit_ex()");
120 goto done;
121 }
122 if (EVP_DigestVerify(mctx, sig, siglen, (uint8_t *)test_msg, strlen(test_msg)) != 1)
123 {
124 print_error("EVP_DigestVerify failed");
125 goto done;
126 }
127 ret = 1;
128
129done:
130 if (mctx)
131 {
132 EVP_MD_CTX_free(mctx); /* this also frees pctx */
133 }
134 test_free(sig);
135 return ret;
136}
137#endif /* HAVE_XKEY_PROVIDER */
void OSSL_LIB_CTX
OSSL_LIB_CTX * tls_libctx
Definition ssl_openssl.c:78
int digest_sign_verify(EVP_PKEY *privkey, EVP_PKEY *pubkey)