/*
 * Given a SecCertificateRef cert, obtain its public key as a SSLPubKey.
 * Caller must sslFreePubKey and free the SSLPubKey itself.
 */
extern OSStatus sslCopyPeerPubKey(
	SSLContext 				*ctx,
	SSLPubKey               **pubKey)
{
    OSStatus status = noErr;

    check(pubKey);
    check(ctx->peerSecTrust);

    if (!ctx->enableCertVerify) {
        SecTrustResultType result;
        require_noerr(status = SecTrustEvaluate(ctx->peerSecTrust, &result),
            errOut);
	}

    SecKeyRef key = SecTrustCopyPublicKey(ctx->peerSecTrust);
    if (!key) {
		sslErrorLog("sslCopyPeerPubKey: %s, ctx->peerSecTrust=%p\n",
			"SecTrustCopyPublicKey failed", (uintptr_t)ctx->peerSecTrust);
		return errSSLBadCert;
	}
    *pubKey = (SSLPubKey*)key;

errOut:
	if (status) {
		sslErrorLog("sslCopyPeerPubKey: error %d\n", status);
	}
	return status;
}
Exemple #2
0
/* Extract public SecKeyRef from Certificate Chain */
static
int sslCopyPeerPubKey(const SSLCertificate *certchain,
                      SecKeyRef            *pubKey)
{
    int err;
    check(pubKey);
    SecTrustRef trust = NULL;
    const SSLCertificate *cert;
    CFMutableArrayRef certArray = NULL;
    CFDataRef certData = NULL;
    SecCertificateRef cfCert = NULL;

    err = errSSLInternal;

    certArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
    cert = certchain;
    while(cert) {
        require((certData = CFDataCreate(kCFAllocatorDefault, cert->derCert.data, cert->derCert.length)), out);
        require((cfCert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)), out);
        CFArrayAppendValue(certArray, cfCert);
        CFReleaseNull(cfCert);
        CFReleaseNull(certData);
        cert=cert->next;
    }

    require_noerr((err=SecTrustCreateWithCertificates(certArray, NULL, &trust)), out);
    SecKeyRef key = SecTrustCopyPublicKey(trust);
    require_action(key, out, err=-9808); // errSSLBadCert

    *pubKey = key;

    err = errSecSuccess;

out:
    CFReleaseSafe(certData);
    CFReleaseSafe(cfCert);
    CFReleaseSafe(trust);
    CFReleaseSafe(certArray);

    return err;
}
OSStatus
parseIncomingCerts(
	SSLContext			*ctx,
	CFArrayRef			certs,
	CFArrayRef			*destCertChain,	/* &ctx->{localCertChain,encryptCertChain} */
	SSLPubKey			**sslPubKey,	/* &ctx->signingPubKey, etc. */
	SSLPrivKey			**sslPrivKey,	/* &ctx->signingPrivKeyRef, etc. */
	CFIndex				*signerAlg)		/* optional */
{
	OSStatus			ortn;
	CFIndex				ix, numCerts;
	SecIdentityRef 		identity;
	CFMutableArrayRef	certChain = NULL;	/* Retained */
	SecCertificateRef	leafCert = NULL;	/* Retained */
	SecKeyRef			pubKey = NULL;		/* Retained */
	SecKeyRef           privKey = NULL;		/* Retained */
	SecTrustRef         trust = NULL;		/* Retained */
	SecTrustResultType	trustResult;

	assert(ctx != NULL);
	assert(destCertChain != NULL);		/* though its referent may be NULL */
	assert(sslPubKey != NULL);
	assert(sslPrivKey != NULL);

	if (certs == NULL) {
		sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
		ortn = errSSLBadCert;
		goto errOut;
	}
	numCerts = CFArrayGetCount(certs);
	if (numCerts == 0) {
		sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
		ortn = errSSLBadCert;
		goto errOut;
	}

	/*
	 * Certs[0] is an SecIdentityRef from which we extract subject cert,
	 * privKey, pubKey.
	 *
	 * 1. ensure the first element is a SecIdentityRef.
	 */
	identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
	if (identity == NULL) {
		sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
		ortn = paramErr;
		goto errOut;
	}
	if (CFGetTypeID(identity) != SecIdentityGetTypeID()) {
		sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
		ortn = paramErr;
		goto errOut;
	}

	/*
	 * 2. Extract cert, keys and convert to local format.
	 */
	ortn = SecIdentityCopyCertificate(identity, &leafCert);
	if (ortn) {
		sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
		goto errOut;
	}

	/* Fetch private key from identity */
	ortn = SecIdentityCopyPrivateKey(identity, &privKey);
	if (ortn) {
		sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
			(int)ortn);
		goto errOut;
	}

	/* Convert the input array of SecIdentityRef at the start to an array of
	   all certificates. */
	certChain = CFArrayCreateMutable(kCFAllocatorDefault, numCerts,
		&kCFTypeArrayCallBacks);
	if (!certChain) {
		ortn = memFullErr;
		goto errOut;
	}
	CFArrayAppendValue(certChain, leafCert);
	for (ix = 1; ix < numCerts; ++ix) {
		SecCertificateRef intermediate =
			(SecCertificateRef)CFArrayGetValueAtIndex(certs, ix);
		if (intermediate == NULL) {
			sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
			ortn = paramErr;
			goto errOut;
		}
		if (CFGetTypeID(intermediate) != SecCertificateGetTypeID()) {
			sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
			ortn = paramErr;
			goto errOut;
		}

		CFArrayAppendValue(certChain, intermediate);
	}

	/* Obtain public key from cert */
#if TARGET_OS_IOS
	ortn = SecTrustCreateWithCertificates(certChain, NULL, &trust);
#else
	{
		SecPolicyRef policy = SecPolicyCreateBasicX509();
		ortn = SecTrustCreateWithCertificates(certChain, policy, &trust);
		CFReleaseSafe(policy);
		if (!ortn) {
			/* We are only interested in getting the public key from the leaf
			 * cert here, so for best performance, don't try to build a chain
			 * or search any keychains.
			 */
			CFArrayRef emptyArray = CFArrayCreate(NULL, NULL, 0, NULL);
			(void)SecTrustSetAnchorCertificates(trust, emptyArray);
			(void)SecTrustSetKeychains(trust, emptyArray);
			CFReleaseSafe(emptyArray);
		}
	}
#endif
	if (ortn) {
		sslErrorLog("parseIncomingCerts: SecTrustCreateWithCertificates err %d\n",
			(int)ortn);
		goto errOut;
	}
	ortn = SecTrustEvaluate(trust, &trustResult);
	if (ortn) {
		sslErrorLog("parseIncomingCerts: SecTrustEvaluate err %d\n",
			(int)ortn);
		goto errOut;
	}
	pubKey = SecTrustCopyPublicKey(trust);
	if (pubKey == NULL) {
		sslErrorLog("parseIncomingCerts: SecTrustCopyPublicKey failed\n");
		ortn = -67712; // errSecInvalidKeyRef
		goto errOut;
	}

	/* SUCCESS */
errOut:
	CFReleaseSafe(trust);
	CFReleaseSafe(leafCert);
	CFReleaseSafe(*destCertChain);
    sslFreePubKey(sslPubKey);
    sslFreePrivKey(sslPrivKey);

	if (ortn) {
		CFReleaseSafe(certChain);
		CFReleaseSafe(pubKey);
		CFReleaseSafe(privKey);

		*destCertChain = NULL;
	} else {
		*destCertChain = certChain;
		*sslPubKey = (SSLPubKey*)pubKey;
		*sslPrivKey = (SSLPrivKey*)privKey;
	}

	return ortn;
}
/* Extract the pubkey from a cert chain, and send it to the tls_handshake context */
int tls_set_encrypt_pubkey(tls_handshake_t hdsk, const SSLCertificate *certchain)
{
    int err;
    CFIndex algId;
    SecTrustRef trustRef = NULL;
    SecKeyRef pubkey = NULL;
    CFDataRef modulus = NULL;
    CFDataRef exponent = NULL;

#if 0
    { /* dump certs */
        int i=0;
        int j;
        const SSLCertificate *tmp = certchain;
        while(tmp) {
            printf("cert%d[] = {", i);
            for(j=0; j<tmp->derCert.length; j++) {
                if((j&0xf)==0)
                    printf("\n");
                printf("0x%02x, ", tmp->derCert.data[j]);
            }
            printf("}\n");
            tmp=tmp->next;
            i++;
        }
    }
#endif

    require_noerr((err=tls_create_trust_from_certs(certchain, &trustRef)), errOut);
    require_action((pubkey = SecTrustCopyPublicKey(trustRef)), errOut, err=-9808); // errSSLBadCert

#if TARGET_OS_IPHONE
    algId = SecKeyGetAlgorithmID(pubkey);
#else
    algId = SecKeyGetAlgorithmId(pubkey);
#endif

    err = -9809; //errSSLCrypto;

    switch(algId) {
        case kSecRSAAlgorithmID:
        {
            require((modulus = SecKeyCopyModulus(pubkey)), errOut);
            require((exponent = SecKeyCopyExponent(pubkey)), errOut);

            tls_buffer mod;
            tls_buffer exp;

            mod.data = (uint8_t *)CFDataGetBytePtr(modulus);
            mod.length = CFDataGetLength(modulus);

            exp.data = (uint8_t *)CFDataGetBytePtr(exponent);
            exp.length = CFDataGetLength(exponent);

            err = tls_handshake_set_encrypt_rsa_public_key(hdsk, &mod, &exp);
            break;
        }
        default:
            break;
    }

errOut:
    CFReleaseSafe(trustRef);
    CFReleaseSafe(pubkey);
    CFReleaseSafe(modulus);
    CFReleaseSafe(exponent);

    return err;
}
/* Test basic add delete update copy matching stuff. */
static void tests(void)
{
    SecTrustRef trust;
	SecCertificateRef cert0, cert1;
	isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)),
		NULL, "create cert0");
	isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)),
		NULL, "create cert1");
	const void *v_certs[] = {
		cert0,
		cert1
	};
    SecPolicyRef policy = SecPolicyCreateSSL(false, NULL);
    CFArrayRef certs = CFArrayCreate(NULL, v_certs,
		array_size(v_certs), NULL);

    /* SecTrustCreateWithCertificates using single cert. */
    ok_status(SecTrustCreateWithCertificates(cert0, policy, &trust),
        "create trust with single cert0");
    is(SecTrustGetCertificateCount(trust), 1, "cert count is 1");
    is(SecTrustGetCertificateAtIndex(trust, 0), cert0, "cert 0 is leaf");
    CFReleaseNull(trust);

    /* SecTrustCreateWithCertificates failures. */
    is_status(SecTrustCreateWithCertificates(kCFBooleanTrue, policy, &trust),
        errSecParam, "create trust with boolean instead of cert");
    is_status(SecTrustCreateWithCertificates(cert0, kCFBooleanTrue, &trust),
        errSecParam, "create trust with boolean instead of policy");

    /* SecTrustCreateWithCertificates using array of certs. */
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust");
    /* NOTE: prior to <rdar://11810677 SecTrustGetCertificateCount would return 1 at this point.
     * Now, however, we do an implicit SecTrustEvaluate to build the chain if it has not yet been
     * evaluated, so we now expect the full chain length.
     */
    is(SecTrustGetCertificateCount(trust), 3, "cert count is 3");
    is(SecTrustGetCertificateAtIndex(trust, 0), cert0, "cert 0 is leaf");

	/* Jan 1st 2006. */
	CFDateRef date = CFDateCreate(NULL, 157680000.0);
    ok_status(SecTrustSetVerifyDate(trust, date), "set date");

    is(SecTrustGetVerifyTime(trust), 157680000.0, "get date");

	SecTrustResultType trustResult;

SKIP: {
#ifdef NO_SERVER
    skip("Can't fail to connect to securityd in NO_SERVER mode", 4, false);
#endif
    // Test Restore OS environment
    SecServerSetMachServiceName("com.apple.security.doesn't-exist");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust without securityd running");
    is_status(trustResult, kSecTrustResultInvalid, "trustResult is kSecTrustResultInvalid");
	is(SecTrustGetCertificateCount(trust), 1, "cert count is 1 without securityd running");
    SecKeyRef pubKey = NULL;
    ok(pubKey = SecTrustCopyPublicKey(trust), "copy public key without securityd running");
    CFReleaseNull(pubKey);
    SecServerSetMachServiceName(NULL);
    // End of Restore OS environment tests
}

    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trustResult is kSecTrustResultUnspecified");

	is(SecTrustGetCertificateCount(trust), 3, "cert count is 3");

	CFDataRef c0_serial = CFDataCreate(NULL, _c0_serial, sizeof(_c0_serial));
	CFDataRef serial;
	ok(serial = SecCertificateCopySerialNumber(cert0), "copy cert0 serial");
	ok(CFEqual(c0_serial, serial), "serial matches");

    CFArrayRef anchors = CFArrayCreate(NULL, (const void **)&cert1, 1, &kCFTypeArrayCallBacks);
    ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");
	is(SecTrustGetCertificateCount(trust), 2, "cert count is 2");

	CFReleaseSafe(anchors);
    anchors = CFArrayCreate(NULL, NULL, 0, NULL);
    ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set empty anchors list");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
		"trust is kSecTrustResultRecoverableTrustFailure");

	ok_status(SecTrustSetAnchorCertificatesOnly(trust, false), "trust passed in anchors and system anchors");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

	ok_status(SecTrustSetAnchorCertificatesOnly(trust, true), "only trust passed in anchors (default)");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
		"trust is kSecTrustResultRecoverableTrustFailure");

    /* Test cert_1 intermididate from the keychain. */
    CFReleaseSafe(trust);
    ok_status(SecTrustCreateWithCertificates(cert0, policy, &trust),
              "create trust with single cert0");
    ok_status(SecTrustSetVerifyDate(trust, date), "set date");

    // Add cert1
    CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
        kSecClass, kSecClassCertificate, kSecValueRef, cert1, NULL);
    ok_status(SecItemAdd(query, NULL), "add cert1 to keychain");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    // Cleanup added cert1.
    ok_status(SecItemDelete(query), "remove cert1 from keychain");
    CFReleaseSafe(query);
    is_status(trustResult, kSecTrustResultUnspecified,
              "trust is kSecTrustResultUnspecified");
	is(SecTrustGetCertificateCount(trust), 3, "cert count is 3");

    /* Set certs to be the xedge2 leaf. */
	CFReleaseSafe(certs);
	const void *cert_xedge2;
	isnt(cert_xedge2 = SecCertificateCreateWithBytes(NULL, xedge2_certificate,
        sizeof(xedge2_certificate)), NULL, "create cert_xedge2");
    certs = CFArrayCreate(NULL, &cert_xedge2, 1, NULL);

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
	CFReleaseSafe(date);
    bool server = true;
    policy = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ssl server xedge2.apple.com");
    /* Jan 1st 2009. */
    date = CFDateCreate(NULL, 252288000.0);
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
    server = false;
    policy = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ssl client xedge2.apple.com");
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
		"trust is kSecTrustResultRecoverableTrustFailure");

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
    server = true;
    policy = SecPolicyCreateIPSec(server, CFSTR("xedge2.apple.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ip server xedge2.apple.com");
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
#if 0
    /* Although this shouldn't be a valid ipsec cert, since we no longer
       check for ekus in the ipsec policy it is. */
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
		"trust is kSecTrustResultRecoverableTrustFailure");
#else
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");
#endif

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
    server = true;
    policy = SecPolicyCreateSSL(server, CFSTR("nowhere.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ssl server nowhere.com");
    SecPolicyRef replacementPolicy = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com"));
    SecTrustSetPolicies(trust, replacementPolicy);
    CFReleaseSafe(replacementPolicy);
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
    server = true;
    policy = SecPolicyCreateSSL(server, CFSTR("nowhere.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ssl server nowhere.com");
    SecPolicyRef replacementPolicy2 = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com"));
    CFArrayRef replacementPolicies = CFArrayCreate(kCFAllocatorDefault, (CFTypeRef*)&replacementPolicy2, 1, &kCFTypeArrayCallBacks);
    SecTrustSetPolicies(trust, replacementPolicies);
    CFReleaseSafe(replacementPolicy2);
    CFReleaseSafe(replacementPolicies);
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

    /* Test self signed ssl cert with cert itself set as anchor. */
	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
	CFReleaseSafe(certs);
	CFReleaseSafe(date);
	const void *garthc2;
    server = true;
	isnt(garthc2 = SecCertificateCreateWithBytes(NULL, garthc2_certificate,
        sizeof(garthc2_certificate)), NULL, "create garthc2");
    certs = CFArrayCreate(NULL, &garthc2, 1, NULL);
    policy = SecPolicyCreateSSL(server, CFSTR("garthc2.apple.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ip server garthc2.apple.com");
    date = CFDateCreate(NULL, 269568000.0);
    ok_status(SecTrustSetVerifyDate(trust, date),
        "set garthc2 trust date to Aug 2009");
    ok_status(SecTrustSetAnchorCertificates(trust, certs),
        "set garthc2 as anchor");
    ok_status(SecTrustEvaluate(trust, &trustResult),
        "evaluate self signed cert with cert as anchor");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

	CFReleaseSafe(garthc2);
	CFReleaseSafe(cert_xedge2);
	CFReleaseSafe(anchors);
	CFReleaseSafe(trust);
	CFReleaseSafe(serial);
	CFReleaseSafe(c0_serial);
	CFReleaseSafe(policy);
	CFReleaseSafe(certs);
	CFReleaseSafe(cert0);
	CFReleaseSafe(cert1);
	CFReleaseSafe(date);
    
    /* Test prt_forest_fi */
    const void *prt_forest_fi;
    isnt(prt_forest_fi = SecCertificateCreateWithBytes(NULL, prt_forest_fi_certificate,
						 sizeof(prt_forest_fi_certificate)), NULL, "create prt_forest_fi");
    isnt(certs = CFArrayCreate(NULL, &prt_forest_fi, 1, NULL), NULL, "failed to create cert array");
    policy = SecPolicyCreateSSL(false, CFSTR("owa.prt-forest.fi"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
	      "create trust for ip client owa.prt-forest.fi");
    date = CFDateCreate(NULL, 391578321.0);
    ok_status(SecTrustSetVerifyDate(trust, date),
	      "set owa.prt-forest.fi trust date to May 2013");
    
    SecKeyRef pubkey = SecTrustCopyPublicKey(trust);
    is(pubkey, NULL, "pubkey returned");
    
	CFReleaseSafe(certs);
    CFReleaseNull(prt_forest_fi);
    CFReleaseNull(policy);
    CFReleaseNull(trust);
    CFReleaseNull(pubkey);
    CFReleaseNull(date);

}