0

I have some signed data (separated in signdata and its signature[base64 encoded]) that should be verified by a provided public key for a match. The data is provide by external functions that store the data in a structure like the following.

typedef struct {
    char * signature;
    char * signedData;   // base64 encoded --> decoding required
} data;

I'm in need of converting it to fit into the openssl functions and assume there is a mistake(s) somewhere. It compiles, but crashes (SIGSEGV). It's an Android library and I'm using the NDK. Any ideas/hints? Probably some sort of conversion issue?

// base64 function source: How do I base64 encode (decode) in C?

// check signature based on http://fm4dd.com/openssl/manual-crypto/EVP_PKEY_verify.htm

    size_t sdlen, siglen; 

    char *tmp = malloc(1000);
    char *signature = malloc(1000);
    char *signData = malloc(1000);

    sprintf(tmp, "%s", data.signature);
    signature = base64decode(&tmp, strlen(tmp));
    siglen = strlen(signature);

    sprintf(signData, "%s", data.signedData);
    sdlen = strlen(signData);


    EVP_PKEY_CTX *ctx = malloc(1000);
    unsigned char *md, *sig;

    char publickeybase64[] = "MIIBIjANBgkqhk.....";
    char *publickey = base64decode(&publickeybase64, strlen(publickeybase64));

    EVP_PKEY *verify_key = malloc(1000);
    sprintf((char *) verify_key, "%s", publickey);

    ctx = EVP_PKEY_CTX_new(verify_key, 0);

    if (!ctx) {
        printf("E1\n");
    }
    if (EVP_PKEY_verify_init(ctx) <= 0) {
        printf("E2\n");
    }
    if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) {
        printf("E3\n");
    }
    if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256() <= 0)) {
        printf("E4\n");
    }

    int ret = EVP_PKEY_verify(ctx, signature, siglen, signData, sdlen);

    printf("RESULTVERIFY %d \n", ret);

    /* ret == 1 indicates success, 0 verify failure and < 0 for some
     * other error.
     */
Community
  • 1
  • 1
Nils
  • 1,705
  • 6
  • 23
  • 32
  • You must check the return value from `malloc()`. Also, why are you passint `&publickeybase64`? BTW: `base64` as fairly simple and it should take 20 min to write a function. – Iharob Al Asimi May 19 '16 at 20:48
  • `base64decode(&tmp, strlen(tmp))` is wrong, since tmp is already a `char *`. You want to pass in `tmp` as the first argument rather than `&tmp`. This is the address of your array pointer, so when it's dereferenced within `base64decode` as `data[i++]`, you get a SIGSEGV. – russianfool May 19 '16 at 23:45
  • Furthermore, `strlen` accepts a nil terminated string; since the reference `base64_decode` implementation doesn't nil terminate it, that could/will result in another SIGSEGV. It's also bad form to call `strlen` if you just performed an operation to fill the buffer... you know exactly how much you filled it. Also, why `sprintf` into the `tmp` buffer? `base64decode` can be implemented without modifying the initial buffer. Don't forget to free all those `malloc`ed buffers. – russianfool May 19 '16 at 23:54

1 Answers1

0

I do not know what exactly is encoded in "publickeybase64" but the whole process of creating your public key seems a little strange to me.

Firstly, I would replace

EVP_PKEY *verify_key = malloc(1000);

by something like

EVP_PKEY *verify_key = malloc(sizeof(EVP_PKEY));

or, if you use the latest version of OpenSSL,

EVP_PKEY *verify_key = EVP_PKEY_new();

Then you need to set an RSA key to the verify_key. See https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_set1_RSA.html

Therefore, I think you first need to create the RSA key(https://www.openssl.org/docs/manmaster/crypto/RSA_new.html) and set its modulus and public exponent (see https://www.openssl.org/docs/manmaster/crypto/RSA_set0_key.html).

Marek Klein
  • 1,410
  • 12
  • 20