1*e0c4386eSCy Schubert /*
2*e0c4386eSCy Schubert * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert *
4*e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the "License"). You may not use
5*e0c4386eSCy Schubert * this file except in compliance with the License. You can obtain a copy
6*e0c4386eSCy Schubert * in the file LICENSE in the source distribution or at
7*e0c4386eSCy Schubert * https://www.openssl.org/source/license.html
8*e0c4386eSCy Schubert */
9*e0c4386eSCy Schubert
10*e0c4386eSCy Schubert #include <stdio.h>
11*e0c4386eSCy Schubert #include <stdlib.h>
12*e0c4386eSCy Schubert #include <openssl/core_names.h>
13*e0c4386eSCy Schubert #include <openssl/evp.h>
14*e0c4386eSCy Schubert #include <openssl/rsa.h>
15*e0c4386eSCy Schubert #include <openssl/params.h>
16*e0c4386eSCy Schubert #include <openssl/err.h>
17*e0c4386eSCy Schubert #include <openssl/bio.h>
18*e0c4386eSCy Schubert #include "rsa_pss.h"
19*e0c4386eSCy Schubert
20*e0c4386eSCy Schubert /* The data to be signed. This will be hashed. */
21*e0c4386eSCy Schubert static const char test_message[] =
22*e0c4386eSCy Schubert "This is an example message to be signed.";
23*e0c4386eSCy Schubert
24*e0c4386eSCy Schubert /* A property query used for selecting algorithm implementations. */
25*e0c4386eSCy Schubert static const char *propq = NULL;
26*e0c4386eSCy Schubert
27*e0c4386eSCy Schubert /*
28*e0c4386eSCy Schubert * This function demonstrates RSA signing of an arbitrary-length message.
29*e0c4386eSCy Schubert * Hashing is performed automatically. In this example, SHA-256 is used. If you
30*e0c4386eSCy Schubert * have already hashed your message and simply want to sign the hash directly,
31*e0c4386eSCy Schubert * see rsa_pss_direct.c.
32*e0c4386eSCy Schubert */
sign(OSSL_LIB_CTX * libctx,unsigned char ** sig,size_t * sig_len)33*e0c4386eSCy Schubert static int sign(OSSL_LIB_CTX *libctx, unsigned char **sig, size_t *sig_len)
34*e0c4386eSCy Schubert {
35*e0c4386eSCy Schubert int rv = 0;
36*e0c4386eSCy Schubert EVP_PKEY *pkey = NULL;
37*e0c4386eSCy Schubert EVP_MD_CTX *mctx = NULL;
38*e0c4386eSCy Schubert OSSL_PARAM params[2], *p = params;
39*e0c4386eSCy Schubert const unsigned char *ppriv_key = NULL;
40*e0c4386eSCy Schubert
41*e0c4386eSCy Schubert *sig = NULL;
42*e0c4386eSCy Schubert
43*e0c4386eSCy Schubert /* Load DER-encoded RSA private key. */
44*e0c4386eSCy Schubert ppriv_key = rsa_priv_key;
45*e0c4386eSCy Schubert pkey = d2i_PrivateKey_ex(EVP_PKEY_RSA, NULL, &ppriv_key,
46*e0c4386eSCy Schubert sizeof(rsa_priv_key), libctx, propq);
47*e0c4386eSCy Schubert if (pkey == NULL) {
48*e0c4386eSCy Schubert fprintf(stderr, "Failed to load private key\n");
49*e0c4386eSCy Schubert goto end;
50*e0c4386eSCy Schubert }
51*e0c4386eSCy Schubert
52*e0c4386eSCy Schubert /* Create MD context used for signing. */
53*e0c4386eSCy Schubert mctx = EVP_MD_CTX_new();
54*e0c4386eSCy Schubert if (mctx == NULL) {
55*e0c4386eSCy Schubert fprintf(stderr, "Failed to create MD context\n");
56*e0c4386eSCy Schubert goto end;
57*e0c4386eSCy Schubert }
58*e0c4386eSCy Schubert
59*e0c4386eSCy Schubert /* Initialize MD context for signing. */
60*e0c4386eSCy Schubert *p++ = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE,
61*e0c4386eSCy Schubert OSSL_PKEY_RSA_PAD_MODE_PSS, 0);
62*e0c4386eSCy Schubert *p = OSSL_PARAM_construct_end();
63*e0c4386eSCy Schubert
64*e0c4386eSCy Schubert if (EVP_DigestSignInit_ex(mctx, NULL, "SHA256", libctx, propq,
65*e0c4386eSCy Schubert pkey, params) == 0) {
66*e0c4386eSCy Schubert fprintf(stderr, "Failed to initialize signing context\n");
67*e0c4386eSCy Schubert goto end;
68*e0c4386eSCy Schubert }
69*e0c4386eSCy Schubert
70*e0c4386eSCy Schubert /*
71*e0c4386eSCy Schubert * Feed data to be signed into the algorithm. This may
72*e0c4386eSCy Schubert * be called multiple times.
73*e0c4386eSCy Schubert */
74*e0c4386eSCy Schubert if (EVP_DigestSignUpdate(mctx, test_message, sizeof(test_message)) == 0) {
75*e0c4386eSCy Schubert fprintf(stderr, "Failed to hash message into signing context\n");
76*e0c4386eSCy Schubert goto end;
77*e0c4386eSCy Schubert }
78*e0c4386eSCy Schubert
79*e0c4386eSCy Schubert /* Determine signature length. */
80*e0c4386eSCy Schubert if (EVP_DigestSignFinal(mctx, NULL, sig_len) == 0) {
81*e0c4386eSCy Schubert fprintf(stderr, "Failed to get signature length\n");
82*e0c4386eSCy Schubert goto end;
83*e0c4386eSCy Schubert }
84*e0c4386eSCy Schubert
85*e0c4386eSCy Schubert /* Allocate memory for signature. */
86*e0c4386eSCy Schubert *sig = OPENSSL_malloc(*sig_len);
87*e0c4386eSCy Schubert if (*sig == NULL) {
88*e0c4386eSCy Schubert fprintf(stderr, "Failed to allocate memory for signature\n");
89*e0c4386eSCy Schubert goto end;
90*e0c4386eSCy Schubert }
91*e0c4386eSCy Schubert
92*e0c4386eSCy Schubert /* Generate signature. */
93*e0c4386eSCy Schubert if (EVP_DigestSignFinal(mctx, *sig, sig_len) == 0) {
94*e0c4386eSCy Schubert fprintf(stderr, "Failed to sign\n");
95*e0c4386eSCy Schubert goto end;
96*e0c4386eSCy Schubert }
97*e0c4386eSCy Schubert
98*e0c4386eSCy Schubert rv = 1;
99*e0c4386eSCy Schubert end:
100*e0c4386eSCy Schubert EVP_MD_CTX_free(mctx);
101*e0c4386eSCy Schubert EVP_PKEY_free(pkey);
102*e0c4386eSCy Schubert
103*e0c4386eSCy Schubert if (rv == 0)
104*e0c4386eSCy Schubert OPENSSL_free(*sig);
105*e0c4386eSCy Schubert
106*e0c4386eSCy Schubert return rv;
107*e0c4386eSCy Schubert }
108*e0c4386eSCy Schubert
109*e0c4386eSCy Schubert /*
110*e0c4386eSCy Schubert * This function demonstrates verification of an RSA signature over an
111*e0c4386eSCy Schubert * arbitrary-length message using the PSS signature scheme. Hashing is performed
112*e0c4386eSCy Schubert * automatically.
113*e0c4386eSCy Schubert */
verify(OSSL_LIB_CTX * libctx,const unsigned char * sig,size_t sig_len)114*e0c4386eSCy Schubert static int verify(OSSL_LIB_CTX *libctx, const unsigned char *sig, size_t sig_len)
115*e0c4386eSCy Schubert {
116*e0c4386eSCy Schubert int rv = 0;
117*e0c4386eSCy Schubert EVP_PKEY *pkey = NULL;
118*e0c4386eSCy Schubert EVP_MD_CTX *mctx = NULL;
119*e0c4386eSCy Schubert OSSL_PARAM params[2], *p = params;
120*e0c4386eSCy Schubert const unsigned char *ppub_key = NULL;
121*e0c4386eSCy Schubert
122*e0c4386eSCy Schubert /* Load DER-encoded RSA public key. */
123*e0c4386eSCy Schubert ppub_key = rsa_pub_key;
124*e0c4386eSCy Schubert pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ppub_key, sizeof(rsa_pub_key));
125*e0c4386eSCy Schubert if (pkey == NULL) {
126*e0c4386eSCy Schubert fprintf(stderr, "Failed to load public key\n");
127*e0c4386eSCy Schubert goto end;
128*e0c4386eSCy Schubert }
129*e0c4386eSCy Schubert
130*e0c4386eSCy Schubert /* Create MD context used for verification. */
131*e0c4386eSCy Schubert mctx = EVP_MD_CTX_new();
132*e0c4386eSCy Schubert if (mctx == NULL) {
133*e0c4386eSCy Schubert fprintf(stderr, "Failed to create MD context\n");
134*e0c4386eSCy Schubert goto end;
135*e0c4386eSCy Schubert }
136*e0c4386eSCy Schubert
137*e0c4386eSCy Schubert /* Initialize MD context for verification. */
138*e0c4386eSCy Schubert *p++ = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE,
139*e0c4386eSCy Schubert OSSL_PKEY_RSA_PAD_MODE_PSS, 0);
140*e0c4386eSCy Schubert *p = OSSL_PARAM_construct_end();
141*e0c4386eSCy Schubert
142*e0c4386eSCy Schubert if (EVP_DigestVerifyInit_ex(mctx, NULL, "SHA256", libctx, propq,
143*e0c4386eSCy Schubert pkey, params) == 0) {
144*e0c4386eSCy Schubert fprintf(stderr, "Failed to initialize signing context\n");
145*e0c4386eSCy Schubert goto end;
146*e0c4386eSCy Schubert }
147*e0c4386eSCy Schubert
148*e0c4386eSCy Schubert /*
149*e0c4386eSCy Schubert * Feed data to be signed into the algorithm. This may
150*e0c4386eSCy Schubert * be called multiple times.
151*e0c4386eSCy Schubert */
152*e0c4386eSCy Schubert if (EVP_DigestVerifyUpdate(mctx, test_message, sizeof(test_message)) == 0) {
153*e0c4386eSCy Schubert fprintf(stderr, "Failed to hash message into signing context\n");
154*e0c4386eSCy Schubert goto end;
155*e0c4386eSCy Schubert }
156*e0c4386eSCy Schubert
157*e0c4386eSCy Schubert /* Verify signature. */
158*e0c4386eSCy Schubert if (EVP_DigestVerifyFinal(mctx, sig, sig_len) == 0) {
159*e0c4386eSCy Schubert fprintf(stderr, "Failed to verify signature; "
160*e0c4386eSCy Schubert "signature may be invalid\n");
161*e0c4386eSCy Schubert goto end;
162*e0c4386eSCy Schubert }
163*e0c4386eSCy Schubert
164*e0c4386eSCy Schubert rv = 1;
165*e0c4386eSCy Schubert end:
166*e0c4386eSCy Schubert EVP_MD_CTX_free(mctx);
167*e0c4386eSCy Schubert EVP_PKEY_free(pkey);
168*e0c4386eSCy Schubert return rv;
169*e0c4386eSCy Schubert }
170*e0c4386eSCy Schubert
main(int argc,char ** argv)171*e0c4386eSCy Schubert int main(int argc, char **argv)
172*e0c4386eSCy Schubert {
173*e0c4386eSCy Schubert int rv = 1;
174*e0c4386eSCy Schubert OSSL_LIB_CTX *libctx = NULL;
175*e0c4386eSCy Schubert unsigned char *sig = NULL;
176*e0c4386eSCy Schubert size_t sig_len = 0;
177*e0c4386eSCy Schubert
178*e0c4386eSCy Schubert if (sign(libctx, &sig, &sig_len) == 0)
179*e0c4386eSCy Schubert goto end;
180*e0c4386eSCy Schubert
181*e0c4386eSCy Schubert if (verify(libctx, sig, sig_len) == 0)
182*e0c4386eSCy Schubert goto end;
183*e0c4386eSCy Schubert
184*e0c4386eSCy Schubert rv = 0;
185*e0c4386eSCy Schubert end:
186*e0c4386eSCy Schubert OPENSSL_free(sig);
187*e0c4386eSCy Schubert OSSL_LIB_CTX_free(libctx);
188*e0c4386eSCy Schubert return rv;
189*e0c4386eSCy Schubert }
190