diff options
author | Michele Papalini <micpapal+fdio@cisco.com> | 2017-02-24 08:00:33 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@fd.io> | 2017-02-24 08:00:33 +0000 |
commit | 4df7f4cc98b6288177df256e1db70ddc3f7d00db (patch) | |
tree | 55e71277b419e4830ae641868ab8e751c8b86972 /libparc/parc/security/parc_InMemoryVerifier.c | |
parent | f28308bd99381ef5f1e178e2e1f870f245e35873 (diff) | |
parent | ec688b4723a041044226358bcd4dd6e2da39da49 (diff) |
Merge "Initial commit: cframework. Longbow and Libparc" into cframework/master
Diffstat (limited to 'libparc/parc/security/parc_InMemoryVerifier.c')
-rw-r--r-- | libparc/parc/security/parc_InMemoryVerifier.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/libparc/parc/security/parc_InMemoryVerifier.c b/libparc/parc/security/parc_InMemoryVerifier.c new file mode 100644 index 00000000..e5a9ba06 --- /dev/null +++ b/libparc/parc/security/parc_InMemoryVerifier.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @header parc_InMemoryVerifier.c + * <#Abstract#> + * + * <#Discussion#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +#include <config.h> +#include <stdio.h> + +#include <LongBow/runtime.h> +#include <parc/security/parc_InMemoryVerifier.h> +#include <parc/security/parc_CryptoHasher.h> +#include <parc/security/parc_CryptoCache.h> +#include <parc/algol/parc_Memory.h> + +#include <openssl/x509v3.h> + +struct parc_inmemory_verifier { + PARCCryptoHasher *hasher_sha256; + PARCCryptoHasher *hasher_sha512; + PARCCryptoCache *key_cache; +}; + +static bool +_parcInMemoryVerifier_Destructor(PARCInMemoryVerifier **verifierPtr) +{ + PARCInMemoryVerifier *verifier = *verifierPtr; + + parcCryptoHasher_Release(&(verifier->hasher_sha256)); + parcCryptoHasher_Release(&(verifier->hasher_sha512)); + parcCryptoCache_Destroy(&(verifier->key_cache)); + + return true; +} + +parcObject_ImplementAcquire(parcInMemoryVerifier, PARCInMemoryVerifier); +parcObject_ImplementRelease(parcInMemoryVerifier, PARCInMemoryVerifier); + +parcObject_Override(PARCInMemoryVerifier, PARCObject, + .destructor = (PARCObjectDestructor *) _parcInMemoryVerifier_Destructor); + +PARCInMemoryVerifier * +parcInMemoryVerifier_Create() +{ + PARCInMemoryVerifier *verifier = parcObject_CreateInstance(PARCInMemoryVerifier); + if (verifier != NULL) { + // right now only support sha-256. need to figure out how to make this flexible + verifier->hasher_sha256 = parcCryptoHasher_Create(PARCCryptoHashType_SHA256); + verifier->hasher_sha512 = parcCryptoHasher_Create(PARCCryptoHashType_SHA512); + verifier->key_cache = parcCryptoCache_Create(); + } + + return verifier; +} + + +// ====================================== + +static PARCCryptoHasher * +_parcInMemoryVerifier_GetCryptoHasher(void *interfaceContext, PARCKeyId *keyid, PARCCryptoHashType hashType) +{ + PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext; + + const PARCKey *key = parcCryptoCache_GetKey(verifier->key_cache, keyid); + if (key == NULL) { + return false; + } + + assertFalse(parcKey_GetSigningAlgorithm(key) == PARCSigningAlgorithm_HMAC, "HMAC not supported yet"); + + switch (hashType) { + case PARCCryptoHashType_SHA256: + return verifier->hasher_sha256; + + case PARCCryptoHashType_SHA512: + return verifier->hasher_sha512; + + default: + trapUnexpectedState("unsupported hash type: %d", hashType); + } +} + +static bool +_parcInMemoryVerifier_AllowedCryptoSuite(void *interfaceContext, PARCKeyId *keyid, PARCCryptoSuite suite) +{ + PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext; + + const PARCKey *key = parcCryptoCache_GetKey(verifier->key_cache, keyid); + if (key == NULL) { + return false; + } + + switch (parcKey_GetSigningAlgorithm(key)) { + case PARCSigningAlgorithm_RSA: + switch (suite) { + case PARCCryptoSuite_RSA_SHA256: + return true; + + case PARCCryptoSuite_RSA_SHA512: + return true; + + default: + return false; + } + break; + + case PARCSigningAlgorithm_DSA: + switch (suite) { + default: + return false; + } + break; + + case PARCSigningAlgorithm_HMAC: + switch (suite) { + case PARCCryptoSuite_HMAC_SHA256: + return true; + default: + return false; + } + break; + + default: + trapUnexpectedState("Unknown signing algorithm: %s", + parcSigningAlgorithm_ToString(parcKey_GetSigningAlgorithm(key))); + return false; + } + + return false; +} + +static bool _parcInMemoryVerifier_RSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash, + PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey); + +/** + * The signature verifies if: + * 0) we know the key for keyid + * 1) the signing algorithm of the key corresponding to keyid is same as CCNxSignature + * 2) The hash of the locallyComputedHash is the same type as the content object's ciphersuite + * 3) the signature verifies + * + * Example: + * @code + * <#example#> + * @endcode + */ +static bool +_parcInMemoryVerifier_VerifyDigest(void *interfaceContext, PARCKeyId *keyid, PARCCryptoHash *locallyComputedHash, + PARCCryptoSuite suite, PARCSignature *objectSignature) +{ + PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext; + + const PARCKey *key = parcCryptoCache_GetKey(verifier->key_cache, keyid); + if (key == NULL) { + return false; + } + + assertTrue(_parcInMemoryVerifier_AllowedCryptoSuite(interfaceContext, keyid, suite), "Invalid crypto suite for keyid"); + + if (parcKey_GetSigningAlgorithm(key) != parcSignature_GetSigningAlgorithm(objectSignature)) { + fprintf(stdout, "Signatured failed, signing algorithms do not match: key %s sig %s\n", + parcSigningAlgorithm_ToString(parcKey_GetSigningAlgorithm(key)), + parcSigningAlgorithm_ToString(parcSignature_GetSigningAlgorithm(objectSignature))); + return false; + } + + if (parcCryptoHash_GetDigestType(locallyComputedHash) != parcCryptoSuite_GetCryptoHash(suite)) { + fprintf(stdout, "Signatured failed, digest algorithms do not match: digest %s suite %s\n", + parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(locallyComputedHash)), + parcCryptoHashType_ToString(parcCryptoSuite_GetCryptoHash(suite))); + return false; + } + + switch (parcSignature_GetSigningAlgorithm(objectSignature)) { + case PARCSigningAlgorithm_RSA: + return _parcInMemoryVerifier_RSAKey_Verify(verifier, locallyComputedHash, objectSignature, parcKey_GetKey(key)); + + case PARCSigningAlgorithm_DSA: + trapNotImplemented("DSA not supported"); + break; + + case PARCSigningAlgorithm_HMAC: + trapNotImplemented("HMAC not supported"); + break; + + default: + trapUnexpectedState("Unknown signing algorithm: %d", parcSignature_GetSigningAlgorithm(objectSignature)); + } + + + return false; +} + +static void +_parcInMemoryVerifier_AddKey(void *interfaceContext, PARCKey *key) +{ + assertNotNull(interfaceContext, "interfaceContext must be non-null"); + assertNotNull(key, "key must be non-null"); + + PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext; + bool success = parcCryptoCache_AddKey(verifier->key_cache, key); + assertTrue(success, "could not add key, it must be a duplicate"); +} + +static void +_parcInMemoryVerifier_RemoveKeyId(void *interfaceContext, PARCKeyId *keyid) +{ + assertNotNull(interfaceContext, "interfaceContent must be non-null"); + assertNotNull(keyid, "key must be non-null"); + + PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext; + parcCryptoCache_RemoveKey(verifier->key_cache, keyid); +} + +// ============================================================== +// Openssl specific parts + +#ifdef __APPLE__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + +/** + * 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 PARCCryptoHashType_SHA256: + openssl_digest_type = NID_sha256; + break; + case PARCCryptoHashType_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; +} + +PARCVerifierInterface *PARCInMemoryVerifierAsVerifier = &(PARCVerifierInterface) { + .GetCryptoHasher = _parcInMemoryVerifier_GetCryptoHasher, + .VerifyDigest = _parcInMemoryVerifier_VerifyDigest, + .AddKey = _parcInMemoryVerifier_AddKey, + .RemoveKeyId = _parcInMemoryVerifier_RemoveKeyId, + .AllowedCryptoSuite = _parcInMemoryVerifier_AllowedCryptoSuite, +}; + +#ifdef __APPLE__ +#pragma clang diagnostic pop +#endif |