/*
 * Demonstrates a bug in OpenSSL where an incorrect result will be returned
 * from the HMAC() function if `key` is NULL, even when `key_len` is also 0.
 *
 * Versions tested:
 * OpenSSL 0.9.8y 5 Feb 2013 (OS X)
 * OpenSSL 1.0.1 14 Mar 2012 (Ubuntu)
 *
 * To the extent possible under law, Petroules Corporation has waived all
 * copyright and related or neighboring rights to this example code.
 *
 * Contact: Jake Petroules <jake.petroules@petroules.com>
 */

#include <string.h>
#include <openssl/hmac.h>

#ifdef __APPLE__
#include <CommonCrypto/CommonCrypto.h>
#endif

void printHMACTest(const void *key, int key_len,
        		   const unsigned char *d, size_t n)
{
    int i;
    unsigned char r[EVP_MAX_MD_SIZE];
    unsigned int r_len;
    const unsigned char *ret = HMAC(EVP_sha1(), key, key_len, d, n, 0, &r_len);

#ifdef __APPLE__
    r_len = CC_SHA1_DIGEST_LENGTH;
    CCHmac(kCCHmacAlgSHA1, key, key_len, d, n, r);
#endif

    printf("--- Test ---\n");
    printf("key:\t\t%p\n", key);
    printf("key_len:\t%d\n", key_len);
    printf("d:\t\t%p\n", d);
    printf("n:\t\t%zu\n", n);

    printf("OpenSSL:\t0x");
    for (i = 0; i < r_len; ++i)
        printf("%02x", ret[i]);

    printf("\n");

#ifdef __APPLE__
    printf("CommonCrypto:\t0x");
    for (i = 0; i < r_len; ++i)
        printf("%02x", r[i]);

    printf("\n");
#endif

    printf("\n\n");
}

int main()
{
    // Dummy buffer
    const char nil = '\0';

    // The "null" result for HMAC(SHA-1)
    printf("expected:\t0x%s\n\n", "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d");

    printHMACTest(0, 0, 0, 0);

    printHMACTest(&nil, 0, 0, 0);

    printHMACTest(0, 0, (unsigned char*)&nil, 0);

    printHMACTest(&nil, 0, (unsigned char*)&nil, 0);

    return 0;
}
