]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_smime/regressions/cms-01-basic.c
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_smime / regressions / cms-01-basic.c
diff --git a/OSX/libsecurity_smime/regressions/cms-01-basic.c b/OSX/libsecurity_smime/regressions/cms-01-basic.c
new file mode 100644 (file)
index 0000000..40f6689
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "cms-01-basic.h"
+#include "smime_regressions.h"
+
+#include <AssertMacros.h>
+
+#include <utilities/SecCFRelease.h>
+
+#include <Security/SecBase.h>
+#include <Security/SecImportExport.h>
+#include <Security/SecKeychain.h>
+#include <Security/SecIdentity.h>
+#include <Security/SecPolicy.h>
+
+#include <Security/SecCmsMessage.h>
+#include <Security/SecCmsSignedData.h>
+#include <Security/SecCmsContentInfo.h>
+#include <Security/SecCmsSignerInfo.h>
+#include <Security/SecCmsEncoder.h>
+#include <Security/SecCmsDecoder.h>
+#include <Security/SecCmsEnvelopedData.h>
+#include <Security/SecCmsRecipientInfo.h>
+
+#include <security_asn1/secerr.h>
+#include <security_asn1/seccomon.h>
+
+#define TMP_KEYCHAIN_PATH "/tmp/cms_01_test.keychain"
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic ignored "-Wunused-function"
+
+#define kNumberSetupTests 10
+static SecKeychainRef setup_keychain(const uint8_t *p12, size_t p12_len, SecIdentityRef *identity, SecCertificateRef *cert) {
+    CFDataRef p12Data = NULL;
+    CFArrayRef imported_items = NULL, oldSearchList = NULL;
+    CFMutableArrayRef newSearchList = NULL;
+    SecKeychainRef keychain = NULL;
+    SecExternalFormat sef = kSecFormatPKCS12;
+    SecItemImportExportKeyParameters keyParams = {
+        .passphrase = CFSTR("password")
+    };
+
+    /* Create keychain and add to search list (for decryption) */
+    unlink(TMP_KEYCHAIN_PATH);
+    ok_status(SecKeychainCopySearchList(&oldSearchList),
+              "Copy keychain search list");
+    require(oldSearchList, out);
+    ok(newSearchList = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(oldSearchList)+1, oldSearchList),
+       "Create new search list");
+    ok_status(SecKeychainCreate(TMP_KEYCHAIN_PATH, 8, "password", false, NULL, &keychain),
+              "Create keychain for identity");
+    require(keychain, out);
+    CFArrayAppendValue(newSearchList, keychain);
+    ok_status(SecKeychainSetSearchList(newSearchList),
+              "Set keychain search list");
+
+    /* Load identity and set as signer */
+    ok(p12Data = CFDataCreate(NULL, p12, p12_len),
+       "Create p12 data");
+    ok_status(SecItemImport(p12Data, NULL, &sef, NULL, 0, &keyParams, keychain, &imported_items),
+              "Import identity");
+    is(CFArrayGetCount(imported_items),1,"Imported 1 items");
+    is(CFGetTypeID(CFArrayGetValueAtIndex(imported_items, 0)), SecIdentityGetTypeID(),
+       "Got back an identity");
+    ok(*identity = (SecIdentityRef) CFRetainSafe(CFArrayGetValueAtIndex(imported_items, 0)),
+       "Retrieve identity");
+    ok_status(SecIdentityCopyCertificate(*identity, cert),
+              "Copy certificate");
+
+    CFReleaseNull(p12Data);
+    CFReleaseNull(imported_items);
+
+out:
+    return keychain;
+}
+
+#define kNumberCleanupTests 1
+static void cleanup_keychain(SecKeychainRef keychain, SecIdentityRef identity, SecCertificateRef cert) {
+    /* Delete keychain - from the search list and from disk */
+    ok_status(SecKeychainDelete(keychain), "Delete temporary keychain");
+    CFReleaseNull(keychain);
+    CFReleaseNull(cert);
+    CFReleaseNull(identity);
+}
+
+static OSStatus sign_please(SecIdentityRef identity, SECOidTag digestAlgTag, bool withAttrs, uint8_t *expected_output, size_t expected_len) {
+
+    OSStatus status = SECFailure;
+
+    SecCmsMessageRef cmsg = NULL;
+    SecCmsSignedDataRef sigd = NULL;
+    SecCmsContentInfoRef cinfo = NULL;
+    SecCmsSignerInfoRef signerInfo = NULL;
+    SecCmsEncoderRef encoder = NULL;
+    SecArenaPoolRef arena = NULL;
+    CSSM_DATA cms_data = {
+        .Data = NULL,
+        .Length = 0
+    };
+    uint8_t string_to_sign[] = "This message is signed. Ain't it pretty?";
+
+    /* setup the message */
+    require_action_string(cmsg = SecCmsMessageCreate(NULL), out,
+                          status = errSecAllocate, "Failed to create message");
+    require_action_string(sigd = SecCmsSignedDataCreate(cmsg), out,
+                          status = errSecAllocate, "Failed to create signed data");
+    require_action_string(cinfo = SecCmsMessageGetContentInfo(cmsg), out,
+                          status = errSecParam, "Failed to get cms content info");
+    require_noerr_string(status = SecCmsContentInfoSetContentSignedData(cmsg, cinfo, sigd), out,
+                         "Failed to set signed data into content info");
+    require_action_string(cinfo = SecCmsSignedDataGetContentInfo(sigd), out,
+                          status = errSecParam, "Failed to get content info from signed data");
+    require_noerr_string(status = SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, false), out,
+                         "Failed to set signed data content info");
+    require_action_string(signerInfo = SecCmsSignerInfoCreate(cmsg, identity, digestAlgTag), out,
+                          status = errSecAllocate, "Failed to create signer info");
+    require_noerr_string(status = SecCmsSignerInfoIncludeCerts(signerInfo, SecCmsCMCertOnly,
+                                                               certUsageEmailSigner), out,
+                         "Failed to put certs in signer info");
+
+    if(withAttrs) {
+        require_noerr_string(status = SecCmsSignerInfoAddSigningTime(signerInfo, 480000000.0), out,
+                             "Couldn't add an attribute");
+    }
+    require_noerr_string(status = SecCmsSignedDataAddSignerInfo(sigd, signerInfo), out,
+                         "Couldn't add signer info to signed data");
+
+    /* encode now */
+    require_noerr_string(status = SecArenaPoolCreate(1024, &arena), out,
+                         "Failed to create arena");
+    require_noerr_string(status = SecCmsEncoderCreate(cmsg, NULL, NULL, &cms_data, arena, NULL, NULL,
+                                                      NULL, NULL, NULL, NULL, &encoder), out,
+                         "Failed to create encoder");
+    require_noerr_string(status = SecCmsEncoderUpdate(encoder, string_to_sign, sizeof(string_to_sign)), out,
+                         "Failed to add data ");
+    status = SecCmsEncoderFinish(encoder);
+    encoder = NULL; // SecCmsEncoderFinish always frees the encoder but doesn't NULL it.
+    require_noerr_quiet(status, out);
+
+    /* verify the output matches expected results */
+    if (expected_output) {
+        require_action_string(expected_len == cms_data.Length, out,
+                              status = -1, "Output size differs from expected");
+        require_noerr_action_string(memcmp(expected_output, cms_data.Data, expected_len), out,
+                                    status = -1, "Output differs from expected");
+    }
+
+out:
+    if (encoder) {
+        SecCmsEncoderDestroy(encoder);
+    }
+    if (arena) {
+        SecArenaPoolFree(arena, false);
+    }
+    if (cmsg) {
+        SecCmsMessageDestroy(cmsg);
+    }
+    return status;
+
+}
+
+static OSStatus verify_please(SecKeychainRef keychain, uint8_t *data_to_verify, size_t length) {
+    OSStatus status = SECFailure;
+    SecCmsDecoderRef decoder = NULL;
+    SecCmsMessageRef cmsg = NULL;
+    SecCmsContentInfoRef cinfo = NULL;
+    SecCmsSignedDataRef sigd = NULL;
+    SecPolicyRef policy = NULL;
+    SecTrustRef trust = NULL;
+
+    if (!data_to_verify) {
+        return errSecSuccess; // reasons...
+    }
+
+    require_noerr_string(status = SecCmsDecoderCreate(NULL, NULL, NULL, NULL, NULL,
+                                                      NULL, NULL, &decoder), out,
+                         "Failed to create decoder");
+    require_noerr_string(status = SecCmsDecoderUpdate(decoder, data_to_verify, length), out,
+                         "Failed to add data ");
+    status = SecCmsDecoderFinish(decoder, &cmsg);
+    decoder = NULL; // SecCmsDecoderFinish always frees the decoder
+    require_noerr_quiet(status, out);
+
+    require_action_string(cinfo = SecCmsMessageContentLevel(cmsg, 0), out,
+                          status = errSecDecode, "Failed to get content info");
+    require_action_string(SEC_OID_PKCS7_SIGNED_DATA == SecCmsContentInfoGetContentTypeTag(cinfo), out,
+                          status = errSecDecode, "Content type was pkcs7 signed data");
+    require_action_string(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out,
+                          status = errSecDecode, "Failed to get signed data");
+    require_action_string(policy = SecPolicyCreateBasicX509(), out,
+                          status = errSecAllocate, "Failed to create basic policy");
+    status = SecCmsSignedDataVerifySignerInfo(sigd, 0, keychain, policy, &trust);
+
+out:
+    if (decoder) {
+        SecCmsDecoderDestroy(decoder);
+    }
+    if (cmsg) {
+        SecCmsMessageDestroy(cmsg);
+    }
+    CFReleaseNull(policy);
+    CFReleaseNull(trust);
+    return status;
+}
+
+static uint8_t *invalidate_signature(uint8_t *cms_data, size_t length) {
+    if (!cms_data || !length || (length < 10)) {
+        return NULL;
+    }
+    uint8_t *invalid_cms = NULL;
+
+    invalid_cms = malloc(length);
+    if (invalid_cms) {
+        memcpy(invalid_cms, cms_data, length);
+        /* This modifies the signature part of the test cms binaries */
+        invalid_cms[length - 10] = 0x00;
+    }
+
+    return invalid_cms;
+}
+
+static OSStatus invalidate_and_verify(SecKeychainRef kc, uint8_t *cms_data, size_t length) {
+    OSStatus status = SECFailure;
+    uint8_t *invalid_cms_data = NULL;
+
+    if (!cms_data) {
+        return SECFailure; // reasons...
+    }
+
+    require_action_string(invalid_cms_data = invalidate_signature(cms_data, length), out,
+                          status = errSecAllocate, "Unable to allocate buffer for invalid cms data");
+    status = verify_please(kc, invalid_cms_data, length);
+
+out:
+    if (invalid_cms_data) {
+        free(invalid_cms_data);
+    }
+    return status;
+}
+
+/* forward declaration */
+static OSStatus decrypt_please(uint8_t *data_to_decrypt, size_t length);
+
+static OSStatus encrypt_please(SecCertificateRef recipient, SECOidTag encAlg, int keysize) {
+    OSStatus status = SECFailure;
+    SecCmsMessageRef cmsg = NULL;
+    SecCmsEnvelopedDataRef envd = NULL;
+    SecCmsContentInfoRef cinfo = NULL;
+    SecCmsRecipientInfoRef rinfo = NULL;
+    SecArenaPoolRef arena = NULL;
+    SecCmsEncoderRef encoder = NULL;
+    CSSM_DATA cms_data = {
+        .Data = NULL,
+        .Length = 0
+    };
+    const uint8_t data_to_encrypt[] = "This data is encrypted. Is cool, no?";
+
+    /* set up the message */
+    require_action_string(cmsg = SecCmsMessageCreate(NULL), out,
+                          status = errSecAllocate, "Failed to create message");
+    require_action_string(envd = SecCmsEnvelopedDataCreate(cmsg, encAlg, keysize), out,
+                          status = errSecAllocate, "Failed to create enveloped data");
+    require_action_string(cinfo = SecCmsMessageGetContentInfo(cmsg), out,
+                          status = errSecParam, "Failed to get content info from cms message");
+    require_noerr_string(status = SecCmsContentInfoSetContentEnvelopedData(cmsg, cinfo, envd), out,
+                         "Failed to set enveloped data in cms message");
+    require_action_string(cinfo = SecCmsEnvelopedDataGetContentInfo(envd), out,
+                          status = errSecParam, "Failed to get content info from enveloped data");
+    require_noerr_string(status = SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, false), out,
+                         "Failed to set data type in envelope");
+    require_action_string(rinfo = SecCmsRecipientInfoCreate(cmsg, recipient), out,
+                          status = errSecAllocate, "Failed to create recipient info");
+    require_noerr_string(status = SecCmsEnvelopedDataAddRecipient(envd, rinfo), out,
+                         "Failed to add recipient info to envelope");
+
+    /* encode the message */
+    require_noerr_string(status = SecArenaPoolCreate(1024, &arena), out,
+                         "Failed to create arena");
+    require_noerr_string(status = SecCmsEncoderCreate(cmsg, NULL, NULL, &cms_data, arena, NULL, NULL,
+                                                      NULL, NULL, NULL, NULL, &encoder), out,
+                         "Failed to create encoder");
+    require_noerr_string(status = SecCmsEncoderUpdate(encoder, data_to_encrypt, sizeof(data_to_encrypt)), out,
+                         "Failed to update encoder with data");
+    status = SecCmsEncoderFinish(encoder);
+    encoder = NULL; // SecCmsEncoderFinish always frees the encoder but doesn't NULL it.
+    require_noerr_quiet(status, out);
+
+    require_noerr_string(status = decrypt_please(cms_data.Data, cms_data.Length), out,
+                         "Failed to decrypt the data we just encrypted");
+
+out:
+    if (encoder) {
+        SecCmsEncoderDestroy(encoder);
+    }
+    if (arena) {
+        SecArenaPoolFree(arena, false);
+    }
+    if (cmsg) {
+        SecCmsMessageDestroy(cmsg);
+    }
+    return status;
+}
+
+static OSStatus decrypt_please(uint8_t *data_to_decrypt, size_t length) {
+    OSStatus status = SECFailure;
+    SecCmsDecoderRef decoder = NULL;
+    SecCmsMessageRef cmsg = NULL;
+    CSSM_DATA_PTR content = NULL;
+    const uint8_t encrypted_string[] = "This data is encrypted. Is cool, no?";
+
+    require_noerr_string(status = SecCmsDecoderCreate(NULL, NULL, NULL, NULL, NULL,
+                                                      NULL, NULL, &decoder), out,
+                         "Failed to create decoder");
+    require_noerr_string(status = SecCmsDecoderUpdate(decoder, data_to_decrypt, length), out,
+                         "Failed to add data ");
+    status = SecCmsDecoderFinish(decoder, &cmsg);
+    decoder = NULL; // SecCmsDecoderFinish always frees the decoder
+    require_noerr_quiet(status, out);
+    require_action_string(content = SecCmsMessageGetContent(cmsg), out,
+                          status = errSecDecode, "Unable to get message contents");
+
+    /* verify the output matches expected results */
+    require_action_string(sizeof(encrypted_string) == content->Length, out,
+                          status = -1, "Output size differs from expected");
+    require_noerr_action_string(memcmp(encrypted_string, content->Data, content->Length), out,
+                                status = -1, "Output differs from expected");
+
+out:
+    if (cmsg) {
+        SecCmsMessageDestroy(cmsg);
+    }
+    return status;
+}
+
+/* Signing with attributes goes through a different code path than signing without,
+ * so we need to test both. */
+#define kNumberSignTests 10
+static void sign_tests(SecIdentityRef identity, bool isRSA) {
+
+    /* no attributes */
+    is(sign_please(identity, SEC_OID_MD5, false, NULL, 0),
+       SEC_ERROR_INVALID_ALGORITHM, "Signed with MD5. Not cool.");
+    is(sign_please(identity, SEC_OID_SHA1, false, (isRSA) ? rsa_sha1 : NULL,
+                   (isRSA) ? sizeof(rsa_sha1) : 0),
+       errSecSuccess, "Signed with SHA-1");
+    is(sign_please(identity, SEC_OID_SHA256, false, (isRSA) ? rsa_sha256 : NULL,
+                   (isRSA) ? sizeof(rsa_sha256) : 0),
+       errSecSuccess, "Signed with SHA-256");
+    is(sign_please(identity, SEC_OID_SHA384, false, NULL, 0), errSecSuccess, "Signed with SHA-384");
+    is(sign_please(identity, SEC_OID_SHA512, false, NULL, 0), errSecSuccess, "Signed with SHA-512");
+
+    /* with attributes */
+    is(sign_please(identity, SEC_OID_MD5, true, NULL, 0),
+       SEC_ERROR_INVALID_ALGORITHM, "Signed with MD5 and attributes. Not cool.");
+    is(sign_please(identity, SEC_OID_SHA1, true, (isRSA) ? rsa_sha1_attr : NULL,
+                   (isRSA) ? sizeof(rsa_sha1_attr) : 0),
+       errSecSuccess, "Signed with SHA-1 and attributes");
+    is(sign_please(identity, SEC_OID_SHA256, true, (isRSA) ? rsa_sha256_attr : NULL,
+                   (isRSA) ? sizeof(rsa_sha256_attr) : 0),
+       errSecSuccess, "Signed with SHA-256 and attributes");
+    is(sign_please(identity, SEC_OID_SHA384, true, NULL, 0),
+       errSecSuccess, "Signed with SHA-384 and attributes");
+    is(sign_please(identity, SEC_OID_SHA512, true, NULL, 0),
+       errSecSuccess, "Signed with SHA-512 and attributes");
+}
+
+/* Verifying with attributes goes through a different code path than verifying without,
+ * so we need to test both. */
+#define kNumberVerifyTests 12
+static void verify_tests(SecKeychainRef kc, bool isRsa) {
+    /* no attributes */
+    is(verify_please(kc, (isRsa) ? rsa_md5 : ec_md5,
+                     (isRsa) ? sizeof(rsa_md5) : sizeof(ec_md5)),
+       (isRsa) ? errSecSuccess : SECFailure,
+       "Verify MD5, no attributes");
+    is(verify_please(kc, (isRsa) ? rsa_sha1 : ec_sha1,
+                     (isRsa) ? sizeof(rsa_sha1) : sizeof(ec_sha1)),
+       errSecSuccess, "Verify SHA1, no attributes");
+    is(verify_please(kc, (isRsa) ? rsa_sha256 : ec_sha256,
+                     (isRsa) ? sizeof(rsa_sha256) : sizeof(ec_sha256)),
+       errSecSuccess, "Verify SHA256, no attributes");
+
+    /* with attributes */
+    is(verify_please(kc, (isRsa) ? rsa_md5_attr : NULL,
+                     (isRsa) ? sizeof(rsa_md5_attr) : 0),
+       errSecSuccess, "Verify MD5, with attributes");
+    is(verify_please(kc, (isRsa) ? rsa_sha1_attr : ec_sha1_attr,
+                     (isRsa) ? sizeof(rsa_sha1_attr) : sizeof(ec_sha1_attr)),
+       errSecSuccess, "Verify SHA1, with attributes");
+    is(verify_please(kc, (isRsa) ? rsa_sha256_attr : ec_sha256_attr,
+                     (isRsa) ? sizeof(rsa_sha256_attr) : sizeof(ec_sha256_attr)),
+       errSecSuccess, "Verify SHA256, with attributes");
+
+    /***** Once more, with validation errors *****/
+
+    /* no attributes */
+    is(invalidate_and_verify(kc, (isRsa) ? rsa_md5 : ec_md5,
+                     (isRsa) ? sizeof(rsa_md5) : sizeof(ec_md5)),
+       SECFailure, "Verify invalid MD5, no attributes");
+    is(invalidate_and_verify(kc, (isRsa) ? rsa_sha1 : ec_sha1,
+                     (isRsa) ? sizeof(rsa_sha1) : sizeof(ec_sha1)),
+       SECFailure, "Verify invalid SHA1, no attributes");
+    is(invalidate_and_verify(kc, (isRsa) ? rsa_sha256 : ec_sha256,
+                     (isRsa) ? sizeof(rsa_sha256) : sizeof(ec_sha256)),
+       SECFailure, "Verify invalid SHA256, no attributes");
+
+    /* with attributes */
+    is(invalidate_and_verify(kc, (isRsa) ? rsa_md5_attr : NULL,
+                     (isRsa) ? sizeof(rsa_md5_attr) : 0),
+       SECFailure, "Verify invalid MD5, with attributes");
+    is(invalidate_and_verify(kc, (isRsa) ? rsa_sha1_attr : ec_sha1_attr,
+                     (isRsa) ? sizeof(rsa_sha1_attr) : sizeof(ec_sha1_attr)),
+       SECFailure, "Verify invalid SHA1, with attributes");
+    is(invalidate_and_verify(kc, (isRsa) ? rsa_sha256_attr : ec_sha256_attr,
+                     (isRsa) ? sizeof(rsa_sha256_attr) : sizeof(ec_sha256_attr)),
+       SECFailure, "Verify invalid SHA256, with attributes");
+}
+
+#define kNumberEncryptTests 5
+static void encrypt_tests(SecCertificateRef certificate) {
+    is(encrypt_please(certificate, SEC_OID_DES_EDE3_CBC, 192),
+       errSecSuccess, "Encrypt with 3DES");
+    is(encrypt_please(certificate, SEC_OID_RC2_CBC, 128),
+       errSecSuccess, "Encrypt with 128-bit RC2");
+    is(encrypt_please(certificate, SEC_OID_AES_128_CBC, 128),
+       errSecSuccess, "Encrypt with 128-bit AES");
+    is(encrypt_please(certificate, SEC_OID_AES_192_CBC, 192),
+       errSecSuccess, "Encrypt with 192-bit AES");
+    is(encrypt_please(certificate, SEC_OID_AES_256_CBC, 256),
+       errSecSuccess, "Encrypt with 256-bit AES");
+}
+
+#define kNumberDecryptTests 5
+static void decrypt_tests(bool isRsa) {
+    is(decrypt_please((isRsa) ? rsa_3DES : ec_3DES,
+                      (isRsa) ? sizeof(rsa_3DES) : sizeof(ec_3DES)),
+       errSecSuccess, "Decrypt 3DES");
+    is(decrypt_please((isRsa) ? rsa_RC2 : ec_RC2,
+                      (isRsa) ? sizeof(rsa_RC2) : sizeof(ec_RC2)),
+       errSecSuccess, "Decrypt 128-bit RC2");
+    is(decrypt_please((isRsa) ? rsa_AES_128 : ec_AES_128,
+                      (isRsa) ? sizeof(rsa_AES_128) : sizeof(ec_AES_128)),
+       errSecSuccess, "Decrypt 128-bit AES");
+    is(decrypt_please((isRsa) ? rsa_AES_192 : ec_AES_192,
+                      (isRsa) ? sizeof(rsa_AES_192) : sizeof(ec_AES_192)),
+       errSecSuccess, "Decrypt 192-bit AES");
+    is(decrypt_please((isRsa) ? rsa_AES_256 : ec_AES_256,
+                      (isRsa) ? sizeof(rsa_AES_256) : sizeof(ec_AES_256)),
+       errSecSuccess, "Decrypt 256-bit AES");
+}
+
+int cms_01_basic(int argc, char *const *argv)
+{
+    plan_tests(2*(kNumberSetupTests + kNumberSignTests + kNumberVerifyTests +
+                  kNumberEncryptTests + kNumberDecryptTests + kNumberCleanupTests));
+
+    SecKeychainRef kc = NULL;
+    SecIdentityRef identity = NULL;
+    SecCertificateRef certificate = NULL;
+
+    /* RSA tests */
+    kc = setup_keychain(_rsa_identity, sizeof(_rsa_identity), &identity, &certificate);
+    sign_tests(identity, true);
+    verify_tests(kc, true);
+    encrypt_tests(certificate);
+    decrypt_tests(true);
+    cleanup_keychain(kc, identity, certificate);
+
+    /* EC tests */
+    kc = setup_keychain(_ec_identity, sizeof(_ec_identity), &identity, &certificate);
+    sign_tests(identity, false);
+    verify_tests(kc, false);
+    encrypt_tests(certificate);
+    decrypt_tests(false);
+    cleanup_keychain(kc, identity, certificate);
+
+    return 0;
+}
\ No newline at end of file