Beispiel #1
0
      Certificate_Store_MacOS_Impl() :
         m_policy(SecPolicyCreateBasicX509()),
         m_system_roots(nullptr),
         m_system_chain(nullptr),
         m_keychains(nullptr)
         {
         check_success(SecKeychainOpen(system_roots, &m_system_roots.get()),
                       "open system root certificates");
         check_success(SecKeychainOpen(system_keychain, &m_system_chain.get()),
                       "open system keychain");
         check_notnull(m_system_roots, "open system root certificate chain");
         check_notnull(m_system_chain, "open system certificate chain");

         // m_keychains is merely a convenience list view into all open keychain
         // objects. This list is required in prepareQuery().
         std::array<const void*, 2> keychains{{
               m_system_roots.get(),
               m_system_chain.get()
               }};

         m_keychains.assign(
            CFArrayCreate(kCFAllocatorDefault,
                          keychains.data(),
                          keychains.size(),
                          &kCFTypeArrayCallBacks));
         check_notnull(m_keychains, "initialize keychain array");
         }
Beispiel #2
0
static VALUE rb_open_keychain(VALUE self, VALUE path){
  SecKeychainRef keychain=NULL;
  OSStatus result =SecKeychainOpen(StringValueCStr(path), &keychain);
  CheckOSStatusOrRaise(result);

  return KeychainFromSecKeychainRef(keychain);
}
Beispiel #3
0
void makeEncryptKey(CFStringRef pass)
{
	UInt32				passLen;
	unsigned char		*passData;

	SecKeychainItemRef	itemRef=NULL;
	SecKeychainRef		sysChain;
	OSStatus			secRes;
	
	BF_KEY				temp_key;
	unsigned char		encrypt_key[8];	
	
	if ((secRes = SecKeychainOpen(SYSTEM_KEYCHAIN, &sysChain)) != 0)
	{
		syslog(LOG_ERR,"Couldn't get system keychain: %d\n",secRes);
		exit(-1);
	}

	if ((secRes = SecKeychainFindGenericPassword(sysChain, strlen(SECRET_SERVICENAME), SECRET_SERVICENAME, 0, NULL, &passLen, (void**)&passData, &itemRef))!=0)
	{
		syslog(LOG_ERR,"Error finding secret in keychain (%d). Failing",secRes);
		exit(-1);
	}
	
	BF_set_key(&temp_key,passLen,passData);
	BF_ecb_encrypt((const unsigned char*)CFStringGetCStringPtr(pass,CFStringGetFastestEncoding(pass)),encrypt_key,&temp_key,BF_ENCRYPT);
	BF_set_key(&encrypt_bf_key,8,encrypt_key);	
	return;
}
Beispiel #4
0
static int
keychain_init(hx509_context context,
	      hx509_certs certs, void **data, int flags,
	      const char *residue, hx509_lock lock)
{
    struct ks_keychain *ctx;

    ctx = calloc(1, sizeof(*ctx));
    if (ctx == NULL) {
	hx509_clear_error_string(context);
	return ENOMEM;
    }

    if (residue) {
	if (strcasecmp(residue, "system-anchors") == 0) {
	    ctx->anchors = 1;
	} else if (strncasecmp(residue, "FILE:", 5) == 0) {
	    OSStatus ret;

	    ret = SecKeychainOpen(residue + 5, &ctx->keychain);
	    if (ret != noErr) {
		hx509_set_error_string(context, 0, ENOENT, 
				       "Failed to open %s", residue);
		return ENOENT;
	    }
	} else {
	    hx509_set_error_string(context, 0, ENOENT, 
				   "Unknown subtype %s", residue);
	    return ENOENT;
	}
    }

    *data = ctx;
    return 0;
}
Beispiel #5
0
SecKeychainRef SROpenKeychain(char* path) {
  SecKeychainRef keychain = NULL;
  OSStatus status = SecKeychainOpen(path, &keychain);
  SecKeychainStatus keychainStatus = 0;
  status = SecKeychainGetStatus(keychain, &keychainStatus);
  if (status == 0) {
  } else {
    fprintf(stderr, "Unable to open keychain at path %s: ", path);
    SRHandleError(status, false);
    exit(EX_IOERR);
  }
  return keychain;
}
Beispiel #6
0
void genKeychains(const std::string& path, CFMutableArrayRef& keychains) {
  std::vector<std::string> paths;

  // Support both a directory and explicit path search.
  if (isDirectory(path).ok()) {
    // Try to list every file in the given keychain search path.
    if (!listFilesInDirectory(path, paths).ok()) {
      return;
    }
  } else {
    // The explicit path search comes from a query predicate.
    paths.push_back(path);
  }

  for (const auto& keychain_path : paths) {
    SecKeychainRef keychain = nullptr;
    auto status = SecKeychainOpen(keychain_path.c_str(), &keychain);
    if (status == 0 && keychain != nullptr) {
      CFArrayAppendValue(keychains, keychain);
    }
  }
}
Beispiel #7
0
static CFArrayRef				/* O - Array of certificates */
copy_cdsa_certificate(
    cupsd_client_t *con)			/* I - Client connection */
{
  OSStatus		err;		/* Error info */
  SecKeychainRef	keychain = NULL;/* Keychain reference */
  SecIdentitySearchRef	search = NULL;	/* Search reference */
  SecIdentityRef	identity = NULL;/* Identity */
  CFArrayRef		certificates = NULL;
					/* Certificate array */
  SecPolicyRef		policy = NULL;	/* Policy ref */
  CFStringRef		servername = NULL;
					/* Server name */
  CFMutableDictionaryRef query = NULL;	/* Query qualifiers */
  CFArrayRef		list = NULL;	/* Keychain list */
#    if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  char			localname[1024];/* Local hostname */
#    endif /* HAVE_DNSSD || HAVE_AVAHI */


  cupsdLogMessage(CUPSD_LOG_DEBUG,
                  "copy_cdsa_certificate: Looking for certs for \"%s\".",
		  con->servername);

  if ((err = SecKeychainOpen(ServerCertificate, &keychain)))
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)",
	            ServerCertificate, cssmErrorString(err), (int)err);
    goto cleanup;
  }

  servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername,
					 kCFStringEncodingUTF8);

  policy = SecPolicyCreateSSL(1, servername);

  if (servername)
    CFRelease(servername);

  if (!policy)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
    goto cleanup;
  }

  if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
					  &kCFTypeDictionaryKeyCallBacks,
					  &kCFTypeDictionaryValueCallBacks)))
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary");
    goto cleanup;
  }

  list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1,
                       &kCFTypeArrayCallBacks);

  CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
  CFDictionaryAddValue(query, kSecMatchPolicy, policy);
  CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
  CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
  CFDictionaryAddValue(query, kSecMatchSearchList, list);

  CFRelease(list);

  err = SecItemCopyMatching(query, (CFTypeRef *)&identity);

#    if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  if (err && DNSSDHostName)
  {
   /*
    * Search for the connection server name failed; try the DNS-SD .local
    * hostname instead...
    */

    snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);

    cupsdLogMessage(CUPSD_LOG_DEBUG,
		    "copy_cdsa_certificate: Looking for certs for \"%s\".",
		    localname);

    servername = CFStringCreateWithCString(kCFAllocatorDefault, localname,
					   kCFStringEncodingUTF8);

    CFRelease(policy);

    policy = SecPolicyCreateSSL(1, servername);

    if (servername)
      CFRelease(servername);

    if (!policy)
    {
      cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
      goto cleanup;
    }

    CFDictionarySetValue(query, kSecMatchPolicy, policy);

    err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
  }
#    endif /* HAVE_DNSSD || HAVE_AVAHI */

  if (err)
  {
    cupsdLogMessage(CUPSD_LOG_DEBUG,
		    "Cannot find signing key in keychain \"%s\": %s (%d)",
		    ServerCertificate, cssmErrorString(err), (int)err);
    goto cleanup;
  }

  if (CFGetTypeID(identity) != SecIdentityGetTypeID())
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure.");
    goto cleanup;
  }

  if ((certificates = CFArrayCreate(NULL, (const void **)&identity,
				  1, &kCFTypeArrayCallBacks)) == NULL)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array");
    goto cleanup;
  }

  cleanup :

  if (keychain)
    CFRelease(keychain);
  if (search)
    CFRelease(search);
  if (identity)
    CFRelease(identity);

  if (policy)
    CFRelease(policy);
  if (query)
    CFRelease(query);

  return (certificates);
}
Beispiel #8
0
static value cert_load_defaults(){
#if defined(NEKO_WINDOWS)
	value v;
	HCERTSTORE store;
	PCCERT_CONTEXT cert;
	mbedtls_x509_crt *chain = (mbedtls_x509_crt *)alloc(sizeof(mbedtls_x509_crt));
	mbedtls_x509_crt_init( chain );
	if( store = CertOpenSystemStore(0, (LPCSTR)"Root") ){
		cert = NULL;
		while( cert = CertEnumCertificatesInStore(store, cert) )
			mbedtls_x509_crt_parse_der( chain, (unsigned char *)cert->pbCertEncoded, cert->cbCertEncoded );
		CertCloseStore(store, 0);
	}
	v = alloc_abstract(k_cert, chain);
	val_gc(v,free_cert);
	return v;
#elif defined(NEKO_MAC)
	CFMutableDictionaryRef search;
	CFArrayRef result;
	SecKeychainRef keychain;
	SecCertificateRef item;
	CFDataRef dat;
	value v;
	mbedtls_x509_crt *chain = NULL;

	// Load keychain
	if( SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain",&keychain) != errSecSuccess )
		return val_null;

	// Search for certificates
	search = CFDictionaryCreateMutable( NULL, 0, NULL, NULL );
	CFDictionarySetValue( search, kSecClass, kSecClassCertificate );
	CFDictionarySetValue( search, kSecMatchLimit, kSecMatchLimitAll );
	CFDictionarySetValue( search, kSecReturnRef, kCFBooleanTrue );
	CFDictionarySetValue( search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL) );
	if( SecItemCopyMatching( search, (CFTypeRef *)&result ) == errSecSuccess ){
		CFIndex n = CFArrayGetCount( result );
		for( CFIndex i = 0; i < n; i++ ){
			item = (SecCertificateRef)CFArrayGetValueAtIndex( result, i );

			// Get certificate in DER format
			dat = SecCertificateCopyData( item );
			if( dat ){
				if( chain == NULL ){
					chain = (mbedtls_x509_crt *)alloc(sizeof(mbedtls_x509_crt));
					mbedtls_x509_crt_init( chain );
				}
				mbedtls_x509_crt_parse_der( chain, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat) );
				CFRelease( dat );
			}
		}
	}
	CFRelease(keychain);
	if( chain != NULL ){
		v = alloc_abstract(k_cert, chain);
		val_gc(v,free_cert);
		return v;
	}else{
		return val_null;
	}
#else
	return val_null;
#endif
}
/* 
 * Returns true if we are to allow/trust the specified
 * cert as a PKINIT-only anchor.
 */
static bool tpCheckPkinitServerCert(
	TPCertGroup &certGroup)
{
	/* 
	 * Basic requirement: exactly one cert, self-signed.
	 * The numCerts == 1 requirement might change...
	 */
	unsigned numCerts = certGroup.numCerts();
	if(numCerts != 1) {
		tpDebug("tpCheckPkinitServerCert: too many certs");
		return false;
	}
	/* end of chain... */
	TPCertInfo *theCert = certGroup.certAtIndex(numCerts - 1);
	if(!theCert->isSelfSigned()) {
		tpDebug("tpCheckPkinitServerCert: 1 cert, not self-signed");
		return false;
	}
	const CSSM_DATA *subjectName = theCert->subjectName();
	
	/* 
	 * Open the magic keychain.
	 * We're going up and over the Sec layer here, not generally 
	 * kosher, but this is a temp hack.
	 */
	OSStatus ortn;
	SecKeychainRef kcRef = NULL;
	string fullPathName;
	const char *homeDir = getenv("HOME");
	if (homeDir == NULL)
	{
		// If $HOME is unset get the current user's home directory
		// from the passwd file.
		uid_t uid = geteuid();
		if (!uid) uid = getuid();
		struct passwd *pw = getpwuid(uid);
		if (!pw) {
			return false;
		}
		homeDir = pw->pw_dir;
	}
	fullPathName = homeDir;
	fullPathName += "/Library/Application Support/PKINIT/TrustedServers.keychain";
	ortn = SecKeychainOpen(fullPathName.c_str(), &kcRef);
	if(ortn) {
		tpDebug("tpCheckPkinitServerCert: keychain not found (1)");
		return false;
	}
	/* subsequent errors to errOut: */
	
	bool ourRtn = false;
	SecKeychainStatus kcStatus;
	CSSM_DATA_PTR subjSerial = NULL;
	CSSM_RETURN crtn;
	SecKeychainSearchRef		srchRef = NULL;
	SecKeychainAttributeList	attrList;
	SecKeychainAttribute		attrs[2];
	SecKeychainItemRef			foundItem = NULL;
	
	ortn = SecKeychainGetStatus(kcRef, &kcStatus);
	if(ortn) {
		tpDebug("tpCheckPkinitServerCert: keychain not found (2)");
		goto errOut;
	}
	
	/*
	 * We already have this cert's normalized name; get its
	 * serial number.
	 */
	crtn = theCert->fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial);
	if(crtn) {
		/* should never happen */
		tpDebug("tpCheckPkinitServerCert: error fetching serial number");
		goto errOut;
	}
	
	attrs[0].tag    = kSecSubjectItemAttr;
	attrs[0].length = subjectName->Length;
	attrs[0].data   = subjectName->Data;
	attrs[1].tag    = kSecSerialNumberItemAttr;
	attrs[1].length = subjSerial->Length;
	attrs[1].data   = subjSerial->Data;
	attrList.count  = 2;
	attrList.attr   = attrs;
	
	ortn = SecKeychainSearchCreateFromAttributes(kcRef,
		kSecCertificateItemClass,
		&attrList,
		&srchRef);
	if(ortn) {
		tpDebug("tpCheckPkinitServerCert: search failure");
		goto errOut;
	}
	for(;;) {
		ortn = SecKeychainSearchCopyNext(srchRef, &foundItem);
		if(ortn) {
			tpDebug("tpCheckPkinitServerCert: end search");
			break;
		}
		
		/* found a matching cert; do byte-for-byte compare */
		CSSM_DATA certData;
		ortn = SecCertificateGetData((SecCertificateRef)foundItem, &certData);
		if(ortn) {
			tpDebug("tpCheckPkinitServerCert: SecCertificateGetData failure");
			continue;
		}
		if(tpCompareCssmData(&certData, theCert->itemData())){
			tpDebug("tpCheckPkinitServerCert: FOUND CERT");
			ourRtn = true;
			break;
		}
		tpDebug("tpCheckPkinitServerCert: skipping matching cert");
		CFRelease(foundItem);
		foundItem = NULL;
	}
errOut:
	CFRELEASE(kcRef);
	CFRELEASE(srchRef);
	CFRELEASE(foundItem);
	if(subjSerial != NULL) {
		theCert->freeField(&CSSMOID_X509V1SerialNumber, subjSerial);
	}
	return ourRtn;
}
Beispiel #10
0
static void
tls_get_cert_from_keychain( char *host )
{
	/* Cert info is kept in the global options. */
	struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();
	if ( !lo ) return;

        /* If the server identity option is set, don't need to do anything
         * as the certificate will get set in the SSL context during context
         * initialization. 
         */
        if (lo->ldo_tls_server_ident_ref_name) {
                return;
        }

	/* If the cert is set in the options, don't override it. */
	if ( lo->ldo_tls_cacertfile || lo->ldo_tls_certfile ) {
		Debug( LDAP_DEBUG_ANY,
		       "TLS: not reading certificate from keychain, option %s is set\n",
		       lo->ldo_tls_cacertfile ? "cacertfile" : "certfile", 0, 0 );

		return;
	}

	SecKeychainRef keychainRef = NULL;
	OSStatus status = SecKeychainOpen( SYSTEM_KEYCHAIN_PATH, &keychainRef );
	if ( status != errSecSuccess ) {
		Debug( LDAP_DEBUG_ANY, "TLS: SecKeychainOpen failed for keychain %s: %d",
		       SYSTEM_KEYCHAIN_PATH, (int)status, 0 );
		syslog( LOG_ERR, "TLS: SecKeychainOpen failed for keychain %s: %d",
			SYSTEM_KEYCHAIN_PATH, (int)status, 0 );
		cssmPerror( "SecKeychainOpen", status );
		return;
	}

	SecKeychainSearchRef searchRef = NULL;
	status = SecKeychainSearchCreateFromAttributes( keychainRef, kSecCertificateItemClass, NULL, &searchRef );
	if ( status != errSecSuccess ) {
		Debug( LDAP_DEBUG_ANY, "TLS: SecKeychainSearchCreateFromAttributes failed: %d",
		       (int)status, 0, 0 );
		syslog( LOG_ERR, "TLS: SecKeychainSearchCreateFromAttributes failed: %d", (int)status );
		cssmPerror( "SecKeychainSearchCreateFromAttributes", status );
	}

	while ( status == errSecSuccess ) {

		SecCertificateRef certificateRef = NULL;
		status = SecKeychainSearchCopyNext( searchRef, (SecKeychainItemRef*)&certificateRef );

		/* Bail on any error. */
		if ( status != errSecSuccess ) {
			/* Only complain if the error is something other than
			 * the normal search end. 
			 */
			if ( status != errSecItemNotFound ) {
				Debug( LDAP_DEBUG_ANY, "TLS: SecKeychainSearchCopyNext failed: %d",
				       (int)status, 0, 0 );
				syslog( LOG_ERR, "SecKeychainSearchCopyNext failed: %d", (int)status );
				cssmPerror( "SecKeychainSearchCopyNext", status );
			}
			break;
		}

		/* Extract the name from the certificate.  Will check against the host
		 * name passed in.
		 */
		CFStringRef commonName = NULL;
		status = SecCertificateCopyCommonName( certificateRef, &commonName );
		if ( status != errSecSuccess || !commonName ) {
			Debug( LDAP_DEBUG_ANY, "TLS: SecCertificateCopyCommonName failed: %d",
			       (int)status, 0, 0 );
			cssmPerror( "SecCertificateCopyCommonName", status );

			/* Reset 'status' to allow the loop to continue.  No need to
			 * stop just because we can't get the name from one of the
			 * certs.
			 */
			status = errSecSuccess;
		}
		else {
			/* If the common name in the certificate matches the host name, save
			 * the certificate reference in the options data for later use.
			 */
			char commonNameCStr[PATH_MAX];
			if ( !CFStringGetCString( commonName,
						  commonNameCStr,
						  sizeof(commonNameCStr),
						  kCFStringEncodingUTF8 ) )
			{
				Debug( LDAP_DEBUG_ANY,
				       "TLS: Unable to convert certificate common name CFString into C String",
				       0, 0, 0);
			}
			CFRelease( commonName );

			if ( commonNameCStr && strcmp( commonNameCStr, host ) == 0 ) {
				if ( lo->ldo_tls_cert_ref ) {
					CFRelease( lo->ldo_tls_cert_ref );
				}

				lo->ldo_tls_cert_ref = certificateRef;
				status = !errSecSuccess;  /* cert found - terminate the loop */
			}
		}

		/* Only release the ref if we don't care about it.  Refs we care
		 * about get released later (when the connection is closed).
		 */
		if ( lo->ldo_tls_cert_ref != certificateRef ) {
			CFRelease( certificateRef );
		}
	}

	if ( searchRef ) {
		CFRelease( searchRef );
	}

	CFRelease( keychainRef );

	Debug( LDAP_DEBUG_ANY,
	       "TLS: %s certificate in keychain for host \"%s\"\n",
	       lo->ldo_tls_cert_ref ? "found" : "did not find", host, 0 );
}
/*
 * Convert a keychain name (which may be NULL) into the CFArrayRef required
 * by SSLSetCertificate. This is a bare-bones example of this operation,
 * since it requires and assumes that there is exactly one SecIdentity
 * in the keychain - i.e., there is exactly one matching cert/private key 
 * pair. A real world server would probably search a keychain for a SecIdentity 
 * matching some specific criteria. 
 */
CFArrayRef getSslCerts( 
	const char			*kcName,				// may be NULL, i.e., use default
	bool                encryptOnly,
	bool                completeCertChain,
	const char			*anchorFile,			// optional trusted anchor
	SecKeychainRef		*pKcRef)				// RETURNED
{
#if 0
	SecKeychainRef 		kcRef = nil;
	OSStatus			ortn;
	
	*pKcRef = nil;
	
	/* pick a keychain */
	if(kcName) {
		ortn = SecKeychainOpen(kcName, &kcRef);
		if(ortn) {
			printf("SecKeychainOpen returned %d.\n", (int)ortn);
			printf("Cannot open keychain at %s. Aborting.\n", kcName);
			return NULL;
		}
	}
	else {
		/* use default keychain */
		ortn = SecKeychainCopyDefault(&kcRef);
		if(ortn) {
			printf("SecKeychainCopyDefault returned %d; aborting.\n", (int)ortn);
			return nil;
		}
	}
	*pKcRef = kcRef;
	return sslKcRefToCertArray(kcRef, encryptOnly, completeCertChain, anchorFile);
#else
	SecCertificateRef cert = NULL;
	SecIdentityRef identity = NULL;
	CFMutableArrayRef certificates = NULL, result = NULL;
	CFMutableDictionaryRef certQuery = NULL, keyQuery = NULL, keyResult = NULL;
	SecTrustRef trust = NULL;
	SecKeyRef key = NULL;
	CFTypeRef pkdigest = NULL;

	// Find the first private key in the keychain and return both it's
	// attributes and a ref to it.
	require(keyQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut);
	CFDictionaryAddValue(keyQuery, kSecClass, kSecClassKey);
	CFDictionaryAddValue(keyQuery, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
	CFDictionaryAddValue(keyQuery, kSecReturnRef, kCFBooleanTrue);
	CFDictionaryAddValue(keyQuery, kSecReturnAttributes, kCFBooleanTrue);
	require_noerr(SecItemCopyMatching(keyQuery, (CFTypeRef *)&keyResult),
		errOut);
	require(key = (SecKeyRef)CFDictionaryGetValue(keyResult, kSecValueRef),
		errOut);
	require(pkdigest = CFDictionaryGetValue(keyResult, kSecAttrApplicationLabel),
		errOut);

	// Find the first certificate that has the same public key hash as the
	// returned private key and return it as a ref.
	require(certQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut);
	CFDictionaryAddValue(certQuery, kSecClass, kSecClassCertificate);
	CFDictionaryAddValue(certQuery, kSecAttrPublicKeyHash, pkdigest);
	CFDictionaryAddValue(certQuery, kSecReturnRef, kCFBooleanTrue);
	require_noerr(SecItemCopyMatching(certQuery, (CFTypeRef *)&cert), errOut);

	// Create an identity from the key and certificate.
	require(identity = SecIdentityCreate(NULL, cert, key), errOut);

	// Build a (partial) certificate chain from cert
	require(certificates = CFArrayCreateMutable(NULL, 0,
		&kCFTypeArrayCallBacks), errOut);
	CFArrayAppendValue(certificates, cert);
	require_noerr(SecTrustCreateWithCertificates(certificates, NULL, &trust),
		errOut);
	SecTrustResultType tresult;
	require_noerr(SecTrustEvaluate(trust, &tresult), errOut);

	CFIndex certCount, ix;
	// We need at least 1 certificate
	require(certCount = SecTrustGetCertificateCount(trust), errOut);

	// Build a result where element 0 is the identity and the other elements
	// are the certs in the chain starting at the first intermediate up to the
	// anchor, if we found one, or as far as we were able to build the chain
	// if not.
	require(result = CFArrayCreateMutable(NULL, certCount, &kCFTypeArrayCallBacks),
		errOut);

	// We are commited to returning a result now, so do not use require below
	// this line without setting result to NULL again.
	CFArrayAppendValue(result, identity);
	for (ix = 1; ix < certCount; ++ix) {
		CFArrayAppendValue(result, SecTrustGetCertificateAtIndex(trust, ix));
	}

errOut:
	CFReleaseSafe(trust);
	CFReleaseSafe(certificates);
	CFReleaseSafe(identity);
	CFReleaseSafe(cert);
	CFReleaseSafe(certQuery);
	CFReleaseSafe(keyResult);
	CFReleaseSafe(keyQuery);

    return result;
#endif
}
int main(int argc, char **argv)
{
	if(argc < 2) {
		usage(argv);
	}
	ocspOp op;
	switch(argv[1][0]) {
		case 'g': op = op_genReq; break;
		case 'G': op = op_parseReq; break;
		case 'r': op = op_genReply; break;
		case 'R': op = op_parseResp; break;
		case 'p': op = op_post; break;
		default: usage(argv);
	}
	
	/* user defined vars */
	char *inFile = NULL;
	char *outFile = NULL;
	char *inCertName = NULL;
	char *issuerCertName = NULL;
	SecAsn1OCSPCertStatusTag certStatus = CS_Good;
	CE_CrlReason crlReason = CE_CR_Unspecified;
	char *kcName = NULL;
	bool verbose = false;
	bool doParse = false;
	const char *responderURI = NULL;
	
    extern int optind;
	optind = 2;
    extern char *optarg;
	int arg;
    while ((arg = getopt(argc, argv, "c:C:i:o:s:r:k:phvu:")) != -1) {
		switch (arg) {
			case 'c':
				inCertName = optarg;
				break;
			case 'C':
				issuerCertName = optarg;
				break;
			case 'i':
				inFile = optarg;
				break;
			case 'o':
				outFile = optarg;
				break;
			case 's':
				switch(optarg[0]) {
					case 'g':
						certStatus = CS_Good;
						break;
					case 'r':
						certStatus = CS_Revoked;
						break;
					case 'u':
						certStatus = CS_Unknown;
						break;
					default:
						printf("***Unrecognized certStatus***\n");
						usage(argv);
				}
				break;
			case 'r':
				crlReason = atoi(optarg);
				break;
			case 'k':
				kcName = optarg;
				break;
			case 'v':
				verbose = 1;
				break;
			case 'p':
				doParse = true;
				break;
			case 'u':
				responderURI = optarg;
				break;
			default:
			case '?':
				usage(argv);
		}
	}
	if(optind != argc) {
		/* this happens if you give getopt() an arg which doesn't start with '-' */
		usage(argv);
	}
	
	unsigned char *certData = NULL;
	unsigned certDataLen = 0;
	unsigned char *issuerCertData = NULL;
	unsigned issuerCertDataLen = 0;
	unsigned char *inData = NULL;
	unsigned inDataLen = 0;
	unsigned char *outData = NULL;
	unsigned outDataLen = 0;
	SecKeychainRef kcRef = NULL;
	OSStatus ortn;
	
	if(inCertName) {
		if(readFile(inCertName, &certData, &certDataLen)) {
			printf("***Error reading cert file %s. Aborting.\n", inCertName);
			exit(1);
		}
	}
	if(issuerCertName) {
		if(readFile(issuerCertName, &issuerCertData, &issuerCertDataLen)) {
			printf("***Error reading cert file %s. Aborting.\n", issuerCertName);
			exit(1);
		}
	}
	if(inFile) {
		if(readFile(inFile, &inData, &inDataLen)) {
			printf("***Error reading input file %s. Aborting.\n", inFile);
			exit(1);
		}
	}
	if(kcName) {
		ortn = SecKeychainOpen(kcName, &kcRef);
		if(ortn) {
			cssmPerror("SecKeychainOpen", ortn);
			return ortn;
		}
	}
	CSSM_CL_HANDLE clHand = cuClStartup();
	
	switch(op) {
		case op_genReq:
			ortn = genOcspReq(clHand, certData, certDataLen, 
				issuerCertData, issuerCertDataLen,
				&outData, &outDataLen);
			break;
		case op_parseReq:
			ortn = parseOcspReq(clHand, inData, inDataLen, verbose);
			break;
		case op_genReply:
		{
			SecIdentityRef idRef = NULL;
			ortn = sslSimpleIdentPicker(kcRef, &idRef);
			if(ortn) {
				printf("***Error choosing identity. Aborting.\n");
				exit(1);
			}
			ortn = genOcspResp(clHand, certStatus, crlReason,
				certData, certDataLen, issuerCertData, issuerCertDataLen,
				idRef, &outData, &outDataLen);
			CFRelease(idRef);
			break;
		}
		case op_parseResp:
			ortn = parseOcspResp(clHand, inData, inDataLen, verbose);
			break;
		case op_post:
			ortn = postOcspReq(clHand, certData, certDataLen, 
				issuerCertData, issuerCertDataLen, responderURI,
				doParse, verbose,
				&outData, &outDataLen);
			break;
		default:	
			printf("Op %s is not yet implemented.\n", argv[1]);
			exit(1);
	}
	
	if(ortn == 0) {
		if(outData != NULL) {
			if(outFile== NULL) {
				printf("...generated %u bytes but no place to write it.\n", outDataLen);
			}
			else {
				ortn = writeFile(outFile, outData, outDataLen);
				if(ortn) {
					printf("***Error writing output to %s.\n", outFile);
				}
				else {
					printf("...wrote %u bytes to %s\n", outDataLen, outFile);
				}
			}
		}
	}
	return ortn;
}
int main(int argc, char **argv)
{
	char *kcName = NULL;
	SecKeychainRef kcRef = NULL;
	char *prefName = NULL;
	bool doSet = false;
	
	if((argc < 2) || (argv[1][0] == 'h')) {
		usage(argv);
	}
	if(!strcmp(argv[1], "get")) {
		doSet = false;
	}
	else if(!strcmp(argv[1], "set")) {
		doSet = true;
	}
	else {
		printf("Bad op argument\n");
		usage(argv);
	}
	
	extern int optind;
	optind = 2;
	extern char *optarg;
	int arg;
	while ((arg = getopt(argc, argv, "p:k:h")) != -1) {
		switch (arg) {
			case 'p':
				prefName = optarg;
				break;
			case 'k':
				kcName = optarg;
				break;
			case 'h':
				usage(argv);
		}
	}
	if(optind != argc) {
		usage(argv);
	}
	if(prefName == NULL) {
		printf("***You must specify a preference name via -p.\n");
		usage(argv);
	}
	CFStringRef prefStr = CFStringCreateWithCString(NULL, prefName, kCFStringEncodingASCII);
	if(prefStr == NULL) {
		printf("***Error converting pref name '%s' to CFString.\n", prefName);
		exit(1);
	}
	
	OSStatus ortn;
	if(kcName) {
		ortn = SecKeychainOpen(kcName, &kcRef);
		if(ortn) {
			cssmPerror("SecKeychainOpen", ortn);
			exit(1);
		}
	}
	
	SecIdentityRef idRef = NULL;
	if(doSet) {
		ortn = sslSimpleIdentPicker(kcRef, &idRef);
		if(ortn) {
			printf("Error picking identity; aborting.\n");
			exit(1);
		}
		ortn = SecIdentitySetPreference(idRef, prefStr, 0);
		if(ortn) {
			cssmPerror("SecIdentitySetPreference", ortn);
			exit(1);
		}
		printf("...Identity preference set for name '%s'.\n", prefName);
	}
	else {
		ortn = SecIdentityCopyPreference(prefStr, 0, NULL, &idRef);
		if(ortn) {
			cssmPerror("SecIdentityCopyPreference", ortn);
		}
		else {
			SecCertificateRef certRef = NULL;
			ortn = SecIdentityCopyCertificate(idRef, &certRef);
			if(ortn) {
				cssmPerror("SecIdentityCopyCertificate", ortn);
				exit(1);
			}
			char *idName = kcItemPrintableName((SecKeychainItemRef)certRef);
			printf("Identity for prefName '%s' found : '%s'\n", 
				prefName, idName);
			free(idName);
			CFRelease(certRef);
		}
	}
	CFRelease(idRef);
	
	return 0;
}
int main(int argc, char **argv)
{
	/* user-spec'd variables */
	const char 		*kcName = DEFAULT_KC;
	unsigned 		xferSize = XFERSIZE_DEF;
	int 			port = PORT_DEF;
	const char 		*hostName = HOST_DEF;
	SSLCipherSuite 	cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA;
	SSLProtocol 	prot = kTLSProtocol1Only;
	char 			password[200];
	bool 			clientAuthEnable = false;
	bool 			isServer = false;
	unsigned 		bufSize = BUFSIZE;
	bool			diffieHellman = false;
	int				nonBlocking = 0;
	
	if(argc < 2) {
		usage(argv);
	}
	password[0] = 0;
	switch(argv[1][0]) {
		case 's':
			isServer = true;
			break;
		case 'c':
			isServer = false;
			break;
		default:
			usage(argv);
	}
	
	extern int optind;
	extern char *optarg;
	int arg;
	optind = 2;
	while ((arg = getopt(argc, argv, "h:p:k:x:c:v:w:b:aB")) != -1) {
		switch (arg) {
			case 'h':
				hostName = optarg;
				break;
			case 'p':
				port = atoi(optarg);
				break;
			case 'k':
				kcName = optarg;
				break;
			case 'x':
				xferSize = atoi(optarg);
				break;
			case 'c':
				if(!isServer) {
					printf("***Specify cipherSuite on server side.\n");
					exit(1);
				}
				switch(optarg[0]) {
					case 'r':
						cipherSuite = SSL_RSA_WITH_RC4_128_SHA;
						break;
					case 'd':
						cipherSuite = SSL_RSA_WITH_DES_CBC_SHA;
						break;
					case 'D':
						cipherSuite = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
						break;
					case 'h':
						cipherSuite = SSL_DH_anon_WITH_RC4_128_MD5;
						diffieHellman = true;
						break;
					case 'H':
						cipherSuite = SSL_DHE_DSS_WITH_DES_CBC_SHA;
						diffieHellman = true;
						break;
					case 'A':
						cipherSuite = TLS_RSA_WITH_AES_256_CBC_SHA;
						break;
					default:
						usage(argv);
				}
				break;
			case 'v':
				if(!isServer) {
					printf("***Specify protocol on server side.\n");
					exit(1);
				}
				switch(optarg[0]) {
					case 't':
						prot = kTLSProtocol1Only;
						break;
					case '2':
						prot = kSSLProtocol2;
						break;
					case '3':
						prot = kSSLProtocol3Only;
						break;
					default:
						usage(argv);
				}
				break;
			case 'w':
				strcpy(password, optarg);
				break;
			case 'b':
				bufSize = atoi(optarg);
				break;
			case 'a':
				clientAuthEnable = true;
				break;
			case 'B':
				nonBlocking = 1;
				break;
			default:
				usage(argv);
		}
	}
	
	/* per-transfer buffer - make it random for server */
	char *buf = (char *)malloc(bufSize);
	if(isServer) {
		Security::DevRandomGenerator rng;
		rng.random(buf, bufSize);
	}
	
	/* gather Diffie-Hellman params from cwd */
	unsigned char *dhParams = NULL;
	unsigned dhParamsLen = 0;
	if(diffieHellman && isServer) {
		if(readFile(DH_PARAM_FILE, &dhParams, &dhParamsLen)) {
			printf("***Error reading Diffie-Hellman Params. Prepare to "
				"wait for a minute during SSL handshake.\n");
		}
	}
	
	/*
	 * Open keychain; both sides use the same one.
	 */
	OSStatus ortn;
	SecKeychainRef certKc = NULL;
	CFAbsoluteTime kcOpenStart = CFAbsoluteTimeGetCurrent();
	ortn = SecKeychainOpen(kcName, &certKc);
	if(ortn) {
		printf("Error opening keychain %s (%d); aborting.\n",
			kcName, (int)ortn);
		exit(1);
	}
	if(password[0]) {
		ortn = SecKeychainUnlock(certKc, strlen(password), password, true);
		if(ortn) {
			printf("SecKeychainUnlock returned %d\n", (int)ortn);
			/* oh well */
		}
	}
	CFAbsoluteTime kcOpenEnd = CFAbsoluteTimeGetCurrent();
	
	otSocket peerSock = 0;
	otSocket listenSock = 0;			// for server only
    PeerSpec peerId;
	
	if(isServer) {
		printf("...listening for client connection on port %d\n", port);
		ortn = ListenForClients(port, nonBlocking, &listenSock);
		if(ortn) {
			printf("...error establishing a listen socket. Aborting.\n");
			exit(1);
		}
		ortn = AcceptClientConnection(listenSock, &peerSock, &peerId);
		if(ortn) {
			printf("...error listening for connection. Aborting.\n");
			exit(1);
		}
	}
	else {
		printf("...connecting to host %s at port %d\n", hostName, port);
		ortn = MakeServerConnection(hostName, port, nonBlocking, &peerSock,
			&peerId);
		if(ortn) {
			printf("...error connecting to server %s. Aborting.\n",
				hostName);
			exit(1);
		}
	}

	/* start timing SSL setup */
	CFAbsoluteTime setupStart = CFAbsoluteTimeGetCurrent();

	SSLContextRef ctx;
	ortn = SSLNewContext(isServer, &ctx);
	if(ortn) {
		printSslErrStr("SSLNewContext", ortn);
		exit(1);
	} 
	ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
	if(ortn) {
		printSslErrStr("SSLSetIOFuncs", ortn);
		exit(1);
	} 
	ortn = SSLSetConnection(ctx, (SSLConnectionRef)peerSock);
	if(ortn) {
		printSslErrStr("SSLSetConnection", ortn);
		exit(1);
	}
	ortn = SSLSetPeerDomainName(ctx, hostName, strlen(hostName) + 1);
	if(ortn) {
		printSslErrStr("SSLSetPeerDomainName", ortn);
		exit(1);
	}	
	
	/*
	 * Server/client specific setup.
	 *
	 * Client uses the same keychain as server, but it uses it for 
	 * sslAddTrustedRoots() instead of getSslCerts() and 
	 * SSLSetCertificate().
	 */
	CFArrayRef myCerts = NULL;
	if(clientAuthEnable || isServer) {
		myCerts = sslKcRefToCertArray(certKc, CSSM_FALSE, CSSM_FALSE, NULL, NULL);
		if(myCerts == NULL) {
			exit(1);
		}
		ortn = addIdentityAsTrustedRoot(ctx, myCerts);
		if(ortn) {
			exit(1);
		}
		ortn = SSLSetCertificate(ctx, myCerts);
		if(ortn) {
			printSslErrStr("SSLSetCertificate", ortn);
			exit(1);
		}
	}
	if(isServer) {
		SSLAuthenticate auth;
		if(clientAuthEnable) {
			auth = kAlwaysAuthenticate;
		}
		else {
			auth = kNeverAuthenticate;
		}
		ortn = SSLSetClientSideAuthenticate(ctx, auth);
		if(ortn) {
			printSslErrStr("SSLSetClientSideAuthenticate", ortn);
			exit(1);
		}
		ortn = SSLSetEnabledCiphers(ctx, &cipherSuite, 1);
		if(ortn) {
			printSslErrStr("SSLSetEnabledCiphers", ortn);
			exit(1);
		}
		ortn = SSLSetProtocolVersion(ctx, prot);
		if(ortn) {
			printSslErrStr("SSLSetProtocolVersion", ortn);
			exit(1);
		}
		if(dhParams != NULL) {
			ortn = SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen);
			if(ortn) {
				printSslErrStr("SSLSetDiffieHellmanParams", ortn);
				exit(1);
			}
		}
	}
	else {
		/* client setup */
		if(!clientAuthEnable) {
			/* We're not presenting a cert; trust the server certs */
			bool foundOne;
			ortn = sslAddTrustedRoots(ctx, certKc, &foundOne);
			if(ortn) {
				printSslErrStr("sslAddTrustedRoots", ortn);
				exit(1);
			}
		}
	}
	
	/*
	 * Context setup complete. Start timing handshake.
	 */
	CFAbsoluteTime hshakeStart = CFAbsoluteTimeGetCurrent();
    do {   
		ortn = SSLHandshake(ctx);
    } while (ortn == errSSLWouldBlock);
	if(ortn) {
		printSslErrStr("SSLHandshake", ortn);
		exit(1);
	}
	CFAbsoluteTime hshakeEnd = CFAbsoluteTimeGetCurrent();
	
	/* snag these before data xfer possibly shuts down connection */
	SSLProtocol	negVersion;
	SSLCipherSuite negCipher;
	SSLClientCertificateState certState;		// RETURNED

	SSLGetNegotiatedCipher(ctx, &negCipher);
	SSLGetNegotiatedProtocolVersion(ctx, &negVersion);
	SSLGetClientCertificateState(ctx, &certState);
	
	/* server sends xferSize bytes to client and shuts down */
	size_t bytesMoved;
	
	CFAbsoluteTime dataStart = CFAbsoluteTimeGetCurrent();
	size_t totalMoved = 0;
	if(isServer) {
		size_t bytesToGo = xferSize;
		bool done = false;
		do {
			size_t thisMove = bufSize;
			if(thisMove > bytesToGo) {
				thisMove = bytesToGo;
			}
			ortn = SSLWrite(ctx, buf, thisMove, &bytesMoved);
			switch(ortn) {
				case noErr:
				case errSSLWouldBlock:
					break;
				default:
					done = true;
					break;
			}
			bytesToGo -= bytesMoved;
			totalMoved += bytesMoved;
			if(bytesToGo == 0) {
				done = true;
			}
		} while(!done);
		if(ortn != noErr) {
			printSslErrStr("SSLWrite", ortn);
			exit(1);
		}
	}
	else {
		/* client reads until error or errSSLClosedGraceful */
		bool done = false;
		do {
			ortn = SSLRead(ctx, buf, bufSize, &bytesMoved);
			switch(ortn) {
				case errSSLClosedGraceful:
					done = true;
					break;
				case noErr:
				case errSSLWouldBlock:
					break;
				default:
					done = true;
					break;
			}
			totalMoved += bytesMoved;
		} while(!done);
		if(ortn != errSSLClosedGraceful) {
			printSslErrStr("SSLRead", ortn);
			exit(1);
		}
	}
	
	/* shut down channel */
	ortn = SSLClose(ctx);
	if(ortn) {
		printSslErrStr("SSLCLose", ortn);
		exit(1);
	}
	CFAbsoluteTime dataEnd = CFAbsoluteTimeGetCurrent();

	/* how'd we do? */
	printf("SSL version          : %s\n", 
		sslGetProtocolVersionString(negVersion));
	printf("CipherSuite          : %s\n",
		sslGetCipherSuiteString(negCipher));
	printf("Client Cert State    : %s\n",
			sslGetClientCertStateString(certState));

	if(password[0]) {
		printf("keychain open/unlock : ");
	}
	else {
		printf("keychain open        : ");
	}
	printf("%f s\n", kcOpenEnd - kcOpenStart);
	printf("SSLContext setup     : %f s\n", hshakeStart - setupStart);
	printf("SSL Handshake        : %f s\n", hshakeEnd - hshakeStart);
	printf("Data Transfer        : %u bytes in %f s\n", (unsigned)totalMoved, 
		dataEnd - dataStart);
	printf("                     : %.1f Kbytes/s\n", 
			totalMoved / (dataEnd - dataStart) / 1024.0);
	return 0;
}
static void tests(void)
{
	char *home = getenv("HOME");
	char kcname1[256], kcname2[256];
	SecKeychainStatus status1, status2;

	if (!home || strlen(home) > 200)
		plan_skip_all("home too big");

	sprintf(kcname1, "%s/kctests/kc1/kc1", home);
	SecKeychainRef kc1 = NULL, kc2 = NULL;
    kc1 = createNewKeychainAt(kcname1, "test");

	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	is(status1, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus,
		"status unlocked readable writable");
	ok_status(SecKeychainLock(kc1), "SecKeychainLock kc1");
	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	TODO: {
		todo("<rdar://problem/2668794> KeychainImpl::status() returns "
			"incorrect status (always writable?)");

		is(status1, kSecReadPermStatus|kSecWritePermStatus,
			"status (locked) readable writable");
	}

	/* Make keychain non writable. */
	char kcdir1[256];
	sprintf(kcdir1, "%s/kctests/kc1", home);
	ok_unix(chmod(kcdir1, 0555), "chmod kcdir1 0555");

	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	is(status1, kSecReadPermStatus, "status (locked) readable");
	ok_status(SecKeychainUnlock(kc1, 4, "test", TRUE), "SecKeychainLock kc1");
	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	TODO: {
		todo("<rdar://problem/2668794> KeychainImpl::status() returns "
			"incorrect status (always writable?)");

		is(status1, kSecUnlockStateStatus|kSecReadPermStatus,
			"status unlocked readable");
	}

	/* Reopen the keychain. */
	CFRelease(kc1);
	ok_status(SecKeychainOpen(kcname1, &kc1), "SecKeychainOpen kc1");

	ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status");
	TODO: {
		todo("<rdar://problem/2668794> KeychainImpl::status() returns "
			"incorrect status (always writable?)");

		is(status1, kSecUnlockStateStatus|kSecReadPermStatus,
			"status unlocked readable");
	}

	sprintf(kcname2, "%s/kctests/kc2/kc2", home);
    kc2 = createNewKeychainAt(kcname2, "test");
	ok_unix(chmod(kcname2, 0444), "chmod kc2 0444");
	ok_status(SecKeychainGetStatus(kc2, &status2), "get kc2 status");
	is(status2, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus,
		"status unlocked readable writable");

	/* Reopen the keychain. */
	CFRelease(kc2);
	ok_status(SecKeychainOpen(kcname2, &kc2), "SecKeychainOpen kc2");

	ok_status(SecKeychainGetStatus(kc2, &status2), "get kc2 status");
	is(status2, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus,
		"status unlocked readable writable");

	/* Restore dir to writable so cleanup code will work ok. */
	ok_unix(chmod(kcdir1, 0755), "chmod kcdir1 0755");
    ok_status(SecKeychainDelete(kc1), "%s: SecKeychainDelete", testName);
	CFRelease(kc1);
    ok_status(SecKeychainDelete(kc2), "%s: SecKeychainDelete", testName);
	CFRelease(kc2);

	bool testWithFreshlyCreatedKeychain = true;
	SecKeychainRef keychain = createNewKeychain("test", "test");
	ok_status(SecKeychainLock(keychain), "SecKeychainLock");

	do {
		SecKeychainStatus keychainStatus = 0;
		is_status(SecKeychainUnlock(keychain, 0, NULL, true), -25293, "SecKeychainUnlock with NULL password (incorrect)");
		ok_status(SecKeychainGetStatus(keychain, &keychainStatus), "SecKeychainGetStatus");
		is( (keychainStatus & kSecUnlockStateStatus), 0, "Check it's not unlocked");

		keychainStatus = 0;
		ok_status(SecKeychainUnlock(keychain, strlen("test"), "test", true), "SecKeychainUnlock with correct password");
		ok_status(SecKeychainGetStatus(keychain, &keychainStatus), "SecKeychainGetStatus");
		is( (keychainStatus & kSecUnlockStateStatus), kSecUnlockStateStatus, "Check it's unlocked");
		
		ok_status(SecKeychainLock(keychain), "SecKeychainLock");

		if (testWithFreshlyCreatedKeychain)
		{
        CFRelease(keychain);
			testWithFreshlyCreatedKeychain = false;
			ok_status(SecKeychainOpen("test", &keychain), "SecKeychainOpen");
		}
        else {
			testWithFreshlyCreatedKeychain = true;

            ok_status(SecKeychainDelete(keychain), "%s: SecKeychainDelete", testName);
            CFReleaseNull(keychain);
        }
		
	}
	while(!testWithFreshlyCreatedKeychain);

}