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