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