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