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 /* 21 * The digest to be signed. This should be the output of a hash function. 22 * Here we sign an all-zeroes digest for demonstration purposes. 23 */ 24 static const unsigned char test_digest[32] = {0}; 25 26 /* A property query used for selecting algorithm implementations. */ 27 static const char *propq = NULL; 28 29 /* 30 * This function demonstrates RSA signing of a SHA-256 digest using the PSS 31 * padding scheme. You must already have hashed the data you want to sign. 32 * For a higher-level demonstration which does the hashing for you, see 33 * rsa_pss_hash.c. 34 * 35 * For more information, see RFC 8017 section 9.1. The digest passed in 36 * (test_digest above) corresponds to the 'mHash' value. 37 */ 38 static int sign(OSSL_LIB_CTX *libctx, unsigned char **sig, size_t *sig_len) 39 { 40 int rv = 0; 41 EVP_PKEY *pkey = NULL; 42 EVP_PKEY_CTX *ctx = NULL; 43 EVP_MD *md = NULL; 44 const unsigned char *ppriv_key = NULL; 45 46 *sig = NULL; 47 48 /* Load DER-encoded RSA private key. */ 49 ppriv_key = rsa_priv_key; 50 pkey = d2i_PrivateKey_ex(EVP_PKEY_RSA, NULL, &ppriv_key, 51 sizeof(rsa_priv_key), libctx, propq); 52 if (pkey == NULL) { 53 fprintf(stderr, "Failed to load private key\n"); 54 goto end; 55 } 56 57 /* Fetch hash algorithm we want to use. */ 58 md = EVP_MD_fetch(libctx, "SHA256", propq); 59 if (md == NULL) { 60 fprintf(stderr, "Failed to fetch hash algorithm\n"); 61 goto end; 62 } 63 64 /* Create signing context. */ 65 ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); 66 if (ctx == NULL) { 67 fprintf(stderr, "Failed to create signing context\n"); 68 goto end; 69 } 70 71 /* Initialize context for signing and set options. */ 72 if (EVP_PKEY_sign_init(ctx) == 0) { 73 fprintf(stderr, "Failed to initialize signing context\n"); 74 goto end; 75 } 76 77 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) == 0) { 78 fprintf(stderr, "Failed to configure padding\n"); 79 goto end; 80 } 81 82 if (EVP_PKEY_CTX_set_signature_md(ctx, md) == 0) { 83 fprintf(stderr, "Failed to configure digest type\n"); 84 goto end; 85 } 86 87 /* Determine length of signature. */ 88 if (EVP_PKEY_sign(ctx, NULL, sig_len, 89 test_digest, sizeof(test_digest)) == 0) { 90 fprintf(stderr, "Failed to get signature length\n"); 91 goto end; 92 } 93 94 /* Allocate memory for signature. */ 95 *sig = OPENSSL_malloc(*sig_len); 96 if (*sig == NULL) { 97 fprintf(stderr, "Failed to allocate memory for signature\n"); 98 goto end; 99 } 100 101 /* Generate signature. */ 102 if (EVP_PKEY_sign(ctx, *sig, sig_len, 103 test_digest, sizeof(test_digest)) != 1) { 104 fprintf(stderr, "Failed to sign\n"); 105 goto end; 106 } 107 108 rv = 1; 109 end: 110 EVP_PKEY_CTX_free(ctx); 111 EVP_PKEY_free(pkey); 112 EVP_MD_free(md); 113 114 if (rv == 0) 115 OPENSSL_free(*sig); 116 117 return rv; 118 } 119 120 /* 121 * This function demonstrates verification of an RSA signature over a SHA-256 122 * digest using the PSS signature scheme. 123 */ 124 static int verify(OSSL_LIB_CTX *libctx, const unsigned char *sig, size_t sig_len) 125 { 126 int rv = 0; 127 const unsigned char *ppub_key = NULL; 128 EVP_PKEY *pkey = NULL; 129 EVP_PKEY_CTX *ctx = NULL; 130 EVP_MD *md = NULL; 131 132 /* Load DER-encoded RSA public key. */ 133 ppub_key = rsa_pub_key; 134 pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ppub_key, sizeof(rsa_pub_key)); 135 if (pkey == NULL) { 136 fprintf(stderr, "Failed to load public key\n"); 137 goto end; 138 } 139 140 /* Fetch hash algorithm we want to use. */ 141 md = EVP_MD_fetch(libctx, "SHA256", propq); 142 if (md == NULL) { 143 fprintf(stderr, "Failed to fetch hash algorithm\n"); 144 goto end; 145 } 146 147 /* Create verification context. */ 148 ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); 149 if (ctx == NULL) { 150 fprintf(stderr, "Failed to create verification context\n"); 151 goto end; 152 } 153 154 /* Initialize context for verification and set options. */ 155 if (EVP_PKEY_verify_init(ctx) == 0) { 156 fprintf(stderr, "Failed to initialize verification context\n"); 157 goto end; 158 } 159 160 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) == 0) { 161 fprintf(stderr, "Failed to configure padding\n"); 162 goto end; 163 } 164 165 if (EVP_PKEY_CTX_set_signature_md(ctx, md) == 0) { 166 fprintf(stderr, "Failed to configure digest type\n"); 167 goto end; 168 } 169 170 /* Verify signature. */ 171 if (EVP_PKEY_verify(ctx, sig, sig_len, 172 test_digest, sizeof(test_digest)) == 0) { 173 fprintf(stderr, "Failed to verify signature; " 174 "signature may be invalid\n"); 175 goto end; 176 } 177 178 rv = 1; 179 end: 180 EVP_PKEY_CTX_free(ctx); 181 EVP_PKEY_free(pkey); 182 EVP_MD_free(md); 183 return rv; 184 } 185 186 int main(int argc, char **argv) 187 { 188 int rv = 1; 189 OSSL_LIB_CTX *libctx = NULL; 190 unsigned char *sig = NULL; 191 size_t sig_len = 0; 192 193 if (sign(libctx, &sig, &sig_len) == 0) 194 goto end; 195 196 if (verify(libctx, sig, sig_len) == 0) 197 goto end; 198 199 rv = 0; 200 end: 201 OPENSSL_free(sig); 202 OSSL_LIB_CTX_free(libctx); 203 return rv; 204 } 205