xref: /freebsd/crypto/openssl/demos/signature/rsa_pss_hash.c (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
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