/** * 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); }
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); }