/**
 * Return if the signature and key verify with the local hash.
 *
 * PRECONDITION:
 *  - You know the signature and key are RSA.
 *
 * Example:
 * @code
 * <#example#>
 * @endcode
 */
static bool
_parcInMemoryVerifier_RSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash,
                                    PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey)
{
    const uint8_t *der_bytes = parcByteArray_Array(parcBuffer_Array(derEncodedKey));

    long der_length = parcBuffer_Remaining(derEncodedKey);
    EVP_PKEY *unwrapped_key = d2i_PUBKEY(NULL, &der_bytes, der_length);

    if (unwrapped_key != NULL) {
        int success = 0;
        RSA *rsa = EVP_PKEY_get1_RSA(unwrapped_key);

        if (rsa != NULL) {
            int openssl_digest_type;

            switch (parcCryptoHash_GetDigestType(localHash)) {
                case PARC_HASH_SHA256:
                    openssl_digest_type = NID_sha256;
                    break;
                case PARC_HASH_SHA512:
                    openssl_digest_type = NID_sha512;
                    break;
                default:
                    trapUnexpectedState("Unknown digest type: %s",
                                        parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(localHash)));
            }

            PARCBuffer *sigbits = parcSignature_GetSignature(signatureToVerify);
            PARCByteArray *bytearray = parcBuffer_Array(sigbits);
            unsigned signatureLength = (unsigned) parcBuffer_Remaining(sigbits);
            uint8_t *sigbuffer = parcByteArray_Array(bytearray);
            size_t signatureOffset = parcBuffer_ArrayOffset(sigbits);

            success = RSA_verify(openssl_digest_type,
                                 (unsigned char *) parcByteArray_Array(parcBuffer_Array(parcCryptoHash_GetDigest(localHash))),
                                 (unsigned) parcBuffer_Remaining(parcCryptoHash_GetDigest(localHash)),
                                 sigbuffer + signatureOffset,
                                 signatureLength,
                                 rsa);
            RSA_free(rsa);
        }
        EVP_PKEY_free(unwrapped_key);

        if (success) {
            return true;
        }
    }
    return false;
}
/**
 * Gets the DER encoded public key
 */
LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedPublicKey)
{
    PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARC_HASH_SHA256);
    PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
    parcPkcs12KeyStore_Release(&publicKeyStore);

    PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARC_HASH_SHA256);
    parcKeyStore_Release(&keyStore);
    PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
    parcPublicKeySigner_Release(&publicKeySigner);

    assertNotNull(signer, "Got null result from opening openssl pkcs12 file");

    PARCBuffer *pubkey_der = parcKeyStore_GetDEREncodedPublicKey(parcSigner_GetKeyStore(signer));
    assertNotNull(pubkey_der, "got null public key der for external pkcs12");

    // read in the "truth" from the command line utilities

    int fd = open("test_rsa_pub.der", O_RDONLY);
    uint8_t true_der[1024];
    ssize_t read_bytes = read(fd, true_der, 1024);
    close(fd);

    assertTrue(read_bytes == 162, "could not read %d byte digest from test_rsa_pub_sha256.bin", 162);

    const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(pubkey_der));
    size_t bb_length = parcBuffer_Remaining(pubkey_der);
    assertTrue(bb_length == read_bytes, "Incorrect digest length returned from GetCertificateDigest: %zu", bb_length);
    assertTrue(memcmp(bb_buffer, true_der, read_bytes) == 0, "digests did not match");

    parcSigner_Release(&signer);
    parcBuffer_Release(&pubkey_der);
}
Exemple #3
0
PARCBuffer *
parcBuffer_Resize(PARCBuffer *buffer, size_t newCapacity)
{
    parcBuffer_OptionalAssertValid(buffer);

    PARCByteArray *newArray = parcByteArray_Allocate(newCapacity);
    if (newArray == NULL) {
        return NULL;
    }

    size_t numberOfBytesToCopy = parcBuffer_Capacity(buffer);
    if (numberOfBytesToCopy > newCapacity) {
        numberOfBytesToCopy = newCapacity;
    }

    parcByteArray_PutBytes(newArray, 0, numberOfBytesToCopy, &parcByteArray_Array(buffer->array)[buffer->arrayOffset]);

    parcByteArray_Release(&buffer->array);

    buffer->array = newArray;
    buffer->arrayOffset = 0;
    buffer->limit = _computeNewLimit(buffer->capacity, buffer->limit, newCapacity);
    buffer->mark = _computeNewMark(buffer->mark, buffer->limit, newCapacity);
    buffer->capacity = newCapacity;
    buffer->position = (buffer->position < buffer->limit) ? buffer->position : buffer->limit;

    parcBuffer_OptionalAssertValid(buffer);

    return buffer;
}
Exemple #4
0
static PARCSignature *
_SignDigest(PARCPublicKeySigner *signer, const PARCCryptoHash *digestToSign)
{
    parcSecurity_AssertIsInitialized();

    assertNotNull(signer, "Parameter must be non-null CCNxFileKeystore");
    assertNotNull(digestToSign, "Buffer to sign must not be null");

    // TODO: what is the best way to expose this?
    PARCKeyStore *keyStore = signer->keyStore;
    PARCBuffer *privateKeyBuffer = parcKeyStore_GetDEREncodedPrivateKey(keyStore);
    EVP_PKEY *privateKey = NULL;
    size_t keySize = parcBuffer_Remaining(privateKeyBuffer);
    uint8_t *bytes = parcBuffer_Overlay(privateKeyBuffer, keySize);
    privateKey = d2i_PrivateKey(EVP_PKEY_RSA, &privateKey, (const unsigned char **) &bytes, keySize);
    parcBuffer_Release(&privateKeyBuffer);

    RSA *rsa = EVP_PKEY_get1_RSA(privateKey);

    int opensslDigestType;

    switch (parcCryptoHash_GetDigestType(digestToSign)) {
        case PARCCryptoHashType_SHA256:
            opensslDigestType = NID_sha256;
            break;
        case PARCCryptoHashType_SHA512:
            opensslDigestType = NID_sha512;
            break;
        default:
            trapUnexpectedState("Unknown digest type: %s",
                                parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(digestToSign)));
    }

    uint8_t *sig = parcMemory_Allocate(RSA_size(rsa));
    assertNotNull(sig, "parcMemory_Allocate(%u) returned NULL", RSA_size(rsa));

    unsigned sigLength = 0;
    PARCBuffer *bb_digest = parcCryptoHash_GetDigest(digestToSign);
    int result = RSA_sign(opensslDigestType,
                          (unsigned char *) parcByteArray_Array(parcBuffer_Array(bb_digest)),
                          (int) parcBuffer_Remaining(bb_digest),
                          sig,
                          &sigLength,
                          rsa);
    assertTrue(result == 1, "Got error from RSA_sign: %d", result);
    RSA_free(rsa);

    PARCBuffer *bbSign = parcBuffer_Allocate(sigLength);
    parcBuffer_Flip(parcBuffer_PutArray(bbSign, sigLength, sig));
    parcMemory_Deallocate((void **) &sig);

    PARCSignature *signature =
    parcSignature_Create(_GetSigningAlgorithm(signer),
                         parcCryptoHash_GetDigestType(digestToSign),
                         bbSign
                         );
    parcBuffer_Release(&bbSign);
    return signature;
}
LONGBOW_TEST_CASE(Specialization, test_hmac_sha512)
{
    HMAC_CTX ctx;
    char key[] = "apple_pie_is_good";
    int fd;
    uint8_t to_digest_buffer[MAXPATHLEN];
    ssize_t to_digest_length;

    uint8_t true_hmac_buffer[MAXPATHLEN];
    ssize_t true_hmac_length;

LONGBOW_STOP_DEPRECATED_WARNINGS
    HMAC_CTX_init(&ctx);
    HMAC_Init_ex(&ctx, key, sizeof(key), EVP_sha512(), NULL);
LONGBOW_START_DEPRECATED_WARNINGS

    fd = open("test_random_bytes", O_RDONLY);
    assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
    to_digest_length = read(fd, to_digest_buffer, sizeof(to_digest_buffer));
    assertTrue(to_digest_length > 0, "Could not read input file: %s", strerror(errno));
    close(fd);

    fd = open("test_random_bytes.hmac_sha512", O_RDONLY);
    assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
    true_hmac_length = read(fd, true_hmac_buffer, sizeof(true_hmac_buffer));
    assertTrue(true_hmac_length > 0, "Could not read input file: %s", strerror(errno));
    close(fd);

    _hmacInit(&ctx);
    _hmacUpdate(&ctx, to_digest_buffer, to_digest_length);
    PARCBuffer *output = _hmacFinalize(&ctx);

    assertTrue(parcBuffer_Position(output) == true_hmac_length,
               "hmac wrong length, expected %zu got %zu",
               true_hmac_length,
               parcBuffer_Position(output));

    assertTrue(memcmp(parcByteArray_Array(parcBuffer_Array(output)), true_hmac_buffer, true_hmac_length) == 0,
               "hmac values did not match");

LONGBOW_STOP_DEPRECATED_WARNINGS
    HMAC_cleanup(&ctx);
LONGBOW_START_DEPRECATED_WARNINGS

    parcBuffer_Release(&output);
}
static void *
_hmacCreate(void *env)
{
    _PARCAesSignerFileStore *keystore = (_PARCAesSignerFileStore *) env;

    // HMAC_Init_ex seems to overrun the size of HMAC_CTX, so make it bigger

    HMAC_CTX *ctx = parcMemory_Allocate(sizeof(HMAC_CTX) * 2);
    assertNotNull(ctx, "parcMemory_Allocate(%zu) returned NULL for HMAC_CTX", sizeof(HMAC_CTX) * 2);

    HMAC_CTX_init(ctx);

    // Now initialize it with our digest and key, so in hmac_init we can avoid using those
    assertTrue(parcBuffer_Remaining(keystore->secretKey) < INT_MAX, "The keystore secret key cannot be longer than %d", INT_MAX);
    HMAC_Init_ex(ctx, parcByteArray_Array(parcBuffer_Array(keystore->secretKey)), (int) parcBuffer_Remaining(keystore->secretKey), keystore->opensslMd, NULL);

    return ctx;
}
static void *
_hmacCreate(void *env)
{
    PARCSymmetricKeySigner *signer = (PARCSymmetricKeySigner *) env;

    // HMAC_Init_ex seems to overrun the size of HMAC_CTX, so make it bigger

    HMAC_CTX *ctx = parcMemory_Allocate(sizeof(HMAC_CTX) * 2);
    assertNotNull(ctx, "parcMemory_Allocate(%zu) returned NULL for HMAC_CTX", sizeof(HMAC_CTX) * 2);

    HMAC_CTX_init(ctx);

    // Now initialize it with our digest and key, so in hmac_init we can avoid using those
    PARCBuffer *secretKey = parcSymmetricKeyStore_GetKey(signer->keyStore);
    assertTrue(parcBuffer_Remaining(secretKey) < 512, "The keystore secret key cannot be longer than %d", 512);

    HMAC_Init_ex(ctx, parcByteArray_Array(parcBuffer_Array(secretKey)), (int) parcBuffer_Remaining(secretKey), signer->opensslMd, NULL);

    return ctx;
}
/**
 * read in the openssl command-line generated pkcs12 file
 */
LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetPublicKeyDigest)
{
    PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARC_HASH_SHA256);
    PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
    parcPkcs12KeyStore_Release(&publicKeyStore);

    PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARC_HASH_SHA256);
    parcKeyStore_Release(&keyStore);
    PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
    parcPublicKeySigner_Release(&publicKeySigner);

    assertNotNull(signer, "parcPkcs12KeyStore_Open(\"test_rsa.p12\", \"blueberry\", PARC_HASH_SHA256) returned NULL");

    PARCCryptoHash *pkd = parcKeyStore_GetVerifierKeyDigest(parcSigner_GetKeyStore(signer));
    assertNotNull(pkd, "got null public key digest for external pkcs12");

    // read in the "truth" from the command line utilities

    int fd = open("test_rsa_pub_sha256.bin", O_RDONLY);
    uint8_t true_digest[SHA256_DIGEST_LENGTH];
    ssize_t read_bytes = read(fd, true_digest, SHA256_DIGEST_LENGTH);
    close(fd);

    assertTrue(read_bytes == SHA256_DIGEST_LENGTH, "could not read %d byte digest from test_rsa_pub_sha256.bin", SHA256_DIGEST_LENGTH);

    PARCBuffer *digest = parcCryptoHash_GetDigest(pkd);
    const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(digest));
    size_t bb_length = parcBuffer_Remaining(digest);
    assertTrue(bb_length == SHA256_DIGEST_LENGTH,
               "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);

    assertTrue(memcmp(bb_buffer, true_digest, SHA256_DIGEST_LENGTH) == 0, "digests did not match");


    parcSigner_Release(&signer);
    parcCryptoHash_Release(&pkd);
}
/**
 * Read the secret key out of the encrypted file.
 *
 * This function needs its name corrected and rewritten.
 *
 * Example:
 * @code
 * <#example#>
 * @endcode
 */
static PARCBuffer *
_AESKeyStoreInit(const char *filename, const char *password)
{
    PARCBuffer *secret_key = NULL;

    FILE *fp = NULL;
    _PARCSymmeticSignerFileStoreInfo *ki = NULL;
    int version;
    char oidstr[80];

    PARCBuffer *aes_key = NULL;
    PARCBuffer *mac_key = NULL;

    unsigned char check[SHA256_DIGEST_LENGTH];
    unsigned char *keybuf = NULL;
    int check_start;
    EVP_CIPHER_CTX ctx;
    int length = 0;
    int final_length = 0;

    fp = fopen(filename, "rb");
    if (fp == NULL) {
        goto Bail;
    }

    ki = _d2iAESKeystoreFp(fp, NULL);
    fclose(fp);
    if (ki == NULL) {
        goto Bail;
    }

    version = (int) ASN1_INTEGER_get(ki->version);
    if (version != AES_KEYSTORE_VERSION) {
        goto Bail;
    }

    OBJ_obj2txt(oidstr, sizeof(oidstr), ki->algorithm_oid, 0);
    if (strcasecmp(oidstr, AES_DEFAULT_DIGEST_ALGORITHM)) {
        goto Bail;
    }

    if (ki->encrypted_key->length < IV_SIZE + (SHA256_DIGEST_LENGTH * 2) + AES_BLOCK_SIZE) {
        goto Bail;
    }

    aes_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\0", 1);
    mac_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\1", 1);

    check_start = ki->encrypted_key->length - SHA256_DIGEST_LENGTH;
    HMAC(EVP_sha256(),
         parcByteArray_Array(parcBuffer_Array(mac_key)),
         SHA256_DIGEST_LENGTH,
         ki->encrypted_key->data,
         check_start,
         check,
         NULL);

    if (memcmp(&ki->encrypted_key->data[check_start], check, SHA256_DIGEST_LENGTH)) {
        goto Bail;
    }
    keybuf = malloc(SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE);
    EVP_CIPHER_CTX_init(&ctx);
    if (!EVP_DecryptInit(&ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), ki->encrypted_key->data)) {
        goto Bail;
    }
    if (!EVP_DecryptUpdate(&ctx, keybuf, &length, &ki->encrypted_key->data[IV_SIZE],
                           ki->encrypted_key->length - IV_SIZE - SHA256_DIGEST_LENGTH)) {
        goto Bail;
    }

    if (!EVP_DecryptFinal(&ctx, keybuf + length, &final_length)) {
        goto Bail;
    }

    secret_key = parcBuffer_CreateFromArray(keybuf, length);
    parcBuffer_Flip(secret_key);

    goto out;

 Bail:
    free(keybuf);

 out:
    if (aes_key) {
        parcBuffer_Release(&aes_key);
    }

    if (mac_key) {
        parcBuffer_Release(&mac_key);
    }

    return secret_key;
}
/**
 * returns 0 success, -1 error
 *
 * Example:
 * @code
 * <#example#>
 * @endcode
 */
static int
_createAESKeyStore(const char *filename, const char *password, PARCBuffer *key)
{
    FILE *fp = NULL;
    int fd = -1;
    int ans = -1;
    int nid;

    _PARCSymmeticSignerFileStoreInfo *keystore = NULL;

    EVP_CIPHER_CTX ctx;
    unsigned char *encrypted_key = NULL;

    int ekl = IV_SIZE + (int) parcBuffer_Remaining(key) + SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE;
    int encrypt_length;

    fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);

    if (fd == -1) {
        goto Bail;
    }
    fp = fdopen(fd, "wb");
    if (fp == NULL) {
        goto Bail;
    }

    PARCBuffer *aes_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\0", 1);
    PARCBuffer *mac_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\1", 1);

    encrypted_key = malloc(ekl);
    if (!encrypted_key) {
        goto Bail;
    }
    RAND_bytes(encrypted_key, IV_SIZE);
    EVP_CIPHER_CTX_init(&ctx);
    if (!EVP_EncryptInit(&ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), encrypted_key)) {
        goto Bail;
    }

    unsigned char *p;
    p = encrypted_key + IV_SIZE;
    if (!EVP_EncryptUpdate(&ctx, p, &encrypt_length, parcByteArray_Array(parcBuffer_Array(key)), (int) parcBuffer_Remaining(key))) {
        goto Bail;
    }
    p += encrypt_length;
    if (!EVP_EncryptFinal(&ctx, p, &encrypt_length)) {
        goto Bail;
    }
    p += encrypt_length;
    HMAC(EVP_sha256(), parcByteArray_Array(parcBuffer_Array(mac_key)), SHA256_DIGEST_LENGTH, encrypted_key, p - encrypted_key, p, NULL);

    if (!(keystore = _PARCSymmeticSignerFileStoreInfo_new())) {
        goto Bail;
    }
    if (!(keystore->version = ASN1_INTEGER_new())) {
        goto Bail;
    }
    if (!ASN1_INTEGER_set(keystore->version, AES_KEYSTORE_VERSION)) {
        goto Bail;
    }

    keystore->algorithm_oid = OBJ_txt2obj(AES_DEFAULT_DIGEST_ALGORITHM, 0);
    nid = OBJ_obj2nid(keystore->algorithm_oid);
    if (nid == NID_undef) {
        goto Bail;  // Shouldn't happen now but could later if we support more algorithms
    }
    if (!ASN1_OCTET_STRING_set(keystore->encrypted_key, encrypted_key, ekl)) {
        goto Bail;
    }
    _i2d_AESKeystore_fp(fp, keystore);
    ans = 0;
    goto cleanup;

 Bail:
    ans = -1;
 cleanup:

    parcBuffer_Release(&aes_key);
    parcBuffer_Release(&mac_key);

    if (fp != NULL) {
        fclose(fp);
    }
    if (encrypted_key) {
        free(encrypted_key);
    }
    if (keystore) {
        _PARCSymmeticSignerFileStoreInfo_free(keystore);
    }
    if (fd != -1) {
        close(fd);
    }
    return (ans);
}