Beispiel #1
0
/* Reads certificates from the list of known locations into store.  Stops when
 * any location contains any certificates, to prevent spending unnecessary time
 * adding redundant certificates, e.g. when both a certificate bundle and
 * individual certificates exist in the same directory.
 */
static void read_trusted_roots_from_known_locations(HCERTSTORE store)
{
    HCERTSTORE from = CertOpenStore(CERT_STORE_PROV_MEMORY,
     X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);

    if (from)
    {
        DWORD i;
        BOOL ret = FALSE;

#ifdef HAVE_SECURITY_SECURITY_H
        OSStatus status;
        CFArrayRef rootCerts;

        status = SecTrustCopyAnchorCertificates(&rootCerts);
        if (status == noErr)
        {
            int i;
            for (i = 0; i < CFArrayGetCount(rootCerts); i++)
            {
                SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(rootCerts, i);
                CFDataRef certData;
                if ((status = SecKeychainItemExport(cert, kSecFormatX509Cert, 0, NULL, &certData)) == noErr)
                {
                    if (CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
                            CFDataGetBytePtr(certData), CFDataGetLength(certData),
                            CERT_STORE_ADD_NEW, NULL))
                        ret = TRUE;
                    else
                        WARN("adding root cert %d failed: %08x\n", i, GetLastError());
                    CFRelease(certData);
                }
                else
                    WARN("could not export certificate %d to X509 format: 0x%08x\n", i, (unsigned int)status);
            }
            CFRelease(rootCerts);
        }
#endif

        for (i = 0; !ret &&
         i < sizeof(CRYPT_knownLocations) / sizeof(CRYPT_knownLocations[0]);
         i++)
            ret = import_certs_from_path(CRYPT_knownLocations[i], from, TRUE);
        check_and_store_certs(from, store);
    }
    CertCloseStore(from, 0);
}
Beispiel #2
0
SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session,
                                                       PCCERT_CONTEXT *cert)
{
    struct mac_session* s = (struct mac_session*)session;
    SECURITY_STATUS ret = SEC_E_INTERNAL_ERROR;
    CFArrayRef certs;
    OSStatus status;

    TRACE("(%p/%p, %p)\n", s, s->context, cert);

    status = SSLCopyPeerCertificates(s->context, &certs);
    if (status == noErr && certs)
    {
        SecCertificateRef mac_cert;
        CFDataRef data;
        if (CFArrayGetCount(certs) &&
            (mac_cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, 0)) &&
            (SecKeychainItemExport(mac_cert, kSecFormatX509Cert, 0, NULL, &data) == noErr))
        {
            *cert = CertCreateCertificateContext(X509_ASN_ENCODING,
                    CFDataGetBytePtr(data), CFDataGetLength(data));
            if (*cert)
                ret = SEC_E_OK;
            else
            {
                ret = GetLastError();
                WARN("CertCreateCertificateContext failed: %x\n", ret);
            }
            CFRelease(data);
        }
        else
            WARN("Couldn't extract certificate data\n");
        CFRelease(certs);
    }
    else
        WARN("SSLCopyPeerCertificates failed: %ld\n", (long)status);

    return ret;
}
Beispiel #3
0
SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store,
                                                       PCCERT_CONTEXT *ret_cert)
{
    struct mac_session* s = (struct mac_session*)session;
    SECURITY_STATUS ret = SEC_E_OK;
    PCCERT_CONTEXT cert = NULL;
    SecCertificateRef mac_cert;
    CFArrayRef cert_array;
    int status;
    CFIndex cnt, i;
    CFDataRef data;
    BOOL res;

    TRACE("(%p/%p, %p)\n", s, s->context, cert);

#ifdef HAVE_SSLCOPYPEERCERTIFICATES
    status = SSLCopyPeerCertificates(s->context, &cert_array);
#else
    status = SSLGetPeerCertificates(s->context, &cert_array);
#endif
    if (status != noErr || !cert_array)
    {
        WARN("SSLCopyPeerCertificates failed: %d\n", status);
        return SEC_E_INTERNAL_ERROR;
    }

    cnt = CFArrayGetCount(cert_array);
    for (i=0; i < cnt; i++) {
        if (!(mac_cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, i)) ||
            (SecKeychainItemExport(mac_cert, kSecFormatX509Cert, 0, NULL, &data) != noErr))
        {
            WARN("Couldn't extract certificate data\n");
            ret = SEC_E_INTERNAL_ERROR;
            break;
        }

        res = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, CFDataGetBytePtr(data), CFDataGetLength(data),
                                               CERT_STORE_ADD_REPLACE_EXISTING, i ? NULL : &cert);
        CFRelease(data);
        if (!res)
        {
            ret = GetLastError();
            WARN("CertAddEncodedCertificateToStore failed: %x\n", ret);
            break;
        }
    }

#ifndef HAVE_SSLCOPYPEERCERTIFICATES
    /* This is why SSLGetPeerCertificates was deprecated */
    CFArrayApplyFunction(cert_array, CFRangeMake(0, CFArrayGetCount(cert_array)),
                         schan_imp_cf_release, NULL);
#endif
    CFRelease(cert_array);
    if (ret != SEC_E_OK) {
        if(cert)
            CertFreeCertificateContext(cert);
        return ret;
    }

    *ret_cert = cert;
    return SEC_E_OK;
}
int main(int argc, char **argv)
{
	bool verbose = false;
	
	int arg;
	while ((arg = getopt(argc, argv, "vh")) != -1) {
		switch (arg) {
			case 'v':
				verbose = true;
				break;
			case 'h':
				usage(argv);
		}
	}
	if(optind != argc) {
		usage(argv);
	}
	
	printNoDialog();
	
	/* initial setup */
	verboseDisp(verbose, "deleting keychain");
	unlink(KEYCHAIN_NAME);
	
	verboseDisp(verbose, "creating keychain");
	SecKeychainRef kcRef = NULL;
	OSStatus ortn = SecKeychainCreate(KEYCHAIN_NAME, 
		strlen(KEYCHAIN_PWD), KEYCHAIN_PWD,
		false, NULL, &kcRef);
	if(ortn) {
		cssmPerror("SecKeychainCreate", ortn);
		exit(1);
	}

	/* 
	 * 1. Generate key pair with cleartext public key.
	 *    Ensure we can use the public key when keychain is locked with no
	 *    user interaction.  
	 */
	 
	/* generate key pair, cleartext public key */
	verboseDisp(verbose, "creating key pair, cleartext public key");
	SecKeyRef pubKeyRef = NULL;
	SecKeyRef privKeyRef = NULL;
	if(genKeyPair(false, kcRef, &pubKeyRef, &privKeyRef)) {
		exit(1);
	}
	
	/* Use generated cleartext public key with locked keychain */
	verboseDisp(verbose, "locking keychain, exporting public key");
	SecKeychainLock(kcRef);
	CFDataRef exportData = NULL;
	ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
	if(ortn) {
		cssmPerror("SecKeychainCreate", ortn);
		exit(1);
	}
	CFRelease(exportData);
	
	verboseDisp(verbose, "locking keychain, encrypting with public key");
	SecKeychainLock(kcRef);
	if(pubKeyEncrypt(pubKeyRef)) {
		exit(1);
	}

	/* reset */
	verboseDisp(verbose, "deleting keys");
	ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	ortn = SecKeychainItemDelete((SecKeychainItemRef)privKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	CFRelease(pubKeyRef);
	CFRelease(privKeyRef);

	/* 
	 * 2. Generate key pair with encrypted public key.
	 *    Ensure that user interaction is required when we use the public key 
	 *    when keychain is locked.
	 */

	verboseDisp(verbose, "programmatically unlocking keychain");
	ortn = SecKeychainUnlock(kcRef, strlen(KEYCHAIN_PWD), KEYCHAIN_PWD, TRUE);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	
	/* generate key pair, encrypted public key */
	verboseDisp(verbose, "creating key pair, encrypted public key");
	if(genKeyPair(true, kcRef, &pubKeyRef, &privKeyRef)) {
		exit(1);
	}

	/* Use generated encrypted public key with locked keychain */
	verboseDisp(verbose, "locking keychain, exporting public key");
	SecKeychainLock(kcRef);
	printExpectDialog();
	ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
	if(ortn) {
		cssmPerror("SecKeychainCreate", ortn);
		exit(1);
	}
	/* we'll use that exported blob later to test import */
	if(!didGetDialog()) {
		exit(1);
	}
	
	verboseDisp(verbose, "locking keychain, encrypting with public key");
	SecKeychainLock(kcRef);
	printExpectDialog();
	if(pubKeyEncrypt(pubKeyRef)) {
		exit(1);
	}
	if(!didGetDialog()) {
		exit(1);
	}

	/* reset */
	printNoDialog();
	verboseDisp(verbose, "locking keychain");
	SecKeychainLock(kcRef);
	verboseDisp(verbose, "deleting keys");
	ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	ortn = SecKeychainItemDelete((SecKeychainItemRef)privKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	CFRelease(pubKeyRef);
	CFRelease(privKeyRef);

	/* 
	 * 3. Import public key, storing in cleartext. Ensure that the import
	 *    doesn't require unlock, and ensure we can use the public key 
	 *    when keychain is locked with no user interaction.  
	 */

	printNoDialog();
	verboseDisp(verbose, "locking keychain");
	SecKeychainLock(kcRef);

	/* import public key - default is in the clear */
	verboseDisp(verbose, "importing public key, store in the clear (default)");
	CFArrayRef outArray = NULL;
	SecExternalFormat format = kSecFormatOpenSSL;
	SecExternalItemType type = kSecItemTypePublicKey;
	ortn = SecKeychainItemImport(exportData, 
		NULL, &format, &type,
		0, NULL,
		kcRef, &outArray);
	if(ortn) {
		cssmPerror("SecKeychainItemImport", ortn);
		exit(1);
	}
	CFRelease(exportData);
	if(CFArrayGetCount(outArray) != 1) {
		printf("***Unexpected outArray size (%ld) after import\n",
			(long)CFArrayGetCount(outArray));
		exit(1);
	}
	pubKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
	if(CFGetTypeID(pubKeyRef) != SecKeyGetTypeID()) {
		printf("***Unexpected item type after import\n");
		exit(1);
	}
	
	/* Use imported cleartext public key with locked keychain */
	verboseDisp(verbose, "locking keychain, exporting public key");
	SecKeychainLock(kcRef);
	exportData = NULL;
	ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
	if(ortn) {
		cssmPerror("SecKeychainItemExport", ortn);
		exit(1);
	}
	/* we'll use exportData again */
	
	verboseDisp(verbose, "locking keychain, encrypting with public key");
	SecKeychainLock(kcRef);
	if(pubKeyEncrypt(pubKeyRef)) {
		exit(1);
	}

	/* reset */
	verboseDisp(verbose, "deleting key");
	ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
	if(ortn) {
		cssmPerror("SecKeychainItemDelete", ortn);
		exit(1);
	}
	CFRelease(pubKeyRef);
	
	/* 
	 * Import public key, storing in encrypted form.
	 * Ensure that user interaction is required when we use the public key 
	 * when keychain is locked.
	 */

	/* import public key, encrypted in the keychain */
	SecKeyImportExportParameters impExpParams;
	memset(&impExpParams, 0, sizeof(impExpParams));
	impExpParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
	impExpParams.keyAttributes = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | 
								 CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT;
	verboseDisp(verbose, "importing public key, store encrypted");
	printExpectDialog();
	outArray = NULL;
	format = kSecFormatOpenSSL;
	type = kSecItemTypePublicKey;
	ortn = SecKeychainItemImport(exportData, 
		NULL, &format, &type,
		0, &impExpParams,
		kcRef, &outArray);
	if(ortn) {
		cssmPerror("SecKeychainItemImport", ortn);
		exit(1);
	}
	if(!didGetDialog()) {
		exit(1);
	}
	CFRelease(exportData);
	if(CFArrayGetCount(outArray) != 1) {
		printf("***Unexpected outArray size (%ld) after import\n",
			(long)CFArrayGetCount(outArray));
		exit(1);
	}
	pubKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
	if(CFGetTypeID(pubKeyRef) != SecKeyGetTypeID()) {
		printf("***Unexpected item type after import\n");
		exit(1);
	}
					
	/* Use imported encrypted public key with locked keychain */
	verboseDisp(verbose, "locking keychain, exporting public key");
	SecKeychainLock(kcRef);
	printExpectDialog();
	ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
	if(ortn) {
		cssmPerror("SecKeychainItemExport", ortn);
		exit(1);
	}
	if(!didGetDialog()) {
		exit(1);
	}
	CFRelease(exportData);
	
	verboseDisp(verbose, "locking keychain, encrypting with public key");
	SecKeychainLock(kcRef);
	printExpectDialog();
	if(pubKeyEncrypt(pubKeyRef)) {
		exit(1);
	}
	if(!didGetDialog()) {
		exit(1);
	}

	SecKeychainDelete(kcRef);
	printf("...test succeeded.\n");
	return 0;
}
static int testExtractable(
    SecKeychainRef keychain,
	Boolean extractable,
	Boolean explicit)
{
	OSStatus status;
	SecKeyRef publicKeyRef = NULL;
	SecKeyRef privateKeyRef = NULL;
	CFStringRef label = (extractable) ? CFSTR("test-extractable-YES") : CFSTR("test-extractable-NO");
	Boolean *extractablePtr = (explicit) ? &extractable : NULL;

    status = GenerateRSAKeyPair(keychain,
                                label,
								1024, // size
								extractablePtr,
								&publicKeyRef,
								&privateKeyRef);

	if (status != noErr) {
        //errx(EXIT_FAILURE, "Unable to get key pair (err = %d)", status);
        return status;
	}

	// check that the attributes of the generated private key are what we think they are
	const CSSM_KEY *cssmPrivKey;
	status = SecKeyGetCSSMKey(privateKeyRef, &cssmPrivKey);
    ok_status(status, "%s: SecKeyGetCSSMKey", testName);

	if (status != noErr) {
        //errx(EXIT_FAILURE, "Unable to get CSSM reference key (err = %d)", status);
        return status;
	}
	if (extractable) {
        ok(cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE, "%s: check private key marked as extractable (as requested)", testName);
		if (!(cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
            //errx(EXIT_FAILURE, "Oops! the private key was not marked as extractable!");
            return 1;
		}
	}
	else {
        ok(!(cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE), "%s: check private key marked as non-extractable (as requested)", testName);
		if (cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE) {
            //errx(EXIT_FAILURE, "Oops! the private key was marked as extractable!");
            return 1;
		}
	}

	SecKeyImportExportParameters keyParams;
	memset(&keyParams, 0, sizeof(keyParams));
	keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
	keyParams.passphrase = CFSTR("borken");

	CFDataRef exportedData = NULL;

    status = SecKeychainItemExport(privateKeyRef, kSecFormatWrappedPKCS8, 0, &keyParams, &exportedData);
    if(extractable) {
        ok_status(status, "%s: SecKeychainItemExport (PKCS8) (and we expected it to succeed)", testName);
    } else {
        is(status, errSecDataNotAvailable, "%s: SecKeychainItemExport (PKCS8) (and we expected this to fail with errSecDataNotAvailable)", testName);
    }

    status = SecKeychainItemExport(privateKeyRef, kSecFormatPKCS12, 0, &keyParams, &exportedData);
    if(extractable) {
        ok_status(status, "%s: SecKeychainItemExport(and we expected it to succeed)", testName);
    } else {
        is(status, errSecDataNotAvailable, "%s: SecKeychainItemExport (PKCS12)  (and we expected this to fail with errSecDataNotAvailable)", testName);
    }

	if (status != noErr) {
		if (extractable) {
			//errx(EXIT_FAILURE, "Unable to export extractable key! (err = %d)", status);
            return 1;
		}
		else {
			status = 0; // wasn't extractable, so this is the expected result
		}
	}
	else if (status == noErr && !extractable) {
		//errx(EXIT_FAILURE, "Was able to export non-extractable key! (err = %d)", status);
        return 1;
	}

	status = SecKeychainItemDelete((SecKeychainItemRef)publicKeyRef);
    ok_status(status, "%s: SecKeychainItemDelete", testName);
	if (status != noErr) {
		warnx("Unable to delete created public key from keychain (err = %d)", (int)status);
	}

	status = SecKeychainItemDelete((SecKeychainItemRef)privateKeyRef);
    ok_status(status, "%s: SecKeychainItemDelete", testName);
	if (status != noErr) {
		warnx("Unable to delete created private key from keychain (err = %d)", (int)status);
	}

	CFRelease(publicKeyRef);
	CFRelease(privateKeyRef);

	return 0;
}
static int do_keychain_export(
	SecKeychainRef		kcRef,
	SecExternalFormat   externFormat,
	ItemSpec			itemSpec,
	const char			*passphrase,
	int					doPem,
	const char			*fileName)
{
	int result = 0;
	CFIndex numItems;
	unsigned numPrivKeys = 0;
	unsigned numPubKeys = 0;
	unsigned numCerts = 0;
	unsigned numIdents = 0;
	OSStatus ortn;
	uint32 expFlags = 0;		// SecItemImportExportFlags
	SecKeyImportExportParameters keyParams;
	CFStringRef	passStr = NULL;
	CFDataRef outData = NULL;
	unsigned len;

	/* gather items */
	CFMutableArrayRef exportItems = CFArrayCreateMutable(NULL, 0,
		&kCFTypeArrayCallBacks);
	switch(itemSpec) {
		case IS_Certs:
			ortn = addKcItems(kcRef, kSecCertificateItemClass, exportItems, &numCerts);
			if(ortn) {
				result = 1;
				goto loser;
			}
			break;

		case IS_PrivKeys:
			ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems,
				&numPrivKeys);
			if(ortn) {
				result = 1;
				goto loser;
			}
			break;

		case IS_PubKeys:
			ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PUBLIC_KEY, exportItems,
				&numPubKeys);
			if(ortn) {
				result = 1;
				goto loser;
			}
			break;

		case IS_AllKeys:
			ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems,
				&numPrivKeys);
			if(ortn) {
				result = 1;
				goto loser;
			}
			ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PUBLIC_KEY, exportItems,
				&numPubKeys);
			if(ortn) {
				result = 1;
				goto loser;
			}
			break;

		case IS_All:
			/* No public keys here - PKCS12 doesn't support them */
			ortn = addKcItems(kcRef, kSecCertificateItemClass, exportItems, &numCerts);
			if(ortn) {
				result = 1;
				goto loser;
			}
			ortn = addKcItems(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, exportItems,
				&numPrivKeys);
			if(ortn) {
				result = 1;
				goto loser;
			}
			break;

		case IS_Identities:
			ortn = addIdentities(kcRef, exportItems, &numIdents);
			if(ortn) {
				result = 1;
				goto loser;
			}
			if(numIdents) {
				numPrivKeys += numIdents;
				numCerts    += numIdents;
			}
			break;
		default:
			sec_error("Internal error parsing item_spec");
			result = 1;
			goto loser;
	}

	numItems = CFArrayGetCount(exportItems);
	if(externFormat == kSecFormatUnknown) {
		/* Use default export format per set of items */
		if(numItems > 1) {
			externFormat = kSecFormatPEMSequence;
		}
		else if(numCerts) {
			externFormat = kSecFormatX509Cert;
		}
		else {
			externFormat = kSecFormatOpenSSL;
		}
	}
	if(doPem) {
		expFlags |= kSecItemPemArmour;
	}

	/*
	 * Key related arguments, ignored if we're not exporting keys.
	 * Always specify some kind of passphrase - default is secure passkey.
	 */
	memset(&keyParams, 0, sizeof(keyParams));
	keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
	if(passphrase != NULL) {
		passStr = CFStringCreateWithCString(NULL, passphrase, kCFStringEncodingASCII);
		keyParams.passphrase = passStr;
	}
	else {
		keyParams.flags = kSecKeySecurePassphrase;
	}

	/* Go */
	ortn = SecKeychainItemExport(exportItems, externFormat, expFlags, &keyParams,
		&outData);
	if(ortn) {
		sec_perror("SecKeychainItemExport", ortn);
		result = 1;
		goto loser;
	}

	len = CFDataGetLength(outData);
	if(fileName) {
		int rtn = writeFile(fileName, CFDataGetBytePtr(outData), len);
		if(rtn == 0) {
			if(!do_quiet) {
				fprintf(stderr, "...%u bytes written to %s\n", len, fileName);
			}
		}
		else {
			sec_error("Error writing to %s: %s", fileName, strerror(errno));
			result = 1;
		}
	}
	else {
		int irtn = write(STDOUT_FILENO, CFDataGetBytePtr(outData), len);
		if(irtn != (int)len) {
			perror("write");
		}
	}
loser:
	if(exportItems) {
		CFRelease(exportItems);
	}
	if(passStr) {
		CFRelease(passStr);
	}
	if(outData) {
		CFRelease(outData);
	}
	return result;
}