3

Problem: Using the written demo code (given below) I can create and verify without problems. However, using the openssl command line tool, verifying a signature (created by the demo code) always seems to fail.

What I have done: The demo code creates a defined public/private key pair, then signs a defined hash and verifies it.

This is the program output:

Public key: 04DFEC134530603832A31F8885EF01888884483D611F87A698213F168534EC06D85D21F7C85795435BC9A7F78190126CC6E52E050CBDFD43E27175FB1DF3E3DEF6 
Hash: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Verified EC Signature
R: 383EB65E4A284CBCBA41A9777CE7C0816C5C23161EA9BC4EF8B1E668C7641A2A 
S: 608F4BAB9DFE6DC8F976C32D72508CD5BD68F9E325ADED69A9883CE487E6698B

It as well outputs the follwing files:

  • privkey.pem (private key in PEM format)
  • pubkey.pem (public Key in PEM format)
  • data.bin (the hash, nothing fancy)
  • data_sig.der (the DER encoded signature: R & S value)

All files seem to be created correctly.

Next, I try to verify data_sig.der with the openssl command line tool.

$ openssl dgst -verify pubkey.pem -signature data_sig.der data.bin
Verification Failure

Why does this fail?

I can only assume, that one of the 4 files has been written incorrectly, but I double-checked everything and cannot spot my error.

Furthermore, using the PEM files created by the demo program, sign & verify works fine from the command line:

$openssl dgst -sign privkey.pem data.bin > data_sig2.der
$openssl dgst -verify pubkey.pem -signature data_sig2.der data.bin
Verified OK

Here is the demo code (compiles with gcc demo_code.c -lcrypto -lssl -o demo_code):

#include <stdio.h>
#include <stdlib.h>

#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#include <openssl/ecdsa.h>
#include <openssl/pem.h>
#include <openssl/bn.h>

void createSignature()
{
    EC_KEY* eckey = EC_KEY_new();
    EC_GROUP* ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
    EC_KEY_set_group(eckey,ecgroup);
    EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);

    /* the private key value */
    const char *p_str = "7D22AB6A1FD3FC1F5EBEDCA222151375683B733E9DDC9CA5B2485E202C55D25C";
    BIGNUM* prv = BN_new();
    BN_hex2bn(&prv, p_str);
    EC_POINT* pub = EC_POINT_new(ecgroup);

    /* calculate the public key */
    EC_POINT_mul(ecgroup, pub, prv, NULL, NULL, NULL);

    /* add the private & public key to the EC_KEY structure */
    EC_KEY_set_private_key(eckey, prv);
    EC_KEY_set_public_key(eckey, pub);
    /* output public key in hex format */
    char* hexPKey = EC_POINT_point2hex( ecgroup, pub, POINT_CONVERSION_UNCOMPRESSED, NULL );
    printf("Public key: %s \n", hexPKey); 
    /* create hash */
    printf("Hash: ");
    uint8_t hash[32];
    for(int i=0; i < 32; i++) {
        hash[i] = i;
        printf("%02x",hash[i]);
    }
    printf("\n");
    /* create and verify signature */
    ECDSA_SIG* signature = ECDSA_do_sign(hash, 32, eckey);
    //hash[0] = 0xff; // Uncomment to test if verification fails with a wrong hash
    if (1 != ECDSA_do_verify(hash, 32, signature, eckey)) {
        printf("Failed to verify EC Signature\n");
    } else {
        printf("Verified EC Signature\n");
    }
    /*print R & S value in hex format */
    char* hexR = BN_bn2hex(signature->r);
    char* hexS = BN_bn2hex(signature->s);
    printf("R: %s \nS: %s\n", hexR, hexS);
    /* export raw signature to DER-encoded format */
    int sigSize = i2d_ECDSA_SIG(signature, NULL);
    uint8_t* derSig = (uint8_t*)malloc(sigSize);
    uint8_t* p = derSig;    //memset(sig_bytes, 6, sig_size);
    sigSize= i2d_ECDSA_SIG(signature, &p);

    EVP_PKEY* pkey = EVP_PKEY_new();
    EVP_PKEY_set1_EC_KEY(pkey, eckey);

    /* write files */
    FILE* fp = fopen("pubkey.pem", "w");
    PEM_write_PUBKEY(fp, pkey);
    fclose(fp);
    fp = fopen("privkey.pem", "w");
    PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, 0, NULL);
    fclose(fp);
    fp = fopen("data.bin", "w");
    fwrite(hash, 1, sizeof(hash), fp);
    fclose(fp);
    fp = fopen("data_sig.der", "w");
    fwrite(derSig, 1, sigSize, fp);
    fclose(fp);

    /* free runtime allocated res */
    free(derSig);
    OPENSSL_free(hexPKey); OPENSSL_free(hexR); OPENSSL_free(hexS);
    BN_free(prv);
    EC_POINT_free(pub);
    EC_GROUP_free(ecgroup); 
    EC_KEY_free(eckey);
}

int main(int argc, char** argv) {
    createSignature();
    return (EXIT_SUCCESS);
}

1 Answer 1

4

It seems you sign data rather than result of hashing data. But when you run:

$ openssl dgst -verify pubkey.pem -signature data_sig.der data.bin

openssl utility calculate sha256 hash from data.bin and try to verify signature on this hash.

So you need to calc sha256 from 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f and sign result:

void createSignature()
{
    EC_KEY* eckey = EC_KEY_new();
    EC_GROUP* ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
    EC_KEY_set_group(eckey,ecgroup);
    EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);

    /* the private key value */
    const char *p_str = "7D22AB6A1FD3FC1F5EBEDCA222151375683B733E9DDC9CA5B2485E202C55D25C";
    BIGNUM* prv = BN_new();
    BN_hex2bn(&prv, p_str);
    EC_POINT* pub = EC_POINT_new(ecgroup);

    /* calculate the public key */
    EC_POINT_mul(ecgroup, pub, prv, NULL, NULL, NULL);

    /* add the private & public key to the EC_KEY structure */
    EC_KEY_set_private_key(eckey, prv);
    EC_KEY_set_public_key(eckey, pub);
    /* output public key in hex format */
    char* hexPKey = EC_POINT_point2hex( ecgroup, pub, POINT_CONVERSION_UNCOMPRESSED, NULL );
    printf("Public key: %s \n", hexPKey); 
    /* create hash */
    printf("Data: ");
    uint8_t data[32];
    for(int i=0; i < 32; i++) {
        data[i] = i;
        printf("%02x",data[i]);
    }
    printf("\n");

    uint8_t hash[32];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, data, sizeof(data));
    SHA256_Final(hash, &sha256);

    printf("Hash: ");
    for(int i=0; i < 32; i++) {
        data[i] = i;
        printf("%02x",hash[i]);
    }
    printf("\n");

    /* create and verify signature */
    ECDSA_SIG* signature = ECDSA_do_sign(hash, 32, eckey);
    /* hash[0] = 0xff; // Uncomment to test if verification fails with a wrong hash */
    if (1 != ECDSA_do_verify(hash, 32, signature, eckey)) {
        printf("Failed to verify EC Signature\n");
    } else {
        printf("Verified EC Signature\n");
    }
    /*print R & S value in hex format */
    char* hexR = BN_bn2hex(signature->r);
    char* hexS = BN_bn2hex(signature->s);
    printf("R: %s \nS: %s\n", hexR, hexS);
    /* export raw signature to DER-encoded format */
    int sigSize = i2d_ECDSA_SIG(signature, NULL);
    uint8_t* derSig = (uint8_t*)malloc(sigSize);
    uint8_t* p = derSig;    //memset(sig_bytes, 6, sig_size);
    sigSize= i2d_ECDSA_SIG(signature, &p);

    EVP_PKEY* pkey = EVP_PKEY_new();
    EVP_PKEY_set1_EC_KEY(pkey, eckey);

    /* write files */
    FILE* fp = fopen("pubkey.pem", "w");
    PEM_write_PUBKEY(fp, pkey);
    fclose(fp);
    fp = fopen("privkey.pem", "w");
    PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, 0, NULL);
    fclose(fp);
    fp = fopen("data.bin", "w");
    fwrite(data, 1, sizeof(data), fp);
    fclose(fp);
    fp = fopen("data_sig.der", "w");
    fwrite(derSig, 1, sigSize, fp);
    fclose(fp);

    /* free runtime allocated res */
    free(derSig);
    OPENSSL_free(hexPKey);
    OPENSSL_free(hexR); OPENSSL_free(hexS);
    BN_free(prv);
    EC_POINT_free(pub);
    EC_GROUP_free(ecgroup); 
    EC_KEY_free(eckey);
}

Now openssl check works:

$ openssl dgst -verify pubkey.pem -signature data_sig.der data.bin
Verified OK
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.