]> git.saurik.com Git - apple/security.git/blobdiff - OSX/sec/Security/Regressions/secitem/si-40-seckey.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / sec / Security / Regressions / secitem / si-40-seckey.c
index 1644000cc42168da031f618c9f41e274cba8b08a..9213b94183b6d594c89fc39a3b74dc1c7af77e40 100644 (file)
 #include <Security/SecureTransport.h>
 #include <Security/SecRandom.h>
 #include <utilities/array_size.h>
+#include <utilities/SecCFWrappers.h>
 #include <CommonCrypto/CommonDigest.h>
 #include <libDER/libDER.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <corecrypto/ccsha1.h>
+#include <corecrypto/ccsha2.h>
 
 #include "Security_regressions.h"
 
@@ -71,10 +74,11 @@ static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecA
         ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
             sig, sigLen), "digest and verify");
         /* Invalidate the signature. */
-        sig[0] ^= 0xff;
+        /* Tweak the least-significant bit to avoid putting the signature out of range. */
+        sig[sigLen-1] ^= 1;
         is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
             sig, sigLen), errSSLCrypto, "digest and verify bad sig");
-        sig[0] ^= 0xff;
+        sig[sigLen-1] ^= 1;
         dataToDigest[0] ^= 0xff;
         is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
             sig, sigLen), errSSLCrypto, "digest and verify bad digest");
@@ -122,7 +126,7 @@ static void dump_bytes(uint8_t* bytes, size_t amount)
 }
 #endif
 
-#define kEncryptDecryptTestCount 5
+#define kEncryptDecryptTestCount 6
 static void test_encrypt_decrypt(SecKeyRef pubKey, SecKeyRef privKey, uint32_t padding, size_t keySizeInBytes)
 {
     SKIP: {
@@ -134,13 +138,13 @@ static void test_encrypt_decrypt(SecKeyRef pubKey, SecKeyRef privKey, uint32_t p
             default: skip("what is the max_len for this padding?", 5, false);
         }
 
-        uint8_t secret[max_len + 1], encrypted_secret[keySizeInBytes], decrypted_secret[keySizeInBytes];
+        uint8_t secret[max_len + 2], encrypted_secret[keySizeInBytes], decrypted_secret[keySizeInBytes];
         uint8_t *secret_ptr = secret;
         size_t secret_len = max_len;
         size_t encrypted_secret_len = sizeof(encrypted_secret);
         size_t decrypted_secret_len = sizeof(decrypted_secret);
         memset(decrypted_secret, 0xff, decrypted_secret_len);
-        SecRandomCopyBytes(kSecRandomDefault, sizeof(secret), secret);
+        ok_status(SecRandomCopyBytes(kSecRandomDefault, sizeof(secret), secret),"rng");
 
         // zero pad, no accidental second zero byte
         if (padding == kSecPaddingNone) {
@@ -170,7 +174,7 @@ static void test_encrypt_decrypt(SecKeyRef pubKey, SecKeyRef privKey, uint32_t p
     }
 }
 
-#define kKeyGenTestCount (49 + (3*kEncryptDecryptTestCount))
+#define kKeyGenTestCount (50 + (3*kEncryptDecryptTestCount))
 static void testkeygen(size_t keySizeInBits) {
        SecKeyRef pubKey = NULL, privKey = NULL;
        size_t keySizeInBytes = (keySizeInBits + 7) / 8;
@@ -199,109 +203,111 @@ static void testkeygen(size_t keySizeInBits) {
                /* Sign something. */
                uint8_t something[keySizeInBytes];
         size_t something_len = keySizeInBytes - 11;
-        SecRandomCopyBytes(kSecRandomDefault, sizeof(something), something);
+        ok_status(SecRandomCopyBytes(kSecRandomDefault, sizeof(something), something),"rng");
                uint8_t sig[keySizeInBytes];
                size_t sigLen = sizeof(sig);
-               is_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
-                                something, something_len + 1, sig, &sigLen),
-                                errSecParam, "sign overflow");
-               ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
-                       something, something_len, sig, &sigLen), "sign something");
-               ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1,
-                       something, something_len, sig, sigLen), "verify sig on something");
-
-        // Torture test ASN.1 encoder by setting high bit to 1.
-        uint8_t digest[CC_SHA512_DIGEST_LENGTH] = {
-            0x80, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-        };
-        //CC_MD2(something, sizeof(something), digest);
-               ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD2,
-                       digest, CC_MD2_DIGEST_LENGTH, sig, &sigLen),
-            "don't sign md2 digest");
-               ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD2,
-                       digest, CC_MD2_DIGEST_LENGTH, sig, sigLen),
-            "verify sig on md2 digest fails");
-
-        //CC_MD5(something, sizeof(something), digest);
-               sigLen = sizeof(sig);
-               ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD5,
-                       digest, CC_MD5_DIGEST_LENGTH, sig, &sigLen),
-            "don't sign md5 digest");
-               ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD5,
-                       digest, CC_MD5_DIGEST_LENGTH, sig, sigLen),
-            "verify sig on md5 digest fails");
-
-        //CCDigest(kCCDigestSHA1, something, sizeof(something), digest);
-               sigLen = sizeof(sig);
-               ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA1,
-                       digest, CC_SHA1_DIGEST_LENGTH, sig, &sigLen),
-            "sign sha1 digest");
-               ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA1,
-                       digest, CC_SHA1_DIGEST_LENGTH, sig, sigLen),
-            "verify sig on sha1 digest");
-
-               uint8_t signature[keySizeInBytes], *ptr = signature;
-               size_t signature_len = sizeof(signature);
-               ok_status(SecKeyDecrypt(pubKey, kSecPaddingNone, sig, sigLen, signature, &signature_len), "inspect signature");
-               is(signature_len, keySizeInBytes - 1, "got signature");
-               while(*ptr && ((size_t)(ptr - signature) < signature_len)) ptr++;
-               is(signature + signature_len - ptr, 16 /* length(\0 || OID_SHA1) */ + CC_SHA1_DIGEST_LENGTH, "successful decode");
-
-        /* PKCS1 padding is 00 01 PAD * 8 or more 00 data.
-           data is SEQ { SEQ { OID NULL } BIT STRING 00 DIGEST }
-           So min data + pad overhead is 11 + 9 + oidlen
-           oidlen = 11 for the sha2 family of oids, so we have 29 bytes; or
-           232 bits of minimum overhead.  */
-        const size_t pkcs1Overhead = 232;
-        if (keySizeInBits > 224 + pkcs1Overhead) {
-            //CC_SHA224(something, sizeof(something), digest);
+        if (privKey != NULL && pubKey != NULL) {
+            is_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
+                                    something, something_len + 1, sig, &sigLen),
+                      errSecParam, "sign overflow");
+            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1,
+                                    something, something_len, sig, &sigLen), "sign something");
+            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1,
+                                      something, something_len, sig, sigLen), "verify sig on something");
+
+            // Torture test ASN.1 encoder by setting high bit to 1.
+            uint8_t digest[CC_SHA512_DIGEST_LENGTH] = {
+                0x80, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+            };
+            //CC_MD2(something, sizeof(something), digest);
+            ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD2,
+                                     digest, CC_MD2_DIGEST_LENGTH, sig, &sigLen),
+                      "don't sign md2 digest");
+            ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD2,
+                                       digest, CC_MD2_DIGEST_LENGTH, sig, sigLen),
+                      "verify sig on md2 digest fails");
+
+            //CC_MD5(something, sizeof(something), digest);
             sigLen = sizeof(sig);
-            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA224,
-                                    digest, CC_SHA224_DIGEST_LENGTH, sig, &sigLen),
-                      "sign sha224 digest");
-            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA224,
-                                      digest, CC_SHA224_DIGEST_LENGTH, sig, sigLen),
-                      "verify sig on sha224 digest");
-        }
-
-        if (keySizeInBits > 256 + pkcs1Overhead) {
-            //CC_SHA256(something, sizeof(something), digest);
-            sigLen = sizeof(sig);
-            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA256,
-                                    digest, CC_SHA256_DIGEST_LENGTH, sig, &sigLen),
-                      "sign sha256 digest");
-            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA256,
-                                      digest, CC_SHA256_DIGEST_LENGTH, sig, sigLen),
-                      "verify sig on sha256 digest");
-        }
-
-        if (keySizeInBits > 384 + pkcs1Overhead) {
-            //CC_SHA384(something, sizeof(something), digest);
-            sigLen = sizeof(sig);
-            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA384,
-                                    digest, CC_SHA384_DIGEST_LENGTH, sig, &sigLen),
-                      "sign sha384 digest");
-            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA384,
-                                      digest, CC_SHA384_DIGEST_LENGTH, sig, sigLen),
-                      "verify sig on sha384 digest");
-        }
-
-        if (keySizeInBits > 512 + pkcs1Overhead) {
-            //CC_SHA512(something, sizeof(something), digest);
+            ok_status(!SecKeyRawSign(privKey, kSecPaddingPKCS1MD5,
+                                     digest, CC_MD5_DIGEST_LENGTH, sig, &sigLen),
+                      "don't sign md5 digest");
+            ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1MD5,
+                                       digest, CC_MD5_DIGEST_LENGTH, sig, sigLen),
+                      "verify sig on md5 digest fails");
+
+            //CCDigest(kCCDigestSHA1, something, sizeof(something), digest);
             sigLen = sizeof(sig);
-            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA512,
-                                    digest, CC_SHA512_DIGEST_LENGTH, sig, &sigLen),
-                      "sign sha512 digest");
-            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA512,
-                                      digest, CC_SHA512_DIGEST_LENGTH, sig, sigLen),
-                      "verify sig on sha512 digest");
+            ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA1,
+                                    digest, CC_SHA1_DIGEST_LENGTH, sig, &sigLen),
+                      "sign sha1 digest");
+            ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA1,
+                                      digest, CC_SHA1_DIGEST_LENGTH, sig, sigLen),
+                      "verify sig on sha1 digest");
+
+            uint8_t signature[keySizeInBytes], *ptr = signature;
+            size_t signature_len = sizeof(signature);
+            ok_status(SecKeyDecrypt(pubKey, kSecPaddingNone, sig, sigLen, signature, &signature_len), "inspect signature");
+            is(signature_len, keySizeInBytes - 1, "got signature");
+            while(*ptr && ((size_t)(ptr - signature) < signature_len)) ptr++;
+            is(signature + signature_len - ptr, 16 /* length(\0 || OID_SHA1) */ + CC_SHA1_DIGEST_LENGTH, "successful decode");
+
+            /* PKCS1 padding is 00 01 PAD * 8 or more 00 data.
+             data is SEQ { SEQ { OID NULL } BIT STRING 00 DIGEST }
+             So min data + pad overhead is 11 + 9 + oidlen
+             oidlen = 11 for the sha2 family of oids, so we have 29 bytes; or
+             232 bits of minimum overhead.  */
+            const size_t pkcs1Overhead = 232;
+            if (keySizeInBits > 224 + pkcs1Overhead) {
+                //CC_SHA224(something, sizeof(something), digest);
+                sigLen = sizeof(sig);
+                ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA224,
+                                        digest, CC_SHA224_DIGEST_LENGTH, sig, &sigLen),
+                          "sign sha224 digest");
+                ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA224,
+                                          digest, CC_SHA224_DIGEST_LENGTH, sig, sigLen),
+                          "verify sig on sha224 digest");
+            }
+
+            if (keySizeInBits > 256 + pkcs1Overhead) {
+                //CC_SHA256(something, sizeof(something), digest);
+                sigLen = sizeof(sig);
+                ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA256,
+                                        digest, CC_SHA256_DIGEST_LENGTH, sig, &sigLen),
+                          "sign sha256 digest");
+                ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA256,
+                                          digest, CC_SHA256_DIGEST_LENGTH, sig, sigLen),
+                          "verify sig on sha256 digest");
+            }
+
+            if (keySizeInBits > 384 + pkcs1Overhead) {
+                //CC_SHA384(something, sizeof(something), digest);
+                sigLen = sizeof(sig);
+                ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA384,
+                                        digest, CC_SHA384_DIGEST_LENGTH, sig, &sigLen),
+                          "sign sha384 digest");
+                ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA384,
+                                          digest, CC_SHA384_DIGEST_LENGTH, sig, sigLen),
+                          "verify sig on sha384 digest");
+            }
+
+            if (keySizeInBits > 512 + pkcs1Overhead) {
+                //CC_SHA512(something, sizeof(something), digest);
+                sigLen = sizeof(sig);
+                ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1SHA512,
+                                        digest, CC_SHA512_DIGEST_LENGTH, sig, &sigLen),
+                          "sign sha512 digest");
+                ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1SHA512,
+                                          digest, CC_SHA512_DIGEST_LENGTH, sig, sigLen),
+                          "verify sig on sha512 digest");
+            }
         }
 
         test_encrypt_decrypt(pubKey, privKey, kSecPaddingNone, keySizeInBytes);
@@ -343,7 +349,7 @@ static void testkeygen(size_t keySizeInBits) {
 #define kKeyGen2TestCount 12
 static void testkeygen2(size_t keySizeInBits) {
        SecKeyRef pubKey = NULL, privKey = NULL;
-       size_t keySizeInBytes = (keySizeInBits + 7) / 8;
+    int32_t keySizeInBytes = (int32_t)((keySizeInBits + 7) / 8);
        CFNumberRef kzib;
 
     CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault);
@@ -373,8 +379,8 @@ static void testkeygen2(size_t keySizeInBits) {
 
        OSStatus status;
        ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
-              "Generate %ld bit (%ld byte) persistent RSA keypair",
-              keySizeInBits, keySizeInBytes);
+              "Generate %d bit (%d byte) persistent RSA keypair",
+              (int)keySizeInBits, (int)keySizeInBytes);
        CFRelease(kzib);
        CFRelease(kgp);
 
@@ -431,8 +437,543 @@ static void testkeygen2(size_t keySizeInBits) {
        CFRelease(privd);
 }
 
+static const int kTestSupportedCount = 3 + (4 * 11) + 2 + (4 * 5);
+static void testsupportedalgos(size_t keySizeInBits)
+{
+    SecKeyRef pubKey = NULL, privKey = NULL;
+    int32_t keySizeInBytes = (int)((keySizeInBits + 7) / 8);
+    CFNumberRef kzib;
+
+    int32_t iKeySizeInBits = (int32_t) keySizeInBits;
+    kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &iKeySizeInBits);
+    CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
+    CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeRSA);
+    CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
+
+    OSStatus status;
+    ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
+              "Generate %d bit (%d byte) persistent RSA keypair",
+              (int)keySizeInBits, (int)keySizeInBytes);
+    CFRelease(kzib);
+    CFRelease(kgp);
+
+    is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
+    is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
+
+    const SecKeyAlgorithm sign[] = {
+        kSecKeyAlgorithmRSASignatureRaw,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512,
+    };
+
+    for (size_t i = 0; i < array_size(sign); i++) {
+        ok(SecKeyIsAlgorithmSupported(privKey, kSecKeyOperationTypeSign, sign[i]),
+           "privKey supports sign algorithm %@", sign[i]);
+        ok(SecKeyIsAlgorithmSupported(pubKey, kSecKeyOperationTypeVerify, sign[i]),
+           "pubKey supports verify algorithm %@", sign[i]);
+        // Our privKey actually supports even verify operation because it is adapter over decrypt...
+        ok(SecKeyIsAlgorithmSupported(privKey, kSecKeyOperationTypeVerify, sign[i]),
+           "privKey supports verify algorithm %@", sign[i]);
+        ok(!SecKeyIsAlgorithmSupported(pubKey, kSecKeyOperationTypeSign, sign[i]),
+           "pubKey doesn't support verify algorithm %@", sign[i]);
+    }
+    ok(!SecKeyIsAlgorithmSupported(privKey, kSecKeyOperationTypeSign, kSecKeyAlgorithmECDSASignatureDigestX962),
+       "RSA privKey does not support ECDSA algorithm");
+    ok(!SecKeyIsAlgorithmSupported(privKey, kSecKeyOperationTypeVerify, kSecKeyAlgorithmECDSASignatureDigestX962),
+       "RSA pubKey does not support ECDSA algorithm");
+
+    const SecKeyAlgorithm crypt[] = {
+        kSecKeyAlgorithmRSAEncryptionRaw,
+        kSecKeyAlgorithmRSAEncryptionPKCS1,
+        kSecKeyAlgorithmRSAEncryptionOAEPSHA1,
+        kSecKeyAlgorithmRSAEncryptionOAEPSHA224,
+        kSecKeyAlgorithmRSAEncryptionOAEPSHA256,
+//        kSecKeyAlgorithmRSAEncryptionOAEPSHA384,
+//        kSecKeyAlgorithmRSAEncryptionOAEPSHA512,
+    };
+    for (size_t i = 0; i < array_size(crypt); i++) {
+        ok(SecKeyIsAlgorithmSupported(privKey, kSecKeyOperationTypeDecrypt, crypt[i]),
+           "privKey supports decrypt algorithm %@", crypt[i]);
+        ok(SecKeyIsAlgorithmSupported(pubKey, kSecKeyOperationTypeEncrypt, crypt[i]),
+           "pubKey supports encrypt algorithm %@", crypt[i]);
+        ok(!SecKeyIsAlgorithmSupported(privKey, kSecKeyOperationTypeEncrypt, crypt[i]),
+           "privKey doesn't supports encrypt algorithm %@", crypt[i]);
+        ok(SecKeyIsAlgorithmSupported(pubKey, kSecKeyOperationTypeDecrypt, crypt[i]),
+           "pubKey supports decrypt algorithm %@", crypt[i]);
+    }
+
+    /* Cleanup. */
+    CFReleaseNull(pubKey);
+    CFReleaseNull(privKey);
+}
+
+#define kCreateWithDataTestCount 13
+static void testcreatewithdata(unsigned long keySizeInBits)
+{
+    size_t keySizeInBytes = (keySizeInBits + 7) / 8;
+    int32_t keysz32 = (int32_t)keySizeInBits;
+
+    CFNumberRef kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
+    CFDictionaryRef kgp = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+                                                       kSecAttrKeyType, kSecAttrKeyTypeRSA,
+                                                       kSecAttrKeySizeInBits, kzib,
+                                                       kSecAttrIsPermanent, kCFBooleanFalse,
+                                                       NULL);
+    SecKeyRef pubKey = NULL, privKey = NULL;
+    OSStatus status;
+    ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
+              "Generate %ld bit (%ld byte) RSA keypair (status = %d)",
+              keySizeInBits, keySizeInBytes, (int)status);
+    CFReleaseNull(kgp);
+
+    CFMutableDictionaryRef kcwd = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault,
+                                                                          kSecAttrKeyType, kSecAttrKeyTypeRSA,
+                                                                          kSecAttrKeySizeInBits, kzib,
+                                                                          kSecAttrIsPermanent, kCFBooleanFalse,
+                                                                          NULL);
+    CFReleaseNull(kzib);
+
+    CFErrorRef error = NULL;
+    CFDataRef privExternalData = NULL, pubExternalData = NULL;
+    SecKeyRef dataKey = NULL;
+
+    { // privKey
+        privExternalData = SecKeyCopyExternalRepresentation(privKey, &error);
+        ok(privExternalData && CFGetTypeID(privExternalData) == CFDataGetTypeID(),
+           "priv key SecKeyCopyExternalRepresentation failed");
+        CFReleaseNull(error);
+
+        SKIP: {
+            skip("invalid priv key external data", 4, privExternalData);
+
+            CFDictionarySetValue(kcwd, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
+            dataKey = SecKeyCreateWithData(privExternalData, kcwd, &error);
+            ok(dataKey, "priv key SecKeyCreateWithData failed");
+            CFReleaseNull(error);
+
+            eq_cf(privKey, dataKey, "priv keys differ");
+            CFReleaseNull(dataKey);
+
+            CFDictionarySetValue(kcwd, kSecAttrKeyClass, kSecAttrKeyClassPublic);
+            dataKey = SecKeyCreateWithData(privExternalData, kcwd, &error);
+            ok(!dataKey, "priv key SecKeyCreateWithData succeeded with invalid kSecAttrKeyClass");
+            CFReleaseNull(error);
+            CFReleaseNull(dataKey);
+
+            CFMutableDataRef modifiedExternalData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+            CFDataAppend(modifiedExternalData, privExternalData);
+            *CFDataGetMutableBytePtr(modifiedExternalData) ^= 0xff;
+
+            CFDictionarySetValue(kcwd, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
+            dataKey = SecKeyCreateWithData(modifiedExternalData, kcwd, &error);
+            ok(!dataKey, "priv key SecKeyCreateWithData succeeded with invalid external data");
+            CFReleaseNull(error);
+            CFReleaseNull(dataKey);
+
+            CFReleaseNull(modifiedExternalData);
+        }
+    }
+
+    { // pubKey
+        pubExternalData = SecKeyCopyExternalRepresentation(pubKey, &error);
+        ok(pubExternalData && CFGetTypeID(pubExternalData) == CFDataGetTypeID(),
+           "pub key SecKeyCopyExternalRepresentation failed");
+        CFReleaseNull(error);
+
+        SKIP: {
+            skip("invalid pub key external data", 4, pubExternalData);
+
+            CFDictionarySetValue(kcwd, kSecAttrKeyClass, kSecAttrKeyClassPublic);
+            dataKey = SecKeyCreateWithData(pubExternalData, kcwd, &error);
+            ok(dataKey, "pub key SecKeyCreateWithData failed");
+            CFReleaseNull(error);
+
+            eq_cf(pubKey, dataKey, "pub keys differ");
+            CFReleaseNull(dataKey);
+
+            CFDictionarySetValue(kcwd, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
+            dataKey = SecKeyCreateWithData(pubExternalData, kcwd, &error);
+            ok(!dataKey, "pub key SecKeyCreateWithData succeeded with invalid kSecAttrKeyClass");
+            CFReleaseNull(error);
+            CFReleaseNull(dataKey);
+
+            CFMutableDataRef modifiedExternalData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+            CFDataAppend(modifiedExternalData, pubExternalData);
+            *CFDataGetMutableBytePtr(modifiedExternalData) ^= 0xff;
+
+            CFDictionarySetValue(kcwd, kSecAttrKeyClass, kSecAttrKeyClassPublic);
+            dataKey = SecKeyCreateWithData(modifiedExternalData, kcwd, &error);
+            ok(!dataKey, "pub key SecKeyCreateWithData succeeded with invalid external data");
+            CFReleaseNull(error);
+            CFReleaseNull(dataKey);
+
+            CFReleaseNull(modifiedExternalData);
+        }
+    }
+
+    SKIP: {
+        skip("invalid pub key external data", 1, pubExternalData);
+
+        CFDictionarySetValue(kcwd, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
+        dataKey = SecKeyCreateWithData(pubExternalData, kcwd, &error);
+        ok(!dataKey, "priv key SecKeyCreateWithData succeeded with public external data");
+        CFReleaseNull(error);
+        CFReleaseNull(dataKey);
+
+        CFReleaseNull(pubExternalData);
+    }
+
+    SKIP: {
+        skip("invalid priv key external data", 1, privExternalData);
+
+        CFDictionarySetValue(kcwd, kSecAttrKeyClass, kSecAttrKeyClassPublic);
+        dataKey = SecKeyCreateWithData(privExternalData, kcwd, &error);
+        ok(!dataKey, "pub key SecKeyCreateWithData succeeded with private external data");
+        CFReleaseNull(error);
+        CFReleaseNull(dataKey);
+
+        CFReleaseNull(privExternalData);
+    }
+
+    CFReleaseNull(kcwd);
+    CFReleaseNull(pubKey);
+    CFReleaseNull(privKey);
+}
+
+#define kCopyAttributesTestCount 20
+static void testcopyattributes(unsigned long keySizeInBits)
+{
+    size_t keySizeInBytes = (keySizeInBits + 7) / 8;
+    int32_t keysz32 = (int32_t)keySizeInBits;
+
+    CFNumberRef kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
+    CFDictionaryRef kgp = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+                                                       kSecAttrKeyType, kSecAttrKeyTypeRSA,
+                                                       kSecAttrKeySizeInBits, kzib,
+                                                       kSecAttrIsPermanent, kCFBooleanFalse,
+                                                       NULL);
+    SecKeyRef pubKey = NULL, privKey = NULL;
+    OSStatus status;
+    ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
+              "Generate %ld bit (%ld byte) RSA keypair (status = %d)",
+              keySizeInBits, keySizeInBytes, (int)status);
+    CFReleaseNull(kgp);
+
+    CFDictionaryRef attributes;
+    CFTypeRef attrValue = NULL, privAppLabel = NULL, pubAppLabel = NULL;
+
+    { // privKey
+        attributes = SecKeyCopyAttributes(privKey);
+        ok(attributes && CFGetTypeID(attributes) == CFDictionaryGetTypeID(),
+           "priv key SecKeyCopyAttributes failed");
+
+        SKIP: {
+            skip("invalid attributes", 8, attributes);
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanEncrypt);
+            eq_cf(attrValue, kCFBooleanFalse, "invalid priv key kSecAttrCanEncrypt");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanDecrypt);
+            eq_cf(attrValue, kCFBooleanTrue, "invalid priv key kSecAttrCanDecrypt");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanDerive);
+            eq_cf(attrValue, kCFBooleanFalse, "invalid priv key kSecAttrCanDerive");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanSign);
+            eq_cf(attrValue, kCFBooleanTrue, "invalid priv key kSecAttrCanSign");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanVerify);
+            eq_cf(attrValue, kCFBooleanFalse, "invalid priv key kSecAttrCanVerify");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrKeyClass);
+            eq_cf(attrValue, kSecAttrKeyClassPrivate, "priv key invalid kSecAttrKeyClass");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrKeyType);
+            eq_cf(attrValue, kSecAttrKeyTypeRSA, "invalid priv key kSecAttrKeyType");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrKeySizeInBits);
+            eq_cf(attrValue, kzib, "invalid priv key kSecAttrKeySizeInBits");
+
+            privAppLabel = CFDictionaryGetValue(attributes, kSecAttrApplicationLabel);
+            CFRetainSafe(privAppLabel);
+
+            CFReleaseNull(attributes);
+        }
+    }
+
+    { // pubKey
+        attributes = SecKeyCopyAttributes(pubKey);
+        ok(attributes && CFGetTypeID(attributes) == CFDictionaryGetTypeID(),
+           "pub key SecKeyCopyAttributes failed");
+
+        SKIP: {
+            skip("invalid attributes", 8, attributes);
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanEncrypt);
+            eq_cf(attrValue, kCFBooleanTrue, "pub key invalid kSecAttrCanEncrypt");
+
+            // Although unusual, our RSA public key can even decrypt.
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanDecrypt);
+            eq_cf(attrValue, kCFBooleanTrue, "pub key invalid kSecAttrCanDecrypt");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanDerive);
+            eq_cf(attrValue, kCFBooleanFalse, "pub key invalid kSecAttrCanDerive");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanSign);
+            eq_cf(attrValue, kCFBooleanFalse, "pub key invalid kSecAttrCanSign");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrCanVerify);
+            eq_cf(attrValue, kCFBooleanTrue, "pub key invalid kSecAttrCanVerify");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrKeyClass);
+            eq_cf(attrValue, kSecAttrKeyClassPublic, "pub key invalid kSecAttrKeyClass");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrKeyType);
+            eq_cf(attrValue, kSecAttrKeyTypeRSA, "pub key invalid kSecAttrKeyType");
+
+            attrValue = CFDictionaryGetValue(attributes, kSecAttrKeySizeInBits);
+            eq_cf(attrValue, kzib, "pub key invalid kSecAttrKeySizeInBits");
+
+            pubAppLabel = CFDictionaryGetValue(attributes, kSecAttrApplicationLabel);
+            CFRetainSafe(pubAppLabel);
+
+            CFReleaseNull(attributes);
+        }
+    }
+
+    eq_cf(privAppLabel, pubAppLabel, "priv key and pub key kSecAttrApplicationLabel differ");
+
+    CFReleaseNull(privAppLabel);
+    CFReleaseNull(pubAppLabel);
+    CFReleaseNull(kzib);
+    CFReleaseNull(pubKey);
+    CFReleaseNull(privKey);
+}
+
+#define kCopyPublicKeyTestCount 5
+static void testcopypublickey(unsigned long keySizeInBits)
+{
+    size_t keySizeInBytes = (keySizeInBits + 7) / 8;
+    int32_t keysz32 = (int32_t)keySizeInBits;
+
+    CFNumberRef kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
+    CFDictionaryRef kgp = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+                                                       kSecAttrKeyType, kSecAttrKeyTypeRSA,
+                                                       kSecAttrKeySizeInBits, kzib,
+                                                       kSecAttrIsPermanent, kCFBooleanFalse,
+                                                       NULL);
+    CFReleaseNull(kzib);
+
+    SecKeyRef pubKey = NULL, privKey = NULL;
+    OSStatus status;
+    ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
+              "Generate %ld bit (%ld byte) RSA keypair (status = %d)",
+              keySizeInBits, keySizeInBytes, (int)status);
+    CFReleaseNull(kgp);
+
+    SecKeyRef pubKeyCopy = NULL;
+
+    { // privKey
+        pubKeyCopy = SecKeyCopyPublicKey(privKey);
+        ok(pubKeyCopy, "priv key SecKeyCopyPublicKey failed");
+        eq_cf(pubKeyCopy, pubKey, "pub key from priv key SecKeyCopyPublicKey and pub key differ");
+        CFReleaseNull(pubKeyCopy);
+    }
+
+    { // pubKey
+        pubKeyCopy = SecKeyCopyPublicKey(pubKey);
+        ok(pubKeyCopy, "pub key SecKeyCopyPublicKey failed");
+        eq_cf(pubKeyCopy, pubKey, "pub key from pub key SecKeyCopyPublicKey and pub key differ");
+        CFReleaseNull(pubKeyCopy);
+    }
+
+    CFReleaseNull(pubKey);
+    CFReleaseNull(privKey);
+}
+
+#define kSignAndVerifyTestCount 84
+static void testsignverify(unsigned long keySizeInBits)
+{
+    size_t keySizeInBytes = (keySizeInBits + 7) / 8;
+    int32_t keysz32 = (int32_t)keySizeInBits;
+
+    CFNumberRef kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
+    CFDictionaryRef kgp = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+                                                       kSecAttrKeyType, kSecAttrKeyTypeRSA,
+                                                       kSecAttrKeySizeInBits, kzib,
+                                                       kSecAttrIsPermanent, kCFBooleanFalse,
+                                                       NULL);
+    CFReleaseNull(kzib);
+
+    SecKeyRef pubKey = NULL, privKey = NULL;
+    OSStatus status;
+    ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
+              "Generate %ld bit (%ld byte) RSA keypair (status = %d)",
+              keySizeInBits, keySizeInBytes, (int)status);
+    CFReleaseNull(kgp);
+
+    SecKeyAlgorithm algorithms[] = {
+        kSecKeyAlgorithmRSASignatureRaw,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384,
+        kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384,
+        kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512,
+    };
+
+    CFDataRef testData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("test"), kCFStringEncodingUTF8, 0);
+    ok(testData, "creating test data failed");
+
+    SKIP: {
+        skip("invalid test data", 71, testData);
+
+        CFErrorRef error = NULL;
+
+        for (uint32_t ix = 0; ix < array_size(algorithms); ++ix) {
+            SecKeyAlgorithm algorithm = algorithms[ix];
+            SecKeyAlgorithm incompatibleAlgorithm = (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRaw)) ?
+            kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1 : kSecKeyAlgorithmRSASignatureRaw;
+
+            CFDataRef dataToSign = NULL;
+            if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1)) {
+                dataToSign = CFDataCreateWithHash(kCFAllocatorDefault, ccsha1_di(),
+                                                  CFDataGetBytePtr(testData), CFDataGetLength(testData));
+                ok(dataToSign, "creating digest failed for algorithm %@", algorithm);
+            }
+            else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224)) {
+                dataToSign = CFDataCreateWithHash(kCFAllocatorDefault, ccsha224_di(),
+                                                  CFDataGetBytePtr(testData), CFDataGetLength(testData));
+                ok(dataToSign, "creating digest failed for algorithm %@", algorithm);
+            }
+            else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256)) {
+                dataToSign = CFDataCreateWithHash(kCFAllocatorDefault, ccsha256_di(),
+                                                  CFDataGetBytePtr(testData), CFDataGetLength(testData));
+                ok(dataToSign, "creating digest failed for algorithm %@", algorithm);
+            }
+            else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384)) {
+                dataToSign = CFDataCreateWithHash(kCFAllocatorDefault, ccsha384_di(),
+                                                  CFDataGetBytePtr(testData), CFDataGetLength(testData));
+                ok(dataToSign, "creating digest failed for algorithm %@", algorithm);
+            }
+            else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512)) {
+                dataToSign = CFDataCreateWithHash(kCFAllocatorDefault, ccsha512_di(),
+                                                  CFDataGetBytePtr(testData), CFDataGetLength(testData));
+                ok(dataToSign, "creating digest failed for algorithm %@", algorithm);
+            }
+            else {
+                CFRetainAssign(dataToSign, testData);
+            }
+            CFReleaseNull(error);
+
+            SKIP: {
+                skip("invalid data to sign", 7, dataToSign);
+
+                CFDataRef signature = SecKeyCreateSignature(pubKey, algorithm, dataToSign, &error);
+                ok(!signature, "SecKeyCopySignature succeeded with pub key for algorithm %@", algorithm);
+                CFReleaseNull(error);
+                CFReleaseNull(signature);
+
+                signature = SecKeyCreateSignature(privKey, algorithm, dataToSign, &error);
+                ok(signature, "SecKeyCopySignature failed for algorithm %@", algorithm);
+                CFReleaseNull(error);
+
+                SKIP: {
+                    skip("invalid signature", 4, signature);
+
+                    ok(!SecKeyVerifySignature(privKey, algorithm, dataToSign, signature, &error),
+                       "SecKeyVerifySignature succeeded with priv key for algorithm %@", algorithm);
+                    CFReleaseNull(error);
+
+                    ok(!SecKeyVerifySignature(pubKey, incompatibleAlgorithm, dataToSign, signature, &error),
+                       "SecKeyVerifySignature succeeded with wrong algorithm for algorithm %@", algorithm);
+                    CFReleaseNull(error);
+
+                    ok(SecKeyVerifySignature(pubKey, algorithm, dataToSign, signature, &error),
+                       "SecKeyVerifySignature failed for algorithm %@", algorithm);
+                    CFReleaseNull(error);
+
+                    CFMutableDataRef modifiedSignature = CFDataCreateMutable(kCFAllocatorDefault, 0);
+                    CFDataAppend(modifiedSignature, signature);
+                    *CFDataGetMutableBytePtr(modifiedSignature) ^= 0xff;
+
+                    ok(!SecKeyVerifySignature(pubKey, algorithm, dataToSign, modifiedSignature, &error),
+                       "SecKeyVerifySignature succeeded with bad signature for algorithm %@", algorithm);
+                    CFReleaseNull(error);
+
+                    CFMutableDataRef modifiedDataToSign = CFDataCreateMutable(kCFAllocatorDefault, 0);
+                    CFDataAppend(modifiedDataToSign, dataToSign);
+                    *CFDataGetMutableBytePtr(modifiedDataToSign) ^= 0xff;
+
+                    ok(!SecKeyVerifySignature(pubKey, algorithm, modifiedDataToSign, signature, &error),
+                       "SecKeyVerifySignature succeeded with bad data for algorithm %@", algorithm);
+                    CFReleaseNull(error);
+
+                    CFReleaseNull(modifiedDataToSign);
+                    CFReleaseNull(modifiedSignature);
+                    CFReleaseNull(signature);
+                }
+                CFReleaseNull(dataToSign);
+            }
+        }
+        CFReleaseNull(testData);
+    }
+
+    CFReleaseNull(pubKey);
+    CFReleaseNull(privKey);
+}
+
+
+#define kSPKITestCount 4
+static void testspki(CFStringRef keytype, size_t keySizeInBits)
+{
+    SecKeyRef pubKey = NULL, privKey = NULL, pubKey2 = NULL;
+    size_t keySizeInBytes = (keySizeInBits + 7) / 8;
+    CFNumberRef kzib;
+    int32_t keysz32 = (int32_t)keySizeInBits;
+    CFDataRef spki = NULL;
+
+    kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
+    CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
+    CFDictionaryAddValue(kgp, kSecAttrKeyType, keytype);
+    CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
+
+    OSStatus status;
+    ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
+              "Generate %ld bit (%ld byte) keypair", keySizeInBits, keySizeInBytes);
+    CFRelease(kzib);
+    CFRelease(kgp);
+
+    spki = SecKeyCopySubjectPublicKeyInfo(pubKey);
+    ok(spki, "failed to create SPKI");
+
+    pubKey2 = SecKeyCreateFromSubjectPublicKeyInfoData(NULL, spki);
+    ok(pubKey2, "failed to create key from SPKI");
+
+    eq_cf(pubKey, pubKey2, "public not same after going though SPKI");
+
+    CFReleaseNull(pubKey);
+    CFReleaseNull(pubKey2);
+    CFReleaseNull(privKey);
+    CFReleaseNull(spki);
+}
+
+
 /* Test basic add delete update copy matching stuff. */
-#define kTestCount ((3 * kKeyGenTestCount) + kKeyGen2TestCount)
+#define kTestCount ((3 * kKeyGenTestCount) + kKeyGen2TestCount + kTestSupportedCount + kCreateWithDataTestCount \
+    + kCopyAttributesTestCount + kCopyPublicKeyTestCount + kSignAndVerifyTestCount + ((3 + 3) * kSPKITestCount))
 static void tests(void)
 {
        /* Comment out lines below for testing generating all common key sizes,
@@ -445,6 +986,20 @@ static void tests(void)
        //testkeygen(4096);
 
     testkeygen2(768);
+
+    testsupportedalgos(768);
+    testcreatewithdata(768);
+    testcopyattributes(768);
+    testcopypublickey(768);
+    testsignverify(768);
+
+    testspki(kSecAttrKeyTypeRSA, 1024);
+    testspki(kSecAttrKeyTypeRSA, 2048);
+    testspki(kSecAttrKeyTypeRSA, 4096);
+
+    testspki(kSecAttrKeyTypeEC, 256);
+    testspki(kSecAttrKeyTypeEC, 384);
+    testspki(kSecAttrKeyTypeEC, 521);
 }
 
 int si_40_seckey(int argc, char *const *argv)