Once upon a time Dr. Stephen Henson wrote:
>
> A PKCS#1 signature doesn't just consist of the padded raw digest value it is
> contained in a DigestInfo structure which is then padded.
>
> You can create a DigestInfo structure using the ASN1 code and X509_SIG or just
> prepend static data to the result: this is what the FIPS code does to avoid
> the need to include a full ASN1 encoder in the module.
>
> See the code in fips/rsa/fips_rsa_sign.c in any FIPS version of the master
> branch of OpenSSL for details.
Thanks!
Adding the static bytes for the DigestInfo structure (for SHA256 in my
case) was the missing piece. For future reference, in case anyone
else runs into this question, I've attached a modified version of the
test code which now works correctly.
--
Jyri J. Virkki - Santa Cruz, CA
--
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#define DATALEN 512
// Predetermined ASN.1 encoding for DigestInfo w/SHA256
// See fips/rsa/fips_rsa_sign.c for others.
static const unsigned char sha256_bin[] = {
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
};
void main()
{
EVP_PKEY_CTX * ctx = NULL;
EVP_PKEY * key = NULL;
int i;
// Some data to sign
unsigned char data[DATALEN];
for (i = 0; i < DATALEN; i++) { data[i]=i; }
printf("Generating a key...\n");
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
EVP_PKEY_keygen_init(ctx);
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048);
EVP_PKEY_keygen(ctx, &key);
EVP_PKEY_CTX_free(ctx);
printf("Hashing data...\n");
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data, DATALEN);
SHA256_Final(hash, &sha256);
printf("Building DigestInfo structure...\n");
size_t dilen = sizeof(sha256_bin) + SHA256_DIGEST_LENGTH;
unsigned char di[dilen];
memcpy(di, sha256_bin, sizeof(sha256_bin));
memcpy(di + sizeof(sha256_bin), hash, SHA256_DIGEST_LENGTH);
printf("Adding padding around it...\n");
size_t buflen = 2048/8;
unsigned char buffer[buflen];
RSA_padding_add_PKCS1_type_1(buffer, buflen, di, dilen);
printf("Signing pre-padded buffer...\n");
ctx = EVP_PKEY_CTX_new(key, NULL);
EVP_PKEY_sign_init(ctx);
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING);
size_t siglen;
EVP_PKEY_sign(ctx, NULL, &siglen, buffer, buflen);
printf("siglen = %zu\n", siglen);
unsigned char signature[siglen];
EVP_PKEY_sign(ctx, signature, &siglen, buffer, buflen);
EVP_PKEY_CTX_free(ctx);
printf("Now trying to verify signature directly...\n");
ctx = EVP_PKEY_CTX_new(key, NULL);
EVP_PKEY_verify_init(ctx);
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256());
if (EVP_PKEY_verify(ctx, signature, siglen, hash, SHA256_DIGEST_LENGTH) <= 0) {
printf("Signature did not verify\n");
} else {
printf("Signature OK!\n");
}
EVP_PKEY_CTX_free(ctx);
exit(0);
}