#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"
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");
}
#endif
-#define kEncryptDecryptTestCount 5
+#define kEncryptDecryptTestCount 6
static void test_encrypt_decrypt(SecKeyRef pubKey, SecKeyRef privKey, uint32_t padding, size_t keySizeInBytes)
{
SKIP: {
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) {
}
}
-#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;
/* 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);
#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);
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);
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,
//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)