From 75a923f0ee362a039b51a141a719ce50597ca233 Mon Sep 17 00:00:00 2001 From: Devel Date: Thu, 12 Apr 2018 18:07:08 +0200 Subject: Added signature calculation and verification for ECDSA Change-Id: I946e146b9a6ae33ee294a09417e8366853faa502 Signed-off-by: Devel --- .../parc/security/command-line/parc-publickey.c | 11 +- libparc/parc/security/parc_CertificateFactory.c | 14 +- libparc/parc/security/parc_CertificateFactory.h | 2 +- libparc/parc/security/parc_CryptoSuite.c | 51 ++- libparc/parc/security/parc_CryptoSuite.h | 37 +- libparc/parc/security/parc_Identity.c | 4 +- libparc/parc/security/parc_Identity.h | 5 +- libparc/parc/security/parc_IdentityFile.c | 11 +- libparc/parc/security/parc_IdentityFile.h | 2 +- libparc/parc/security/parc_InMemoryVerifier.c | 82 +++- libparc/parc/security/parc_InMemoryVerifier.h | 1 + libparc/parc/security/parc_Key.c | 1 + libparc/parc/security/parc_KeyStore.c | 9 + libparc/parc/security/parc_KeyStore.h | 30 ++ libparc/parc/security/parc_KeyType.c | 56 +++ libparc/parc/security/parc_KeyType.h | 66 +++ libparc/parc/security/parc_Pkcs12KeyStore.c | 136 ++++-- libparc/parc/security/parc_Pkcs12KeyStore.h | 20 +- libparc/parc/security/parc_PublicKeySigner.c | 96 +++- libparc/parc/security/parc_PublicKeySigner.h | 2 +- libparc/parc/security/parc_Signer.h | 24 +- libparc/parc/security/parc_SigningAlgorithm.c | 3 + libparc/parc/security/parc_SigningAlgorithm.h | 3 +- libparc/parc/security/parc_X509Certificate.c | 253 ++++++++--- libparc/parc/security/parc_X509Certificate.h | 5 +- libparc/parc/security/test/CMakeLists.txt | 13 + libparc/parc/security/test/README.keystore | 28 ++ libparc/parc/security/test/test_ec.crt | 12 + libparc/parc/security/test/test_ec.csr | 8 + libparc/parc/security/test/test_ec.p12 | Bin 0 -> 1011 bytes libparc/parc/security/test/test_ec_crt.der | Bin 0 -> 438 bytes libparc/parc/security/test/test_ec_crt_sha256.bin | 1 + libparc/parc/security/test/test_ec_key.der | Bin 0 -> 118 bytes libparc/parc/security/test/test_ec_key.pem | 5 + libparc/parc/security/test/test_ec_pub.der | Bin 0 -> 88 bytes libparc/parc/security/test/test_ec_pub.pem | 4 + libparc/parc/security/test/test_ec_pub_sha256.bin | 1 + .../parc/security/test/test_ec_pub_sha256.bin.sig | Bin 0 -> 70 bytes libparc/parc/security/test/test_parc_CryptoSuite.c | 2 +- libparc/parc/security/test/test_parc_Identity.c | 2 +- .../parc/security/test/test_parc_IdentityFile.c | 2 +- .../security/test/test_parc_InMemoryVerifier.c | 6 +- .../test/test_parc_InMemoryVerifierECDSA.c | 417 +++++++++++++++++ .../parc/security/test/test_parc_Pkcs12KeyStore.c | 36 +- .../security/test/test_parc_Pkcs12KeyStoreECDSA.c | 470 +++++++++++++++++++ .../security/test/test_parc_PublicKeyECSigner.c | 495 +++++++++++++++++++++ .../parc/security/test/test_parc_PublicKeySigner.c | 24 +- libparc/parc/security/test/test_parc_Signature.c | 24 +- libparc/parc/security/test/test_parc_SignerEC.c | 312 +++++++++++++ .../parc/security/test/test_parc_X509Certificate.c | 20 + .../parc/security/test/test_random_bytes.sig_ec | Bin 0 -> 71 bytes 51 files changed, 2597 insertions(+), 209 deletions(-) create mode 100644 libparc/parc/security/parc_KeyType.c create mode 100644 libparc/parc/security/parc_KeyType.h create mode 100644 libparc/parc/security/test/test_ec.crt create mode 100644 libparc/parc/security/test/test_ec.csr create mode 100644 libparc/parc/security/test/test_ec.p12 create mode 100644 libparc/parc/security/test/test_ec_crt.der create mode 100644 libparc/parc/security/test/test_ec_crt_sha256.bin create mode 100644 libparc/parc/security/test/test_ec_key.der create mode 100644 libparc/parc/security/test/test_ec_key.pem create mode 100644 libparc/parc/security/test/test_ec_pub.der create mode 100644 libparc/parc/security/test/test_ec_pub.pem create mode 100644 libparc/parc/security/test/test_ec_pub_sha256.bin create mode 100644 libparc/parc/security/test/test_ec_pub_sha256.bin.sig create mode 100644 libparc/parc/security/test/test_parc_InMemoryVerifierECDSA.c create mode 100644 libparc/parc/security/test/test_parc_Pkcs12KeyStoreECDSA.c create mode 100644 libparc/parc/security/test/test_parc_PublicKeyECSigner.c create mode 100644 libparc/parc/security/test/test_parc_SignerEC.c create mode 100644 libparc/parc/security/test/test_random_bytes.sig_ec diff --git a/libparc/parc/security/command-line/parc-publickey.c b/libparc/parc/security/command-line/parc-publickey.c index 30733113..e88e94b6 100644 --- a/libparc/parc/security/command-line/parc-publickey.c +++ b/libparc/parc/security/command-line/parc-publickey.c @@ -36,16 +36,17 @@ parcPublicKey_Create(PARCArrayList *args) char *fileName = parcArrayList_Get(args, 2); char *password = parcArrayList_Get(args, 3); char *subjectName = parcArrayList_Get(args, 4); - + PARCSigningAlgorithm signAlgo = *(int *)parcArrayList_Get(args, 5); + if (parcArrayList_Size(args) > 5) { - keyLength = (unsigned int) strtoul(parcArrayList_Get(args, 5), NULL, 10); + keyLength = (unsigned int) strtoul(parcArrayList_Get(args, 6), NULL, 10); } if (parcArrayList_Size(args) > 6) { - validityDays = (unsigned int) strtoul(parcArrayList_Get(args, 6), NULL, 10); + validityDays = (unsigned int) strtoul(parcArrayList_Get(args, 7), NULL, 10); } - bool result = parcPkcs12KeyStore_CreateFile(fileName, password, subjectName, keyLength, validityDays); + bool result = parcPkcs12KeyStore_CreateFile(fileName, password, subjectName, keyLength, validityDays, signAlgo); if (!result) { printf("Error: %s %s", fileName, strerror(errno)); return; @@ -62,7 +63,7 @@ parcPublicKey_Validate(PARCArrayList *args) PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(fileName, password, PARCCryptoHashType_SHA256); PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore); - PARCPublicKeySigner *signer = parcPublicKeySigner_Create(publicKeyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *signer = parcPublicKeySigner_Create(publicKeyStore, PARCCryptoSuite_RSA_SHA256); PARCSigner *pkSigner = parcSigner_Create(signer, PARCPublicKeySignerAsSigner); parcKeyStore_Release(&publicKeyStore); diff --git a/libparc/parc/security/parc_CertificateFactory.c b/libparc/parc/security/parc_CertificateFactory.c index 3825ae04..3a758c53 100644 --- a/libparc/parc/security/parc_CertificateFactory.c +++ b/libparc/parc/security/parc_CertificateFactory.c @@ -78,10 +78,20 @@ parcCertificateFactory_CreateCertificateFromBuffer(PARCCertificateFactory *facto PARCCertificate * parcCertificateFactory_CreateSelfSignedCertificate(PARCCertificateFactory *factory, PARCBuffer **privateKey, - char *subjectName, size_t keyLength, size_t valdityDays) + char *subjectName, PARCSigningAlgorithm signAlgo, + size_t keyLength, size_t valdityDays) { if (factory->type == PARCCertificateType_X509 && factory->encoding == PARCContainerEncoding_DER) { - PARCX509Certificate *certificate = parcX509Certificate_CreateSelfSignedCertificate(privateKey, subjectName, (int) keyLength, valdityDays); + PARCX509Certificate *certificate = NULL; + switch (signAlgo) + { + case PARCSigningAlgorithm_RSA: + certificate = parcX509Certificate_CreateSelfSignedCertificate(privateKey, subjectName, (int) keyLength, valdityDays, PARCKeyType_RSA); + break; + case PARCSigningAlgorithm_ECDSA: + certificate = parcX509Certificate_CreateSelfSignedCertificate(privateKey, subjectName, (int) keyLength, valdityDays, PARCKeyType_EC); + break; + } // This may fail. if (certificate == NULL) { diff --git a/libparc/parc/security/parc_CertificateFactory.h b/libparc/parc/security/parc_CertificateFactory.h index 5f49ac23..de034d1b 100755 --- a/libparc/parc/security/parc_CertificateFactory.h +++ b/libparc/parc/security/parc_CertificateFactory.h @@ -114,7 +114,7 @@ PARCCertificate *parcCertificateFactory_CreateCertificateFromBuffer(PARCCertific * } * @endcode */ -PARCCertificate *parcCertificateFactory_CreateSelfSignedCertificate(PARCCertificateFactory *factort, PARCBuffer **privateKey, char *subjectName, size_t keyLength, size_t valdityDays); +PARCCertificate *parcCertificateFactory_CreateSelfSignedCertificate(PARCCertificateFactory *factort, PARCBuffer **privateKey, char *subjectName, PARCSigningAlgorithm signAlgo, size_t keyLength, size_t valdityDays); /** * Increase the number of references to a `PARCCertificateFactory` instance. diff --git a/libparc/parc/security/parc_CryptoSuite.c b/libparc/parc/security/parc_CryptoSuite.c index 9f4506e7..c807f9aa 100755 --- a/libparc/parc/security/parc_CryptoSuite.c +++ b/libparc/parc/security/parc_CryptoSuite.c @@ -28,7 +28,7 @@ parcCryptoSuite_GetCryptoHash(PARCCryptoSuite suite) case PARCCryptoSuite_DSA_SHA256: // fallthrough case PARCCryptoSuite_HMAC_SHA256: // fallthrough case PARCCryptoSuite_RSA_SHA256: // fallthrough - case PARCCryptoSuite_EC_SECP_256K1: + case PARCCryptoSuite_ECDSA_SHA256: return PARCCryptoHashType_SHA256; case PARCCryptoSuite_HMAC_SHA512: // fallthrough @@ -42,3 +42,52 @@ parcCryptoSuite_GetCryptoHash(PARCCryptoSuite suite) trapIllegalValue(suite, "Unknown crypto suite: %d", suite); } } + +int +parcCryptoSuite_GetSignatureSizeBits(PARCCryptoSuite suite, int keyLengthBits) +{ + switch (suite) { + case PARCCryptoSuite_DSA_SHA256: // fallthrough + case PARCCryptoSuite_RSA_SHA256: // fallthrough + case PARCCryptoSuite_RSA_SHA512: + return keyLengthBits; + + case PARCCryptoSuite_ECDSA_SHA256: + return keyLengthBits*2 + 64; //Overhead added by ECDSA + + case PARCCryptoSuite_HMAC_SHA256: // fallthrough + case PARCCryptoSuite_HMAC_SHA512: // fallthrough + return 512; + + case PARCCryptoSuite_NULL_CRC32C: + return 32; + + default: + trapIllegalValue(suite, "Unknown crypto suite: %d", suite); + } +} + +int +parcCryptoSuite_GetSignatureSizeBytes(PARCCryptoSuite suite, int keyLengthBits) +{ + int keyLengthBytes = keyLengthBits >> 3; + switch (suite) { + case PARCCryptoSuite_DSA_SHA256: // fallthrough + case PARCCryptoSuite_RSA_SHA256: // fallthrough + case PARCCryptoSuite_RSA_SHA512: + return keyLengthBytes; + + case PARCCryptoSuite_ECDSA_SHA256: + return keyLengthBytes*2 + 8; //Overhead added by ECDSA + + case PARCCryptoSuite_HMAC_SHA256: // fallthrough + case PARCCryptoSuite_HMAC_SHA512: // fallthrough + return 64; + + case PARCCryptoSuite_NULL_CRC32C: + return 4; + + default: + trapIllegalValue(suite, "Unknown crypto suite: %d", suite); + } +} diff --git a/libparc/parc/security/parc_CryptoSuite.h b/libparc/parc/security/parc_CryptoSuite.h index b9c138e2..a8e07f02 100755 --- a/libparc/parc/security/parc_CryptoSuite.h +++ b/libparc/parc/security/parc_CryptoSuite.h @@ -36,7 +36,7 @@ typedef enum { PARCCryptoSuite_HMAC_SHA256, PARCCryptoSuite_HMAC_SHA512, PARCCryptoSuite_NULL_CRC32C, - PARCCryptoSuite_EC_SECP_256K1, + PARCCryptoSuite_ECDSA_SHA256, PARCCryptoSuite_UNKNOWN } PARCCryptoSuite; @@ -55,4 +55,39 @@ typedef enum { * @endcode */ PARCCryptoHashType parcCryptoSuite_GetCryptoHash(PARCCryptoSuite suite); + +/** + * Given a PARCCryptoSuite value and the key length, return the expected length in bits of the signature. + * For ECDSA the result is the maximum length + * + * @param [in] suite A PARCCryptoSuite value. + * + * @return A PARCCryptoHashType value + * + * Example: + * @code + * { + * int bits = parcCryptoSuite_GetSignatureSizeBits(PARCCryptoSuite_RSA_SHA256, 1024); + * } + * @endcode + */ +int parcCryptoSuite_GetSignatureSizeBits(PARCCryptoSuite suite, int keyLengthBits); + +/** + * Given a PARCCryptoSuite value and the key length, return the expected length in bytes of the signature. + * For ECDSA the result is the maximum length + * + * @param [in] suite A PARCCryptoSuite value. + * + * @return A PARCCryptoHashType value + * + * Example: + * @code + * { + * int bytes = parcCryptoSuite_GetSignatureSizeBits(PARCCryptoSuite_RSA_SHA256, 1024); + * } + * @endcode + */ +int parcCryptoSuite_GetSignatureSizeBytes(PARCCryptoSuite suite, int keyLengthBits); + #endif // libparc_parc_CryptoSuite_h diff --git a/libparc/parc/security/parc_Identity.c b/libparc/parc/security/parc_Identity.c index 0afef9f7..a132964a 100755 --- a/libparc/parc/security/parc_Identity.c +++ b/libparc/parc/security/parc_Identity.c @@ -99,9 +99,9 @@ parcIdentity_GetPassWord(const PARCIdentity *identity) } PARCSigner * -parcIdentity_CreateSigner(const PARCIdentity *identity) +parcIdentity_CreateSigner(const PARCIdentity *identity, PARCCryptoSuite suite) { - return identity->interface->GetSigner(identity->instance); + return identity->interface->GetSigner(identity->instance, suite); } void diff --git a/libparc/parc/security/parc_Identity.h b/libparc/parc/security/parc_Identity.h index d581b97d..32b9b179 100755 --- a/libparc/parc/security/parc_Identity.h +++ b/libparc/parc/security/parc_Identity.h @@ -45,6 +45,7 @@ #include #include +#include struct parc_identity; typedef struct parc_identity PARCIdentity; @@ -73,7 +74,7 @@ typedef struct parc_identity_interface { /** * @see parcIdentity_CreateSigner */ - PARCSigner *(*GetSigner)(const void *identity); + PARCSigner *(*GetSigner)(const void *identity, PARCCryptoSuite suite); /** * @see parcIdentity_Equals @@ -278,7 +279,7 @@ const char *parcIdentity_GetPassWord(const PARCIdentity *identity); * } * @endcode */ -PARCSigner *parcIdentity_CreateSigner(const PARCIdentity *identity); +PARCSigner *parcIdentity_CreateSigner(const PARCIdentity *identity, PARCCryptoSuite suite); /** * Determine if two PARCIdentity are equal. diff --git a/libparc/parc/security/parc_IdentityFile.c b/libparc/parc/security/parc_IdentityFile.c index f5f6d067..972c8d05 100644 --- a/libparc/parc/security/parc_IdentityFile.c +++ b/libparc/parc/security/parc_IdentityFile.c @@ -42,7 +42,7 @@ PARCIdentityInterface *PARCIdentityFileAsPARCIdentity = &(PARCIdentityInterface) .Release = (void (*)(void **))parcIdentityFile_Release, .GetPassWord = (void *(*)(const void *))parcIdentityFile_GetPassWord, .GetFileName = (void *(*)(const void *))parcIdentityFile_GetFileName, - .GetSigner = (PARCSigner * (*)(const void *))parcIdentityFile_CreateSigner, + .GetSigner = (PARCSigner * (*)(const void *, PARCCryptoSuite))parcIdentityFile_CreateSigner, .Equals = (bool (*)(const void *, const void *))parcIdentityFile_Equals, .Display = (void (*)(const void *, size_t))parcIdentityFile_Display }; @@ -104,13 +104,18 @@ parcIdentityFile_GetPassWord(const PARCIdentityFile *identity) } PARCSigner * -parcIdentityFile_CreateSigner(const PARCIdentityFile *identity) +parcIdentityFile_CreateSigner(const PARCIdentityFile *identity, PARCCryptoSuite suite) { PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(identity->fileName, identity->passWord, PARCCryptoHashType_SHA256); PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&keyStore); - PARCPublicKeySigner *signer = parcPublicKeySigner_Create(publicKeyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCSigningAlgorithm signAlgo = parcKeyStore_getSigningAlgorithm(publicKeyStore); + + if (signAlgo != parcSigningAlgorithm_GetSigningAlgorithm(suite)) + return NULL; + + PARCPublicKeySigner *signer = parcPublicKeySigner_Create(publicKeyStore, suite); PARCSigner *pkSigner = parcSigner_Create(signer, PARCPublicKeySignerAsSigner); parcPublicKeySigner_Release(&signer); parcKeyStore_Release(&publicKeyStore); diff --git a/libparc/parc/security/parc_IdentityFile.h b/libparc/parc/security/parc_IdentityFile.h index c5ee4ac5..c125ffb2 100644 --- a/libparc/parc/security/parc_IdentityFile.h +++ b/libparc/parc/security/parc_IdentityFile.h @@ -205,7 +205,7 @@ const char *parcIdentityFile_GetPassWord(const PARCIdentityFile *identity); * } * @endcode */ -PARCSigner *parcIdentityFile_CreateSigner(const PARCIdentityFile *identity); +PARCSigner *parcIdentityFile_CreateSigner(const PARCIdentityFile *identity, PARCCryptoSuite suite); /** * Determine if two PARCIdentityFiles are equal. diff --git a/libparc/parc/security/parc_InMemoryVerifier.c b/libparc/parc/security/parc_InMemoryVerifier.c index e5a9ba06..e5946d33 100644 --- a/libparc/parc/security/parc_InMemoryVerifier.c +++ b/libparc/parc/security/parc_InMemoryVerifier.c @@ -34,6 +34,8 @@ #include #include +#include + struct parc_inmemory_verifier { PARCCryptoHasher *hasher_sha256; @@ -124,6 +126,17 @@ _parcInMemoryVerifier_AllowedCryptoSuite(void *interfaceContext, PARCKeyId *keyi } break; + case PARCSigningAlgorithm_ECDSA: + switch (suite) { + case PARCCryptoSuite_ECDSA_SHA256: + return true; + + default: + return false; + } + break; + + case PARCSigningAlgorithm_DSA: switch (suite) { default: @@ -152,6 +165,8 @@ _parcInMemoryVerifier_AllowedCryptoSuite(void *interfaceContext, PARCKeyId *keyi static bool _parcInMemoryVerifier_RSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash, PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey); +static bool _parcInMemoryVerifier_ECDSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash, + PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey); /** * The signature verifies if: * 0) we know the key for keyid @@ -195,6 +210,9 @@ _parcInMemoryVerifier_VerifyDigest(void *interfaceContext, PARCKeyId *keyid, PAR case PARCSigningAlgorithm_RSA: return _parcInMemoryVerifier_RSAKey_Verify(verifier, locallyComputedHash, objectSignature, parcKey_GetKey(key)); + case PARCSigningAlgorithm_ECDSA: + return _parcInMemoryVerifier_ECDSAKey_Verify(verifier, locallyComputedHash, objectSignature, parcKey_GetKey(key)); + case PARCSigningAlgorithm_DSA: trapNotImplemented("DSA not supported"); break; @@ -295,7 +313,69 @@ _parcInMemoryVerifier_RSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHa } EVP_PKEY_free(unwrapped_key); - if (success) { + if (success == 1) { + return true; + } + } + return false; +} + +/** + * Return if the signature and key verify with the local hash. + * + * PRECONDITION: + * - You know the signature and key are ECDSA. + * + * Example: + * @code + * <#example#> + * @endcode + */ +static bool +_parcInMemoryVerifier_ECDSAKey_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; + EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(unwrapped_key); + + if (ec_key != 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 = ECDSA_verify(openssl_digest_type, + (unsigned char *) parcByteArray_Array(parcBuffer_Array(parcCryptoHash_GetDigest(localHash))), + (unsigned) parcBuffer_Remaining(parcCryptoHash_GetDigest(localHash)), + sigbuffer + signatureOffset, + signatureLength, + ec_key); + EC_KEY_free(ec_key); + } + EVP_PKEY_free(unwrapped_key); + + if (success == 1) { return true; } } diff --git a/libparc/parc/security/parc_InMemoryVerifier.h b/libparc/parc/security/parc_InMemoryVerifier.h index d9f1cf98..bbec8130 100755 --- a/libparc/parc/security/parc_InMemoryVerifier.h +++ b/libparc/parc/security/parc_InMemoryVerifier.h @@ -27,6 +27,7 @@ struct parc_inmemory_verifier; typedef struct parc_inmemory_verifier PARCInMemoryVerifier; + extern PARCVerifierInterface *PARCInMemoryVerifierAsVerifier; /** * Create an empty verifier. It's destroyed via the PARCVerifierInterface->Destroy call. diff --git a/libparc/parc/security/parc_Key.c b/libparc/parc/security/parc_Key.c index 06b85420..3802549e 100755 --- a/libparc/parc/security/parc_Key.c +++ b/libparc/parc/security/parc_Key.c @@ -69,6 +69,7 @@ parcKey_CreateFromDerEncodedPublicKey(PARCKeyId *keyid, PARCSigningAlgorithm sig switch (signingAlg) { case PARCSigningAlgorithm_RSA: // fallthrough case PARCSigningAlgorithm_DSA: + case PARCSigningAlgorithm_ECDSA: break; default: diff --git a/libparc/parc/security/parc_KeyStore.c b/libparc/parc/security/parc_KeyStore.c index 912861d1..00fac015 100755 --- a/libparc/parc/security/parc_KeyStore.c +++ b/libparc/parc/security/parc_KeyStore.c @@ -102,3 +102,12 @@ parcKeyStore_GetDEREncodedPrivateKey(const PARCKeyStore *interfaceContext) } return NULL; } + +PARCSigningAlgorithm +parcKeyStore_getSigningAlgorithm(const PARCKeyStore *interfaceContext) +{ + if (interfaceContext->interface != NULL) { + return interfaceContext->interface->getSigningAlgorithm(interfaceContext->instance); + } + return PARCSigningAlgortihm_NULL; +} diff --git a/libparc/parc/security/parc_KeyStore.h b/libparc/parc/security/parc_KeyStore.h index 03be78af..253505d5 100755 --- a/libparc/parc/security/parc_KeyStore.h +++ b/libparc/parc/security/parc_KeyStore.h @@ -30,6 +30,7 @@ #include #include #include +#include struct parc_key_store; typedef struct parc_key_store PARCKeyStore; @@ -105,6 +106,15 @@ typedef PARCBuffer *(PARCKeyStoreGetDEREncodedPublicKey)(const void *interfaceCo */ typedef PARCBuffer *(PARCKeyStoreGetDEREncodedPrivateKey)(const void *interfaceContext); +/** + * Returns the signing algorithm from the key type store in the keystore + * + * + * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance. + * + * @return A pointer to a PARCBuffer containing the encoded private key. + */ +typedef PARCSigningAlgorithm (PARCKeyStoreGetSigningAlgorithm)(const void *interfaceContext); typedef struct parc_keystore_interface { /** @@ -177,6 +187,16 @@ typedef struct parc_keystore_interface { * @return A pointer to a PARCBuffer containing the encoded private key. */ PARCKeyStoreGetDEREncodedPrivateKey *getDEREncodedPrivateKey; + + /** + * Returns the signing algorithm from the key type store in the keystore + * + * + * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance. + * + * @return A pointer to a PARCBuffer containing the encoded private key. + */ + PARCKeyStoreGetSigningAlgorithm *getSigningAlgorithm; } PARCKeyStoreInterface; /** @@ -345,4 +365,14 @@ PARCBuffer *parcKeyStore_GetDEREncodedPublicKey(const PARCKeyStore *interfaceCon * @endcode */ PARCBuffer *parcKeyStore_GetDEREncodedPrivateKey(const PARCKeyStore *interfaceContext); + +/** + * Returns the signing algorithm from the key type store in the keystore + * + * + * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance. + * + * @return A pointer to a PARCBuffer containing the encoded private key. + */ +PARCSigningAlgorithm parcKeyStore_getSigningAlgorithm(const PARCKeyStore *interfaceContext); #endif // libparc_parc_KeyStore_h diff --git a/libparc/parc/security/parc_KeyType.c b/libparc/parc/security/parc_KeyType.c new file mode 100644 index 00000000..62fc0000 --- /dev/null +++ b/libparc/parc/security/parc_KeyType.c @@ -0,0 +1,56 @@ +/* + * 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. + */ + +/** + */ +#include + +#include +#include + +#include + +#include + +static struct { + PARCKeyType type; + char *name; +} _keyType_ToString[] = { + { PARCKeyType_RSA, "PARCKeyType_RSA" }, + { PARCKeyType_EC, "PARCKeyType_EC" }, + { 0, NULL } +}; + +const char * +parcKeyType_ToString(PARCKeyType type) +{ + for (int i = 0; _keyType_ToString[i].name != NULL; i++) { + if (_keyType_ToString[i].type == type) { + return _keyType_ToString[i].name; + } + } + return NULL; +} + +PARCKeyType +parcKeyType_FromString(const char *name) +{ + for (int i = 0; _keyType_ToString[i].name != NULL; i++) { + if (strcmp(_keyType_ToString[i].name, name) == 0) { + return _keyType_ToString[i].type; + } + } + return PARCKeyType_Invalid; +} diff --git a/libparc/parc/security/parc_KeyType.h b/libparc/parc/security/parc_KeyType.h new file mode 100644 index 00000000..92d58ed4 --- /dev/null +++ b/libparc/parc/security/parc_KeyType.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +/** + * @file parc_KeyType.h + * @ingroup security + * @brief A type specifying a key. + * + */ +#ifndef libparc_parc_KeyType_h +#define libparc_parc_KeyType_h + +typedef enum { + PARCKeyType_RSA, + PARCKeyType_EC, + PARCKeyType_Invalid +} PARCKeyType; + +/** + * Convert the `PARCKeyType` value to a human-readable string representation. + * + * @param [in] type A `PARCKeyType` value + * + * @return A static, null-terminated string. + * + * Example: + * @code + * { + * PARCKeyType type = PARCKeyType_RSA; + * const char *stringRep = parcKeyType_ToString(type); + * // use stringRep as necessary, and then free + * } + * @endcode + */ +const char *parcKeyType_ToString(PARCKeyType type); + +/** + * Convert a string representation value of a `PARCKeyType` to an actual value. + * + * @param [in] name A string representation of a `PARCKeyType` value. + * + * @return A `PARCKeyType` value. + * + * Example: + * @code + * { + * const char stringRep[17] = "PARCKeyType_RSA"; + * PARCKeyType type = parcKeyType_FromString(stringRep); + * // use stringRep as necessary, and then free + * } + * @endcode + */ +PARCKeyType parcKeyType_FromString(const char *name); +#endif // libparc_parc_KeyType_h diff --git a/libparc/parc/security/parc_Pkcs12KeyStore.c b/libparc/parc/security/parc_Pkcs12KeyStore.c index 4b9693b5..fd12c56f 100644 --- a/libparc/parc/security/parc_Pkcs12KeyStore.c +++ b/libparc/parc/security/parc_Pkcs12KeyStore.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -48,6 +49,7 @@ struct parc_pkcs12_keystore { EVP_PKEY *private_key; EVP_PKEY *public_key; X509 *x509_cert; + PARCSigningAlgorithm signAlgo; // These will be 0 length until asked for PARCBuffer *public_key_digest; @@ -63,7 +65,7 @@ struct parc_pkcs12_keystore { static bool _parcPkcs12KeyStore_Finalize(PARCPkcs12KeyStore **instancePtr) { - assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCPublicKeySigner pointer."); + assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCPkcs12KeyStore pointer."); PARCPkcs12KeyStore *keystore = *instancePtr; EVP_PKEY_free(keystore->private_key); @@ -124,6 +126,22 @@ _parcPkcs12KeyStore_ParseFile(PARCPkcs12KeyStore *keystore, const char *filename } keystore->public_key = X509_get_pubkey(keystore->x509_cert); + if (keystore->public_key) { + switch (keystore->public_key->type) { + case EVP_PKEY_RSA: + keystore->signAlgo = PARCSigningAlgorithm_RSA; + break; + case EVP_PKEY_DSA: + keystore->signAlgo = PARCSigningAlgorithm_DSA; + break; + case EVP_PKEY_EC: + keystore->signAlgo = PARCSigningAlgorithm_ECDSA; + break; + default: + fprintf(stderr, "%d bit unknown Key type\n\n", EVP_PKEY_bits(keystore->public_key)); + break; + } + } return 0; } @@ -131,11 +149,80 @@ _parcPkcs12KeyStore_ParseFile(PARCPkcs12KeyStore *keystore, const char *filename LONGBOW_STOP_DEPRECATED_WARNINGS // ============================================================= +PKCS12 *_createPkcs12KeyStore_RSA( + PARCBuffer *privateKeyBuffer, + PARCCertificate *certificate, + const char *password) +{ + // Extract the private key + EVP_PKEY *privateKey = NULL; + uint8_t *privateKeyBytes = parcBuffer_Overlay(privateKeyBuffer, parcBuffer_Limit(privateKeyBuffer)); + d2i_PrivateKey(EVP_PKEY_RSA, &privateKey, (const unsigned char **) &privateKeyBytes, parcBuffer_Limit(privateKeyBuffer)); + parcBuffer_Release(&privateKeyBuffer); + + // Extract the certificate + PARCBuffer *certBuffer = parcCertificate_GetDEREncodedCertificate(certificate); + uint8_t *certBytes = parcBuffer_Overlay(certBuffer, parcBuffer_Limit(certBuffer)); + X509 *cert = NULL; + d2i_X509(&cert, (const unsigned char **) &certBytes, parcBuffer_Limit(certBuffer)); + + parcCertificate_Release(&certificate); + + PKCS12 *pkcs12 = PKCS12_create((char *) password, + "ccnxuser", + privateKey, + cert, + NULL, + 0, + 0, + 0 /*default iter*/, + PKCS12_DEFAULT_ITER /*mac_iter*/, + 0); + X509_free(cert); + EVP_PKEY_free(privateKey); + return pkcs12; +} + +PKCS12 *_createPkcs12KeyStore_ECDSA( + PARCBuffer *privateKeyBuffer, + PARCCertificate *certificate, + const char *password) +{ + // Extract the private key + EVP_PKEY *privateKey = NULL; + uint8_t *privateKeyBytes = parcBuffer_Overlay(privateKeyBuffer, parcBuffer_Limit(privateKeyBuffer)); + d2i_PrivateKey(EVP_PKEY_EC, &privateKey, (const unsigned char **) &privateKeyBytes, parcBuffer_Limit(privateKeyBuffer)); + parcBuffer_Release(&privateKeyBuffer); + + // Extract the certificate + PARCBuffer *certBuffer = parcCertificate_GetDEREncodedCertificate(certificate); + uint8_t *certBytes = parcBuffer_Overlay(certBuffer, parcBuffer_Limit(certBuffer)); + X509 *cert = NULL; + d2i_X509(&cert, (const unsigned char **) &certBytes, parcBuffer_Limit(certBuffer)); + + parcCertificate_Release(&certificate); + + PKCS12 *pkcs12 = PKCS12_create((char *) password, + "ccnxuser", + privateKey, + cert, + NULL, + 0, + 0, + 0 /*default iter*/, + PKCS12_DEFAULT_ITER /*mac_iter*/, + 0); + X509_free(cert); + EVP_PKEY_free(privateKey); + return pkcs12; +} + bool parcPkcs12KeyStore_CreateFile( const char *filename, const char *password, const char *subjectName, + PARCSigningAlgorithm signAlgo, unsigned keyLength, unsigned validityDays) { @@ -146,38 +233,24 @@ parcPkcs12KeyStore_CreateFile( PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_DER); PARCBuffer *privateKeyBuffer; - PARCCertificate *certificate = parcCertificateFactory_CreateSelfSignedCertificate(factory, &privateKeyBuffer, (char *) subjectName, keyLength, validityDays); + PARCCertificate *certificate = parcCertificateFactory_CreateSelfSignedCertificate(factory, &privateKeyBuffer, (char *) subjectName,signAlgo, keyLength, validityDays); parcCertificateFactory_Release(&factory); if (certificate != NULL) { - // construct the full PKCS12 keystore to hold the certificate and private key - - // Extract the private key - EVP_PKEY *privateKey = NULL; - uint8_t *privateKeyBytes = parcBuffer_Overlay(privateKeyBuffer, parcBuffer_Limit(privateKeyBuffer)); - d2i_PrivateKey(EVP_PKEY_RSA, &privateKey, (const unsigned char **) &privateKeyBytes, parcBuffer_Limit(privateKeyBuffer)); - parcBuffer_Release(&privateKeyBuffer); - - // Extract the certificate - PARCBuffer *certBuffer = parcCertificate_GetDEREncodedCertificate(certificate); - uint8_t *certBytes = parcBuffer_Overlay(certBuffer, parcBuffer_Limit(certBuffer)); - X509 *cert = NULL; - d2i_X509(&cert, (const unsigned char **) &certBytes, parcBuffer_Limit(certBuffer)); - - parcCertificate_Release(&certificate); - - PKCS12 *pkcs12 = PKCS12_create((char *) password, - "ccnxuser", - privateKey, - cert, - NULL, - 0, - 0, - 0 /*default iter*/, - PKCS12_DEFAULT_ITER /*mac_iter*/, - 0); + PKCS12 *pkcs12; + switch (signAlgo){ + case PARCSigningAlgorithm_RSA: + pkcs12 = _createPkcs12KeyStore_RSA(privateKeyBuffer, certificate, password); + break; + case PARCSigningAlgorithm_ECDSA: + pkcs12 = _createPkcs12KeyStore_ECDSA(privateKeyBuffer, certificate, password); + break; + default: + return result; + } + if (pkcs12 != NULL) { int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600); if (fd != -1) { @@ -194,8 +267,6 @@ parcPkcs12KeyStore_CreateFile( trapUnrecoverableState("Cannot open(2) the file '%s': %s", filename, strerror(errno)); } PKCS12_free(pkcs12); - X509_free(cert); - EVP_PKEY_free(privateKey); } else { unsigned long errcode; while ((errcode = ERR_get_error()) != 0) { @@ -228,6 +299,10 @@ parcPkcs12KeyStore_Open(const char *filename, const char *password, PARCCryptoHa return keyStore; } +PARCSigningAlgorithm _GetSigningAlgorithm(PARCPkcs12KeyStore *keystore) +{ + return keystore->signAlgo; +} static PARCCryptoHash * _GetPublickKeyDigest(PARCPkcs12KeyStore *keystore) @@ -365,6 +440,7 @@ PARCKeyStoreInterface *PARCPkcs12KeyStoreAsKeyStore = &(PARCKeyStoreInterface) { .getDEREncodedCertificate = (PARCKeyStoreGetDEREncodedCertificate *) _GetDEREncodedCertificate, .getDEREncodedPublicKey = (PARCKeyStoreGetDEREncodedPublicKey *) _GetDEREncodedPublicKey, .getDEREncodedPrivateKey = (PARCKeyStoreGetDEREncodedPrivateKey *) _GetDEREncodedPrivateKey, + .getSigningAlgorithm = (PARCKeyStoreGetSigningAlgorithm *) _GetSigningAlgorithm, }; // ============================================================= diff --git a/libparc/parc/security/parc_Pkcs12KeyStore.h b/libparc/parc/security/parc_Pkcs12KeyStore.h index ed04c702..950284ea 100644 --- a/libparc/parc/security/parc_Pkcs12KeyStore.h +++ b/libparc/parc/security/parc_Pkcs12KeyStore.h @@ -24,6 +24,7 @@ #include #include +#include struct parc_pkcs12_keystore; typedef struct parc_pkcs12_keystore PARCPkcs12KeyStore; @@ -31,13 +32,13 @@ typedef struct parc_pkcs12_keystore PARCPkcs12KeyStore; extern PARCKeyStoreInterface *PARCPkcs12KeyStoreAsKeyStore; /** - * Increase the number of references to a `PARCPublicKeySigner` instance. + * Increase the number of references to a `PARCPkcs12KeyStore` instance. * - * Note that new `PARCPublicKeySigner` is not created, - * only that the given `PARCPublicKeySigner` reference count is incremented. - * Discard the reference by invoking `parcPublicKeySigner_Release`. + * Note that new `PARCPkcs12KeyStore` is not created, + * only that the given `PARCPkcs12KeyStore` reference count is incremented. + * Discard the reference by invoking `parcPkcs12KeyStore_Release`. * - * @param [in] instance A pointer to a valid PARCPublicKeySigner instance. + * @param [in] instance A pointer to a valid PARCPkcs12KeyStore instance. * * @return The same value as @p instance. * @@ -97,12 +98,12 @@ void parcPkcs12KeyStore_Release(PARCPkcs12KeyStore **instancePtr); * const char *filename = "/tmp/ccnxFileKeyStore_Pkcs12Open_CreateAndOpen.p12"; * const char *password = "12345"; * const char *subject = "alice"; - * bool result = parcPkcs12KeyStore_CreateFile(filename, password, subject, 1024, 32); + * bool result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32); * } * @endcode */ bool parcPkcs12KeyStore_CreateFile(const char *filename, const char *password, const char *subjectName, - unsigned keyLength, unsigned validityDays); + PARCSigningAlgorithm signAlgo, unsigned keyLength, unsigned validityDays); /** * Create a `PARCPkcs12KeyStore` instance. @@ -123,12 +124,11 @@ bool parcPkcs12KeyStore_CreateFile(const char *filename, const char *password, c * * ... * - * PARCSigningInterface *interface = parcPublicKeySignerPkcs12Store_Open(filename, password, PARCCryptoHashType_SHA256); + * PARCSigningInterface *interface = parcPkcs12Store_Open(filename, password, PARCCryptoHashType_SHA256); * * ... * } * @endcode */ PARCPkcs12KeyStore *parcPkcs12KeyStore_Open(const char *filename, const char *password, PARCCryptoHashType hashType); - -#endif // libparc_parc_PublicKeySignerPkcs12Store_h +#endif // libparc_parc_Pkcs12Store_h diff --git a/libparc/parc/security/parc_PublicKeySigner.c b/libparc/parc/security/parc_PublicKeySigner.c index 6411f075..0f11b957 100644 --- a/libparc/parc/security/parc_PublicKeySigner.c +++ b/libparc/parc/security/parc_PublicKeySigner.c @@ -118,13 +118,17 @@ parcObject_Override(PARCPublicKeySigner, PARCObject, .hashCode = (PARCObjectHashCode *) parcPublicKeySigner_HashCode); PARCPublicKeySigner * -parcPublicKeySigner_Create(PARCKeyStore *keyStore, PARCSigningAlgorithm signingAlgorithm, PARCCryptoHashType hashType) +parcPublicKeySigner_Create(PARCKeyStore *keyStore, PARCCryptoSuite suite) { PARCPublicKeySigner *result = parcObject_CreateInstance(PARCPublicKeySigner); + PARCSigningAlgorithm signAlgo = parcSigningAlgorithm_GetSigningAlgorithm(suite); + PARCCryptoHashType hashType = parcCryptoSuite_GetCryptoHash(suite); + + if (result != NULL) { result->keyStore = parcKeyStore_Acquire(keyStore); - result->signingAlgorithm = signingAlgorithm; + result->signingAlgorithm = signAlgo; result->hashType = hashType; result->hasher = parcCryptoHasher_Create(hashType); } @@ -133,9 +137,10 @@ parcPublicKeySigner_Create(PARCKeyStore *keyStore, PARCSigningAlgorithm signingA } static PARCSigningAlgorithm -_GetSigningAlgorithm(PARCPublicKeySigner *interfaceContext) +_GetSigningAlgorithm(PARCPublicKeySigner *signer) { - return PARCSigningAlgorithm_RSA; + assertNotNull(signer, "Parameter must be non-null PARCCryptoHasher"); + return signer->signingAlgorithm; } static PARCCryptoHashType @@ -159,6 +164,56 @@ _GetKeyStore(PARCPublicKeySigner *signer) return signer->keyStore; } +static inline int _SignDigestRSA(const PARCCryptoHash *digestToSign, PARCBuffer *privateKeyBuffer, int opensslDigestType, uint8_t ** sig, unsigned * sigLength) +{ + 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); + + RSA *rsa = EVP_PKEY_get1_RSA(privateKey); + *sig = parcMemory_Allocate(RSA_size(rsa)); + + assertNotNull(*sig, "parcMemory_Allocate(%u) returned NULL", RSA_size(rsa)); + + *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); + return result; +} + +static inline int _SignDigestECDSA(const PARCCryptoHash *digestToSign, PARCBuffer *privateKeyBuffer, int opensslDigestType, uint8_t ** sig, unsigned * sigLength) +{ + EVP_PKEY *privateKey = NULL; + size_t keySize = parcBuffer_Remaining(privateKeyBuffer); + uint8_t *bytes = parcBuffer_Overlay(privateKeyBuffer, keySize); + privateKey = d2i_PrivateKey(EVP_PKEY_EC, &privateKey, (const unsigned char **) &bytes, keySize); + + EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(privateKey); + + *sig = parcMemory_Allocate(ECDSA_size(ec_key)); + assertNotNull(sig, "parcMemory_Allocate(%u) returned NULL", ECDSA_size(ec_key)); + + *sigLength = 0; + PARCBuffer *bb_digest = parcCryptoHash_GetDigest(digestToSign); + int result = ECDSA_sign(opensslDigestType, + (unsigned char *) parcByteArray_Array(parcBuffer_Array(bb_digest)), + (int) parcBuffer_Remaining(bb_digest), + *sig, + sigLength, + ec_key); + assertTrue(result == 1, "Got error from ECDSA_sign: %d", result); + EC_KEY_free(ec_key); + +} + static PARCSignature * _SignDigest(PARCPublicKeySigner *signer, const PARCCryptoHash *digestToSign) { @@ -170,15 +225,10 @@ _SignDigest(PARCPublicKeySigner *signer, const PARCCryptoHash *digestToSign) // 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; + uint8_t *sig; + unsigned sigLength; switch (parcCryptoHash_GetDigestType(digestToSign)) { case PARCCryptoHashType_SHA256: @@ -192,19 +242,16 @@ _SignDigest(PARCPublicKeySigner *signer, const PARCCryptoHash *digestToSign) 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); + switch (signer->signingAlgorithm) { + case PARCSigningAlgorithm_RSA: + _SignDigestRSA(digestToSign, privateKeyBuffer, opensslDigestType, &sig, &sigLength); + break; + case PARCSigningAlgorithm_ECDSA: + _SignDigestECDSA(digestToSign, privateKeyBuffer, opensslDigestType, &sig, &sigLength); + break; + default: + return NULL; + } PARCBuffer *bbSign = parcBuffer_Allocate(sigLength); parcBuffer_Flip(parcBuffer_PutArray(bbSign, sigLength, sig)); @@ -216,6 +263,7 @@ _SignDigest(PARCPublicKeySigner *signer, const PARCCryptoHash *digestToSign) bbSign ); parcBuffer_Release(&bbSign); + parcBuffer_Release(&privateKeyBuffer); return signature; } diff --git a/libparc/parc/security/parc_PublicKeySigner.h b/libparc/parc/security/parc_PublicKeySigner.h index d2803418..99aa14fa 100644 --- a/libparc/parc/security/parc_PublicKeySigner.h +++ b/libparc/parc/security/parc_PublicKeySigner.h @@ -104,7 +104,7 @@ void parcPublicKeySigner_AssertValid(const PARCPublicKeySigner *instance); * } * @endcode */ -PARCPublicKeySigner *parcPublicKeySigner_Create(PARCKeyStore *keyStore, PARCSigningAlgorithm signingAlgorithm, PARCCryptoHashType hashType); +PARCPublicKeySigner *parcPublicKeySigner_Create(PARCKeyStore *keyStore, PARCCryptoSuite suite); /** * Compares @p instance with @p other for order. diff --git a/libparc/parc/security/parc_Signer.h b/libparc/parc/security/parc_Signer.h index c6d49480..1c967b75 100755 --- a/libparc/parc/security/parc_Signer.h +++ b/libparc/parc/security/parc_Signer.h @@ -130,7 +130,7 @@ typedef struct parc_signer_interface { * Example * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * * parcSigner_AssertValid(signer); * } @@ -150,7 +150,7 @@ void parcSigner_AssertValid(const PARCSigner *signer); * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * } * @endcode */ @@ -171,7 +171,7 @@ PARCSigner *parcSigner_Create(PARCObject *instance, PARCSigningInterface *interf * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * PARCSigner *handle = parcSigner_Acquire(signer); * // use the handle instance as needed * } @@ -197,7 +197,7 @@ PARCSigner *parcSigner_Acquire(const PARCSigner *signer); * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * * parcSigner_Release(&signer); * } @@ -215,7 +215,7 @@ void parcSigner_Release(PARCSigner **signerPtr); * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * * PARCKeyId *keyId = parcSigner_CreateKeyId(signer); * } @@ -233,7 +233,7 @@ PARCKeyId *parcSigner_CreateKeyId(const PARCSigner *signer); * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * * PARCKey *publicKey = parcSigner_CreatePublicKey(signer); * } @@ -257,7 +257,7 @@ PARCKey *parcSigner_CreatePublicKey(PARCSigner *signer); * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * * PARCCryptoHasher hasher = parcSigner_GetCryptoHasher(signer); * } @@ -279,7 +279,7 @@ PARCCryptoHasher *parcSigner_GetCryptoHasher(const PARCSigner *signer); * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * * PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer); * parcCryptoHasher_Init(hasher); @@ -303,7 +303,7 @@ PARCSignature *parcSigner_SignDigest(const PARCSigner *signer, const PARCCryptoH * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * PARCBuffer *inputBuffer = ... * * PARCSignature signature = parcSigner_SignBuffer(signer, inputBuffer); @@ -322,7 +322,7 @@ PARCSignature *parcSigner_SignBuffer(const PARCSigner *signer, const PARCBuffer * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * * PARCSigningAlgorithm suite = parcSigner_GetSigningAlgorithm(signer); * } @@ -340,7 +340,7 @@ PARCSigningAlgorithm parcSigner_GetSigningAlgorithm(PARCSigner *signer); * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * * PARCCryptoHashType suite = parcSigner_GetCryptoHashType(signer); * } @@ -358,7 +358,7 @@ PARCCryptoHashType parcSigner_GetCryptoHashType(const PARCSigner *signer); * Example: * @code * { - * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); + * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner); * * PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer); * } diff --git a/libparc/parc/security/parc_SigningAlgorithm.c b/libparc/parc/security/parc_SigningAlgorithm.c index d0dadd4a..1e800a6a 100755 --- a/libparc/parc/security/parc_SigningAlgorithm.c +++ b/libparc/parc/security/parc_SigningAlgorithm.c @@ -32,6 +32,7 @@ static struct { { PARCSigningAlgorithm_RSA, "PARCSigningAlgorithm_RSA" }, { PARCSigningAlgorithm_DSA, "PARCSigningAlgorithm_DSA" }, { PARCSigningAlgorithm_HMAC, "PARCSigningAlgorithm_HMAC" }, + { PARCSigningAlgorithm_ECDSA,"PARCSigningAlgorithm_ECDSA"}, { 0, NULL } }; @@ -72,6 +73,8 @@ parcSigningAlgorithm_GetSigningAlgorithm(PARCCryptoSuite suite) case PARCCryptoSuite_HMAC_SHA512: return PARCSigningAlgorithm_HMAC; + case PARCCryptoSuite_ECDSA_SHA256: + return PARCSigningAlgorithm_ECDSA; case PARCCryptoSuite_NULL_CRC32C: return PARCSigningAlgortihm_NULL; diff --git a/libparc/parc/security/parc_SigningAlgorithm.h b/libparc/parc/security/parc_SigningAlgorithm.h index 02f7c946..ae5fc252 100644 --- a/libparc/parc/security/parc_SigningAlgorithm.h +++ b/libparc/parc/security/parc_SigningAlgorithm.h @@ -34,7 +34,8 @@ typedef enum { PARCSigningAlgorithm_RSA = 1, PARCSigningAlgorithm_DSA = 2, PARCSigningAlgorithm_HMAC = 3, - PARCSigningAlgortihm_NULL = 4, + PARCSigningAlgorithm_ECDSA = 4, + PARCSigningAlgortihm_NULL = 5, } PARCSigningAlgorithm; /** diff --git a/libparc/parc/security/parc_X509Certificate.c b/libparc/parc/security/parc_X509Certificate.c index 8cc4b0b7..67ee6b2b 100644 --- a/libparc/parc/security/parc_X509Certificate.c +++ b/libparc/parc/security/parc_X509Certificate.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -398,91 +399,219 @@ parcX509Certificate_CreateFromDERBuffer(const PARCBuffer *buffer) return cert; } -PARCX509Certificate * -parcX509Certificate_CreateSelfSignedCertificate(PARCBuffer **privateKeyBuffer, char *subjectName, int keyLength, size_t validityDays) +PARCX509Certificate * _createSelfSignedCertificate_RSA(PARCBuffer **privateKeyBuffer, char *subjectName, int keyLength, size_t validityDays) { - parcSecurity_AssertIsInitialized(); + parcSecurity_AssertIsInitialized(); - RSA *rsa = RSA_new(); - assertNotNull(rsa, "RSA_new failed."); + RSA *rsa = RSA_new(); + assertNotNull(rsa, "RSA_new failed."); - EVP_PKEY *privateKey = EVP_PKEY_new(); - assertNotNull(privateKey, "EVP_PKEY_new() failed."); + EVP_PKEY *privateKey = EVP_PKEY_new(); + assertNotNull(privateKey, "EVP_PKEY_new() failed."); - X509 *cert = X509_new(); - assertNotNull(cert, "X509_new() failed."); + X509 *cert = X509_new(); + assertNotNull(cert, "X509_new() failed."); - int res; - BIGNUM *pub_exp; + int res; + BIGNUM *pub_exp; - pub_exp = BN_new(); + pub_exp = BN_new(); - BN_set_word(pub_exp, RSA_F4); - res = 1; - bool result = false; - if (RSA_generate_key_ex(rsa, keyLength, pub_exp, NULL)) { - if (EVP_PKEY_set1_RSA(privateKey, rsa)) { - if (X509_set_version(cert, 2)) { // 2 => X509v3 - result = true; - } - } + BN_set_word(pub_exp, RSA_F4); + res = 1; + bool result = false; + if (RSA_generate_key_ex(rsa, keyLength, pub_exp, NULL)) { + if (EVP_PKEY_set1_RSA(privateKey, rsa)) { + if (X509_set_version(cert, 2)) { // 2 => X509v3 + result = true; + } } - if (result) { - // add serial number - if (_addRandomSerial(cert) == true) { - if (_addValidityPeriod(cert, validityDays) == true) { - if (X509_set_pubkey(cert, privateKey) == 1) { - if (_addSubjectName(cert, subjectName) == true) { - if (_addExtensions(cert) == true) { - if (_addKeyIdentifier(cert) == true) { - // The certificate is complete, sign it. - if (X509_sign(cert, privateKey, EVP_sha256())) { - result = true; - } else { - printf("error: (%d) %s\n", res, ERR_lib_error_string(res)); - } - } - } - } + } + if (result) { + // add serial number + if (_addRandomSerial(cert) == true) { + if (_addValidityPeriod(cert, validityDays) == true) { + if (X509_set_pubkey(cert, privateKey) == 1) { + if (_addSubjectName(cert, subjectName) == true) { + if (_addExtensions(cert) == true) { + if (_addKeyIdentifier(cert) == true) { + // The certificate is complete, sign it. + if (X509_sign(cert, privateKey, EVP_sha256())) { + result = true; + } else { + printf("error: (%d) %s\n", res, ERR_lib_error_string(res)); } + } } + } } + } } + } - ERR_print_errors_fp(stdout); + ERR_print_errors_fp(stdout); - BN_free(pub_exp); + BN_free(pub_exp); - uint8_t *certificateDerEncoding = NULL; - int numBytes = i2d_X509(cert, &certificateDerEncoding); - if (numBytes < 0) { - EVP_PKEY_free(privateKey); - RSA_free(rsa); - X509_free(cert); + uint8_t *certificateDerEncoding = NULL; + int numBytes = i2d_X509(cert, &certificateDerEncoding); + if (numBytes < 0) { + EVP_PKEY_free(privateKey); + RSA_free(rsa); + X509_free(cert); - return NULL; - } + return NULL; + } - PARCBuffer *derBuffer = parcBuffer_Allocate(numBytes); - parcBuffer_Flip(parcBuffer_PutArray(derBuffer, numBytes, certificateDerEncoding)); + PARCBuffer *derBuffer = parcBuffer_Allocate(numBytes); + parcBuffer_Flip(parcBuffer_PutArray(derBuffer, numBytes, certificateDerEncoding)); - PARCX509Certificate *certificate = parcX509Certificate_CreateFromDERBuffer(derBuffer); - parcBuffer_Release(&derBuffer); + PARCX509Certificate *certificate = parcX509Certificate_CreateFromDERBuffer(derBuffer); + parcBuffer_Release(&derBuffer); - uint8_t *privateKeyBytes = NULL; - int privateKeyByteCount = i2d_PrivateKey(privateKey, &privateKeyBytes); - if (privateKeyByteCount < 0) { - EVP_PKEY_free(privateKey); - RSA_free(rsa); - X509_free(cert); + uint8_t *privateKeyBytes = NULL; + int privateKeyByteCount = i2d_PrivateKey(privateKey, &privateKeyBytes); + if (privateKeyByteCount < 0) { + EVP_PKEY_free(privateKey); + RSA_free(rsa); + X509_free(cert); - return NULL; + return NULL; + } + + *privateKeyBuffer = parcBuffer_Allocate(privateKeyByteCount); + parcBuffer_Flip(parcBuffer_PutArray(*privateKeyBuffer, privateKeyByteCount, privateKeyBytes)); + + EVP_PKEY_free(privateKey); + RSA_free(rsa); + X509_free(cert); + + return certificate; +} + +static inline int _get_EC_params_from_lenght(int keyLength) +{ + //For the moment only support 256bit key length + switch (keyLength) + { + case 160: + return NID_secp160k1; + case 192: + return NID_secp192k1; + case 224: + return NID_secp224k1; + case 256: + return NID_secp256k1; + default: + return -1; + } + +} + +PARCX509Certificate * _createSelfSignedCertificate_EC(PARCBuffer **privateKeyBuffer, char *subjectName, int keyLength, size_t validityDays) +{ + parcSecurity_AssertIsInitialized(); + int curve_params = _get_EC_params_from_lenght(keyLength); + bool result = false; + + if (curve_params == -1) + return NULL; + + EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve_params); + assertNotNull(ec_key, "EC key creation failed."); + + EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE); + + EVP_PKEY *pkey = EVP_PKEY_new(); + assertNotNull(pkey, "EVP_PKEY_new() failed."); + + X509 *cert = X509_new(); + assertNotNull(cert, "X509_new() failed."); + + int res; + + + if((res = (EC_KEY_generate_key(ec_key))) < 0 ) + printf("error: (%d) %s\n", res, ERR_lib_error_string(res)); + else if((res = (EVP_PKEY_set1_EC_KEY(pkey, ec_key))) < 0 ) + printf("error: (%d) %s\n", res, ERR_lib_error_string(res)); + else if (X509_set_version(cert, 2)) { // 2 => X509v3 + result = true; + } + + if (result) { + // add serial number + if (_addRandomSerial(cert) == true) { + if (_addValidityPeriod(cert, validityDays) == true) { + if (X509_set_pubkey(cert, pkey) == 1) { + if (_addSubjectName(cert, subjectName) == true) { + if (_addExtensions(cert) == true) { + if (_addKeyIdentifier(cert) == true) { + // The certificate is complete, sign it. + if (X509_sign(cert, pkey, EVP_sha256())) { + result = true; + } else { + printf("error: (%d) %s\n", res, ERR_lib_error_string(res)); + } + } + } + } + } + } } + } - *privateKeyBuffer = parcBuffer_Allocate(privateKeyByteCount); - parcBuffer_Flip(parcBuffer_PutArray(*privateKeyBuffer, privateKeyByteCount, privateKeyBytes)); + ERR_print_errors_fp(stdout); - return certificate; + + + uint8_t *certificateDerEncoding = NULL; + int numBytes = i2d_X509(cert, &certificateDerEncoding); + if (numBytes < 0) { + EVP_PKEY_free(pkey); + EC_KEY_free(ec_key); + X509_free(cert); + + return NULL; + } + + PARCBuffer *derBuffer = parcBuffer_Allocate(numBytes); + parcBuffer_Flip(parcBuffer_PutArray(derBuffer, numBytes, certificateDerEncoding)); + + PARCX509Certificate *certificate = parcX509Certificate_CreateFromDERBuffer(derBuffer); + parcBuffer_Release(&derBuffer); + + uint8_t *pkeyBytes = NULL; + int pkeyByteCount = i2d_PrivateKey(pkey, &pkeyBytes); + if (pkeyByteCount < 0) { + EVP_PKEY_free(pkey); + EC_KEY_free(ec_key); + X509_free(cert); + + return NULL; + } + + *privateKeyBuffer = parcBuffer_Allocate(pkeyByteCount); + parcBuffer_Flip(parcBuffer_PutArray(*privateKeyBuffer, pkeyByteCount, pkeyBytes)); + + EVP_PKEY_free(pkey); + EC_KEY_free(ec_key); + X509_free(cert); + + return certificate; +} + +PARCX509Certificate * +parcX509Certificate_CreateSelfSignedCertificate(PARCBuffer **privateKeyBuffer, char *subjectName, int keyLength, size_t validityDays, PARCKeyType keyType) +{ + switch(keyType) { + case PARCKeyType_RSA: + return _createSelfSignedCertificate_RSA(privateKeyBuffer, subjectName, keyLength, validityDays); + case PARCKeyType_EC: + return _createSelfSignedCertificate_EC(privateKeyBuffer, subjectName, keyLength, validityDays); + } + + return NULL; } diff --git a/libparc/parc/security/parc_X509Certificate.h b/libparc/parc/security/parc_X509Certificate.h index 037d6aac..c6ca8247 100755 --- a/libparc/parc/security/parc_X509Certificate.h +++ b/libparc/parc/security/parc_X509Certificate.h @@ -23,7 +23,8 @@ #ifndef libparc_parc_X509Certificate_h #define libparc_parc_X509Certificate_h -#include +#include +#include struct parc_X509_certificate; typedef struct parc_X509_certificate PARCX509Certificate; @@ -67,7 +68,7 @@ PARCX509Certificate *parcX509Certificate_CreateFromPEMFile(const char *filename) PARCX509Certificate *parcX509Certificate_CreateFromDERBuffer(const PARCBuffer *buffer); // TODO -PARCX509Certificate *parcX509Certificate_CreateSelfSignedCertificate(PARCBuffer **privateKey, char *subjectName, int keyLength, size_t valdityDays); +PARCX509Certificate *parcX509Certificate_CreateSelfSignedCertificate(PARCBuffer **privateKey, char *subjectName, int keyLength, size_t valdityDays, PARCKeyType ketType); /** * Increase the number of references to a `PARCX509Certificate` instance. diff --git a/libparc/parc/security/test/CMakeLists.txt b/libparc/parc/security/test/CMakeLists.txt index 189bc7ca..40a5eb70 100644 --- a/libparc/parc/security/test/CMakeLists.txt +++ b/libparc/parc/security/test/CMakeLists.txt @@ -13,17 +13,21 @@ set(TestsExpectedToPass test_parc_Identity test_parc_IdentityFile test_parc_InMemoryVerifier + test_parc_InMemoryVerifierECDSA test_parc_Key test_parc_KeyId test_parc_KeyStore test_parc_SecureRandom test_parc_Pkcs12KeyStore + test_parc_Pkcs12KeyStoreECDSA test_parc_PublicKeySigner + test_parc_PublicKeyECSigner test_parc_SymmetricKeySigner test_parc_SymmetricKeyStore test_parc_Security test_parc_Signature test_parc_Signer + test_parc_SignerEC test_parc_SigningAlgorithm test_parc_Verifier test_parc_X509Certificate @@ -46,6 +50,7 @@ set(EXTRA_DATA_FILES test_pubkey.pem test_random_bytes test_random_bytes.sig + test_random_bytes.sig_ec test_random_bytes.hmac_sha256 test_random_bytes.hmac_sha512 test_rsa.p12 @@ -58,6 +63,14 @@ set(EXTRA_DATA_FILES test_rsa_pub_sha256.bin test_symmetric_key.bin test_symmetric_key.sha256 + test_ec.p12 + test_ec_crt.der + test_ec_crt_sha256.bin + test_ec_key.der + test_ec_key.pem + test_ec_pub.der + test_ec_pub.pem + test_ec_pub_sha256.bin ) foreach(data_file ${EXTRA_DATA_FILES}) diff --git a/libparc/parc/security/test/README.keystore b/libparc/parc/security/test/README.keystore index 70227d33..0c9c3a58 100644 --- a/libparc/parc/security/test/README.keystore +++ b/libparc/parc/security/test/README.keystore @@ -33,3 +33,31 @@ openssl sha -sha256 -sign test_rsa_key.pem -out test_random_bytes.sig < test_ran # the "-in test_rsa_pub_sha256.bin" is the binary digest we will sign. openssl rsautl -sign -inkey test_rsa_key.pem -in test_rsa_pub_sha256.bin -out test_rsa_pub_sha256.bin.sig + +#EC +openssl ecparam -name secp256k1 -genkey -noout -out test_ec_key.pem +openssl ec -pubout -in test_ec_key.pem -out test_ec_pub.pem +openssl req -new -key test_ec_key.pem -out test_ec.csr +openssl x509 -req -days 365 -in test_ec.csr -signkey test_ec_key.pem -out test_ec.crt +openssl pkcs12 -export -in test_ec.crt -inkey test_ec_key.pem -out test_ec.p12 -name ccnxuser -CAfile test_ec.crt -caname root -chain -passout pass:blueberry + +# saves the public key in DER form so we can calculate the sha256 of it +openssl ec -in test_ec_key.pem -outform DER -pubout -out test_ec_pub.der + +# save the private key in DER form so we can compare in code +openssl ec -in test_ec_key.pem -outform DER -out test_ec_key.der + +# computes the sha256 and saves it in binary form +openssl sha256 -out test_ec_pub_sha256.bin -sha256 -binary < test_ec_pub.der + +# Save the certificate in DER form, then get the SHA256 hash of it +# These are similar to doing "openssl x509 -in test_rsa.crt -fingerprint -sha256" +openssl x509 -outform DER -out test_ec_crt.der -in test_ec.crt +openssl sha256 -out test_ec_crt_sha256.bin -sha256 -binary < test_ec_crt.der + +# To verify signing, we create a random buffer, then sign with a SHA256 digest + +openssl sha -sha256 -sign test_ec_key.pem -out test_random_bytes.sig_ec < test_random_bytes + +# the "-in test_rsa_pub_sha256.bin" is the binary digest we will sign. +openssl rsautl -sign -inkey test_ec_key.pem -in test_ec_pub_sha256.bin -out test_ec_pub_sha256.bin.sig \ No newline at end of file diff --git a/libparc/parc/security/test/test_ec.crt b/libparc/parc/security/test/test_ec.crt new file mode 100644 index 00000000..69c446c2 --- /dev/null +++ b/libparc/parc/security/test/test_ec.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBsjCCAVkCCQDTJPDkG9R7gjAKBggqhkjOPQQDAjBjMQswCQYDVQQGEwJGUjEP +MA0GA1UECAwGRnJhbmNlMRwwGgYDVQQHDBNJc3N5LWxlcy1tb3VsaW5lYXV4MRYw +FAYDVQQKDA1DaXNjbyBTeXN0ZW1zMQ0wCwYDVQQLDARDVEFPMB4XDTE4MDQxMTEw +MDYzNVoXDTE5MDQxMTEwMDYzNVowYzELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZy +YW5jZTEcMBoGA1UEBwwTSXNzeS1sZXMtbW91bGluZWF1eDEWMBQGA1UECgwNQ2lz +Y28gU3lzdGVtczENMAsGA1UECwwEQ1RBTzBWMBAGByqGSM49AgEGBSuBBAAKA0IA +BKl0iUeCpxrOueZrbZLiWMhs7PAGgNYt+x4koWPJ0wELrbs7oNIqys8mJXQM9oTw +I1b4IIgloT7/VcPanz66NgcwCgYIKoZIzj0EAwIDRwAwRAIgSc4s8ZKkEmuyV8wO +08C58dN3dxXVYdW1v1zt3lq88dwCICf64KpJok1MGSX/t/QldOiVqPtPAv6l4lq2 +9EiLK+m9 +-----END CERTIFICATE----- diff --git a/libparc/parc/security/test/test_ec.csr b/libparc/parc/security/test/test_ec.csr new file mode 100644 index 00000000..49247a4e --- /dev/null +++ b/libparc/parc/security/test/test_ec.csr @@ -0,0 +1,8 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBGzCBwgIBADBjMQswCQYDVQQGEwJGUjEPMA0GA1UECAwGRnJhbmNlMRwwGgYD +VQQHDBNJc3N5LWxlcy1tb3VsaW5lYXV4MRYwFAYDVQQKDA1DaXNjbyBTeXN0ZW1z +MQ0wCwYDVQQLDARDVEFPMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEqXSJR4KnGs65 +5mttkuJYyGzs8AaA1i37HiShY8nTAQutuzug0irKzyYldAz2hPAjVvggiCWhPv9V +w9qfPro2B6AAMAoGCCqGSM49BAMCA0gAMEUCIQCCQ5E36YNPG5LV2Q8i9flCPWk+ +4MjtioNV2I+NSf/6XgIgUjEeA54lw5dS8yqAkH8TDvw6ROe90rzBAfjsI1X2Y0k= +-----END CERTIFICATE REQUEST----- diff --git a/libparc/parc/security/test/test_ec.p12 b/libparc/parc/security/test/test_ec.p12 new file mode 100644 index 00000000..5fb44d05 Binary files /dev/null and b/libparc/parc/security/test/test_ec.p12 differ diff --git a/libparc/parc/security/test/test_ec_crt.der b/libparc/parc/security/test/test_ec_crt.der new file mode 100644 index 00000000..d3294e20 Binary files /dev/null and b/libparc/parc/security/test/test_ec_crt.der differ diff --git a/libparc/parc/security/test/test_ec_crt_sha256.bin b/libparc/parc/security/test/test_ec_crt_sha256.bin new file mode 100644 index 00000000..22d1e2c4 --- /dev/null +++ b/libparc/parc/security/test/test_ec_crt_sha256.bin @@ -0,0 +1 @@ +Ý!bL?åœ'Âkàçllýã!çT°ƒh é~ï–z~p` \ No newline at end of file diff --git a/libparc/parc/security/test/test_ec_key.der b/libparc/parc/security/test/test_ec_key.der new file mode 100644 index 00000000..28fbd5a5 Binary files /dev/null and b/libparc/parc/security/test/test_ec_key.der differ diff --git a/libparc/parc/security/test/test_ec_key.pem b/libparc/parc/security/test/test_ec_key.pem new file mode 100644 index 00000000..6b0e1941 --- /dev/null +++ b/libparc/parc/security/test/test_ec_key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIJXMLfUwhGUPNiXdmfpvWtfLzRSTL2fm9s+lTLCBGRdVoAcGBSuBBAAK +oUQDQgAEqXSJR4KnGs655mttkuJYyGzs8AaA1i37HiShY8nTAQutuzug0irKzyYl +dAz2hPAjVvggiCWhPv9Vw9qfPro2Bw== +-----END EC PRIVATE KEY----- diff --git a/libparc/parc/security/test/test_ec_pub.der b/libparc/parc/security/test/test_ec_pub.der new file mode 100644 index 00000000..e9150405 Binary files /dev/null and b/libparc/parc/security/test/test_ec_pub.der differ diff --git a/libparc/parc/security/test/test_ec_pub.pem b/libparc/parc/security/test/test_ec_pub.pem new file mode 100644 index 00000000..2ab68ff8 --- /dev/null +++ b/libparc/parc/security/test/test_ec_pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEqXSJR4KnGs655mttkuJYyGzs8AaA1i37 +HiShY8nTAQutuzug0irKzyYldAz2hPAjVvggiCWhPv9Vw9qfPro2Bw== +-----END PUBLIC KEY----- diff --git a/libparc/parc/security/test/test_ec_pub_sha256.bin b/libparc/parc/security/test/test_ec_pub_sha256.bin new file mode 100644 index 00000000..c0dd0fac --- /dev/null +++ b/libparc/parc/security/test/test_ec_pub_sha256.bin @@ -0,0 +1 @@ +1&,@‡‰ n Èå š„t©¢-DÔ|Œ¶>%—õžz` \ No newline at end of file diff --git a/libparc/parc/security/test/test_ec_pub_sha256.bin.sig b/libparc/parc/security/test/test_ec_pub_sha256.bin.sig new file mode 100644 index 00000000..787f8b3a Binary files /dev/null and b/libparc/parc/security/test/test_ec_pub_sha256.bin.sig differ diff --git a/libparc/parc/security/test/test_parc_CryptoSuite.c b/libparc/parc/security/test/test_parc_CryptoSuite.c index f210fd79..42007617 100755 --- a/libparc/parc/security/test/test_parc_CryptoSuite.c +++ b/libparc/parc/security/test/test_parc_CryptoSuite.c @@ -64,7 +64,7 @@ LONGBOW_TEST_CASE(Global, parcCryptoSuite_GetCryptoHash) assertTrue(PARCCryptoHashType_SHA256 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_HMAC_SHA256), "Expected to be true"); assertTrue(PARCCryptoHashType_SHA512 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_HMAC_SHA512), "Expected to be true"); assertTrue(PARCCryptoHashType_CRC32C == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_NULL_CRC32C), "Expected to be true"); - assertTrue(PARCCryptoHashType_SHA256 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_EC_SECP_256K1), "Expected to be true"); + assertTrue(PARCCryptoHashType_SHA256 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_ECDSA_SHA256), "Expected to be true"); } LONGBOW_TEST_CASE_EXPECTS(Global, parcCryptoSuite_GetCryptoHash_IllegalValue, .event = &LongBowTrapIllegalValue) diff --git a/libparc/parc/security/test/test_parc_Identity.c b/libparc/parc/security/test/test_parc_Identity.c index 4177cc98..3208efcb 100644 --- a/libparc/parc/security/test/test_parc_Identity.c +++ b/libparc/parc/security/test/test_parc_Identity.c @@ -162,7 +162,7 @@ LONGBOW_TEST_CASE(Global, parcIdentity_CreateSigner) assertEqualStrings(keystorePassword, parcIdentity_GetPassWord(identity)); - PARCSigner *signer = parcIdentity_CreateSigner(identity); + PARCSigner *signer = parcIdentity_CreateSigner(identity, PARCCryptoSuite_RSA_SHA256); assertNotNull(signer, "Expected non-null"); diff --git a/libparc/parc/security/test/test_parc_IdentityFile.c b/libparc/parc/security/test/test_parc_IdentityFile.c index cbc877f2..5bcc5570 100644 --- a/libparc/parc/security/test/test_parc_IdentityFile.c +++ b/libparc/parc/security/test/test_parc_IdentityFile.c @@ -176,7 +176,7 @@ LONGBOW_TEST_CASE(Global, parcIdentityFile_CreateSigner) } else { perror("getcwd() error"); } - PARCSigner *signer = parcIdentityFile_CreateSigner(identityFile); + PARCSigner *signer = parcIdentityFile_CreateSigner(identityFile, PARCCryptoSuite_RSA_SHA256); assertNotNull(signer, "Expected non-null"); diff --git a/libparc/parc/security/test/test_parc_InMemoryVerifier.c b/libparc/parc/security/test/test_parc_InMemoryVerifier.c index 1d8c9b0f..81baebc7 100755 --- a/libparc/parc/security/test/test_parc_InMemoryVerifier.c +++ b/libparc/parc/security/test/test_parc_InMemoryVerifier.c @@ -114,11 +114,11 @@ LONGBOW_TEST_FIXTURE_SETUP(Local) PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *signer = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); parcKeyStore_Release(&keyStore); - data->signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); - parcPublicKeySigner_Release(&publicKeySigner); + data->signer = parcSigner_Create(signer, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&signer); assertNotNull(data->signer, "Got null result from opening openssl pkcs12 file"); data->inMemoryInterface = parcInMemoryVerifier_Create(); diff --git a/libparc/parc/security/test/test_parc_InMemoryVerifierECDSA.c b/libparc/parc/security/test/test_parc_InMemoryVerifierECDSA.c new file mode 100644 index 00000000..c007c176 --- /dev/null +++ b/libparc/parc/security/test/test_parc_InMemoryVerifierECDSA.c @@ -0,0 +1,417 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_InMemoryVerifier.c" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +LONGBOW_TEST_RUNNER(parc_InMemoryVerifier) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_InMemoryVerifier) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_InMemoryVerifier) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + parcSecurity_Init(); + LONGBOW_RUN_TEST_CASE(Global, parcInMemoryVerifier_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + parcSecurity_Fini(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcInMemoryVerifier_Create) +{ + PARCInMemoryVerifier *verifier = parcInMemoryVerifier_Create(); + + assertNotNull(verifier, "Got null result from parcInMemoryVerifier_Create"); + + parcInMemoryVerifier_Release(&verifier); +} + +// =========== +// We use the known keys on disk for these tests + +typedef struct test_data { + PARCSigner *signer; + PARCInMemoryVerifier *inMemoryInterface; +} TestData; + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_AddKeyId); + LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_GetCryptoHasher); + LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_AllowedCryptoSuite_ECDSA); + + LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_RemoveKeyId); + LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature); + LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHashAlg); + LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadSigAlg); + LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHash); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + parcSecurity_Init(); + + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + parcKeyStore_Release(&keyStore); + + data->signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + assertNotNull(data->signer, "Got null result from opening openssl pkcs12 file"); + + data->inMemoryInterface = parcInMemoryVerifier_Create(); + + longBowTestCase_SetClipBoardData(testCase, data); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + parcInMemoryVerifier_Release(&data->inMemoryInterface); + parcSigner_Release(&data->signer); + parcMemory_Deallocate((void **) &data); + + parcSecurity_Fini(); + + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_GetCryptoHasher) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCKey *key = parcSigner_CreatePublicKey(data->signer); + _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key); + + PARCCryptoHasher *hasher = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256); + parcKey_Release(&key); + assertNotNull(hasher, "Got a null hasher"); +} + +LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_AddKeyId) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // create the key with copies of the byte buffers + PARCKey *key = parcSigner_CreatePublicKey(data->signer); + + _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key); + + // now do something that uses the key + bool success = _parcInMemoryVerifier_AllowedCryptoSuite(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoSuite_ECDSA_SHA256); + parcKey_Release(&key); + assertTrue(success, "Should have allowed PARCCryptoSuite_ECDSA_SHA256 for an ECDSA keystore"); +} + +LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_AllowedCryptoSuite_ECDSA) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCKey *key = parcSigner_CreatePublicKey(data->signer); + _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key); + + // now do something that uses the key + bool success = _parcInMemoryVerifier_AllowedCryptoSuite(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoSuite_ECDSA_SHA256); + parcKey_Release(&key); + assertTrue(success, "Should have allowed PARCCryptoSuite_ECDSA_SHA256 for an ECDSA keystore"); +} + +LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_RemoveKeyId) +{ + testUnimplemented("This test is unimplemented"); +} + +/** + * Verify the openssl signature using the public key and our locally computed hash + */ +LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // Setup the key in the verifier + + PARCKey *key = parcSigner_CreatePublicKey(data->signer); + + _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key); + + // read the buffer to sign + int fd = open("test_random_bytes", O_RDONLY); + uint8_t buffer_to_sign[2048]; + ssize_t read_bytes = read(fd, buffer_to_sign, 2048); + close(fd); + + // Digest it + PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256); + assertNotNull(digester, "got null cryptohasher from inmemory verifier"); + + parcCryptoHasher_Init(digester); + parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes); + PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester); + + // now read the "true" signature + uint8_t scratch_buffer[1024]; + fd = open("test_random_bytes.sig_ec", O_RDONLY); + read_bytes = read(fd, scratch_buffer, 1024); + assertTrue(read_bytes <= 72, + "read incorrect size signature from disk: %zu", read_bytes); + close(fd); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes); + PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer); + + PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bb_sig); + parcBuffer_Release(&bb_sig); + parcBufferComposer_Release(&composer); + + bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_ECDSA_SHA256, signatureToVerify); + + parcSignature_Release(&signatureToVerify); + parcCryptoHash_Release(&localHash); + parcKey_Release(&key); + + assertTrue(success, "Could not validate signature"); +} + +/** + * Same as the "good" code above, but calculate the hash with the wrong hash algorithm. This is + * what would happen if the signer and the verifier did not use the same hash algorithym. + */ +LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHashAlg) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool success; + + // Setup the key in the verifier + + PARCKey *key = parcSigner_CreatePublicKey(data->signer); + + _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key); + + // read the buffer to sign + int fd = open("test_random_bytes", O_RDONLY); + uint8_t buffer_to_sign[2048]; + ssize_t read_bytes = read(fd, buffer_to_sign, 2048); + close(fd); + + // Digest it WITH THE WRONG HASH + PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA512); + assertNotNull(digester, "got null cryptohasher from inmemory verifier"); + + parcCryptoHasher_Init(digester); + parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes); + PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester); + + // now read the "true" signature + uint8_t scratch_buffer[1024]; + fd = open("test_random_bytes.sig_ec", O_RDONLY); + read_bytes = read(fd, scratch_buffer, 1024); + assertTrue(read_bytes <= 72, "read incorrect size signature from disk: %zu", read_bytes); + close(fd); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes); + PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer); + + PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_ECDSA, + PARCCryptoHashType_SHA256, + bb_sig); + parcBuffer_Release(&bb_sig); + parcBufferComposer_Release(&composer); + + success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_ECDSA_SHA256, signatureToVerify); + + parcSignature_Release(&signatureToVerify); + parcCryptoHash_Release(&localHash); + parcKey_Release(&key); + + assertFalse(success, "Signatures should not have verified! Wrong hash types!"); +} + + +/** + * Same as the "good" code, but tell the verifier the wrong key type. This is what would + * happen if the verifier somehow picked the wrong cryptosuite. + */ +LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadSigAlg) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // Setup the key in the verifier + PARCKey *key = parcSigner_CreatePublicKey(data->signer); + + _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key); + + // read the buffer to sign + int fd = open("test_random_bytes", O_RDONLY); + uint8_t buffer_to_sign[2048]; + ssize_t read_bytes = read(fd, buffer_to_sign, 2048); + close(fd); + + // Digest it + PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256); + assertNotNull(digester, "got null cryptohasher from inmemory verifier"); + + parcCryptoHasher_Init(digester); + parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes); + PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester); + + // now read the "true" signature + uint8_t scratch_buffer[1024]; + fd = open("test_random_bytes.sig_ec", O_RDONLY); + read_bytes = read(fd, scratch_buffer, 1024); + assertTrue(read_bytes <= 72, "read incorrect size signature from disk: %zu", read_bytes); + close(fd); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes); + PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer); + + // HERE WE TELL IT DSA, NOT RSA + PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_DSA, + PARCCryptoHashType_SHA256, + bb_sig); + parcBuffer_Release(&bb_sig); + parcBufferComposer_Release(&composer); + + bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_ECDSA_SHA256, signatureToVerify); + + parcSignature_Release(&signatureToVerify); + parcCryptoHash_Release(&localHash); + parcKey_Release(&key); + + assertFalse(success, "Signatures should not have verified! Wrong hash types!"); +} + +/** + * THis tests the locally computed digest not matching te digest used for the signature. + */ +LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHash) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // Setup the key in the verifier + + PARCKey *key = parcSigner_CreatePublicKey(data->signer); + + _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key); + + // read the buffer to sign + int fd = open("test_random_bytes", O_RDONLY); + uint8_t buffer_to_sign[2048]; + ssize_t read_bytes = read(fd, buffer_to_sign, 2048); + close(fd); + + // Digest it + PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256); + assertNotNull(digester, "got null cryptohasher from inmemory verifier"); + + // DIGEST THE BYTES TWICE TO GIVE WRONG HASH + parcCryptoHasher_Init(digester); + parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes); + parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes); + PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester); + + // now read the "true" signature + uint8_t scratch_buffer[1024]; + fd = open("test_random_bytes.sig_ec", O_RDONLY); + read_bytes = read(fd, scratch_buffer, 1024); + assertTrue(read_bytes <= 72, "read incorrect size signature from disk: %zu", read_bytes); + close(fd); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes); + PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer); + + PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_ECDSA, + PARCCryptoHashType_SHA256, + bb_sig); + parcBuffer_Release(&bb_sig); + parcBufferComposer_Release(&composer); + + bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_ECDSA_SHA256, signatureToVerify); + + parcSignature_Release(&signatureToVerify); + parcCryptoHash_Release(&localHash); + parcKey_Release(&key); + + assertFalse(success, "Signature verified even with wrong hash"); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_InMemoryVerifier); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/security/test/test_parc_Pkcs12KeyStore.c b/libparc/parc/security/test/test_parc_Pkcs12KeyStore.c index 1cd004cd..17a5b60f 100755 --- a/libparc/parc/security/test/test_parc_Pkcs12KeyStore.c +++ b/libparc/parc/security/test/test_parc_Pkcs12KeyStore.c @@ -109,7 +109,7 @@ LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_CreateAndOpen) const char *subject = "alice"; bool result; - result = parcPkcs12KeyStore_CreateFile(filename, password, subject, 1024, 32); + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32); assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); @@ -128,7 +128,7 @@ LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_CreateFile_Fail) const char *subject = "alice"; bool result; - result = parcPkcs12KeyStore_CreateFile(filename, password, subject, -1, 32); + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, -1, 32); assertFalse(result, "Expected false result from parcPkcs12KeyStore_CreateFile()"); unlink(filename); @@ -170,7 +170,7 @@ LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetCertificateDigest) const char *subject = "alice"; bool result; - result = parcPkcs12KeyStore_CreateFile(filename, password, subject, 1024, 32); + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32); assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); @@ -199,7 +199,7 @@ LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetPublicKeyDigest) const char *subject = "alice"; bool result; - result = parcPkcs12KeyStore_CreateFile(filename, password, subject, 1024, 32); + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32); assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); @@ -225,7 +225,7 @@ LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedCertificate) const char *subject = "alice"; bool result; - result = parcPkcs12KeyStore_CreateFile(filename, password, subject, 1024, 32); + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32); assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); @@ -255,7 +255,7 @@ LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedPublicKey) const char *subject = "alice"; bool result; - result = parcPkcs12KeyStore_CreateFile(filename, password, subject, 1024, 32); + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32); assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); @@ -310,10 +310,10 @@ LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetPublicKeyDigest) PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *PublicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); parcKeyStore_Release(&keyStore); - PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); - parcPublicKeySigner_Release(&publicKeySigner); + PARCSigner *signer = parcSigner_Create(PublicKeySigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&PublicKeySigner); assertNotNull(signer, "parcPkcs12KeyStore_Open(\"test_rsa.p12\", \"blueberry\", PARCCryptoHashType_SHA256) returned NULL"); @@ -351,10 +351,10 @@ LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetCertificateDigest) PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *PublicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); parcKeyStore_Release(&keyStore); - PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); - parcPublicKeySigner_Release(&publicKeySigner); + PARCSigner *signer = parcSigner_Create(PublicKeySigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&PublicKeySigner); assertNotNull(signer, "Got null result from opening openssl pkcs12 file"); @@ -387,10 +387,10 @@ LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedCertificate) PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *PublicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); parcKeyStore_Release(&keyStore); - PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); - parcPublicKeySigner_Release(&publicKeySigner); + PARCSigner *signer = parcSigner_Create(PublicKeySigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&PublicKeySigner); assertNotNull(signer, "Got null result from opening openssl pkcs12 file"); @@ -427,10 +427,10 @@ LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedPublicKey) PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *PublicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); parcKeyStore_Release(&keyStore); - PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); - parcPublicKeySigner_Release(&publicKeySigner); + PARCSigner *signer = parcSigner_Create(PublicKeySigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&PublicKeySigner); assertNotNull(signer, "Got null result from opening openssl pkcs12 file"); diff --git a/libparc/parc/security/test/test_parc_Pkcs12KeyStoreECDSA.c b/libparc/parc/security/test/test_parc_Pkcs12KeyStoreECDSA.c new file mode 100644 index 00000000..f6b19593 --- /dev/null +++ b/libparc/parc/security/test/test_parc_Pkcs12KeyStoreECDSA.c @@ -0,0 +1,470 @@ +/* + * 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. + */ + + +/** + */ +#include + +#include + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../parc_Pkcs12KeyStore.c" + +#include +#include +#include + +const char *filename = "/tmp/filekeystore.p12"; + +LONGBOW_TEST_RUNNER(ccnx_FileKeystore) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(openssl_commandline); + LONGBOW_RUN_TEST_FIXTURE(ccnx_internal); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnx_FileKeystore) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_FileKeystore) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_Open); + LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_badpass); + LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_CreateAndOpen); + LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_CreateFile_Fail); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + parcSecurity_Init(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + unlink(filename); + parcSecurity_Fini(); + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_Open) +{ + // open our test p12 file created with openssl + parcSecurity_Init(); + + PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + + assertNotNull(keyStore, "Got null result from opening openssl pkcs12 file"); + + parcPkcs12KeyStore_Release(&keyStore); + parcSecurity_Fini(); +} + +LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_badpass) +{ + // open our test p12 file created with openssl + + fprintf(stderr, "The next openssl error is expected, we're using the wrong password\n"); + PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open("test_ec.p12", "orange", PARCCryptoHashType_SHA256); + + assertNull(keyStore, "Got null result from opening openssl pkcs12 file"); +} + +LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_CreateAndOpen) +{ + // create a file and open it + const char *filename = "/tmp/parcPkcs12KeyStore_CreateAndOpen.p12"; + const char *password = "12345"; + const char *subject = "alice"; + bool result; + + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32); + assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); + + PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); + + assertNotNull(keyStore, "Got null result from opening openssl pkcs12 file"); + + parcPkcs12KeyStore_Release(&keyStore); + unlink(filename); +} + +LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_CreateFile_Fail) +{ + // create a file and open it + const char *filename = "/tmp/parcPkcs12KeyStore_CreateAndOpen.p12"; + const char *password = "12345"; + const char *subject = "alice"; + bool result; + + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, -1, 32); + assertFalse(result, "Expected false result from parcPkcs12KeyStore_CreateFile()"); + + unlink(filename); +} + + +// ===================================================== +// These are tests based on internally-generated pkcs12 + +LONGBOW_TEST_FIXTURE(ccnx_internal) +{ + LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetCertificateDigest); + LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetPublicKeyDigest); + LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedCertificate); + LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedPublicKey); +} + +LONGBOW_TEST_FIXTURE_SETUP(ccnx_internal) +{ + parcSecurity_Init(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ccnx_internal) +{ + unlink(filename); + parcSecurity_Fini(); + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetCertificateDigest) +{ + // create a file and open it + const char *password = "12345"; + const char *subject = "alice"; + bool result; + + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32); + assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); + + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); + assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file"); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCCryptoHash *cert_digest = parcKeyStore_GetCertificateDigest(keyStore); + assertNotNull(cert_digest, "got null public key digest for external pkcs12"); + + size_t bb_length = parcBuffer_Remaining(parcCryptoHash_GetDigest(cert_digest)); + assertTrue(bb_length == SHA256_DIGEST_LENGTH, + "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length); + + parcKeyStore_Release(&keyStore); + parcCryptoHash_Release(&cert_digest); +} + +/** + * Use a ccnx-generated pkcs12 file + */ +LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetPublicKeyDigest) +{ + // create a file and open it + const char *password = "12345"; + const char *subject = "alice"; + bool result; + + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32); + assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); + + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); + assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file"); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCCryptoHash *pkd = parcKeyStore_GetVerifierKeyDigest(keyStore); + assertNotNull(pkd, "got null public key digest for external pkcs12"); + + size_t bb_length = parcBuffer_Remaining(parcCryptoHash_GetDigest(pkd)); + assertTrue(bb_length == SHA256_DIGEST_LENGTH, "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length); + + parcKeyStore_Release(&keyStore); + parcCryptoHash_Release(&pkd); +} + + +LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedCertificate) +{ + // create a file and open it + const char *password = "12345"; + const char *subject = "alice"; + bool result; + + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32); + assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); + + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); + assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file"); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCBuffer *certificate_der = parcKeyStore_GetDEREncodedCertificate(keyStore); + assertNotNull(certificate_der, "got null public key digest for external pkcs12"); + + // 557 (64-bit) and 553 (32-bit) are pre-etermined sizes of how big a DER encoded + // certificate with a 1024-bit key should be + size_t expectedMinimumLength = 400; + size_t expectedMaximumLength = 560; + size_t bb_length = parcBuffer_Remaining(certificate_der); + assertTrue(expectedMinimumLength <= bb_length && bb_length <= expectedMaximumLength, + "Digest unexpected size: got %zu expected %zu - %zu", bb_length, expectedMinimumLength, expectedMaximumLength); + + parcKeyStore_Release(&keyStore); + parcBuffer_Release(&certificate_der); +} + +LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedPublicKey) +{ + // create a file and open it + const char *password = "12345"; + const char *subject = "alice"; + bool result; + + result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32); + assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File"); + + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); + assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file"); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCBuffer *pubkey_der = parcKeyStore_GetDEREncodedPublicKey(keyStore); + assertNotNull(pubkey_der, "got null public key digest for external pkcs12"); + + size_t bb_length = parcBuffer_Remaining(pubkey_der); + //assertTrue(bb_length == 162, "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length); + + parcKeyStore_Release(&keyStore); + parcBuffer_Release(&pubkey_der); +} + +// ===================================================== +// These are tests based on pre-generated material from the openssl command line + +LONGBOW_TEST_FIXTURE(openssl_commandline) +{ + LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetCertificateDigest); + LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetPublicKeyDigest); + LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedCertificate); + LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedPublicKey); +} + +LONGBOW_TEST_FIXTURE_SETUP(openssl_commandline) +{ + parcSecurity_Init(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(openssl_commandline) +{ + unlink(filename); + parcSecurity_Fini(); + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/** + * read in the openssl command-line generated pkcs12 file + */ +LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetPublicKeyDigest) +{ + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + parcKeyStore_Release(&keyStore); + PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + + assertNotNull(signer, "parcPkcs12KeyStore_Open(\"test_ec.p12\", \"blueberry\", PARCCryptoHashType_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_ec_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_ec_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); +} + +/** + * Get the certificate digest from the openssl command line pkcs12 + */ +LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetCertificateDigest) +{ + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + parcKeyStore_Release(&keyStore); + PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + + assertNotNull(signer, "Got null result from opening openssl pkcs12 file"); + + PARCCryptoHash *cert_digest = parcKeyStore_GetCertificateDigest(parcSigner_GetKeyStore(signer)); + assertNotNull(cert_digest, "got null public key digest for external pkcs12"); + + // read in the "truth" from the command line utilities + + int fd = open("test_ec_crt_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_ec_pub_sha256.bin", SHA256_DIGEST_LENGTH); + + const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(parcCryptoHash_GetDigest(cert_digest))); + size_t bb_length = parcBuffer_Remaining(parcCryptoHash_GetDigest(cert_digest)); + assertTrue(bb_length == SHA256_DIGEST_LENGTH, + "Incorrect digest length returned from GetCertificateDigest: %zu", bb_length); + + assertTrue(memcmp(bb_buffer, true_digest, SHA256_DIGEST_LENGTH) == 0, "digests did not match"); + + parcSigner_Release(&signer); + parcCryptoHash_Release(&cert_digest); +} + +LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedCertificate) +{ + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + parcKeyStore_Release(&keyStore); + PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + + assertNotNull(signer, "Got null result from opening openssl pkcs12 file"); + + PARCBuffer *certificate_der = parcKeyStore_GetDEREncodedCertificate(parcSigner_GetKeyStore(signer)); + assertNotNull(certificate_der, "got null der certificate for external pkcs12"); + + // read in the "truth" from the command line utilities + + int fd = open("test_ec_crt.der", O_RDONLY); + uint8_t true_der[1024]; + ssize_t read_bytes = read(fd, true_der, 1024); + close(fd); + + // assertTrue(read_bytes == 517, + // "could not read %d byte digest from test_ec_pub_sha256.bin", 517); + + const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(certificate_der)); + size_t bb_length = parcBuffer_Remaining(certificate_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(&certificate_der); +} + +/** + * Gets the DER encoded public key + */ +LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedPublicKey) +{ + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + parcKeyStore_Release(&keyStore); + PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + + 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_ec_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_ec_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); +} + +LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_VerifySignature_Cert) +{ + testUnimplemented("Not Implemented"); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_FileKeystore); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/security/test/test_parc_PublicKeyECSigner.c b/libparc/parc/security/test/test_parc_PublicKeyECSigner.c new file mode 100644 index 00000000..417282a0 --- /dev/null +++ b/libparc/parc/security/test/test_parc_PublicKeyECSigner.c @@ -0,0 +1,495 @@ +/* + * 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. + */ + +/** + */ +#include "../parc_PublicKeySigner.c" +#include "../parc_InMemoryVerifier.c" +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +typedef struct test_data { + PARCSigner *signer; + PARCInMemoryVerifier *inMemoryInterface; +} TestData; + + +LONGBOW_TEST_RUNNER(parc_PublicKeySigner) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease); + LONGBOW_RUN_TEST_FIXTURE(Object); + LONGBOW_RUN_TEST_FIXTURE(Specialization); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_PublicKeySigner) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_PublicKeySigner) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateAcquireRelease) +{ + LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + parcSecurity_Init(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease) +{ + parcSecurity_Fini(); + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease) +{ + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *instance = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + parcKeyStore_Release(&keyStore); + assertNotNull(instance, "Expected non-null result from parcPublicKeySigner_Create();"); + + parcObjectTesting_AssertAcquireReleaseContract(parcPublicKeySigner_Acquire, instance); + + parcPublicKeySigner_Release(&instance); + assertNull(instance, "Expected null result from parcPublicKeySigner_Release();"); +} + +LONGBOW_TEST_FIXTURE(Object) +{ + LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_Equals); + LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_HashCode); + LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_IsValid); + LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Object) +{ + parcSecurity_Init(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Object) +{ + parcSecurity_Fini(); + if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) { + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +static PARCPublicKeySigner * +_createSigner(char *path) +{ + char dirname[] = "/tmp/pubkeystore_XXXXXX"; + char filename[MAXPATHLEN]; + + char *temporaryDirectory = mkdtemp(dirname); + assertNotNull(temporaryDirectory, "tmp_dirname should not be null"); + sprintf(filename, "%s/%s", temporaryDirectory, path); + + parcPkcs12KeyStore_CreateFile(filename, "blueberry", "person", PARCSigningAlgorithm_ECDSA, 256, 365); + PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(filename, "blueberry", PARCCryptoHashType_SHA256); + PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&keyStore); + PARCPublicKeySigner *pksigner = parcPublicKeySigner_Create(publicKeyStore, PARCCryptoSuite_ECDSA_SHA256); + parcKeyStore_Release(&publicKeyStore); + + return pksigner; +} + +LONGBOW_TEST_CASE(Object, parcPublicKeySigner_Equals) +{ + PARCPublicKeySigner *x = _createSigner("bananasA"); + PARCPublicKeySigner *y = _createSigner("bananasB"); + PARCPublicKeySigner *z = _createSigner("bananasC"); + + parcObjectTesting_AssertEquals(x, y, z, NULL); + + parcPublicKeySigner_Release(&x); + parcPublicKeySigner_Release(&y); + parcPublicKeySigner_Release(&z); +} + +LONGBOW_TEST_CASE(Object, parcPublicKeySigner_HashCode) +{ + PARCPublicKeySigner *x = _createSigner("bananasX"); + PARCPublicKeySigner *y = _createSigner("bananasY"); + + parcObjectTesting_AssertHashCode(x, y); + + parcPublicKeySigner_Release(&x); + parcPublicKeySigner_Release(&y); +} + +LONGBOW_TEST_CASE(Object, parcPublicKeySigner_IsValid) +{ + PARCPublicKeySigner *instance = _createSigner("bananas"); + assertTrue(parcPublicKeySigner_IsValid(instance), "Expected parcPublicKeySigner_Create to result in a valid instance."); + + parcPublicKeySigner_Release(&instance); + assertFalse(parcPublicKeySigner_IsValid(instance), "Expected parcPublicKeySigner_Release to result in an invalid instance."); +} + +LONGBOW_TEST_CASE(Object, parcPublicKeySigner_ToString) +{ + PARCPublicKeySigner *instance = _createSigner("bananas"); + + char *string = parcPublicKeySigner_ToString(instance); + + assertNotNull(string, "Expected non-NULL result from parcPublicKeySigner_ToString"); + + parcMemory_Deallocate((void **) &string); + parcPublicKeySigner_Release(&instance); +} + +LONGBOW_TEST_FIXTURE(Specialization) +{ + LONGBOW_RUN_TEST_CASE(Specialization, parcPkcs12KeyStore_VerifySignature_Cert); + LONGBOW_RUN_TEST_CASE(Specialization, parcPkcs12KeyStore_SignBuffer); +} + +LONGBOW_TEST_FIXTURE_SETUP(Specialization) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + parcSecurity_Init(); + + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + parcKeyStore_Release(&keyStore); + + data->signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + assertNotNull(data->signer, "Got null result from opening openssl pkcs12 file"); + + data->inMemoryInterface = parcInMemoryVerifier_Create(); + + longBowTestCase_SetClipBoardData(testCase, data); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + parcInMemoryVerifier_Release(&data->inMemoryInterface); + parcSigner_Release(&data->signer); + parcMemory_Deallocate((void **) &data); + + parcSecurity_Fini(); + + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Specialization, parcPkcs12KeyStore_VerifySignature_Cert) +{ +} + +/** + * Sign the file "test_rsa_pub_sha256.bin" using the test_rsa.p12 private key. + */ +LONGBOW_TEST_CASE(Specialization, parcPkcs12KeyStore_SignBuffer) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file"); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + parcKeyStore_Release(&keyStore); + PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + + PARCKey *key = parcSigner_CreatePublicKey(data->signer); + _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key); + + assertNotNull(signer, "Got null result from opening openssl pkcs12 file"); + + // read the buffer to sign + int fd = open("test_random_bytes", O_RDONLY); + assertTrue(fd != -1, "Cannot open test_random_bytes file."); + uint8_t buffer_to_sign[2048]; + ssize_t read_bytes = read(fd, buffer_to_sign, 2048); + close(fd); + + assertTrue(read_bytes > 0, + "Buffer to sign null: %zu", + read_bytes); + + // Digest it + PARCCryptoHasher *digester = parcSigner_GetCryptoHasher(signer); + parcCryptoHasher_Init(digester); + parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes); + PARCCryptoHash *parcDigest = parcCryptoHasher_Finalize(digester); + + assertTrue(parcBuffer_Remaining(parcCryptoHash_GetDigest(parcDigest)) >0, + "Incorrect signaturedigest size: %zu", + parcBuffer_Remaining(parcCryptoHash_GetDigest(parcDigest))); + + + PARCSignature *bb_test_sign = parcSigner_SignDigest(signer, parcDigest); + + assertNotNull(bb_test_sign, "Got null byte buffer from SignBuffer"); + assertTrue(parcBuffer_Remaining(parcSignature_GetSignature(bb_test_sign)) <= 72, + "Incorrect signature size: %zu", + parcBuffer_Remaining(parcSignature_GetSignature(bb_test_sign))); + + bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), parcDigest, PARCCryptoSuite_ECDSA_SHA256, bb_test_sign); + + parcSigner_Release(&signer); + parcSignature_Release(&bb_test_sign); + parcCryptoHash_Release(&parcDigest); + parcKey_Release(&key); + + assertTrue(success, "signatures did not match"); +} + +LONGBOW_TEST_CASE(Global, parcSigner_GetCertificateDigest) +{ + char dirname[] = "pubkeystore_XXXXXX"; + char filename[MAXPATHLEN]; + const char *password = "flumox"; + unsigned key_bits = 256; + unsigned valid_days = 30; + + const char to_sign[] = "it was a dark and stormy night, and all through the house not a digest was creeping"; + + char *tmp_dirname = mkdtemp(dirname); + assertNotNull(tmp_dirname, "tmp_dirname should not be null"); + sprintf(filename, "%s/pubkeystore.p12", tmp_dirname); + + // create the file + parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_ECDSA, key_bits, valid_days); + + // open it as an RSA provider for the signer + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + + PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer); + parcCryptoHasher_Init(hasher); + parcCryptoHasher_UpdateBytes(hasher, to_sign, sizeof(to_sign)); + PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher); + PARCSignature *sig = parcSigner_SignDigest(signer, hash); + + unlink(filename); + int rc = rmdir(tmp_dirname); + assertTrue(rc == 0, "directory cleanup failed"); + + char *s = parcSignature_ToString(sig); + printf("Signature: %s\n", s); + parcMemory_Deallocate((void **) &s); + + PARCCryptoHash *certDigest = parcKeyStore_GetCertificateDigest(parcSigner_GetKeyStore(signer)); + assertNotNull(certDigest, "Expected a non NULL value"); + parcCryptoHash_Release(&certDigest); + + parcKeyStore_Release(&keyStore); + parcCryptoHash_Release(&hash); + parcSignature_Release(&sig); + parcSigner_Release(&signer); +} + +LONGBOW_TEST_CASE(Global, parcSigner_GetDEREncodedCertificate) +{ + char dirname[] = "pubkeystore_XXXXXX"; + char filename[MAXPATHLEN]; + const char *password = "flumox"; + unsigned key_bits = 256; + unsigned valid_days = 30; + + const char to_sign[] = "it was a dark and stormy night, and all through the house not a digest was creeping"; + + char *tmp_dirname = mkdtemp(dirname); + assertNotNull(tmp_dirname, "tmp_dirname should not be null"); + sprintf(filename, "%s/pubkeystore.p12", tmp_dirname); + + // create the file + parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_ECDSA, key_bits, valid_days); + + // open it as an RSA provider for the signer + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + + PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer); + parcCryptoHasher_Init(hasher); + parcCryptoHasher_UpdateBytes(hasher, to_sign, sizeof(to_sign)); + PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher); + PARCSignature *sig = parcSigner_SignDigest(signer, hash); + + unlink(filename); + int rc = rmdir(tmp_dirname); + assertTrue(rc == 0, "directory cleanup failed"); + + char *s = parcSignature_ToString(sig); + printf("Signature: %s\n", s); + parcMemory_Deallocate((void **) &s); + + PARCBuffer *certificate_der = parcKeyStore_GetDEREncodedCertificate(parcSigner_GetKeyStore(signer)); + assertNotNull(certificate_der, "Expected a non NULL value"); + parcBuffer_Release(&certificate_der); + + parcKeyStore_Release(&keyStore); + parcCryptoHash_Release(&hash); + parcSignature_Release(&sig); + parcSigner_Release(&signer); +} + +LONGBOW_TEST_CASE(Global, parcSigner_CreatePublicKey) +{ + char dirname[] = "pubkeystore_XXXXXX"; + char filename[MAXPATHLEN]; + const char *password = "flumox"; + unsigned key_bits = 256; + unsigned valid_days = 30; + + char *tmp_dirname = mkdtemp(dirname); + assertNotNull(tmp_dirname, "tmp_dirname should not be null"); + sprintf(filename, "%s/pubkeystore.p12", tmp_dirname); + + // create the file + parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_ECDSA, key_bits, valid_days); + + // open it as an RSA provider for the signer + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + + PARCKey *key = parcSigner_CreatePublicKey(signer); + assertNotNull(key, "Expected a non NULL value"); + parcKey_Release(&key); + parcKeyStore_Release(&keyStore); + + parcSigner_Release(&signer); +} + +LONGBOW_TEST_CASE(Global, parcSigner_CreateKeyId) +{ + char dirname[] = "pubkeystore_XXXXXX"; + char filename[MAXPATHLEN]; + const char *password = "flumox"; + unsigned key_bits = 256; + unsigned valid_days = 30; + + const char to_sign[] = "it was a dark and stormy night, and all through the house not a digest was creeping"; + + char *tmp_dirname = mkdtemp(dirname); + assertNotNull(tmp_dirname, "tmp_dirname should not be null"); + sprintf(filename, "%s/pubkeystore.p12", tmp_dirname); + + // create the file + parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_ECDSA, key_bits, valid_days); + + // open it as an RSA provider for the signer + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); + PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256); + PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner); + parcPublicKeySigner_Release(&ecSigner); + + PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer); + parcCryptoHasher_Init(hasher); + parcCryptoHasher_UpdateBytes(hasher, to_sign, sizeof(to_sign)); + PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher); + PARCSignature *sig = parcSigner_SignDigest(signer, hash); + + unlink(filename); + int rc = rmdir(tmp_dirname); + assertTrue(rc == 0, "directory cleanup failed"); + + char *s = parcSignature_ToString(sig); + printf("Signature: %s\n", s); + parcMemory_Deallocate((void **) &s); + + PARCKeyId *keyId = parcSigner_CreateKeyId(signer); + assertNotNull(keyId, "Expected a non NULL value"); + parcKeyId_Release(&keyId); + + parcKeyStore_Release(&keyStore); + parcCryptoHash_Release(&hash); + parcSignature_Release(&sig); + parcSigner_Release(&signer); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_PublicKeySigner); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/security/test/test_parc_PublicKeySigner.c b/libparc/parc/security/test/test_parc_PublicKeySigner.c index 0af1aca8..49fd42c7 100644 --- a/libparc/parc/security/test/test_parc_PublicKeySigner.c +++ b/libparc/parc/security/test/test_parc_PublicKeySigner.c @@ -81,7 +81,7 @@ LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease) PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *instance = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *instance = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); parcKeyStore_Release(&keyStore); assertNotNull(instance, "Expected non-null result from parcPublicKeySigner_Create();"); @@ -125,11 +125,11 @@ _createSigner(char *path) assertNotNull(temporaryDirectory, "tmp_dirname should not be null"); sprintf(filename, "%s/%s", temporaryDirectory, path); - parcPkcs12KeyStore_CreateFile(filename, "blueberry", "person", 1024, 365); + parcPkcs12KeyStore_CreateFile(filename, "blueberry", "person", PARCSigningAlgorithm_RSA, 1024, 365); PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(filename, "blueberry", PARCCryptoHashType_SHA256); PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&keyStore); - PARCPublicKeySigner *pksigner = parcPublicKeySigner_Create(publicKeyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *pksigner = parcPublicKeySigner_Create(publicKeyStore, PARCCryptoSuite_RSA_SHA256); parcKeyStore_Release(&publicKeyStore); return pksigner; @@ -216,7 +216,7 @@ LONGBOW_TEST_CASE(Specialization, parcPkcs12KeyStore_SignBuffer) PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); parcKeyStore_Release(&keyStore); PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); parcPublicKeySigner_Release(&publicKeySigner); @@ -276,14 +276,14 @@ LONGBOW_TEST_CASE(Global, parcSigner_GetCertificateDigest) sprintf(filename, "%s/pubkeystore.p12", tmp_dirname); // create the file - parcPkcs12KeyStore_CreateFile(filename, password, "alice", key_bits, valid_days); + parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_RSA, key_bits, valid_days); // open it as an RSA provider for the signer PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); parcPublicKeySigner_Release(&publicKeySigner); @@ -326,14 +326,14 @@ LONGBOW_TEST_CASE(Global, parcSigner_GetDEREncodedCertificate) sprintf(filename, "%s/pubkeystore.p12", tmp_dirname); // create the file - parcPkcs12KeyStore_CreateFile(filename, password, "alice", key_bits, valid_days); + parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_RSA, key_bits, valid_days); // open it as an RSA provider for the signer PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); parcPublicKeySigner_Release(&publicKeySigner); @@ -374,14 +374,14 @@ LONGBOW_TEST_CASE(Global, parcSigner_CreatePublicKey) sprintf(filename, "%s/pubkeystore.p12", tmp_dirname); // create the file - parcPkcs12KeyStore_CreateFile(filename, password, "alice", key_bits, valid_days); + parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_RSA, key_bits, valid_days); // open it as an RSA provider for the signer PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); parcPublicKeySigner_Release(&publicKeySigner); @@ -408,14 +408,14 @@ LONGBOW_TEST_CASE(Global, parcSigner_CreateKeyId) sprintf(filename, "%s/pubkeystore.p12", tmp_dirname); // create the file - parcPkcs12KeyStore_CreateFile(filename, password, "alice", key_bits, valid_days); + parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_RSA, key_bits, valid_days); // open it as an RSA provider for the signer PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256); PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); parcPkcs12KeyStore_Release(&publicKeyStore); - PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256); + PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256); PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner); parcPublicKeySigner_Release(&publicKeySigner); diff --git a/libparc/parc/security/test/test_parc_Signature.c b/libparc/parc/security/test/test_parc_Signature.c index 9f54da37..4c57d5a9 100755 --- a/libparc/parc/security/test/test_parc_Signature.c +++ b/libparc/parc/security/test/test_parc_Signature.c @@ -73,7 +73,7 @@ LONGBOW_TEST_FIXTURE_TEARDOWN(Global) LONGBOW_TEST_CASE(Global, parcSignature_Create) { PARCBuffer *bits = parcBuffer_Allocate(10); // arbitrary buffer size -- not important - PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_DSA, PARCCryptoHashType_SHA256, bits); + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits); parcBuffer_Release(&bits); assertNotNull(signature, "Expected non-NULL PARCSignature"); @@ -88,7 +88,7 @@ LONGBOW_TEST_CASE(Global, parcSignature_Create) LONGBOW_TEST_CASE(Global, parcSignature_Acquire) { PARCBuffer *bits = parcBuffer_Allocate(10); // arbitrary buffer size -- not important - PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_DSA, PARCCryptoHashType_SHA256, bits); + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits); PARCSignature *handle = parcSignature_Acquire(signature); parcBuffer_Release(&bits); @@ -106,7 +106,7 @@ LONGBOW_TEST_CASE(Global, parcSignature_Acquire) LONGBOW_TEST_CASE(Global, parcSignature_Release) { PARCBuffer *bits = parcBuffer_Allocate(10); // arbitrary bufer size -- not important - PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_DSA, PARCCryptoHashType_SHA256, bits); + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits); PARCSignature *handle = parcSignature_Acquire(signature); parcBuffer_Release(&bits); @@ -129,12 +129,12 @@ LONGBOW_TEST_CASE(Global, parcSignature_Equals) PARCBuffer *otherBits = parcBuffer_Allocate(strlen("hello")); parcBuffer_PutArray(otherBits, strlen("hello"), (uint8_t *) "hello"); - PARCSignature *x = parcSignature_Create(PARCSigningAlgorithm_DSA, PARCCryptoHashType_SHA256, bits); - PARCSignature *y = parcSignature_Create(PARCSigningAlgorithm_DSA, PARCCryptoHashType_SHA256, bits); - PARCSignature *z = parcSignature_Create(PARCSigningAlgorithm_DSA, PARCCryptoHashType_SHA256, bits); + PARCSignature *x = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits); + PARCSignature *y = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits); + PARCSignature *z = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits); PARCSignature *unequal1 = parcSignature_Create(PARCSigningAlgorithm_HMAC, PARCCryptoHashType_SHA256, bits); - PARCSignature *unequal2 = parcSignature_Create(PARCSigningAlgorithm_DSA, PARCCryptoHashType_CRC32C, bits); - PARCSignature *unequal3 = parcSignature_Create(PARCSigningAlgorithm_DSA, PARCCryptoHashType_SHA256, otherBits); + PARCSignature *unequal2 = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_CRC32C, bits); + PARCSignature *unequal3 = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, otherBits); parcObjectTesting_AssertEqualsFunction(parcSignature_Equals, x, y, z, unequal1, unequal2, unequal3, NULL); @@ -154,7 +154,7 @@ LONGBOW_TEST_CASE(Global, parcSignature_GetHashType) PARCBuffer *bits = parcBuffer_Allocate(strlen("Hello")); parcBuffer_PutArray(bits, strlen("Hello"), (uint8_t *) "Hello"); PARCCryptoHashType expected = PARCCryptoHashType_SHA256; - PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_DSA, expected, bits); + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, expected, bits); parcBuffer_Release(&bits); PARCCryptoHashType actual = parcSignature_GetHashType(signature); @@ -167,7 +167,7 @@ LONGBOW_TEST_CASE(Global, parcSignature_GetSignature) { PARCBuffer *expected = parcBuffer_Allocate(strlen("Hello")); parcBuffer_PutArray(expected, strlen("Hello"), (uint8_t *) "Hello"); - PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_DSA, PARCCryptoHashType_SHA256, expected); + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, expected); PARCBuffer *actual = parcSignature_GetSignature(signature); @@ -180,7 +180,7 @@ LONGBOW_TEST_CASE(Global, parcSignature_GetSigningAlgorithm) { PARCBuffer *signatureBits = parcBuffer_Allocate(strlen("Hello")); parcBuffer_PutArray(signatureBits, strlen("Hello"), (uint8_t *) "Hello"); - PARCSigningAlgorithm expected = PARCSigningAlgorithm_DSA; + PARCSigningAlgorithm expected = PARCSigningAlgorithm_ECDSA; PARCSignature *signature = parcSignature_Create(expected, PARCCryptoHashType_SHA256, signatureBits); PARCSigningAlgorithm actual = parcSignature_GetSigningAlgorithm(signature); @@ -194,7 +194,7 @@ LONGBOW_TEST_CASE(Global, parcSignature_ToString) { PARCBuffer *signatureBits = parcBuffer_Allocate(strlen("Hello")); parcBuffer_PutArray(signatureBits, strlen("Hello"), (uint8_t *) "Hello"); - PARCSigningAlgorithm expected = PARCSigningAlgorithm_DSA; + PARCSigningAlgorithm expected = PARCSigningAlgorithm_ECDSA; PARCSignature *signature = parcSignature_Create(expected, PARCCryptoHashType_SHA256, signatureBits); char *string = parcSignature_ToString(signature); diff --git a/libparc/parc/security/test/test_parc_SignerEC.c b/libparc/parc/security/test/test_parc_SignerEC.c new file mode 100644 index 00000000..2b6fc577 --- /dev/null +++ b/libparc/parc/security/test/test_parc_SignerEC.c @@ -0,0 +1,312 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#include "../parc_Signer.c" + +#include +#include +#include + +#include +#include +#include +#include + +#define FAKE_SIGNATURE "signature" + +typedef struct { + PARCCryptoHasher *hasher; + PARCKeyStore *keyStore; +} _MockSigner; + +static PARCSignature * +_SignDigest(PARCSigner *interfaceContext) +{ + PARCBuffer *buffer = parcBuffer_WrapCString(FAKE_SIGNATURE); + PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, buffer); + parcBuffer_Release(&buffer); + return signature; +} + +static PARCSigningAlgorithm +_GetSigningAlgorithm(PARCSigner *interfaceContext) +{ + return PARCSigningAlgorithm_ECDSA; +} + +static PARCCryptoHashType +_GetCryptoHashType(PARCSigner *signer) +{ + return PARCCryptoHashType_SHA256; +} + +static PARCCryptoHasher * +_GetCryptoHasher(_MockSigner *signer) +{ + return signer->hasher; +} + +static PARCKeyStore * +_GetKeyStore(_MockSigner *signer) +{ + return signer->keyStore; +} + +static bool +_releaseSigner(_MockSigner **signer) +{ + parcCryptoHasher_Release(&((*signer)->hasher)); + parcKeyStore_Release(&((*signer)->keyStore)); + return true; +} + +parcObject_ImplementAcquire(_mockSigner, _MockSigner); +parcObject_ImplementRelease(_mockSigner, _MockSigner); + +parcObject_Override(_MockSigner, PARCObject, + .destructor = (PARCObjectDestructor *) _releaseSigner); + +static _MockSigner * +_createSigner() +{ + const char *filename = "/tmp/test_ecdsa.p12"; + const char *password = "12345"; + const char *subject = "alice"; + _MockSigner *signer = parcObject_CreateInstance(_MockSigner); + + signer->hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256); + + bool res = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 180); + assertTrue(res, "Unable to create an ECDSA key"); + + PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256); + + assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file"); + + signer->keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore); + parcPkcs12KeyStore_Release(&publicKeyStore); + + return signer; +} + +static PARCSigningInterface *_MockSignerInterface = &(PARCSigningInterface) { + .GetCryptoHasher = (PARCCryptoHasher * (*)(void *))_GetCryptoHasher, + .SignDigest = (PARCSignature * (*)(void *, const PARCCryptoHash *))_SignDigest, + .GetSigningAlgorithm = (PARCSigningAlgorithm (*)(void *))_GetSigningAlgorithm, + .GetCryptoHashType = (PARCCryptoHashType (*)(void *))_GetCryptoHashType, + .GetKeyStore = (PARCKeyStore * (*)(void *))_GetKeyStore, +}; + +LONGBOW_TEST_RUNNER(parc_Signer) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(parc_Signer) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(parc_Signer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcSigner_Create); + LONGBOW_RUN_TEST_CASE(Global, parcSigner_AcquireRelease); + LONGBOW_RUN_TEST_CASE(Global, parcSigner_CreateKeyId); + LONGBOW_RUN_TEST_CASE(Global, parcSigner_CreatePublicKey); + LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetCryptoHasher); + LONGBOW_RUN_TEST_CASE(Global, parcSigner_SignDigest); + LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetSigningAlgorithm); + LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetCryptoHashType); + LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetKeyStore); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + parcSecurity_Init(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + parcSecurity_Fini(); + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, parcSigner_Create) +{ + _MockSigner *mock = _createSigner(); + PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface); + _mockSigner_Release(&mock); + + assertNotNull(signer, "Expected non-null signer"); + + parcSigner_Release(&signer); +} + +LONGBOW_TEST_CASE(Global, parcSigner_AcquireRelease) +{ + _MockSigner *mock = _createSigner(); + PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface); + _mockSigner_Release(&mock); + + assertNotNull(signer, "Expected non-null signer"); + + parcObjectTesting_AssertAcquireReleaseContract(parcSigner_Acquire, signer); + + parcSigner_Release(&signer); + assertNull(signer, "Expected null result from parcSigner_Release();"); +} + +LONGBOW_TEST_CASE(Global, parcSigner_CreateKeyId) +{ + _MockSigner *mock = _createSigner(); + PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface); + _mockSigner_Release(&mock); + + PARCKeyId *keyId = parcSigner_CreateKeyId(signer); + + assertNotNull(keyId, "Expected non-NULL PARCKeyId"); + + parcKeyId_Release(&keyId); + parcSigner_Release(&signer); +} + +LONGBOW_TEST_CASE(Global, parcSigner_CreatePublicKey) +{ + _MockSigner *mock = _createSigner(); + PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface); + + PARCKey *key = parcSigner_CreatePublicKey(signer); + + // Compute the real value + PARCCryptoHash *hash = parcKeyStore_GetVerifierKeyDigest(mock->keyStore); + PARCKeyId *keyid = parcKeyId_Create(parcCryptoHash_GetDigest(hash)); + PARCBuffer *derEncodedKey = parcKeyStore_GetDEREncodedPublicKey(mock->keyStore); + + PARCKey *expectedKey = parcKey_CreateFromDerEncodedPublicKey(keyid, + parcSigner_GetSigningAlgorithm(signer), + derEncodedKey); + + parcBuffer_Release(&derEncodedKey); + parcKeyId_Release(&keyid); + + parcCryptoHash_Release(&hash); + + assertTrue(parcKey_Equals(key, expectedKey), "Expected public keys to be computed equally."); + + parcKey_Release(&key); + parcKey_Release(&expectedKey); + parcSigner_Release(&signer); + _mockSigner_Release(&mock); +} + +LONGBOW_TEST_CASE(Global, parcSigner_GetCryptoHasher) +{ + _MockSigner *mock = _createSigner(); + PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface); + _mockSigner_Release(&mock); + + PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer); + + assertNotNull(hasher, "Expected non-NULL PARCCryptoHasher"); + + parcSigner_Release(&signer); +} + +LONGBOW_TEST_CASE(Global, parcSigner_SignDigest) +{ + _MockSigner *mock = _createSigner(); + PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface); + _mockSigner_Release(&mock); + + PARCBuffer *buffer = parcBuffer_Allocate(10); + PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer); + PARCSignature *signature = parcSigner_SignDigest(signer, hash); + + assertNotNull(signature, "Expected non-NULL PARCSignature"); + + PARCBuffer *bits = parcSignature_GetSignature(signature); + char *bitstring = parcBuffer_ToString(bits); + char *expectedString = FAKE_SIGNATURE; + assertTrue(strcmp(bitstring, expectedString) == 0, "Expected the forced signature as output %s, got %s", expectedString, bitstring); + parcMemory_Deallocate(&bitstring); + + parcCryptoHash_Release(&hash); + parcBuffer_Release(&buffer); + parcSignature_Release(&signature); + parcSigner_Release(&signer); +} + +LONGBOW_TEST_CASE(Global, parcSigner_GetSigningAlgorithm) +{ + _MockSigner *mock = _createSigner(); + PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface); + _mockSigner_Release(&mock); + + PARCSigningAlgorithm alg = parcSigner_GetSigningAlgorithm(signer); + assertTrue(PARCSigningAlgorithm_ECDSA == alg, "Expected PARCSigningAlgorithm_ECDSA algorithm, got %d", alg); + + parcSigner_Release(&signer); +} + +LONGBOW_TEST_CASE(Global, parcSigner_GetCryptoHashType) +{ + _MockSigner *mock = _createSigner(); + PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface); + _mockSigner_Release(&mock); + + PARCCryptoHashType type = parcSigner_GetCryptoHashType(signer); + assertTrue(PARCCryptoHashType_SHA256 == type, "Expected PARCCryptoHashType_SHA256 algorithm, got %d", type); + + parcSigner_Release(&signer); +} + +LONGBOW_TEST_CASE(Global, parcSigner_GetKeyStore) +{ + _MockSigner *mock = _createSigner(); + PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface); + _mockSigner_Release(&mock); + + PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer); + assertNotNull(keyStore, "Expected non-NULL PARCKeyStore"); + + parcSigner_Release(&signer); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Signer); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libparc/parc/security/test/test_parc_X509Certificate.c b/libparc/parc/security/test/test_parc_X509Certificate.c index 3ddb8220..dda9a9ff 100755 --- a/libparc/parc/security/test/test_parc_X509Certificate.c +++ b/libparc/parc/security/test/test_parc_X509Certificate.c @@ -53,6 +53,8 @@ LONGBOW_TEST_FIXTURE(Global) LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_GetCertificateDigest); LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_GetDEREncodedCertificate); LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_GetDEREncodedPublicKey); + LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_CreateSelfSignedCertificate_RSA); + LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_CreateSelfSignedCertificate_EC); } LONGBOW_TEST_FIXTURE_SETUP(Global) @@ -98,6 +100,24 @@ LONGBOW_TEST_CASE(Global, parc_X509Certificate_Create) assertNull(certificate, "Expected NULL certificate with non-existent file"); } +LONGBOW_TEST_CASE(Global, parc_X509Certificate_CreateSelfSignedCertificate_EC) +{ + PARCBuffer *privateKeyBuffer = NULL; + PARCX509Certificate *certificate = _createSelfSignedCertificate_EC(&privateKeyBuffer, "TEST", 256, 180); + assertNotNull(certificate, "Expected non-NULL EC certificate"); + parcBuffer_Release(&privateKeyBuffer); + parcX509Certificate_Release(&certificate); +} + +LONGBOW_TEST_CASE(Global, parc_X509Certificate_CreateSelfSignedCertificate_RSA) +{ + PARCBuffer *privateKeyBuffer = NULL; + PARCX509Certificate *certificate = _createSelfSignedCertificate_RSA(&privateKeyBuffer, "TEST", 1024, 180); + assertNotNull(certificate, "Expected non-NULL RSA certificate"); + parcBuffer_Release(&privateKeyBuffer); + parcX509Certificate_Release(&certificate); +} + LONGBOW_TEST_CASE(Global, parc_X509Certificate_CreateFromDERBuffer) { char *fileName = "test.pem"; diff --git a/libparc/parc/security/test/test_random_bytes.sig_ec b/libparc/parc/security/test/test_random_bytes.sig_ec new file mode 100644 index 00000000..92b210a1 Binary files /dev/null and b/libparc/parc/security/test/test_random_bytes.sig_ec differ -- cgit 1.2.3-korg