Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
/*
** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
** verify a certificate by checking validity times against a certain time,
** that we trust the issuer, and that the signature on the certificate is
** valid.
**	"cert" the certificate to verify
**	"checkSig" only check signatures if true
*/
SECStatus
CERT_VerifyCert(SecKeychainRef keychainOrArray, SecCertificateRef cert,
		const CSSM_DATA_PTR *otherCerts,    /* intermediates */
		CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
{
    CFMutableArrayRef certificates = NULL;
    SecTrustRef trust = NULL;
    OSStatus rv;
    int numOtherCerts = SecCmsArrayCount((void **)otherCerts);
    int dex;
    
    /* 
     * Certs to evaluate: first the leaf - our cert - then all the rest we know
     * about. It's OK for otherCerts to contain a copy of the leaf. 
     */
    certificates = CFArrayCreateMutable(NULL, numOtherCerts + 1, &kCFTypeArrayCallBacks);
    CFArrayAppendValue(certificates, cert);
    for(dex=0; dex<numOtherCerts; dex++) {
	SecCertificateRef intCert;
	
	rv = SecCertificateCreateFromData(otherCerts[dex], 
	    CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
	    &intCert);
	if(rv) {
	    goto loser;
	}
	CFArrayAppendValue(certificates, intCert);
	CFRelease(intCert);
    }
    rv = SecTrustCreateWithCertificates(certificates, policies, &trust);
    CFRelease(certificates);
    certificates = NULL;
    if (rv)
	goto loser;

    rv = SecTrustSetKeychains(trust, keychainOrArray);
    if (rv)
	goto loser;

    CFDateRef verifyDate = CFDateCreate(NULL, stime);
    rv = SecTrustSetVerifyDate(trust, verifyDate);
    CFRelease(verifyDate);
    if (rv)
	goto loser;

    if (trustRef)
    {
	*trustRef = trust;
    }
    else
    {
	SecTrustResultType result;
	/* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
	rv = SecTrustEvaluate(trust, &result);
	if (rv)
	    goto loser;

	switch (result)
	{
	case kSecTrustResultProceed:
	case kSecTrustResultUnspecified:
	    /* TP Verification succeeded and there was either a UserTurst entry
	       telling us to procceed, or no user trust setting was specified. */
	    CFRelease(trust);
	    break;
	default:
	    PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
	    rv = SECFailure;
	    goto loser;
	    break;
	}
    }

    return SECSuccess;
loser:
    if (trust)
	CFRelease(trust);
    if(certificates) 
	CFRelease(certificates);
    return rv;
}