static CF_RETURNS_RETAINED CFDictionaryRef SecKeyGenerateAttributeDictionaryFor(SecKeyRef key,
                                                                                CFTypeRef keyType,
                                                                                CFDataRef privateBlob)
{
	CFAllocatorRef allocator = CFGetAllocator(key);
	DICT_DECLARE(25);
	CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL;
	CFDictionaryRef dict = NULL;
    
    size_t sizeValue = SecKeyGetSize(key, kSecKeyKeySizeInBits);
    CFNumberRef sizeInBits = CFNumberCreate(allocator, kCFNumberLongType, &sizeValue);
    
	/* encode the public key. */
    require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut);
    require(pubKeyBlob, errOut);
    
	/* Calculate the digest of the public key. */
	require(pubKeyDigest = SecSHA1DigestCreate(allocator,
                                               CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)),
			errOut);
    
	DICT_ADDPAIR(kSecClass, kSecClassKey);
	DICT_ADDPAIR(kSecAttrKeyClass, privateBlob ? kSecAttrKeyClassPrivate : kSecAttrKeyClassPublic);
	DICT_ADDPAIR(kSecAttrApplicationLabel, pubKeyDigest);
	DICT_ADDPAIR(kSecAttrIsPermanent, kCFBooleanTrue);
	DICT_ADDPAIR(kSecAttrIsPrivate, kCFBooleanTrue);
	DICT_ADDPAIR(kSecAttrIsModifiable, kCFBooleanTrue);
	DICT_ADDPAIR(kSecAttrKeyType, keyType);
	DICT_ADDPAIR(kSecAttrKeySizeInBits, sizeInBits);
	DICT_ADDPAIR(kSecAttrEffectiveKeySize, sizeInBits);
	DICT_ADDPAIR(kSecAttrIsSensitive, kCFBooleanFalse);
	DICT_ADDPAIR(kSecAttrWasAlwaysSensitive, kCFBooleanFalse);
	DICT_ADDPAIR(kSecAttrIsExtractable, kCFBooleanTrue);
	DICT_ADDPAIR(kSecAttrWasNeverExtractable, kCFBooleanFalse);
	DICT_ADDPAIR(kSecAttrCanEncrypt, kCFBooleanFalse);
	DICT_ADDPAIR(kSecAttrCanDecrypt, kCFBooleanTrue);
	DICT_ADDPAIR(kSecAttrCanDerive, kCFBooleanTrue);
	DICT_ADDPAIR(kSecAttrCanSign, kCFBooleanTrue);
	DICT_ADDPAIR(kSecAttrCanVerify, kCFBooleanFalse);
	DICT_ADDPAIR(kSecAttrCanSignRecover, kCFBooleanFalse);
	DICT_ADDPAIR(kSecAttrCanVerifyRecover, kCFBooleanFalse);
	DICT_ADDPAIR(kSecAttrCanWrap, kCFBooleanFalse);
	DICT_ADDPAIR(kSecAttrCanUnwrap, kCFBooleanTrue);
	DICT_ADDPAIR(kSecValueData, privateBlob ? privateBlob : pubKeyBlob);
    dict = DICT_CREATE(allocator);
    
errOut:
	// @@@ Zero out key material.
	CFReleaseSafe(pubKeyDigest);
	CFReleaseSafe(pubKeyBlob);
	CFReleaseSafe(sizeInBits);
    
	return dict;
}
/* Test basic add delete update copy matching stuff. */
static void tests(SecKeyDescriptor *descriptor)
{
    const uint8_t *keyData = (const uint8_t *)"abc";
    CFIndex keyDataLength = 3;
    SecKeyEncoding encoding = kSecKeyEncodingRaw;
    ok(customKey = SecKeyCreate(kCFAllocatorDefault,
        descriptor, keyData, keyDataLength, encoding),
        "create custom key");
    is(customKey, initedCustomKey, "CustomKeyInit got the right key");

    SecPadding padding = kSecPaddingPKCS1;
    const uint8_t *src = (const uint8_t *)"defgh";
    size_t srcLen = 5;
    uint8_t dst[5];
    size_t dstLen = 5;

    ok_status(SecKeyDecrypt(customKey, padding, src, srcLen, dst, &dstLen),
        "SecKeyDecrypt");
    ok_status(SecKeyEncrypt(customKey, padding, src, srcLen, dst, &dstLen),
        "SecKeyEncrypt");
    ok_status(SecKeyRawSign(customKey, padding, src, srcLen, dst, &dstLen),
        "SecKeyRawSign");
    ok_status(SecKeyRawVerify(customKey, padding, src, srcLen, dst, dstLen),
        "SecKeyRawVerify");
    is(SecKeyGetSize(customKey, kSecKeyKeySizeInBits), (size_t)5*8, "SecKeyGetSize");

    CFDictionaryRef attrDict = NULL;
    ok(attrDict = SecKeyCopyAttributeDictionary(customKey),
        "SecKeyCopyAttributeDictionary");
    CFReleaseNull(attrDict);

    CFDataRef pubdata = NULL;
    ok(SecKeyCopyPublicBytes(customKey, &pubdata) != 0, "SecKeyCopyPublicBytes");
    CFReleaseNull(pubdata);

    CFDataRef wrapped;
    wrapped = _SecKeyCopyWrapKey(customKey, kSecKeyWrapPublicKeyPGP, pubdata, NULL, NULL, NULL);
    ok(wrapped == NULL, "_SecKeyCopyWrapKey");
    CFReleaseNull(wrapped);

    wrapped = _SecKeyCopyUnwrapKey(customKey, kSecKeyWrapPublicKeyPGP, pubdata, NULL, NULL, NULL);
    ok(wrapped == NULL, "_SecKeyCopyUnwrapKey");
    CFReleaseNull(wrapped);

    //ok(SecKeyGeneratePair(customKey, ), "SecKeyGeneratePair");
    ok(SecKeyGetTypeID() != 0, "SecKeyGetTypeID works");

    if (customKey) {
        CFRelease(customKey);
        customKey = NULL;
    }
}
OSStatus
SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool *poolp, 
				 SecPublicKeyRef publickey, 
				 SecSymmetricKeyRef bulkkey, SecAsn1Item * encKey)
{
    OSStatus rv;
    size_t data_len;
    //KeyType keyType;
    void *mark = NULL;

    mark = PORT_ArenaMark(poolp);
    if (!mark)
	goto loser;

#if 0
    /* sanity check */
    keyType = SECKEY_GetPublicKeyType(publickey);
    PORT_Assert(keyType == rsaKey);
    if (keyType != rsaKey) {
	goto loser;
    }
#endif
    /* allocate memory for the encrypted key */
#if USE_CDSA_CRYPTO
    rv = SecKeyGetStrengthInBits(publickey, NULL, &data_len);
    if (rv)
	goto loser;
    // Convert length to bytes;
    data_len >>= 2;
#else
    data_len = SecKeyGetSize(publickey, kSecKeyEncryptedDataSize);
#endif

    encKey->Data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len);
    encKey->Length = data_len;
    if (encKey->Data == NULL)
	goto loser;

    /* encrypt the key now */
    rv = WRAP_PubWrapSymKey(publickey, bulkkey, encKey);
    if (rv != SECSuccess)
	goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    if (mark) {
	PORT_ArenaRelease(poolp, mark);
    }
    return SECFailure;
}
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;

    /* Get the oid in decimal for display purposes. */
    CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, &oid);
	char oidBuf[40];
    CFStringGetCString(oidStr, oidBuf, sizeof(oidBuf), kCFStringEncodingUTF8);
    CFRelease(oidStr);

SKIP: {
    OSStatus status;

    /* Time to sign. */
    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);

    /* Verify the signature we just made. */
    ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen,
                                    sig, sigLen), "digest and verify");
    /* Invalidate the signature. */
    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 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 = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault,
                                                                          kSecAttrLabel, publicName,
                                                                          NULL);
    CFMutableDictionaryRef privd = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault,
                                                                           kSecAttrLabel, privateName,
                                                                           NULL);

	kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
    CFDictionaryRef kgp = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
                                                       kSecAttrKeyType, kSecAttrKeyTypeEC,
                                                       kSecAttrKeySizeInBits, kzib,
                                                       kSecAttrIsPermanent, kCFBooleanTrue,
                                                       kSecPublicKeyAttrs, pubd,
                                                       kSecPrivateKeyAttrs, privd,
                                                       NULL);

    CFReleaseNull(kzib);

	OSStatus status;
	ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
              "Generate %ld bit (%ld byte) persistent RSA keypair",
              keySizeInBits, keySizeInBytes);

    CFReleaseNull(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");

    /* Sign something. */
    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");

    /* Cleanup. */
    CFReleaseNull(pubKey2);
    CFReleaseNull(privKey2);
}

    /* delete from keychain - note: do it before releasing publicName and privateName
       because pubd and privd have no retain/release callbacks */
    ok_status(SecItemDelete(pubd), "delete generated pub key");
    ok_status(SecItemDelete(privd), "delete generated priv key");

	/* Cleanup. */
	CFReleaseNull(pubKey);
	CFReleaseNull(privKey);

    CFReleaseNull(publicName);
    CFReleaseNull(privateName);

	CFReleaseNull(pubd);
	CFReleaseNull(privd);
}
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");

    /* Sign something. */
    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);

    /* Cleanup. */
    CFReleaseNull(pubKey);
    CFReleaseNull(privKey);
}
}
static void tests(void)
{
    CFDataRef message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
        _user_one_p12, sizeof(_user_one_p12), kCFAllocatorNull);
    CFArrayRef items = NULL;
    SecCertificateRef cert = NULL;
    SecKeyRef pkey = NULL;

    is_status(SecPKCS12Import(message, NULL, NULL), errSecAuthFailed,
        "try null password on a known good p12");

    CFStringRef password = CFSTR("user-one");
    CFDictionaryRef options = CFDictionaryCreate(NULL,
        (const void **)&kSecImportExportPassphrase,
        (const void **)&password, 1,
        &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);
    ok_status(SecPKCS12Import(message, options, &items), "import user one");

    is(CFArrayGetCount(items), 1, "one identity");
    CFDictionaryRef item = CFArrayGetValueAtIndex(items, 0);
    SecIdentityRef identity = NULL;
    ok(identity = (SecIdentityRef)CFDictionaryGetValue(item, kSecImportItemIdentity), "pull identity from imported data");

    ok(CFGetTypeID(identity)==SecIdentityGetTypeID(),"this is a SecIdentityRef");
    ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key");
    ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate");

    CFReleaseNull(items);
    CFReleaseNull(message);
    CFReleaseNull(options);
    CFReleaseNull(password);
    CFReleaseNull(cert);
    CFReleaseNull(pkey);

    message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
        _user_two_p12, sizeof(_user_two_p12), kCFAllocatorNull);
    items = NULL;
    password = CFSTR("user-two");
    options = CFDictionaryCreate(NULL,
        (const void **)&kSecImportExportPassphrase,
        (const void **)&password, 1,
        &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);

    ok_status(SecPKCS12Import(message, options, &items), "import user two");
    is(CFArrayGetCount(items), 1, "one identity");
    item = CFArrayGetValueAtIndex(items, 0);
    ok(identity = (SecIdentityRef)CFDictionaryGetValue(item, kSecImportItemIdentity), "pull identity from imported data");

    ok(CFGetTypeID(identity)==SecIdentityGetTypeID(),"this is a SecIdentityRef");
    ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key");
    ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate");

    CFReleaseNull(items);
    CFReleaseNull(message);
    CFReleaseNull(options);
    CFReleaseNull(password);
    CFReleaseNull(cert);
    CFReleaseNull(pkey);



    message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
                                          ECDSA_fails_import_p12, ECDSA_fails_import_p12_len, kCFAllocatorNull);
    items = NULL;
    password = CFSTR("test");
    options = CFDictionaryCreate(NULL,
                                 (const void **)&kSecImportExportPassphrase,
                                 (const void **)&password, 1,
                                 &kCFTypeDictionaryKeyCallBacks,
                                 &kCFTypeDictionaryValueCallBacks);

    ok_status(SecPKCS12Import(message, options, &items), "import ECDSA_fails_import_p12");
    is(CFArrayGetCount(items), 1, "one identity");
    item = CFArrayGetValueAtIndex(items, 0);
    ok(identity = (SecIdentityRef)CFDictionaryGetValue(item, kSecImportItemIdentity), "pull identity from imported data");

    ok(CFGetTypeID(identity)==SecIdentityGetTypeID(),"this is a SecIdentityRef");
    ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key");
    ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate");

    CFDataRef pubdata = NULL;
    SecKeyRef pubkey = NULL;

    ok_status(SecKeyCopyPublicBytes(pkey, &pubdata), "pub key from priv key");
    ok(pubkey = SecKeyCreateECPublicKey(kCFAllocatorDefault,
        CFDataGetBytePtr(pubdata), CFDataGetLength(pubdata), kSecKeyEncodingBytes),
       "recreate seckey");

    /* Sign something. */
    uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
    size_t sigLen = SecKeyGetSize(pkey, kSecKeySignatureSize);
    uint8_t sig[sigLen];
    ok_status(SecKeyRawSign(pkey, kSecPaddingPKCS1,
                            something, sizeof(something), sig, &sigLen), "sign something");
    ok_status(SecKeyRawVerify(pubkey, kSecPaddingPKCS1,
                              something, sizeof(something), sig, sigLen), "verify sig on something");


    CFReleaseNull(pubdata);
    CFReleaseNull(pubkey);
    CFReleaseNull(pkey);

    ok(pkey = SecKeyCreateECPrivateKey(kCFAllocatorDefault,
        ECDSA_fails_import_priv_only, ECDSA_fails_import_priv_only_len,
        kSecKeyEncodingPkcs1), "import privkey without pub");
    ok_status(SecKeyCopyPublicBytes(pkey, &pubdata), "pub key from priv key");
    ok(pubkey = SecKeyCreateECPublicKey(kCFAllocatorDefault,
        CFDataGetBytePtr(pubdata), CFDataGetLength(pubdata), kSecKeyEncodingBytes),
       "recreate seckey");
    ok_status(SecKeyRawVerify(pubkey, kSecPaddingPKCS1,
        something, sizeof(something), sig, sigLen), "verify sig on something");

    CFReleaseNull(pubdata);
    CFReleaseNull(pubkey);
    CFReleaseNull(pkey);
    CFReleaseNull(items);
    CFReleaseNull(message);
    CFReleaseNull(options);
    CFReleaseNull(password);
    CFReleaseNull(cert);

}