aboutsummaryrefslogtreecommitdiffstats
path: root/libparc/parc/security
diff options
context:
space:
mode:
Diffstat (limited to 'libparc/parc/security')
-rw-r--r--libparc/parc/security/.gitignore5
-rw-r--r--libparc/parc/security/command-line/.gitignore1
-rw-r--r--libparc/parc/security/command-line/CMakeLists.txt8
-rw-r--r--libparc/parc/security/command-line/parc-publickey.c127
-rw-r--r--libparc/parc/security/command-line/parcPublicKey_About.c44
-rwxr-xr-xlibparc/parc/security/command-line/parcPublicKey_About.h54
-rwxr-xr-xlibparc/parc/security/parc_Certificate.c135
-rwxr-xr-xlibparc/parc/security/parc_Certificate.h352
-rw-r--r--libparc/parc/security/parc_CertificateFactory.c97
-rwxr-xr-xlibparc/parc/security/parc_CertificateFactory.h166
-rwxr-xr-xlibparc/parc/security/parc_CertificateType.c55
-rwxr-xr-xlibparc/parc/security/parc_CertificateType.h65
-rwxr-xr-xlibparc/parc/security/parc_ContainerEncoding.c57
-rwxr-xr-xlibparc/parc/security/parc_ContainerEncoding.h67
-rwxr-xr-xlibparc/parc/security/parc_CryptoCache.c157
-rwxr-xr-xlibparc/parc/security/parc_CryptoCache.h94
-rwxr-xr-xlibparc/parc/security/parc_CryptoHash.c134
-rwxr-xr-xlibparc/parc/security/parc_CryptoHash.h234
-rw-r--r--libparc/parc/security/parc_CryptoHashType.c57
-rwxr-xr-xlibparc/parc/security/parc_CryptoHashType.h71
-rwxr-xr-xlibparc/parc/security/parc_CryptoHasher.c530
-rwxr-xr-xlibparc/parc/security/parc_CryptoHasher.h306
-rwxr-xr-xlibparc/parc/security/parc_CryptoSuite.c44
-rwxr-xr-xlibparc/parc/security/parc_CryptoSuite.h58
-rw-r--r--libparc/parc/security/parc_DiffieHellman.c55
-rw-r--r--libparc/parc/security/parc_DiffieHellman.h119
-rwxr-xr-xlibparc/parc/security/parc_DiffieHellmanGroup.h31
-rw-r--r--libparc/parc/security/parc_DiffieHellmanKeyShare.c297
-rw-r--r--libparc/parc/security/parc_DiffieHellmanKeyShare.h151
-rwxr-xr-xlibparc/parc/security/parc_Identity.c116
-rwxr-xr-xlibparc/parc/security/parc_Identity.h342
-rw-r--r--libparc/parc/security/parc_IdentityFile.c145
-rw-r--r--libparc/parc/security/parc_IdentityFile.h271
-rw-r--r--libparc/parc/security/parc_InMemoryVerifier.c315
-rwxr-xr-xlibparc/parc/security/parc_InMemoryVerifier.h88
-rwxr-xr-xlibparc/parc/security/parc_Key.c205
-rwxr-xr-xlibparc/parc/security/parc_Key.h325
-rwxr-xr-xlibparc/parc/security/parc_KeyId.c141
-rwxr-xr-xlibparc/parc/security/parc_KeyId.h348
-rwxr-xr-xlibparc/parc/security/parc_KeyStore.c104
-rwxr-xr-xlibparc/parc/security/parc_KeyStore.h348
-rw-r--r--libparc/parc/security/parc_Pkcs12KeyStore.c372
-rw-r--r--libparc/parc/security/parc_Pkcs12KeyStore.h134
-rw-r--r--libparc/parc/security/parc_PublicKeySigner.c228
-rw-r--r--libparc/parc/security/parc_PublicKeySigner.h341
-rw-r--r--libparc/parc/security/parc_SecureRandom.c123
-rw-r--r--libparc/parc/security/parc_SecureRandom.h189
-rw-r--r--libparc/parc/security/parc_Security.c210
-rwxr-xr-xlibparc/parc/security/parc_Security.h89
-rwxr-xr-xlibparc/parc/security/parc_Signature.c123
-rwxr-xr-xlibparc/parc/security/parc_Signature.h250
-rw-r--r--libparc/parc/security/parc_Signer.c160
-rwxr-xr-xlibparc/parc/security/parc_Signer.h368
-rwxr-xr-xlibparc/parc/security/parc_SigningAlgorithm.c81
-rw-r--r--libparc/parc/security/parc_SigningAlgorithm.h100
-rw-r--r--libparc/parc/security/parc_SymmetricKeySigner.c268
-rw-r--r--libparc/parc/security/parc_SymmetricKeySigner.h355
-rw-r--r--libparc/parc/security/parc_SymmetricKeyStore.c477
-rw-r--r--libparc/parc/security/parc_SymmetricKeyStore.h169
-rwxr-xr-xlibparc/parc/security/parc_Verifier.c107
-rw-r--r--libparc/parc/security/parc_Verifier.h271
-rw-r--r--libparc/parc/security/parc_X509Certificate.c516
-rwxr-xr-xlibparc/parc/security/parc_X509Certificate.h207
-rw-r--r--libparc/parc/security/test/.gitignore24
-rw-r--r--libparc/parc/security/test/CMakeLists.txt75
-rw-r--r--libparc/parc/security/test/README.digests12
-rw-r--r--libparc/parc/security/test/README.keystore35
-rw-r--r--libparc/parc/security/test/README.symmetric9
-rw-r--r--libparc/parc/security/test/test.crt.derbin0 -> 559 bytes
-rw-r--r--libparc/parc/security/test/test.crt.der.sha256.bin1
-rw-r--r--libparc/parc/security/test/test.derbin0 -> 162 bytes
-rw-r--r--libparc/parc/security/test/test.pem13
-rw-r--r--libparc/parc/security/test/test.pkcs12bin0 -> 1646 bytes
-rw-r--r--libparc/parc/security/test/test_crt.derbin0 -> 517 bytes
-rw-r--r--libparc/parc/security/test/test_crt_der.binbin0 -> 517 bytes
-rw-r--r--libparc/parc/security/test/test_crt_sha256.bin1
-rw-r--r--libparc/parc/security/test/test_der.binbin0 -> 162 bytes
-rw-r--r--libparc/parc/security/test/test_digest_bytes_128.bin1
-rw-r--r--libparc/parc/security/test/test_digest_bytes_128.sha2561
-rw-r--r--libparc/parc/security/test/test_digest_bytes_128.sha5121
-rw-r--r--libparc/parc/security/test/test_key.pem6
-rw-r--r--libparc/parc/security/test/test_parc_Certificate.c258
-rwxr-xr-xlibparc/parc/security/test/test_parc_CertificateFactory.c160
-rwxr-xr-xlibparc/parc/security/test/test_parc_CertificateType.c90
-rwxr-xr-xlibparc/parc/security/test/test_parc_ContainerEncoding.c90
-rwxr-xr-xlibparc/parc/security/test/test_parc_CryptoCache.c228
-rwxr-xr-xlibparc/parc/security/test/test_parc_CryptoHash.c184
-rw-r--r--libparc/parc/security/test/test_parc_CryptoHashType.c92
-rwxr-xr-xlibparc/parc/security/test/test_parc_CryptoHasher.c407
-rwxr-xr-xlibparc/parc/security/test/test_parc_CryptoSuite.c82
-rwxr-xr-xlibparc/parc/security/test/test_parc_DiffieHellman.c93
-rwxr-xr-xlibparc/parc/security/test/test_parc_DiffieHellmanKeyShare.c229
-rw-r--r--libparc/parc/security/test/test_parc_Identity.c232
-rw-r--r--libparc/parc/security/test/test_parc_IdentityFile.c242
-rwxr-xr-xlibparc/parc/security/test/test_parc_InMemoryVerifier.c417
-rwxr-xr-xlibparc/parc/security/test/test_parc_Key.c357
-rw-r--r--libparc/parc/security/test/test_parc_KeyId.c216
-rwxr-xr-xlibparc/parc/security/test/test_parc_KeyStore.c137
-rwxr-xr-xlibparc/parc/security/test/test_parc_Pkcs12KeyStore.c470
-rw-r--r--libparc/parc/security/test/test_parc_PublicKeySigner.c453
-rwxr-xr-xlibparc/parc/security/test/test_parc_SecureRandom.c241
-rwxr-xr-xlibparc/parc/security/test/test_parc_Security.c109
-rwxr-xr-xlibparc/parc/security/test/test_parc_Signature.c230
-rw-r--r--libparc/parc/security/test/test_parc_Signer.c305
-rwxr-xr-xlibparc/parc/security/test/test_parc_SigningAlgorithm.c125
-rw-r--r--libparc/parc/security/test/test_parc_SymmetricKeySigner.c247
-rwxr-xr-xlibparc/parc/security/test/test_parc_SymmetricKeyStore.c351
-rwxr-xr-xlibparc/parc/security/test/test_parc_Verifier.c121
-rwxr-xr-xlibparc/parc/security/test/test_parc_X509Certificate.c224
-rw-r--r--libparc/parc/security/test/test_pubkey.bin1
-rw-r--r--libparc/parc/security/test/test_pubkey.der6
-rw-r--r--libparc/parc/security/test/test_pubkey.pem6
-rw-r--r--libparc/parc/security/test/test_random_bytesbin0 -> 512 bytes
-rw-r--r--libparc/parc/security/test/test_random_bytes.hmac_sha256bin0 -> 32 bytes
-rw-r--r--libparc/parc/security/test/test_random_bytes.hmac_sha512bin0 -> 64 bytes
-rw-r--r--libparc/parc/security/test/test_random_bytes.sigbin0 -> 128 bytes
-rw-r--r--libparc/parc/security/test/test_rsa.crt13
-rw-r--r--libparc/parc/security/test/test_rsa.csr11
-rw-r--r--libparc/parc/security/test/test_rsa.p12bin0 -> 1598 bytes
-rw-r--r--libparc/parc/security/test/test_rsa_crt.derbin0 -> 517 bytes
-rw-r--r--libparc/parc/security/test/test_rsa_crt_sha256.bin2
-rw-r--r--libparc/parc/security/test/test_rsa_key.derbin0 -> 608 bytes
-rw-r--r--libparc/parc/security/test/test_rsa_key.pem15
-rw-r--r--libparc/parc/security/test/test_rsa_pub.derbin0 -> 162 bytes
-rw-r--r--libparc/parc/security/test/test_rsa_pub.pem6
-rw-r--r--libparc/parc/security/test/test_rsa_pub_sha256.bin1
-rw-r--r--libparc/parc/security/test/test_symmetric_key.binbin0 -> 32 bytes
-rw-r--r--libparc/parc/security/test/test_symmetric_key.sha2561
128 files changed, 18088 insertions, 0 deletions
diff --git a/libparc/parc/security/.gitignore b/libparc/parc/security/.gitignore
new file mode 100644
index 00000000..c0f8eeb0
--- /dev/null
+++ b/libparc/parc/security/.gitignore
@@ -0,0 +1,5 @@
+parc_LibraryVersion.c
+test/test_ccnx_FileKeystore
+test/test_ccnx_SelfSignedCertificate
+test/test_ccnx_Signature
+test/test_parc_CryptoHasher
diff --git a/libparc/parc/security/command-line/.gitignore b/libparc/parc/security/command-line/.gitignore
new file mode 100644
index 00000000..988c6e03
--- /dev/null
+++ b/libparc/parc/security/command-line/.gitignore
@@ -0,0 +1 @@
+parc_publickey
diff --git a/libparc/parc/security/command-line/CMakeLists.txt b/libparc/parc/security/command-line/CMakeLists.txt
new file mode 100644
index 00000000..df44b81f
--- /dev/null
+++ b/libparc/parc/security/command-line/CMakeLists.txt
@@ -0,0 +1,8 @@
+set(PARC_PUBLICKEY_SRC
+ parc-publickey.c
+ parcPublicKey_About.c
+ )
+
+add_executable(parc-publickey ${PARC_PUBLICKEY_SRC})
+target_link_libraries(parc-publickey ${PARC_BIN_LIBRARIES})
+install( TARGETS parc-publickey RUNTIME DESTINATION bin )
diff --git a/libparc/parc/security/command-line/parc-publickey.c b/libparc/parc/security/command-line/parc-publickey.c
new file mode 100644
index 00000000..30733113
--- /dev/null
+++ b/libparc/parc/security/command-line/parc-publickey.c
@@ -0,0 +1,127 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+void
+parcPublicKey_Create(PARCArrayList *args)
+{
+ unsigned int keyLength = 1024;
+ unsigned int validityDays = 30;
+
+ char *fileName = parcArrayList_Get(args, 2);
+ char *password = parcArrayList_Get(args, 3);
+ char *subjectName = parcArrayList_Get(args, 4);
+
+ if (parcArrayList_Size(args) > 5) {
+ keyLength = (unsigned int) strtoul(parcArrayList_Get(args, 5), NULL, 10);
+ }
+
+ if (parcArrayList_Size(args) > 6) {
+ validityDays = (unsigned int) strtoul(parcArrayList_Get(args, 6), NULL, 10);
+ }
+
+ bool result = parcPkcs12KeyStore_CreateFile(fileName, password, subjectName, keyLength, validityDays);
+ if (!result) {
+ printf("Error: %s %s", fileName, strerror(errno));
+ return;
+ }
+ printf("Created %s, key length %d valid for %d days.\n", fileName, keyLength, validityDays);
+}
+
+void
+parcPublicKey_Validate(PARCArrayList *args)
+{
+ char *fileName = parcArrayList_Get(args, 2);
+ char *password = parcArrayList_Get(args, 3);
+
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(fileName, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore);
+
+ PARCPublicKeySigner *signer = parcPublicKeySigner_Create(publicKeyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ PARCSigner *pkSigner = parcSigner_Create(signer, PARCPublicKeySignerAsSigner);
+
+ parcKeyStore_Release(&publicKeyStore);
+ parcPkcs12KeyStore_Release(&keyStore);
+
+ if (pkSigner == NULL) {
+ printf("Invalid %s\n", fileName);
+ return;
+ }
+ printf("Valid %s\n", fileName);
+}
+
+void
+printUsage(char *progName)
+{
+ printf("usage: %s [-h | --help] [[-c | --create] fileName password subjectName [keyLength validityDays] | [-v | --validate] fileName password]\n", progName);
+ printf("\n");
+ printf("\n");
+ printf("Create and validate PKCS12 keystores that are used with the CCNx code.\n");
+ printf("\n");
+ printf("optional arguments:\n");
+ printf("\t-h, --help\tShow this help message and exit\n");
+ printf("\t-c, --create\tCreate a PKCS12 keystore with the given filename, password, subject name, and optional key length and validity length (in days)\n");
+ printf("\n");
+ printf("\t\t\texample: ./parc_publickey -c keyfile.pkcs12 <password> <subject name> 1024 365\n");
+ printf("\n");
+ printf("\t-v, --validate\tValidate a PKCS12 file with the given password\n");
+ printf("\n");
+ printf("\t\t\texample: ./parc_publickey -v keyfile.pkcs12 <password>");
+ printf("\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *programName = "parc_publickey";
+ if (argc < 2) {
+ printUsage(programName);
+ exit(1);
+ }
+
+ PARCArrayList *args = parcArrayList_Create(NULL);
+ parcArrayList_AddAll(args, (void **) argv, argc);
+
+ parcSecurity_Init();
+
+ char *arg = parcArrayList_Get(args, 1);
+ if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
+ printUsage(programName);
+ return 0;
+ } else if (strcmp(arg, "-c") == 0 || strcmp(arg, "--create") == 0) {
+ parcPublicKey_Create(args);
+ } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "--validate") == 0) {
+ parcPublicKey_Validate(args);
+ } else {
+ printUsage(programName);
+ exit(1);
+ }
+
+ parcSecurity_Fini();
+ return 0;
+}
diff --git a/libparc/parc/security/command-line/parcPublicKey_About.c b/libparc/parc/security/command-line/parcPublicKey_About.c
new file mode 100644
index 00000000..6a242cf4
--- /dev/null
+++ b/libparc/parc/security/command-line/parcPublicKey_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170206.46e2c73a 2017-02-06T08:50:09Z
+
+#include "parcPublicKey_About.h"
+
+const char *parcPublicKey_What = "@(#)" "PARC public key " RELEASE_VERSION " 2017-02-15T13:31:10.603139"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+parcPublicKeyAbout_Name(void)
+{
+ return "PARC public key";
+}
+
+const char *
+parcPublicKeyAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+parcPublicKeyAbout_About(void)
+{
+ return "PARC public key "RELEASE_VERSION " 2017-02-15T13:31:10.603139" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+parcPublicKeyAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+parcPublicKeyAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+parcPublicKeyAbout_LongNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n";
+}
+
diff --git a/libparc/parc/security/command-line/parcPublicKey_About.h b/libparc/parc/security/command-line/parcPublicKey_About.h
new file mode 100755
index 00000000..64670ad8
--- /dev/null
+++ b/libparc/parc/security/command-line/parcPublicKey_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170206.46e2c73a 2017-02-06T08:50:09Z
+
+#ifndef parcPublicKey_About_h
+#define parcPublicKey_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *parcPublicKey_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *parcPublicKeyAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *parcPublicKeyAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *parcPublicKeyAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *parcPublicKeyAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *parcPublicKeyAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *parcPublicKeyAbout_LongNotice(void);
+
+#endif // parcPublicKey_About_h
diff --git a/libparc/parc/security/parc_Certificate.c b/libparc/parc/security/parc_Certificate.c
new file mode 100755
index 00000000..aead0fb5
--- /dev/null
+++ b/libparc/parc/security/parc_Certificate.c
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+/*
+ * parc_Certificate.c
+ * PARC Library
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+
+#include <parc/security/parc_Certificate.h>
+#include <parc/security/parc_CertificateType.h>
+#include <parc/security/parc_ContainerEncoding.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct parc_certificate {
+ PARCCertificateInterface *interface;
+ void *instance;
+};
+
+static void
+_parcCertificate_FinalRelease(PARCCertificate **certP)
+{
+ PARCCertificate *certificate = (PARCCertificate *) *certP;
+
+ if (certificate->instance != NULL) {
+ parcObject_Release(&certificate->instance);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCCertificate, _parcCertificate_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCCertificate *
+_parcCertificate_Create(PARCCertificateInterface *impl, void *instance)
+{
+ PARCCertificate *cert = parcObject_CreateInstance(PARCCertificate);
+ cert->interface = impl;
+ cert->instance = instance;
+ return cert;
+}
+
+parcObject_ImplementAcquire(parcCertificate, PARCCertificate);
+
+parcObject_ImplementRelease(parcCertificate, PARCCertificate);
+
+PARCCertificate *
+parcCertificate_CreateFromInstance(PARCCertificateInterface *impl, void *instance)
+{
+ return _parcCertificate_Create(impl, instance);
+}
+
+PARCCertificateType
+parcCertificate_GetCertificateType(const PARCCertificate *cert)
+{
+ if (cert->interface->GetCertificateType != NULL) {
+ return cert->interface->GetCertificateType(cert->instance);
+ }
+ return PARCCertificateType_Invalid;
+}
+
+PARCContainerEncoding
+parcCertificate_GetContainerEncoding(const PARCCertificate *cert)
+{
+ if (cert->interface->GetContainerEncoding != NULL) {
+ return cert->interface->GetContainerEncoding(cert->instance);
+ }
+ return PARCContainerEncoding_Invalid;
+}
+
+PARCCryptoHash *
+parcCertificate_GetPublicKeyDigest(const PARCCertificate *certificate)
+{
+ if (certificate->interface->GetPublicKeyDigest != NULL) {
+ return certificate->interface->GetPublicKeyDigest(certificate->instance);
+ }
+ return NULL;
+}
+
+PARCCryptoHash *
+parcCertificate_GetCertificateDigest(const PARCCertificate *certificate)
+{
+ if (certificate->interface->GetCertificateDigest != NULL) {
+ return certificate->interface->GetCertificateDigest(certificate->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcCertificate_GetDEREncodedCertificate(const PARCCertificate *certificate)
+{
+ if (certificate->interface->GetDEREncodedCertificate != NULL) {
+ return certificate->interface->GetDEREncodedCertificate(certificate->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcCertificate_GetDEREncodedPublicKey(const PARCCertificate *certificate)
+{
+ if (certificate->interface->GetDEREncodedPublicKey != NULL) {
+ return certificate->interface->GetDEREncodedPublicKey(certificate->instance);
+ }
+ return NULL;
+}
+
+PARCKey *
+parcCertificate_GetPublicKey(const PARCCertificate *certificate)
+{
+ PARCBuffer *derEncodedVersion = parcCertificate_GetDEREncodedPublicKey(certificate);
+ PARCCryptoHash *keyDigest = parcCertificate_GetPublicKeyDigest(certificate);
+ PARCKeyId *keyId = parcKeyId_Create(parcCryptoHash_GetDigest(keyDigest));
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, derEncodedVersion);
+
+ parcBuffer_Release(&derEncodedVersion);
+ parcCryptoHash_Release(&keyDigest);
+ parcKeyId_Release(&keyId);
+
+ return key;
+}
diff --git a/libparc/parc/security/parc_Certificate.h b/libparc/parc/security/parc_Certificate.h
new file mode 100755
index 00000000..43eb9416
--- /dev/null
+++ b/libparc/parc/security/parc_Certificate.h
@@ -0,0 +1,352 @@
+/*
+ * 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_Certificate.h
+ * @ingroup security
+ * @brief The API for a generic certificate.
+ *
+ */
+
+#ifndef libparc_parc_Certificate_h
+#define libparc_parc_Certificate_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CertificateType.h>
+#include <parc/security/parc_ContainerEncoding.h>
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_Signature.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_Key.h>
+
+struct parc_certificate;
+/**
+ * @typedef PARCCertificate
+ * @brief The structure for PARCCertificate
+ */
+typedef struct parc_certificate PARCCertificate;
+
+typedef struct parc_certificate_interface {
+ /**
+ * The hash of the certificate's public key.
+ *
+ * Try using `parcSigner_CreateKeyId` for a sinterfaceer interface.
+ * You must destroy the returned PARCCryptoHash.
+ * For public key, its the SHA256 digest of the public key.
+ * For HMAC, its the SHA256 digest of the secret key.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return A `PARCCryptoHash` instance.
+ */
+ PARCCryptoHash *(*GetPublicKeyDigest)(void *certificate);
+
+ /**
+ * Returns a copy of the the certificate digest.
+ *
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate.
+ */
+ PARCCryptoHash *(*GetCertificateDigest)(void *certificate);
+
+ /**
+ * Returns a copy of the DER encoded certificate.
+ *
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return A pointer to a `PARCBuffer` containing the encoded certificate.
+ */
+ PARCBuffer *(*GetDEREncodedCertificate)(void *certificate);
+
+ /**
+ * Returns a copy of the encoded public key in DER form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return A pointer to a `PARCBuffer` containing the encoded public key.
+ */
+ PARCBuffer *(*GetDEREncodedPublicKey)(void *certificate);
+
+ /**
+ * Returns the `PARCCertificateType` of this certificate, i.e., PEM, DER, PKCS12.
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return The `PARCCertificateType` associated with this certificate.
+ */
+ PARCCertificateType (*GetCertificateType)(const void *certificate);
+
+ /**
+ * Returns the `PARCContainerEncoding` of this certificate, e.g., X509.
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return The `PARCContainerEncoding` associated with this certificate.
+ */
+ PARCContainerEncoding (*GetContainerEncoding)(const void *certificate);
+} PARCCertificateInterface;
+
+/**
+ * Create a generic `PARCCertificate` instance from a concrete `PARCCertificate` instance.
+ *
+ * NOTE: This function should not be used directly. Construct certificates using the
+ * `PARCCertificateFactory` instead.
+ *
+ * @param [in] impl A pointer to a concrete `PARCCertificate` interface implementation.
+ * @param [in] instance A pointer to the instance that implements this interface.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificate` instance containing the concrete
+ * `PARCCertificate` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = ...;
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ * }
+ * @endcode
+ */
+PARCCertificate *parcCertificate_CreateFromInstance(PARCCertificateInterface *impl, void *instance);
+
+/**
+ * Increase the number of references to a `PARCCertificate` instance.
+ *
+ * Note that a new `PARCCertificate` is not created,
+ * only that the given `PARCCertificate` reference count is incremented.
+ * Discard the reference by invoking {@link parcCertificate_Release}.
+ *
+ * @param [in] certificate A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificate *x = parcCertificate_CreateFromInstance(...);
+ * PARCCertificate *x2 = parcCertificate_Acquire(x);
+ *
+ * parcCertificate_Release(&x);
+ * parcCertificate_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCertificate_Release}
+ */
+PARCCertificate *parcCertificate_Acquire(const PARCCertificate *certificate);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] certificateP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificate *x = parcCertificate_Acquire(...);
+ *
+ * parcCertificate_Release(&x);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCertificate_Acquire}
+ */
+void parcCertificate_Release(PARCCertificate **certificateP);
+
+/**
+ * Returns the `PARCCertificateType` of this certificate, i.e., X509.
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return The `PARCCertificateType` associated with this certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCCertificateType type = parcCertificate_GetCertificateType(wrapper);
+ * // type == PARCCertificateType_X509
+ * }
+ * @endcode
+ */
+PARCCertificateType parcCertificate_GetCertificateType(const PARCCertificate *certificate);
+
+/**
+ * Returns the `PARCContainerEncoding` of this certificate, e.g., PEM, DER.
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return The `PARCContainerEncoding` associated with this certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCContainerEncoding encoding = parcCertificate_GetCertificateType(wrapper);
+ * // encoding == PARCCertificateType_PEM
+ * }
+ * @endcode
+ */
+PARCContainerEncoding parcCertificate_GetContainerEncoding(const PARCCertificate *certificate);
+
+/**
+ * Retrieve the SHA-256 hash digest of the certificate's public key.
+ *
+ * You must release the returned `PARCCryptoHash` via {@link parcCryptoHash_Release}.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A `PARCCryptoHash` value which internally contains a hash digest of the certificate key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCCryptoHash *certificateKeyDigest = parcCertificate_GetPublicKeyDigest(wrapper);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCertificate_GetPublicKeyDigest(const PARCCertificate *certificate);
+
+/**
+ * Get the SHA-256 digest of the certificate.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCCryptoHash *certificateKeyDigest = parcCertificate_GetPublicKeyDigest(wrapper);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCertificate_GetCertificateDigest(const PARCCertificate *certificate);
+
+/**
+ * Get a `PARCBuffer` containing the DER encoded representation of the certificate.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCBuffer` containing the encoded certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCBuffer *certificateDER = parcCertificate_GetDEREncodedCertificate(wrapper);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcCertificate_GetDEREncodedCertificate(const PARCCertificate *certificate);
+
+/**
+ * Get the certificate's public key in DER encoding in a `PARCBuffer`.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCBuffer` containing the encoded certificate's public key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCBuffer *certificateDER = parcCertificate_GetDEREncodedPublicKey(wrapper);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcCertificate_GetDEREncodedPublicKey(const PARCCertificate *certificate);
+
+/**
+ * Get the `PARCKey` public key associated with this certificate.
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCKey` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCKey *publicKey = parcCertificate_GetPublicKey(wrapper);
+ * }
+ * @endcode
+ */
+PARCKey *parcCertificate_GetPublicKey(const PARCCertificate *certificate);
+#endif // libparc_parc_Certificate_h
diff --git a/libparc/parc/security/parc_CertificateFactory.c b/libparc/parc/security/parc_CertificateFactory.c
new file mode 100644
index 00000000..3825ae04
--- /dev/null
+++ b/libparc/parc/security/parc_CertificateFactory.c
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+/*
+ * parc_CertificateFactory.c
+ * PARC Library
+ */
+
+#include <config.h>
+
+#include <parc/security/parc_CertificateFactory.h>
+#include <parc/security/parc_X509Certificate.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct parc_certificate_factory {
+ PARCCertificateType type;
+ PARCContainerEncoding encoding;
+};
+
+parcObject_ExtendPARCObject(PARCCertificateFactory, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(parcCertificateFactory, PARCCertificateFactory);
+parcObject_ImplementRelease(parcCertificateFactory, PARCCertificateFactory);
+
+PARCCertificateFactory *
+parcCertificateFactory_Create(PARCCertificateType type, PARCContainerEncoding encoding)
+{
+ PARCCertificateFactory *factory = parcObject_CreateInstance(PARCCertificateFactory);
+ factory->type = type;
+ factory->encoding = encoding;
+ return factory;
+}
+
+PARCCertificate *
+parcCertificateFactory_CreateCertificateFromFile(PARCCertificateFactory *factory, char *filename, char *password __attribute__((unused)))
+{
+ if (factory->type == PARCCertificateType_X509 && factory->encoding == PARCContainerEncoding_PEM) {
+ PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ return wrapper;
+ }
+
+ // Unsupported configuration
+ return NULL;
+}
+
+PARCCertificate *
+parcCertificateFactory_CreateCertificateFromBuffer(PARCCertificateFactory *factory, PARCBuffer *buffer)
+{
+ if (factory->type == PARCCertificateType_X509 && factory->encoding == PARCContainerEncoding_DER) {
+ PARCX509Certificate *certificate = parcX509Certificate_CreateFromDERBuffer(buffer);
+
+ // This may fail.
+ if (certificate == NULL) {
+ return NULL;
+ }
+
+ PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ return wrapper;
+ }
+
+ // Unsupported configuration
+ return NULL;
+}
+
+PARCCertificate *
+parcCertificateFactory_CreateSelfSignedCertificate(PARCCertificateFactory *factory, PARCBuffer **privateKey,
+ char *subjectName, size_t keyLength, size_t valdityDays)
+{
+ if (factory->type == PARCCertificateType_X509 && factory->encoding == PARCContainerEncoding_DER) {
+ PARCX509Certificate *certificate = parcX509Certificate_CreateSelfSignedCertificate(privateKey, subjectName, (int) keyLength, valdityDays);
+
+ // This may fail.
+ if (certificate == NULL) {
+ return NULL;
+ }
+
+ PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ return wrapper;
+ }
+
+ // Unsupported configuration
+ return NULL;
+}
diff --git a/libparc/parc/security/parc_CertificateFactory.h b/libparc/parc/security/parc_CertificateFactory.h
new file mode 100755
index 00000000..5f49ac23
--- /dev/null
+++ b/libparc/parc/security/parc_CertificateFactory.h
@@ -0,0 +1,166 @@
+/*
+ * 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_CertificateFactory.h
+ * @ingroup security
+ * @brief A factory to build certificates.
+ *
+ */
+#ifndef libparc_parc_CertificateFactory_h
+#define libparc_parc_CertificateFactory_h
+
+#include <parc/security/parc_Certificate.h>
+#include <parc/security/parc_CertificateType.h>
+#include <parc/security/parc_ContainerEncoding.h>
+
+struct parc_certificate_factory;
+typedef struct parc_certificate_factory PARCCertificateFactory;
+
+/**
+ * Create a `PARCCertificateFactory` to build certificates with the specified type and encoding.
+ *
+ * @param [in] type The `PARCCertificateType` of certificates to construct.
+ * @param [in] encoding The `PARCContainerEncoding` of certificates to construct.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificateFactory`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ * }
+ * @endcode
+ */
+PARCCertificateFactory *parcCertificateFactory_Create(PARCCertificateType type, PARCContainerEncoding encoding);
+
+/**
+ * Create a `PARCCertificate` from the specified filename and password.
+ *
+ * @param [in] factory The `PARCCertificateFactory` instance used to build the certificate.
+ * @param [in] filename A nul-terminated path to the certificate file.
+ * @param [in] password A nul-terminated password.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pathToCertificate = "file.pem";
+ * PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ * PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromFile(factory, pathToCertificate, NULL);
+ * }
+ * @endcode
+ */
+PARCCertificate *parcCertificateFactory_CreateCertificateFromFile(PARCCertificateFactory *factory, char *filename, char *password);
+
+/**
+ * Create a `PARCCertificate` from the specified `PARCBuffer`.
+ *
+ * @param [in] factory The `PARCCertificateFactory` instance used to build the certificate.
+ * @param [in] buffer A `PARCBuffer` encoding a `PARCCertificate` instance.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...;
+ * PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_DER);
+ * PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromBuffer(factory, buffer);
+ * }
+ * @endcode
+ */
+PARCCertificate *parcCertificateFactory_CreateCertificateFromBuffer(PARCCertificateFactory *factory, PARCBuffer *buffer);
+
+/**
+ * Create a self-signed `PARCCertificate` using the specified parameters and return
+ * the corresponding private key.
+ *
+ * Note: this is equivalent to the following OpenSSL command:
+ * XXXXYYYYZZZZ
+ * TODO TODO TODO
+ *
+ * @param [in] factory The `PARCCertificateFactory` instance used to build the certificate.
+ * @param [in, out] privateKey A pointer to a `PARCBuffer` pointer where the new certificate private key will be stored.
+ * @param [in] subjectName The name of the certificate subject.
+ * @param [in] keyLength The length of the public key to be derived.
+ * @param [in] validityDays The validity period.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...;
+ * PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_DER);
+ * PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromBuffer(factory, buffer);
+ * }
+ * @endcode
+ */
+PARCCertificate *parcCertificateFactory_CreateSelfSignedCertificate(PARCCertificateFactory *factort, PARCBuffer **privateKey, char *subjectName, size_t keyLength, size_t valdityDays);
+
+/**
+ * Increase the number of references to a `PARCCertificateFactory` instance.
+ *
+ * Note that a new `PARCCertificateFactory` is not created,
+ * only that the given `PARCCertificateFactory` reference count is incremented.
+ * Discard the reference by invoking {@link parcCertificateFactory_Release}.
+ *
+ * @param [in] certificate A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificateFactory *x = parcCertificateFactory_CreateFromFile(...);
+ * PARCCertificateFactory *x2 = parcCertificateFactory_Acquire(x);
+ *
+ * parcCertificateFactory_Release(&x);
+ * parcCertificateFactory_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCertificateFactory_Release}
+ */
+PARCCertificateFactory *parcCertificateFactory_Acquire(const PARCCertificateFactory *factory);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] factoryP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificateFactory *x = parcCertificateFactory_CreateFromFile(...);
+ *
+ * parcCertificateFactory_Release(&x);
+ * }
+ * @endcode
+ */
+void parcCertificateFactory_Release(PARCCertificateFactory **factoryP);
+#endif // libparc_parc_CertificateFactory_h
diff --git a/libparc/parc/security/parc_CertificateType.c b/libparc/parc/security/parc_CertificateType.c
new file mode 100755
index 00000000..9da557fd
--- /dev/null
+++ b/libparc/parc/security/parc_CertificateType.c
@@ -0,0 +1,55 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_CertificateType.h>
+
+static struct {
+ PARCCertificateType type;
+ char *name;
+} _certificateType_ToString[] = {
+ { PARCCertificateType_X509, "PARCCertificateType_X509" },
+ { 0, NULL }
+};
+
+const char *
+parcCertificateType_ToString(PARCCertificateType type)
+{
+ for (int i = 0; _certificateType_ToString[i].name != NULL; i++) {
+ if (_certificateType_ToString[i].type == type) {
+ return _certificateType_ToString[i].name;
+ }
+ }
+ return NULL;
+}
+
+PARCCertificateType
+parcCertificateType_FromString(const char *name)
+{
+ for (int i = 0; _certificateType_ToString[i].name != NULL; i++) {
+ if (strcmp(_certificateType_ToString[i].name, name) == 0) {
+ return _certificateType_ToString[i].type;
+ }
+ }
+ return PARCCertificateType_Invalid;
+}
diff --git a/libparc/parc/security/parc_CertificateType.h b/libparc/parc/security/parc_CertificateType.h
new file mode 100755
index 00000000..596cd293
--- /dev/null
+++ b/libparc/parc/security/parc_CertificateType.h
@@ -0,0 +1,65 @@
+/*
+ * 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_CertificateType.h
+ * @ingroup security
+ * @brief A type specifying a certificate.
+ *
+ */
+#ifndef libparc_parc_CertificateType_h
+#define libparc_parc_CertificateType_h
+
+typedef enum {
+ PARCCertificateType_X509,
+ PARCCertificateType_Invalid
+} PARCCertificateType;
+
+/**
+ * Convert the `PARCCertificateType` value to a human-readable string representation.
+ *
+ * @param [in] type A `PARCCertificateType` value
+ *
+ * @return A static, null-terminated string.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificateType type = PARCCertificateType_X509;
+ * const char *stringRep = parcCertificateType_ToString(type);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+const char *parcCertificateType_ToString(PARCCertificateType type);
+
+/**
+ * Convert a string representation value of a `PARCCertificateType` to an actual value.
+ *
+ * @param [in] name A string representation of a `PARCCertificateType` value.
+ *
+ * @return A `PARCCertificateType` value.
+ *
+ * Example:
+ * @code
+ * {
+ * const char stringRep[17] = "PARCCertificateType_X509";
+ * PARCCertificateType type = parcCertificateType_FromString(stringRep);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+PARCCertificateType parcCertificateType_FromString(const char *name);
+#endif // libparc_parc_CertificateType_h
diff --git a/libparc/parc/security/parc_ContainerEncoding.c b/libparc/parc/security/parc_ContainerEncoding.c
new file mode 100755
index 00000000..8f51031a
--- /dev/null
+++ b/libparc/parc/security/parc_ContainerEncoding.c
@@ -0,0 +1,57 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_ContainerEncoding.h>
+
+static struct {
+ PARCContainerEncoding type;
+ char *name;
+} _certificateType_ToString[] = {
+ { PARCContainerEncoding_PEM, "PARCContainerEncoding_PEM" },
+ { PARCContainerEncoding_DER, "PARCContainerEncoding_DER" },
+ { PARCContainerEncoding_PKCS12, "PARCContainerEncoding_PKCS12" },
+ { 0, NULL }
+};
+
+const char *
+parcContainerEncoding_ToString(PARCContainerEncoding type)
+{
+ for (int i = 0; _certificateType_ToString[i].name != NULL; i++) {
+ if (_certificateType_ToString[i].type == type) {
+ return _certificateType_ToString[i].name;
+ }
+ }
+ return NULL;
+}
+
+PARCContainerEncoding
+parcContainerEncoding_FromString(const char *name)
+{
+ for (int i = 0; _certificateType_ToString[i].name != NULL; i++) {
+ if (strcmp(_certificateType_ToString[i].name, name) == 0) {
+ return _certificateType_ToString[i].type;
+ }
+ }
+ return PARCContainerEncoding_Invalid;
+}
diff --git a/libparc/parc/security/parc_ContainerEncoding.h b/libparc/parc/security/parc_ContainerEncoding.h
new file mode 100755
index 00000000..7cac3fd1
--- /dev/null
+++ b/libparc/parc/security/parc_ContainerEncoding.h
@@ -0,0 +1,67 @@
+/*
+ * 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_ContainerEncoding.h
+ * @ingroup security
+ * @brief A Encoding specifying a certificate.
+ *
+ */
+#ifndef libparc_parc_Encoding_h
+#define libparc_parc_Encoding_h
+
+typedef enum {
+ PARCContainerEncoding_PEM,
+ PARCContainerEncoding_DER,
+ PARCContainerEncoding_PKCS12,
+ PARCContainerEncoding_Invalid
+} PARCContainerEncoding;
+
+/**
+ * Convert the `PARCContainerEncoding` value to a human-readable string representation.
+ *
+ * @param [in] Encoding A `PARCContainerEncoding` value
+ *
+ * @return A static, null-terminated string.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCContainerEncoding encoding = PARCContainerEncoding_X509;
+ * const char *stringRep = parcContainerEncoding_ToString(encoding);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+const char *parcContainerEncoding_ToString(PARCContainerEncoding Encoding);
+
+/**
+ * Convert a string representation value of a `PARCContainerEncoding` to an actual value.
+ *
+ * @param [in] name A string representation of a `PARCContainerEncoding` value.
+ *
+ * @return A `PARCContainerEncoding` value.
+ *
+ * Example:
+ * @code
+ * {
+ * const char stringRep[17] = "PARCContainerEncoding_PEM";
+ * PARCContainerEncoding encoding = parcContainerEncoding_FromString(stringRep);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+PARCContainerEncoding parcContainerEncoding_FromString(const char *name);
+#endif // libparc_parc_Encoding_h
diff --git a/libparc/parc/security/parc_CryptoCache.c b/libparc/parc/security/parc_CryptoCache.c
new file mode 100755
index 00000000..a454819b
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoCache.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @header parc_CryptoCache.c
+ * <#Abstract#>
+ *
+ * <#Discussion#>
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+/*
+ * This should be updated to make a reference counted copy of PARCKey and store that (along with its KeyId)
+ * instead of using a direct copy of the user data. That way, there's no issues about destroying the entry
+ * but the user retaining a (now invalid) reference to it.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_CryptoCache.h>
+#include <parc/algol/parc_HashCodeTable.h>
+
+struct parc_crypto_cache {
+ PARCHashCodeTable *keyid_table;
+};
+
+// =====================================================================
+// Translations from void* to typed pointer for use in HashCodeTable
+
+static bool
+_keyidEquals(const void *ptrA, const void *ptrB)
+{
+ return parcKeyId_Equals((const PARCKeyId *) ptrA, (const PARCKeyId *) ptrB);
+}
+
+static void
+_dataDestroy(void **voidPtr)
+{
+ PARCKey **keyPtr = (PARCKey **) voidPtr;
+ parcKey_Release(keyPtr);
+}
+
+// =====================================================================
+
+PARCCryptoCache *
+parcCryptoCache_Create()
+{
+ PARCCryptoCache *cache = parcMemory_AllocateAndClear(sizeof(PARCCryptoCache));
+ assertNotNull(cache, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoCache));
+
+ // KeyIdDestroyer is NULL because we get the keyid out of the key, and it will be destroyed
+ // when the key is destroyed.
+ cache->keyid_table = parcHashCodeTable_Create(_keyidEquals, parcKeyId_HashCodeFromVoid, NULL, _dataDestroy);
+
+ return cache;
+}
+
+/**
+ * Destroys the cache and all internal buffers.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+parcCryptoCache_Destroy(PARCCryptoCache **cryptoCachePtr)
+{
+ assertNotNull(cryptoCachePtr, "Parameter must be non-null double pointer");
+ assertNotNull(*cryptoCachePtr, "Parameter must dereference to non-null pointer");
+
+ PARCCryptoCache *cache = *cryptoCachePtr;
+ parcHashCodeTable_Destroy(&cache->keyid_table);
+ parcMemory_Deallocate((void **) cryptoCachePtr);
+ *cryptoCachePtr = NULL;
+}
+
+/**
+ * Adds the specified key to the keycache.
+ *
+ * Parameters must be non-null
+ * Returns true if added or false if keyid alredy existed and was a different than <code>key</code>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool
+parcCryptoCache_AddKey(PARCCryptoCache *cache, PARCKey *original_key)
+{
+ assertNotNull(cache, "Parameter cache must be non-null");
+ assertNotNull(original_key, "Parameter key must be non-null");
+
+ PARCKey *key = parcKey_Copy(original_key);
+ PARCKeyId *keyid = parcKey_GetKeyId(key);
+
+ return parcHashCodeTable_Add(cache->keyid_table, keyid, key);
+}
+
+/**
+ * Fetches the Key. The user must node modify or destroy the key.
+ *
+ * Returns NULL if the keyid is not found.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const PARCKey *
+parcCryptoCache_GetKey(PARCCryptoCache *cache, const PARCKeyId *keyid)
+{
+ assertNotNull(cache, "Parameter cache must be non-null");
+ assertNotNull(keyid, "Parameter keyid must be non-null");
+
+ return parcHashCodeTable_Get(cache->keyid_table, keyid);
+}
+
+/**
+ * Removes the keyid and key. The internal buffers are destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+parcCryptoCache_RemoveKey(PARCCryptoCache *cache, const PARCKeyId *keyid)
+{
+ assertNotNull(cache, "Parameter cache must be non-null");
+ assertNotNull(keyid, "Parameter keyid must be non-null");
+
+ parcHashCodeTable_Del(cache->keyid_table, keyid);
+}
diff --git a/libparc/parc/security/parc_CryptoCache.h b/libparc/parc/security/parc_CryptoCache.h
new file mode 100755
index 00000000..497ee38d
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoCache.h
@@ -0,0 +1,94 @@
+/*
+ * 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_CryptoCache.h
+ * @ingroup security
+ * @brief In-memory cache of keys or certificates.
+ *
+ * Not sure how to differentiate between keys and certs at the moment. The current API
+ * is thus built around keys.
+ *
+ */
+#include <parc/security/parc_Key.h>
+
+#ifndef libparc_parc_CryptoCache_h
+#define libparc_parc_CryptoCache_h
+
+struct parc_crypto_cache;
+typedef struct parc_crypto_cache PARCCryptoCache;
+
+PARCCryptoCache *parcCryptoCache_Create(void);
+
+/**
+ * Destroys the cache and all internal buffers.
+ *
+ * @param [in,out] cryptoCachePtr A pointer to a pointer to a `PARCCryptoCache` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcCryptoCache_Destroy(PARCCryptoCache **cryptoCachePtr);
+
+/**
+ * Adds the specified key to the keycache.
+ *
+ * Parameters must be non-null
+ * Returns true if added or false if keyid alredy existed and was a different than <code>key</code>
+ * This will store its own reference to the key, so the caller must free key.
+ *
+ * @param [in] cache A pointer to a PARCCryptoCache instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKey *key = ....;
+ * PARCCryptoCache *cache = parcCryptoCache_Create();
+ * parcCryptoCache_AddKey(cache, key);
+ * parcKey_release(&key);
+ * // do stuff with the crypto cache
+ * parcCryptoCache_Destroy(&cache);
+ * }
+ * @endcode
+ */
+bool parcCryptoCache_AddKey(PARCCryptoCache *cache, PARCKey *key);
+
+/**
+ * Fetches the Key. The user must not modify or destroy the key.
+ *
+ * Returns NULL if the keyid is not found.
+ *
+ * @param [in] cache A pointer to a PARCCryptoCache instance.
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const PARCKey *parcCryptoCache_GetKey(PARCCryptoCache *cache, const PARCKeyId *keyid);
+
+/**
+ * Removes the keyid and key. The internal buffers are destroyed.
+ *
+ * @param [in] cache A pointer to a PARCCryptoCache instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcCryptoCache_RemoveKey(PARCCryptoCache *cache, const PARCKeyId *keyid);
+#endif // libparc_parc_CryptoCache_h
diff --git a/libparc/parc/security/parc_CryptoHash.c b/libparc/parc/security/parc_CryptoHash.c
new file mode 100755
index 00000000..3fc40b16
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHash.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @header parcCryptoHash.c
+ * <#Abstract#>
+ *
+ * <#Discussion#>
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct parc_crypto_hash {
+ PARCCryptoHashType type;
+ PARCBuffer *digestBuffer;
+};
+
+static bool
+_parcCryptoHash_FinalRelease(PARCCryptoHash **hashP)
+{
+ PARCCryptoHash *hash = (PARCCryptoHash *) *hashP;
+ if (hash->digestBuffer != NULL) {
+ parcBuffer_Release(&hash->digestBuffer);
+ }
+ return true;
+}
+
+parcObject_Override(PARCCryptoHash, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcCryptoHash_FinalRelease,
+ .equals = (PARCObjectEquals *) parcCryptoHash_Equals);
+
+parcObject_ImplementAcquire(parcCryptoHash, PARCCryptoHash);
+
+parcObject_ImplementRelease(parcCryptoHash, PARCCryptoHash);
+
+PARCCryptoHash *
+parcCryptoHash_Create(PARCCryptoHashType digestType, const PARCBuffer *digestBuffer)
+{
+ PARCCryptoHash *parcDigest = parcObject_CreateInstance(PARCCryptoHash);
+ assertNotNull(parcDigest, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoHash));
+ parcDigest->type = digestType;
+
+ parcDigest->digestBuffer = parcBuffer_Acquire((PARCBuffer *) digestBuffer); // casting to un-const
+
+ return parcDigest;
+}
+
+/**
+ * Create a digest, copying the buffer
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCCryptoHash *
+parcCryptoHash_CreateFromArray(PARCCryptoHashType digestType, const void *buffer, size_t length)
+{
+ PARCCryptoHash *parcDigest = parcObject_CreateInstance(PARCCryptoHash);
+ assertNotNull(parcDigest, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoHash));
+ parcDigest->type = digestType;
+
+ // create a reference counted copy
+ parcDigest->digestBuffer =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(length), length, buffer));
+
+ return parcDigest;
+}
+
+/**
+ * Returns the digest algorithm.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCCryptoHashType
+parcCryptoHash_GetDigestType(const PARCCryptoHash *parcDigest)
+{
+ assertNotNull(parcDigest, "Parameter must be non-null");
+ return parcDigest->type;
+}
+
+bool
+parcCryptoHash_Equals(const PARCCryptoHash *a, const PARCCryptoHash *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a->type == b->type) {
+ if (parcBuffer_Equals(a->digestBuffer, b->digestBuffer)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+PARCBuffer *
+parcCryptoHash_GetDigest(const PARCCryptoHash *parcDigest)
+{
+ assertNotNull(parcDigest, "Parameter must be non-null");
+ return parcDigest->digestBuffer;
+}
diff --git a/libparc/parc/security/parc_CryptoHash.h b/libparc/parc/security/parc_CryptoHash.h
new file mode 100755
index 00000000..d0312d9e
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHash.h
@@ -0,0 +1,234 @@
+/*
+ * 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_CryptoHash.h
+ * @ingroup security
+ *
+ * @brief PARCDigest holds a cryptographic digest, which is comprised
+ * the bytes of the digest and the algorithm used for the digest.
+ *
+ */
+#ifndef libparc_parc_CryptoHash_h
+#define libparc_parc_CryptoHash_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CryptoHashType.h>
+
+struct parc_crypto_hash;
+typedef struct parc_crypto_hash PARCCryptoHash;
+
+/**
+ * Create a Digest holding the type and digest buffer.
+ *
+ * Creates a new reference to the given PARCBuffer `digest`.
+ *
+ * @param [in] digestType The type of hash digest algorithm used to compute this digest.
+ * @param [in] digestBuffer The actual hash digest instance.
+ *
+ * @return A newly allocated `PARCCryptoHash` instance that must be freed via `parcCryptoHash_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *digestBuffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, digestBuffer);
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCryptoHash_Create(PARCCryptoHashType digestType, const PARCBuffer *digestBuffer);
+
+/**
+ * Increase the number of references to a `PARCCryptoHash` instance.
+ *
+ * Note that a new `PARCCryptoHash` is not created,
+ * only that the given `PARCCryptoHash` reference count is incremented.
+ * Discard the reference by invoking {@link parcCryptoHash_Release}.
+ *
+ * @param [in] hash A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHash *x = ...
+ * PARCCryptoHash *x2 = parcCryptoHash_Acquire(x);
+ *
+ * parcCryptoHash_Release(&x);
+ * parcCryptoHash_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCryptoHash_Release}
+ */
+PARCCryptoHash *parcCryptoHash_Acquire(const PARCCryptoHash *hash);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] hashP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHash *x = ...
+ *
+ * parcCryptoHash_Release(&x);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCryptoHash_Acquire}
+ */
+void parcCryptoHash_Release(PARCCryptoHash **hashP);
+
+/**
+ * Create a digest, copying the buffer.
+ *
+ * @param [in] digestType The type of hash digest algorithm used to compute this digest.
+ * @param [in] buffer Pointer to array containing the raw digest bytes.
+ * @param [in] length Length of the digest byte array.
+ *
+ * @return A newly allocated `PARCCryptoHash` instance that must be freed via `parcCryptoHash_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * size_t bufferLen = 32;
+ * uint8_t *buffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer, bufferLen);
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * // free the raw buffer as needed
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCryptoHash_CreateFromArray(PARCCryptoHashType digestType, const void *buffer, size_t length);
+
+/**
+ * Destroy the specified `PARCCryptoHash` instance.
+ *
+ * @param [in,out] parcDigestPtr Pointer to the instance to be destroyed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * }
+ * @endcode
+ */
+void parcCryptoHash_Release(PARCCryptoHash **parcDigestPtr);
+
+/**
+ * Returns the digest algorithm, of type `PARCCryptoHashType`.
+ *
+ * @param [in] parcDigest The `PARCCryptoHash` instance being examined.
+ *
+ * @return A `PARCCryptoHashType` value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ * PARCCryptoHashType type = parcCryptoHash_GetDigestType(digest);
+ * // type will be PARCCryptoHashType_SHA256
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcCryptoHash_GetDigestType(const PARCCryptoHash *parcDigest);
+
+/**
+ * Returnes the digest buffer, copy if you will destroy
+ *
+ * Returns the inner digest buffer. You must copy it if you will make
+ * changes or destroy it.
+ *
+ * @param [in] cryptoHash The `PARCCryptoHash` instance being examined.
+ *
+ * @return A `PARCBuffer` instance containing the raw hash digest.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ * PARCBuffer *rawDigest = parcCryptoHash_GetDigest(digest);
+ * // use the raw digest as necessary
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcCryptoHash_GetDigest(const PARCCryptoHash *cryptoHash);
+
+/**
+ * Determine if two PARCCryptoHash instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCCryptoHash` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcCryptoHash_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcCryptoHash_Equals(x, y)` must return true if and only if
+ * parcCryptoHash_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcCryptoHash_Equals(x, y)` returns true and
+ * `parcCryptoHash_Equals(y, z)` returns true,
+ * then `parcCryptoHash_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcCryptoHash_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcCryptoHash_Equals(x, NULL)` must return false.
+ *
+ * @param [in] a A pointer to a PARCCryptoHash instance.
+ * @param [in] b A pointer to a PARCCryptoHash instance.
+ *
+ * @return True if the given PARCCryptoHash instances are equal, false otherwise.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...
+ * PARCCryptoHash *orig = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ * PARCCryptoHash *copy = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ *
+ * if (parcCryptoHash_Equals(orig, copy)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ *
+ * parcCryptoHash_Release(&orig);
+ * parcCryptoHash_Release(&copy);
+ * }
+ * @endcode
+ */
+bool parcCryptoHash_Equals(const PARCCryptoHash *a, const PARCCryptoHash *b);
+#endif // libparc_parc_CryptoHash_h
diff --git a/libparc/parc/security/parc_CryptoHashType.c b/libparc/parc/security/parc_CryptoHashType.c
new file mode 100644
index 00000000..78440f33
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHashType.c
@@ -0,0 +1,57 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_CryptoHashType.h>
+
+static struct {
+ PARCCryptoHashType type;
+ char *name;
+} cryptoHashType_ToString[] = {
+ { PARCCryptoHashType_SHA256, "PARCCryptoHashType_SHA256" },
+ { PARCCryptoHashType_SHA512, "PARCCryptoHashType_SHA512" },
+ { PARCCryptoHashType_CRC32C, "PARCCryptoHashType_CRC32C" },
+ { 0, NULL }
+};
+
+const char *
+parcCryptoHashType_ToString(PARCCryptoHashType type)
+{
+ for (int i = 0; cryptoHashType_ToString[i].name != NULL; i++) {
+ if (cryptoHashType_ToString[i].type == type) {
+ return cryptoHashType_ToString[i].name;
+ }
+ }
+ return NULL;
+}
+
+PARCCryptoHashType
+parcCryptoHashType_FromString(const char *name)
+{
+ for (int i = 0; cryptoHashType_ToString[i].name != NULL; i++) {
+ if (strcmp(cryptoHashType_ToString[i].name, name) == 0) {
+ return cryptoHashType_ToString[i].type;
+ }
+ }
+ return PARCCryptoHashType_NULL;
+}
diff --git a/libparc/parc/security/parc_CryptoHashType.h b/libparc/parc/security/parc_CryptoHashType.h
new file mode 100755
index 00000000..3ab1d9c9
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHashType.h
@@ -0,0 +1,71 @@
+/*
+ * 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_CryptoHashType.h
+ * @ingroup security
+ * @brief A type specifying a cryptographic hash (or CRC check) algorithm.
+ *
+ * This type is overloaded to support both cryptographic hash digest algorithms and cyclical-reduncancy
+ * check (CRC) algorithms. See the available `PARCCryptoHashType` enum types for an exhaustive
+ * list of the supported algorithms.
+ *
+ */
+#ifndef libparc_parc_CryptoHashType_h
+#define libparc_parc_CryptoHashType_h
+
+typedef enum {
+ PARCCryptoHashType_SHA256,
+ PARCCryptoHashType_SHA512,
+ PARCCryptoHashType_CRC32C,
+ PARCCryptoHashType_NULL
+} PARCCryptoHashType;
+
+/**
+ * Convert the `PARCCryptoHashType` value to a human-readable string representation.
+ *
+ * @param [in] type A `PARCCryptoHashType` value
+ *
+ * @return A static, null-terminated string.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHashType type = PARCCryptoHashType_SHA256;
+ * const char *stringRep = parcCryptoHashType_ToString(type);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+const char *parcCryptoHashType_ToString(PARCCryptoHashType type);
+
+/**
+ * Convert a string representation value of a `PARCCryptoHashType` to an actual value.
+ *
+ * @param [in] name A string representation of a `PARCCryptoHashType` value.
+ *
+ * @return A `PARCCryptoHashType` value.
+ *
+ * Example:
+ * @code
+ * {
+ * const char stringRep[17] = "PARCCryptoHashType_SHA256";
+ * PARCCryptoHashType type = parcCryptoHashType_FromString(stringRep);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcCryptoHashType_FromString(const char *name);
+#endif // libparc_parc_CryptoHashType_h
diff --git a/libparc/parc/security/parc_CryptoHasher.c b/libparc/parc/security/parc_CryptoHasher.c
new file mode 100755
index 00000000..f2c00967
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHasher.c
@@ -0,0 +1,530 @@
+/*
+ * 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.
+ */
+
+/**
+ * Implements SHA256, and SHA512 with OpenSSL or Apple's CommonCrypto, depending on platform.
+ * It all follows the OpenSSL calling conventions:
+ * CTX_* is the digest's context
+ * INIT_* initializes the digest
+ * UPDATE_* updates the digest given a buffer
+ * FINAL_* finalizes the digest, returning the digest
+ * LENGTH_* is the byte length of the digest.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Object.h>
+
+#ifdef __APPLE__
+#include <CommonCrypto/CommonDigest.h>
+
+#define CTX_SHA256 CC_SHA256_CTX
+#define INIT_SHA256 CC_SHA256_Init
+#define UPDATE_SHA256 CC_SHA256_Update
+#define FINAL_SHA256 CC_SHA256_Final
+#define LENGTH_SHA256 CC_SHA256_DIGEST_LENGTH
+
+#define CTX_SHA512 CC_SHA512_CTX
+#define INIT_SHA512 CC_SHA512_Init
+#define UPDATE_SHA512 CC_SHA512_Update
+#define FINAL_SHA512 CC_SHA512_Final
+#define LENGTH_SHA512 CC_SHA512_DIGEST_LENGTH
+
+#else
+#include <openssl/sha.h>
+#define CTX_SHA256 SHA256_CTX
+#define INIT_SHA256 SHA256_Init
+#define UPDATE_SHA256 SHA256_Update
+#define FINAL_SHA256 SHA256_Final
+#define LENGTH_SHA256 SHA256_DIGEST_LENGTH
+
+#define CTX_SHA512 SHA512_CTX
+#define INIT_SHA512 SHA512_Init
+#define UPDATE_SHA512 SHA512_Update
+#define FINAL_SHA512 SHA512_Final
+#define LENGTH_SHA512 SHA512_DIGEST_LENGTH
+#endif
+
+// -------------------------------------------------------------
+// function prototypes for use in the function structures
+static void *_sha256_create(void *env);
+static int _sha256_init(void *ctx);
+static int _sha256_update(void *ctx, const void *buffer, size_t length);
+static PARCBuffer *_sha256_finalize(void *ctx);
+static void _sha256_destroy(void **ctxPtr);
+
+static void *_sha512_create(void *env);
+static int _sha512_init(void *ctx);
+static int _sha512_update(void *ctx, const void *buffer, size_t length);
+static PARCBuffer *_sha512_finalize(void *ctx);
+static void _sha512_destroy(void **ctxPtr);
+
+static void *_crc32_create(void *env);
+static int _crc32_init(void *ctx);
+static int _crc32_update(void *ctx, const void *buffer, size_t length);
+static PARCBuffer *_crc32_finalize(void *ctx);
+static void _crc32_destroy(void **ctxPtr);
+// -------------------------------------------------------------
+
+// These are templates for the environments. SHA256 and SHA512 do not
+// have a functor_env, all the state is carried in the setup context.
+
+static PARCCryptoHasherInterface functor_sha256 = {
+ .functor_env = NULL,
+ .hasher_setup = _sha256_create,
+ .hasher_init = _sha256_init,
+ .hasher_update = _sha256_update,
+ .hasher_finalize = _sha256_finalize,
+ .hasher_destroy = _sha256_destroy
+};
+
+static PARCCryptoHasherInterface functor_sha512 = {
+ .functor_env = NULL,
+ .hasher_setup = _sha512_create,
+ .hasher_init = _sha512_init,
+ .hasher_update = _sha512_update,
+ .hasher_finalize = _sha512_finalize,
+ .hasher_destroy = _sha512_destroy
+};
+
+static PARCCryptoHasherInterface functor_crc32 = {
+ .functor_env = NULL,
+ .hasher_setup = _crc32_create,
+ .hasher_init = _crc32_init,
+ .hasher_update = _crc32_update,
+ .hasher_finalize = _crc32_finalize,
+ .hasher_destroy = _crc32_destroy
+};
+
+struct parc_crypto_hasher {
+ PARCCryptoHashType type;
+ PARCCryptoHasherInterface functor;
+ void *hasher_ctx;
+};
+
+static void
+_parcCryptoHasher_FinalRelease(PARCCryptoHasher **hasherP)
+{
+ PARCCryptoHasher *hasher = (PARCCryptoHasher *) *hasherP;
+ hasher->functor.hasher_destroy(&(hasher->hasher_ctx));
+}
+
+parcObject_ExtendPARCObject(PARCCryptoHasher, _parcCryptoHasher_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(parcCryptoHasher, PARCCryptoHasher);
+
+parcObject_ImplementRelease(parcCryptoHasher, PARCCryptoHasher);
+
+PARCCryptoHasher *
+parcCryptoHasher_Create(PARCCryptoHashType type)
+{
+ PARCCryptoHasher *hasher = parcObject_CreateInstance(PARCCryptoHasher);
+ assertNotNull(hasher, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoHasher));
+
+ hasher->type = type;
+
+ switch (type) {
+ case PARCCryptoHashType_SHA256:
+ hasher->functor = functor_sha256;
+ break;
+
+ case PARCCryptoHashType_SHA512:
+ hasher->functor = functor_sha512;
+ break;
+
+ case PARCCryptoHashType_CRC32C:
+ hasher->functor = functor_crc32;
+ break;
+
+ default:
+ parcMemory_Deallocate((void **) &hasher);
+ trapIllegalValue(type, "Unknown hasher type: %d", type);
+ }
+
+ hasher->hasher_ctx = hasher->functor.hasher_setup(hasher->functor.functor_env);
+ return hasher;
+}
+
+PARCCryptoHasher *
+parcCryptoHasher_CustomHasher(PARCCryptoHashType type, PARCCryptoHasherInterface functor)
+{
+ PARCCryptoHasher *hasher = parcObject_CreateInstance(PARCCryptoHasher);
+ assertNotNull(hasher, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoHasher));
+ hasher->type = type;
+ hasher->functor = functor;
+ hasher->hasher_ctx = hasher->functor.hasher_setup(hasher->functor.functor_env);
+ return hasher;
+}
+
+/**
+ * Reset the internal state of the digest to start a new session
+ * Returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+parcCryptoHasher_Init(PARCCryptoHasher *digester)
+{
+ assertNotNull(digester, "Parameter must be non-null");
+
+ int success = digester->functor.hasher_init(digester->hasher_ctx);
+ return (success == 1) ? 0 : -1;
+}
+
+int
+parcCryptoHasher_UpdateBytes(PARCCryptoHasher *digester, const void *buffer, size_t length)
+{
+ assertNotNull(digester, "Parameter must be non-null");
+ int success = digester->functor.hasher_update(digester->hasher_ctx, buffer, length);
+ return (success == 1) ? 0 : -1;
+}
+
+int
+parcCryptoHasher_UpdateBuffer(PARCCryptoHasher *digester, const PARCBuffer *buffer)
+{
+ assertNotNull(digester, "Parameter must be non-null");
+ PARCBuffer *buf = parcBuffer_Slice(buffer);
+ size_t length = parcBuffer_Limit(buf);
+ void *byteArray = parcBuffer_Overlay(buf, length);
+ int success = digester->functor.hasher_update(digester->hasher_ctx, byteArray, length);
+
+ parcBuffer_Release(&buf);
+ return (success == 1) ? 0 : -1;
+}
+
+PARCCryptoHash *
+parcCryptoHasher_Finalize(PARCCryptoHasher *digester)
+{
+ assertNotNull(digester, "Parameter must be non-null");
+ PARCBuffer *digestBuffer = digester->functor.hasher_finalize(digester->hasher_ctx);
+
+ if (parcBuffer_Position(digestBuffer) != 0) {
+ parcBuffer_Flip(digestBuffer);
+ }
+
+ PARCCryptoHash *parcDigest = parcCryptoHash_Create(digester->type, digestBuffer);
+
+ parcBuffer_Release(&digestBuffer);
+ return parcDigest;
+}
+
+// ===============================================
+
+static void *
+_sha256_create(void *dummy)
+{
+ void *ctx = parcMemory_AllocateAndClear(sizeof(CTX_SHA256));
+ return ctx;
+}
+
+static int
+_sha256_init(void *ctx)
+{
+ return INIT_SHA256(ctx);
+}
+
+static int
+_sha256_update(void *ctx, const void *buffer, size_t length)
+{
+ return UPDATE_SHA256(ctx, buffer, (unsigned) length);
+}
+
+static PARCBuffer *
+_sha256_finalize(void *ctx)
+{
+ uint8_t buffer[LENGTH_SHA256];
+ FINAL_SHA256(buffer, ctx);
+
+ PARCBuffer *output = parcBuffer_Allocate(LENGTH_SHA256);
+ parcBuffer_PutArray(output, LENGTH_SHA256, buffer);
+
+ return output;
+}
+
+static void
+_sha256_destroy(void **ctxPtr)
+{
+ parcMemory_Deallocate((void **) ctxPtr);
+ *ctxPtr = NULL;
+}
+
+// ===============================================
+
+static void *
+_sha512_create(void *dummy)
+{
+ void *ctx = parcMemory_AllocateAndClear(sizeof(CTX_SHA512));
+ return ctx;
+}
+
+static int
+_sha512_init(void *ctx)
+{
+ return INIT_SHA512(ctx);
+}
+
+static int
+_sha512_update(void *ctx, const void *buffer, size_t length)
+{
+ return UPDATE_SHA512(ctx, buffer, (unsigned) length);
+}
+
+static PARCBuffer *
+_sha512_finalize(void *ctx)
+{
+ uint8_t buffer[LENGTH_SHA512];
+ FINAL_SHA512(buffer, ctx);
+
+ PARCBuffer *output = parcBuffer_Allocate(LENGTH_SHA512);
+ parcBuffer_PutArray(output, LENGTH_SHA512, buffer);
+
+ return output;
+}
+
+static void
+_sha512_destroy(void **ctxPtr)
+{
+ parcMemory_Deallocate((void **) ctxPtr);
+ *ctxPtr = NULL;
+}
+
+// ==================================================
+// CRC32C Implementation PARCCryptoHasher
+
+typedef struct crc32c_state {
+ uint32_t crc32;
+} _CRC32CState;
+
+// =====================================
+// Hardware calculation
+
+#ifdef __SSE4_2__
+#include <nmmintrin.h>
+
+#ifdef __x86_64__
+// The length rounded to 8-bytes
+#define CRC_ROUNDING_MASK 0xFFFFFFFFFFFFFFF8ULL
+#define LARGEST_CRC_INTRINSIC _mm_crc32_u64
+#define CRC_CAST_TYPE uint64_t
+#else
+// The length rounded to 4-bytes
+#define CRC_ROUNDING_MASK 0xFFFFFFFCUL
+#define LARGEST_CRC_INTRINSIC _mm_crc32_u32
+#define CRC_CAST_TYPE uint32_t
+#endif //__x86_64__
+
+static uint32_t
+_crc32c_UpdateIntel(uint32_t crc, size_t len, uint8_t p[len])
+{
+ size_t blocks = len & CRC_ROUNDING_MASK;
+ size_t offset = 0;
+
+ while (offset < blocks) {
+ crc = (uint32_t) LARGEST_CRC_INTRINSIC((CRC_CAST_TYPE) crc, *(CRC_CAST_TYPE *) &p[offset]);
+ offset += sizeof(CRC_CAST_TYPE);
+ }
+
+ // now do the last bytes if it was not 8-byte aligned
+ size_t position = blocks;
+ while (position < len) {
+ crc = _mm_crc32_u8((uint32_t) crc, p[position]);
+ position++;
+ }
+
+ return crc;
+}
+#endif
+
+// =====================================
+// Software calculation
+
+// Table generated from CRC Calculator http://sourceforge.net/projects/crccalculator/files/CRC/
+// The table is for bit-reversed bytes
+
+static const uint32_t _crc32c_table[] = {
+ 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
+ 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
+ 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
+ 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
+ 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
+ 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
+ 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
+ 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
+ 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
+ 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
+ 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
+ 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
+ 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
+ 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
+ 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
+ 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
+ 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
+ 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
+ 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
+ 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
+ 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
+ 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
+ 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
+ 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
+ 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
+ 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
+ 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
+ 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
+ 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
+ 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
+ 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
+ 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
+ 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
+ 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
+ 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
+ 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
+ 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
+ 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
+ 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
+ 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
+ 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
+ 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
+ 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
+ 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
+ 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
+ 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
+ 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
+ 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
+ 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
+ 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
+ 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
+ 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
+ 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
+ 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
+ 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
+ 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
+ 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
+ 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
+ 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
+ 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
+ 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
+ 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
+ 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
+ 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
+};
+
+/*
+ * If we use the hardware implementation, this function may be unused, but
+ * we keep it around for unit testing
+ */
+__attribute__((unused))
+static uint32_t
+_crc32c_UpdateSoftware(uint32_t crc, size_t len, uint8_t p[len])
+{
+ for (int i = 0; i < len; i++) {
+ crc = (crc >> 8) ^ _crc32c_table[((uint8_t) (crc & 0xFF)) ^ p[i]];
+ }
+
+ return crc;
+}
+
+/**
+ * Initializes the CRC32C value (init to 0xFFFFFFFF)
+ */
+static uint32_t
+_crc32c_Init(void)
+{
+ return ~0;
+}
+
+
+/**
+ * Finalizes the CRC32 (xor with 0xFFFFFFFF)
+ */
+static uint32_t
+_crc32c_Finalize(uint32_t crc)
+{
+ return crc ^ ~0;
+}
+
+/**
+ * Updates the CRC32 value with a byte array. Does
+ * bit mirroring to match either the Intel instruction set or
+ * the CRC table used by the software calculation.
+ */
+static uint32_t
+_crc32c_Update(uint32_t crc, size_t len, uint8_t p[len])
+{
+#ifdef __SSE4_2__
+ crc = _crc32c_UpdateIntel(crc, len, p);
+#else
+ crc = _crc32c_UpdateSoftware(crc, len, p);
+#endif
+ return crc;
+}
+
+/*
+ * Creates a new context variable for starting a hash
+ */
+static void *
+_crc32_create(void *env __attribute__ ((unused)))
+{
+ _CRC32CState *ctx = parcMemory_AllocateAndClear(sizeof(_CRC32CState));
+ assertNotNull(ctx, "parcMemory_AllocateAndClear(%zu) returned NULL for _CRC32CState", sizeof(_CRC32CState));
+
+ // Now initialize it with our digest and key, so in hmac_init we can avoid using those
+ return ctx;
+}
+
+static int
+_crc32_init(void *ctx)
+{
+ _CRC32CState *state = ctx;
+
+ // initialize the CRC32C with all 1's
+ state->crc32 = _crc32c_Init();
+
+ return 0;
+}
+
+static int
+_crc32_update(void *ctx, const void *buffer, size_t length)
+{
+ _CRC32CState *state = ctx;
+ state->crc32 = _crc32c_Update(state->crc32, length, (uint8_t *) buffer);
+ return 0;
+}
+
+static PARCBuffer *
+_crc32_finalize(void *ctx)
+{
+ _CRC32CState *state = ctx;
+ state->crc32 = _crc32c_Finalize(state->crc32);
+ PARCBuffer *crcDigest = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(crcDigest, state->crc32);
+ return parcBuffer_Flip(crcDigest);
+}
+
+static void
+_crc32_destroy(void **ctxPtr)
+{
+ _CRC32CState *state = *ctxPtr;
+ parcMemory_Deallocate((void **) &state);
+ *ctxPtr = NULL;
+}
diff --git a/libparc/parc/security/parc_CryptoHasher.h b/libparc/parc/security/parc_CryptoHasher.h
new file mode 100755
index 00000000..2c93c1f7
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHasher.h
@@ -0,0 +1,306 @@
+/*
+ * 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_CryptoHasher.h
+ * @ingroup security
+ * @brief Computes digests of bytes or PARCBuffers.
+ *
+ * The PARCCryptoHasher computes digests of bytes or PARCBuffers.
+ * It produces a PARCCryptoHash (without the "er"), which contains the
+ * digest and the algorithm used to compute the digest.
+ *
+ */
+
+#ifndef libparc_parc_CryptoHasher_h
+#define libparc_parc_CryptoHasher_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CryptoHash.h>
+
+struct parc_crypto_hasher;
+typedef struct parc_crypto_hasher PARCCryptoHasher;
+
+typedef struct parc_crypto_hasher_interface {
+ void *functor_env;
+
+ /**
+ * Called with the environment and returns the setup context.
+ *
+ * @param [in] env The context environment (modified if needed).
+ */
+ void *(*hasher_setup)(void *env);
+
+ /**
+ * Setup the local context for the cryptographic hasher.
+ *
+ * These operate on the setup context, not the environment.
+ *
+ * @param [in] setup_ctx The local context that is initialized.
+ *
+ * @return 0 Successful initialization
+ * @return -1 An error occurred
+ */
+ int (*hasher_init)(void *setup_ctx);
+
+ /**
+ * Updated the digest using raw bytes
+ *
+ * @param [in] setup_ctx The local context for the hash digester
+ * @param [in] buffer Pointer to an array containing hte raw bytes used to update the digester
+ * @param [in] length Length of the input byte array
+ *
+ * @return 0 Successul update
+ * @return -1 An error occurred
+ */
+ int (*hasher_update)(void *setup_ctx, const void *buffer, size_t length);
+
+ /**
+ * Finalize the digest. Appends the digest to the output buffer, which
+ * the user must allocate.
+ *
+ * @param [in] setup_ctx The local context for the hash digester
+ *
+ * @return non-NULL A `PARCBuffer` containing the final hash digest.
+ * @return NULL An error ocurred
+ */
+ PARCBuffer* (*hasher_finalize)(void *setup_ctx);
+
+ /**
+ * Destroy the digester, releasing internal references as needed.
+ *
+ * @param [in] setup_ctx A pointer to a local context to destroy.
+ */
+ void (*hasher_destroy)(void **setup_ctx);
+} PARCCryptoHasherInterface;
+
+/**
+ * Create one of the pre-defined cryptographic hash "digesters" from the
+ * available `PARCCryptoHashType` types.
+ *
+ * @param [in] type A `PARCCryptoHashType` value.
+ *
+ * @return A newly allocated `PARCCryptoHasher` instance that must be freed by `parcCryptoHasher_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * // initialize if needed
+ * // update bytes or finalize as needed
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+PARCCryptoHasher *parcCryptoHasher_Create(PARCCryptoHashType type);
+
+
+/**
+ * Creates a custom hasher using the provided functor. Useful for
+ * implementing HMAC [RFC 2104] without leaking the key outside the keystore.
+ *
+ * The functor may carry an environment (i.e. info from the keystore) that will
+ * be echod back when CryptoHasher call the <code>functor->hasher_setup(functor->functor_env)</code>.
+ * All subsequent calls are passed the setup context
+ *
+ * Example:
+ * @code
+ * {
+ * static PARCCryptoHasherInterface hash_crc32c_template = {
+ * .functor_env = NULL,
+ * .hasher_setup = crc32cHasher_setup,
+ * .hasher_init = crc32cHasher_init,
+ * .hasher_update = crc32cHasher_update,
+ * .hasher_finalize= crc32cHasher_finalize,
+ * .hasher_destroy = crc32cHasher_destroy
+ * };
+ *
+ * CRC32CSigner *crc32Signer = parcMemory_AllocateAndClear(sizeof(CRC32CSigner));
+ * crc32Signer->hasher_functor = hash_crc32c_template;
+ * crc32Signer->hasher_functor.functor_env = crc32Signer;
+ * crc32Signer->hasher = parcCryptoHasher_CustomHasher(PARCCryptoHashType_CRC32C, crc32Signer->hasher_functor);
+ *
+ * PARCSigningInterface *signer = parcMemory_AllocateAndClear(sizeof(PARCSigningInterface));
+ * *signer = crc32signerimpl_template;
+ * signer->interfaceContext crc32Signer;
+ * return signer;
+ * }
+ * @endcode
+ */
+PARCCryptoHasher *parcCryptoHasher_CustomHasher(PARCCryptoHashType type, PARCCryptoHasherInterface functor);
+
+/**
+ * Increase the number of references to a `PARCCryptoHasher` instance.
+ *
+ * Note that a new `PARCCryptoHasher` is not created,
+ * only that the given `PARCCryptoHasher` reference count is incremented.
+ * Discard the reference by invoking {@link parcCryptoHasher_Release}.
+ *
+ * @param [in] hasher A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *x = ...
+ * PARCCryptoHasher *x2 = parcCryptoHasher_Acquire(x);
+ *
+ * parcCryptoHasher_Release(&x);
+ * parcCryptoHasher_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCryptoHasher_Release}
+ */
+PARCCryptoHasher *parcCryptoHasher_Acquire(const PARCCryptoHasher *hasher);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] hasherP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *x = ...
+ *
+ * parcCryptoHasher_Release(&x);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCryptoHasher_Acquire}
+ */
+void parcCryptoHasher_Release(PARCCryptoHasher **hasherP);
+
+/**
+ * Reset the internal state of the digest to start a new session.
+ *
+ * @param [in] digester A `PARCCryptoHasher` instance.
+ *
+ * @return 0 Successful reset
+ * @return -1 Some failure occurred
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * // update bytes or finalize as needed
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+int parcCryptoHasher_Init(PARCCryptoHasher *digester);
+
+/**
+ * Add bytes to the digest.
+ *
+ * @param [in] hasher A `PARCCryptoHasher` instance.
+ * @param [in] buffer A pointer to a raw buffer with bytes to update the hash digest.
+ * @param [in] length Length of the input byte array.
+ *
+ * @return 0 Successfully added bytes to the digest internally.
+ * @return -1 Some failure occurred
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * ...
+ * uint8_t *buffer = ...
+ * size_t bufferLen = 32;
+ * parcCryptoHasher_UpdateBytes(digester, buffer, bufferLen);
+ * // update bytes or finalize as needed
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+int parcCryptoHasher_UpdateBytes(PARCCryptoHasher *hasher, const void *buffer, size_t length);
+
+/**
+ * Add bytes to the digest. The bytes used are those starting at the
+ * specified buffer's "position" value.
+ *
+ * @param [in] hasher A `PARCCryptoHasher` instance.
+ * @param [in] buffer A `PARCBuffer` instance containing the bytes to add to the digest.
+ *
+ * @return 0 Successfully added bytes to the digest internally.
+ * @return -1 Some failure occurred
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * ...
+ * PARCBuffer *buffer = ...
+ * parcCryptoHasher_UpdateBuffer(digester, buffer);
+ * // update bytes or finalize as needed
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+int parcCryptoHasher_UpdateBuffer(PARCCryptoHasher *hasher, const PARCBuffer *buffer);
+
+/**
+ * Finalize the digest. Appends the digest to the output buffer, which
+ * the user must allocate.
+ *
+ * @param [in] hasher A `PARCCryptoHasher` instance.
+ *
+ * @return The output buffer - the final digest from the hash function computation.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * ...
+ * PARCBuffer *buffer = ...
+ * parcCryptoHasher_UpdateBuffer(digester, buffer);
+ * PARCBuffer *hashDigest = parcCryptoHasher_Finalize(digester);
+ * // use the hashDigest as needed
+ * parcBuffer_Release(&hashDigest);
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCryptoHasher_Finalize(PARCCryptoHasher *hasher);
+
+/**
+ * Destroy the digester, releasing internal references as needed.
+ *
+ * @param [in] hasherPtr A pointer to a `PARCCryptoHasher` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * ...
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+void parcCryptoHasher_Release(PARCCryptoHasher **hasherPtr);
+#endif // libparc_parc_CryptoHasher_h
diff --git a/libparc/parc/security/parc_CryptoSuite.c b/libparc/parc/security/parc_CryptoSuite.c
new file mode 100755
index 00000000..9f4506e7
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoSuite.c
@@ -0,0 +1,44 @@
+/*
+ * 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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_CryptoSuite.h>
+
+PARCCryptoHashType
+parcCryptoSuite_GetCryptoHash(PARCCryptoSuite suite)
+{
+ switch (suite) {
+ case PARCCryptoSuite_DSA_SHA256: // fallthrough
+ case PARCCryptoSuite_HMAC_SHA256: // fallthrough
+ case PARCCryptoSuite_RSA_SHA256: // fallthrough
+ case PARCCryptoSuite_EC_SECP_256K1:
+ return PARCCryptoHashType_SHA256;
+
+ case PARCCryptoSuite_HMAC_SHA512: // fallthrough
+ case PARCCryptoSuite_RSA_SHA512:
+ return PARCCryptoHashType_SHA512;
+
+ case PARCCryptoSuite_NULL_CRC32C:
+ return PARCCryptoHashType_CRC32C;
+
+ default:
+ trapIllegalValue(suite, "Unknown crypto suite: %d", suite);
+ }
+}
diff --git a/libparc/parc/security/parc_CryptoSuite.h b/libparc/parc/security/parc_CryptoSuite.h
new file mode 100755
index 00000000..b9c138e2
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoSuite.h
@@ -0,0 +1,58 @@
+/*
+ * 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_CryptoSuite.h
+ * @ingroup security
+ * @brief Represent a cryptographic suite, a set of corresponding hash and signing/MAC/CRC algorithms.
+ *
+ * A cryptographic suite encapsulates the method by which (public key) digital signatures and
+ * (private key) MACs. For example, a digital signature suite might combine SHA-256 as the hash
+ * digest algorithm and RSA as the signature generation/verification algorithm. Such a suite
+ * would would have the PARCCryptoSuite value PARCCryptoSuite_RSA_SHA256.
+ *
+ */
+#ifndef libparc_parc_CryptoSuite_h
+#define libparc_parc_CryptoSuite_h
+
+#include <parc/security/parc_CryptoHashType.h>
+
+typedef enum {
+ PARCCryptoSuite_RSA_SHA256,
+ PARCCryptoSuite_DSA_SHA256,
+ PARCCryptoSuite_RSA_SHA512,
+ PARCCryptoSuite_HMAC_SHA256,
+ PARCCryptoSuite_HMAC_SHA512,
+ PARCCryptoSuite_NULL_CRC32C,
+ PARCCryptoSuite_EC_SECP_256K1,
+ PARCCryptoSuite_UNKNOWN
+} PARCCryptoSuite;
+
+/**
+ * Given a PARCCryptoSuite value, return the corresponding cryptographic hash as a `PARCCryptoHashType`.
+ *
+ * @param [in] suite A PARCCryptoSuite value.
+ *
+ * @return A PARCCryptoHashType value
+ *
+ * Example:
+ * @code
+ * {
+ * PARCryptoHashType hash = parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_RSA_SHA256);
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcCryptoSuite_GetCryptoHash(PARCCryptoSuite suite);
+#endif // libparc_parc_CryptoSuite_h
diff --git a/libparc/parc/security/parc_DiffieHellman.c b/libparc/parc/security/parc_DiffieHellman.c
new file mode 100644
index 00000000..03edb0d9
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellman.c
@@ -0,0 +1,55 @@
+/*
+ * 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/algol/parc_Object.h>
+
+#include <parc/security/parc_DiffieHellman.h>
+
+struct parc_diffie_hellman {
+ PARCDiffieHellmanGroup groupType;
+};
+
+static bool
+_parcDiffieHellman_Destructor(PARCDiffieHellman **pointer)
+{
+ return true;
+}
+
+parcObject_Override(PARCDiffieHellman, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcDiffieHellman_Destructor);
+
+parcObject_ImplementAcquire(parcDiffieHellman, PARCDiffieHellman);
+parcObject_ImplementRelease(parcDiffieHellman, PARCDiffieHellman);
+
+PARCDiffieHellman *
+parcDiffieHellman_Create(PARCDiffieHellmanGroup groupType)
+{
+ PARCDiffieHellman *dh = parcObject_CreateInstance(PARCDiffieHellman);
+
+ if (dh != NULL) {
+ dh->groupType = groupType;
+ }
+
+ return dh;
+}
+
+PARCDiffieHellmanKeyShare *
+parcDiffieHellman_GenerateKeyShare(PARCDiffieHellman *dh)
+{
+ return parcDiffieHellmanKeyShare_Create(dh->groupType);
+}
diff --git a/libparc/parc/security/parc_DiffieHellman.h b/libparc/parc/security/parc_DiffieHellman.h
new file mode 100644
index 00000000..b6a8c809
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellman.h
@@ -0,0 +1,119 @@
+/*
+ * 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_DiffieHellman.h
+ * @ingroup security
+ * @brief A factory for Diffie Hellman parameters.
+ *
+ */
+#ifndef libparc_parc_DiffieHellman_h
+#define libparc_parc_DiffieHellman_h
+
+#include <parc/security/parc_DiffieHellmanGroup.h>
+#include <parc/security/parc_DiffieHellmanKeyShare.h>
+
+struct parc_diffie_hellman;
+typedef struct parc_diffie_hellman PARCDiffieHellman;
+
+/**
+ * Create an instance of `PARCDiffieHellman.` that generates Diffie Hellman shares
+ * for the specified key exchange mechanisms.
+ *
+ * @param [in] groupType A type of PARCDiffieHellmanGroup
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCDiffieHellman` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * parcDiffieHellman_Release(&dh);
+ * }
+ * @endcode
+ */
+PARCDiffieHellman *parcDiffieHellman_Create(PARCDiffieHellmanGroup groupType);
+
+/**
+ * Increase the number of references to an instance of this object.
+ *
+ * Note that new instance is not created, only that the given instance's reference count
+ * is incremented. Discard the reference by invoking `parcDiffieHellman_Release()`.
+ *
+ * @param [in] dh A `PARCDiffieHellman` instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCDiffieHellman *dh = parcDiffieHellman_Acquire(dhInstance);
+ *
+ * parcDiffieHellman_Release(&dh);
+ * }
+ * @endcode
+ *
+ * @see parcDiffieHellman_Release
+ */
+PARCDiffieHellman *parcDiffieHellman_Acquire(const PARCDiffieHellman *dh);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] dhP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * parcDiffieHellman_Release(&dh);
+ * }
+ * @endcode
+ */
+void parcDiffieHellman_Release(PARCDiffieHellman **dhP);
+
+/*
+ * Generate a fresh Diffie Hellman key share.
+ *
+ * @param [in] dh A `PARCDiffieHellman` instance.
+ *
+ * @return A `PARCDiffieHellmanKeyShare` instnace.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellman_GenerateKeyShare(dh);
+ * // use the key share
+ *
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+PARCDiffieHellmanKeyShare *parcDiffieHellman_GenerateKeyShare(PARCDiffieHellman *dh);
+#endif // libparc_parc_DiffieHellman_h
diff --git a/libparc/parc/security/parc_DiffieHellmanGroup.h b/libparc/parc/security/parc_DiffieHellmanGroup.h
new file mode 100755
index 00000000..7402399e
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellmanGroup.h
@@ -0,0 +1,31 @@
+/*
+ * 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_DiffieHellmanGroup.h
+ * @ingroup security
+ * @brief An enumeration of the supported Diffie Hellman key exchange mechanisms.
+ *
+ */
+#ifndef libparc_parc_DiffieHellmanGroup_h
+#define libparc_parc_DiffieHellmanGroup_h
+
+typedef enum {
+ PARCDiffieHellmanGroup_Prime256v1, // NIST Prime-Curve P-256
+ PARCDiffieHellmanGroup_Secp521r1, // NIST Prime-Curve P-521
+ PARCDiffieHellmanGroup_Curve2559 // Curve2559
+} PARCDiffieHellmanGroup;
+
+#endif // libparc_parc_DiffieHellmanGroup_h
diff --git a/libparc/parc/security/parc_DiffieHellmanKeyShare.c b/libparc/parc/security/parc_DiffieHellmanKeyShare.c
new file mode 100644
index 00000000..250e5664
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellmanKeyShare.c
@@ -0,0 +1,297 @@
+/*
+ * 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/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_DiffieHellmanKeyShare.h>
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_CryptoHash.h>
+
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+
+struct parc_diffie_hellman_keyshare {
+ PARCDiffieHellmanGroup groupType;
+ EVP_PKEY *privateKey;
+};
+
+static bool
+_parcDiffieHellmanKeyShare_Destructor(PARCDiffieHellmanKeyShare **pointer)
+{
+ PARCDiffieHellmanKeyShare *share = *pointer;
+
+ if (share->privateKey != NULL) {
+ EVP_PKEY_free(share->privateKey);
+ }
+
+ return true;
+}
+
+parcObject_Override(PARCDiffieHellmanKeyShare, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcDiffieHellmanKeyShare_Destructor);
+
+parcObject_ImplementAcquire(parcDiffieHellmanKeyShare, PARCDiffieHellmanKeyShare);
+parcObject_ImplementRelease(parcDiffieHellmanKeyShare, PARCDiffieHellmanKeyShare);
+
+static EVP_PKEY *
+_parcDiffieHellmanKeyShare_CreateShare(int curveid)
+{
+ EVP_PKEY_CTX *pctx;
+ EVP_PKEY_CTX *kctx;
+
+ pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+ if (pctx == NULL) {
+ return NULL;
+ }
+
+ int result = EVP_PKEY_paramgen_init(pctx);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ return NULL;
+ }
+
+ result = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, curveid);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ return NULL;
+ }
+
+ EVP_PKEY *params = NULL;
+ result = EVP_PKEY_paramgen(pctx, &params);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ return NULL;
+ }
+
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+ if (kctx == NULL) {
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_free(params);
+ return NULL;
+ }
+
+ result = EVP_PKEY_keygen_init(kctx);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_free(params);
+ return NULL;
+ }
+
+ EVP_PKEY *pkey = NULL;
+ result = EVP_PKEY_keygen(kctx, &pkey);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+ return NULL;
+ }
+
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_CTX_free(kctx);
+ EVP_PKEY_free(params);
+
+ return pkey;
+}
+
+PARCDiffieHellmanKeyShare *
+parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup groupType)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcObject_CreateInstance(PARCDiffieHellmanKeyShare);
+
+ if (keyShare != NULL) {
+ keyShare->groupType = groupType;
+
+ switch (groupType) {
+ case PARCDiffieHellmanGroup_Prime256v1:
+ keyShare->privateKey = _parcDiffieHellmanKeyShare_CreateShare(NID_X9_62_prime256v1);
+ break;
+ case PARCDiffieHellmanGroup_Secp521r1:
+ keyShare->privateKey = _parcDiffieHellmanKeyShare_CreateShare(NID_secp521r1);
+ break;
+ case PARCDiffieHellmanGroup_Curve2559:
+ default:
+ break;
+ }
+
+ if (keyShare->privateKey == NULL) {
+ assertTrue(false, "Unable to instantiate a private key.");
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+ }
+ }
+
+ return keyShare;
+}
+
+PARCBuffer *
+parcDiffieHellmanKeyShare_SerializePublicKey(PARCDiffieHellmanKeyShare *keyShare)
+{
+ EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(keyShare->privateKey);
+
+ BN_CTX *bnctx = BN_CTX_new();
+ point_conversion_form_t form = EC_KEY_get_conv_form(ecKey);
+ const EC_POINT *point = EC_KEY_get0_public_key(ecKey);
+ const EC_GROUP *group = EC_KEY_get0_group(ecKey);
+ char *keyBuffer = EC_POINT_point2hex(group, point, form, bnctx);
+ int length = strlen(keyBuffer);
+
+ PARCBuffer *publicKey = parcBuffer_Allocate(length);
+ parcBuffer_PutArray(publicKey, length, (uint8_t *) keyBuffer);
+ parcBuffer_Flip(publicKey);
+
+ free(keyBuffer);
+ BN_CTX_free(bnctx);
+
+ return publicKey;
+}
+
+static EVP_PKEY *
+_parcDiffieHellman_DeserializePublicKeyShare(PARCDiffieHellmanKeyShare *keyShare, PARCBuffer *keyBuffer)
+{
+ EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(keyShare->privateKey);
+ const EC_GROUP *myGroup = EC_KEY_get0_group(ecKey);
+
+ EC_KEY *newKey = EC_KEY_new();
+ BN_CTX *newCtx = BN_CTX_new();
+ int result = EC_KEY_set_group(newKey, myGroup);
+ if (result != 1) {
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ return NULL;
+ }
+
+ EC_POINT *newPoint = EC_POINT_new(myGroup);
+ char *keyString = parcBuffer_ToString(keyBuffer);
+ newPoint = EC_POINT_hex2point(myGroup, keyString, newPoint, newCtx);
+ if (newPoint == NULL) {
+ parcMemory_Deallocate(&keyString);
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ EC_POINT_free(newPoint);
+ return NULL;
+ }
+
+ result = EC_KEY_set_public_key(newKey, newPoint);
+ if (result != 1) {
+ parcMemory_Deallocate(&keyString);
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ EC_POINT_free(newPoint);
+ return NULL;
+ }
+
+ EVP_PKEY *peerkey = EVP_PKEY_new();
+ result = EVP_PKEY_set1_EC_KEY(peerkey, newKey);
+ if (result != 1) {
+ parcMemory_Deallocate(&keyString);
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ EC_POINT_free(newPoint);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ parcMemory_Deallocate((void **) &keyString);
+ EC_POINT_free(newPoint);
+
+ return peerkey;
+}
+
+static PARCBuffer *
+_parcDiffieHellmanKeyShare_HashSharedSecret(PARCBuffer *secret)
+{
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBuffer(hasher, secret);
+ PARCCryptoHash *digest = parcCryptoHasher_Finalize(hasher);
+
+ PARCBuffer *sharedSecret = parcBuffer_Acquire(parcCryptoHash_GetDigest(digest));
+
+ parcCryptoHash_Release(&digest);
+ parcCryptoHasher_Release(&hasher);
+
+ return sharedSecret;
+}
+
+PARCBuffer *
+parcDiffieHellmanKeyShare_Combine(PARCDiffieHellmanKeyShare *keyShare, PARCBuffer *theirs)
+{
+ EVP_PKEY *peerkey = _parcDiffieHellman_DeserializePublicKeyShare(keyShare, theirs);
+ if (peerkey == NULL) {
+ return NULL;
+ }
+
+ EVP_PKEY *privateKey = keyShare->privateKey;
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(privateKey, NULL);
+ if (ctx == NULL) {
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ int result = EVP_PKEY_derive_init(ctx);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ result = EVP_PKEY_derive_set_peer(ctx, peerkey);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ size_t secretLength = 0;
+ result = EVP_PKEY_derive(ctx, NULL, &secretLength);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ unsigned char *secret = OPENSSL_malloc(secretLength);
+ if (secret == NULL) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ result = EVP_PKEY_derive(ctx, secret, &secretLength);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ OPENSSL_free(secret);
+ return NULL;
+ }
+
+ PARCBuffer *secretBuffer = parcBuffer_Allocate(secretLength);
+ parcBuffer_PutArray(secretBuffer, secretLength, secret);
+ parcBuffer_Flip(secretBuffer);
+
+ PARCBuffer *sharedSecret = _parcDiffieHellmanKeyShare_HashSharedSecret(secretBuffer);
+ parcBuffer_Release(&secretBuffer);
+
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ OPENSSL_free(secret);
+
+ return sharedSecret;
+}
diff --git a/libparc/parc/security/parc_DiffieHellmanKeyShare.h b/libparc/parc/security/parc_DiffieHellmanKeyShare.h
new file mode 100644
index 00000000..54e0f458
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellmanKeyShare.h
@@ -0,0 +1,151 @@
+/*
+ * 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_DiffieHellmanKeyShare.h
+ * @ingroup security
+ * @brief A Diffie Hellman key share.
+ *
+ */
+#ifndef libparc_parc_DiffieHellmanKeyShare_h
+#define libparc_parc_DiffieHellmanKeyShare_h
+
+#include <parc/security/parc_DiffieHellmanGroup.h>
+
+struct parc_diffie_hellman_keyshare;
+typedef struct parc_diffie_hellman_keyshare PARCDiffieHellmanKeyShare;
+
+/**
+ * Create a `PARCDiffieHellmanKeyShare` instance to hold one public and private
+ * Diffie Hellman key share for the specified group.
+ *
+ * @param [in] groupType A type of PARCDiffieHellmanGroup
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCDiffieHellmanKeyShare` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+PARCDiffieHellmanKeyShare *parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup groupType);
+
+/**
+ * Increase the number of references to an instance of this object.
+ *
+ * Note that new instance is not created, only that the given instance's reference count
+ * is incremented. Discard the reference by invoking `parcDiffieHellman_Release()`.
+ *
+ * @param [in] keyShare A `PARCDiffieHellmanKeyShare` instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Acquire(keyShareInstance);
+ *
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ *
+ * @see parcDiffieHellmanKeyShare_Release
+ */
+PARCDiffieHellmanKeyShare *parcDiffieHellmanKeyShare_Acquire(const PARCDiffieHellmanKeyShare *keyShare);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] keyShareP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Acquire(keyShareInstance);
+ *
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+void parcDiffieHellmanKeyShare_Release(PARCDiffieHellmanKeyShare **keyShareP);
+
+/**
+ * Serialize the public key part of a `PARCDiffieHellmanKeyShare.`
+ *
+ * The public key is saved to a `PARCBuffer` and can be used for transport if needed.
+ *
+ * @param [in] keyShare A `PARCDiffieHellmanKeyShare` instance.
+ *
+ * @return A `PARCBuffer` containing the public key of this key share.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ * // use the public key
+ *
+ * parcBuffer_Release(&publicKey);
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcDiffieHellmanKeyShare_SerializePublicKey(PARCDiffieHellmanKeyShare *keyShare);
+
+/**
+ * Combine a `PARCDiffieHellmanKeyShare` with an encoded public key to create a shared secret.
+ *
+ * @param [in] keyShare A `PARCDiffieHellmanKeyShare` instance.
+ * @param [in] publicShare The public key share to use to derive the shared secrect.
+ *
+ * @return A `PARCBuffer` containing the shared secret from the Diffie Hellman exchange.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ *
+ * ...
+ *
+ * PARCBuffer *sharedSecret = parcDiffieHellmanKeyShare_Combine(keyShare, publicKey);
+ * // use the shared secret to derive other cryptographic secrets.
+ *
+ * parcBuffer_Release(&sharedSecret);
+ * parcBuffer_Release(&publicKey);
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcDiffieHellmanKeyShare_Combine(PARCDiffieHellmanKeyShare *keyShare, PARCBuffer *publicShare);
+#endif // libparc_parc_DiffieHellmanKeyShare_h
diff --git a/libparc/parc/security/parc_Identity.c b/libparc/parc/security/parc_Identity.c
new file mode 100755
index 00000000..0afef9f7
--- /dev/null
+++ b/libparc/parc/security/parc_Identity.c
@@ -0,0 +1,116 @@
+/*
+ * 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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/security/parc_Identity.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+struct parc_identity {
+ void *instance;
+ const PARCIdentityInterface *interface;
+};
+
+static void
+_parcIdentity_Destroy(PARCIdentity **identityPtr)
+{
+ PARCIdentity *identity = *identityPtr;
+
+ identity->interface->Release(&identity->instance);
+}
+
+parcObject_ExtendPARCObject(PARCIdentity, _parcIdentity_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+bool
+parcIdentity_IsValid(const PARCIdentity *identity)
+{
+ bool result = false;
+
+ if (identity != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+void
+parcIdentity_AssertValid(const PARCIdentity *identity)
+{
+ trapInvalidValueIf(parcIdentity_IsValid(identity) == false, "PARCIdentity");
+}
+
+PARCIdentity *
+parcIdentity_Create(PARCObject *instance, const PARCIdentityInterface *interface)
+{
+ assertNotNull(interface, "Got null interface in parcIdentity_Create");
+
+ PARCIdentity *result = parcObject_CreateInstance(PARCIdentity);
+
+ result->instance = parcObject_Acquire(instance);
+ result->interface = interface;
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcIdentity, PARCIdentity);
+
+parcObject_ImplementRelease(parcIdentity, PARCIdentity);
+
+bool
+parcIdentity_Equals(const PARCIdentity *a, const PARCIdentity *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+ return a->interface->Equals(a->instance, b->instance);
+}
+
+
+const char *
+parcIdentity_GetFileName(const PARCIdentity *identity)
+{
+ return identity->interface->GetFileName(identity->instance);
+}
+
+const char *
+parcIdentity_GetPassWord(const PARCIdentity *identity)
+{
+ return identity->interface->GetPassWord(identity->instance);
+}
+
+PARCSigner *
+parcIdentity_CreateSigner(const PARCIdentity *identity)
+{
+ return identity->interface->GetSigner(identity->instance);
+}
+
+void
+parcIdentity_Display(const PARCIdentity *identity, int indentation)
+{
+ assertNotNull(identity->interface->Display, "Got null implementation in parcIdentity_Display");
+
+ parcDisplayIndented_PrintLine(indentation, "PARCIdentity@%p {", identity);
+ parcDisplayIndented_PrintLine(indentation, ".instance=");
+ identity->interface->Display(identity->instance, 1);
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+}
diff --git a/libparc/parc/security/parc_Identity.h b/libparc/parc/security/parc_Identity.h
new file mode 100755
index 00000000..d581b97d
--- /dev/null
+++ b/libparc/parc/security/parc_Identity.h
@@ -0,0 +1,342 @@
+/*
+ * 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_Identity.h
+ * @ingroup security
+ * @brief A generic cryptographic identity that is assigned to an entity
+ * (user, group, process) and is associated with a set of cryptographic
+ * material, e.g., public and private keys.
+ *
+ * Identities are used for authentication and authorization purposes.
+ * To illustrate their use, consider the following model. Digital signatures
+ * are computed with a private key owned by some entity. This private
+ * key is associated with an identity. It is said that the digital signature
+ * in this case was procured by an entity with the identity associated
+ * with the private key. Moreover, verifying this digital signature with
+ * the corresponding public key is analogous to verifying that the signature
+ * was generated by an entity with the corresponding identity.
+ *
+ * The relationship between identities and entities means that an entity may have
+ * multiple identities, each of which is associated with its own set of cryptographic
+ * information.
+ *
+ * Finally, an identity is typically backed by a file which stores the set of
+ * cryptographic material. For instance, once an identity may be represented as a
+ * PKCS12 (public and private) key store. Other concrete identity implementations
+ * may have different backing stores (i.e., not files, but services) with
+ * different notions of secret passwords.
+ *
+ */
+#ifndef libparc_parc_Identity_h
+#define libparc_parc_Identity_h
+
+#include <parc/algol/parc_Object.h>
+#include <parc/security/parc_Signer.h>
+
+struct parc_identity;
+typedef struct parc_identity PARCIdentity;
+
+typedef struct parc_identity_interface {
+ /**
+ * @see parcIdentity_Acquire
+ */
+ PARCIdentity *(*Acquire)(void *identity);
+
+ /**
+ * @see parcIdentity_Release
+ */
+ void (*Release)(void **identityPtr);
+
+ /**
+ * @see parcIdentity_GetPassWord
+ */
+ void *(*GetPassWord)(const void *original);
+
+ /**
+ * @see parcIdentity_GetFileName
+ */
+ void *(*GetFileName)(const void *original);
+
+ /**
+ * @see parcIdentity_CreateSigner
+ */
+ PARCSigner *(*GetSigner)(const void *identity);
+
+ /**
+ * @see parcIdentity_Equals
+ */
+ bool (*Equals)(const void *a, const void *b);
+
+ /**
+ * @see `parcIdentity_Display`
+ */
+ void (*Display)(const void *identity, size_t indentation);
+} PARCIdentityInterface;
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcIdentity_OptionalAssertValid(_instance_)
+#else
+# define parcIdentity_OptionalAssertValid(_instance_) parcIdentity_AssertValid(_instance_)
+#endif
+
+/**
+ * Determine if an instance of `PARCIdentity` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] identity A pointer to a `PARCIdentity` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *instance = parcIdentity_Create();
+ *
+ * if (parcIdentity_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcIdentity_IsValid(const PARCIdentity *identity);
+
+/**
+ * Assert that the given `PARCIdentity` instance is valid.
+ *
+ * @param [in] identity A pointer to a valid PARCIdentity instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *a = parcIdentity_Create();
+ *
+ * parcIdentity_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcIdentity_Release(&b);
+ * }
+ * @endcode
+ */
+void parcIdentity_AssertValid(const PARCIdentity *identity);
+
+/**
+ * Create an instance of PARCIdentity from the given pointer to a subtype
+ * and the subtype's `PARCIdentityInterface` instance.
+ *
+ * A new reference to @p instance is acquired.
+ *
+ * @param [in] instance A pointer to a suitable subtype of `PARCIdentity`.
+ * @param [in] interface A poitner to the subtype's `PARCIdentityInterface` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCIdentity` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ *
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+PARCIdentity *parcIdentity_Create(PARCObject *instance, const PARCIdentityInterface *interface);
+
+/**
+ * Increase the number of references to a `PARCIdentity` instance.
+ *
+ * Note that new `PARCIdentity` is not created,
+ * only that the given `PARCIdentity` reference count is incremented.
+ * Discard the reference by invoking `parcIdentity_Release`.
+ *
+ * @param [in] identity A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ * PARCIdentity *i2 = parcIdentity_Acquire(identity);
+ * // use both as needed
+ * parcIdentity_Release(&i2);
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ *
+ * @see parcIdentity_Release
+ */
+PARCIdentity *parcIdentity_Acquire(const PARCIdentity *identity);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] identityPtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ *
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+void parcIdentity_Release(PARCIdentity **identityPtr);
+
+/**
+ * Retrieve the file name associated with this identity.
+ *
+ * In the case of an identity file, this is the actual file name.
+ * Other concrete identity implementations may have different notions of secret passwords.
+ *
+ * NOTE: This function is set to be removed from the PARCIdentity API.
+ *
+ * @param [in] identity A `PARCIdentity` instance.
+ *
+ * @return A nul-terminated string containing the file name.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ * char *fileName = parcIdentity_GetFileName(identity);
+ * // use the filename
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+const char *parcIdentity_GetFileName(const PARCIdentity *identity);
+
+/**
+ * Retrieve the secret password associated with this identity..
+ *
+ * In the case of an identity file, the password will be one that opens the file for access.
+ * Other concrete identity implementations may have different notions of secret passwords.
+ *
+ * NOTE: This function is set to be removed from the PARCIdentity API.
+ *
+ * @param [in] identity A `PARCIdentity` instance.
+ *
+ * @return A character array containing the identity password.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ * char *pw = parcIdentity_GetPassWord(identity);
+ * // use the password pw
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+const char *parcIdentity_GetPassWord(const PARCIdentity *identity);
+
+/**
+ * Create an instance of `PARCSigner` from the given `PARCIdentity`.
+ *
+ * The `PARCSigner` instance must be released via `parcSignature_Release()`.
+ *
+ * @param [in] identity A pointer to a PARCIdentity instance.
+ *
+ * @return PARCSigner A newly allocated `PARCSigner` instance based off this identity.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ * PARCSigner *signer = parcIdentity_CreateSigner(identity);
+ *
+ * // use the signer as needed...
+ *
+ * parcSigner_Release(&signer);
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+PARCSigner *parcIdentity_CreateSigner(const PARCIdentity *identity);
+
+/**
+ * Determine if two PARCIdentity are equal.
+ *
+ * The following equivalence relations on non-null `XXX` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, parcIdentity_Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, PARCIdentity_Equals(x, y) must return true if and only if
+ * parcIdentity_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcIdentity_Equals(x, y) returns true and
+ * parcIdentity_Equals(y, z) returns true,
+ * then parcIdentity_Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcIdentity_Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, parcIdentity_Equals(x, NULL)) must return false.
+ *
+ * @param a A pointer to a PARCIdentity instance.
+ * @param b A pointer to a PARCIdentity instance.
+ * @return True if the referenced PARCIdentity are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *a = parcIdentity_Create(...);
+ * PARCIdentity *b = parcIdentity_Create(...);
+ * parcIdentity_Equals(a, b)
+ * if (parcIdentity_Equals(a, b)) {
+ * // this is expected
+ * } else {
+ * // this is not expected
+ * }
+ * parcIdentity_Release(&a);
+ * parcIdentity_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcIdentity_Equals(const PARCIdentity *a, const PARCIdentity *b);
+
+/**
+ * Print a human readable representation of the given `PARCIdentity`.
+ *
+ * @param [in] identity A pointer to the instance to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *instance = parcIdentity_Create(...);
+ *
+ * parcIdentity_Display(instance, 0);
+ *
+ * parcIdentity_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcIdentity_Display(const PARCIdentity *identity, int indentation);
+#endif // libparc_parc_Identity_h
diff --git a/libparc/parc/security/parc_IdentityFile.c b/libparc/parc/security/parc_IdentityFile.c
new file mode 100644
index 00000000..f5f6d067
--- /dev/null
+++ b/libparc/parc/security/parc_IdentityFile.c
@@ -0,0 +1,145 @@
+/*
+ * 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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <parc/security/parc_Identity.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+#include <parc/security/parc_IdentityFile.h>
+
+struct parc_identity_file {
+ const char *fileName;
+ const char *passWord;
+};
+
+PARCIdentityInterface *PARCIdentityFileAsPARCIdentity = &(PARCIdentityInterface) {
+ .Acquire = (PARCIdentity * (*)(void *))parcIdentityFile_Acquire,
+ .Release = (void (*)(void **))parcIdentityFile_Release,
+ .GetPassWord = (void *(*)(const void *))parcIdentityFile_GetPassWord,
+ .GetFileName = (void *(*)(const void *))parcIdentityFile_GetFileName,
+ .GetSigner = (PARCSigner * (*)(const void *))parcIdentityFile_CreateSigner,
+ .Equals = (bool (*)(const void *, const void *))parcIdentityFile_Equals,
+ .Display = (void (*)(const void *, size_t))parcIdentityFile_Display
+};
+
+void static
+_finalize(PARCIdentityFile **IdentityPtr)
+{
+ PARCIdentityFile *identity = *IdentityPtr;
+ parcMemory_Deallocate((void **) &(identity->fileName));
+ parcMemory_Deallocate((void **) &(identity->passWord));
+}
+
+
+parcObject_ExtendPARCObject(PARCIdentityFile, _finalize, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCIdentityFile *
+parcIdentityFile_Create(const char *fileName, const char *passWord)
+{
+ PARCIdentityFile *instance = parcObject_CreateInstance(PARCIdentityFile);
+
+ if (instance != NULL) {
+ instance->fileName = parcMemory_StringDuplicate(fileName, strlen(fileName));
+ instance->passWord = parcMemory_StringDuplicate(passWord, strlen(passWord));
+ }
+
+ return instance;
+}
+
+parcObject_ImplementAcquire(parcIdentityFile, PARCIdentityFile);
+
+parcObject_ImplementRelease(parcIdentityFile, PARCIdentityFile);
+
+bool
+parcIdentityFile_Exists(const PARCIdentityFile *identity)
+{
+ bool result = false;
+
+ struct stat statbuf;
+
+ if (stat(parcIdentityFile_GetFileName(identity), &statbuf) != -1) {
+ if (S_ISREG(statbuf.st_mode)) {
+ result = (access(parcIdentityFile_GetFileName(identity), F_OK | R_OK) == 0);
+ }
+ }
+
+ return result;
+}
+
+const char *
+parcIdentityFile_GetFileName(const PARCIdentityFile *identity)
+{
+ return identity->fileName;
+}
+
+const char *
+parcIdentityFile_GetPassWord(const PARCIdentityFile *identity)
+{
+ return identity->passWord;
+}
+
+PARCSigner *
+parcIdentityFile_CreateSigner(const PARCIdentityFile *identity)
+{
+ 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);
+ PARCSigner *pkSigner = parcSigner_Create(signer, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&signer);
+ parcKeyStore_Release(&publicKeyStore);
+
+ return pkSigner;
+}
+
+bool
+parcIdentityFile_Equals(const PARCIdentityFile *a, const PARCIdentityFile *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+ if (strcmp(parcIdentityFile_GetFileName(a), parcIdentityFile_GetFileName(b)) != 0) {
+ return false;
+ }
+ if (strcmp(parcIdentityFile_GetPassWord(a), parcIdentityFile_GetPassWord(b)) != 0) {
+ return false;
+ }
+ return true;
+}
+
+void
+parcIdentityFile_Display(const PARCIdentityFile *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCIdentityFile@%p {", instance);
+ parcDisplayIndented_PrintLine(indentation + 1, ".fileName='%s', .passWord='%s'", instance->fileName, instance->passWord);
+ parcDisplayIndented_PrintLine(indentation, "}", instance);
+}
diff --git a/libparc/parc/security/parc_IdentityFile.h b/libparc/parc/security/parc_IdentityFile.h
new file mode 100644
index 00000000..c5ee4ac5
--- /dev/null
+++ b/libparc/parc/security/parc_IdentityFile.h
@@ -0,0 +1,271 @@
+/*
+ * 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_IdentityFile.h
+ * @ingroup security
+ * @brief This is a PARCIdentity represented as a PKCS12 keystore file.
+ *
+ * To create these files, use the `parc-publickey` command line tool. Or you could also
+ * use `openssl` to create the same file.
+ *
+ * A `PARCIdentityFile` is a concrete instance of a `PARCIdentity`. To create a
+ * `PARCIdentity` from a `PARCIdentityFile`, one would do the following:
+ *
+ * @code
+ * {
+ * const char *keystoreName = "my_identity.p12";
+ * const char *keystorePassword = "my_password";
+ *
+ * // Create the concrete identity instance from the PKCS12 file
+ * PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ *
+ * // Create a generic `PARCIdentity` from the concrete identity instance
+ * PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ *
+ * // Now use the `PARCIdentity` for signing purposes (amongst other things)
+ * PARCSigner *signer = parcIdentity_GetSigner(identity);
+ * }
+ * @endcode
+ *
+ */
+#ifndef libparc_parc_IdentityFile_h
+#define libparc_parc_IdentityFile_h
+
+#include <parc/security/parc_Identity.h>
+
+struct parc_identity_file;
+typedef struct parc_identity_file PARCIdentityFile;
+
+/**
+ * The mapping of a PARCIdentityFile to the generic PARCIdentity.
+ */
+extern PARCIdentityInterface *PARCIdentityFileAsPARCIdentity;
+
+/**
+ * Create an instance of `PARCIdentityFile` from a given filename, and a password to unlock the stored information.
+ *
+ * The information is stored in PKCS 12 format.
+ *
+ * @param [in] fileName The name (relative path) to a file to be opened
+ * @param [in] password The password to be used to open the identity file
+ *
+ * @return NULL A `PARCIdentityFile` could not be allocated.
+ * @return PARCIdentityFile A newly allocated `PARCIdentityFile` that must be freed with `parcIdentityFile_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * ...
+ * parcIdentityFile_Release(&file);
+ * }
+ * @endcode
+ */
+PARCIdentityFile *parcIdentityFile_Create(const char *fileName, const char *password);
+
+/**
+ * Increase the number of references to the given `PARCIdentityFile` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking `parcIdentityFile_Release()`.
+ *
+ * @param [in] identity A pointer to a `PARCIdentityFile` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCIdentityFile instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * PARCIdentityFile *secondHandle = parcIdentityFile_Acquire(file);
+ * // use both handles as needed
+ * parcIdentityFile_Release(&file);
+ * parcIdentityFile_Release(&secondHandle);
+ * }
+ * @endcode
+ */
+PARCIdentityFile *parcIdentityFile_Acquire(const PARCIdentityFile *identity);
+
+/**
+ * Decrease the number of references to the given `PARCIdentityFile` instance.
+ *
+ * This only decrements the reference count so long as count >= 1. If the count
+ * reaches zero, the object's memory is freed. The content pointer is always
+ * NULLified after invocation.
+ *
+ * @param [in,out] identityPtr A pointer to a `PARCIdentityFile` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * // use handle as needed
+ * parcIdentityFile_Release(&file);
+ * }
+ * @endcode
+ */
+void parcIdentityFile_Release(PARCIdentityFile **identityPtr);
+
+/**
+ * Determine if the PARCIdentityFile exists.
+ *
+ * It must exist and be a regular file.
+ *
+ * @param [in] identity A pointer to a valid PARCIdentity instance.
+ *
+ * @return true The file exists and is a regular file.
+ * @return false The file does not exist (see errno values for stat(2)) or is not a regular file.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ *
+ * if (parcIdentityFile_Exists(file) == true) {
+ * printf("The file exists\n");
+ * } else {
+ * printf("The file does not exist fos\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcIdentityFile_Exists(const PARCIdentityFile *identity);
+
+/**
+ * Retrieve the name of the file associated with this `PARCIdentityFile` instance.
+ *
+ * @param [in] identity A pointer to a `PARCIdentityFile` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCIdentityFile instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * const char *fileName = parcIdentityFile_GetFileName(file);
+ * // use handle and/or file name as needed
+ * parcIdentityFile_Release(&file);
+ * }
+ * @endcode
+ */
+const char *parcIdentityFile_GetFileName(const PARCIdentityFile *identity);
+
+/**
+ * Retrieve the file password associated with this `PARCIdentityFile` instance.
+ *
+ * @param [in] identity A pointer to a `PARCIdentityFile` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCIdentityFile instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * const char *password = parcIdentityFile_GetPassWord(file);
+ * // use handle and/or file name as needed
+ * parcIdentityFile_Release(&file);
+ * }
+ * @endcode
+ */
+const char *parcIdentityFile_GetPassWord(const PARCIdentityFile *identity);
+
+/**
+ * Create an instance of `PARCSigner` from the given `PARCIdentity`
+ *
+ * @param [in] identity A pointer to a PARCIdentity instance.
+ *
+ * @return NULL An error occurred
+ * @return PARCSigner A new `PARCSigner` instance created using the identity file for the public/private signing keys
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * PARCSigner *signer = parcIdentityFile_GetSigner(file);
+ * parcIdentityFile_Release(&file);
+ * // use the signer
+ * parcSigner_Release(&signer);
+ * }
+ * @endcode
+ */
+PARCSigner *parcIdentityFile_CreateSigner(const PARCIdentityFile *identity);
+
+/**
+ * Determine if two PARCIdentityFiles are equal.
+ *
+ * The following equivalence relations on non-null `PARCIdentityFile` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, parcIdentityFile_Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, parcIdentityFile_Equals(x, y) must return true if and only if
+ * parcIdentityFile_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcIdentityFile_Equals(x, y) returns true and
+ * parcIdentityFile_Equals(y, z) returns true,
+ * then parcIdentityFile_Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcIdentityFile_Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, parcIdentityFile_Equals(x, NULL)) must return false.
+ *
+ * @param a A pointer to a PARCIdentityFile instance.
+ * @param b A pointer to a PARCIdentityFile instance.
+ * @return True if the referenced PARCIdentityFiles are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *a = parcIdentityFile_Create(...);
+ * PARCIdentityFile *b = parcIdentityFile_Create(...);
+ * if (parcIdentityFile_Equals(a, b)) {
+ * // this is expected
+ * } else {
+ * // this is not expected
+ * }
+ * parcIdentityFile_Release(&a);
+ * parcIdentityFile_Release(&b);
+ * }
+ *
+ * }
+ * @endcode
+ */
+bool parcIdentityFile_Equals(const PARCIdentityFile *a, const PARCIdentityFile *b);
+
+/**
+ * Print a human readable representation of the given `PARCIdentityFile`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] instance A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *instance = parcIdentityFile_Create("./secret.p12", "1234");
+ *
+ * parcIdentityFile_Display(instance, 0);
+ *
+ * parcIdentityFile_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcIdentityFile_Display(const PARCIdentityFile *instance, int indentation);
+#endif // libparc_parc_IdentityFile_h
diff --git a/libparc/parc/security/parc_InMemoryVerifier.c b/libparc/parc/security/parc_InMemoryVerifier.c
new file mode 100644
index 00000000..e5a9ba06
--- /dev/null
+++ b/libparc/parc/security/parc_InMemoryVerifier.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @header parc_InMemoryVerifier.c
+ * <#Abstract#>
+ *
+ * <#Discussion#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+#include <parc/security/parc_InMemoryVerifier.h>
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_CryptoCache.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <openssl/x509v3.h>
+
+struct parc_inmemory_verifier {
+ PARCCryptoHasher *hasher_sha256;
+ PARCCryptoHasher *hasher_sha512;
+ PARCCryptoCache *key_cache;
+};
+
+static bool
+_parcInMemoryVerifier_Destructor(PARCInMemoryVerifier **verifierPtr)
+{
+ PARCInMemoryVerifier *verifier = *verifierPtr;
+
+ parcCryptoHasher_Release(&(verifier->hasher_sha256));
+ parcCryptoHasher_Release(&(verifier->hasher_sha512));
+ parcCryptoCache_Destroy(&(verifier->key_cache));
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcInMemoryVerifier, PARCInMemoryVerifier);
+parcObject_ImplementRelease(parcInMemoryVerifier, PARCInMemoryVerifier);
+
+parcObject_Override(PARCInMemoryVerifier, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcInMemoryVerifier_Destructor);
+
+PARCInMemoryVerifier *
+parcInMemoryVerifier_Create()
+{
+ PARCInMemoryVerifier *verifier = parcObject_CreateInstance(PARCInMemoryVerifier);
+ if (verifier != NULL) {
+ // right now only support sha-256. need to figure out how to make this flexible
+ verifier->hasher_sha256 = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ verifier->hasher_sha512 = parcCryptoHasher_Create(PARCCryptoHashType_SHA512);
+ verifier->key_cache = parcCryptoCache_Create();
+ }
+
+ return verifier;
+}
+
+
+// ======================================
+
+static PARCCryptoHasher *
+_parcInMemoryVerifier_GetCryptoHasher(void *interfaceContext, PARCKeyId *keyid, PARCCryptoHashType hashType)
+{
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+
+ const PARCKey *key = parcCryptoCache_GetKey(verifier->key_cache, keyid);
+ if (key == NULL) {
+ return false;
+ }
+
+ assertFalse(parcKey_GetSigningAlgorithm(key) == PARCSigningAlgorithm_HMAC, "HMAC not supported yet");
+
+ switch (hashType) {
+ case PARCCryptoHashType_SHA256:
+ return verifier->hasher_sha256;
+
+ case PARCCryptoHashType_SHA512:
+ return verifier->hasher_sha512;
+
+ default:
+ trapUnexpectedState("unsupported hash type: %d", hashType);
+ }
+}
+
+static bool
+_parcInMemoryVerifier_AllowedCryptoSuite(void *interfaceContext, PARCKeyId *keyid, PARCCryptoSuite suite)
+{
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+
+ const PARCKey *key = parcCryptoCache_GetKey(verifier->key_cache, keyid);
+ if (key == NULL) {
+ return false;
+ }
+
+ switch (parcKey_GetSigningAlgorithm(key)) {
+ case PARCSigningAlgorithm_RSA:
+ switch (suite) {
+ case PARCCryptoSuite_RSA_SHA256:
+ return true;
+
+ case PARCCryptoSuite_RSA_SHA512:
+ return true;
+
+ default:
+ return false;
+ }
+ break;
+
+ case PARCSigningAlgorithm_DSA:
+ switch (suite) {
+ default:
+ return false;
+ }
+ break;
+
+ case PARCSigningAlgorithm_HMAC:
+ switch (suite) {
+ case PARCCryptoSuite_HMAC_SHA256:
+ return true;
+ default:
+ return false;
+ }
+ break;
+
+ default:
+ trapUnexpectedState("Unknown signing algorithm: %s",
+ parcSigningAlgorithm_ToString(parcKey_GetSigningAlgorithm(key)));
+ return false;
+ }
+
+ return false;
+}
+
+static bool _parcInMemoryVerifier_RSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash,
+ PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey);
+
+/**
+ * The signature verifies if:
+ * 0) we know the key for keyid
+ * 1) the signing algorithm of the key corresponding to keyid is same as CCNxSignature
+ * 2) The hash of the locallyComputedHash is the same type as the content object's ciphersuite
+ * 3) the signature verifies
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_parcInMemoryVerifier_VerifyDigest(void *interfaceContext, PARCKeyId *keyid, PARCCryptoHash *locallyComputedHash,
+ PARCCryptoSuite suite, PARCSignature *objectSignature)
+{
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+
+ const PARCKey *key = parcCryptoCache_GetKey(verifier->key_cache, keyid);
+ if (key == NULL) {
+ return false;
+ }
+
+ assertTrue(_parcInMemoryVerifier_AllowedCryptoSuite(interfaceContext, keyid, suite), "Invalid crypto suite for keyid");
+
+ if (parcKey_GetSigningAlgorithm(key) != parcSignature_GetSigningAlgorithm(objectSignature)) {
+ fprintf(stdout, "Signatured failed, signing algorithms do not match: key %s sig %s\n",
+ parcSigningAlgorithm_ToString(parcKey_GetSigningAlgorithm(key)),
+ parcSigningAlgorithm_ToString(parcSignature_GetSigningAlgorithm(objectSignature)));
+ return false;
+ }
+
+ if (parcCryptoHash_GetDigestType(locallyComputedHash) != parcCryptoSuite_GetCryptoHash(suite)) {
+ fprintf(stdout, "Signatured failed, digest algorithms do not match: digest %s suite %s\n",
+ parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(locallyComputedHash)),
+ parcCryptoHashType_ToString(parcCryptoSuite_GetCryptoHash(suite)));
+ return false;
+ }
+
+ switch (parcSignature_GetSigningAlgorithm(objectSignature)) {
+ case PARCSigningAlgorithm_RSA:
+ return _parcInMemoryVerifier_RSAKey_Verify(verifier, locallyComputedHash, objectSignature, parcKey_GetKey(key));
+
+ case PARCSigningAlgorithm_DSA:
+ trapNotImplemented("DSA not supported");
+ break;
+
+ case PARCSigningAlgorithm_HMAC:
+ trapNotImplemented("HMAC not supported");
+ break;
+
+ default:
+ trapUnexpectedState("Unknown signing algorithm: %d", parcSignature_GetSigningAlgorithm(objectSignature));
+ }
+
+
+ return false;
+}
+
+static void
+_parcInMemoryVerifier_AddKey(void *interfaceContext, PARCKey *key)
+{
+ assertNotNull(interfaceContext, "interfaceContext must be non-null");
+ assertNotNull(key, "key must be non-null");
+
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+ bool success = parcCryptoCache_AddKey(verifier->key_cache, key);
+ assertTrue(success, "could not add key, it must be a duplicate");
+}
+
+static void
+_parcInMemoryVerifier_RemoveKeyId(void *interfaceContext, PARCKeyId *keyid)
+{
+ assertNotNull(interfaceContext, "interfaceContent must be non-null");
+ assertNotNull(keyid, "key must be non-null");
+
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+ parcCryptoCache_RemoveKey(verifier->key_cache, keyid);
+}
+
+// ==============================================================
+// Openssl specific parts
+
+#ifdef __APPLE__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+/**
+ * Return if the signature and key verify with the local hash.
+ *
+ * PRECONDITION:
+ * - You know the signature and key are RSA.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_parcInMemoryVerifier_RSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash,
+ PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey)
+{
+ const uint8_t *der_bytes = parcByteArray_Array(parcBuffer_Array(derEncodedKey));
+
+ long der_length = parcBuffer_Remaining(derEncodedKey);
+ EVP_PKEY *unwrapped_key = d2i_PUBKEY(NULL, &der_bytes, der_length);
+
+ if (unwrapped_key != NULL) {
+ int success = 0;
+ RSA *rsa = EVP_PKEY_get1_RSA(unwrapped_key);
+
+ if (rsa != NULL) {
+ int openssl_digest_type;
+
+ switch (parcCryptoHash_GetDigestType(localHash)) {
+ case PARCCryptoHashType_SHA256:
+ openssl_digest_type = NID_sha256;
+ break;
+ case PARCCryptoHashType_SHA512:
+ openssl_digest_type = NID_sha512;
+ break;
+ default:
+ trapUnexpectedState("Unknown digest type: %s",
+ parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(localHash)));
+ }
+
+ PARCBuffer *sigbits = parcSignature_GetSignature(signatureToVerify);
+ PARCByteArray *bytearray = parcBuffer_Array(sigbits);
+ unsigned signatureLength = (unsigned) parcBuffer_Remaining(sigbits);
+ uint8_t *sigbuffer = parcByteArray_Array(bytearray);
+ size_t signatureOffset = parcBuffer_ArrayOffset(sigbits);
+
+ success = RSA_verify(openssl_digest_type,
+ (unsigned char *) parcByteArray_Array(parcBuffer_Array(parcCryptoHash_GetDigest(localHash))),
+ (unsigned) parcBuffer_Remaining(parcCryptoHash_GetDigest(localHash)),
+ sigbuffer + signatureOffset,
+ signatureLength,
+ rsa);
+ RSA_free(rsa);
+ }
+ EVP_PKEY_free(unwrapped_key);
+
+ if (success) {
+ return true;
+ }
+ }
+ return false;
+}
+
+PARCVerifierInterface *PARCInMemoryVerifierAsVerifier = &(PARCVerifierInterface) {
+ .GetCryptoHasher = _parcInMemoryVerifier_GetCryptoHasher,
+ .VerifyDigest = _parcInMemoryVerifier_VerifyDigest,
+ .AddKey = _parcInMemoryVerifier_AddKey,
+ .RemoveKeyId = _parcInMemoryVerifier_RemoveKeyId,
+ .AllowedCryptoSuite = _parcInMemoryVerifier_AllowedCryptoSuite,
+};
+
+#ifdef __APPLE__
+#pragma clang diagnostic pop
+#endif
diff --git a/libparc/parc/security/parc_InMemoryVerifier.h b/libparc/parc/security/parc_InMemoryVerifier.h
new file mode 100755
index 00000000..11dae09e
--- /dev/null
+++ b/libparc/parc/security/parc_InMemoryVerifier.h
@@ -0,0 +1,88 @@
+/*
+ * 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_InMemoryVerifier.h
+ * @ingroup security
+ * @brief In memory verifier
+ *
+ */
+#ifndef libparc_parc_InMemoryVerifier_h
+#define libparc_parc_InMemoryVerifier_h
+
+#include <parc/security/parc_Verifier.h>
+
+struct parc_inmemory_verifier;
+typedef struct parc_inmemory_verifier PARCInMemoryVerifier;
+
+/**
+ * Create an empty verifier. It's destroyed via the PARCVerifierInterface->Destroy call.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCInMemoryVerifier *parcInMemoryVerifier_Create(void);
+
+/**
+ * Increase the number of references to the given `PARCInMemoryVerifier` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking `parcInMemoryVerifier_Release()`.
+ *
+ * @param [in] signer A pointer to a `PARCInMemoryVerifier` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCInMemoryVerifier instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCInMemoryVerifier *verifier = parcInMemoryVerifier_Create();
+ * PARCInMemoryVerifier *handle = parcInMemoryVerifier_Acquire(signer);
+ * // use the handle instance as needed
+ * }
+ * @endcode
+ */
+PARCInMemoryVerifier *parcInMemoryVerifier_Acquire(const PARCInMemoryVerifier *verifier);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] verifierPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCInMemoryVerifier *verifier = parcInMemoryVerifier_Create();
+ *
+ * parcInMemoryVerifier_Release(&verifier);
+ * }
+ * @endcode
+ */
+void parcInMemoryVerifier_Release(PARCInMemoryVerifier **verifierPtr);
+#endif // libparc_parc_InMemoryVerifier_h
diff --git a/libparc/parc/security/parc_Key.c b/libparc/parc/security/parc_Key.c
new file mode 100755
index 00000000..06b85420
--- /dev/null
+++ b/libparc/parc/security/parc_Key.c
@@ -0,0 +1,205 @@
+/*
+ * 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 <config.h>
+
+#include <string.h>
+#include <stdio.h>
+
+#include <parc/security/parc_Key.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+
+struct parc_key {
+ PARCKeyId *keyid;
+ PARCSigningAlgorithm signingAlg;
+ PARCBuffer *key;
+};
+
+static void
+_parcKey_FinalRelease(PARCKey **keyP)
+{
+ if ((*keyP)->keyid != NULL) {
+ parcKeyId_Release(&(*keyP)->keyid);
+ }
+ if ((*keyP)->key != NULL) {
+ parcBuffer_Release(&(*keyP)->key);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCKey, _parcKey_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCKey *
+_parcKey_Create()
+{
+ PARCKey *key = parcObject_CreateInstance(PARCKey);
+ return key;
+}
+
+/**
+ * Create a Key for use with the specified signing algorithm.
+ *
+ * This method support Public Key alogirhtms
+ *
+ * For Public Key algorithms, the buffer should be a DER encoded key.
+ */
+PARCKey *
+parcKey_CreateFromDerEncodedPublicKey(PARCKeyId *keyid, PARCSigningAlgorithm signingAlg, PARCBuffer *derEncodedKey)
+{
+ assertNotNull(keyid, "Parameter keyid must be non-null");
+ assertNotNull(derEncodedKey, "Parameter derEncodedKey must be non-null");
+
+ // Exclude the symmetric key algorithms
+ switch (signingAlg) {
+ case PARCSigningAlgorithm_RSA: // fallthrough
+ case PARCSigningAlgorithm_DSA:
+ break;
+
+ default:
+ trapIllegalValueIf(true, "Unknown key algorithm or symmetric key algorithm: %s\n", parcSigningAlgorithm_ToString(signingAlg));
+ }
+
+ PARCKey *key = _parcKey_Create();
+ assertNotNull(key, "Unable to allocate memory for PARCKey");
+
+ key->key = parcBuffer_Acquire(derEncodedKey);
+ key->signingAlg = signingAlg;
+ key->keyid = parcKeyId_Acquire(keyid);
+ return key;
+}
+
+/**
+ * Create a Key for use with the specified signing algorithm.
+ *
+ * This method support HMAC with symmetric keys.
+ *
+ * The secretkey is a set of random bytes.
+ */
+PARCKey *
+parcKey_CreateFromSymmetricKey(PARCKeyId *keyid, PARCSigningAlgorithm signingAlg, PARCBuffer *secretkey)
+{
+ assertNotNull(keyid, "Parameter keyid must be non-null");
+ assertNotNull(secretkey, "Parameter derEncodedKey must be non-null");
+
+ // Exclude the symmetric key algorithms
+ switch (signingAlg) {
+ case PARCSigningAlgorithm_HMAC:
+ break;
+
+ default:
+ trapIllegalValueIf(true, "Unknown key algorithm or symmetric key algorithm: %s\n", parcSigningAlgorithm_ToString(signingAlg));
+ }
+
+ PARCKey *key = _parcKey_Create();
+ assertNotNull(key, "Unable to allocate memory for PARCKey");
+
+ key->key = parcBuffer_Acquire(secretkey);
+ key->signingAlg = signingAlg;
+ key->keyid = parcKeyId_Acquire(keyid);
+ return key;
+}
+
+/**
+ * Destroys the key, keyid, and key byte buffer
+ */
+
+parcObject_ImplementAcquire(parcKey, PARCKey);
+
+parcObject_ImplementRelease(parcKey, PARCKey);
+
+void
+parcKey_AssertValid(PARCKey *keyPtr)
+{
+ assertNotNull(keyPtr, "Parameter must be non-null double pointer");
+ assertNotNull(keyPtr->key, "Parameter key must not be null");
+ assertNotNull(keyPtr->keyid, "Parameter keyId must not be null");
+}
+
+PARCKeyId *
+parcKey_GetKeyId(const PARCKey *key)
+{
+ assertNotNull(key, "Parameter must be non-null");
+ return key->keyid;
+}
+
+PARCSigningAlgorithm
+parcKey_GetSigningAlgorithm(const PARCKey *key)
+{
+ assertNotNull(key, "Parameter must be non-null");
+ return key->signingAlg;
+}
+
+PARCBuffer *
+parcKey_GetKey(const PARCKey *key)
+{
+ assertNotNull(key, "Parameter must be non-null");
+ return key->key;
+}
+
+/**
+ * keyA equals keyB iff the KeyIds are equal, the SigningAlgs are equal, and the keys are equal.
+ * NULL equals NULL, but NULL does not equal any non-NULL
+ */
+bool
+parcKey_Equals(const PARCKey *keyA, const PARCKey *keyB)
+{
+ if (keyA == keyB) {
+ return true;
+ }
+
+ if (keyA == NULL || keyB == NULL) {
+ return false;
+ }
+
+ if (keyA->signingAlg == keyB->signingAlg) {
+ if (parcKeyId_Equals(keyA->keyid, keyB->keyid)) {
+ if (parcBuffer_Equals(keyA->key, keyB->key)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+PARCKey *
+parcKey_Copy(const PARCKey *original)
+{
+ PARCKey *newkey = _parcKey_Create();
+ assertNotNull(newkey, "Unable to allocate memory for a new key");
+ newkey->key = parcBuffer_Copy(original->key);
+ newkey->keyid = parcKeyId_Copy(original->keyid);
+ newkey->signingAlg = original->signingAlg;
+ return newkey;
+}
+
+char *
+parcKey_ToString(const PARCKey *key)
+{
+ char *string;
+ int failure = asprintf(&string, "PARCKey {.KeyID=\"%s\", .SigningAlgorithm=\"%s\" }",
+ parcKeyId_ToString(key->keyid),
+ parcSigningAlgorithm_ToString(key->signingAlg));
+ assertTrue(failure > -1, "Error asprintf");
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+
+ return result;
+}
diff --git a/libparc/parc/security/parc_Key.h b/libparc/parc/security/parc_Key.h
new file mode 100755
index 00000000..426405bb
--- /dev/null
+++ b/libparc/parc/security/parc_Key.h
@@ -0,0 +1,325 @@
+/*
+ * 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_Key.h
+ * @ingroup security
+ * @brief A `PARCKey` encapsulates a raw public (asymmetric) or private (symmetric) key.
+ *
+ * The PARC security library supports both public (asymmetric) digital signature and
+ * private (symmetric) MAC algorithms. A key is used in each such scheme for computing
+ * the signature or MAC. This type encapsulates both the raw key used in such schemes, but also
+ * a KeyId used to identify the key for hash-based data structures and the target signing/MAC
+ * scheme to which the key is applied.
+ *
+ */
+#include <parc/security/parc_KeyId.h>
+
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+#ifndef libparc_parc_Key_h
+#define libparc_parc_Key_h
+
+struct parc_key;
+typedef struct parc_key PARCKey;
+
+/**
+ * Increase the number of references to an instance of this object.
+ *
+ * Note that new instance is not created, only that the given instance's reference count
+ * is incremented. Discard the reference by invoking `parcKey_Release()`.
+ *
+ * @param [in] key A pointer to the original instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKey *key = parcKey_Acquire(keyInstance);
+ *
+ * parcKey_Release(&key);
+ * }
+ * @endcode
+ *
+ * @see parcKey_Release
+ */
+PARCKey *parcKey_Acquire(const PARCKey *key);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in] keyPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKey *key = parcKey_Acquire(keyInstance);
+ *
+ * parcKey_Release(&key);
+ * }
+ * @endcode
+ */
+void parcKey_Release(PARCKey **keyPtr);
+
+/**
+ * Check that the `PARCKey` instance is valid. It should be non-null,
+ * and any referenced data should also be valid.
+ *
+ * @param [in] key A pointer to the instance to check.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKey *key = parcKey_Acquire(keyInstance);
+ *
+ * parcKey_AssertValid(key);
+ * }
+ * @endcode
+ */
+void parcKey_AssertValid(PARCKey *key);
+
+/**
+ * Create a Key for use with the specified signing algorithm.
+ *
+ * This method supports Public Key algorithms. For such algorithms,
+ * the buffer should be a DER encoded key.
+ *
+ * @param [in] keyid A `PARCKeyId` instance for the new key
+ * @param [in] signingAlg The signing algorithm which is to be associated with this key
+ * @param [in] derEncodedKey The raw, DER-encoded key
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a new PARCKey instance that must be deallocated via `parcKey_Destory()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * // do stuff with key
+ * parcKey_Release(&key);
+ * }
+ */
+PARCKey *parcKey_CreateFromDerEncodedPublicKey(PARCKeyId *keyid, PARCSigningAlgorithm signingAlg, PARCBuffer *derEncodedKey);
+
+/**
+ * Create a Key for use with the specified signing algorithm.
+ *
+ * This method support HMAC with symmetric keys.
+ *
+ * The secretkey is a set of random bytes.
+ *
+ * @param [in] keyid A pointer to a PARCKeyId instance.
+ * @param [in] signingAlg A PARCSigningAlgorithm value (only MAC-like algorithms allowed)
+ * @param [in] secretkey A pointer to a PARCBuffer instance containing the secret key.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a new PARCKey instance that must be deallocated via `parcKey_Destory()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *symmetricKey = ....;
+ * PARCKey *key = parcKey_CreateFromSymmetricKey(keyid, PARCSigningAlgorithm_HMAC, symmetricKey);
+ * parcBuffer_Release(&symmetricKey);
+ * parcKeyId_Destroy(&keyid);
+ * // do stuff with key
+ * parcKey_Release(&key);
+ * }
+ * @endcode
+ *
+ * @see parcKey_Destory
+ */
+PARCKey *parcKey_CreateFromSymmetricKey(PARCKeyId *keyid, PARCSigningAlgorithm signingAlg, PARCBuffer *secretkey);
+
+/**
+ * Create an independent, deep-copy of the given instance.
+ *
+ * A new instance is created as a complete,
+ * independent copy of the original such that `Equals(original, copy) == true`.
+ *
+ * @param [in] key A pointer to a `PARCKey` instance.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a new PARCKey instance that must be deallocated via `parcKey_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * PARCKey *copy = parcKey_Copy(key);
+ * // do stuff with the key copy, which is equals to the original key instance
+ * parcKey_Release(&key);
+ * parcKey_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCKey *parcKey_Copy(const PARCKey *key);
+
+/**
+ * Determine if two `PARCKey` instances are equal.
+ * Two instances of PARCKey are equal iff the key digests are equal,
+ * the signing algorithms are equal, and the keys are equal.
+ *
+ * Two NULL keys are equal, but NULL does not equal any non-NULL
+ *
+ * The following equivalence relations on non-null `XXX` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `Equals(x, y)` must return true if and only if
+ * `Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `Equals(x, y)` returns true and
+ * `Equals(y, z)` returns true,
+ * then `Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `Equals(x, NULL)` must return false.
+ *
+ * @param [in] keyA A pointer to a `PARCKey` instance.
+ * @param [in] keyB A pointer to a `PARCKey` instance.
+ *
+ * @return true `PARCKey` keyA and keyB are equal.
+ * @return false `PARCKey` keyA and keyB are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKey *keyA = parcKey_Create(...);
+ * PARCKey *keyB = parcKey_Create(...);
+ *
+ * if (parcBuffer_Equals(keyA, keyB)) {
+ * printf("Keys are equal.\n");
+ * } else {
+ * printf("Keys are NOT equal.\n");
+ * }
+ *
+ * parcKey_Release(&bufferA);
+ * parcKey_Release(&bufferB);
+ * }
+ * @endcode
+ */
+bool parcKey_Equals(const PARCKey *keyA, const PARCKey *keyB);
+
+/**
+ * Retrieve the `PARCKeyId` associated with the specified `PARCKey` instance.
+ *
+ * You must Aqcuire your own reference if you will store the key.
+ * Do not release this instance.
+ *
+ * @param [in] key A pointer to the `PARCKey` instance
+ *
+ * @return PARCKeyId A pointer to the `PARCKeyId` associated with this `PARCKey` instance. A handle is not acquired.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * PARCKeyId *innerKeyId = parcKey_GetKeyId(key);
+ * // use the innerKeyId as needed - DO NOT RELEASE IT via parcKeyId_Release()
+ * }
+ * @endcode
+ */
+PARCKeyId *parcKey_GetKeyId(const PARCKey *key);
+
+/**
+ * Retrieve the `PARCSigningAlgorithm` associated with the specified `PARCKey` instance.
+ *
+ * @param [in] key A pointer to the `PARCKey` instance
+ *
+ * @return PARCSigningAlgorithm A PARCSigningAlgorithm value
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * PARCSigningAlgorithm signingAlg = parcKey_GetSigningAlgorithm(key);
+ * // use the signingAlg value as needed
+ * }
+ * @endcode
+ */
+PARCSigningAlgorithm parcKey_GetSigningAlgorithm(const PARCKey *key);
+
+/**
+ * Returns the key's instance of the key buffer.
+ *
+ * You must Aqcuire your own reference if you will store the key.
+ * Do not release this instance.
+ *
+ * @param [in] key A pointer to the `PARCKey` instance
+ *
+ * @return PARCBuffer A pointer to the `PARCBuffer` associated with this `PARCKey` instance. A handle is not acquired.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * PARCBuffer *innerKey = parcKey_GetKey(key);
+ * // use the innerKey as needed - DO NOT RELEASE IT via parcBuffer_Release()
+ * }
+ * @endcode
+ */
+PARCBuffer *parcKey_GetKey(const PARCKey *key);
+
+/**
+ * Create a null-terminated string representation of the given `PARCKey`.
+ *
+ * The returned value must be freed by the caller using {@link parcMemory_Deallocate()}.
+ *
+ * @param [in] link A pointer to a `PARCKey` instance.
+ * @return A pointer to null-terminated string of characters that must be freed by the caller by `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *parcKey_ToString(const PARCKey *key);
+#endif // libparc_parc_Key_h
diff --git a/libparc/parc/security/parc_KeyId.c b/libparc/parc/security/parc_KeyId.c
new file mode 100755
index 00000000..1dbd9512
--- /dev/null
+++ b/libparc/parc/security/parc_KeyId.c
@@ -0,0 +1,141 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_KeyId.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Hash.h>
+
+struct parc_keyid {
+ PARCBuffer *keyid;
+ PARCHashCode hashcode;
+};
+
+static void
+_parcKeyId_Destroy(PARCKeyId **keyIdPtr)
+{
+ PARCKeyId *keyId = *keyIdPtr;
+
+ parcBuffer_Release(&keyId->keyid);
+}
+
+parcObject_ExtendPARCObject(PARCKeyId, _parcKeyId_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+void
+parcKeyId_AssertValid(const PARCKeyId *keyId)
+{
+ assertNotNull(keyId, "Pointer must be a non-null pointer to a PARCKeyId");
+}
+
+PARCKeyId *
+parcKeyId_Create(PARCBuffer *preComputedKeyId)
+{
+ PARCKeyId *keyid = parcObject_CreateInstance(PARCKeyId);
+
+ if (keyid != NULL) {
+ keyid->keyid = parcBuffer_Acquire(preComputedKeyId);
+ keyid->hashcode = parcBuffer_HashCode(preComputedKeyId);
+ }
+ return keyid;
+}
+
+parcObject_ImplementAcquire(parcKeyId, PARCKeyId);
+parcObject_ImplementRelease(parcKeyId, PARCKeyId);
+
+bool
+parcKeyId_Equals(const PARCKeyId *keyidA, const PARCKeyId *keyidB)
+{
+ if (keyidA == keyidB) {
+ return true;
+ }
+
+ if (keyidA == NULL || keyidB == NULL) {
+ return false;
+ }
+
+ return parcBuffer_Equals(keyidA->keyid, keyidB->keyid);
+}
+
+PARCHashCode
+parcKeyId_HashCode(const PARCKeyId *keyid)
+{
+ parcKeyId_OptionalAssertValid(keyid);
+
+ return keyid->hashcode;
+}
+
+PARCHashCode
+parcKeyId_HashCodeFromVoid(const void *keyid)
+{
+ parcKeyId_OptionalAssertValid(keyid);
+
+ return ((PARCKeyId *) keyid)->hashcode;
+}
+
+const PARCBuffer *
+parcKeyId_GetKeyId(const PARCKeyId *keyid)
+{
+ parcKeyId_OptionalAssertValid(keyid);
+
+ return keyid->keyid;
+}
+
+PARCKeyId *
+parcKeyId_Copy(const PARCKeyId *original)
+{
+ parcKeyId_OptionalAssertValid(original);
+
+ PARCBuffer *bufferCopy = parcBuffer_Copy(original->keyid);
+ PARCKeyId *result = parcKeyId_Create(bufferCopy);
+ parcBuffer_Release(&bufferCopy);
+ return result;
+}
+
+PARCBufferComposer *
+parcKeyId_BuildString(const PARCKeyId *keyid, PARCBufferComposer *composer)
+{
+ // output format = "0x<hex>\00"
+ parcBufferComposer_Format(composer, "0x");
+ for (int i = 0; i < parcBuffer_Capacity(keyid->keyid); i += 2) {
+ parcBufferComposer_Format(composer, "%02X", parcBuffer_GetAtIndex(keyid->keyid, i));
+ }
+ return composer;
+}
+
+char *
+parcKeyId_ToString(const PARCKeyId *keyid)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ parcKeyId_BuildString(keyid, composer);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ }
+ return result;
+}
diff --git a/libparc/parc/security/parc_KeyId.h b/libparc/parc/security/parc_KeyId.h
new file mode 100755
index 00000000..daa2a2fe
--- /dev/null
+++ b/libparc/parc/security/parc_KeyId.h
@@ -0,0 +1,348 @@
+/*
+ * 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_KeyId.h
+ * @ingroup security
+ * @brief Represent a key by an octet string
+ *
+ * A KeyId is a hash digest used to identify a key. These are used as key entries in hash-table
+ * based key stores that cache raw keys. Instead of transferring raw keys, parties may exchange
+ * KeyIds used to index into key stores for constant-time key retrieval. This exchange
+ * expects that the raw key will be present in the key store. If not, the lookup will fail.
+ * Consequently, KeyIds are not used to encapsulate or transfer raw keys.
+ *
+ */
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+#ifndef libparc_parc_KeyId_h
+#define libparc_parc_KeyId_h
+
+struct parc_keyid;
+/**
+ * @typedef PARCKeyId
+ * @brief A KeyId is a hash digest used to identify a key.
+ */
+
+typedef struct parc_keyid PARCKeyId;
+
+/**
+ * @def parcKeyId_OptionalAssertValid
+ * Optional validation of the given instance.
+ *
+ * Define `PARCLibrary_DISABLE_VALIDATION` to disable validation.
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcKeyId_OptionalAssertValid(_instance_)
+#else
+# define parcKeyId_OptionalAssertValid(_instance_) parcKeyId_AssertValid(_instance_)
+#endif
+
+/**
+ * Create a `PARCKeyId` from the given pre-computed-key identifier.
+ *
+ * A reference to the given identifer is created and the caller is responsible for releasing the remaining references.
+ *
+ * @param [in] preComputedKeyId A pointer to a `PARCBuffer` instance containing the pre-computed-key identifier.
+ * @return A pointer to an allocated `PARCKeyId` that must be released via `parcKeyId_Release`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *keybits = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *keyid = parcKeyId_Create(keybits);
+ * parcBuffer_Release(&keybits);
+ * // do something with keyid
+ * parcKeyId_Release(&keyid);
+ * }
+ * @endcode
+ */
+PARCKeyId *parcKeyId_Create(PARCBuffer *preComputedKeyId);
+
+/**
+ * Increase the number of references to a `PARCKeyId`.
+ *
+ * Note that new `PARCKeyId` is not created,
+ * only that the given `PARCKeyId` reference count is incremented.
+ * Discard the reference by invoking `parcKeyId_Release`.
+ *
+ * @param [in] instance A pointer to the instance of `PARCKeyId`.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *instance = parcKeyId_CreateFromByteBuffer(buffer);
+ * parcBuffer_Release(&buffer);
+ *
+ * PARCKeyId *reference = parcKeyId_Acquire(instance);
+ *
+ * parcKeyId_Release(&instance);
+ * parcKeyId_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see parcKeyId
+ */
+PARCKeyId *parcKeyId_Acquire(const PARCKeyId *instance);
+
+/**
+ * Assert a valid PARCKeyId instance.
+ *
+ * @param [in] keyId A pointer to a `PARCKeyId` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *instance = parcKeyId_CreateFromByteBuffer(buffer);
+ * parcBuffer_Release(&buffer);
+ *
+ * parcKeyId_AssertValid(&instance);
+ * parcKeyId_Release(&instance);
+ * }
+ * @endcode
+ * @see parcKeyId_OptionalAssertValid
+ */
+void parcKeyId_AssertValid(const PARCKeyId *keyId);
+
+/**
+ * Create a copy of the KeyId from the specified `PARCKeyId` instance.
+ *
+ * A deep copy is performed, acquiring handles to objects when needed.
+ *
+ * @param [in] original A pointer to a `PARCKeyId` instance containing the pre-computerd-key identifier.
+ * @return A pointer to a newly allocated `PARCKeyId` that must be released via `parcKeyId_Release`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *keybits = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *keyid = parcKeyId_Create(keybits);
+ * parcBuffer_Release(&keybits);
+ * // do something with keyid
+ * parcKeyId_Release(&keyid);
+ * }
+ * @endcode
+ */
+PARCKeyId *parcKeyId_Copy(const PARCKeyId *original);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] object A pointer to a pointer to the `PARCKeyId` instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *instance = parcKeyId_CreateFromByteBuffer(buffer);
+ * parcBuffer_Release(&buffer);
+ *
+ * parcKeyId_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcKeyId_Release(PARCKeyId **object);
+
+/**
+ * Determine if two `PARCKeyId` instances are equal.
+ *
+ * Two `PARCKeyId` instances are equal if, and only if,
+ *
+ * The following equivalence relations on non-null `PARCKeyId` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcKeyId_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcKeyId_Equals(x, y)` must return true if and only if
+ * `parcKeyId_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcKeyId_Equals(x, y)` returns true and
+ * `parcKeyId_Equals(y, z)` returns true,
+ * then `parcKeyId_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcKeyId_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcKeyId_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `PARCKeyId` instance.
+ * @param b A pointer to a `PARCKeyId` instance.
+ * @return true if the two `PARCKeyId` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKeyId *a = parcKeyId_Create(...);
+ * PARCKeyId *b = parcKeyId_Create(...);
+ *
+ * if (parcKeyId_Equals(a, b)) {
+ * // equal
+ * } else {
+ * // unequal
+ * }
+ * }
+ * @endcode
+ */
+bool parcKeyId_Equals(const PARCKeyId *a, const PARCKeyId *b);
+
+/**
+ * Get the digest bytes of a `PARCKeyId` instance;
+ *
+ * @param [in] keyid A pointer to a `PARCKeyId` instance.
+ *
+ * @return A pointer to a (shared) {@link PARCBuffer} instance containing the digest bytes of the `PARCKeyId`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *instance = parcKeyId_CreateFromByteBuffer(buffer);
+ * PARCBuffer *bytes = parcKeyId_GetKeyId(instance);
+ * // use or display the bytes buffer as needed
+ * }
+ * @endcode
+ */
+const PARCBuffer *parcKeyId_GetKeyId(const PARCKeyId *keyid);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `parcKeyId_HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an
+ * execution of an application,
+ * the {@link parcKeyId_HashCode} function must consistently return the same value,
+ * provided no information used in a corresponding {@link parcKeyId_Equals}
+ * comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to
+ * another execution of the same application.
+ * If two instances are equal according to the {@link parcKeyId_Equals} function,
+ * then calling the {@link parcKeyId_HashCode} function on each of the two instances must
+ * produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcKeyId_Equals} function,
+ * then calling the {@link parcKeyId_HashCode}
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] keyid A pointer to the `PARCKeyId` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKeyId *x = parcKeyId_Create(...);
+ * uint32_t hashValue = parcKeyId_HashCode(array);
+ * parcKeyId_Release(&x);
+ * }
+ * @endcode
+ */
+PARCHashCode parcKeyId_HashCode(const PARCKeyId *keyid);
+
+/**
+ * Compute a non-cryptographic hash of a `PARCKeyId` instance from a void pointer.
+ *
+ * This is useful for use in {@link PARCHashCodeTable}.
+ *
+ * @param [in] keyId A pointer to the instance to be hashed
+ *
+ * @return A 32-bit non-cryptographic hash of the instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKeyId *x = parcKeyId_Create(...);
+ * uint32_t hash = parcKeyId_HashCode((void*)x);
+ * // use the hash to index into a table, or something else
+ * }
+ * @endcode
+ *
+ * @see parcKeyId_HashCode
+ */
+PARCHashCode parcKeyId_HashCodeFromVoid(const void *keyId);
+
+/**
+ * Append a representation of the specified instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * @param [in] keyId A pointer to a `PARCKeyId` instance.
+ * @param [in] composer A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcKeyId_BuildString(instance, result);
+ *
+ * char *string = parcBuffer_ToString(parcBufferComposer_ProduceBuffer(result));
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcKeyId_BuildString(const PARCKeyId *keyId, PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to the instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated,
+ * null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKeyId *instance = parcKeyId_Create(...);
+ *
+ * char *string = parcKeyId_ToString(instance);
+ *
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ *
+ * parcKeyId_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcKeyId_BuildString
+ */
+char *parcKeyId_ToString(const PARCKeyId *instance);
+#endif // libparc_parc_KeyId_h
diff --git a/libparc/parc/security/parc_KeyStore.c b/libparc/parc/security/parc_KeyStore.c
new file mode 100755
index 00000000..912861d1
--- /dev/null
+++ b/libparc/parc/security/parc_KeyStore.c
@@ -0,0 +1,104 @@
+/*
+ * 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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_KeyStore.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_key_store {
+ PARCObject *instance;
+ const PARCKeyStoreInterface *interface;
+};
+
+static bool
+_parcKeyStore_Destructor(PARCKeyStore **keyStorePtr)
+{
+ PARCKeyStore *keyStore = *keyStorePtr;
+ if (keyStore->interface != NULL && keyStore->instance != NULL) {
+ parcObject_Release(&keyStore->instance);
+ }
+
+ return true;
+}
+
+parcObject_Override(PARCKeyStore, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcKeyStore_Destructor);
+
+parcObject_ImplementAcquire(parcKeyStore, PARCKeyStore);
+parcObject_ImplementRelease(parcKeyStore, PARCKeyStore);
+
+PARCKeyStore *
+parcKeyStore_Create(PARCObject *instance, const PARCKeyStoreInterface *interface)
+{
+ PARCKeyStore *keyStore = parcObject_CreateInstance(PARCKeyStore);
+
+ if (keyStore != NULL) {
+ keyStore->instance = parcObject_Acquire(instance);
+ keyStore->interface = interface;
+ }
+
+ return keyStore;
+}
+
+PARCCryptoHash *
+parcKeyStore_GetVerifierKeyDigest(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getVerifierKeyDigest(interfaceContext->instance);
+ }
+ return NULL;
+}
+
+PARCCryptoHash *
+parcKeyStore_GetCertificateDigest(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getCertificateDigest(interfaceContext->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcKeyStore_GetDEREncodedCertificate(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getDEREncodedCertificate(interfaceContext->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcKeyStore_GetDEREncodedPublicKey(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getDEREncodedPublicKey(interfaceContext->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcKeyStore_GetDEREncodedPrivateKey(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getDEREncodedPrivateKey(interfaceContext->instance);
+ }
+ return NULL;
+}
diff --git a/libparc/parc/security/parc_KeyStore.h b/libparc/parc/security/parc_KeyStore.h
new file mode 100755
index 00000000..03be78af
--- /dev/null
+++ b/libparc/parc/security/parc_KeyStore.h
@@ -0,0 +1,348 @@
+/*
+ * 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_KeyStore.h
+ * @ingroup security
+ * @brief A container of Key Store information.
+ *
+ * A Key Store is a repository of key information typically accessable
+ * through some authentication and authorisation system.
+ * The PARCKeyStore type contains the necessary information to successfully
+ * gain access to a Key Store.
+ *
+ */
+#ifndef libparc_parc_KeyStore_h
+#define libparc_parc_KeyStore_h
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CryptoHash.h>
+
+struct parc_key_store;
+typedef struct parc_key_store PARCKeyStore;
+
+/**
+ * The hash of the signer's public key (or secret key for HMAC).
+ *
+ * Try using `parcSigner_CreateKeyId` for a sinterfaceer interface.
+ * You must destroy the returned PARCCryptoHash.
+ * For public key, its the SHA256 digest of the public key.
+ * For HMAC, its the SHA256 digest of the secret key.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A PARCCryptoHash value.
+ */
+typedef PARCCryptoHash *(PARCKeyStoreGetVerifierKeyDigest)(const void *interfaceContext);
+
+/**
+ * Returns a copy of the the certificate digest.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate used by the signer.
+ */
+typedef PARCCryptoHash *(PARCKeyStoreGetCertificateDigest)(const void *interfaceContext);
+
+/**
+ * Returns a copy of the DER encoded certificate.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded certificate.
+ */
+typedef PARCBuffer *(PARCKeyStoreGetDEREncodedCertificate)(const void *interfaceContext);
+
+/**
+ * Returns a copy of the encoded public key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded public key.
+ */
+typedef PARCBuffer *(PARCKeyStoreGetDEREncodedPublicKey)(const void *interfaceContext);
+
+/**
+ * Returns a copy of the encoded private key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -out test_rsa.der`
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded private key.
+ */
+typedef PARCBuffer *(PARCKeyStoreGetDEREncodedPrivateKey)(const void *interfaceContext);
+
+
+typedef struct parc_keystore_interface {
+ /**
+ * The hash of the signer's public key (or secret key for HMAC).
+ *
+ * Try using `parcSigner_CreateKeyId` for a sinterfaceer interface.
+ * You must destroy the returned PARCCryptoHash.
+ * For public key, its the SHA256 digest of the public key.
+ * For HMAC, its the SHA256 digest of the secret key.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A PARCCryptoHash value.
+ */
+ PARCKeyStoreGetVerifierKeyDigest *getVerifierKeyDigest;
+
+ /**
+ * Returns a copy of the the certificate digest.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate used by the signer.
+ */
+ PARCKeyStoreGetCertificateDigest *getCertificateDigest;
+
+ /**
+ * Returns a copy of the DER encoded certificate.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded certificate.
+ */
+ PARCKeyStoreGetDEREncodedCertificate *getDEREncodedCertificate;
+
+ /**
+ * Returns a copy of the encoded public key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded public key.
+ */
+ PARCKeyStoreGetDEREncodedPublicKey *getDEREncodedPublicKey;
+
+ /**
+ * Returns a copy of the encoded private key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -out test_rsa.der`
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded private key.
+ */
+ PARCKeyStoreGetDEREncodedPrivateKey *getDEREncodedPrivateKey;
+} PARCKeyStoreInterface;
+
+/**
+ * Create a `PARCKeyStore` from a filename.
+ *
+ * @param [in] instance A concrete instance of a `PARCKeyStore.`
+ * @param [in] interface The interface for the `PARCKeyStore.`
+ *
+ * @return A pointer to the new `PARCKeyStore`
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCKeyStore *parcKeyStore_Create(PARCObject *instance, const PARCKeyStoreInterface *interface);
+
+/**
+ * Increase the number of references to an instance of this object.
+ *
+ * Note that new instance is not created, only that the given instance's reference count
+ * is incremented. Discard the reference by invoking `parcKeyStore_Release()`.
+ *
+ * @param [in] keyStore A pointer to the original instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKeyStore *keyStore = parcKeyStore_Acquire(keyStoreInstance);
+ *
+ * parcKeyStore_Release(&keyStore);
+ * }
+ * @endcode
+ *
+ * @see parcKey_Release
+ */
+PARCKeyStore *parcKeyStore_Acquire(const PARCKeyStore *keyStore);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in] keyStorePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKeyStore *keyStore = parcKeyStore_Acquire(keyStoreInstance);
+ *
+ * parcKeyStore_Release(&keyStore);
+ * }
+ * @endcode
+ */
+void parcKeyStore_Release(PARCKeyStore **keyStorePtr);
+
+/**
+ * The hash of the signer's public key (or secret key for HMAC).
+ *
+ * Try using `parcSigner_CreateKeyId` for a sinterfaceer interface.
+ * You must destroy the returned PARCCryptoHash.
+ * For public key, its the SHA256 digest of the public key.
+ * For HMAC, its the SHA256 digest of the secret key.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A PARCCryptoHash value.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcKeyStore_GetVerifierKeyDigest(const PARCKeyStore *interfaceContext);
+
+/**
+ * Returns a copy of the the certificate digest.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate used by the signer.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcKeyStore_GetCertificateDigest(const PARCKeyStore *interfaceContext);
+
+/**
+ * Returns a copy of the DER encoded certificate.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCBuffer *parcKeyStore_GetDEREncodedCertificate(const PARCKeyStore *interfaceContext);
+
+/**
+ * Returns a copy of the encoded public key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded public key.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCBuffer *parcKeyStore_GetDEREncodedPublicKey(const PARCKeyStore *interfaceContext);
+
+/**
+ * Returns a copy of the encoded private key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -out test_rsa.der`
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded private key.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCBuffer *parcKeyStore_GetDEREncodedPrivateKey(const PARCKeyStore *interfaceContext);
+#endif // libparc_parc_KeyStore_h
diff --git a/libparc/parc/security/parc_Pkcs12KeyStore.c b/libparc/parc/security/parc_Pkcs12KeyStore.c
new file mode 100644
index 00000000..4b9693b5
--- /dev/null
+++ b/libparc/parc/security/parc_Pkcs12KeyStore.c
@@ -0,0 +1,372 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/longBow_Compiler.h>
+
+#include <parc/algol/parc_Object.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_Certificate.h>
+#include <parc/security/parc_CertificateFactory.h>
+#include <parc/security/parc_CertificateType.h>
+#include <parc/security/parc_ContainerEncoding.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+
+struct parc_pkcs12_keystore {
+ EVP_PKEY *private_key;
+ EVP_PKEY *public_key;
+ X509 *x509_cert;
+
+ // These will be 0 length until asked for
+ PARCBuffer *public_key_digest;
+ PARCBuffer *certificate_digest;
+ PARCBuffer *public_key_der;
+ PARCBuffer *certificate_der;
+ PARCBuffer *private_key_der;
+
+ PARCCryptoHashType hashType;
+ PARCCryptoHasher *hasher;
+};
+
+static bool
+_parcPkcs12KeyStore_Finalize(PARCPkcs12KeyStore **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCPublicKeySigner pointer.");
+ PARCPkcs12KeyStore *keystore = *instancePtr;
+
+ EVP_PKEY_free(keystore->private_key);
+ EVP_PKEY_free(keystore->public_key);
+ X509_free(keystore->x509_cert);
+
+ if (keystore->public_key_digest != NULL) {
+ parcBuffer_Release(&keystore->public_key_digest);
+ }
+ if (keystore->certificate_digest != NULL) {
+ parcBuffer_Release(&keystore->certificate_digest);
+ }
+ if (keystore->public_key_der != NULL) {
+ parcBuffer_Release(&keystore->public_key_der);
+ }
+ if (keystore->certificate_der != NULL) {
+ parcBuffer_Release(&keystore->certificate_der);
+ }
+ if (keystore->private_key_der != NULL) {
+ parcBuffer_Release(&keystore->private_key_der);
+ }
+
+ parcCryptoHasher_Release(&(keystore->hasher));
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcPkcs12KeyStore, PARCPkcs12KeyStore);
+parcObject_ImplementRelease(parcPkcs12KeyStore, PARCPkcs12KeyStore);
+parcObject_Override(PARCPkcs12KeyStore, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcPkcs12KeyStore_Finalize);
+
+static int
+_parcPkcs12KeyStore_ParseFile(PARCPkcs12KeyStore *keystore, const char *filename, const char *password)
+{
+ parcSecurity_AssertIsInitialized();
+
+ FILE *fp = fopen(filename, "rb");
+
+ assertNotNull(fp, "Error opening %s: %s", filename, strerror(errno));
+ if (fp == NULL) {
+ return -1;
+ }
+
+ PKCS12 *p12Keystore = NULL;
+ d2i_PKCS12_fp(fp, &p12Keystore);
+ fclose(fp);
+
+ int success = PKCS12_parse(p12Keystore, password, &keystore->private_key, &keystore->x509_cert, NULL);
+ PKCS12_free(p12Keystore);
+
+ if (!success) {
+ unsigned long errcode;
+ while ((errcode = ERR_get_error()) != 0) {
+ fprintf(stderr, "openssl error: %s\n", ERR_error_string(errcode, NULL));
+ }
+ return -1;
+ }
+
+ keystore->public_key = X509_get_pubkey(keystore->x509_cert);
+ return 0;
+}
+
+// =============================================================
+LONGBOW_STOP_DEPRECATED_WARNINGS
+// =============================================================
+
+bool
+parcPkcs12KeyStore_CreateFile(
+ const char *filename,
+ const char *password,
+ const char *subjectName,
+ unsigned keyLength,
+ unsigned validityDays)
+{
+ parcSecurity_AssertIsInitialized();
+
+ bool result = false;
+
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_DER);
+
+ PARCBuffer *privateKeyBuffer;
+ PARCCertificate *certificate = parcCertificateFactory_CreateSelfSignedCertificate(factory, &privateKeyBuffer, (char *) subjectName, 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);
+
+ if (pkcs12 != NULL) {
+ int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
+ if (fd != -1) {
+ FILE *fp = fdopen(fd, "wb");
+ if (fp != NULL) {
+ i2d_PKCS12_fp(fp, pkcs12);
+ fclose(fp);
+ result = true;
+ } else {
+ trapUnrecoverableState("Cannot fdopen(3) the file descriptor %d", fd);
+ }
+ close(fd);
+ } else {
+ 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) {
+ fprintf(stderr, "openssl error: %s\n", ERR_error_string(errcode, NULL));
+ }
+ trapUnrecoverableState("PKCS12_create returned a NULL value.");
+ }
+ }
+
+ return result;
+}
+
+PARCPkcs12KeyStore *
+parcPkcs12KeyStore_Open(const char *filename, const char *password, PARCCryptoHashType hashType)
+{
+ PARCPkcs12KeyStore *keyStore = parcObject_CreateAndClearInstance(PARCPkcs12KeyStore);
+ if (keyStore != NULL) {
+ keyStore->hasher = parcCryptoHasher_Create(hashType);
+ keyStore->public_key_digest = NULL;
+ keyStore->certificate_digest = NULL;
+ keyStore->public_key_der = NULL;
+ keyStore->certificate_der = NULL;
+ keyStore->hashType = hashType;
+
+ if (_parcPkcs12KeyStore_ParseFile(keyStore, filename, password) != 0) {
+ parcPkcs12KeyStore_Release(&keyStore);
+ }
+ }
+
+ return keyStore;
+}
+
+
+static PARCCryptoHash *
+_GetPublickKeyDigest(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+ if (keystore->public_key_digest == NULL) {
+ AUTHORITY_KEYID *akid = X509_get_ext_d2i(keystore->x509_cert, NID_authority_key_identifier, NULL, NULL);
+ if (akid != NULL) {
+ ASN1_OCTET_STRING *skid = X509_get_ext_d2i(keystore->x509_cert, NID_subject_key_identifier, NULL, NULL);
+ if (skid != NULL) {
+ keystore->public_key_digest =
+ parcBuffer_PutArray(parcBuffer_Allocate(skid->length), skid->length, skid->data);
+ parcBuffer_Flip(keystore->public_key_digest);
+ ASN1_OCTET_STRING_free(skid);
+ }
+ AUTHORITY_KEYID_free(akid);
+ }
+ }
+
+ // If we could not load the digest from the certificate, then calculate it from the public key.
+ if (keystore->public_key_digest == NULL) {
+ uint8_t digestBuffer[SHA256_DIGEST_LENGTH];
+
+ int result = ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY),
+ EVP_sha256(),
+ X509_get_X509_PUBKEY(keystore->x509_cert),
+ digestBuffer,
+ NULL);
+ if (result != 1) {
+ assertTrue(0, "Could not compute digest over certificate public key");
+ } else {
+ keystore->public_key_digest =
+ parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, digestBuffer);
+ parcBuffer_Flip(keystore->public_key_digest);
+ }
+ }
+
+ // This stores a reference, so keystore->public_key_digest will remain valid
+ // even if the cryptoHasher is destroyed
+ return parcCryptoHash_Create(PARCCryptoHashType_SHA256, keystore->public_key_digest);
+}
+
+static PARCCryptoHash *
+_GetCertificateDigest(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+ if (keystore->certificate_digest == NULL) {
+ uint8_t digestBuffer[SHA256_DIGEST_LENGTH];
+ int result = X509_digest(keystore->x509_cert, EVP_sha256(), digestBuffer, NULL);
+ if (result) {
+ keystore->certificate_digest =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, digestBuffer));
+ }
+ }
+
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, keystore->certificate_digest);
+ return hash;
+}
+
+static PARCBuffer *
+_GetDEREncodedCertificate(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+ if (keystore->certificate_der == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_X509(keystore->x509_cert, &der);
+ if (derLength > 0) {
+ keystore->certificate_der =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return parcBuffer_Copy(keystore->certificate_der);
+}
+
+static PARCBuffer *
+_GetDEREncodedPublicKey(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+ if (keystore->public_key_der == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_PUBKEY(keystore->public_key, &der);
+ if (derLength > 0) {
+ keystore->public_key_der =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return parcBuffer_Copy(keystore->public_key_der);
+}
+
+static PARCBuffer *
+_GetDEREncodedPrivateKey(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+ if (keystore->private_key_der == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_PrivateKey(keystore->private_key, &der);
+ if (derLength > 0) {
+ keystore->private_key_der =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return parcBuffer_Copy(keystore->private_key_der);
+}
+
+PARCKeyStoreInterface *PARCPkcs12KeyStoreAsKeyStore = &(PARCKeyStoreInterface) {
+ .getVerifierKeyDigest = (PARCKeyStoreGetVerifierKeyDigest *) _GetPublickKeyDigest,
+ .getCertificateDigest = (PARCKeyStoreGetCertificateDigest *) _GetCertificateDigest,
+ .getDEREncodedCertificate = (PARCKeyStoreGetDEREncodedCertificate *) _GetDEREncodedCertificate,
+ .getDEREncodedPublicKey = (PARCKeyStoreGetDEREncodedPublicKey *) _GetDEREncodedPublicKey,
+ .getDEREncodedPrivateKey = (PARCKeyStoreGetDEREncodedPrivateKey *) _GetDEREncodedPrivateKey,
+};
+
+// =============================================================
+LONGBOW_START_DEPRECATED_WARNINGS
+// =============================================================
diff --git a/libparc/parc/security/parc_Pkcs12KeyStore.h b/libparc/parc/security/parc_Pkcs12KeyStore.h
new file mode 100644
index 00000000..ed04c702
--- /dev/null
+++ b/libparc/parc/security/parc_Pkcs12KeyStore.h
@@ -0,0 +1,134 @@
+/*
+ * 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_Pkcs12KeyStore.h
+ * @ingroup security
+ * @brief A concrete implementation of PARCKeyStore based on a PCKS12 keystore.
+ *
+ */
+#ifndef libparc_parc_Pkcs12KeyStore_h
+#define libparc_parc_Pkcs12KeyStore_h
+
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_Signer.h>
+
+struct parc_pkcs12_keystore;
+typedef struct parc_pkcs12_keystore PARCPkcs12KeyStore;
+
+extern PARCKeyStoreInterface *PARCPkcs12KeyStoreAsKeyStore;
+
+/**
+ * Increase the number of references to a `PARCPublicKeySigner` instance.
+ *
+ * Note that new `PARCPublicKeySigner` is not created,
+ * only that the given `PARCPublicKeySigner` reference count is incremented.
+ * Discard the reference by invoking `parcPublicKeySigner_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * parcPkcs12KeyStore_CreateFile(...);
+ * PARCPkcs12KeyStore *a = parcPkcs12Store_Open(...)
+ *
+ * PARCPkcs12KeyStore *b = parcPkcs12KeyStore_Acquire();
+ *
+ * parcPkcs12KeyStore_Release(&a);
+ * parcPkcs12KeyStore_Release(&b);
+ * }
+ * @endcode
+ */
+PARCPkcs12KeyStore *parcPkcs12KeyStore_Acquire(const PARCPkcs12KeyStore *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCPkcs12KeyStore` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPkcs12KeyStore *a = parcPkcs12Store_Open(...);
+ *
+ * parcPkcs12KeyStore_Release(&a);
+ * }
+ * @endcode
+ */
+void parcPkcs12KeyStore_Release(PARCPkcs12KeyStore **instancePtr);
+
+/**
+ * Creates a PKCS12 keystore identity with a self-signed certifiate. Note that this call currently
+ * aborts if keystore i/o access fails, behavior that may change in the future.
+ *
+ * @param [in] filename The name of the PKCS12 file.
+ * @param [in] password The password to open the PKCS12 file.
+ * @param [in] subjectName The certificate subject associated with the PKCS12 file.
+ * @param [in] keyLength The length of the public key associated with the PKCS12 file.
+ * @param [in] validityDays The validity (in days) of the certificate associated with the PKCS12 file.
+ *
+ * @return true on success, false if certificate creation fails, and will abort if keystore i/o fails.
+ *
+ * Example:
+ * @code
+ * {
+ * 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);
+ * }
+ * @endcode
+ */
+bool parcPkcs12KeyStore_CreateFile(const char *filename, const char *password, const char *subjectName,
+ unsigned keyLength, unsigned validityDays);
+
+/**
+ * Create a `PARCPkcs12KeyStore` instance.
+ *
+ * @param [in] filename The name of a file containing the PKCS12 keystore.
+ * @param [in] password The password to decrypt/unlock the determines how the signer digests data. Supports PARCCryptoHashType_SHA256 and PARCCryptoHashType_SHA512.
+ * @param [in] hashType Determines how the signer digests data. Possible values are PARCCryptoHashType_SHA256 and PARCCryptoHashType_SHA512.
+ *
+ * @return A `PARCPkcs12KeyStore` instance using the public/private key pair contained within the PKCS12 file.
+ *
+ * Example:
+ * @code
+ * {
+ * 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);
+ *
+ * ...
+ *
+ * PARCSigningInterface *interface = parcPublicKeySignerPkcs12Store_Open(filename, password, PARCCryptoHashType_SHA256);
+ *
+ * ...
+ * }
+ * @endcode
+ */
+PARCPkcs12KeyStore *parcPkcs12KeyStore_Open(const char *filename, const char *password, PARCCryptoHashType hashType);
+
+#endif // libparc_parc_PublicKeySignerPkcs12Store_h
diff --git a/libparc/parc/security/parc_PublicKeySigner.c b/libparc/parc/security/parc_PublicKeySigner.c
new file mode 100644
index 00000000..6411f075
--- /dev/null
+++ b/libparc/parc/security/parc_PublicKeySigner.c
@@ -0,0 +1,228 @@
+/*
+ * 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 <config.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_Security.h>
+
+#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+
+struct PARCPublicKeySigner {
+ PARCKeyStore *keyStore;
+ PARCSigningAlgorithm signingAlgorithm;
+ PARCCryptoHashType hashType;
+ PARCCryptoHasher *hasher;
+};
+
+static bool
+_parcPublicKeySigner_Finalize(PARCPublicKeySigner **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCPublicKeySigner pointer.");
+
+ PARCPublicKeySigner *instance = *instancePtr;
+
+ if (instance->keyStore != NULL) {
+ parcKeyStore_Release(&(instance->keyStore));
+ }
+ if (instance->hasher != NULL) {
+ parcCryptoHasher_Release(&(instance->hasher));
+ }
+
+ return true;
+}
+
+void
+parcPublicKeySigner_AssertValid(const PARCPublicKeySigner *instance)
+{
+ assertTrue(parcPublicKeySigner_IsValid(instance), "PARCPublicKeySigner is not valid.");
+}
+
+bool
+parcPublicKeySigner_Equals(const PARCPublicKeySigner *x, const PARCPublicKeySigner *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (x->signingAlgorithm == y->signingAlgorithm) {
+ if (x->hashType == y->hashType) {
+ return true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcPublicKeySigner_HashCode(const PARCPublicKeySigner *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcPublicKeySigner_IsValid(const PARCPublicKeySigner *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+char *
+parcPublicKeySigner_ToString(const PARCPublicKeySigner *instance)
+{
+ char *result = parcMemory_Format("PARCPublicKeySigner@%p\n", instance);
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcPublicKeySigner, PARCPublicKeySigner);
+parcObject_ImplementRelease(parcPublicKeySigner, PARCPublicKeySigner);
+
+parcObject_Override(PARCPublicKeySigner, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcPublicKeySigner_Finalize,
+ .toString = (PARCObjectToString *) parcPublicKeySigner_ToString,
+ .equals = (PARCObjectEquals *) parcPublicKeySigner_Equals,
+ .hashCode = (PARCObjectHashCode *) parcPublicKeySigner_HashCode);
+
+PARCPublicKeySigner *
+parcPublicKeySigner_Create(PARCKeyStore *keyStore, PARCSigningAlgorithm signingAlgorithm, PARCCryptoHashType hashType)
+{
+ PARCPublicKeySigner *result = parcObject_CreateInstance(PARCPublicKeySigner);
+
+ if (result != NULL) {
+ result->keyStore = parcKeyStore_Acquire(keyStore);
+ result->signingAlgorithm = signingAlgorithm;
+ result->hashType = hashType;
+ result->hasher = parcCryptoHasher_Create(hashType);
+ }
+
+ return result;
+}
+
+static PARCSigningAlgorithm
+_GetSigningAlgorithm(PARCPublicKeySigner *interfaceContext)
+{
+ return PARCSigningAlgorithm_RSA;
+}
+
+static PARCCryptoHashType
+_GetCryptoHashType(PARCPublicKeySigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null PARCCryptoHasher");
+ return signer->hashType;
+}
+
+static PARCCryptoHasher *
+_GetCryptoHasher(PARCPublicKeySigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null PARCCryptoHasher");
+ return signer->hasher;
+}
+
+static PARCKeyStore *
+_GetKeyStore(PARCPublicKeySigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null PARCCryptoHasher");
+ return signer->keyStore;
+}
+
+static PARCSignature *
+_SignDigest(PARCPublicKeySigner *signer, const PARCCryptoHash *digestToSign)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(signer, "Parameter must be non-null CCNxFileKeystore");
+ assertNotNull(digestToSign, "Buffer to sign must not be null");
+
+ // TODO: what is the best way to expose this?
+ PARCKeyStore *keyStore = signer->keyStore;
+ PARCBuffer *privateKeyBuffer = parcKeyStore_GetDEREncodedPrivateKey(keyStore);
+ EVP_PKEY *privateKey = NULL;
+ size_t keySize = parcBuffer_Remaining(privateKeyBuffer);
+ uint8_t *bytes = parcBuffer_Overlay(privateKeyBuffer, keySize);
+ privateKey = d2i_PrivateKey(EVP_PKEY_RSA, &privateKey, (const unsigned char **) &bytes, keySize);
+ parcBuffer_Release(&privateKeyBuffer);
+
+ RSA *rsa = EVP_PKEY_get1_RSA(privateKey);
+
+ int opensslDigestType;
+
+ switch (parcCryptoHash_GetDigestType(digestToSign)) {
+ case PARCCryptoHashType_SHA256:
+ opensslDigestType = NID_sha256;
+ break;
+ case PARCCryptoHashType_SHA512:
+ opensslDigestType = NID_sha512;
+ break;
+ default:
+ trapUnexpectedState("Unknown digest type: %s",
+ parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(digestToSign)));
+ }
+
+ uint8_t *sig = parcMemory_Allocate(RSA_size(rsa));
+ assertNotNull(sig, "parcMemory_Allocate(%u) returned NULL", RSA_size(rsa));
+
+ unsigned sigLength = 0;
+ PARCBuffer *bb_digest = parcCryptoHash_GetDigest(digestToSign);
+ int result = RSA_sign(opensslDigestType,
+ (unsigned char *) parcByteArray_Array(parcBuffer_Array(bb_digest)),
+ (int) parcBuffer_Remaining(bb_digest),
+ sig,
+ &sigLength,
+ rsa);
+ assertTrue(result == 1, "Got error from RSA_sign: %d", result);
+ RSA_free(rsa);
+
+ PARCBuffer *bbSign = parcBuffer_Allocate(sigLength);
+ parcBuffer_Flip(parcBuffer_PutArray(bbSign, sigLength, sig));
+ parcMemory_Deallocate((void **) &sig);
+
+ PARCSignature *signature =
+ parcSignature_Create(_GetSigningAlgorithm(signer),
+ parcCryptoHash_GetDigestType(digestToSign),
+ bbSign
+ );
+ parcBuffer_Release(&bbSign);
+ return signature;
+}
+
+PARCSigningInterface *PARCPublicKeySignerAsSigner = &(PARCSigningInterface) {
+ .GetCryptoHasher = (PARCCryptoHasher * (*)(void *))_GetCryptoHasher,
+ .SignDigest = (PARCSignature * (*)(void *, const PARCCryptoHash *))_SignDigest,
+ .GetSigningAlgorithm = (PARCSigningAlgorithm (*)(void *))_GetSigningAlgorithm,
+ .GetCryptoHashType = (PARCCryptoHashType (*)(void *))_GetCryptoHashType,
+ .GetKeyStore = (PARCKeyStore * (*)(void *))_GetKeyStore,
+};
diff --git a/libparc/parc/security/parc_PublicKeySigner.h b/libparc/parc/security/parc_PublicKeySigner.h
new file mode 100644
index 00000000..d2803418
--- /dev/null
+++ b/libparc/parc/security/parc_PublicKeySigner.h
@@ -0,0 +1,341 @@
+/*
+ * 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_PublicKeySigner.h
+ * @brief An entity to produce digital signatures based on public/private key stores.
+ *
+ */
+#ifndef PARCLibrary_parc_PublicKeySigner
+#define PARCLibrary_parc_PublicKeySigner
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+#include <parc/security/parc_Signer.h>
+
+struct PARCPublicKeySigner;
+typedef struct PARCPublicKeySigner PARCPublicKeySigner;
+
+extern PARCSigningInterface *PARCPublicKeySignerAsSigner;
+
+/**
+ * Increase the number of references to a `PARCPublicKeySigner` instance.
+ *
+ * Note that new `PARCPublicKeySigner` is not created,
+ * only that the given `PARCPublicKeySigner` reference count is incremented.
+ * Discard the reference by invoking `parcPublicKeySigner_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * PARCPublicKeySigner *b = parcPublicKeySigner_Acquire();
+ *
+ * parcPublicKeySigner_Release(&a);
+ * parcPublicKeySigner_Release(&b);
+ * }
+ * @endcode
+ */
+PARCPublicKeySigner *parcPublicKeySigner_Acquire(const PARCPublicKeySigner *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcPublicKeySigner_OptionalAssertValid(_instance_)
+#else
+# define parcPublicKeySigner_OptionalAssertValid(_instance_) parcPublicKeySigner_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCPublicKeySigner` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * parcPublicKeySigner_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcPublicKeySigner_Release(&b);
+ * }
+ * @endcode
+ */
+void parcPublicKeySigner_AssertValid(const PARCPublicKeySigner *instance);
+
+/**
+ * Create an instance of PARCPublicKeySigner
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCPublicKeySigner instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCPublicKeySigner *parcPublicKeySigner_Create(PARCKeyStore *keyStore, PARCSigningAlgorithm signingAlgorithm, PARCCryptoHashType hashType);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ * @param [in] other A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ * PARCPublicKeySigner *b = parcPublicKeySigner_Create();
+ *
+ * if (parcPublicKeySigner_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcPublicKeySigner_Release(&a);
+ * parcPublicKeySigner_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcPublicKeySigner_Equals
+ */
+int parcPublicKeySigner_Compare(const PARCPublicKeySigner *instance, const PARCPublicKeySigner *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCPublicKeySigner` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * PARCPublicKeySigner *copy = parcPublicKeySigner_Copy(&b);
+ *
+ * parcPublicKeySigner_Release(&b);
+ * parcPublicKeySigner_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCPublicKeySigner *parcPublicKeySigner_Copy(const PARCPublicKeySigner *original);
+
+/**
+ * Determine if two `PARCPublicKeySigner` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCPublicKeySigner` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcPublicKeySigner_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcPublicKeySigner_Equals(x, y)` must return true if and only if
+ * `parcPublicKeySigner_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcPublicKeySigner_Equals(x, y)` returns true and
+ * `parcPublicKeySigner_Equals(y, z)` returns true,
+ * then `parcPublicKeySigner_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcPublicKeySigner_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcPublicKeySigner_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCPublicKeySigner instance.
+ * @param [in] y A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ * PARCPublicKeySigner *b = parcPublicKeySigner_Create();
+ *
+ * if (parcPublicKeySigner_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcPublicKeySigner_Release(&a);
+ * parcPublicKeySigner_Release(&b);
+ * }
+ * @endcode
+ * @see parcPublicKeySigner_HashCode
+ */
+bool parcPublicKeySigner_Equals(const PARCPublicKeySigner *x, const PARCPublicKeySigner *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcPublicKeySigner_Equals} method,
+ * then calling the {@link parcPublicKeySigner_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcPublicKeySigner_Equals} function,
+ * then calling the `parcPublicKeySigner_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * PARCHashCode hashValue = parcPublicKeySigner_HashCode(buffer);
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcPublicKeySigner_HashCode(const PARCPublicKeySigner *instance);
+
+/**
+ * Determine if an instance of `PARCPublicKeySigner` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * if (parcPublicKeySigner_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcPublicKeySigner_IsValid(const PARCPublicKeySigner *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCPublicKeySigner` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+void parcPublicKeySigner_Release(PARCPublicKeySigner **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * PARCJSON *json = parcPublicKeySigner_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcPublicKeySigner_ToJSON(const PARCPublicKeySigner *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCPublicKeySigner`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * char *string = parcPublicKeySigner_ToString(a);
+ *
+ * parcPublicKeySigner_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcPublicKeySigner_Display
+ */
+char *parcPublicKeySigner_ToString(const PARCPublicKeySigner *instance);
+#endif
diff --git a/libparc/parc/security/parc_SecureRandom.c b/libparc/parc/security/parc_SecureRandom.c
new file mode 100644
index 00000000..8ebf7f0f
--- /dev/null
+++ b/libparc/parc/security/parc_SecureRandom.c
@@ -0,0 +1,123 @@
+/*
+ * 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 <config.h>
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_SecureRandom.h>
+
+struct parc_securerandom {
+ int randomfd;
+};
+
+static bool
+_parcSecureRandom_Destructor(PARCSecureRandom **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCSecureRandom pointer.");
+ PARCSecureRandom *instance = *instancePtr;
+
+ close(instance->randomfd);
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcSecureRandom, PARCSecureRandom);
+parcObject_ImplementRelease(parcSecureRandom, PARCSecureRandom);
+parcObject_Override(PARCSecureRandom, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcSecureRandom_Destructor);
+
+void
+parcSecureRandom_AssertValid(const PARCSecureRandom *instance)
+{
+ assertTrue(parcSecureRandom_IsValid(instance),
+ "PARCSecureRandom is not valid.");
+}
+
+PARCSecureRandom *
+parcSecureRandom_Create()
+{
+ PARCSecureRandom *result = NULL;
+
+ int fd = open("/dev/urandom", O_RDWR);
+ if (fd != -1) {
+ result = parcObject_CreateInstance(PARCSecureRandom);
+ if (result != NULL) {
+ result->randomfd = fd;
+ } else {
+ close(fd);
+ }
+ }
+
+ return result;
+}
+
+static void
+_parcSecureRandom_ReSeed(PARCSecureRandom *random, PARCBuffer *buffer)
+{
+ size_t length = parcBuffer_Remaining(buffer);
+ write(random->randomfd, parcBuffer_Overlay(buffer, length), length);
+}
+
+PARCSecureRandom *
+parcSecureRandom_CreateWithSeed(PARCBuffer *seed)
+{
+ PARCSecureRandom *result = parcSecureRandom_Create();
+
+ if (result != NULL) {
+ _parcSecureRandom_ReSeed(result, seed);
+ }
+
+ return result;
+}
+
+uint32_t
+parcSecureRandom_Next(PARCSecureRandom *random)
+{
+ uint32_t value;
+ read(random->randomfd, &value, sizeof(value));
+ return value;
+}
+
+ssize_t
+parcSecureRandom_NextBytes(PARCSecureRandom *random, PARCBuffer *buffer)
+{
+ size_t length = parcBuffer_Remaining(buffer);
+ ssize_t result = read(random->randomfd, parcBuffer_Overlay(buffer, 0), length);
+ return result;
+}
+
+bool
+parcSecureRandom_IsValid(const PARCSecureRandom *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ if (instance->randomfd != -1) {
+ result = true;
+ }
+ }
+
+ return result;
+}
diff --git a/libparc/parc/security/parc_SecureRandom.h b/libparc/parc/security/parc_SecureRandom.h
new file mode 100644
index 00000000..e5c67fc3
--- /dev/null
+++ b/libparc/parc/security/parc_SecureRandom.h
@@ -0,0 +1,189 @@
+/*
+ * 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_SecureRandom.h
+ * @brief A cryptographically secure pseudorandom number generator that reads
+ * from a secure randomness source on the system, e.g., /dev/urandom.
+ *
+ */
+#ifndef Libparc_parc_SecureRandom
+#define Libparc_parc_SecureRandom
+
+#include <stdbool.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct parc_securerandom;
+typedef struct parc_securerandom PARCSecureRandom;
+
+/**
+ * Increase the number of references to a `PARCSecureRandom` instance.
+ *
+ * Note that new `PARCSecureRandom` is not created,
+ * only that the given `PARCSecureRandom` reference count is incremented.
+ * Discard the reference by invoking `parcSecureRandom_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSecureRandom instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *a = parcSecureRandom_Create();
+ *
+ * PARCSecureRandom *b = parcSecureRandom_Acquire();
+ *
+ * parcSecureRandom_Release(&a);
+ * parcSecureRandom_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSecureRandom *parcSecureRandom_Acquire(const PARCSecureRandom *instance);
+
+/**
+ * Create an instance of PARCSecureRandom
+ *
+ * @return non-NULL A pointer to a valid PARCSecureRandom instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * parcSecureRandom_Release(&rng);
+ * }
+ * @endcode
+ */
+PARCSecureRandom *parcSecureRandom_Create(void);
+
+/**
+ * Create an instance of PARCSecureRandom with a specific seed stored in
+ * a `PARCBuffer` instance.
+ *
+ * @param [in] seed A `PARCBuffer` instance.
+ *
+ * @return non-NULL A pointer to a valid PARCSecureRandom instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *seed = ...
+ * PARCSecureRandom *rng = parcSecureRandom_CreateWithSeed(seed);
+ *
+ * parcSecureRandom_Release(&rng);
+ * }
+ * @endcode
+ */
+PARCSecureRandom *parcSecureRandom_CreateWithSeed(PARCBuffer *seed);
+
+/**
+ * Generate a 32-bit unsigned integer from a `PARCSecureRandom` instance.
+ *
+ * @param [in] rng A `PARCSecureRandom` instance.
+ *
+ * @return non-NULL A pointer to a valid PARCSecureRandom instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * uint32_t nextWord = parcSecureRandom_Next(rng);
+ * // use the word
+ * }
+ * @endcode
+ */
+uint32_t parcSecureRandom_Next(PARCSecureRandom *rng);
+
+/**
+ * Fill a `PARCBuffer` instance with random bytes from a `PARCSecureRandom` instance.
+ * The resultant `PARCBuffer` will be ready for reading, i.e., one does not need
+ * to call `parcBuffer_Flip()` on the result.
+ *
+ * @param [in] rng A `PARCSecureRandom` instance.
+ * @param [in] buffer A `PARCBuffer` instance to fill.
+ *
+ * @return non-NULL A pointer to a valid PARCSecureRandom instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(32);
+ * ssize_t numBytes = parcSecureRandom_NextBytes(rng, buffer);
+ * // use the buffer
+ * }
+ * @endcode
+ */
+ssize_t parcSecureRandom_NextBytes(PARCSecureRandom *rng, PARCBuffer *buffer);
+
+/**
+ * Determine if an instance of `PARCSecureRandom` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCSecureRandom instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * if (parcSecureRandom_IsValid(rng)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcSecureRandom_Release(&rng);
+ * }
+ * @endcode
+ *
+ */
+bool parcSecureRandom_IsValid(const PARCSecureRandom *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSecureRandom` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * parcSecureRandom_Release(&rng);
+ * }
+ * @endcode
+ */
+void parcSecureRandom_Release(PARCSecureRandom **instancePtr);
+#endif
diff --git a/libparc/parc/security/parc_Security.c b/libparc/parc/security/parc_Security.c
new file mode 100644
index 00000000..70731ba3
--- /dev/null
+++ b/libparc/parc/security/parc_Security.c
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * June 9, 2014 add openssl multithreaded support.
+ * See http://www.openssl.org/docs/crypto/threads.html.
+ * We need to implement locking_function() and threadid_func().
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#include <pthread.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+#include <openssl/crypto.h>
+
+#define OPENSSL_THREAD_DEFINES
+#include <openssl/opensslconf.h>
+#if !defined(OPENSSL_THREADS)
+#error OpenSSL must support threads
+#endif
+
+// OPENSSL_VERSION_NUMBER = MMNNFFPPS
+// MM = major NN = minor FF = fix PP = patch S = 0 (dev), 1-E (betas), F (release)
+// This will require 1.0.1e release minimum version
+//#if OPENSSL_VERSION_NUMBER < 0x1000105fL
+#if OPENSSL_VERSION_NUMBER < 0x0009081fL
+#pragma message(OPENSSL_VERSION_TEXT)
+#error OpenSSL version must be at least 0.9.8 release
+#endif
+
+// Use the LongBow aids for this (case 999)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+/*
+ * OpenSSL requires one lock per thread, so we have a global lock array
+ */
+static pthread_mutex_t *perThreadLocks;
+
+static volatile bool parcSecurity_initialized = false;
+static unsigned long parcSecurity_count = 0;
+
+pthread_mutex_t parcSecurity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+_lockingCallback(int mode, int type, const char *file __attribute__((unused)), int line __attribute__((unused)))
+{
+ int error = 0;
+ if (mode & CRYPTO_LOCK) {
+ error = pthread_mutex_lock(&(perThreadLocks[type]));
+ } else {
+ error = pthread_mutex_unlock(&(perThreadLocks[type]));
+ }
+
+ assertTrue(error == 0, "Error in pthreads: (%d) %s", errno, strerror(errno));
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x1000005fL
+
+// for older pre-1.0 versions of openssl
+static unsigned long
+_getThreadId(void)
+{
+ // Now, do the "right thing" with it. Some systems return a pointer to a struct
+ // and other systems return a native type. OpenSSL (1.0 or later) provide two
+ // mapping functions to convert these types of representations to CRYPTO_THREADID.
+#if defined(__APPLE__)
+ uint64_t threadid = 0;
+ int error = pthread_threadid_np(pthread_self(), &threadid);
+ assertTrue(error == 0, "Error getting threadid");
+ return (unsigned long) threadid;
+#elif defined(__linux__)
+ // linux (at least ubuntu and redhat) uses unsigned long int
+ pthread_t threadid = pthread_self();
+ return (unsigned long) threadid;
+#else
+#error Unsupported platform, only __APPLE__ and __linux__ supported
+#endif
+}
+
+#else
+
+// For new 1.0 or later versions of openssl
+static void
+_getThreadId(CRYPTO_THREADID *id)
+{
+ pthread_t threadid = pthread_self();
+
+ // Now, do the "right thing" with it. Some systems return a pointer to a struct
+ // and other systems return a native type. OpenSSL (1.0 or later) provide two
+ // mapping functions to convert these types of representations to CRYPTO_THREADID.
+
+#if defined(__APPLE__)
+ // The Apple Mac OS X pthreads uses a pointer to a struct (struct _opaque_pthread_t)
+ CRYPTO_THREADID_set_pointer(id, threadid);
+#elif defined(__linux__)
+ // linux (at least ubuntu and redhat) uses unsigned long int
+ CRYPTO_THREADID_set_numeric(id, threadid);
+#else
+#error Unsupported platform, only __APPLE__ and __linux__ supported
+#endif
+}
+#endif
+
+static void
+_initLocks(void)
+{
+ perThreadLocks = parcMemory_AllocateAndClear(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+ assertNotNull(perThreadLocks, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+
+ for (int i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_init(&(perThreadLocks[i]), NULL);
+ }
+
+#if OPENSSL_VERSION_NUMBER < 0x1000005fL
+ // for older pre-1.0 versions
+ CRYPTO_set_id_callback(_getThreadId);
+#else
+ CRYPTO_THREADID_set_callback(_getThreadId);
+#endif
+
+ CRYPTO_set_locking_callback(_lockingCallback);
+}
+
+static void
+_finiLocks(void)
+{
+ CRYPTO_set_locking_callback(NULL);
+ for (int i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_destroy(&(perThreadLocks[i]));
+ }
+ parcMemory_Deallocate((void **) &perThreadLocks);
+}
+
+void
+parcSecurity_AssertIsInitialized(void)
+{
+ trapUnexpectedStateIf(parcSecurity_IsInitialized() == false, "PARC Security framework is not initialized. See parcSecurity_Init()");
+}
+
+void
+parcSecurity_Init(void)
+{
+ int lockSuccessful = pthread_mutex_lock(&parcSecurity_mutex) == 0;
+ assertTrue(lockSuccessful, "Unable to lock the PARC Security framework.");
+
+ if (!parcSecurity_initialized) {
+ _initLocks();
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+ parcSecurity_initialized = true;
+ }
+ parcSecurity_count++;
+
+ int unlockSuccessful = pthread_mutex_unlock(&parcSecurity_mutex) == 0;
+ assertTrue(unlockSuccessful, "Unable to unlock the PARC Security framework.");
+}
+
+bool
+parcSecurity_IsInitialized(void)
+{
+ return parcSecurity_initialized;
+}
+
+void
+parcSecurity_Fini(void)
+{
+ int lockSuccessful = pthread_mutex_lock(&parcSecurity_mutex) == 0;
+ assertTrue(lockSuccessful, "Unable to lock the PARC Security framework.");
+
+ parcSecurity_count--;
+ if (parcSecurity_count == 0) {
+ EVP_cleanup();
+ ERR_free_strings();
+ parcSecurity_initialized = false;
+ _finiLocks();
+ }
+
+ int unlockSuccessful = pthread_mutex_unlock(&parcSecurity_mutex) == 0;
+ assertTrue(unlockSuccessful, "Unable to unlock the PARC Security framework.");
+}
+
+#pragma GCC diagnostic pop
diff --git a/libparc/parc/security/parc_Security.h b/libparc/parc/security/parc_Security.h
new file mode 100755
index 00000000..2c20496b
--- /dev/null
+++ b/libparc/parc/security/parc_Security.h
@@ -0,0 +1,89 @@
+/*
+ * 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_Security.h
+ * @ingroup security
+ * @brief PARC Security Library framework director.
+ *
+ */
+#ifndef libparc_parc_Security_h
+#define libparc_parc_Security_h
+
+#include <stdbool.h>
+
+/**
+ * Initialise the PARC Security framework.
+ *
+ * This function may be called multiple times,
+ * each time incrementing a reference count that is decremented by calls to `parcSecurityFini`.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_Init();
+ * }
+ * @endcode
+ *
+ * @see parcSecurity_Fini
+ */
+void parcSecurity_Init(void);
+
+/**
+ * Deinitialise the PARC Security framework.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_Fini();
+ * }
+ * @endcode
+ *
+ * @see parcSecurity_Init
+ */
+void parcSecurity_Fini(void);
+
+/**
+ * Assert that the PARC Security Framework is initalised.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_AssertIsInitialized();
+ *
+ * }
+ * @endcode
+ *
+ * @see parcSecurity_Init
+ */
+void parcSecurity_AssertIsInitialized(void);
+
+/**
+ * Determine if the PARC Security Framework is initalised.
+ *
+ * @return True if the PARC Security Framework is initalised.
+ * @return False otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_IsInitialized();
+ * }
+ * @endcode
+ *
+ * @see parcSecurity_Init
+ */
+bool parcSecurity_IsInitialized(void);
+#endif // libparc_parc_Security_h
diff --git a/libparc/parc/security/parc_Signature.c b/libparc/parc/security/parc_Signature.c
new file mode 100755
index 00000000..1021b2a4
--- /dev/null
+++ b/libparc/parc/security/parc_Signature.c
@@ -0,0 +1,123 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/security/parc_Signature.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_signature {
+ PARCSigningAlgorithm signingAlgorithm;
+ PARCCryptoHashType hashType;
+ PARCBuffer *signatureBits;
+};
+
+static void
+_parcSignature_FinalRelease(PARCSignature **signatureP)
+{
+ parcBuffer_Release(&(*signatureP)->signatureBits);
+}
+
+parcObject_ExtendPARCObject(PARCSignature, _parcSignature_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCSignature *
+parcSignature_Create(PARCSigningAlgorithm signingAlgorithm, PARCCryptoHashType hashType, PARCBuffer *signatureBits)
+{
+ assertNotNull(signatureBits, "SignatureBits Parameter cannot be null");
+
+ PARCSignature *signature = parcObject_CreateInstance(PARCSignature);
+ assertNotNull(signature, "parcObject_CreateInstance(%zu) returned NULL", sizeof(PARCSignature));
+
+ signature->signingAlgorithm = signingAlgorithm;
+ signature->hashType = hashType;
+ signature->signatureBits = parcBuffer_Acquire(signatureBits);
+
+ return signature;
+}
+
+parcObject_ImplementAcquire(parcSignature, PARCSignature);
+
+parcObject_ImplementRelease(parcSignature, PARCSignature);
+
+
+PARCSigningAlgorithm
+parcSignature_GetSigningAlgorithm(const PARCSignature *signature)
+{
+ assertNotNull(signature, "Parameter must be non-null");
+ return signature->signingAlgorithm;
+}
+
+PARCCryptoHashType
+parcSignature_GetHashType(const PARCSignature *signature)
+{
+ assertNotNull(signature, "Parameter must be non-null");
+ return signature->hashType;
+}
+
+PARCBuffer *
+parcSignature_GetSignature(const PARCSignature *signature)
+{
+ assertNotNull(signature, "Parameter must be non-null");
+ return signature->signatureBits;
+}
+
+char *
+parcSignature_ToString(const PARCSignature *signature)
+{
+ assertNotNull(signature, "Parameter must be a non-null CCNxSignature pointer");
+
+ char *bits = parcBuffer_ToString(signature->signatureBits);
+
+ char *string;
+ int nwritten = asprintf(&string, "CCNxSignedInfo { .signingAlg=%d, .digestAlg=%d, .signature=%s }",
+ signature->signingAlgorithm,
+ signature->hashType,
+ bits);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+
+ parcMemory_Deallocate((void **) &bits);
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+ return result;
+}
+
+bool
+parcSignature_Equals(const PARCSignature *x, const PARCSignature *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->signingAlgorithm == y->signingAlgorithm) {
+ if (x->hashType == y->hashType) {
+ if (parcBuffer_Equals(x->signatureBits, y->signatureBits)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/libparc/parc/security/parc_Signature.h b/libparc/parc/security/parc_Signature.h
new file mode 100755
index 00000000..3d28ac56
--- /dev/null
+++ b/libparc/parc/security/parc_Signature.h
@@ -0,0 +1,250 @@
+/*
+ * 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_Signature.h
+ * @ingroup security
+ * @brief A tuple of (SigningAlgorithm, SignatureBuffer, PublicKeyDigest)
+ *
+ * A PARCSignature wraps the tuple { SigningAlgorithm, SignatureBuffer, PublicKeyDigest },
+ * where PublicKeyDigest is a PARCCryptoHash of the publisher public key digest.
+ *
+ */
+#ifndef libparc_parc_Signature_h
+#define libparc_parc_Signature_h
+
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_signature;
+typedef struct parc_signature PARCSignature;
+
+/**
+ * Create a `PARCSignature` instance wrapping all the pieces needed to use it.
+ *
+ * @param [in] signingAlgorithm is the algorithm used to produce the signature
+ * @param [in] hashType The PARCCryptoHashType of cryptographic hash digest computed from the input bits which is ultimately signed.
+ * @param [in] signatureBits is the actual signature, as an array of bytes
+ *
+ * @return A pointer to a `PARCSignature` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ * }
+ * @endcode
+ */
+PARCSignature *parcSignature_Create(PARCSigningAlgorithm signingAlgorithm, PARCCryptoHashType hashType, PARCBuffer *signatureBits);
+
+/**
+ * Increase the number of references to an instance of this object.
+ *
+ * Note that new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the reference by invoking `parcSignature_Release`.
+ *
+ * @param [in] signature A pointer to the instance of `PARCSignature` to acquire.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCSignature *signature = parcSignature_Acquire(instance);
+ *
+ * parcSignature_Release(&signature);
+ * }
+ * @endcode
+ *
+ * @see `parcSignature_Release`
+ */
+
+PARCSignature *parcSignature_Acquire(const PARCSignature *signature);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] signaturePtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ * parcSignature_Release(&signature);
+ * }
+ * @endcode
+ *
+ * @see `parcSignature_Acquire`
+ */
+void parcSignature_Release(PARCSignature **signaturePtr);
+
+/**
+ * Returns the signing algorithm.
+ *
+ * @param [in] signature The `PARCSignature` instance from which the signing algorithm is retrieved.
+ *
+ * @return A `PARCSigningAlgorithm` value corresponding to this signature.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * PARCSigningAlgorithm algorithm = parcSignature_GetSigningAlgorithm(signature);
+ * }
+ * @endcode
+ */
+PARCSigningAlgorithm parcSignature_GetSigningAlgorithm(const PARCSignature *signature);
+
+/**
+ * Returns the digest algorithm used to compute the digest we signed.
+ *
+ * @param [in] signature The `PARCSignature` instance from which the hash type is retrieved.
+ *
+ * @return A `PARCCryptoHashType` value corresponding to this signature.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * PARCCryptoHashType hashType = parcSignature_GetHashType(signature);
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcSignature_GetHashType(const PARCSignature *signature);
+
+/**
+ * Gets the signature as a buffer of bits.
+ *
+ * @param [in] signature The `PARCSignature` instance from which the signature payload is retrieved.
+ *
+ * @return A `PARCBuffer` instanace containing the raw signature bytes.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * PARCBuffer *payload = parcSignature_GetSignature(signature);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcSignature_GetSignature(const PARCSignature *signature);
+
+/**
+ * Produce a nul-terminated string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via `parcMemory_Deallocate()`.
+ *
+ * @param [in] signature A pointer to a PARCSignature instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a nul-terminated C-string the must be dellocated via `parcMemory_Deallocate()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * char *string = parcSignature_ToString(signature);
+ *
+ * parcMemory_Deallocate(&signature);
+ * }
+ * @endcode
+ */
+char *parcSignature_ToString(const PARCSignature *signature);
+
+/**
+ * Determine if two PARCSignature instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCSignature` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcSignature_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcSignature_Equals(x, y)` must return true if and only if
+ * `parcSignature_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcSignature_Equals(x, y)` returns true and
+ * `parcSignature_Equals(y, z)` returns true,
+ * then `parcSignature_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcSignature_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcSignature_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] a A pointer to a PARCSignature instance.
+ * @param [in] b A pointer to a PARCSignature instance.
+ *
+ * @return true if the two instances are equal
+ * @return false if the two instancea are no equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signatureA = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * PARCSignature *signatureB = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * if (parcSignature_Equals(signatureA, signatureB)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * parcMemory_Deallocate(&signatureA);
+ * parcMemory_Deallocate(&signatureB);
+ * }
+ * @endcode
+ */
+bool parcSignature_Equals(const PARCSignature *a, const PARCSignature *b);
+#endif // libparc_parc_Signature_h
diff --git a/libparc/parc/security/parc_Signer.c b/libparc/parc/security/parc_Signer.c
new file mode 100644
index 00000000..2135070c
--- /dev/null
+++ b/libparc/parc/security/parc_Signer.c
@@ -0,0 +1,160 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_KeyStore.h>
+
+struct parc_signer {
+ PARCObject *instance;
+ PARCSigningInterface *interface;
+};
+
+static bool
+_parcSigner_FinalRelease(PARCSigner **signerPtr)
+{
+ PARCSigner *signer = *signerPtr;
+ if (signer->instance != NULL) {
+ parcObject_Release(&(signer->instance));
+ }
+ return true;
+}
+
+void
+parcSigner_AssertValid(const PARCSigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null PARCSigner");
+}
+
+parcObject_ImplementAcquire(parcSigner, PARCSigner);
+parcObject_ImplementRelease(parcSigner, PARCSigner);
+
+parcObject_Override(PARCSigner, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcSigner_FinalRelease);
+
+PARCSigner *
+parcSigner_Create(PARCObject *instance, PARCSigningInterface *interfaceContext)
+{
+ assertNotNull(interfaceContext, "Parameter must be non-null implementation pointer");
+
+ PARCSigner *signer = parcObject_CreateInstance(PARCSigner);
+ if (signer != NULL) {
+ signer->instance = parcObject_Acquire(instance);
+ signer->interface = interfaceContext;
+ }
+ return signer;
+}
+
+PARCKey *
+parcSigner_CreatePublicKey(PARCSigner *signer)
+{
+ PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer);
+
+ PARCCryptoHash *hash = parcKeyStore_GetVerifierKeyDigest(keyStore);
+
+ PARCKeyId *keyid = parcKeyId_Create(parcCryptoHash_GetDigest(hash));
+ parcCryptoHash_Release(&hash);
+
+ PARCBuffer *derEncodedKey = parcKeyStore_GetDEREncodedPublicKey(keyStore);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid,
+ parcSigner_GetSigningAlgorithm(signer),
+ derEncodedKey);
+
+ parcBuffer_Release(&derEncodedKey);
+ parcKeyId_Release(&keyid);
+
+ return key;
+}
+
+PARCKeyId *
+parcSigner_CreateKeyId(const PARCSigner *signer)
+{
+ PARCCryptoHash *hash = parcKeyStore_GetVerifierKeyDigest(parcSigner_GetKeyStore(signer));
+ PARCBuffer *keyidBytes = parcCryptoHash_GetDigest(hash);
+ PARCKeyId *result = parcKeyId_Create(keyidBytes);
+
+ parcCryptoHash_Release(&hash);
+ return result;
+}
+
+PARCCryptoHasher *
+parcSigner_GetCryptoHasher(const PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ return signer->interface->GetCryptoHasher(signer->instance);
+}
+
+PARCSignature *
+parcSigner_SignDigest(const PARCSigner *signer, const PARCCryptoHash *parcDigest)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ assertNotNull(parcDigest, "parcDigest to sign must not be null");
+ return signer->interface->SignDigest(signer->instance, parcDigest);
+}
+
+PARCSignature *
+parcSigner_SignBuffer(const PARCSigner *signer, const PARCBuffer *buffer)
+{
+ parcSigner_OptionalAssertValid(signer);
+ assertNotNull(buffer, "buffer to sign must not be null");
+
+ PARCCryptoHashType hashType = parcSigner_GetCryptoHashType(signer);
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(hashType);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBuffer(hasher, buffer);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ parcCryptoHasher_Release(&hasher);
+
+ PARCSignature *signature = parcSigner_SignDigest(signer, hash);
+ parcCryptoHash_Release(&hash);
+
+ return signature;
+}
+
+PARCSigningAlgorithm
+parcSigner_GetSigningAlgorithm(PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ return signer->interface->GetSigningAlgorithm(signer->instance);
+}
+
+PARCCryptoHashType
+parcSigner_GetCryptoHashType(const PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ return signer->interface->GetCryptoHashType(signer->instance);
+}
+
+PARCKeyStore *
+parcSigner_GetKeyStore(const PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ return signer->interface->GetKeyStore(signer->instance);
+}
diff --git a/libparc/parc/security/parc_Signer.h b/libparc/parc/security/parc_Signer.h
new file mode 100755
index 00000000..c6d49480
--- /dev/null
+++ b/libparc/parc/security/parc_Signer.h
@@ -0,0 +1,368 @@
+/*
+ * 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_Signer.h
+ * @ingroup security
+ * @brief The API a crytography provider must interfaceement.
+ *
+ * A signer IS NOT THREAD-SAFE.
+ *
+ */
+#ifndef libparc_parc_Signer_h
+#define libparc_parc_Signer_h
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_Signature.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_Key.h>
+#include <parc/security/parc_KeyStore.h>
+
+struct parc_signer;
+/**
+ * @typedef PARCSigner
+ * @brief The structure for PARCSigner
+ */
+
+typedef struct parc_signer PARCSigner;
+
+/**
+ * @def parcSigner_OptionalAssertValid
+ * Optional validation of the given instance.
+ *
+ * Define `PARCLibrary_DISABLE_VALIDATION` to disable validation.
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcSigner_OptionalAssertValid(_instance_)
+#else
+# define parcSigner_OptionalAssertValid(_instance_) parcSigner_AssertValid(_instance_)
+#endif
+
+/**
+ * @typedef PARCSigningInterface
+ * @brief The CCN signing implementation structure.
+ *
+ * This defines the contract that any concrete implementation provides.
+ *
+ */
+typedef struct parc_signer_interface {
+ /**
+ * Returns a the hasher to use for the signature. This is important for
+ * symmetric key HMAC to use this hasher, not one from PARCCryptoHasher.
+ *
+ * DO NOT DESTROY THIS HASHER! Just call _Init, _Update, and _Finalize.
+ *
+ * The hash type will be based on how the underlying implementation was initialized
+ *
+ * Equivalent of (for rsa/sha256)
+ * openssl rsautl -sign -inkey test_rsa_key.pem -in infile_digest -out infile.sig
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCSigner instance.
+ */
+ PARCCryptoHasher *(*GetCryptoHasher)(void *interfaceContext);
+
+ /**
+ * Compute the signature of the given PARCCryptoHash.
+ *
+ * Equivalent of (for rsa/sha256)
+ * openssl rsautl -sign -inkey test_rsa_key.pem -in infile_digest -out infile.sig
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCSigner instance.
+ * @param [in] hashToSign The output of the given digest to sign
+ *
+ * @return A pointer to a PARCSignature instance that must be released via parcSignature_Release()
+ */
+ PARCSignature *(*SignDigest)(void *interfaceContext, const PARCCryptoHash * parcDigest);
+
+ /**
+ * Return the PARSigningAlgorithm used for signing with the given `PARCSigner`
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCSigner instance.
+ *
+ * @return A PARSigningAlgorithm value.
+ */
+ PARCSigningAlgorithm (*GetSigningAlgorithm)(void *interfaceContext);
+
+ /**
+ * Return the digest algorithm used by the Signer
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCSigner instance.
+ *
+ * @return A PARCCryptoHashType value.
+ */
+ PARCCryptoHashType (*GetCryptoHashType)(void *interfaceContext);
+
+ /**
+ * Return the PARCKeyStore for this Signer.
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCSigner instance.
+ *
+ * @return A PARCKeyStore instance.
+ */
+ PARCKeyStore *(*GetKeyStore)(void *interfaceContext);
+} PARCSigningInterface;
+
+/**
+ * Assert that an instance of `PARCSigner` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue}
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * Example
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ *
+ * parcSigner_AssertValid(signer);
+ * }
+ * @endcode
+ */
+void parcSigner_AssertValid(const PARCSigner *signer);
+
+/**
+ * Create a signing context based on a concrete implementation.
+ *
+ * @param [in] instance A concrete implementation of a `PARCSigner`
+ * @param [in] interfaceContext The interface of a concrete implementation of a `PARCSigner`
+ *
+ * @return NULL A `PARCSigner` could not be allocated
+ * @return PARCSigner A new `PARCSigner` instance derived from the specified concrete signer context.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ * }
+ * @endcode
+ */
+PARCSigner *parcSigner_Create(PARCObject *instance, PARCSigningInterface *interfaceContext);
+
+/**
+ * Increase the number of references to the given `PARCSigner` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking `parcSigner_Release()`.
+ *
+ * @param [in] signer A pointer to a `PARCSigner` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCSigner instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ * PARCSigner *handle = parcSigner_Acquire(signer);
+ * // use the handle instance as needed
+ * }
+ * @endcode
+ */
+PARCSigner *parcSigner_Acquire(const PARCSigner *signer);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] signerPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ *
+ * parcSigner_Release(&signer);
+ * }
+ * @endcode
+ */
+void parcSigner_Release(PARCSigner **signerPtr);
+
+/**
+ * Create a PARCKeyId instance from the given pinter to a `PARCSigner` instance.
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * @return A pointer to a created PARCKeyId instance that must be released via `parcKeyId_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ *
+ * PARCKeyId *keyId = parcSigner_CreateKeyId(signer);
+ * }
+ * @endcode
+ */
+PARCKeyId *parcSigner_CreateKeyId(const PARCSigner *signer);
+
+/**
+ * Get the DER encoded public key and keyid wrapped in a `PARCKey` instance.
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * @return A newly allocated `PARCKey` instance containing the public key used to verify signatures computed by this signer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ *
+ * PARCKey *publicKey = parcSigner_CreatePublicKey(signer);
+ * }
+ * @endcode
+ */
+PARCKey *parcSigner_CreatePublicKey(PARCSigner *signer);
+
+/**
+ * Returns a the hasher to use for the signature. This is important for
+ * symmetric key HMAC to use this hasher, not one from PARCCryptoHasher.
+ *
+ * DO NOT DESTROY THIS HASHER! Just call _Init, _Update, and _Finalize.
+ *
+ * The hash type will be based on how the underlying implementation was initialized
+ *
+ * Equivalent of (for rsa/sha256)
+ * openssl rsautl -sign -inkey test_rsa_key.pem -in infile_digest -out infile.sig
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ *
+ * PARCCryptoHasher hasher = parcSigner_GetCryptoHasher(signer);
+ * }
+ * @endcode
+ */
+PARCCryptoHasher *parcSigner_GetCryptoHasher(const PARCSigner *signer);
+
+/**
+ * Compute the signature of the given PARCCryptoHash.
+ *
+ * Equivalent of (for rsa/sha256)
+ * openssl rsautl -sign -inkey test_rsa_key.pem -in infile_digest -out infile.sig
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ * @param [in] hashToSign The output of the given digest
+ *
+ * @return A pointer to a PARCSignature instance that must be released via parcSignature_Release()
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ *
+ * PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ * parcCryptoHasher_Init(hasher);
+ * parcCryptoHasher_Update_Bytes(hasher, &block->memory[relativePosition], length);
+ * PARCCryptoHash *hashToSign = parcCryptoHasher_Finalize(hasher);
+ *
+ * PARCSignature signature = parcSigner_SignDigest(signer, hashToSign);
+ * }
+ * @endcode
+ */
+PARCSignature *parcSigner_SignDigest(const PARCSigner *signer, const PARCCryptoHash *hashToSign);
+
+/**
+ * Compute the signature of a given `PARCBuffer`.
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ * @param [in] buffer The input to be hashed and signed.
+ *
+ * @return A pointer to a PARCSignature instance that must be released via parcSignature_Release()
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ * PARCBuffer *inputBuffer = ...
+ *
+ * PARCSignature signature = parcSigner_SignBuffer(signer, inputBuffer);
+ * }
+ * @endcode
+ */
+PARCSignature *parcSigner_SignBuffer(const PARCSigner *signer, const PARCBuffer *buffer);
+
+/**
+ * Return the PARSigningAlgorithm used for signing with the given `PARCSigner`
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * @return A PARSigningAlgorithm value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ *
+ * PARCSigningAlgorithm suite = parcSigner_GetSigningAlgorithm(signer);
+ * }
+ * @endcode
+ */
+PARCSigningAlgorithm parcSigner_GetSigningAlgorithm(PARCSigner *signer);
+
+/**
+ * Return the digest algorithm used by the Signer
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * @return A PARCCryptoHashType value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ *
+ * PARCCryptoHashType suite = parcSigner_GetCryptoHashType(signer);
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcSigner_GetCryptoHashType(const PARCSigner *signer);
+
+/**
+ * Given a `PARCSigner` instance, return the `PARCKeyStore` containing its public key information.
+ *
+ * @param [in] signer A pointer to a `PARCSigner` instance.
+ *
+ * @return A `PARCKeyStore` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ *
+ * PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer);
+ * }
+ * @endcode
+ */
+PARCKeyStore *parcSigner_GetKeyStore(const PARCSigner *signer);
+#endif // libparc_parc_Signer_h
diff --git a/libparc/parc/security/parc_SigningAlgorithm.c b/libparc/parc/security/parc_SigningAlgorithm.c
new file mode 100755
index 00000000..d0dadd4a
--- /dev/null
+++ b/libparc/parc/security/parc_SigningAlgorithm.c
@@ -0,0 +1,81 @@
+/*
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_SigningAlgorithm.h>
+
+static struct {
+ PARCSigningAlgorithm alg;
+ char *name;
+} _signingAlgorithm_ToString[] = {
+ { PARCSigningAlgortihm_NULL, "PARCSigningAlgortihm_NULL" },
+ { PARCSigningAlgorithm_RSA, "PARCSigningAlgorithm_RSA" },
+ { PARCSigningAlgorithm_DSA, "PARCSigningAlgorithm_DSA" },
+ { PARCSigningAlgorithm_HMAC, "PARCSigningAlgorithm_HMAC" },
+ { 0, NULL }
+};
+
+const char *
+parcSigningAlgorithm_ToString(PARCSigningAlgorithm alg)
+{
+ for (int i = 0; _signingAlgorithm_ToString[i].name != NULL; i++) {
+ if (_signingAlgorithm_ToString[i].alg == alg) {
+ return _signingAlgorithm_ToString[i].name;
+ }
+ }
+ return NULL;
+}
+
+PARCSigningAlgorithm
+parcSigningAlgorithm_FromString(const char *name)
+{
+ for (int i = 0; _signingAlgorithm_ToString[i].name != NULL; i++) {
+ if (strcmp(_signingAlgorithm_ToString[i].name, name) == 0) {
+ return _signingAlgorithm_ToString[i].alg;
+ }
+ }
+ return PARCSigningAlgorithm_UNKNOWN;
+}
+
+PARCSigningAlgorithm
+parcSigningAlgorithm_GetSigningAlgorithm(PARCCryptoSuite suite)
+{
+ switch (suite) {
+ case PARCCryptoSuite_DSA_SHA256:
+ return PARCSigningAlgorithm_DSA;
+
+ case PARCCryptoSuite_RSA_SHA256: // fallthrough
+ case PARCCryptoSuite_RSA_SHA512:
+ return PARCSigningAlgorithm_RSA;
+
+ case PARCCryptoSuite_HMAC_SHA256: // fallthrough
+ case PARCCryptoSuite_HMAC_SHA512:
+ return PARCSigningAlgorithm_HMAC;
+
+ case PARCCryptoSuite_NULL_CRC32C:
+ return PARCSigningAlgortihm_NULL;
+
+ default:
+ trapIllegalValue(suit, "Unknown crypto suite: %d", suite);
+ }
+}
diff --git a/libparc/parc/security/parc_SigningAlgorithm.h b/libparc/parc/security/parc_SigningAlgorithm.h
new file mode 100644
index 00000000..02f7c946
--- /dev/null
+++ b/libparc/parc/security/parc_SigningAlgorithm.h
@@ -0,0 +1,100 @@
+/*
+ * 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_SigningAlgorithm.h
+ * @ingroup security
+ * @brief This module encapsulates information about the types of available signing algorithms.
+ *
+ * Both asymmetric digital signature algorithms, e.g., RSA and DSA, and symmetric Message Authentication
+ * Codes (MACS), e.g., HMAC, are supported. This module exposes the functionality necessary to map between
+ * enum and human-readable string representations of these algorithms.
+ *
+ */
+#ifndef libparc_parc_SigningAlgorithm_h
+#define libparc_parc_SigningAlgorithm_h
+
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_CryptoSuite.h>
+
+typedef enum {
+ PARCSigningAlgorithm_UNKNOWN = -1,
+ PARCSigningAlgorithm_RSA = 1,
+ PARCSigningAlgorithm_DSA = 2,
+ PARCSigningAlgorithm_HMAC = 3,
+ PARCSigningAlgortihm_NULL = 4,
+} PARCSigningAlgorithm;
+
+/**
+ * Return a human readable string representation of the specified signing algorithm.
+ *
+ * @param [in] algorithm A pointer to a PARCSigningAlgorithm as the target signing algorithm.
+ * @return A static, null-terminated string.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigningAlgorithm alg = PARCSigningAlgorithm_RSA;
+ * const char *stringRep = parcSigningAlgorithm_ToString(alg);
+ * // do something with stringRep
+ * }
+ * @endcode
+ *
+ * @see parcSigningAlgorithm_FromString
+ */
+const char *parcSigningAlgorithm_ToString(PARCSigningAlgorithm algorithm);
+
+/**
+ * Get the `PARCSigningAlgorithm` enum from a corresponding human-readable string representation
+ * of a signing algorithm.
+ *
+ * @param [in] name A nul-terminate C-string representation of signing algorithm.
+ * @return A valid `PARCSigningAlgorithm` enum.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *stringRep = "PARCSigningAlgortihm_NULL";
+ * PARCSigningAlgorithm alg = parcSigningAlgorithm_FromString(stringRep);
+ * // do something with alg
+ * }
+ * @endcode
+ *
+ * @see parcSigningAlgorithm_ToString
+ */
+PARCSigningAlgorithm parcSigningAlgorithm_FromString(const char *name);
+
+/**
+ * Get the `PARCSigningAlgorithm` type associated with the specified `PARCCryptoSuite` type.
+ *
+ * PARCCryptoSuite types combine hash and signing algorithms to be used to signature and/or MAC generation.
+ * Therefore, a PARCCryptoSuite type of PARCCryptoSuite_DSA_SHA256, for example, uses the
+ * PARCSigningAlgorithm_DSA type of signing algorithm. This function serves to determine the
+ * signing algorithm type from the suite.
+ *
+ * @param [in] suite The type of cryptographic suite used for signature and/or MAC generation.
+ * @return A valid `PARCSigningAlgorithm` enum associated with the specified `PARCCryptoSuite` type.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256;
+ * PARCSigningAlgorithm alg = parcSigningAlgorithm_GetSigningAlgorithm(suite);
+ * // do something with alg
+ * }
+ * @endcode
+ */
+PARCSigningAlgorithm parcSigningAlgorithm_GetSigningAlgorithm(PARCCryptoSuite suite);
+#endif // libparc_parc_SigningAlgorithm_h
diff --git a/libparc/parc/security/parc_SymmetricKeySigner.c b/libparc/parc/security/parc_SymmetricKeySigner.c
new file mode 100644
index 00000000..aeacb30f
--- /dev/null
+++ b/libparc/parc/security/parc_SymmetricKeySigner.c
@@ -0,0 +1,268 @@
+/*
+ * 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 <config.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+#include <parc/security/parc_KeyStore.h>
+
+#include <openssl/opensslv.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/safestack.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+#include <openssl/hmac.h>
+
+#define AES_KEYSTORE_VERSION 1L
+#define IV_SIZE 16
+#define AES_MAX_DIGEST_SIZE 128
+#define AES_DEFAULT_DIGEST_ALGORITHM "SHA256"
+
+struct PARCSymmetricKeySigner {
+ PARCSymmetricKeyStore *keyStore;
+ PARCKeyStore *generalKeyStore;
+
+ PARCCryptoHash *secretKeyHash;
+ PARCCryptoHasher *hasher;
+ PARCCryptoHasherInterface hasherFunctor;
+ PARCCryptoHashType hashType;
+
+ unsigned hashLength;
+ const EVP_MD *opensslMd;
+};
+
+// ==================================================
+// HMAC implementation
+
+static void *
+_hmacCreate(void *env)
+{
+ PARCSymmetricKeySigner *signer = (PARCSymmetricKeySigner *) env;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX *ctx = HMAC_CTX_new();
+ HMAC_CTX_reset(ctx);
+#else
+ // HMAC_Init_ex seems to overrun the size of HMAC_CTX, so make it bigger
+ HMAC_CTX *ctx = parcMemory_Allocate(sizeof(HMAC_CTX) * 2);
+ assertNotNull(ctx, "parcMemory_Allocate(%zu) returned NULL for HMAC_CTX", sizeof(HMAC_CTX) * 2);
+ HMAC_CTX_init(ctx);
+#endif
+
+ // Now initialize it with our digest and key, so in hmac_init we can avoid using those
+ PARCBuffer *secretKey = parcSymmetricKeyStore_GetKey(signer->keyStore);
+ assertTrue(parcBuffer_Remaining(secretKey) < 512, "The keystore secret key cannot be longer than %d", 512);
+
+ HMAC_Init_ex(ctx, parcByteArray_Array(parcBuffer_Array(secretKey)), (int) parcBuffer_Remaining(secretKey), signer->opensslMd, NULL);
+
+ return ctx;
+}
+
+static int
+_hmacInit(void *ctx)
+{
+ // reset the HMAC state with NULLs, so we'll re-use the values we had from setup.
+ HMAC_Init_ex((HMAC_CTX *) ctx, NULL, 0, NULL, NULL);
+ return 0;
+}
+
+static int
+_hmacUpdate(void *ctx, const void *buffer, size_t length)
+{
+ HMAC_Update(ctx, buffer, length);
+ return 0;
+}
+
+static PARCBuffer*
+_hmacFinalize(void *ctx)
+{
+ uint8_t buffer[EVP_MAX_MD_SIZE];
+ unsigned length;
+ HMAC_Final(ctx, buffer, &length);
+
+ PARCBuffer *output = parcBuffer_Allocate(length);
+ parcBuffer_PutArray(output, length, buffer);
+
+ return output;
+}
+
+static void
+_hmacDestroy(void **ctxPtr)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x1010003fL)
+ HMAC_CTX_free(*ctxPtr);
+#else
+ HMAC_CTX_cleanup(*ctxPtr);
+#endif
+ parcMemory_Deallocate((void **) ctxPtr);
+ *ctxPtr = NULL;
+}
+
+static PARCCryptoHasherInterface functor_hmac = {
+ .functor_env = NULL,
+ .hasher_setup = _hmacCreate,
+ .hasher_init = _hmacInit,
+ .hasher_update = _hmacUpdate,
+ .hasher_finalize = _hmacFinalize,
+ .hasher_destroy = _hmacDestroy
+};
+
+static bool
+_parcSymmetricKeySigner_Finalize(PARCSymmetricKeySigner **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCSymmetricKeySigner pointer.");
+ PARCSymmetricKeySigner *signer = (PARCSymmetricKeySigner *) *instancePtr;
+ if (signer->secretKeyHash != NULL) {
+ parcCryptoHash_Release(&signer->secretKeyHash);
+ }
+ if (signer->hasher != NULL) {
+ parcCryptoHasher_Release(&signer->hasher);
+ }
+
+ if (signer->keyStore != NULL) {
+ parcSymmetricKeyStore_Release(&signer->keyStore);
+ }
+ if (signer->generalKeyStore != NULL) {
+ parcKeyStore_Release(&signer->generalKeyStore);
+ }
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcSymmetricKeySigner, PARCSymmetricKeySigner);
+parcObject_ImplementRelease(parcSymmetricKeySigner, PARCSymmetricKeySigner);
+
+parcObject_Override(PARCSymmetricKeySigner, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcSymmetricKeySigner_Finalize);
+
+void
+parcSymmetricKeySigner_AssertValid(const PARCSymmetricKeySigner *instance)
+{
+ assertTrue(parcSymmetricKeySigner_IsValid(instance),
+ "PARCSymmetricKeySigner is not valid.");
+}
+
+PARCSymmetricKeySigner *
+parcSymmetricKeySigner_Create(PARCSymmetricKeyStore *keyStore, PARCCryptoHashType hmacHashType)
+{
+ PARCSymmetricKeySigner *result = parcObject_CreateInstance(PARCSymmetricKeySigner);
+
+ if (result != NULL) {
+ result->hashType = hmacHashType;
+ switch (hmacHashType) {
+ case PARCCryptoHashType_SHA256:
+ result->hashLength = SHA256_DIGEST_LENGTH;
+ result->opensslMd = EVP_sha256();
+ break;
+
+ case PARCCryptoHashType_SHA512:
+ result->hashLength = SHA512_DIGEST_LENGTH;
+ result->opensslMd = EVP_sha512();
+ break;
+
+ default:
+ parcObject_Release((void **) &result);
+ trapIllegalValue(hmacHashType, "Unknown HMAC hash type: %d", hmacHashType);
+ }
+
+ // the signer key digest is SHA256, independent of the HMAC digest
+ result->secretKeyHash = parcSymmetricKeyStore_GetVerifierKeyDigest(keyStore);
+ result->keyStore = parcSymmetricKeyStore_Acquire(keyStore);
+ result->generalKeyStore = parcKeyStore_Create(result->keyStore, PARCSymmetricKeyStoreAsKeyStore);
+
+ // create the functor from the template then specialize it to this keystore.
+ // This depends on keystore->secret_key being set. It will cause a callback
+ // into hmac_setup()
+ result->hasherFunctor = functor_hmac;
+ result->hasherFunctor.functor_env = result;
+ result->hasher = parcCryptoHasher_CustomHasher(hmacHashType, result->hasherFunctor);
+ }
+
+ return result;
+}
+
+bool
+parcSymmetricKeySigner_IsValid(const PARCSymmetricKeySigner *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+static PARCSigningAlgorithm
+_getSigningAlgorithm(PARCSymmetricKeySigner *signer)
+{
+ return PARCSigningAlgorithm_HMAC;
+}
+
+static PARCCryptoHashType
+_getCryptoHashType(PARCSymmetricKeySigner *signer)
+{
+ return signer->hashType;
+}
+
+static PARCCryptoHasher *
+_getCryptoHasher(PARCSymmetricKeySigner *signer)
+{
+ return signer->hasher;
+}
+
+static PARCKeyStore *
+_getKeyStore(PARCSymmetricKeySigner *signer)
+{
+ return signer->generalKeyStore;
+}
+
+// ==================================================
+// implementation
+
+/**
+ * wrap the HMAC in digestToSign in a PARCSignature
+ *
+ * @param hashToSign is the HMAC computed by the our PARCCryptoHasher.
+ */
+static PARCSignature *
+_signDigest(PARCSymmetricKeySigner *interfaceContext, const PARCCryptoHash *hashToSign)
+{
+ // The digest computed via our hash function (hmac) is the actual signature.
+ // just need to wrap it up with the right parameters.
+ PARCBuffer *signatureBits = parcBuffer_Copy(parcCryptoHash_GetDigest(hashToSign));
+ PARCSignature *result = parcSignature_Create(_getSigningAlgorithm(interfaceContext), parcCryptoHash_GetDigestType(hashToSign), signatureBits);
+ parcBuffer_Release(&signatureBits);
+ return result;
+}
+
+PARCSigningInterface *PARCSymmetricKeySignerAsSigner = &(PARCSigningInterface) {
+ .GetCryptoHashType = (PARCCryptoHashType (*)(void *))_getCryptoHashType,
+ .GetCryptoHasher = (PARCCryptoHasher * (*)(void *))_getCryptoHasher,
+ .SignDigest = (PARCSignature * (*)(void *, const PARCCryptoHash *))_signDigest,
+ .GetSigningAlgorithm = (PARCSigningAlgorithm (*)(void *))_getSigningAlgorithm,
+ .GetKeyStore = (PARCKeyStore * (*)(void *))_getKeyStore,
+};
diff --git a/libparc/parc/security/parc_SymmetricKeySigner.h b/libparc/parc/security/parc_SymmetricKeySigner.h
new file mode 100644
index 00000000..ab4b59f2
--- /dev/null
+++ b/libparc/parc/security/parc_SymmetricKeySigner.h
@@ -0,0 +1,355 @@
+/*
+ * 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_SymmetricKeySigner.h
+ * @brief A symmetric-key signer that creates MAC tags.
+ */
+#ifndef Libparc_parc_SymmetricKeySigner
+#define Libparc_parc_SymmetricKeySigner
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+#include <parc/security/parc_SymmetricKeyStore.h>
+
+struct PARCSymmetricKeySigner;
+typedef struct PARCSymmetricKeySigner PARCSymmetricKeySigner;
+
+extern PARCSigningInterface *PARCSymmetricKeySignerAsSigner;
+
+/**
+ * Increase the number of references to a `PARCSymmetricKeySigner` instance.
+ *
+ * Note that new `PARCSymmetricKeySigner` is not created,
+ * only that the given `PARCSymmetricKeySigner` reference count is incremented.
+ * Discard the reference by invoking `parcSymmetricKeySigner_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * PARCSymmetricKeySigner *b = parcSymmetricKeySigner_Acquire();
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * parcSymmetricKeySigner_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSymmetricKeySigner *parcSymmetricKeySigner_Acquire(const PARCSymmetricKeySigner *instance);
+
+#ifdef Libparc_DISABLE_VALIDATION
+# define parcSymmetricKeySigner_OptionalAssertValid(_instance_)
+#else
+# define parcSymmetricKeySigner_OptionalAssertValid(_instance_) parcSymmetricKeySigner_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCSymmetricKeySigner` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * parcSymmetricKeySigner_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcSymmetricKeySigner_Release(&b);
+ * }
+ * @endcode
+ */
+void parcSymmetricKeySigner_AssertValid(const PARCSymmetricKeySigner *instance);
+
+/**
+ * Create an instance of PARCSymmetricKeySigner
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCSymmetricKeySigner instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCSymmetricKeySigner *parcSymmetricKeySigner_Create(PARCSymmetricKeyStore *keyStore, PARCCryptoHashType hmacHashType);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ * @param [in] other A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ * PARCSymmetricKeySigner *b = parcSymmetricKeySigner_Create();
+ *
+ * if (parcSymmetricKeySigner_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * parcSymmetricKeySigner_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcSymmetricKeySigner_Equals
+ */
+int parcSymmetricKeySigner_Compare(const PARCSymmetricKeySigner *instance, const PARCSymmetricKeySigner *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCSymmetricKeySigner` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * PARCSymmetricKeySigner *copy = parcSymmetricKeySigner_Copy(&b);
+ *
+ * parcSymmetricKeySigner_Release(&b);
+ * parcSymmetricKeySigner_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCSymmetricKeySigner *parcSymmetricKeySigner_Copy(const PARCSymmetricKeySigner *original);
+
+/**
+ * Print a human readable representation of the given `PARCSymmetricKeySigner`.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * parcSymmetricKeySigner_Display(a, 0);
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSymmetricKeySigner_Display(const PARCSymmetricKeySigner *instance, int indentation);
+
+/**
+ * Determine if two `PARCSymmetricKeySigner` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCSymmetricKeySigner` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcSymmetricKeySigner_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcSymmetricKeySigner_Equals(x, y)` must return true if and only if
+ * `parcSymmetricKeySigner_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcSymmetricKeySigner_Equals(x, y)` returns true and
+ * `parcSymmetricKeySigner_Equals(y, z)` returns true,
+ * then `parcSymmetricKeySigner_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcSymmetricKeySigner_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcSymmetricKeySigner_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCSymmetricKeySigner instance.
+ * @param [in] y A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ * PARCSymmetricKeySigner *b = parcSymmetricKeySigner_Create();
+ *
+ * if (parcSymmetricKeySigner_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * parcSymmetricKeySigner_Release(&b);
+ * }
+ * @endcode
+ * @see parcSymmetricKeySigner_HashCode
+ */
+bool parcSymmetricKeySigner_Equals(const PARCSymmetricKeySigner *x, const PARCSymmetricKeySigner *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcSymmetricKeySigner_Equals} method,
+ * then calling the {@link parcSymmetricKeySigner_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcSymmetricKeySigner_Equals} function,
+ * then calling the `parcSymmetricKeySigner_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * PARCHashCode hashValue = parcSymmetricKeySigner_HashCode(buffer);
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcSymmetricKeySigner_HashCode(const PARCSymmetricKeySigner *instance);
+
+/**
+ * Determine if an instance of `PARCSymmetricKeySigner` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * if (parcSymmetricKeySigner_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcSymmetricKeySigner_IsValid(const PARCSymmetricKeySigner *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSymmetricKeySigner` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSymmetricKeySigner_Release(PARCSymmetricKeySigner **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * PARCJSON *json = parcSymmetricKeySigner_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcSymmetricKeySigner_ToJSON(const PARCSymmetricKeySigner *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCSymmetricKeySigner`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * char *string = parcSymmetricKeySigner_ToString(a);
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcSymmetricKeySigner_Display
+ */
+char *parcSymmetricKeySigner_ToString(const PARCSymmetricKeySigner *instance);
+#endif // Libparc_parc_SymmetricKeySigner
diff --git a/libparc/parc/security/parc_SymmetricKeyStore.c b/libparc/parc/security/parc_SymmetricKeyStore.c
new file mode 100644
index 00000000..38996dba
--- /dev/null
+++ b/libparc/parc/security/parc_SymmetricKeyStore.c
@@ -0,0 +1,477 @@
+/*
+ * 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.
+ */
+
+
+/**
+ */
+/**
+ * To compute an HMAC, we need to interfaceement our own CryptoHasher so we can
+ * initialize it with the secret key
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/safestack.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+#include <openssl/hmac.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/longBow_Compiler.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_SymmetricKeyStore.h>
+
+#define AES_KEYSTORE_VERSION 1L
+#define IV_SIZE 16
+#define AES_MAX_DIGEST_SIZE 128
+#define AES_DEFAULT_DIGEST_ALGORITHM "SHA256"
+
+struct parc_symmetric_keystore {
+ PARCBuffer *secretKey;
+};
+
+static PARCBuffer *
+_createDerivedKey(const char *key, size_t keylength, unsigned char *salt, unsigned int saltlen)
+{
+ unsigned char buffer[SHA256_DIGEST_LENGTH];
+ HMAC(EVP_sha256(), key, (int) keylength, salt, saltlen, buffer, NULL);
+ return parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, buffer);
+}
+
+static PARCCryptoHash *
+_getSecretKeyDigest(PARCSymmetricKeyStore *keyStore)
+{
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+
+ parcCryptoHasher_UpdateBuffer(hasher, keyStore->secretKey);
+ PARCCryptoHash *result = parcCryptoHasher_Finalize(hasher);
+ parcCryptoHasher_Release(&hasher);
+
+ return result;
+}
+
+static bool
+_parcSymmetricKeyStore_Finalize(PARCSymmetricKeyStore **interfacePtr)
+{
+ PARCSymmetricKeyStore *keyStore = *interfacePtr;
+ if (keyStore->secretKey != NULL) {
+ parcBuffer_Release(&keyStore->secretKey);
+ }
+ return true;
+}
+
+PARCKeyStoreInterface *PARCSymmetricKeyStoreAsKeyStore = &(PARCKeyStoreInterface) {
+ .getVerifierKeyDigest = (PARCKeyStoreGetVerifierKeyDigest *) _getSecretKeyDigest,
+ .getCertificateDigest = NULL,
+ .getDEREncodedCertificate = NULL,
+ .getDEREncodedPublicKey = NULL,
+ .getDEREncodedPrivateKey = NULL,
+};
+
+parcObject_ImplementAcquire(parcSymmetricKeyStore, PARCSymmetricKeyStore);
+parcObject_ImplementRelease(parcSymmetricKeyStore, PARCSymmetricKeyStore);
+
+parcObject_Override(PARCSymmetricKeyStore, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcSymmetricKeyStore_Finalize);
+
+// =============================================================
+LONGBOW_STOP_DEPRECATED_WARNINGS
+// =============================================================
+
+/**
+ * The openssl ASN1 representation of the PARC symmetric key keystore.
+ * It will be written to disk in DER format with an i2d call
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef struct PARCAESKeystore_info_st {
+ ASN1_INTEGER *version;
+ ASN1_OBJECT *algorithm_oid;
+ ASN1_OCTET_STRING *encrypted_key;
+} _PARCSymmeticSignerFileStoreInfo;
+
+// This generates a name that is not compliant with the PARC Naming conventions.
+DECLARE_ASN1_FUNCTIONS(_PARCSymmeticSignerFileStoreInfo)
+
+ASN1_SEQUENCE(_PARCSymmeticSignerFileStoreInfo) = {
+ ASN1_SIMPLE(_PARCSymmeticSignerFileStoreInfo, version, ASN1_INTEGER),
+ ASN1_SIMPLE(_PARCSymmeticSignerFileStoreInfo, algorithm_oid, ASN1_OBJECT),
+ ASN1_SIMPLE(_PARCSymmeticSignerFileStoreInfo, encrypted_key, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(_PARCSymmeticSignerFileStoreInfo)
+
+IMPLEMENT_ASN1_FUNCTIONS(_PARCSymmeticSignerFileStoreInfo)
+
+static int
+_i2d_AESKeystore_fp(FILE *fp, _PARCSymmeticSignerFileStoreInfo *aki)
+{
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(_PARCSymmeticSignerFileStoreInfo), fp, aki);
+}
+
+static _PARCSymmeticSignerFileStoreInfo *
+_d2iAESKeystoreFp(FILE *fp, _PARCSymmeticSignerFileStoreInfo *aki)
+{
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(_PARCSymmeticSignerFileStoreInfo), fp, aki);
+}
+
+static bool
+_createKeyStore(const char *filename, const char *password, PARCBuffer *key)
+{
+ FILE *fp = NULL;
+ int fd = -1;
+ int ans = -1;
+ int nid;
+
+ _PARCSymmeticSignerFileStoreInfo *keystore = NULL;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+#else
+ EVP_CIPHER_CTX ctx;
+#endif
+ unsigned char *encrypted_key = NULL;
+
+ int ekl = IV_SIZE + (int) parcBuffer_Remaining(key) + SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE;
+ int encrypt_length;
+
+ fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
+
+ if (fd == -1) {
+ goto Bail;
+ }
+ fp = fdopen(fd, "wb");
+ if (fp == NULL) {
+ goto Bail;
+ }
+
+ PARCBuffer *aes_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\0", 1);
+ PARCBuffer *mac_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\1", 1);
+
+ encrypted_key = malloc(ekl);
+ if (!encrypted_key) {
+ goto Bail;
+ }
+ RAND_bytes(encrypted_key, IV_SIZE);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX_init(ctx);
+ if (!EVP_EncryptInit(ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), encrypted_key)) {
+ goto Bail;
+ }
+
+ unsigned char *p;
+ p = encrypted_key + IV_SIZE;
+ if (!EVP_EncryptUpdate(ctx, p, &encrypt_length, parcByteArray_Array(parcBuffer_Array(key)), (int) parcBuffer_Remaining(key))) {
+ goto Bail;
+ }
+ p += encrypt_length;
+ if (!EVP_EncryptFinal(ctx, p, &encrypt_length)) {
+ goto Bail;
+ }
+#else
+ EVP_CIPHER_CTX_init(&ctx);
+ if (!EVP_EncryptInit(&ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), encrypted_key)) {
+ goto Bail;
+ }
+
+ unsigned char *p;
+ p = encrypted_key + IV_SIZE;
+ if (!EVP_EncryptUpdate(&ctx, p, &encrypt_length, parcByteArray_Array(parcBuffer_Array(key)), (int) parcBuffer_Remaining(key))) {
+ goto Bail;
+ }
+ p += encrypt_length;
+ if (!EVP_EncryptFinal(&ctx, p, &encrypt_length)) {
+ goto Bail;
+ }
+#endif
+ p += encrypt_length;
+ HMAC(EVP_sha256(), parcByteArray_Array(parcBuffer_Array(mac_key)), SHA256_DIGEST_LENGTH, encrypted_key, p - encrypted_key, p, NULL);
+
+ if (!(keystore = _PARCSymmeticSignerFileStoreInfo_new())) {
+ goto Bail;
+ }
+ if (!(keystore->version = ASN1_INTEGER_new())) {
+ goto Bail;
+ }
+ if (!ASN1_INTEGER_set(keystore->version, AES_KEYSTORE_VERSION)) {
+ goto Bail;
+ }
+
+ keystore->algorithm_oid = OBJ_txt2obj(AES_DEFAULT_DIGEST_ALGORITHM, 0);
+ nid = OBJ_obj2nid(keystore->algorithm_oid);
+ if (nid == NID_undef) {
+ goto Bail; // Shouldn't happen now but could later if we support more algorithms
+ }
+ if (!ASN1_OCTET_STRING_set(keystore->encrypted_key, encrypted_key, ekl)) {
+ goto Bail;
+ }
+ _i2d_AESKeystore_fp(fp, keystore);
+ ans = 0;
+ goto cleanup;
+
+ Bail:
+ ans = -1;
+ cleanup:
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX_free(ctx);
+#endif
+ parcBuffer_Release(&aes_key);
+ parcBuffer_Release(&mac_key);
+
+ if (fp != NULL) {
+ fclose(fp);
+ }
+ if (encrypted_key) {
+ free(encrypted_key);
+ }
+ if (keystore) {
+ _PARCSymmeticSignerFileStoreInfo_free(keystore);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return (ans);
+}
+
+static PARCBuffer *
+_AESKeyStoreInit(const char *filename, const char *password)
+{
+ PARCBuffer *secret_key = NULL;
+
+ FILE *fp = NULL;
+ _PARCSymmeticSignerFileStoreInfo *ki = NULL;
+ int version;
+ char oidstr[80];
+
+ PARCBuffer *aes_key = NULL;
+ PARCBuffer *mac_key = NULL;
+
+ unsigned char check[SHA256_DIGEST_LENGTH];
+ unsigned char *keybuf = NULL;
+ int check_start;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+#else
+ EVP_CIPHER_CTX ctx;
+#endif
+ int length = 0;
+ int final_length = 0;
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ goto Bail;
+ }
+
+ ki = _d2iAESKeystoreFp(fp, NULL);
+ fclose(fp);
+ if (ki == NULL) {
+ goto Bail;
+ }
+
+ version = (int) ASN1_INTEGER_get(ki->version);
+ if (version != AES_KEYSTORE_VERSION) {
+ goto Bail;
+ }
+
+ OBJ_obj2txt(oidstr, sizeof(oidstr), ki->algorithm_oid, 0);
+ if (strcasecmp(oidstr, AES_DEFAULT_DIGEST_ALGORITHM)) {
+ goto Bail;
+ }
+
+ if (ki->encrypted_key->length < IV_SIZE + (SHA256_DIGEST_LENGTH * 2) + AES_BLOCK_SIZE) {
+ goto Bail;
+ }
+
+ aes_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\0", 1);
+ mac_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\1", 1);
+
+ check_start = ki->encrypted_key->length - SHA256_DIGEST_LENGTH;
+ HMAC(EVP_sha256(),
+ parcByteArray_Array(parcBuffer_Array(mac_key)),
+ SHA256_DIGEST_LENGTH,
+ ki->encrypted_key->data,
+ check_start,
+ check,
+ NULL);
+
+ if (memcmp(&ki->encrypted_key->data[check_start], check, SHA256_DIGEST_LENGTH)) {
+ goto Bail;
+ }
+ keybuf = malloc(SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX_init(ctx);
+ if (!EVP_DecryptInit(ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), ki->encrypted_key->data)) {
+ goto Bail;
+ }
+ if (!EVP_DecryptUpdate(ctx, keybuf, &length, &ki->encrypted_key->data[IV_SIZE],
+ ki->encrypted_key->length - IV_SIZE - SHA256_DIGEST_LENGTH)) {
+ goto Bail;
+ }
+
+ if (!EVP_DecryptFinal(ctx, keybuf + length, &final_length)) {
+ goto Bail;
+ }
+#else
+ EVP_CIPHER_CTX_init(&ctx);
+ if (!EVP_DecryptInit(&ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), ki->encrypted_key->data)) {
+ goto Bail;
+ }
+ if (!EVP_DecryptUpdate(&ctx, keybuf, &length, &ki->encrypted_key->data[IV_SIZE],
+ ki->encrypted_key->length - IV_SIZE - SHA256_DIGEST_LENGTH)) {
+ goto Bail;
+ }
+
+ if (!EVP_DecryptFinal(&ctx, keybuf + length, &final_length)) {
+ goto Bail;
+ }
+#endif
+ secret_key = parcBuffer_CreateFromArray(keybuf, length);
+ parcBuffer_Flip(secret_key);
+
+ goto out;
+
+ Bail:
+ free(keybuf);
+
+ out:
+ if (aes_key) {
+ parcBuffer_Release(&aes_key);
+ }
+
+ if (mac_key) {
+ parcBuffer_Release(&mac_key);
+ }
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX_free(ctx);
+#endif
+ return secret_key;
+}
+
+/**
+ * Create a symmetric (secret) key of the given bit length (e.g. 256)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *
+parcSymmetricKeyStore_CreateKey(unsigned bits)
+{
+ assertTrue((bits & 0x07) == 0, "bits must be a multiple of 8");
+
+ unsigned keylength = bits / 8;
+ uint8_t buffer[keylength];
+ RAND_bytes(buffer, keylength);
+ return parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(keylength), keylength, buffer));
+}
+
+PARCBuffer *
+parcSymmetricKeyStore_GetKey(PARCSymmetricKeyStore *keyStore)
+{
+ return keyStore->secretKey;
+}
+
+PARCCryptoHash *
+parcSymmetricKeyStore_GetVerifierKeyDigest(PARCSymmetricKeyStore *keyStore)
+{
+ return _getSecretKeyDigest(keyStore);
+}
+
+/**
+ * Creates a PARC format symmetric keystore. It only contains a single key.
+ *
+ * The final filename will be "file_prefix.
+ *
+ * Returns 0 on success, -1 on error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool
+parcSymmetricKeyStore_CreateFile(const char *filename, const char *password, PARCBuffer *secret_key)
+{
+ assertTrue(parcBuffer_Remaining(secret_key) > 0, "The secret_key buffer is not flipped. See parcBuffer_Flip()");
+ return _createKeyStore(filename, password, secret_key) == 0;
+}
+
+/**
+ * Create a PKCS12 signing context for use in ccnx_Signing. It is destroyed
+ * by ccnx_Signing when the signing context is destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSymmetricKeyStore *
+parcSymmetricKeyStore_OpenFile(const char *filename, const char *password, PARCCryptoHashType hmacHashType)
+{
+ PARCBuffer *secretKey = _AESKeyStoreInit(filename, password);
+ assertNotNull(secretKey, "Could not read AES keystore %s", filename);
+
+ PARCSymmetricKeyStore *keyStore = parcSymmetricKeyStore_Create(secretKey);
+ parcBuffer_Release(&secretKey);
+
+ return keyStore;
+}
+
+/**
+ * Create a PKCS12 signing context for use in ccnx_Signing from the provided key. It is destroyed
+ * by parc_Signing when the signing context is destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSymmetricKeyStore *
+parcSymmetricKeyStore_Create(PARCBuffer *secret_key)
+{
+ PARCSymmetricKeyStore *keyStore = parcObject_CreateAndClearInstance(PARCSymmetricKeyStore);
+ assertNotNull(keyStore, "parcObject_CreateAndClearInstance returned NULL, cannot allocate keystore");
+
+ keyStore->secretKey = parcBuffer_Acquire(secret_key);
+
+ return keyStore;
+}
+
+// =============================================================
+LONGBOW_START_DEPRECATED_WARNINGS
+// =============================================================
diff --git a/libparc/parc/security/parc_SymmetricKeyStore.h b/libparc/parc/security/parc_SymmetricKeyStore.h
new file mode 100644
index 00000000..3271b676
--- /dev/null
+++ b/libparc/parc/security/parc_SymmetricKeyStore.h
@@ -0,0 +1,169 @@
+/*
+ * 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_SymmetricKeyStore.h
+ * @ingroup security
+ * @brief A PARCKeyStore instance for symmetric keys that can be used to produce,
+ * for example, HMAC authenticator tags.
+ *
+ * The secret key is stored in a PARC proprietary file format.
+ *
+ * ---------------------------------------------------------------------------
+ * From the Java implementation code comments:
+ *
+ * This is a specialized keystore for storing symmetric keys. We looked at PKCS #11 for this but decided
+ * against it for now because industry doesn't seem to be standardizing around it - at least not yet, and
+ * standard support for it is somewhat sketchy at this point.
+ *
+ * The keystore can be used for only one key at a time and is located by naming it with a suffix
+ * created from the key's digest.
+ *
+ * Following is the formula for the KeyStore
+ *
+ * Let P=passphrase
+ * Let PT = symmetric key to store
+ * Let IV = random 16-bytes
+ *
+ * aesK = HMAC-SHA256(P, '\0')
+ * macK = HMAC-SHA256(P, '\1')
+ * AES256-CBC(IV, key, PT) - performs AES256 in CBC mode
+ *
+ * SK = IV || AES256-CBC(IV, aesK, PT) || HMAC-SHA256(macK, AES256-CBC(IV, aesK, PT))
+ *
+ * SK is the symmetric keystore ciphertext
+ *
+ * ASN1 encoded KeyStore = Version || Key algorithm OID || SK
+ * ---------------------------------------------------------------------------
+ *
+ */
+#ifndef libparc_parc_SymmetricKeyStore_h
+#define libparc_parc_SymmetricKeyStore_h
+
+#include <parc/security/parc_Signer.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_symmetric_keystore;
+typedef struct parc_symmetric_keystore PARCSymmetricKeyStore;
+
+extern PARCKeyStoreInterface *PARCSymmetricKeyStoreAsKeyStore;
+
+/**
+ * Increase the number of references to a `PARCSymmetricKeyStore` instance.
+ *
+ * Note that new `PARCSymmetricKeyStore` is not created,
+ * only that the given `PARCSymmetricKeyStore` reference count is incremented.
+ * Discard the reference by invoking `parcSymmetricKeyStore_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeyStore instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSymmetricKeyStore_CreateFile(...);
+ * PARCSymmetricKeyStore *a = parcSymmetricKeyStore_OpenFile(...)
+ *
+ * PARCSymmetricKeyStore *b = parcSymmetricKeyStore_Acquire();
+ *
+ * parcSymmetricKeyStore_Release(&a);
+ * parcSymmetricKeyStore_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSymmetricKeyStore *parcSymmetricKeyStore_Acquire(const PARCSymmetricKeyStore *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSymmetricKeyStore` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeyStore *a = parcSymmetricKeyStore_Open(...);
+ *
+ * parcSymmetricKeyStore_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSymmetricKeyStore_Release(PARCSymmetricKeyStore **instancePtr);
+
+/**
+ * Create a symmetric (secret) key of the given bit length (e.g. 256)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *parcSymmetricKeyStore_CreateKey(unsigned bits);
+
+PARCBuffer *parcSymmetricKeyStore_GetKey(PARCSymmetricKeyStore *keyStore);
+
+PARCCryptoHash *parcSymmetricKeyStore_GetVerifierKeyDigest(PARCSymmetricKeyStore *keyStore);
+
+/**
+ * Creates a PARC format symmetric keystore. It only contains a single key.
+ *
+ * Return 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcSymmetricKeyStore_CreateFile(const char *filename, const char *password, PARCBuffer *secret_key);
+
+/**
+ * Create a PKCS12 signing context for use in ccnx_Signing by reading the PARC symmetric key
+ * file given by filename. It is destroyed
+ * by parc_Signing when the signing context is destroyed.
+ *
+ * @param [in] filename The filename.
+ * @param [in] password The password to use.
+ * @param [in] hmacHashType is for the HMAC, e.g. PARCCryptoHashType_SHA256
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSymmetricKeyStore *parcSymmetricKeyStore_OpenFile(const char *filename, const char *password, PARCCryptoHashType hmacHashType);
+
+/**
+ * Create a PKCS12 signing context for use in ccnx_Signing from the provided key.
+ * This is an in-memory only signer.
+ * It is destroyed by parc_Signing when the signing context is destroyed.
+ *
+ * @param secret_key is the shared secret, we take ownership of the buffer.
+ * @param hmacHashType is for the HMAC, e.g. PARCCryptoHashType_SHA256
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSymmetricKeyStore *parcSymmetricKeyStore_Create(PARCBuffer *secret_key);
+#endif // libparc_parc_SymmetricKeyStore_h
diff --git a/libparc/parc/security/parc_Verifier.c b/libparc/parc/security/parc_Verifier.c
new file mode 100755
index 00000000..967356a5
--- /dev/null
+++ b/libparc/parc/security/parc_Verifier.c
@@ -0,0 +1,107 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_Verifier.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_verifier {
+ PARCObject *instance;
+ PARCVerifierInterface *interface;
+};
+
+static bool
+_parcVerifier_FinalRelease(PARCVerifier **verifierPtr)
+{
+ PARCVerifier *verifier = *verifierPtr;
+ if (verifier->instance != NULL) {
+ parcObject_Release(&(verifier->instance));
+ }
+ return true;
+}
+
+void
+parcVerifier_AssertValid(const PARCVerifier *verifier)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+}
+
+parcObject_ImplementAcquire(parcVerifier, PARCVerifier);
+parcObject_ImplementRelease(parcVerifier, PARCVerifier);
+
+parcObject_Override(PARCVerifier, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcVerifier_FinalRelease);
+
+PARCVerifier *
+parcVerifier_Create(PARCObject *instance, PARCVerifierInterface *interfaceContext)
+{
+ assertNotNull(interfaceContext, "Parameter `interfaceContext` must be non-null interface pointer");
+ assertNotNull(instance, "Parameter `instance` must be non-null PARCObject pointer");
+
+ PARCVerifier *verifier = parcObject_CreateInstance(PARCVerifier);
+ assertNotNull(verifier, "parcObject_CreateInstance returned NULL");
+
+ verifier->instance = parcObject_Acquire(instance);
+ verifier->interface = interfaceContext;
+
+ return verifier;
+}
+
+bool
+parcVerifier_VerifyDigestSignature(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoHash *locallyComputedHash,
+ PARCCryptoSuite suite, PARCSignature *signatureToVerify)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ assertNotNull(locallyComputedHash, "cryptoHash to verify must not be null");
+ assertNotNull(signatureToVerify, "Signature to verify must not be null");
+
+ // null keyid is allowed now that we support CRCs, etc.
+
+ return verifier->interface->VerifyDigest(verifier->instance, keyid, locallyComputedHash, suite, signatureToVerify);
+}
+
+bool
+parcVerifier_AllowedCryptoSuite(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoSuite suite)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ return verifier->interface->AllowedCryptoSuite(verifier->instance, keyid, suite);
+}
+
+PARCCryptoHasher*
+parcVerifier_GetCryptoHasher(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoHashType hashType)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ return verifier->interface->GetCryptoHasher(verifier->instance, keyid, hashType);
+}
+
+void
+parcVerifier_AddKey(PARCVerifier *verifier, PARCKey *key)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ verifier->interface->AddKey(verifier->instance, key);
+}
+
+void
+parcVerifier_RemoveKeyId(PARCVerifier *verifier, PARCKeyId *keyid)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ verifier->interface->RemoveKeyId(verifier->instance, keyid);
+}
diff --git a/libparc/parc/security/parc_Verifier.h b/libparc/parc/security/parc_Verifier.h
new file mode 100644
index 00000000..b08f608e
--- /dev/null
+++ b/libparc/parc/security/parc_Verifier.h
@@ -0,0 +1,271 @@
+/*
+ * 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_Verifier.h
+ * @ingroup security
+ * @brief Structures and functions to support verification.
+ *
+ */
+#ifndef libparc_parc_Verifier_h
+#define libparc_parc_Verifier_h
+
+#include <parc/algol/parc_Object.h>
+
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_Signature.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_Key.h>
+
+struct parc_verifier;
+typedef struct parc_verifier PARCVerifier;
+
+/**
+ * @typedef PARCVerifierInterface
+ * @brief The interface for `PARCVerifier`
+ */
+typedef struct parc_verifier_interface {
+ /** @see parcVerifier_GetCryptoHasher */
+ PARCCryptoHasher *(*GetCryptoHasher)(PARCObject * interfaceContext, PARCKeyId * keyid, PARCCryptoHashType hashType);
+
+ /** @see parcVerifier_VerifyDigest */
+ bool (*VerifyDigest)(PARCObject *interfaceContext, PARCKeyId *keyid, PARCCryptoHash *locallyComputedHash,
+ PARCCryptoSuite suite, PARCSignature *signatureToVerify);
+
+ /** @see parcVerifier_AddKey */
+ void (*AddKey)(PARCObject *interfaceContext, PARCKey *key);
+
+ /** @see parcVerifier_RemoveKeyId */
+ void (*RemoveKeyId)(PARCObject *interfaceContext, PARCKeyId *keyid);
+
+ /** @see parcVerifier_AllowedCryptoSuite */
+ bool (*AllowedCryptoSuite)(PARCObject *interfaceContext, PARCKeyId *keyid, PARCCryptoSuite suite);
+} PARCVerifierInterface;
+
+/**
+ * Create a verifier context based on a concrete implementation.
+ *
+ * @param [in] instance A concrete implementation of a `PARCVerifier`
+ * @param [in] interfaceContext The interface of a concrete implementation of a `PARCVerifier`
+ *
+ * @return NULL A `PARCVerifier` could not be allocated
+ * @return PARCSigner A new `PARCVerifier` instance derived from the specified concrete signer context.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ * }
+ * @endcode
+ */
+PARCVerifier *parcVerifier_Create(PARCObject *instance, PARCVerifierInterface *interfaceContext);
+
+/**
+ * Assert that an instance of `PARCVerifier` is valid.
+ *
+ * If the instance is not valid, terminate via {@link trapIllegalValue}
+ *
+ * Valid means the internal state of the type is consistent with its
+ * required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] verifier A pointer to a PARCVerifier instance.
+ *
+ * Example
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ *
+ * parcVerifier_AssertValid(signer);
+ * }
+ * @endcode
+ */
+void parcVerifier_AssertValid(const PARCVerifier *verifier);
+
+/**
+ * Increase the number of references to the given `PARCVerifier` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking `parcVerifier_Release()`.
+ *
+ * @param [in] signer A pointer to a `PARCVerifier` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCVerifier instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ * PARCVerifier *handle = parcVerifier_Acquire(signer);
+ * // use the handle instance as needed
+ * }
+ * @endcode
+ */
+PARCVerifier *parcVerifier_Acquire(const PARCVerifier *verifier);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] verifierPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ *
+ * parcVerifier_Release(&verifier);
+ * }
+ * @endcode
+ */
+void parcVerifier_Release(PARCVerifier **verifierPtr);
+
+/**
+ * Verify the signature against the provided digest with the specified key.
+ * If we do not trust the key, the signature will be rejected. In this context,
+ * trusting a key means that it was previously added to this verifiers "store".
+ *
+ * Returns true if the signature is accepted,false if it is rejected.
+ *
+ * @param [in] verifier A `PARCVerifier` instance.
+ * @param [in] keyId A `PARCKeyId` which identifies the verification key.
+ * @param [in] hashDigest A `PARCCryptoHash` which stores the locally computed digest.
+ * @param [in] suite The `PARCCryptoSuite` in which verification is performed.
+ * @param [in] signature The `PARCSignature` which is to be verified.
+ *
+ * @retval true If the signature is valid
+ * @retval false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ *
+ * PARCKeyId *keyId = ...
+ * PARCCryptoHash *hash = ...
+ * PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256;
+ * PARCSignature *signature = ...
+ *
+ * bool valid = parcVerifier_VerifyDigestSignature(verifier, keyId, hash, suite, signature);
+ * if (valid) {
+ * // proceed
+ * }
+ * }
+ * @endcode
+ */
+bool
+parcVerifier_VerifyDigestSignature(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoHash *hashDigest,
+ PARCCryptoSuite suite, PARCSignature *signatureToVerify);
+
+/**
+ * Check to see if the specified `PARCKeyId` is allowed with the given `PARCCryptoSuite`.
+ *
+ * A`PARCKey` identified by the given `PARCKeyId` can only be used for a particular algorithm.
+ *
+ * @param [in] verifier A `PARCVerifier` instance with a store of trusted `PARCKey` instances.
+ * @param [in] keyId A `PARCKeyId` referring to the key we will check against (for this verifier).
+ * @param [in] suite A `PARCCryptoSuite` to check against.
+ *
+ * @retval true If allowed
+ * @retval false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifeir = ...
+ * PARCKeyId *keyId = ...
+ * bool isAllowed = parcVerifier_AllowedCryptoSuite(verifier, keyId, PARCCryptoSuite_RSA_SHA256);
+ * // act accordingly
+ * }
+ * @endcode
+ */
+bool parcVerifier_AllowedCryptoSuite(PARCVerifier *verifier, PARCKeyId *keyId, PARCCryptoSuite suite);
+
+/**
+ * Returns a `PARCCryptoHasher` for use with the `PARCKeyId`. The caller should have already
+ * verified that the specified `PARCCryptoHashType` is compatible with the key ID by
+ * checking the AllowedCryptoSuite.
+ *
+ * @param [in] verifier A `PARCVerifier` instance with a store of trusted `PARCKey` instances.
+ * @param [in] keyId A `PARCKeyId` referring to the key we will check against (for this verifier).
+ * @param [in] suite A `PARCCryptoSuite` to check against.
+ *
+ * @retval non-NULL A `PARCCryptoHasher` instance.
+ * @retval NULL If the PARCCryptoHashType is not compatible with the key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifeir = ...
+ * PARCKeyId *keyId = ...
+ * bool isAllowed = parcVerifier_AllowedCryptoSuite(verifier, keyId, PARCCryptoHashType_SHA256);
+ * // act accordingly
+ * }
+ * @endcode
+ */
+PARCCryptoHasher *parcVerifier_GetCryptoHasher(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoHashType hashType);
+
+/**
+ * Add the specified `PARCKey` to the trusted key store.
+ *
+ * @param [in] verifier A `PARCVerifier` instance with a store of trusted `PARCKey` instances.
+ * @param [in] key A `PARCKey` containing the new trusted key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifeir = ...
+ * PARCKey *key = ...
+ * parcVerifier_AddKey(verifier, key);
+ * }
+ * @endcode
+ */
+void parcVerifier_AddKey(PARCVerifier *verifier, PARCKey *key);
+
+/**
+ * Remove the key associated with the given `PARCKeyId` from the trusted key store.
+ *
+ * @param [in] verifier A `PARCVerifier` instance with a store of trusted `PARCKey` instances.
+ * @param [in] keyId A `PARCKeyId` referencing the `PARCKey` to remove from the keystore.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifeir = ...
+ * PARCKey *key = ...
+ * parcVerifier_AddKey(verifier, key);
+ *
+ * // Use the verifier with the key...
+ * ...
+ *
+ * // Now remove it because we no longer need or trust it.
+ * PARCKeyId *keyId = parcKey_GetKeyId(key);
+ * parcVerifier_RemoveKeyId(verifier, keyId);
+ * }
+ * @endcode
+ */
+void parcVerifier_RemoveKeyId(PARCVerifier *verifier, PARCKeyId *keyid);
+#endif // libparc_parc_Verifier_h
diff --git a/libparc/parc/security/parc_X509Certificate.c b/libparc/parc/security/parc_X509Certificate.c
new file mode 100644
index 00000000..8cc4b0b7
--- /dev/null
+++ b/libparc/parc/security/parc_X509Certificate.c
@@ -0,0 +1,516 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * parc_X509Certificate.c
+ * PARC Library
+ */
+
+#include <config.h>
+
+#include <parc/security/parc_X509Certificate.h>
+#include <parc/security/parc_Certificate.h>
+
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_Security.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/pkcs12.h>
+
+static PARCCryptoHash *_getPublicKeyDigest(void *interfaceContext);
+static PARCCryptoHash *_getCertificateDigest(void *interfaceContext);
+static PARCBuffer *_getDEREncodedCertificate(void *interfaceContext);
+static PARCBuffer *_getDEREncodedPublicKey(void *interfaceContext);
+static PARCCertificateType _getCertificateType(const void *cert);
+static PARCContainerEncoding _getContainerEncoding(const void *cert);
+
+PARCCertificateInterface *PARCX509CertificateInterface = &(PARCCertificateInterface) {
+ .GetPublicKeyDigest = _getPublicKeyDigest,
+ .GetCertificateDigest = _getCertificateDigest,
+ .GetDEREncodedCertificate = _getDEREncodedCertificate,
+ .GetDEREncodedPublicKey = _getDEREncodedPublicKey,
+ .GetCertificateType = _getCertificateType,
+ .GetContainerEncoding = _getContainerEncoding
+};
+
+struct parc_X509_certificate {
+ PARCCertificateType type;
+ PARCContainerEncoding encoding;
+
+ // Cache of results
+ PARCCryptoHash *keyDigest;
+ PARCCryptoHash *certificateDigest;
+ PARCBuffer *derEncodedCertificate;
+ PARCBuffer *derEncodedKey;
+
+ BIO *certificateBIO;
+ X509 *certificate;
+ EVP_PKEY *publicKey;
+};
+
+#ifdef __APPLE__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+static PARCCryptoHash *
+_getPublicKeyDigest(void *interfaceContext)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(interfaceContext, "Parameter must be non-null PARCX509Certificate");
+
+ PARCX509Certificate *certificate = (PARCX509Certificate *) interfaceContext;
+
+ if (certificate->keyDigest == NULL) {
+ PARCBuffer *derEncodedKey = _getDEREncodedPublicKey(certificate);
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBuffer(hasher, derEncodedKey);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+
+ certificate->keyDigest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, parcCryptoHash_GetDigest(hash));
+ parcCryptoHash_Release(&hash);
+ parcCryptoHasher_Release(&hasher);
+ }
+
+ return certificate->keyDigest;
+}
+
+static PARCCryptoHash *
+_getCertificateDigest(void *interfaceContext)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(interfaceContext, "Parameter must be non-null PARCX509Certificate");
+
+ PARCX509Certificate *certificate = (PARCX509Certificate *) interfaceContext;
+
+ if (certificate->certificateDigest == NULL) {
+ uint8_t digestBuffer[SHA256_DIGEST_LENGTH];
+ int result = X509_digest(certificate->certificate, EVP_sha256(), digestBuffer, NULL);
+ if (result) {
+ PARCBuffer *digest =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, digestBuffer));
+ certificate->certificateDigest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, digest);
+ parcBuffer_Release(&digest);
+ }
+ }
+
+ return certificate->certificateDigest;
+}
+
+static PARCBuffer *
+_getDEREncodedCertificate(void *interfaceContext)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(interfaceContext, "Parameter must be non-null PARCX509Certificate");
+
+ PARCX509Certificate *certificate = (PARCX509Certificate *) interfaceContext;
+
+ if (certificate->derEncodedCertificate == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_X509(certificate->certificate, &der);
+ if (derLength > 0) {
+ certificate->derEncodedCertificate =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return certificate->derEncodedCertificate;
+}
+
+static PARCBuffer *
+_getDEREncodedPublicKey(void *interfaceContext)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(interfaceContext, "Parameter must be non-null PARCX509Certificate");
+
+ PARCX509Certificate *certificate = (PARCX509Certificate *) interfaceContext;
+
+ if (certificate->derEncodedKey == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_PUBKEY(certificate->publicKey, &der);
+ if (derLength > 0) {
+ certificate->derEncodedKey = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return certificate->derEncodedKey;
+}
+
+static PARCCertificateType
+_getCertificateType(const void *instance)
+{
+ PARCX509Certificate *certificate = (PARCX509Certificate *) instance;
+ return certificate->type;
+}
+
+static PARCContainerEncoding
+_getContainerEncoding(const void *instance)
+{
+ PARCX509Certificate *certificate = (PARCX509Certificate *) instance;
+ return certificate->encoding;
+}
+
+static void
+_parcX509Certificate_FinalRelease(PARCX509Certificate **certP)
+{
+ PARCX509Certificate *cert = (PARCX509Certificate *) *certP;
+ if (cert->certificateBIO != NULL) {
+ BIO_free_all(cert->certificateBIO);
+ }
+ if (cert->publicKey != NULL) {
+ EVP_PKEY_free(cert->publicKey);
+ }
+ if (cert->certificate != NULL) {
+ X509_free(cert->certificate);
+ }
+ if (cert->keyDigest != NULL) {
+ parcCryptoHash_Release(&cert->keyDigest);
+ }
+ if (cert->certificateDigest != NULL) {
+ parcCryptoHash_Release(&cert->certificateDigest);
+ }
+ if (cert->derEncodedCertificate != NULL) {
+ parcBuffer_Release(&cert->derEncodedCertificate);
+ }
+ if (cert->derEncodedKey != NULL) {
+ parcBuffer_Release(&cert->derEncodedKey);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCX509Certificate, _parcX509Certificate_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCX509Certificate *
+_createEmptyCertificate()
+{
+ PARCX509Certificate *cert = parcObject_CreateInstance(PARCX509Certificate);
+ cert->certificateBIO = NULL;
+ cert->certificate = NULL;
+ cert->publicKey = NULL;
+ cert->keyDigest = NULL;
+ cert->certificateDigest = NULL;
+ cert->derEncodedCertificate = NULL;
+ cert->derEncodedKey = NULL;
+ assertNotNull(cert, "Failure allocating memory for a new PARCX509Certificate instance");
+
+ return cert;
+}
+
+static bool
+_addCertificateExtensionWithContext(X509 *cert, int nid, char *value)
+{
+ X509_EXTENSION *extension;
+ X509V3_CTX context;
+
+ X509V3_set_ctx_nodb(&context);
+ X509V3_set_ctx(&context, cert, cert, NULL, NULL, 0);
+ extension = X509V3_EXT_conf_nid(NULL, &context, nid, value);
+ if (extension == NULL) {
+ return false;
+ }
+ X509_add_ext(cert, extension, -1);
+ X509_EXTENSION_free(extension);
+ return true;
+}
+
+static bool
+_addCertificateExtension(X509 *cert, int nid, char *value)
+{
+ X509_EXTENSION *extension = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
+ if (extension == NULL) {
+ return false;
+ }
+ X509_add_ext(cert, extension, -1);
+ X509_EXTENSION_free(extension);
+ return true;
+}
+
+static bool
+_addKeyIdentifier(X509 *cert)
+{
+ unsigned char spkid[SHA256_DIGEST_LENGTH];
+ char spkid_hex[1 + 2 * SHA256_DIGEST_LENGTH];
+
+ /* Generate a KeyID which is the SHA256 digest of the DER encoding
+ * of a SubjectPublicKeyInfo. Note that this is slightly uncommon,
+ * but it is more general and complete than digesting the BIT STRING
+ * component of the SubjectPublicKeyInfo itself (and no standard dictates
+ * how you must generate a key ID). This code must produce the same result
+ * as the Java version applied to the same SubjectPublicKeyInfo.
+ */
+
+ if (ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(), X509_get_X509_PUBKEY(cert), spkid, NULL)) {
+ for (int i = 0; i < 32; i++) {
+ snprintf(&spkid_hex[2 * i], 3, "%02X", (unsigned) spkid[i]);
+ }
+ if (_addCertificateExtension(cert, NID_subject_key_identifier, spkid_hex) == true) {
+ if (_addCertificateExtensionWithContext(cert, NID_authority_key_identifier, "keyid:always") == true) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+_addSubjectName(X509 *cert, const char *subjectname)
+{
+ // Set up the simple subject name and issuer name for the certificate.
+ X509_NAME *name = X509_get_subject_name(cert);
+ assertNotNull(name, "Got null name from X509_get_subject_name");
+
+ if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *) subjectname, -1, -1, 0)) {
+ if (X509_set_issuer_name(cert, name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+_addRandomSerial(X509 *cert)
+{
+ unsigned long serial = 0;
+ unsigned char serial_bytes[sizeof(serial)];
+
+ // Construct random positive serial number.
+ RAND_bytes(serial_bytes, sizeof(serial_bytes));
+ serial_bytes[0] &= 0x7F;
+ serial = 0;
+ for (int i = 0; i < sizeof(serial_bytes); i++) {
+ serial = (256 * serial) + serial_bytes[i];
+ }
+ ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
+ return true;
+}
+
+static bool
+_addValidityPeriod(X509 *cert, size_t validityDays)
+{
+ // Set the validity from now for the specified number of days.
+ X509_gmtime_adj(X509_get_notBefore(cert), (long) 0);
+ X509_gmtime_adj(X509_get_notAfter(cert), (long) (60 * 60 * 24 * validityDays));
+ return true;
+}
+
+static bool
+_addExtensions(X509 *cert)
+{
+ // Add the necessary extensions.
+ if (_addCertificateExtension(cert, NID_basic_constraints, "critical,CA:FALSE") == true) {
+ if (_addCertificateExtension(cert, NID_key_usage, "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement") == true) {
+ if (_addCertificateExtension(cert, NID_ext_key_usage, "clientAuth") == true) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static PARCX509Certificate *
+_parcX509Certificate_CreateFromPEMFile(const char *filename)
+{
+ parcSecurity_AssertIsInitialized();
+
+ PARCX509Certificate *cert = _createEmptyCertificate();
+
+ FILE *fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ parcX509Certificate_Release(&cert);
+ return NULL;
+ }
+
+ cert->certificateBIO = BIO_new(BIO_s_file());
+ size_t result = BIO_read_filename(cert->certificateBIO, filename);
+ assertTrue(result == 1, "Unable to open the specified file");
+
+ cert->certificate = PEM_read_bio_X509(cert->certificateBIO, NULL, 0, NULL);
+ cert->publicKey = X509_get_pubkey(cert->certificate);
+
+ return cert;
+}
+
+parcObject_ImplementAcquire(parcX509Certificate, PARCX509Certificate);
+
+parcObject_ImplementRelease(parcX509Certificate, PARCX509Certificate);
+
+PARCX509Certificate *
+parcX509Certificate_CreateFromPEMFile(const char *filename)
+{
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(filename);
+ if (certificate) {
+ certificate->type = PARCCertificateType_X509;
+ certificate->encoding = PARCContainerEncoding_PEM;
+ return certificate;
+ }
+ return NULL;
+}
+
+PARCX509Certificate *
+parcX509Certificate_CreateFromDERBuffer(const PARCBuffer *buffer)
+{
+ parcSecurity_AssertIsInitialized();
+
+ PARCX509Certificate *cert = _createEmptyCertificate();
+ cert->type = PARCCertificateType_X509;
+ cert->encoding = PARCContainerEncoding_DER;
+
+ PARCByteArray *array = parcBuffer_Array(buffer);
+ uint8_t *arrayIn = parcByteArray_Array(array);
+
+ cert->certificate = d2i_X509(&cert->certificate, (const unsigned char **) &arrayIn, parcBuffer_Remaining(buffer));
+ if (cert->certificate == NULL) {
+ parcX509Certificate_Release(&cert);
+ return NULL;
+ }
+ cert->publicKey = X509_get_pubkey(cert->certificate);
+
+ return cert;
+}
+
+PARCX509Certificate *
+parcX509Certificate_CreateSelfSignedCertificate(PARCBuffer **privateKeyBuffer, char *subjectName, int keyLength, size_t validityDays)
+{
+ parcSecurity_AssertIsInitialized();
+
+ RSA *rsa = RSA_new();
+ assertNotNull(rsa, "RSA_new failed.");
+
+ EVP_PKEY *privateKey = EVP_PKEY_new();
+ assertNotNull(privateKey, "EVP_PKEY_new() failed.");
+
+ X509 *cert = X509_new();
+ assertNotNull(cert, "X509_new() failed.");
+
+ int res;
+ BIGNUM *pub_exp;
+
+ 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;
+ }
+ }
+ }
+ 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);
+
+ 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);
+
+ return NULL;
+ }
+
+ PARCBuffer *derBuffer = parcBuffer_Allocate(numBytes);
+ parcBuffer_Flip(parcBuffer_PutArray(derBuffer, numBytes, certificateDerEncoding));
+
+ 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);
+
+ return NULL;
+ }
+
+ *privateKeyBuffer = parcBuffer_Allocate(privateKeyByteCount);
+ parcBuffer_Flip(parcBuffer_PutArray(*privateKeyBuffer, privateKeyByteCount, privateKeyBytes));
+
+ return certificate;
+}
+
+
+PARCCryptoHash *
+parcX509Certificate_GetCertificateDigest(PARCX509Certificate *certificate)
+{
+ return _getCertificateDigest(certificate);
+}
+
+PARCCryptoHash *
+parcX509Certificate_getPublicKeyDigest(PARCX509Certificate *certificate)
+{
+ return _getPublicKeyDigest(certificate);
+}
+
+PARCBuffer *
+parcX509Certificate_GetDEREncodedCertificate(PARCX509Certificate *certificate)
+{
+ return _getDEREncodedCertificate(certificate);
+}
+
+PARCBuffer *
+parcX509Certificate_GetDEREncodedPublicKey(PARCX509Certificate *certificate)
+{
+ return _getDEREncodedPublicKey(certificate);
+}
+
+#ifdef __APPLE__
+#pragma clang diagnostic pop
+#endif
+
diff --git a/libparc/parc/security/parc_X509Certificate.h b/libparc/parc/security/parc_X509Certificate.h
new file mode 100755
index 00000000..037d6aac
--- /dev/null
+++ b/libparc/parc/security/parc_X509Certificate.h
@@ -0,0 +1,207 @@
+/*
+ * 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_X509Certificate.h
+ * @ingroup security
+ * @brief The API for a generic certificate.
+ *
+ */
+
+#ifndef libparc_parc_X509Certificate_h
+#define libparc_parc_X509Certificate_h
+
+#include <parc/security//parc_Certificate.h>
+
+struct parc_X509_certificate;
+typedef struct parc_X509_certificate PARCX509Certificate;
+
+extern PARCCertificateInterface *PARCX509CertificateInterface;
+
+/**
+ * Create a `PARCX509Certificate` from a PEM-encoded file.
+ *
+ * @param [in] filename A nul-terminated path to a certificate file.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCX509Certificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pathToCertificate = "file.pem";
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(pathToCertificate);
+ * }
+ * @endcode
+ */
+PARCX509Certificate *parcX509Certificate_CreateFromPEMFile(const char *filename);
+
+/**
+ * Create a `PARCX509Certificate` from a DER-encoded buffer.
+ *
+ * @param [in] buffer A `PARCBuffer` instance containing the DER-encoded certificate.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCX509Certificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *certificateBuffer = ...
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromDERBuffer(certificateBuffer);
+ * }
+ * @endcode
+ */
+PARCX509Certificate *parcX509Certificate_CreateFromDERBuffer(const PARCBuffer *buffer);
+
+// TODO
+PARCX509Certificate *parcX509Certificate_CreateSelfSignedCertificate(PARCBuffer **privateKey, char *subjectName, int keyLength, size_t valdityDays);
+
+/**
+ * Increase the number of references to a `PARCX509Certificate` instance.
+ *
+ * Note that a new `PARCX509Certificate` is not created,
+ * only that the given `PARCX509Certificate` reference count is incremented.
+ * Discard the reference by invoking {@link parcX509Certificate_Release}.
+ *
+ * @param [in] certificate A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ * PARCX509Certificate *x2 = parcX509Certificate_Acquire(x);
+ *
+ * parcX509Certificate_Release(&x);
+ * parcX509Certificate_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcX509Certificate_Release}
+ */
+PARCX509Certificate *parcX509Certificate_Acquire(const PARCX509Certificate *certificate);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] certificateP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+void parcX509Certificate_Release(PARCX509Certificate **certificateP);
+
+/**
+ * Retrieve the SHA-256 digest of the DER-encoded certificate.
+ *
+ * @param [in] certificate A pointer to `PARCX509Certificate` instance.
+ *
+ * @return The SHA-256 digest of the @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * PARCCryptoHash *digest = parcX509Certificate_GetCertificateDigest(x);
+ * // use the digest
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcX509Certificate_GetCertificateDigest(PARCX509Certificate *certificate);
+
+/**
+ * Retrieve the SHA-256 digest of the DER-encoded public key that
+ * is contained in the specified `PARCX509Certificate`.
+ *
+ * @param [in] certificate A pointer to `PARCX509Certificate` instance.
+ *
+ * @return The SHA-256 digest of the @p instance's public key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * PARCCryptoHash *digest = parcX509Certificate_GetCertificateKeyDigest(x);
+ * // use the digest
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcX509Certificate_GetCertificateKeyDigest(PARCX509Certificate *certificate);
+
+/**
+ * Retrieve the DER-encoded representation of the specified `PARCX509Certificate`.
+ *
+ * @param [in] certificate A pointer to `PARCX509Certificate` instance.
+ *
+ * @return A newly allocated `PARCBuffer` instance containing the DER-encoded form
+ * of the specified `PARCX509Certificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * PARCBuffer *certificateDER = parcX509Certificate_GetDEREncodedCertificate(x);
+ * // use the digest
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcX509Certificate_GetDEREncodedCertificate(PARCX509Certificate *certificate);
+
+/**
+ * Retrieve the DER-encoded representation of the public key contained within
+ * the specified `PARCX509Certificate`.
+ *
+ * @param [in] certificate A pointer to `PARCX509Certificate` instance.
+ *
+ * @return A newly allocated `PARCBuffer` instance containing the DER-encoded form
+ * of the public key in the `PARCX509Certificate` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * PARCBuffer *publicKeyDER = parcX509Certificate_GetDEREncodedPublicKey(x);
+ * // use the digest
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcX509Certificate_GetDEREncodedPublicKey(PARCX509Certificate *certificate);
+#endif // libparc_parc_X509Certificate_h
diff --git a/libparc/parc/security/test/.gitignore b/libparc/parc/security/test/.gitignore
new file mode 100644
index 00000000..bda8c802
--- /dev/null
+++ b/libparc/parc/security/test/.gitignore
@@ -0,0 +1,24 @@
+test_parc_AesSignerFileStore
+test_parc_CryptoCache
+test_parc_InMemoryVerifier
+test_parc_KeyId
+test_parc_PublicKeySignerPkcs12Store
+test_parc_SelfSignedCertificate
+test_parc_Signature
+test_parc_Signer
+test_parc_SymmetricSignerFileStore
+test_parc_Security
+test_parc_CryptoHash
+test_parc_CryptoHashType
+test_parc_CryptoSuite
+test_parc_Identity
+test_parc_IdentityFile
+test_parc_Key
+test_parc_KeyStore
+test_parc_Verifier
+test_parc_SigningAlgorithm
+test_parc_Certificate
+test_parc_CertificateFactory
+test_parc_ContainerEncoding
+test_parc_CertificateType
+test_parc_X509Certificate
diff --git a/libparc/parc/security/test/CMakeLists.txt b/libparc/parc/security/test/CMakeLists.txt
new file mode 100644
index 00000000..189bc7ca
--- /dev/null
+++ b/libparc/parc/security/test/CMakeLists.txt
@@ -0,0 +1,75 @@
+set(TestsExpectedToPass
+ test_parc_Certificate
+ test_parc_CertificateFactory
+ test_parc_CertificateType
+ test_parc_ContainerEncoding
+ test_parc_CryptoCache
+ test_parc_CryptoHash
+ test_parc_CryptoHashType
+ test_parc_CryptoHasher
+ test_parc_CryptoSuite
+ test_parc_DiffieHellman
+ test_parc_DiffieHellmanKeyShare
+ test_parc_Identity
+ test_parc_IdentityFile
+ test_parc_InMemoryVerifier
+ test_parc_Key
+ test_parc_KeyId
+ test_parc_KeyStore
+ test_parc_SecureRandom
+ test_parc_Pkcs12KeyStore
+ test_parc_PublicKeySigner
+ test_parc_SymmetricKeySigner
+ test_parc_SymmetricKeyStore
+ test_parc_Security
+ test_parc_Signature
+ test_parc_Signer
+ test_parc_SigningAlgorithm
+ test_parc_Verifier
+ test_parc_X509Certificate
+ )
+
+set(EXTRA_DATA_FILES
+ README.digests
+ README.keystore
+ README.symmetric
+ test_crt.der
+ test_crt_der.bin
+ test_crt_sha256.bin
+ test_der.bin
+ test_digest_bytes_128.bin
+ test_digest_bytes_128.sha256
+ test_digest_bytes_128.sha512
+ test.pem
+ test_pubkey.bin
+ test_pubkey.der
+ test_pubkey.pem
+ test_random_bytes
+ test_random_bytes.sig
+ test_random_bytes.hmac_sha256
+ test_random_bytes.hmac_sha512
+ test_rsa.p12
+ test_rsa_crt.der
+ test_rsa_crt_sha256.bin
+ test_rsa_key.der
+ test_rsa_key.pem
+ test_rsa_pub.der
+ test_rsa_pub.pem
+ test_rsa_pub_sha256.bin
+ test_symmetric_key.bin
+ test_symmetric_key.sha256
+ )
+
+foreach(data_file ${EXTRA_DATA_FILES})
+ configure_file(${data_file} ${data_file} COPYONLY)
+endforeach()
+
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libparc/parc/security/test/README.digests b/libparc/parc/security/test/README.digests
new file mode 100644
index 00000000..4abfa940
--- /dev/null
+++ b/libparc/parc/security/test/README.digests
@@ -0,0 +1,12 @@
+#
+# Generate some blocks of bytes to digest, then calculate the "truth" via openssl
+
+dd if=/dev/urandom of=test_digest_bytes_128.bin bs=128 count=1
+
+openssl dgst -sha256 -binary < test_digest_bytes_128.bin > test_digest_bytes_128.sha256
+openssl dgst -sha512 -binary < test_digest_bytes_128.bin > test_digest_bytes_128.sha512
+
+# these are for the symmetric key tests
+openssl sha256 -hmac 'apple_pie_is_good' -binary < test_random_bytes > test_random_bytes.hmac_sha256
+openssl sha512 -hmac 'apple_pie_is_good' -binary < test_random_bytes > test_random_bytes.hmac_sha512
+
diff --git a/libparc/parc/security/test/README.keystore b/libparc/parc/security/test/README.keystore
new file mode 100644
index 00000000..70227d33
--- /dev/null
+++ b/libparc/parc/security/test/README.keystore
@@ -0,0 +1,35 @@
+
+# This set of commands creates an RSA public/private key pair,
+# self-signs it, then puts it all in a pkcs12 container with
+# the password "blueberry"
+#
+# We use these files in the test_ccnx_FileKeystore tests.
+
+openssl genrsa -out test_rsa_key.pem
+openssl rsa -pubout -in test_rsa_key.pem -out test_rsa_pub.pem
+openssl req -new -key test_rsa_key.pem -out test_rsa.csr
+openssl x509 -req -days 365 -in test_rsa.csr -signkey test_rsa_key.pem -out test_rsa.crt
+openssl pkcs12 -export -in test_rsa.crt -inkey test_rsa_key.pem -out test_rsa.p12 -name ccnxuser -CAfile test_rsa.crt -caname root -chain -passout pass:blueberry
+
+# saves the public key in DER form so we can calculate the sha256 of it
+openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+
+# save the private key in DER form so we can compare in code
+openssl rsa -in test_rsa_key.pem -outform DER -out test_rsa_key.der
+
+# computes the sha256 and saves it in binary form
+openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_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_rsa_crt.der -in test_rsa.crt
+openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+
+# To verify signing, we create a random buffer, then sign with a SHA256 digest
+
+dd if=/dev/urandom of=test_random_bytes bs=512 count=1
+openssl sha -sha256 -sign test_rsa_key.pem -out test_random_bytes.sig < test_random_bytes
+
+# 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
+
diff --git a/libparc/parc/security/test/README.symmetric b/libparc/parc/security/test/README.symmetric
new file mode 100644
index 00000000..ce09fe85
--- /dev/null
+++ b/libparc/parc/security/test/README.symmetric
@@ -0,0 +1,9 @@
+
+# random bytes as a 32-byte (256-bit) key
+
+dd if=/dev/random of=test_symmetric_key.bin bs=32 count=1
+
+# compute its sha-256 hash
+openssl sha256 -binary -out test_symmetric_key.sha256 < test_symmetric_key.bin
+
+
diff --git a/libparc/parc/security/test/test.crt.der b/libparc/parc/security/test/test.crt.der
new file mode 100644
index 00000000..8b2e12ca
--- /dev/null
+++ b/libparc/parc/security/test/test.crt.der
Binary files differ
diff --git a/libparc/parc/security/test/test.crt.der.sha256.bin b/libparc/parc/security/test/test.crt.der.sha256.bin
new file mode 100644
index 00000000..1d19a81c
--- /dev/null
+++ b/libparc/parc/security/test/test.crt.der.sha256.bin
@@ -0,0 +1 @@
+> Թ/ͩp 󏝨:), \ No newline at end of file
diff --git a/libparc/parc/security/test/test.der b/libparc/parc/security/test/test.der
new file mode 100644
index 00000000..db368b72
--- /dev/null
+++ b/libparc/parc/security/test/test.der
Binary files differ
diff --git a/libparc/parc/security/test/test.pem b/libparc/parc/security/test/test.pem
new file mode 100644
index 00000000..d9593bac
--- /dev/null
+++ b/libparc/parc/security/test/test.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQDCCG74+EassjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE1MDkwMzIxMDYxNloXDTE2MDkwMjIxMDYxNlowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvp5L
+B7ccwPfBooRduHvQHgJo5gvDIXX5dFz/8oRDgyAnvtvCoQXkfSj5oO+6WpaKIG2k
+RxO+2VEKknY1GyWT3qqHVfSgp33n/AKBsedVb5ZUVAhy4FAOq3BCF8wpfKrkfadQ
+ltmBNYP0DH4YdIvS7+HL5yaKXF1ZnUwWo2WFcucCAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQAt8Op2KgQ6cREBVS6xOWvSeNr7/EXEW8T19BsUkYZeZ596oEJVjT2CrT0P
+s2ADuzfN0w19aGM25UczlBcg/CtkrTZEoXubbIoPGwwZv+taM+v455DhJY1chd0j
+Jq6XeRDokTFvn9qcZmoCX2CVKEMigatTpz4zenATUQmmRwdIVg==
+-----END CERTIFICATE-----
diff --git a/libparc/parc/security/test/test.pkcs12 b/libparc/parc/security/test/test.pkcs12
new file mode 100644
index 00000000..4b032263
--- /dev/null
+++ b/libparc/parc/security/test/test.pkcs12
Binary files differ
diff --git a/libparc/parc/security/test/test_crt.der b/libparc/parc/security/test/test_crt.der
new file mode 100644
index 00000000..42a829ee
--- /dev/null
+++ b/libparc/parc/security/test/test_crt.der
Binary files differ
diff --git a/libparc/parc/security/test/test_crt_der.bin b/libparc/parc/security/test/test_crt_der.bin
new file mode 100644
index 00000000..42a829ee
--- /dev/null
+++ b/libparc/parc/security/test/test_crt_der.bin
Binary files differ
diff --git a/libparc/parc/security/test/test_crt_sha256.bin b/libparc/parc/security/test/test_crt_sha256.bin
new file mode 100644
index 00000000..77d41680
--- /dev/null
+++ b/libparc/parc/security/test/test_crt_sha256.bin
@@ -0,0 +1 @@
+5#LG4%uENlna,*V<w \ No newline at end of file
diff --git a/libparc/parc/security/test/test_der.bin b/libparc/parc/security/test/test_der.bin
new file mode 100644
index 00000000..db368b72
--- /dev/null
+++ b/libparc/parc/security/test/test_der.bin
Binary files differ
diff --git a/libparc/parc/security/test/test_digest_bytes_128.bin b/libparc/parc/security/test/test_digest_bytes_128.bin
new file mode 100644
index 00000000..b6939de1
--- /dev/null
+++ b/libparc/parc/security/test/test_digest_bytes_128.bin
@@ -0,0 +1 @@
+}/W9^Y(Αv|}wλ^K3qh%anĝEvu.cCj'Dv\hE6$][lB}DS \ No newline at end of file
diff --git a/libparc/parc/security/test/test_digest_bytes_128.sha256 b/libparc/parc/security/test/test_digest_bytes_128.sha256
new file mode 100644
index 00000000..6e93005d
--- /dev/null
+++ b/libparc/parc/security/test/test_digest_bytes_128.sha256
@@ -0,0 +1 @@
+NL.T`+۪] \ No newline at end of file
diff --git a/libparc/parc/security/test/test_digest_bytes_128.sha512 b/libparc/parc/security/test/test_digest_bytes_128.sha512
new file mode 100644
index 00000000..88db6953
--- /dev/null
+++ b/libparc/parc/security/test/test_digest_bytes_128.sha512
@@ -0,0 +1 @@
+W Juie>]ϲ OC>4G KNEEop9~kML \ No newline at end of file
diff --git a/libparc/parc/security/test/test_key.pem b/libparc/parc/security/test/test_key.pem
new file mode 100644
index 00000000..bdc42c1e
--- /dev/null
+++ b/libparc/parc/security/test/test_key.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+nksHtxzA98GihF24e9AeAmjm
+C8Mhdfl0XP/yhEODICe+28KhBeR9KPmg77paloogbaRHE77ZUQqSdjUbJZPeqodV
+9KCnfef8AoGx51VvllRUCHLgUA6rcEIXzCl8quR9p1CW2YE1g/QMfhh0i9Lv4cvn
+JopcXVmdTBajZYVy5wIDAQAB
+-----END PUBLIC KEY-----
diff --git a/libparc/parc/security/test/test_parc_Certificate.c b/libparc/parc/security/test/test_parc_Certificate.c
new file mode 100644
index 00000000..24f46f86
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Certificate.c
@@ -0,0 +1,258 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_Certificate.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_Key.h>
+#include <parc/algol/parc_Buffer.h>
+
+PARCCryptoHash *
+_mockGetPublicKeyDigest(void *instance)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ parcBuffer_Release(&buffer);
+ return hash;
+}
+
+PARCCryptoHash *
+_mockGetCertificateDigest(void *instance)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(20);
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ parcBuffer_Release(&buffer);
+ return hash;
+}
+
+PARCBuffer *
+_mockGetDEREncodedCertificate(void *instance)
+{
+ return parcBuffer_Allocate(30);
+}
+
+PARCBuffer *
+_mockGetDEREncodedPublicKey(void *instance)
+{
+ return parcBuffer_Allocate(40);
+}
+
+PARCCertificateType
+_mockGetCertificateType(const void *instance)
+{
+ return PARCCertificateType_X509;
+}
+
+PARCContainerEncoding
+_mockGetContainerEncoding(const void *instance)
+{
+ return PARCContainerEncoding_PEM;
+}
+
+PARCKey *
+_mockGetPublicKey(void *instance)
+{
+ PARCBuffer *realKey = parcBuffer_Allocate(256);
+ PARCBuffer *keyId = parcBuffer_Allocate(256);
+ PARCKeyId *id = parcKeyId_Create(keyId);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(id, PARCSigningAlgorithm_RSA, realKey);
+
+ parcBuffer_Release(&keyId);
+ parcKeyId_Release(&id);
+ parcBuffer_Release(&realKey);
+
+ return key;
+}
+
+PARCCertificateInterface *_mockCertificate = &(PARCCertificateInterface) {
+ .GetPublicKeyDigest = _mockGetPublicKeyDigest,
+ .GetCertificateDigest = _mockGetCertificateDigest,
+ .GetDEREncodedCertificate = _mockGetDEREncodedCertificate,
+ .GetDEREncodedPublicKey = _mockGetDEREncodedPublicKey,
+ .GetCertificateType = _mockGetCertificateType,
+ .GetContainerEncoding = _mockGetContainerEncoding
+};
+
+LONGBOW_TEST_RUNNER(parc_Certificate)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_Certificate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Certificate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetContainerEncoding);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetCertificateType);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetPublicKeyDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetCertificateDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetDEREncodedCertificate);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetDEREncodedPublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetPublicKey);
+}
+
+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, parc_Certificate_AcquireRelease)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+ assertNotNull(certificate, "Expected non-NULL certificate");
+
+ PARCReferenceCount firstCount = parcObject_GetReferenceCount(certificate);
+ PARCCertificate *copy = parcCertificate_Acquire(certificate);
+ PARCReferenceCount secondCount = parcObject_GetReferenceCount(copy);
+
+ assertTrue(firstCount == (secondCount - 1), "Expected incremented reference count after Acquire");
+
+ parcCertificate_Release(&copy);
+ PARCReferenceCount thirdCount = parcObject_GetReferenceCount(certificate);
+
+ assertTrue(firstCount == thirdCount, "Expected equal reference counts after Release");
+
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_Create)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ assertNotNull(certificate, "Expected non-NULL certificate");
+
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetContainerEncoding)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+ PARCContainerEncoding encoding = parcCertificate_GetContainerEncoding(certificate);
+ assertTrue(encoding == PARCContainerEncoding_PEM, "Expected %d, got %d", PARCContainerEncoding_PEM, encoding);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetCertificateType)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+ PARCCertificateType type = parcCertificate_GetCertificateType(certificate);
+ assertTrue(type == PARCCertificateType_X509, "Expected %d, got %d", PARCCertificateType_X509, type);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetPublicKeyDigest)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCCryptoHash *hash = parcCertificate_GetPublicKeyDigest(certificate);
+ size_t length = parcBuffer_Remaining(parcCryptoHash_GetDigest(hash));
+ size_t expected = 10;
+ assertTrue(length == expected, "Expected length of %zu, got %zu", expected, length);
+
+ parcCryptoHash_Release(&hash);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetCertificateDigest)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCCryptoHash *hash = parcCertificate_GetCertificateDigest(certificate);
+ size_t length = parcBuffer_Remaining(parcCryptoHash_GetDigest(hash));
+ size_t expected = 20;
+ assertTrue(length == expected, "Expected length of %zu, got %zu", expected, length);
+
+ parcCryptoHash_Release(&hash);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetDEREncodedCertificate)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCBuffer *buffer = parcCertificate_GetDEREncodedCertificate(certificate);
+ size_t length = parcBuffer_Remaining(buffer);
+ size_t expected = 30;
+ assertTrue(length == expected, "Expected length of %zu, got %zu", expected, length);
+
+ parcBuffer_Release(&buffer);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetDEREncodedPublicKey)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCBuffer *buffer = parcCertificate_GetDEREncodedPublicKey(certificate);
+ size_t length = parcBuffer_Remaining(buffer);
+ size_t expected = 40;
+ assertTrue(length == expected, "Expected length of %zu, got %zu", expected, length);
+
+ parcBuffer_Release(&buffer);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetPublicKey)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCKey *actual = parcCertificate_GetPublicKey(certificate);
+ assertTrue(parcBuffer_Remaining(parcKey_GetKey(actual)) == 40,
+ "Expected PARCKey size to be 40, got %zu",
+ parcBuffer_Remaining(parcKey_GetKey(actual)));
+ assertTrue(parcBuffer_Remaining(parcKeyId_GetKeyId(parcKey_GetKeyId(actual))) == 10,
+ "Expected PARCKey keyId size to be 10, got %zu",
+ parcBuffer_Remaining(parcKeyId_GetKeyId(parcKey_GetKeyId(actual))));
+
+ parcKey_Release(&actual);
+ parcCertificate_Release(&certificate);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Certificate);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CertificateFactory.c b/libparc/parc/security/test/test_parc_CertificateFactory.c
new file mode 100755
index 00000000..29675f94
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CertificateFactory.c
@@ -0,0 +1,160 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_CertificateFactory.c"
+#include <parc/security/parc_X509Certificate.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_CertificateFactory)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_CertificateFactory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CertificateFactory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateFactory_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateFactory_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateFactory_CreateFromFile);
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateFactory_CreateFromBuffer);
+}
+
+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, parc_CertificateFactory_AcquireRelease)
+{
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ assertNotNull(factory, "Expected non-NULL factory");
+
+ PARCReferenceCount firstCount = parcObject_GetReferenceCount(factory);
+ PARCCertificateFactory *copy = parcCertificateFactory_Acquire(factory);
+ PARCReferenceCount secondCount = parcObject_GetReferenceCount(copy);
+
+ assertTrue(firstCount == (secondCount - 1), "Expected incremented reference count after Acquire");
+
+ parcCertificateFactory_Release(&copy);
+ PARCReferenceCount thirdCount = parcObject_GetReferenceCount(factory);
+
+ assertTrue(firstCount == thirdCount, "Expected equal reference counts after Release");
+
+ parcCertificateFactory_Release(&factory);
+}
+
+LONGBOW_TEST_CASE(Global, parc_CertificateFactory_Create)
+{
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ assertNotNull(factory, "Expected non-NULL factory");
+ assertTrue(factory->encoding == PARCContainerEncoding_PEM, "Expected PARCContainerEncoding_PEM (%d) encoding, got %d",
+ PARCContainerEncoding_PEM, factory->encoding);
+ assertTrue(factory->type == PARCCertificateType_X509, "Expected PARCCertificateType_X509 (%d) type, got %d",
+ PARCCertificateType_X509, factory->type);
+ parcCertificateFactory_Release(&factory);
+}
+
+LONGBOW_TEST_CASE(Global, parc_CertificateFactory_CreateFromFile)
+{
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ assertNotNull(factory, "Expected non-NULL factory");
+
+ char *filename = "test.pem";
+ PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromFile(factory, filename, NULL);
+
+ assertNotNull(certificate, "Expected non-NULL certificate");
+ assertTrue(parcCertificate_GetContainerEncoding(certificate) == PARCContainerEncoding_PEM,
+ "Expected PARCContainerEncoding_PEM encoding, got %d", parcCertificate_GetContainerEncoding(certificate));
+ assertTrue(parcCertificate_GetCertificateType(certificate) == PARCCertificateType_X509,
+ "Expected PARCCertificateType_X509 type, got %d", parcCertificate_GetCertificateType(certificate));
+
+ parcCertificate_Release(&certificate);
+ parcCertificateFactory_Release(&factory);
+
+ factory = parcCertificateFactory_Create(PARCCertificateType_Invalid, PARCContainerEncoding_PEM);
+
+ PARCCertificate *nullCertificate = parcCertificateFactory_CreateCertificateFromFile(factory, filename, NULL);
+ assertNull(nullCertificate, "Expected NULL certificate to be returned from factory with an unsupported configuration");
+
+ parcCertificateFactory_Release(&factory);
+}
+
+LONGBOW_TEST_CASE(Global, parc_CertificateFactory_CreateFromBuffer)
+{
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_DER);
+ assertNotNull(factory, "Expected non-NULL factory");
+
+ char *filename = "test.pem";
+ PARCX509Certificate *realCertificate = parcX509Certificate_CreateFromPEMFile(filename);
+ PARCBuffer *certificateBuffer = parcX509Certificate_GetDEREncodedCertificate(realCertificate);
+
+ PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromBuffer(factory, certificateBuffer);
+
+ assertNotNull(certificate, "Expected non-NULL certificate");
+ assertTrue(parcCertificate_GetContainerEncoding(certificate) == PARCContainerEncoding_DER,
+ "Expected PARCContainerEncoding_DER encoding, got %d", parcCertificate_GetContainerEncoding(certificate));
+ assertTrue(parcCertificate_GetCertificateType(certificate) == PARCCertificateType_X509,
+ "Expected PARCCertificateType_X509 type, got %d", parcCertificate_GetCertificateType(certificate));
+
+ parcCertificate_Release(&certificate);
+ parcCertificateFactory_Release(&factory);
+ parcX509Certificate_Release(&realCertificate);
+
+ factory = parcCertificateFactory_Create(PARCCertificateType_Invalid, PARCContainerEncoding_PEM);
+
+ PARCBuffer *invalid = parcBuffer_Allocate(10);
+ PARCCertificate *nullCertificate = parcCertificateFactory_CreateCertificateFromBuffer(factory, invalid);
+ assertNull(nullCertificate, "Expected NULL certificate to be returned from factory with an unsupported configuration");
+
+ parcBuffer_Release(&invalid);
+ parcCertificateFactory_Release(&factory);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CertificateFactory);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CertificateType.c b/libparc/parc/security/test/test_parc_CertificateType.c
new file mode 100755
index 00000000..67ce5e87
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CertificateType.c
@@ -0,0 +1,90 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_CertificateType.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_CertificateType)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_CertificateType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CertificateType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateType_FromString);
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateType_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ 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, parc_CertificateType_FromString)
+{
+ char *inputString = "PARCCertificateType_X509";
+ PARCCertificateType encoding = parcCertificateType_FromString(inputString);
+ assertTrue(encoding == PARCCertificateType_X509, "Expected PARCCertificateType_X509 (%d), for %d", PARCCertificateType_X509, encoding);
+
+ inputString = "the cake is a lie";
+ encoding = parcCertificateType_FromString(inputString);
+ assertTrue(encoding == PARCCertificateType_Invalid, "Expected PARCCertificateType_Invalid (%d), for %d", PARCCertificateType_Invalid, encoding);
+}
+
+LONGBOW_TEST_CASE(Global, parc_CertificateType_ToString)
+{
+ char *expected = "PARCCertificateType_X509";
+ PARCCertificateType encoding = PARCCertificateType_X509;
+ const char *actual = parcCertificateType_ToString(encoding);
+ assertTrue(strcmp(actual, expected) == 0, "Expected %s, got %s", expected, actual);
+
+ actual = parcCertificateType_ToString(PARCCertificateType_Invalid);
+ assertNull(actual, "Expected NULL string to be returned with invalid certificate type");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CertificateType);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_ContainerEncoding.c b/libparc/parc/security/test/test_parc_ContainerEncoding.c
new file mode 100755
index 00000000..01cafa50
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_ContainerEncoding.c
@@ -0,0 +1,90 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_ContainerEncoding.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_ContainerEncoding)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_ContainerEncoding)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_ContainerEncoding)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_ContainerEncoding_FromString);
+ LONGBOW_RUN_TEST_CASE(Global, parc_ContainerEncoding_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ 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, parc_ContainerEncoding_FromString)
+{
+ char *inputString = "PARCContainerEncoding_PEM";
+ PARCContainerEncoding encoding = parcContainerEncoding_FromString(inputString);
+ assertTrue(encoding == PARCContainerEncoding_PEM, "Expected PARCContainerEncoding_PEM (%d), for %d", PARCContainerEncoding_PEM, encoding);
+
+ inputString = "the cake is a lie";
+ encoding = parcContainerEncoding_FromString(inputString);
+ assertTrue(encoding == PARCContainerEncoding_Invalid, "Expected PARCContainerEncoding_Invalid (%d), for %d", PARCContainerEncoding_Invalid, encoding);
+}
+
+LONGBOW_TEST_CASE(Global, parc_ContainerEncoding_ToString)
+{
+ char *expected = "PARCContainerEncoding_PEM";
+ PARCContainerEncoding encoding = PARCContainerEncoding_PEM;
+ const char *actual = parcContainerEncoding_ToString(encoding);
+ assertTrue(strcmp(actual, expected) == 0, "Expected %s, got %s", expected, actual);
+
+ actual = parcContainerEncoding_ToString(PARCContainerEncoding_Invalid);
+ assertNull(actual, "Expected NULL string to be returned with invalid encoding type");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ContainerEncoding);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoCache.c b/libparc/parc/security/test/test_parc_CryptoCache.c
new file mode 100755
index 00000000..8613808d
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoCache.c
@@ -0,0 +1,228 @@
+/*
+ * 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 <config.h>
+#include <LongBow/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_CryptoCache.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/security/parc_CryptoHashType.h>
+
+LONGBOW_TEST_RUNNER(parc_CryptoCache)
+{
+ // 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(Allocate);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_CryptoCache)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoCache)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Allocate)
+{
+ LONGBOW_RUN_TEST_CASE(Allocate, parcCryptoCache_Create_Destroy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Allocate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Allocate)
+{
+ 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(Allocate, parcCryptoCache_Create_Destroy)
+{
+ PARCCryptoCache *cache = parcCryptoCache_Create();
+ parcCryptoCache_Destroy(&cache);
+}
+
+static PARCCryptoCache *cache_under_test;
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoCache_AddGetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoCache_GetMissingKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoCache_GetWrongKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoCache_RemoveKey);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ cache_under_test = parcCryptoCache_Create();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ parcCryptoCache_Destroy(&cache_under_test);
+
+ 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, parcCryptoCache_AddGetKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcCryptoCache_AddKey(cache_under_test, key);
+
+ const PARCKey *test = parcCryptoCache_GetKey(cache_under_test, keyid);
+
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+
+ assertTrue(parcKey_Equals(key, test), "did not return expected key from cache");
+ parcKey_Release(&key);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoCache_GetMissingKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ const PARCKey *test = parcCryptoCache_GetKey(cache_under_test, keyid);
+
+ assertNull(test, "Get missing key returned something!");
+
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoCache_GetWrongKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCBuffer *bb_id2 = parcBuffer_Wrap("not here!", 9, 0, 9);
+
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCKeyId *keyid2 = parcKeyId_Create(bb_id2);
+ parcBuffer_Release(&bb_id2);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcCryptoCache_AddKey(cache_under_test, key);
+
+ const PARCKey *test = parcCryptoCache_GetKey(cache_under_test, keyid2);
+ assertNull(test, "Get missing key returned something!");
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+ parcKeyId_Release(&keyid2);
+}
+
+/**
+ * Add in 2 keys, remove 1, fetch the other
+ */
+LONGBOW_TEST_CASE(Global, parcCryptoCache_RemoveKey)
+{
+ PARCBufferComposer *composer1 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer1, "quack quack");
+ PARCBuffer *bb_key1 = parcBufferComposer_ProduceBuffer(composer1);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer2, "Come with me and you'll be");
+ PARCBuffer *bb_key2 = parcBufferComposer_ProduceBuffer(composer2);
+
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCBuffer *bb_id2 = parcBuffer_Wrap("not here!", 9, 0, 9);
+
+ PARCKeyId *keyid1 = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+ PARCKeyId *keyid2 = parcKeyId_Create(bb_id2);
+ parcBuffer_Release(&bb_id2);
+
+ PARCKey *key1 = parcKey_CreateFromDerEncodedPublicKey(keyid1, PARCSigningAlgorithm_RSA, bb_key1);
+ PARCKey *key2 = parcKey_CreateFromDerEncodedPublicKey(keyid2, PARCSigningAlgorithm_RSA, bb_key2);
+ const PARCKey *test;
+
+ parcCryptoCache_AddKey(cache_under_test, key1);
+ parcCryptoCache_AddKey(cache_under_test, key2);
+
+ test = parcCryptoCache_GetKey(cache_under_test, keyid1);
+ assertTrue(parcKey_Equals(key1, test), "Got wrong key");
+
+ test = parcCryptoCache_GetKey(cache_under_test, keyid2);
+ assertTrue(parcKey_Equals(key2, test), "Got wrong key");
+
+ // remove will free the key, so make a copy of it before removing
+ PARCKeyId *keyid1_copy = parcKeyId_Copy(keyid1);
+ parcCryptoCache_RemoveKey(cache_under_test, keyid1);
+
+ test = parcCryptoCache_GetKey(cache_under_test, keyid1_copy);
+ assertNull(test, "Get of deleted key returned non-null");
+
+ test = parcCryptoCache_GetKey(cache_under_test, keyid2);
+ assertTrue(parcKey_Equals(key2, test), "Got wrong key");
+
+
+ parcKey_Release(&key1);
+ parcKey_Release(&key2);
+
+ parcBuffer_Release(&bb_key1);
+ parcBufferComposer_Release(&composer1);
+ parcKeyId_Release(&keyid1);
+ parcBuffer_Release(&bb_key2);
+ parcBufferComposer_Release(&composer2);
+ parcKeyId_Release(&keyid2);
+
+ parcKeyId_Release(&keyid1_copy);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoCache);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoHash.c b/libparc/parc/security/test/test_parc_CryptoHash.c
new file mode 100755
index 00000000..df5409b2
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoHash.c
@@ -0,0 +1,184 @@
+/*
+ * 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_CryptoHash.c"
+#include "../parc_CryptoHasher.h"
+
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+#include <fcntl.h>
+#include <errno.h>
+
+const int bufferLength = 1024;
+
+LONGBOW_TEST_RUNNER(parc_CryptoHash)
+{
+ // 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);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_CryptoHash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoHash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_CreateFromArray);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_GetDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_GetDigestType);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_CreateFromArray)
+{
+ int fd = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length = read(fd, scratch, bufferLength);
+
+ PARCCryptoHash *hash = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+ assertNotNull(hash, "Expected to be non null");
+
+ parcCryptoHash_Release(&hash);
+ close(fd);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_Release)
+{
+ int fd = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length = read(fd, scratch, bufferLength);
+
+ PARCCryptoHash *hash = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+ assertNotNull(hash, "Expected to be non null");
+
+ parcCryptoHash_Release(&hash);
+ assertNull(hash, "Expected to be null");
+ close(fd);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_Equals)
+{
+ int fd1 = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd1 < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch1[bufferLength];
+ ssize_t read_length = read(fd1, scratch1, bufferLength);
+
+ PARCCryptoHash *hash1 = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch1, read_length);
+ PARCCryptoHash *hash2 = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch1, read_length);
+ PARCCryptoHash *hash3 = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch1, read_length);
+
+ int fd2 = open("test_digest_bytes_128.sha512", O_RDONLY);
+ assertFalse(fd2 < 0, "Could not open %s: %s", "test_digest_bytes_128.sha512", strerror(errno));
+
+ uint8_t scratch2[bufferLength];
+ read_length = read(fd2, scratch2, bufferLength);
+
+ PARCCryptoHash *unequalhash = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch2, read_length);
+
+ parcObjectTesting_AssertEqualsFunction(parcObject_Equals, hash1, hash2, hash3, unequalhash);
+
+ parcCryptoHash_Release(&hash1);
+ parcCryptoHash_Release(&hash2);
+ parcCryptoHash_Release(&hash3);
+ parcCryptoHash_Release(&unequalhash);
+
+ close(fd1);
+ close(fd2);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_GetDigest)
+{
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length = read(fd_truth, scratch, bufferLength);
+
+ PARCCryptoHash *hashTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+
+ read_length = read(fd_buffer, scratch, bufferLength);
+
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, scratch, read_length);
+
+ PARCCryptoHash *hashTest = parcCryptoHasher_Finalize(hasher);
+
+ assertTrue(parcBuffer_Equals(parcCryptoHash_GetDigest(hashTruth), parcCryptoHash_GetDigest(hashTest)), "Expected to be true");
+
+ parcCryptoHasher_Release(&hasher);
+ parcCryptoHash_Release(&hashTruth);
+ parcCryptoHash_Release(&hashTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_GetDigestType)
+{
+ int fd = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length = read(fd, scratch, bufferLength);
+
+ PARCCryptoHash *hash = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+ assertNotNull(hash, "Expected to be non null");
+
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoHash_GetDigestType(hash), "Expected to be true");
+
+ parcCryptoHash_Release(&hash);
+ close(fd);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoHash);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoHashType.c b/libparc/parc/security/test/test_parc_CryptoHashType.c
new file mode 100644
index 00000000..1e1cc68b
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoHashType.c
@@ -0,0 +1,92 @@
+/*
+ * 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_CryptoHashType.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_CryptoHashType)
+{
+ // 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);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_CryptoHashType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoHashType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHashType_FromString);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHashType_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHashType_FromString)
+{
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoHashType_FromString("PARCCryptoHashType_SHA256"), "Expected true");
+
+ assertTrue(PARCCryptoHashType_SHA512 == parcCryptoHashType_FromString("PARCCryptoHashType_SHA512"), "Expected true");
+
+ assertTrue(PARCCryptoHashType_CRC32C == parcCryptoHashType_FromString("PARCCryptoHashType_CRC32C"), "Expected true");
+
+ assertTrue(PARCCryptoHashType_NULL == parcCryptoHashType_FromString("NULL"), "Expected true");
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHashType_ToString)
+{
+ const char *string1 = parcCryptoHashType_ToString(PARCCryptoHashType_SHA256);
+ assertNotNull(string1, "Expected non-null result.");
+
+ const char *string2 = parcCryptoHashType_ToString(PARCCryptoHashType_SHA512);
+ assertNotNull(string2, "Expected non-null result.");
+
+ const char *string3 = parcCryptoHashType_ToString(PARCCryptoHashType_CRC32C);
+ assertNotNull(string3, "Expected non-null result.");
+
+ const char *string4 = parcCryptoHashType_ToString(PARCCryptoHashType_NULL);
+ assertNull(string4, "Expected to be null");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoHashType);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoHasher.c b/libparc/parc/security/test/test_parc_CryptoHasher.c
new file mode 100755
index 00000000..33a3f6bc
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoHasher.c
@@ -0,0 +1,407 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/security/parc_Security.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_CryptoHasher.c"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+
+const int bufferLength = 1024;
+
+/*
+ * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net
+ * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e
+ *
+ * You can also calcaulate them online at http://www.zorc.breitbandkatze.de/crc.html using
+ * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check),
+ * and reverse CRC result before final XOR (check).
+ *
+ */
+struct test_vector {
+ uint32_t crc32c;
+ int length;
+ uint8_t *buffer;
+} vectors[] = {
+ { .crc32c = 0xe3069283, .length = 9, .buffer = (uint8_t []) { '1', '2', '3', '4', '5', '6', '7', '8', '9' } },
+ { .crc32c = 0xddb65633, .length = 1, .buffer = (uint8_t []) { 0x3D } },
+ { .crc32c = 0xc203c1fd, .length = 2, .buffer = (uint8_t []) { 0x3D, 0x41 } },
+ { .crc32c = 0x80a9d169, .length = 3, .buffer = (uint8_t []) { 'b', 'e', 'e' } },
+ { .crc32c = 0xa099f534, .length = 4, .buffer = (uint8_t []) { 'h', 'e', 'l', 'l' } },
+ { .crc32c = 0x9a71bb4c, .length = 5, .buffer = (uint8_t []) { 'h', 'e', 'l', 'l', 'o' } },
+ { .crc32c = 0x2976E503, .length = 6, .buffer = (uint8_t []) { 'g', 'r', 'u', 'm', 'p', 'y' } },
+ { .crc32c = 0xe627f441, .length = 7, .buffer = (uint8_t []) { 'a', 'b', 'c', 'd', 'e', 'f', 'g' } },
+ { .crc32c = 0x2d265c1d, .length = 13, .buffer = (uint8_t []) { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f'} },
+ { .crc32c = 0, .length = 0, .buffer = NULL }
+};
+
+
+LONGBOW_TEST_RUNNER(parc_CryptoHasher)
+{
+ // 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);
+// LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_CryptoHasher)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoHasher)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Create);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Bytes_256);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Buffer_256);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Bytes_512);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Buffer_512);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_CRC32);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_CustomHasher);
+}
+
+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, parcCryptoHasher_Create)
+{
+ PARCCryptoHasher *hasher;
+
+ hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Release(&hasher);
+
+ hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA512);
+ PARCCryptoHasher *handle = parcCryptoHasher_Acquire(hasher);
+
+ assertTrue(parcObject_GetReferenceCount(handle) == 2, "Expected 2 references");
+
+ parcCryptoHasher_Release(&hasher);
+ parcCryptoHasher_Release(&handle);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_Bytes_256)
+{
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length;
+
+ read_length = read(fd_truth, scratch, bufferLength);
+
+ PARCCryptoHash *digestTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+
+ read_length = read(fd_buffer, scratch, bufferLength);
+
+ PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, scratch, read_length);
+
+ PARCCryptoHash *digestTest = parcCryptoHasher_Finalize(digester);
+
+ assertTrue(parcCryptoHash_Equals(digestTruth, digestTest),
+ "sha256 digest of 128-byte buffer using Update_Buffer does not match");
+
+ parcCryptoHasher_Release(&digester);
+ parcCryptoHash_Release(&digestTruth);
+ parcCryptoHash_Release(&digestTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_Buffer_256)
+{
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+
+ ssize_t read_length = read(fd_buffer, scratch, bufferLength);
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch, read_length);
+ PARCBuffer *bb_to_digest = parcBufferComposer_ProduceBuffer(composer);
+
+ read_length = read(fd_truth, scratch, bufferLength);
+ PARCCryptoHash *digestTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+
+ PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBuffer(digester, bb_to_digest);
+ PARCCryptoHash *digestTest = parcCryptoHasher_Finalize(digester);
+
+ assertTrue(parcCryptoHash_Equals(digestTruth, digestTest),
+ "sha256 digest of 128-byte buffer using Update_Buffer does not match");
+
+ parcCryptoHasher_Release(&digester);
+ parcBuffer_Release(&bb_to_digest);
+ parcBufferComposer_Release(&composer);
+ parcCryptoHash_Release(&digestTruth);
+ parcCryptoHash_Release(&digestTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+// ==== 512
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_Bytes_512)
+{
+ PARCCryptoHasher *digester;
+
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha512", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha512", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length;
+
+ read_length = read(fd_truth, scratch, bufferLength);
+ PARCCryptoHash *digestTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA512, scratch, read_length);
+
+ read_length = read(fd_buffer, scratch, bufferLength);
+
+
+ digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA512);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, scratch, read_length);
+ PARCCryptoHash *digestTest = parcCryptoHasher_Finalize(digester);
+
+ assertTrue(parcCryptoHash_Equals(digestTruth, digestTest), "sha512 digest of 128-byte buffer using Update_Buffer does not match");
+
+ parcCryptoHasher_Release(&digester);
+ parcCryptoHash_Release(&digestTruth);
+ parcCryptoHash_Release(&digestTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_Buffer_512)
+{
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha512", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha512", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length;
+
+ read_length = read(fd_buffer, scratch, bufferLength);
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch, read_length);
+ PARCBuffer *bb_to_digest = parcBufferComposer_ProduceBuffer(composer);
+
+ read_length = read(fd_truth, scratch, bufferLength);
+ PARCCryptoHash *digestTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA512, scratch, read_length);
+
+ PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA512);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBuffer(digester, bb_to_digest);
+ PARCCryptoHash *digestTest = parcCryptoHasher_Finalize(digester);
+
+ assertTrue(parcCryptoHash_Equals(digestTruth, digestTest),
+ "sha512 digest of 128-byte buffer using Update_Buffer does not match");
+
+ parcCryptoHasher_Release(&digester);
+ parcBuffer_Release(&bb_to_digest);
+ parcBufferComposer_Release(&composer);
+ parcCryptoHash_Release(&digestTruth);
+ parcCryptoHash_Release(&digestTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_CRC32)
+{
+ for (int i = 0; vectors[i].buffer != NULL; i++) {
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_CRC32C);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, vectors[i].buffer, vectors[i].length);
+ PARCCryptoHash *output = parcCryptoHasher_Finalize(hasher);
+ PARCBuffer *buffer = parcCryptoHash_GetDigest(output);
+ uint32_t testCrc = parcBuffer_GetUint32(buffer);
+ parcCryptoHash_Release(&output);
+
+ assertTrue(testCrc == vectors[i].crc32c,
+ "CRC32C values wrong, index %d got 0x%08x expected 0x%08x\n",
+ i, testCrc, vectors[i].crc32c);
+ parcCryptoHasher_Release(&hasher);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_CustomHasher)
+{
+ PARCCryptoHasher *hasher = parcCryptoHasher_CustomHasher(PARCCryptoHashType_SHA512, functor_sha256);
+ assertNotNull(hasher, "Expected to be non null");
+
+ parcCryptoHasher_Release(&hasher);
+}
+
+// ================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, computeCrc32C_Software);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, computeCrc32C_Software)
+{
+ for (int i = 0; vectors[i].buffer != NULL; i++) {
+ uint32_t testCrc = _crc32c_Init();
+ testCrc = _crc32c_UpdateSoftware(testCrc, vectors[i].length, vectors[i].buffer);
+ testCrc = _crc32c_Finalize(testCrc);
+
+ assertTrue(testCrc == vectors[i].crc32c,
+ "CRC32C values wrong, index %d got 0x%08x expected 0x%08x\n",
+ i, testCrc, vectors[i].crc32c);
+ }
+}
+
+// =======================================================
+
+LONGBOW_TEST_FIXTURE(Performance)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, computeCrc32C);
+ LONGBOW_RUN_TEST_CASE(Performance, computeCrc32C_Software);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static double
+runPerformance(int maxreps, uint32_t (*update)(uint32_t crc, size_t len, uint8_t p[len]))
+{
+ int reps = maxreps;
+ int length = 100;
+
+ uint8_t buffer[length];
+ for (int i = 0; i < length; i++) {
+ buffer[i] = i * 33;
+ }
+
+ // initial value doesnt really matter
+
+ struct timeval t0, t1;
+ gettimeofday(&t0, NULL);
+ while (--reps) {
+ uint32_t crc = _crc32c_Init();
+ update(crc, length, buffer);
+ crc = _crc32c_Finalize(crc);
+ }
+
+ gettimeofday(&t1, NULL);
+
+ timersub(&t1, &t0, &t1);
+
+ double seconds = t1.tv_sec + t1.tv_usec * 1E-6;
+ return seconds;
+}
+
+LONGBOW_TEST_CASE(Performance, computeCrc32C)
+{
+ int maxreps = 1000000;
+ double seconds = runPerformance(maxreps, _crc32c_Update);
+ double rate = maxreps / seconds;
+
+ printf("Best rate = %.3f for %d iterations\n", rate, maxreps);
+}
+
+LONGBOW_TEST_CASE(Performance, computeCrc32C_Software)
+{
+ int maxreps = 1000000;
+ double seconds = runPerformance(maxreps, _crc32c_UpdateSoftware);
+ double rate = maxreps / seconds;
+
+ printf("Best rate = %.3f for %d iterations\n", rate, maxreps);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoHasher);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoSuite.c b/libparc/parc/security/test/test_parc_CryptoSuite.c
new file mode 100755
index 00000000..f210fd79
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoSuite.c
@@ -0,0 +1,82 @@
+/*
+ * 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_CryptoSuite.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_CryptoSuite)
+{
+ // 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);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_CryptoSuite)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoSuite)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoSuite_GetCryptoHash);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoSuite_GetCryptoHash_IllegalValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoSuite_GetCryptoHash)
+{
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_RSA_SHA256), "Expected to be true");
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_DSA_SHA256), "Expected to be true");
+ assertTrue(PARCCryptoHashType_SHA512 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_RSA_SHA512), "Expected to be true");
+ 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");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcCryptoSuite_GetCryptoHash_IllegalValue, .event = &LongBowTrapIllegalValue)
+{
+ parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_UNKNOWN);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoSuite);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_DiffieHellman.c b/libparc/parc/security/test/test_parc_DiffieHellman.c
new file mode 100755
index 00000000..69bc109b
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_DiffieHellman.c
@@ -0,0 +1,93 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include "../parc_DiffieHellman.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_DiffieHellman)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_DiffieHellman)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_DiffieHellman)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellman_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellman_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellman_GenerateKeyShare);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ 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, parcDiffieHellman_Create)
+{
+ PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(dh, "Expected a non-NULL PARCDiffieHellman instance");
+ parcDiffieHellman_Release(&dh);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellman_AcquireRelease)
+{
+ PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ parcObjectTesting_AssertAcquireReleaseContract(parcDiffieHellman_Acquire, dh);
+ parcDiffieHellman_Release(&dh);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellman_GenerateKeyShare)
+{
+ PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellman_GenerateKeyShare(dh);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+ parcDiffieHellman_Release(&dh);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_DiffieHellman);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_DiffieHellmanKeyShare.c b/libparc/parc/security/test/test_parc_DiffieHellmanKeyShare.c
new file mode 100755
index 00000000..e8a2eeca
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_DiffieHellmanKeyShare.c
@@ -0,0 +1,229 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include "../parc_DiffieHellmanKeyShare.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_DiffieHellmanKeyShare)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_DiffieHellmanKeyShare)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_DiffieHellmanKeyShare)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_SerializePublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_SerializeDeserializePublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_DeserializePublicKey_ErrorWrongGroup);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_DeserializePublicKey_ErrorInvalidEncoding);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_Combine);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_Combine_Error_PublicKeyDeserializationFail);
+ LONGBOW_RUN_TEST_CASE(Global, _parcDiffieHellmanKeyShare_HashSharedSecret);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ 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, parcDiffieHellmanKeyShare_AcquireRelease)
+{
+ PARCDiffieHellmanKeyShare *dh = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ parcObjectTesting_AssertAcquireReleaseContract(parcDiffieHellmanKeyShare_Acquire, dh);
+ parcDiffieHellmanKeyShare_Release(&dh);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_Create)
+{
+ PARCDiffieHellmanKeyShare *dh = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(dh, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+ parcDiffieHellmanKeyShare_Release(&dh);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_SerializePublicKey)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ assertNotNull(publicKey, "Expected the public key to be serialized to a non-NULL PARCBuffer");
+
+ const size_t sec521r1KeySize = 266;
+ assertTrue(parcBuffer_Remaining(publicKey) == sec521r1KeySize, "Expected the public key size to be %zu, got %zu", sec521r1KeySize, parcBuffer_Remaining(publicKey));
+
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_SerializeDeserializePublicKey)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ assertNotNull(publicKey, "Expected the public key to be serialized to a non-NULL PARCBuffer");
+
+ const size_t sec521r1KeySize = 266;
+ assertTrue(parcBuffer_Remaining(publicKey) == sec521r1KeySize, "Expected the public key size to be %zu, got %zu", sec521r1KeySize, parcBuffer_Remaining(publicKey));
+
+ // Deserialize the public key to get the OpenSSL EVP_PKEY type
+ EVP_PKEY *rawPublicKey = _parcDiffieHellman_DeserializePublicKeyShare(keyShare, publicKey);
+ assertNotNull(rawPublicKey, "Expected the raw public key to be deserialized");
+
+ // Extract the public portions of the private key share and public key share
+ EC_KEY *publicEcKey = EVP_PKEY_get1_EC_KEY(rawPublicKey);
+ const EC_POINT *publicPoint = EC_KEY_get0_public_key(publicEcKey);
+
+ EC_KEY *privateEcKey = EVP_PKEY_get1_EC_KEY(keyShare->privateKey);
+ const EC_POINT *privatePoint = EC_KEY_get0_public_key(privateEcKey);
+
+ // Compare the public portions of the key shares
+ const EC_GROUP *group = EC_KEY_get0_group(publicEcKey);
+ BN_CTX *bigNumberContext = BN_CTX_new();
+ int equalResult = EC_POINT_cmp(group, publicPoint, privatePoint, bigNumberContext);
+ assertTrue(equalResult == 0, "Expected the two public points to be equal.");
+
+ BN_CTX_free(bigNumberContext);
+ EVP_PKEY_free(rawPublicKey);
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_DeserializePublicKey_ErrorWrongGroup)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ assertNotNull(publicKey, "Expected the public key to be serialized to a non-NULL PARCBuffer");
+
+ PARCDiffieHellmanKeyShare *alternateKeyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Prime256v1);
+
+ // Deserialize the public key with a different group and hit the failure
+ EVP_PKEY *rawPublicKey = _parcDiffieHellman_DeserializePublicKeyShare(alternateKeyShare, publicKey);
+ assertNull(rawPublicKey, "Expected the raw public key to not be deserialized");
+
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+ parcDiffieHellmanKeyShare_Release(&alternateKeyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_DeserializePublicKey_ErrorInvalidEncoding)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ // Deserialize the public key with a different group
+ PARCBuffer *publicKey = parcBuffer_Allocate(32);
+ EVP_PKEY *rawPublicKey = _parcDiffieHellman_DeserializePublicKeyShare(keyShare, publicKey);
+ assertNull(rawPublicKey, "Expected the raw public key to not be deserialized");
+
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_Combine)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ assertNotNull(publicKey, "Expected the public key to be serialized to a non-NULL PARCBuffer");
+
+ PARCBuffer *sharedSecret = parcDiffieHellmanKeyShare_Combine(keyShare, publicKey);
+ assertNotNull(sharedSecret, "Expected the shared secret to be non-NULL");
+
+ const size_t secretSize = 32; // = 256 / 8 bytes
+ assertTrue(parcBuffer_Remaining(sharedSecret) == secretSize, "invalid size");
+
+ parcBuffer_Release(&sharedSecret);
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_Combine_Error_PublicKeyDeserializationFail)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcBuffer_Allocate(32);
+ PARCBuffer *sharedSecret = parcDiffieHellmanKeyShare_Combine(keyShare, publicKey);
+ assertNull(sharedSecret, "Expected the shared secret to be non-NULL");
+
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, _parcDiffieHellmanKeyShare_HashSharedSecret)
+{
+ PARCBuffer *input = parcBuffer_Allocate(1024);
+ PARCBuffer *digestValue = _parcDiffieHellmanKeyShare_HashSharedSecret(input);
+ size_t digestLength = parcBuffer_Remaining(digestValue);
+ size_t expectedLength = 32; // 256 bits for PARCCryptoHashType_SHA256
+ assertTrue(digestLength == 32, "Expected a %zu byte digest, got %zu", expectedLength, digestLength);
+
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBuffer(hasher, input);
+ PARCCryptoHash *digest = parcCryptoHasher_Finalize(hasher);
+
+ PARCBuffer *computedDigest = parcBuffer_Acquire(parcCryptoHash_GetDigest(digest));
+
+ parcCryptoHash_Release(&digest);
+ parcCryptoHasher_Release(&hasher);
+
+ assertTrue(parcBuffer_Equals(digestValue, computedDigest), "Expected the secret input to be hashed correctly.");
+
+ parcBuffer_Release(&input);
+ parcBuffer_Release(&digestValue);
+ parcBuffer_Release(&computedDigest);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_DiffieHellmanKeyShare);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Identity.c b/libparc/parc/security/test/test_parc_Identity.c
new file mode 100644
index 00000000..4177cc98
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Identity.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * @abstract <#Abstract#>
+ * @discussion
+ * <#Discussion#>
+ *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Identity.c"
+#include "../parc_IdentityFile.h"
+#include "../parc_Security.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(test_parc_Identity)
+{
+ // 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);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_Identity)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_Identity)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_GetFileName);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_GetPassWord);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_CreateSigner);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_Display);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_Create)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+ parcIdentityFile_Release(&identityFile);
+
+ parcIdentity_Release(&identity);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_Acquire)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcIdentity_Acquire, identity);
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_GetFileName)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ assertEqualStrings(keystoreName, parcIdentity_GetFileName(identity));
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_GetPassWord)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ assertEqualStrings(keystorePassword, parcIdentity_GetPassWord(identity));
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_CreateSigner)
+{
+ parcSecurity_Init();
+
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ assertEqualStrings(keystorePassword, parcIdentity_GetPassWord(identity));
+
+ PARCSigner *signer = parcIdentity_CreateSigner(identity);
+
+ assertNotNull(signer, "Expected non-null");
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+ parcSigner_Release(&signer);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_Equals)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFileX = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentity *x = parcIdentity_Create(identityFileX, PARCIdentityFileAsPARCIdentity);
+ PARCIdentityFile *identityFileY = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentity *y = parcIdentity_Create(identityFileY, PARCIdentityFileAsPARCIdentity);
+ PARCIdentityFile *identityFileZ = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentity *z = parcIdentity_Create(identityFileZ, PARCIdentityFileAsPARCIdentity);
+
+ PARCIdentityFile *identityFile1 = parcIdentityFile_Create("foo", keystorePassword);
+ PARCIdentityFile *identityFile2 = parcIdentityFile_Create(keystoreName, "bar");
+ PARCIdentity *u1 = parcIdentity_Create(identityFile1, PARCIdentityFileAsPARCIdentity);
+ PARCIdentity *u2 = parcIdentity_Create(identityFile2, PARCIdentityFileAsPARCIdentity);
+
+ parcObjectTesting_AssertEqualsFunction(parcIdentity_Equals, x, y, z, u1, u2);
+
+ parcIdentityFile_Release(&identityFileX);
+ parcIdentityFile_Release(&identityFileY);
+ parcIdentityFile_Release(&identityFileZ);
+ parcIdentityFile_Release(&identityFile1);
+ parcIdentityFile_Release(&identityFile2);
+
+ parcIdentity_Release(&x);
+ parcIdentity_Release(&y);
+ parcIdentity_Release(&z);
+ parcIdentity_Release(&u1);
+ parcIdentity_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_Display)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ parcIdentity_Display(identity, 0);
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Identity);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_IdentityFile.c b/libparc/parc/security/test/test_parc_IdentityFile.c
new file mode 100644
index 00000000..cbc877f2
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_IdentityFile.c
@@ -0,0 +1,242 @@
+/*
+ * 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_IdentityFile.c"
+#include "../parc_Security.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_IdentityFile)
+{
+ // 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);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_IdentityFile)
+{
+ 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_IdentityFile)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_GetFileName);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_GetPassWord);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_CreateSigner);
+// LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Display);
+// LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Exists_True);
+// LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Exists_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ 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, parcIdentityFile_Acquire)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcIdentityFile_Acquire, identityFile);
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Create)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_GetFileName)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ assertEqualStrings(keystoreName, parcIdentityFile_GetFileName(identityFile));
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_GetPassWord)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ assertEqualStrings(keystorePassword, parcIdentityFile_GetPassWord(identityFile));
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Exists_True)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ bool actual = parcIdentityFile_Exists(identityFile);
+
+ assertTrue(actual, "Expected %s to exist.", parcIdentityFile_GetFileName(identityFile));
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Exists_False)
+{
+ const char *keystoreName = "/dev/notgoingtoexist";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ bool actual = parcIdentityFile_Exists(identityFile);
+
+ assertFalse(actual, "Expected %s to not exist.", parcIdentityFile_GetFileName(identityFile));
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_CreateSigner)
+{
+ parcSecurity_Init();
+
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ char cwd[1024];
+ if (getcwd(cwd, sizeof(cwd)) != NULL) {
+ fprintf(stdout, "Current working dir: %s\n", cwd);
+ } else {
+ perror("getcwd() error");
+ }
+ PARCSigner *signer = parcIdentityFile_CreateSigner(identityFile);
+
+ assertNotNull(signer, "Expected non-null");
+
+ parcIdentityFile_Release(&identityFile);
+ parcSigner_Release(&signer);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Release)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ parcIdentityFile_Release(&identityFile);
+ assertNull(identityFile, "Identity File was not nulled out after Release()");
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Equals)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *x = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentityFile *y = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentityFile *z = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentityFile *u1 = parcIdentityFile_Create("foo", keystorePassword);
+ PARCIdentityFile *u2 = parcIdentityFile_Create(keystoreName, "bar");
+
+ parcObjectTesting_AssertEqualsFunction(parcIdentityFile_Equals, x, y, z, u1, u2);
+
+ parcIdentityFile_Release(&x);
+ parcIdentityFile_Release(&y);
+ parcIdentityFile_Release(&z);
+ parcIdentityFile_Release(&u1);
+ parcIdentityFile_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Display)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ parcIdentityFile_Display(identityFile, 0);
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_IdentityFile);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_InMemoryVerifier.c b/libparc/parc/security/test/test_parc_InMemoryVerifier.c
new file mode 100755
index 00000000..1d8c9b0f
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_InMemoryVerifier.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 <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/security/parc_Security.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Signer.h>
+
+#include <fcntl.h>
+#include <LongBow/unit-test.h>
+
+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_RSA);
+
+ 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_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ parcKeyStore_Release(&keyStore);
+
+ data->signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+ 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_RSA_SHA256);
+ parcKey_Release(&key);
+ assertTrue(success, "Should have allowed PARCCryptoSuite_RSA_SHA256 for an RSA keystore");
+}
+
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_AllowedCryptoSuite_RSA)
+{
+ 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_RSA_SHA256);
+ parcKey_Release(&key);
+ assertTrue(success, "Should have allowed PARCCryptoSuite_RSA_SHA256 for an RSA 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", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128,
+ "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_RSA, PARCCryptoHashType_SHA256, bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_RSA_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", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128, "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_RSA,
+ PARCCryptoHashType_SHA256,
+ bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_RSA_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", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128, "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_RSA_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", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128, "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_RSA,
+ PARCCryptoHashType_SHA256,
+ bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_RSA_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_Key.c b/libparc/parc/security/test/test_parc_Key.c
new file mode 100755
index 00000000..d22362b0
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Key.c
@@ -0,0 +1,357 @@
+/*
+ * 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_Key.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Key)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_Key)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Key)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_CreateFromDerEncodedPublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_CreateFromSymmetricKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_GetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_GetKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_Copy)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+ parcKey_AssertValid(key);
+
+ PARCKey *copy = parcKey_Copy(key);
+ parcKey_AssertValid(copy);
+
+ assertTrue(parcKey_Equals(key, copy), "Expected the original key instance and its copy to be equal");
+
+ parcKey_Release(&copy);
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_CreateFromDerEncodedPublicKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcKey_AssertValid(key);
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_CreateFromSymmetricKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromSymmetricKey(keyid, PARCSigningAlgorithm_HMAC, bb_key);
+
+ parcKey_AssertValid(key);
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_Equals)
+{
+ PARCBuffer *bb_id_1 = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid_1 = parcKeyId_Create(bb_id_1);
+ parcBuffer_Release(&bb_id_1);
+
+ PARCBuffer *bb_id_2 = parcBuffer_Wrap("chugga chugga", 13, 0, 13);
+ PARCKeyId *keyid_2 = parcKeyId_Create(bb_id_2);
+ parcBuffer_Release(&bb_id_2);
+
+ PARCBufferComposer *composer1 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer1, "quack quack");
+ PARCBuffer *bb_key_1 = parcBufferComposer_ProduceBuffer(composer1);
+
+ PARCKey *x = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_1);
+ PARCKey *y = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_1);
+ PARCKey *z = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_1);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer2, "mew mew");
+ PARCBuffer *bb_key_2 = parcBufferComposer_ProduceBuffer(composer2);
+ PARCKey *u1 = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_2);
+ PARCKey *u2 = parcKey_CreateFromDerEncodedPublicKey(keyid_2, PARCSigningAlgorithm_RSA, bb_key_1);
+
+ parcObjectTesting_AssertEqualsFunction(parcKey_Equals, x, y, z, u1, u2);
+
+ parcBuffer_Release(&bb_key_1);
+ parcBufferComposer_Release(&composer1);
+ parcBuffer_Release(&bb_key_2);
+ parcBufferComposer_Release(&composer2);
+ parcKeyId_Release(&keyid_1);
+ parcKeyId_Release(&keyid_2);
+
+ parcKey_Release(&x);
+ parcKey_Release(&y);
+ parcKey_Release(&z);
+ parcKey_Release(&u1);
+ parcKey_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_GetKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcKey_AssertValid(key);
+
+ PARCBuffer *rawKey = parcKey_GetKey(key); // reference count is not incremented
+ assertTrue(parcBuffer_Equals(rawKey, bb_key), "Expected the raw key buffers to be equal");
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_GetKeyId)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcKey_AssertValid(key);
+
+ PARCKeyId *rawKeyId = parcKey_GetKeyId(key); // reference count is not incremented
+ assertTrue(parcKeyId_Equals(rawKeyId, keyid), "Expected the raw KeyID buffers to be equal");
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_GetSigningAlgorithm)
+{
+ // Check for PARCSigningAlgorithm_RSA value
+ PARCBuffer *bb_id_1 = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid_1 = parcKeyId_Create(bb_id_1);
+ parcBuffer_Release(&bb_id_1);
+
+ PARCBufferComposer *composer1 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer1, "quack quack");
+ PARCBuffer *bb_key_1 = parcBufferComposer_ProduceBuffer(composer1);
+ PARCKey *key_1 = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_1);
+
+ parcKey_AssertValid(key_1);
+
+ assertTrue((parcKey_GetSigningAlgorithm(key_1) == PARCSigningAlgorithm_RSA), "Signing Algorithms don't match");
+
+ parcBuffer_Release(&bb_key_1);
+ parcBufferComposer_Release(&composer1);
+ parcKeyId_Release(&keyid_1);
+ parcKey_Release(&key_1);
+
+ // Check for PARCSigningAlgorithm_HMAC value
+ PARCBuffer *bb_id_2 = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid_2 = parcKeyId_Create(bb_id_2);
+ parcBuffer_Release(&bb_id_2);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer2, "quack quack");
+ PARCBuffer *bb_key_2 = parcBufferComposer_ProduceBuffer(composer2);
+ PARCKey *key_2 = parcKey_CreateFromSymmetricKey(keyid_2, PARCSigningAlgorithm_HMAC, bb_key_2);
+
+ parcKey_AssertValid(key_2);
+
+ assertTrue((parcKey_GetSigningAlgorithm(key_2) == PARCSigningAlgorithm_HMAC), "Signing Algorithms don't match");
+
+ parcBuffer_Release(&bb_key_2);
+ parcBufferComposer_Release(&composer2);
+ parcKeyId_Release(&keyid_2);
+ parcKey_Release(&key_2);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_Acquire)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcKey_AssertValid(key);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcKey_Acquire, key);
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_ToString)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ char *keyString = parcKey_ToString(key);
+
+ assertNotNull(keyString, "Expected non-null key representation string");
+ assertTrue(strlen(keyString) > 0, "Expected non-null key representation string");
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcKey_CreateFromDerEncodedPublicKey_InvalidAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Errors, parcKey_CreateFromSymmetricKey_InvalidAlgorithm);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcKey_CreateFromDerEncodedPublicKey_InvalidAlgorithm, .event = &LongBowTrapIllegalValue)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_HMAC, bb_key);
+
+ assertNull(key, "This should not be reached"); //To avoid a warning
+
+ // HMAC is an illegal value for this constructor
+
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcKey_CreateFromSymmetricKey_InvalidAlgorithm, .event = &LongBowTrapIllegalValue)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromSymmetricKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ assertNull(key, "This should not be reached"); //To avoid a warning
+
+ // RSA/DSA are illegal values for this constructor
+
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Key);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_KeyId.c b/libparc/parc/security/test/test_parc_KeyId.c
new file mode 100644
index 00000000..1b14486d
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_KeyId.c
@@ -0,0 +1,216 @@
+/*
+ * 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/security/parc_KeyId.c>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+const char *testStr = "hello world";
+
+LONGBOW_TEST_RUNNER(test_parc_KeyId)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(test_parc_KeyId)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_KeyId)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_HashCodeFromVoid);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_GetKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ 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, parcKeyId_Create)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_Acquire)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+ parcObjectTesting_AssertAcquireReleaseContract(parcKeyId_Acquire, keyId);
+
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_Copy)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ PARCKeyId *copy = parcKeyId_Copy(keyId);
+ parcKeyId_AssertValid(keyId);
+ parcKeyId_AssertValid(copy);
+
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "parcKeyId_Release did not null the keyId pointer.");
+
+ parcKeyId_AssertValid(copy);
+ parcKeyId_Release(&copy);
+ assertNull(keyId, "parcKeyId_Release did not null the keyId copy pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_Equals)
+{
+ PARCBuffer *buffer1 = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *x = parcKeyId_Create(buffer1);
+ parcBuffer_Release(&buffer1);
+
+ PARCBuffer *buffer2 = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *y = parcKeyId_Create(buffer2);
+ parcBuffer_Release(&buffer2);
+
+ PARCBuffer *buffer3 = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *z = parcKeyId_Create(buffer3);
+ parcBuffer_Release(&buffer3);
+
+ PARCBuffer *buffer4 = parcBuffer_Wrap("hello worlx", 11, 0, 11);
+ PARCKeyId *u1 = parcKeyId_Create(buffer4);
+ parcBuffer_Release(&buffer4);
+
+ parcObjectTesting_AssertEqualsFunction(parcKeyId_Equals, x, y, z, u1);
+
+ parcKeyId_Release(&x);
+ parcKeyId_Release(&y);
+ parcKeyId_Release(&z);
+ parcKeyId_Release(&u1);
+
+ assertNull(x, "Release did not null the pointer.");
+ assertNull(y, "Release did not null the pointer.");
+ assertNull(z, "Release did not null the pointer.");
+ assertNull(u1, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_HashCode)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ assertTrue(parcKeyId_HashCode(keyId) == parcBuffer_HashCode(buffer), "Expected hash codes to be equal");
+
+ parcBuffer_Release(&buffer);
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+
+LONGBOW_TEST_CASE(Global, parcKeyId_HashCodeFromVoid)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ assertTrue(parcKeyId_HashCodeFromVoid((void *) keyId) == parcBuffer_HashCode(buffer), "Expected hash codes to be equal");
+
+ parcBuffer_Release(&buffer);
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_GetKeyId)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ PARCBuffer *rawBuffer = (PARCBuffer *) parcKeyId_GetKeyId(keyId);
+ assertTrue(parcBuffer_Equals(rawBuffer, buffer), "Expected the raw key buffers to be equal");
+
+ parcBuffer_Release(&buffer);
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_ToString)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+
+ parcBuffer_Release(&buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ char *string = parcKeyId_ToString(keyId);
+ printf("Hello: %s\n", string);
+ parcMemory_Deallocate((void **) &string);
+
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_KeyId);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_KeyStore.c b/libparc/parc/security/test/test_parc_KeyStore.c
new file mode 100755
index 00000000..b48099cb
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_KeyStore.c
@@ -0,0 +1,137 @@
+/*
+ * 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_KeyStore.c"
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_KeyStore)
+{
+ // 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);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_KeyStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_KeyStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_Acquire);
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_CreateFile);
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_GetFileName);
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_GetPassWord);
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_Release);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+//LONGBOW_TEST_CASE(Global, parcKeyStore_Acquire)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// parcObjectTesting_AssertAcquireReleaseContract(parcKeyStore_Acquire, keyStoreFile);
+//
+// parcKeyStore_Release(&keyStoreFile);
+//}
+//
+//LONGBOW_TEST_CASE(Global, parcKeyStore_CreateFile)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// parcKeyStore_Release(&keyStoreFile);
+//}
+//
+//LONGBOW_TEST_CASE(Global, parcKeyStore_GetFileName)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// assertEqualStrings(keystoreName, parcKeyStore_GetFileName(keyStoreFile));
+//
+// parcKeyStore_Release(&keyStoreFile);
+//}
+//
+//LONGBOW_TEST_CASE(Global, parcKeyStore_GetPassWord)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// assertEqualStrings(keystorePassword, parcKeyStore_GetPassWord(keyStoreFile));
+//
+// parcKeyStore_Release(&keyStoreFile);
+//}
+//
+//LONGBOW_TEST_CASE(Global, parcKeyStore_Release)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// parcKeyStore_Release(&keyStoreFile);
+// assertNull(keyStoreFile, "Key store File was not nulled out after Release()");
+//}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_KeyStore);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ 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
new file mode 100755
index 00000000..1cd004cd
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Pkcs12KeyStore.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 <config.h>
+
+#include <LongBow/testing.h>
+
+// 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 <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+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_rsa.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_rsa.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, 1024, 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, -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, 1024, 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, 1024, 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, 1024, 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 = 545;
+ 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, 1024, 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_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ assertNotNull(signer, "parcPkcs12KeyStore_Open(\"test_rsa.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_rsa_pub_sha256.bin", O_RDONLY);
+ uint8_t true_digest[SHA256_DIGEST_LENGTH];
+ ssize_t read_bytes = read(fd, true_digest, SHA256_DIGEST_LENGTH);
+ close(fd);
+
+ assertTrue(read_bytes == SHA256_DIGEST_LENGTH, "could not read %d byte digest from test_rsa_pub_sha256.bin", SHA256_DIGEST_LENGTH);
+
+ PARCBuffer *digest = parcCryptoHash_GetDigest(pkd);
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(digest));
+ size_t bb_length = parcBuffer_Remaining(digest);
+ assertTrue(bb_length == SHA256_DIGEST_LENGTH,
+ "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);
+
+ assertTrue(memcmp(bb_buffer, true_digest, SHA256_DIGEST_LENGTH) == 0, "digests did not match");
+
+
+ parcSigner_Release(&signer);
+ parcCryptoHash_Release(&pkd);
+}
+
+/**
+ * Get the certificate digest from the openssl command line pkcs12
+ */
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetCertificateDigest)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ 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_rsa_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_rsa_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_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ 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_rsa_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_rsa_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_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ assertNotNull(signer, "Got null result from opening openssl pkcs12 file");
+
+ PARCBuffer *pubkey_der = parcKeyStore_GetDEREncodedPublicKey(parcSigner_GetKeyStore(signer));
+ assertNotNull(pubkey_der, "got null public key der for external pkcs12");
+
+ // read in the "truth" from the command line utilities
+
+ int fd = open("test_rsa_pub.der", O_RDONLY);
+ uint8_t true_der[1024];
+ ssize_t read_bytes = read(fd, true_der, 1024);
+ close(fd);
+
+ assertTrue(read_bytes == 162, "could not read %d byte digest from test_rsa_pub_sha256.bin", 162);
+
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(pubkey_der));
+ size_t bb_length = parcBuffer_Remaining(pubkey_der);
+ assertTrue(bb_length == read_bytes, "Incorrect digest length returned from GetCertificateDigest: %zu", bb_length);
+ assertTrue(memcmp(bb_buffer, true_der, read_bytes) == 0, "digests did not match");
+
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&pubkey_der);
+}
+
+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_PublicKeySigner.c b/libparc/parc/security/test/test_parc_PublicKeySigner.c
new file mode 100644
index 00000000..0af1aca8
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_PublicKeySigner.c
@@ -0,0 +1,453 @@
+/*
+ * 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 <sys/param.h>
+
+#include <fcntl.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+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_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *instance = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_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", 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);
+ 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)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ 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)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ 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);
+
+ // Digest it
+ PARCCryptoHasher *digester = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *parcDigest = parcCryptoHasher_Finalize(digester);
+
+ 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)) == 128,
+ "Incorrect signature size: %zu",
+ parcBuffer_Position(parcSignature_GetSignature(bb_test_sign)));
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig", O_RDONLY);
+ assertTrue(fd != -1, "Cannot open test_random_bytes.sig file.");
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128, "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ const unsigned char *actual = parcByteArray_Array(parcBuffer_Array(parcSignature_GetSignature(bb_test_sign)));
+
+ assertTrue(memcmp(scratch_buffer, actual, read_bytes) == 0,
+ "signatures did not match");
+
+ parcSigner_Release(&signer);
+ parcSignature_Release(&bb_test_sign);
+ parcCryptoHash_Release(&parcDigest);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetCertificateDigest)
+{
+ char dirname[] = "pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+ const char *password = "flumox";
+ unsigned key_bits = 1024;
+ 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", 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);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ 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 = 1024;
+ 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", 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);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ 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 = 1024;
+ 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", 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);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ 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 = 1024;
+ 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", 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);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ 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_SecureRandom.c b/libparc/parc/security/test/test_parc_SecureRandom.c
new file mode 100755
index 00000000..82359a70
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_SecureRandom.c
@@ -0,0 +1,241 @@
+/*
+ * 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_SecureRandom.c"
+#include <sys/param.h>
+
+#include <fcntl.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_LinkedList.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#define NUM_TESTS 1000
+#define EPSILON 0.01
+
+LONGBOW_TEST_RUNNER(parc_SecureRandom)
+{
+ // 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_SecureRandom)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_SecureRandom)
+{
+ 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)
+{
+ PARCSecureRandom *rng = parcSecureRandom_Create();
+ assertNotNull(rng, "Expected non-null result from parcSecureRandom_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcSecureRandom_Acquire, rng);
+
+ parcSecureRandom_Release(&rng);
+ assertNull(rng, "Expected null result from parcSecureRandom_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcSecureRandom_IsValid);
+}
+
+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;
+}
+
+LONGBOW_TEST_CASE(Object, parcSecureRandom_IsValid)
+{
+ PARCSecureRandom *rng = parcSecureRandom_Create();
+ assertNotNull(rng, "Expected a non-NULL PARCSecureRandom");
+
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_Create to result in a valid instance.");
+
+ parcSecureRandom_Release(&rng);
+ assertFalse(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSecureRandom_Create);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSecureRandom_CreateWithSeed);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSecureRandom_Next);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSecureRandom_NextBytes);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSecureRandom_Create)
+{
+ PARCSecureRandom *rng = parcSecureRandom_Create();
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_Create to result in a valid instance.");
+ parcSecureRandom_Release(&rng);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSecureRandom_CreateWithSeed)
+{
+ PARCBuffer *seed = parcBuffer_Allocate(1024);
+ PARCSecureRandom *rng = parcSecureRandom_CreateWithSeed(seed);
+
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_CreateWithSeed to result in a valid instance.");
+
+ parcSecureRandom_Release(&rng);
+ parcBuffer_Release(&seed);
+}
+
+static void
+_stressTestNext(PARCSecureRandom *rng)
+{
+ PARCLinkedList *seen = parcLinkedList_Create();
+ size_t duplicates = 0;
+ for (size_t i = 0; i < NUM_TESTS; i++) {
+ uint32_t next = parcSecureRandom_Next(rng);
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(next));
+ parcBuffer_Flip(parcBuffer_PutUint32(buffer, next));
+
+ if (parcLinkedList_Contains(seen, buffer)) {
+ duplicates++;
+ } else {
+ parcLinkedList_Append(seen, buffer);
+ }
+
+ parcBuffer_Release(&buffer);
+ }
+
+ assertFalse(duplicates > (NUM_TESTS * EPSILON), "The RNG failed to generate random values: saw %zu duplicates", duplicates);
+ parcLinkedList_Release(&seen);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSecureRandom_Next)
+{
+ PARCSecureRandom *rng = parcSecureRandom_Create();
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_Create to result in a valid instance");
+ _stressTestNext(rng);
+ parcSecureRandom_Release(&rng);
+}
+
+static void
+_stressTestNextBytes(PARCSecureRandom *rng)
+{
+ PARCLinkedList *seen = parcLinkedList_Create();
+ size_t duplicates = 0;
+ for (size_t i = 0; i < NUM_TESTS; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(32);
+
+ int numBytes = parcSecureRandom_NextBytes(rng, buffer);
+ assertTrue(numBytes == 32, "Expected 32 bytes from the RNG, got %d", numBytes);
+
+ if (parcLinkedList_Contains(seen, buffer)) {
+ duplicates++;
+ } else {
+ parcLinkedList_Append(seen, buffer);
+ }
+
+ parcBuffer_Release(&buffer);
+ }
+
+ assertFalse(duplicates > (NUM_TESTS * EPSILON), "The RNG failed to generate random values: saw %zu duplicates", duplicates);
+ parcLinkedList_Release(&seen);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSecureRandom_NextBytes)
+{
+ PARCBuffer *seed = parcBuffer_Allocate(1024);
+ PARCSecureRandom *rng = parcSecureRandom_CreateWithSeed(seed);
+
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_CreateWithSeed to result in a valid instance.");
+ _stressTestNextBytes(rng);
+
+ parcSecureRandom_Release(&rng);
+ parcBuffer_Release(&seed);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_SecureRandom);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Security.c b/libparc/parc/security/test/test_parc_Security.c
new file mode 100755
index 00000000..c2f2f33e
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Security.c
@@ -0,0 +1,109 @@
+/*
+ * 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_Security.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_Security)
+{
+ // 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);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Security)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Security)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSecurity_Fini);
+ LONGBOW_RUN_TEST_CASE(Global, parcSecurity_Init);
+ LONGBOW_RUN_TEST_CASE(Global, parcSecurity_Init_Multiple);
+ LONGBOW_RUN_TEST_CASE(Global, parcSecurity_IsInitialized);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ 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, parcSecurity_Fini)
+{
+ parcSecurity_Init();
+ parcSecurity_AssertIsInitialized();
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcSecurity_Init)
+{
+ parcSecurity_Init();
+ parcSecurity_AssertIsInitialized();
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcSecurity_Init_Multiple)
+{
+ parcSecurity_Init();
+ parcSecurity_Init();
+ parcSecurity_Init();
+ parcSecurity_Init();
+ parcSecurity_AssertIsInitialized();
+ parcSecurity_Fini();
+ parcSecurity_Fini();
+ parcSecurity_Fini();
+ parcSecurity_Fini();
+ assertFalse(parcSecurity_IsInitialized(), "parcSecurity_IsInitialized should be false now");
+}
+
+LONGBOW_TEST_CASE(Global, parcSecurity_IsInitialized)
+{
+ parcSecurity_Init();
+ parcSecurity_AssertIsInitialized();
+ parcSecurity_Fini();
+ assertFalse(parcSecurity_IsInitialized(), "parcSecurity_IsInitialized should be false now");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Security);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Signature.c b/libparc/parc/security/test/test_parc_Signature.c
new file mode 100755
index 00000000..9f54da37
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Signature.c
@@ -0,0 +1,230 @@
+/*
+ * 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_Signature.c"
+#include <inttypes.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Signature)
+{
+ // 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_Signature)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Signature)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_GetHashType);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_GetSignature);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+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);
+ parcBuffer_Release(&bits);
+
+ assertNotNull(signature, "Expected non-NULL PARCSignature");
+ PARCReferenceCount referenceCount = parcObject_GetReferenceCount(signature);
+ assertTrue(referenceCount == 1,
+ "Expected reference count to be equal to 1, got %" PRIu64 "",
+ referenceCount);
+
+ parcSignature_Release(&signature);
+}
+
+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 *handle = parcSignature_Acquire(signature);
+ parcBuffer_Release(&bits);
+
+ assertNotNull(signature, "Expected non-NULL PARCSignature");
+ assertNotNull(handle, "Expected non-NULL PARCSignature after acquisition");
+ PARCReferenceCount referenceCount = parcObject_GetReferenceCount(handle);
+ assertTrue(referenceCount == 2,
+ "Expected reference count to be equal to 2, got %" PRIu64 "",
+ referenceCount);
+
+ parcSignature_Release(&signature);
+ parcSignature_Release(&handle);
+}
+
+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 *handle = parcSignature_Acquire(signature);
+ parcBuffer_Release(&bits);
+
+ assertNotNull(signature, "Expected non-NULL PARCSignature");
+ assertNotNull(handle, "Expected non-NULL PARCSignature after acquisition");
+ PARCReferenceCount referenceCount = parcObject_GetReferenceCount(handle);
+ assertTrue(referenceCount == 2,
+ "Expected reference count to be equal to 2, got %" PRIu64 "",
+ referenceCount);
+
+ parcSignature_Release(&signature);
+ parcSignature_Release(&handle);
+
+ assertNull(signature, "Expected NULL PARCSignature");
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_Equals)
+{
+ PARCBuffer *bits = parcBuffer_Allocate(10); // arbitrary bufer size -- not important
+ 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 *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);
+
+ parcObjectTesting_AssertEqualsFunction(parcSignature_Equals, x, y, z, unequal1, unequal2, unequal3, NULL);
+
+ parcSignature_Release(&x);
+ parcSignature_Release(&y);
+ parcSignature_Release(&z);
+ parcSignature_Release(&unequal1);
+ parcSignature_Release(&unequal2);
+ parcSignature_Release(&unequal3);
+
+ parcBuffer_Release(&bits);
+ parcBuffer_Release(&otherBits);
+}
+
+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);
+ parcBuffer_Release(&bits);
+
+ PARCCryptoHashType actual = parcSignature_GetHashType(signature);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ parcSignature_Release(&signature);
+}
+
+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);
+
+ PARCBuffer *actual = parcSignature_GetSignature(signature);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected the original signature bits to be equal to the actual bits");
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_GetSigningAlgorithm)
+{
+ PARCBuffer *signatureBits = parcBuffer_Allocate(strlen("Hello"));
+ parcBuffer_PutArray(signatureBits, strlen("Hello"), (uint8_t *) "Hello");
+ PARCSigningAlgorithm expected = PARCSigningAlgorithm_DSA;
+ PARCSignature *signature = parcSignature_Create(expected, PARCCryptoHashType_SHA256, signatureBits);
+
+ PARCSigningAlgorithm actual = parcSignature_GetSigningAlgorithm(signature);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&signatureBits);
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_ToString)
+{
+ PARCBuffer *signatureBits = parcBuffer_Allocate(strlen("Hello"));
+ parcBuffer_PutArray(signatureBits, strlen("Hello"), (uint8_t *) "Hello");
+ PARCSigningAlgorithm expected = PARCSigningAlgorithm_DSA;
+ PARCSignature *signature = parcSignature_Create(expected, PARCCryptoHashType_SHA256, signatureBits);
+
+ char *string = parcSignature_ToString(signature);
+
+ assertNotNull(string, "Expected non-NULL result from parcSignature_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&signatureBits);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Signature);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Signer.c b/libparc/parc/security/test/test_parc_Signer.c
new file mode 100644
index 00000000..b9605384
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Signer.c
@@ -0,0 +1,305 @@
+/*
+ * 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 <config.h>
+#include <LongBow/unit-test.h>
+#include <sys/param.h>
+#include <errno.h>
+
+#include "../parc_Signer.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+
+#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_RSA, PARCCryptoHashType_SHA256, buffer);
+ parcBuffer_Release(&buffer);
+ return signature;
+}
+
+static PARCSigningAlgorithm
+_GetSigningAlgorithm(PARCSigner *interfaceContext)
+{
+ return PARCSigningAlgorithm_RSA;
+}
+
+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()
+{
+ _MockSigner *signer = parcObject_CreateInstance(_MockSigner);
+
+ signer->hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.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_RSA == alg, "Expected PARCSigningAlgorithm_RSA 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_SigningAlgorithm.c b/libparc/parc/security/test/test_parc_SigningAlgorithm.c
new file mode 100755
index 00000000..e8f8581a
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_SigningAlgorithm.c
@@ -0,0 +1,125 @@
+/*
+ * 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_SigningAlgorithm.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_parc_SigningAlgorithm)
+{
+ // 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);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_SigningAlgorithm)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_SigningAlgorithm)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_ToFromString);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_ToFromString_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_FromString_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_GetSigningAlgorithm_BadAlgorithm);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcSigningAlgorithm_ToFromString)
+{
+ PARCSigningAlgorithm expected = PARCSigningAlgorithm_HMAC;
+
+ const char *string = parcSigningAlgorithm_ToString(expected);
+
+ PARCSigningAlgorithm actual = parcSigningAlgorithm_FromString(string);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigningAlgorithm_ToFromString_NotFound)
+{
+ PARCSigningAlgorithm expected = 123456;
+
+ const char *string = parcSigningAlgorithm_ToString(expected);
+
+ assertNull(string, "Expect parcSigningAlgorithm_ToString to return NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcSigningAlgorithm_FromString_NotFound)
+{
+ PARCSigningAlgorithm actual = parcSigningAlgorithm_FromString("garbage string of unknown stuff");
+
+ assertTrue(actual == PARCSigningAlgorithm_UNKNOWN,
+ "Expect parcSigningAlgorithm_FromString to return PARCSigningAlgorithm_UNKNOWN");
+}
+
+LONGBOW_TEST_CASE(Global, parcSigningAlgorithm_GetSigningAlgorithm)
+{
+ PARCSigningAlgorithm actual = parcSigningAlgorithm_GetSigningAlgorithm(PARCCryptoSuite_DSA_SHA256);
+ assertTrue(PARCSigningAlgorithm_DSA == actual, "Expected %d, actual %d", PARCSigningAlgorithm_DSA, actual);
+
+ actual = parcSigningAlgorithm_GetSigningAlgorithm(PARCCryptoSuite_RSA_SHA256);
+ assertTrue(PARCSigningAlgorithm_RSA == actual, "Expected %d, actual %d", PARCSigningAlgorithm_RSA, actual);
+
+ actual = parcSigningAlgorithm_GetSigningAlgorithm(PARCCryptoSuite_RSA_SHA512);
+ assertTrue(PARCSigningAlgorithm_RSA == actual, "Expected %d, actual %d", PARCSigningAlgorithm_RSA, actual);
+
+ actual = parcSigningAlgorithm_GetSigningAlgorithm(PARCCryptoSuite_HMAC_SHA256);
+ assertTrue(PARCSigningAlgorithm_HMAC == actual, "Expected %d, actual %d", PARCSigningAlgorithm_HMAC, actual);
+
+ actual = parcSigningAlgorithm_GetSigningAlgorithm(PARCCryptoSuite_HMAC_SHA512);
+ assertTrue(PARCSigningAlgorithm_HMAC == actual, "Expected %d, actual %d", PARCSigningAlgorithm_HMAC, actual);
+
+ actual = parcSigningAlgorithm_GetSigningAlgorithm(PARCCryptoSuite_NULL_CRC32C);
+ assertTrue(PARCSigningAlgortihm_NULL == actual, "Expected %d, actual %d", PARCSigningAlgortihm_NULL, actual);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcSigningAlgorithm_GetSigningAlgorithm_BadAlgorithm, .event = &LongBowTrapIllegalValue)
+{
+ parcSigningAlgorithm_GetSigningAlgorithm(-1);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_SigningAlgorithm);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_SymmetricKeySigner.c b/libparc/parc/security/test/test_parc_SymmetricKeySigner.c
new file mode 100644
index 00000000..562ba6c6
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_SymmetricKeySigner.c
@@ -0,0 +1,247 @@
+/*
+ * 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_SymmetricKeySigner.c"
+#include <sys/param.h>
+
+#include <errno.h>
+#include <config.h>
+#include <fcntl.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <LongBow/longBow_Compiler.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+static PARCSymmetricKeySigner *
+_createSigner()
+{
+ PARCBuffer *secret_key = parcSymmetricKeyStore_CreateKey(256);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ parcBuffer_Release(&secret_key);
+
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+
+ return privateKeySigner;
+}
+
+LONGBOW_TEST_RUNNER(parc_SymmetricSigner)
+{
+ // 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(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_SymmetricSigner)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_SymmetricSigner)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCSymmetricKeySigner *instance = _createSigner();
+
+ assertNotNull(instance, "Expected non-null result from parcSymmetricKeySigner_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcSymmetricKeySigner_Acquire, instance);
+
+ parcSymmetricKeySigner_Release(&instance);
+ assertNull(instance, "Expected null result from parcSymmetricKeySigner_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, test_hmac_sha256);
+ LONGBOW_RUN_TEST_CASE(Specialization, test_hmac_sha512);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+LONGBOW_TEST_CASE(Specialization, test_hmac_sha256)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX *ctx = HMAC_CTX_new();
+#else
+ HMAC_CTX ctx;
+#endif
+ char key[] = "apple_pie_is_good";
+ int fd;
+ uint8_t to_digest_buffer[MAXPATHLEN];
+ ssize_t to_digest_length;
+
+ uint8_t true_hmac_buffer[MAXPATHLEN];
+ ssize_t true_hmac_length;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_Init_ex(ctx, key, sizeof(key), EVP_sha256(), NULL);
+#else
+ LONGBOW_STOP_DEPRECATED_WARNINGS
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx, key, sizeof(key), EVP_sha256(), NULL);
+ LONGBOW_START_DEPRECATED_WARNINGS
+#endif
+ fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ to_digest_length = read(fd, to_digest_buffer, sizeof(to_digest_buffer));
+ assertTrue(to_digest_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ fd = open("test_random_bytes.hmac_sha256", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ true_hmac_length = read(fd, true_hmac_buffer, sizeof(true_hmac_buffer));
+ assertTrue(true_hmac_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ _hmacInit(ctx);
+ _hmacUpdate(ctx, to_digest_buffer, to_digest_length);
+#else
+ _hmacInit(&ctx);
+ _hmacUpdate(&ctx, to_digest_buffer, to_digest_length);
+#endif
+ PARCBuffer *output = _hmacFinalize(&ctx);
+
+ assertTrue(parcBuffer_Position(output) == true_hmac_length,
+ "hmac wrong length, expected %zu got %zu",
+ true_hmac_length,
+ parcBuffer_Position(output));
+
+ assertTrue(memcmp(parcByteArray_Array(parcBuffer_Array(output)), true_hmac_buffer, true_hmac_length) == 0,
+ "hmac values did not match");
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX_free(ctx);
+#else
+ LONGBOW_STOP_DEPRECATED_WARNINGS
+ HMAC_cleanup(&ctx);
+ LONGBOW_START_DEPRECATED_WARNINGS
+#endif
+ parcBuffer_Release(&output);
+}
+
+LONGBOW_TEST_CASE(Specialization, test_hmac_sha512)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX *ctx = HMAC_CTX_new();
+#else
+ HMAC_CTX ctx;
+#endif
+ char key[] = "apple_pie_is_good";
+ int fd;
+ uint8_t to_digest_buffer[MAXPATHLEN];
+ ssize_t to_digest_length;
+
+ uint8_t true_hmac_buffer[MAXPATHLEN];
+ ssize_t true_hmac_length;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_Init_ex(ctx, key, sizeof(key), EVP_sha512(), NULL);
+#else
+ LONGBOW_STOP_DEPRECATED_WARNINGS
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx, key, sizeof(key), EVP_sha512(), NULL);
+ LONGBOW_START_DEPRECATED_WARNINGS
+#endif
+ fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ to_digest_length = read(fd, to_digest_buffer, sizeof(to_digest_buffer));
+ assertTrue(to_digest_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ fd = open("test_random_bytes.hmac_sha512", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ true_hmac_length = read(fd, true_hmac_buffer, sizeof(true_hmac_buffer));
+ assertTrue(true_hmac_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ _hmacInit(ctx);
+ _hmacUpdate(ctx, to_digest_buffer, to_digest_length);
+#else
+ _hmacInit(&ctx);
+ _hmacUpdate(&ctx, to_digest_buffer, to_digest_length);
+#endif
+ PARCBuffer *output = _hmacFinalize(&ctx);
+
+ assertTrue(parcBuffer_Position(output) == true_hmac_length,
+ "hmac wrong length, expected %zu got %zu",
+ true_hmac_length,
+ parcBuffer_Position(output));
+
+ assertTrue(memcmp(parcByteArray_Array(parcBuffer_Array(output)), true_hmac_buffer, true_hmac_length) == 0,
+ "hmac values did not match");
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX_free(ctx);
+#else
+ LONGBOW_STOP_DEPRECATED_WARNINGS
+ HMAC_cleanup(&ctx);
+ LONGBOW_START_DEPRECATED_WARNINGS
+#endif
+ parcBuffer_Release(&output);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_SymmetricSigner);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_SymmetricKeyStore.c b/libparc/parc/security/test/test_parc_SymmetricKeyStore.c
new file mode 100755
index 00000000..ab9dfddb
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_SymmetricKeyStore.c
@@ -0,0 +1,351 @@
+/*
+ * 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_SymmetricKeyStore.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <errno.h>
+#include <sys/param.h>
+#include <fcntl.h>
+
+#include <parc/security/parc_SymmetricKeySigner.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_SymmetricSignerFileStore)
+{
+ // 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_SymmetricSignerFileStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_SymmetricSignerFileStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSymmetricKeyStore_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcSymmetricKeyStore_CreateKey);
+// LONGBOW_RUN_TEST_CASE(Global, parcSymmetricKeyStore_CreateFail);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ 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, parcSymmetricKeyStore_Create)
+{
+ char dirname[] = "/tmp/pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ PARCBuffer *secret_key = parcSymmetricKeyStore_CreateKey(256);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&secret_key);
+}
+
+LONGBOW_TEST_CASE(Global, parcSymmetricKeyStore_CreateKey)
+{
+ PARCBuffer *bb = parcSymmetricKeyStore_CreateKey(256);
+ assertTrue(parcBuffer_Remaining(bb) == 32, "Key wrong length expected %d got %zu", 32, parcBuffer_Position(bb));
+ parcBuffer_Release(&bb);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcSymmetricKeyStore_CreateFail, .event = &LongBowTrapIllegalValue)
+{
+ PARCBuffer *key = parcSymmetricKeyStore_CreateKey(256);
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_CRC32C);
+
+ // fail.
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+ parcBuffer_Release(&key);
+}
+
+// ==========================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_GetCryptoHashType);
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_GetSecretKeyDigest);
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_SignDigest_sha256);
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_SignDigest_sha512);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ 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, parcSymmetricKeyStore_GetCryptoHashType)
+{
+ PARCBuffer *secret_key = parcSymmetricKeyStore_CreateKey(256);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCCryptoHashType hashType = parcSigner_GetCryptoHashType(signer);
+ assertTrue(hashType == PARCCryptoHashType_SHA256,
+ "Got wrong hash Type, expected %d got %d", PARCCryptoHashType_SHA256, hashType);
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&secret_key);
+}
+
+LONGBOW_TEST_CASE(Local, parcSymmetricKeyStore_GetSecretKeyDigest)
+{
+ int fd;
+ uint8_t key_buffer[128];
+ uint8_t key_sha256[128];
+ ssize_t read_len;
+
+ fd = open("test_symmetric_key.bin", O_RDONLY);
+ read_len = read(fd, key_buffer, sizeof(key_buffer));
+ assertTrue(read_len == 32, "read wrong size, expected 32, got %zd", read_len);
+ close(fd);
+
+ fd = open("test_symmetric_key.sha256", O_RDONLY);
+ read_len = read(fd, key_sha256, sizeof(key_sha256));
+ assertTrue(read_len == 32, "read wrong size, expected 32, got %zd", read_len);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, key_buffer, 32);
+ PARCBuffer *secret_key = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer2, key_sha256, 32);
+ PARCBuffer *secret_sha = parcBufferComposer_ProduceBuffer(composer2);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCCryptoHash *key_hash = parcKeyStore_GetVerifierKeyDigest(parcSigner_GetKeyStore(signer));
+ assertTrue(parcBuffer_Equals(parcCryptoHash_GetDigest(key_hash), secret_sha),
+ "sha256 digests of secret key did not match");
+ parcCryptoHash_Release(&key_hash);
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcBuffer_Release(&secret_sha);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Release(&secret_key);
+ parcBufferComposer_Release(&composer2);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Local, parcSymmetricKeyStore_GetSigningAlgorithm)
+{
+ PARCBuffer *secret_key = parcSymmetricKeyStore_CreateKey(256);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCSigningAlgorithm alg = parcSigner_GetSigningAlgorithm(signer);
+ assertTrue(alg == PARCSigningAlgorithm_HMAC,
+ "Got wrong signing algorithm, expected %d got %d", PARCSigningAlgorithm_HMAC, alg);
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&secret_key);
+}
+
+LONGBOW_TEST_CASE(Local, parcSymmetricKeyStore_SignDigest_sha256)
+{
+ uint8_t to_digest_buffer[MAXPATHLEN];
+ ssize_t to_digest_length;
+ uint8_t true_hmac_buffer[MAXPATHLEN];
+ char key[] = "apple_pie_is_good";
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, key);
+ PARCBuffer *key_buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ int fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ to_digest_length = read(fd, to_digest_buffer, sizeof(to_digest_buffer));
+ assertTrue(to_digest_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ fd = open("test_random_bytes.hmac_sha256", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ ssize_t true_hmac_length = read(fd, true_hmac_buffer, sizeof(true_hmac_buffer));
+ assertTrue(true_hmac_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer2, true_hmac_buffer, true_hmac_length);
+ PARCBuffer *true_hash = parcBufferComposer_ProduceBuffer(composer2);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(key_buffer);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_digest_buffer, to_digest_length);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ assertTrue(parcBuffer_Equals(parcSignature_GetSignature(sig), parcCryptoHash_GetDigest(hash)),
+ "Hashes are not equal");
+ assertTrue(parcBuffer_Equals(parcSignature_GetSignature(sig), true_hash),
+ "Hash does not match file");
+ assertTrue(parcSignature_GetSigningAlgorithm(sig) == PARCSigningAlgorithm_HMAC,
+ "Signing alg incorrect, expected %d got %d",
+ PARCSigningAlgorithm_HMAC, parcSignature_GetSigningAlgorithm(sig));
+ assertTrue(parcSignature_GetHashType(sig) == PARCCryptoHashType_SHA256,
+ "Digest alg incorrect, expected %d got %d",
+ PARCCryptoHashType_SHA256, parcSignature_GetSigningAlgorithm(sig));
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSignature_Release(&sig);
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&true_hash);
+ parcBuffer_Release(&key_buffer);
+ parcBufferComposer_Release(&composer);
+ parcBufferComposer_Release(&composer2);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Local, parcSymmetricKeyStore_SignDigest_sha512)
+{
+ char key[] = "apple_pie_is_good";
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, key);
+ PARCBuffer *key_buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ int fd;
+ uint8_t to_digest_buffer[MAXPATHLEN];
+ ssize_t to_digest_length;
+
+ uint8_t true_hmac_buffer[MAXPATHLEN];
+ ssize_t true_hmac_length;
+
+ fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ to_digest_length = read(fd, to_digest_buffer, sizeof(to_digest_buffer));
+ assertTrue(to_digest_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ fd = open("test_random_bytes.hmac_sha512", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ true_hmac_length = read(fd, true_hmac_buffer, sizeof(true_hmac_buffer));
+ assertTrue(true_hmac_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer2, true_hmac_buffer, true_hmac_length);
+ PARCBuffer *true_hash = parcBufferComposer_ProduceBuffer(composer2);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(key_buffer);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA512);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_digest_buffer, to_digest_length);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ assertTrue(parcBuffer_Equals(parcSignature_GetSignature(sig), parcCryptoHash_GetDigest(hash)),
+ "Hashes are not equal");
+ assertTrue(parcBuffer_Equals(parcSignature_GetSignature(sig), true_hash),
+ "Hash does not match file");
+ assertTrue(parcSignature_GetSigningAlgorithm(sig) == PARCSigningAlgorithm_HMAC,
+ "Signing alg incorrect, expected %d got %d",
+ PARCSigningAlgorithm_HMAC, parcSignature_GetSigningAlgorithm(sig));
+ assertTrue(parcSignature_GetHashType(sig) == PARCCryptoHashType_SHA512,
+ "Digest alg incorrect, expected %d got %d",
+ PARCCryptoHashType_SHA512, parcSignature_GetSigningAlgorithm(sig));
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSignature_Release(&sig);
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&true_hash);
+ parcBuffer_Release(&key_buffer);
+ parcBufferComposer_Release(&composer);
+ parcBufferComposer_Release(&composer2);
+ parcSigner_Release(&signer);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_SymmetricSignerFileStore);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Verifier.c b/libparc/parc/security/test/test_parc_Verifier.c
new file mode 100755
index 00000000..fe382a9b
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Verifier.c
@@ -0,0 +1,121 @@
+/*
+ * 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_Verifier.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Verifier)
+{
+ // 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_Verifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Verifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_AddKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_AllowedCryptoSuite);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_GetCryptoHasher);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_RemoveKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_VerifySignature);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_AddKey)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_AllowedCryptoSuite)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_Create)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_Destroy)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_GetCryptoHasher)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_RemoveKeyId)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_VerifySignature)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Verifier);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ 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
new file mode 100755
index 00000000..3ddb8220
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_X509Certificate.c
@@ -0,0 +1,224 @@
+/*
+ * 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 <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "../parc_X509Certificate.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_X509Certificate)
+{
+ // 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_TEST_RUNNER_SETUP(parc_X509Certificate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_X509Certificate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_CreateFromDERBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_GetPublicKeyDigest);
+ 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_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, parc_X509Certificate_AcquireRelease)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(fileName);
+ assertNotNull(certificate, "Expected non-NULL certificate");
+
+ PARCReferenceCount firstCount = parcObject_GetReferenceCount(certificate);
+ PARCX509Certificate *copy = parcX509Certificate_Acquire(certificate);
+ PARCReferenceCount secondCount = parcObject_GetReferenceCount(copy);
+
+ assertTrue(firstCount == (secondCount - 1), "Expected incremented reference count after Acquire");
+
+ parcX509Certificate_Release(&copy);
+ PARCReferenceCount thirdCount = parcObject_GetReferenceCount(certificate);
+
+ assertTrue(firstCount == thirdCount, "Expected equal reference counts after Release");
+
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_Create)
+{
+ char *fileName = "bad.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+ assertNull(certificate, "Expected NULL certificate with non-existent file");
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_CreateFromDERBuffer)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+ assertNotNull(certificate, "Expected non-NULL certificate");
+
+ PARCBuffer *certificateBuffer = _getDEREncodedCertificate(certificate);
+ PARCX509Certificate *realCertificate = parcX509Certificate_CreateFromDERBuffer(certificateBuffer);
+ assertNotNull(realCertificate, "Expected non-NULL certificate to be parsed from DER buffer");
+
+ parcX509Certificate_Release(&certificate);
+ parcX509Certificate_Release(&realCertificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_GetPublicKeyDigest)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+
+ PARCCryptoHash *digest = _getPublicKeyDigest(certificate);
+ PARCBuffer *digestBuffer = parcCryptoHash_GetDigest(digest);
+
+ size_t expectedLength = SHA256_DIGEST_LENGTH;
+ size_t actualLength = parcBuffer_Remaining(digestBuffer);
+ assertTrue(actualLength == expectedLength, "Digest unexpected size: got %zu expected %zu", actualLength, expectedLength);
+
+ int fd = open("test_pubkey.bin", O_RDONLY);
+ uint8_t rawDigest[SHA256_DIGEST_LENGTH];
+ ssize_t numBytes = read(fd, rawDigest, SHA256_DIGEST_LENGTH);
+ assertTrue(numBytes == SHA256_DIGEST_LENGTH, "Expected to read %d bytes, got %zu", SHA256_DIGEST_LENGTH, numBytes);
+ close(fd);
+
+ PARCBuffer *rawBuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(rawDigest, SHA256_DIGEST_LENGTH));
+
+ assertTrue(parcBuffer_Remaining(rawBuffer) == SHA256_DIGEST_LENGTH, "Expected %d length buffer", SHA256_DIGEST_LENGTH);
+
+ parcBuffer_Release(&rawBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_GetCertificateDigest)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+
+ PARCCryptoHash *digest = _getCertificateDigest(certificate);
+ PARCBuffer *digestBuffer = parcCryptoHash_GetDigest(digest);
+
+ size_t expectedLength = SHA256_DIGEST_LENGTH;
+ size_t actualLength = parcBuffer_Remaining(digestBuffer);
+ assertTrue(actualLength == expectedLength, "Digest unexpected size: got %zu expected %zu", actualLength, expectedLength);
+
+ int fd = open("test_crt_sha256.bin", O_RDONLY);
+ uint8_t rawDigest[SHA256_DIGEST_LENGTH];
+ ssize_t numBytes = read(fd, rawDigest, SHA256_DIGEST_LENGTH);
+ assertTrue(numBytes == SHA256_DIGEST_LENGTH, "Expected to read %d bytes, got %zu", SHA256_DIGEST_LENGTH, numBytes);
+ close(fd);
+
+ PARCBuffer *rawBuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(rawDigest, SHA256_DIGEST_LENGTH));
+
+ assertTrue(parcBuffer_Equals(rawBuffer, digestBuffer), "Expected raw binary to equal the computed result.");
+
+ parcBuffer_Release(&rawBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_GetDEREncodedCertificate)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+
+ PARCBuffer *digestBuffer = _getDEREncodedCertificate(certificate);
+
+ size_t expectedLength = 517;
+ size_t actualLength = parcBuffer_Remaining(digestBuffer);
+ assertTrue(actualLength == expectedLength, "Digest unexpected size: got %zu expected %zu", actualLength, expectedLength);
+
+ int fd = open("test_crt_der.bin", O_RDONLY);
+ uint8_t rawDigest[expectedLength];
+ ssize_t numBytes = read(fd, rawDigest, expectedLength);
+ assertTrue(numBytes == expectedLength, "Expected to read %zu bytes, got %zu", expectedLength, numBytes);
+ close(fd);
+
+ PARCBuffer *rawBuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(rawDigest, expectedLength));
+
+ assertTrue(parcBuffer_Equals(rawBuffer, digestBuffer), "Expected raw binary to equal the computed result.");
+
+ parcBuffer_Release(&rawBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_GetDEREncodedPublicKey)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+
+ PARCBuffer *digestBuffer = _getDEREncodedPublicKey(certificate);
+
+ size_t expectedLength = 162;
+ size_t actualLength = parcBuffer_Remaining(digestBuffer);
+ assertTrue(actualLength == expectedLength, "Digest unexpected size: got %zu expected %zu", actualLength, expectedLength);
+
+ int fd = open("test_der.bin", O_RDONLY);
+ uint8_t rawDigest[expectedLength];
+ ssize_t numBytes = read(fd, rawDigest, expectedLength);
+ assertTrue(numBytes == expectedLength, "Expected to read %zu bytes, got %zu", expectedLength, numBytes);
+ close(fd);
+
+ PARCBuffer *rawBuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(rawDigest, expectedLength));
+
+ assertTrue(parcBuffer_Equals(rawBuffer, digestBuffer), "Expected raw binary to equal the computed result.");
+
+ parcBuffer_Release(&rawBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_X509Certificate);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_pubkey.bin b/libparc/parc/security/test/test_pubkey.bin
new file mode 100644
index 00000000..1d426b87
--- /dev/null
+++ b/libparc/parc/security/test/test_pubkey.bin
@@ -0,0 +1 @@
+_.yWSfbQИ6u\ob \ No newline at end of file
diff --git a/libparc/parc/security/test/test_pubkey.der b/libparc/parc/security/test/test_pubkey.der
new file mode 100644
index 00000000..eb75e987
--- /dev/null
+++ b/libparc/parc/security/test/test_pubkey.der
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR0t1wjPPlx/x3vMDN/yaClXmp
+NqdIX31oejG4nFQrqH821a6vZjaEEk6jNUM9v4a5mDHdgXQCvSjoRVnfCPVi06j/
+h4oylHaANMSOfcP2AimGBT0R1mT8cBHsI1JmYfhS5jSCzxyyTtq0WVDqndGl0qZp
+cRGONepOxn36uZso2QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/libparc/parc/security/test/test_pubkey.pem b/libparc/parc/security/test/test_pubkey.pem
new file mode 100644
index 00000000..eb75e987
--- /dev/null
+++ b/libparc/parc/security/test/test_pubkey.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR0t1wjPPlx/x3vMDN/yaClXmp
+NqdIX31oejG4nFQrqH821a6vZjaEEk6jNUM9v4a5mDHdgXQCvSjoRVnfCPVi06j/
+h4oylHaANMSOfcP2AimGBT0R1mT8cBHsI1JmYfhS5jSCzxyyTtq0WVDqndGl0qZp
+cRGONepOxn36uZso2QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/libparc/parc/security/test/test_random_bytes b/libparc/parc/security/test/test_random_bytes
new file mode 100644
index 00000000..33a80af5
--- /dev/null
+++ b/libparc/parc/security/test/test_random_bytes
Binary files differ
diff --git a/libparc/parc/security/test/test_random_bytes.hmac_sha256 b/libparc/parc/security/test/test_random_bytes.hmac_sha256
new file mode 100644
index 00000000..ee066075
--- /dev/null
+++ b/libparc/parc/security/test/test_random_bytes.hmac_sha256
Binary files differ
diff --git a/libparc/parc/security/test/test_random_bytes.hmac_sha512 b/libparc/parc/security/test/test_random_bytes.hmac_sha512
new file mode 100644
index 00000000..fcd110b2
--- /dev/null
+++ b/libparc/parc/security/test/test_random_bytes.hmac_sha512
Binary files differ
diff --git a/libparc/parc/security/test/test_random_bytes.sig b/libparc/parc/security/test/test_random_bytes.sig
new file mode 100644
index 00000000..9c395ce0
--- /dev/null
+++ b/libparc/parc/security/test/test_random_bytes.sig
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa.crt b/libparc/parc/security/test/test_rsa.crt
new file mode 100644
index 00000000..6f7ce9e6
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa.crt
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQDE2fTij4zOkTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTEzMTAxNTIzMjUyNloXDTE0MTAxNTIzMjUyNlowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp9aT
+xfFzxhK1+nnF7xiL76rNBAGPg3c/sWahWrk5KrI+MPsR/Ff8ndEvd/Crd61mLCbI
+m1Fvab8mEAYp7suwLF6RDiRCjeZ1oE4EQww+TAZ0Z62Ew+j0xZRzxJ8lqEIGv0UZ
+4pgcNqFDTZtxCOGC3+JPKjw9DzWSrnAn+9LkHicCAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQALNQ1/nNF/jMYijV+XI/IL0/zziaUu2GSyTQlGsmfLhMY0/Qx+8Pbaik+R
+DVtNMZatJGSXgSvx6ETGpkXVdsZzZfDIYSIyKrbf7uV3GFfqCv4IqU2OI42ex7TE
+Ry+xm2mioAYgcnAIxA4CmyTm+tWJ9MTJkCG/aPhhcPxP6XzjPA==
+-----END CERTIFICATE-----
diff --git a/libparc/parc/security/test/test_rsa.csr b/libparc/parc/security/test/test_rsa.csr
new file mode 100644
index 00000000..1ff56fc4
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa.csr
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
+MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCn1pPF8XPGErX6ecXvGIvvqs0EAY+Ddz+xZqFauTkqsj4w
++xH8V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEOJEKN5nWgTgRDDD5MBnRn
+rYTD6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8qPD0PNZKucCf70uQeJwID
+AQABoAAwDQYJKoZIhvcNAQEFBQADgYEAEVdzGyNxqWTRSaBo8JybmHNuXiTLvGPR
+GCegG3GwtTiptzwrtUhOmkWoPkWBwB/rLJyga7sPgg73D5aCz3PsagNSqLytCuW+
+qFJdODd6IXQrJ8fUHsV2SENNbkL+zsg1cYVB0T+8B6BP84hHaD3NResmMVjhuPIr
+0uHYQ7e2ex8=
+-----END CERTIFICATE REQUEST-----
diff --git a/libparc/parc/security/test/test_rsa.p12 b/libparc/parc/security/test/test_rsa.p12
new file mode 100644
index 00000000..471c4006
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa.p12
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa_crt.der b/libparc/parc/security/test/test_rsa_crt.der
new file mode 100644
index 00000000..d79f4b47
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_crt.der
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa_crt_sha256.bin b/libparc/parc/security/test/test_rsa_crt_sha256.bin
new file mode 100644
index 00000000..7da092ff
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_crt_sha256.bin
@@ -0,0 +1,2 @@
+VF,-x(SEl/
+:H&64M!:=) \ No newline at end of file
diff --git a/libparc/parc/security/test/test_rsa_key.der b/libparc/parc/security/test/test_rsa_key.der
new file mode 100644
index 00000000..a88e8e94
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_key.der
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa_key.pem b/libparc/parc/security/test/test_rsa_key.pem
new file mode 100644
index 00000000..6c502b15
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCn1pPF8XPGErX6ecXvGIvvqs0EAY+Ddz+xZqFauTkqsj4w+xH8
+V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEOJEKN5nWgTgRDDD5MBnRnrYTD
+6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8qPD0PNZKucCf70uQeJwIDAQAB
+AoGAVOYPA/7aIGSQlu4IOKTDDG3qnM8pSEgG+PbAQgMVrspQ+TfXZj0ftLj++P3N
+zpDw8P6BVUfBQs2FNG/ZwEhaiZVgJAl7cIAxJ9Ac+1oZYSgGyJfb3u9iWvkbMOoj
+83Inx5yyN+Qmk5zceH4pOC5D5cDAuGGZ740Euv4o2/2O3qECQQDTmWZw021PvEbA
+r18O1YfZGxO3zFCwFXCpnHvtSMbP+MXAG5Gt47wZt4Vx1rX9k78beeCUitwqp3d3
+ZI+YlUu3AkEAyw5wssQsJty/n2FL8DbJN3UzUhkcaCFYrKz3RtFye9wu+Bw0TxPC
+3jhFVcynm3nH3ZJN0JsnsPnHXuoQToShEQJATXC51hb6zZC5UDGel348fo9zUvP6
+n8bo+ZoknL3izSBdtyYf1cUgBUVuGDCdYFWfPn4HXDXJx+6MQWzTRON21wJBAMZL
+U8M/z94jtP3wBjiPR/Dggz2pSBRofDAkuVZvM13BqByjbnHK2oIocY1YTlWGl6fJ
+ODR/UEODqS8HZOVIoAECQANcuvVnqDixSIl2ySZvydQytv4DKTbvE0nYSRroYIlJ
+PTOBPy8ynIUkJwc2E1BsLl7V8gO62a5O0ntTwBMnPSQ=
+-----END RSA PRIVATE KEY-----
diff --git a/libparc/parc/security/test/test_rsa_pub.der b/libparc/parc/security/test/test_rsa_pub.der
new file mode 100644
index 00000000..7c931999
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_pub.der
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa_pub.pem b/libparc/parc/security/test/test_rsa_pub.pem
new file mode 100644
index 00000000..7b8f29c2
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_pub.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn1pPF8XPGErX6ecXvGIvvqs0E
+AY+Ddz+xZqFauTkqsj4w+xH8V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEO
+JEKN5nWgTgRDDD5MBnRnrYTD6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8q
+PD0PNZKucCf70uQeJwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/libparc/parc/security/test/test_rsa_pub_sha256.bin b/libparc/parc/security/test/test_rsa_pub_sha256.bin
new file mode 100644
index 00000000..c15478cf
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_pub_sha256.bin
@@ -0,0 +1 @@
+\#L(P {%ba`v8IθY \ No newline at end of file
diff --git a/libparc/parc/security/test/test_symmetric_key.bin b/libparc/parc/security/test/test_symmetric_key.bin
new file mode 100644
index 00000000..2ad3409d
--- /dev/null
+++ b/libparc/parc/security/test/test_symmetric_key.bin
Binary files differ
diff --git a/libparc/parc/security/test/test_symmetric_key.sha256 b/libparc/parc/security/test/test_symmetric_key.sha256
new file mode 100644
index 00000000..910397cf
--- /dev/null
+++ b/libparc/parc/security/test/test_symmetric_key.sha256
@@ -0,0 +1 @@
+A_ӻ-;Ȑn.1~072 \ No newline at end of file