1 /* 2 * Copyright 2022 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 */ 33 static int sign(OSSL_LIB_CTX *libctx, unsigned char **sig, size_t *sig_len) 34 { 35 int rv = 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 rv = 1; 99 end: 100 EVP_MD_CTX_free(mctx); 101 EVP_PKEY_free(pkey); 102 103 if (rv == 0) 104 OPENSSL_free(*sig); 105 106 return rv; 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 */ 114 static int verify(OSSL_LIB_CTX *libctx, const unsigned char *sig, size_t sig_len) 115 { 116 int rv = 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 rv = 1; 165 end: 166 EVP_MD_CTX_free(mctx); 167 EVP_PKEY_free(pkey); 168 return rv; 169 } 170 171 int main(int argc, char **argv) 172 { 173 int rv = 1; 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 rv = 0; 185 end: 186 OPENSSL_free(sig); 187 OSSL_LIB_CTX_free(libctx); 188 return rv; 189 } 190