#include <CoreFoundation/CoreFoundation.h>
#include <Security/SecCertificate.h>
#include <Security/SecCertificateInternal.h>
#include <Security/SecKey.h>
#include <Security/SecKeyPriv.h>
#include <Security/SecItem.h>
#include <Security/SecAsn1Types.h>
#include <Security/oidsalg.h>
#include <Security/SecureTransport.h>
#include <Security/SecRandom.h>
#include <utilities/array_size.h>
#include <CommonCrypto/CommonDigest.h>
#include <libDER/libDER.h>
#include <stdlib.h>
#include <unistd.h>
#include "Security_regressions.h"
#define CFReleaseNull(CF) { CFTypeRef _cf = (CF); if (_cf) { (CF) = NULL; CFRelease(_cf); } }
static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecAsn1AlgId *algId) {
uint8_t dataToDigest[256] = {0,};
size_t dataToDigestLen = sizeof(dataToDigest);
size_t sigLen = SecKeyGetSize(privKey, kSecKeySignatureSize);
uint8_t sig[sigLen];
DERItem oid;
oid.length = algId->algorithm.Length;
oid.data = algId->algorithm.Data;
CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid);
char oidBuf[40];
CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8);
CFRelease(oidStr);
SKIP: {
OSStatus status;
ok_status(status = SecKeyDigestAndSign(privKey, algId, dataToDigest, dataToDigestLen,
sig, &sigLen),
"digest and sign %s with %ld bit RSA key", oidBuf, sigLen * 8);
skip("SecKeyDigestAndSign failed", 3, status == errSecSuccess);
ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
sig, sigLen), "digest and verify");
sig[0] ^= 0xff;
is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
sig, sigLen), errSSLCrypto, "digest and verify bad sig");
sig[0] ^= 0xff;
dataToDigest[0] ^= 0xff;
is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
sig, sigLen), errSSLCrypto, "digest and verify bad digest");
}
}
static void testdigestandsign(SecKeyRef privKey, SecKeyRef pubKey) {
static const SecAsn1Oid *oids[] = {
&CSSMOID_ECDSA_WithSHA1,
#if 0
&CSSMOID_ECDSA_WithSHA224,
&CSSMOID_ECDSA_WithSHA256,
&CSSMOID_ECDSA_WithSHA384,
&CSSMOID_ECDSA_WithSHA512,
#endif
};
uint32_t ix;
SecAsn1AlgId algId = {};
for (ix = 0; ix < array_size(oids); ++ix) {
if (oids[ix]) {
algId.algorithm = *oids[ix];
} else {
algId.algorithm.Length = 0;
algId.algorithm.Data = NULL;
}
testdigestandsignalg(privKey, pubKey, &algId);
}
}
static void testkeygen(size_t keySizeInBits) {
SecKeyRef pubKey = NULL, privKey = NULL;
size_t keySizeInBytes = (keySizeInBits + 7) / 8;
CFNumberRef kzib;
int32_t keysz32 = (int32_t)keySizeInBits;
kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC);
CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
OSStatus status;
ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
"Generate %ld bit (%ld byte) EC keypair", keySizeInBits,
keySizeInBytes);
CFRelease(kzib);
CFRelease(kgp);
SKIP: {
skip("keygen failed", 8, status == errSecSuccess);
ok(pubKey, "pubkey returned");
ok(privKey, "privKey returned");
is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
uint8_t sig[8+2*keySizeInBytes];
size_t sigLen = sizeof(sig);
ok_status(SecKeyRawSign(privKey, kSecPaddingNone,
something, sizeof(something), sig, &sigLen), "sign something");
ok_status(SecKeyRawVerify(pubKey, kSecPaddingNone,
something, sizeof(something), sig, sigLen), "verify sig on something");
testdigestandsign(privKey, pubKey);
const void *privkeys[] = {
kSecValueRef
};
const void *privvalues[] = {
privKey
};
CFDictionaryRef privitem = CFDictionaryCreate(NULL, privkeys, privvalues,
array_size(privkeys), NULL, NULL);
ok_status(SecItemAdd(privitem, NULL), "add private key");
ok_status(SecItemDelete(privitem), "delete public key");
CFReleaseNull(privitem);
const void *pubkeys[] = {
kSecValueRef
};
const void *pubvalues[] = {
pubKey
};
CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubkeys, pubvalues,
array_size(pubkeys), NULL, NULL);
ok_status(SecItemAdd(pubitem, NULL), "add public key");
ok_status(SecItemDelete(pubitem), "delete public key");
CFReleaseNull(pubitem);
CFReleaseNull(pubKey);
CFReleaseNull(privKey);
}
}
static void testkeygen2(size_t keySizeInBits) {
SecKeyRef pubKey = NULL, privKey = NULL;
size_t keySizeInBytes = (keySizeInBits + 7) / 8;
CFNumberRef kzib;
int32_t keysz32 = (int32_t)keySizeInBits;
CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID);
CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
CFReleaseNull(ourUUID);
CFReleaseNull(uuidString);
CFStringAppend(publicName, CFSTR("-Public-41"));
CFStringAppend(privateName, CFSTR("-Private-41"));
CFMutableDictionaryRef pubd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
CFMutableDictionaryRef privd = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
CFDictionaryAddValue(pubd, kSecAttrLabel, publicName);
CFDictionaryAddValue(privd, kSecAttrLabel, privateName);
kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeEC);
CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib);
CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanTrue);
CFDictionaryAddValue(kgp, kSecPublicKeyAttrs, pubd);
CFDictionaryAddValue(kgp, kSecPrivateKeyAttrs, privd);
OSStatus status;
ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
"Generate %ld bit (%ld byte) persistent RSA keypair",
keySizeInBits, keySizeInBytes);
CFRelease(kzib);
CFRelease(kgp);
SKIP: {
skip("keygen failed", 8, status == errSecSuccess);
ok(pubKey, "pubkey returned");
ok(privKey, "privKey returned");
is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");
SecKeyRef pubKey2, privKey2;
CFDictionaryAddValue(pubd, kSecClass, kSecClassKey);
CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue);
CFDictionaryAddValue(privd, kSecClass, kSecClassKey);
CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue);
CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue);
ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2),
"retrieve pub key by label");
ok(pubKey2, "got valid object");
ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2),
"retrieve priv key by label and kSecAttrCanSign");
ok(privKey2, "got valid object");
uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
size_t sigLen = SecKeyGetSize(privKey2, kSecKeySignatureSize);
uint8_t sig[sigLen];
ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1,
something, sizeof(something), sig, &sigLen), "sign something");
ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1,
something, sizeof(something), sig, sigLen), "verify sig on something");
CFReleaseNull(pubKey2);
CFReleaseNull(privKey2);
}
ok_status(SecItemDelete(pubd), "delete generated pub key");
ok_status(SecItemDelete(privd), "delete generated priv key");
CFReleaseNull(pubKey);
CFReleaseNull(privKey);
CFReleaseNull(publicName);
CFReleaseNull(privateName);
CFRelease(pubd);
CFRelease(privd);
}
static void tests(void)
{
testkeygen(192);
testkeygen(224);
testkeygen(256);
testkeygen(384);
testkeygen(521);
testkeygen2(192);
testkeygen2(224);
testkeygen2(256);
testkeygen2(384);
testkeygen2(521);
}
int si_41_sececkey(int argc, char *const *argv)
{
plan_tests(140);
tests();
return 0;
}