/*
 * Compare email address, is presented to the TP in
 * CSSM_APPLE_TP_SMIME_OPTIONS.SenderEmail, to a string obtained
 * from the sender's cert (i.e., from subjectAltName or Subject DN).
 *
 * Returns CSSM_TRUE on match, else CSSM_FALSE.
 *
 * Incoming appEmail string has already been tpNormalizeAddrSpec'd.
 * We do that for certEmail string here.
 */
CSSM_BOOL tpCompareEmailAddr(
	const char	 	*appEmail,		// spec'd by app, normalized
	uint32			appEmailLen,
	char			*certEmail,		// from cert, we normalize
	uint32			certEmailLen,
	bool			normalizeAll)	// true : lower-case all certEmail characters

{
	tpNormalizeAddrSpec(certEmail, certEmailLen, normalizeAll);

	/* tolerate optional NULL terminators for both */
	if(appEmailLen > 0 && appEmail[appEmailLen - 1] == '\0') {
		appEmailLen--;
	}
	if(certEmailLen > 0 && certEmail[certEmailLen - 1] == '\0') {
		certEmailLen--;
	}
	if((certEmailLen == appEmailLen) &&
	    !memcmp(certEmail, appEmail, certEmailLen)) {
		return CSSM_TRUE;
	}
	else {
		/* mismatch */
		tpPolicyError("tpCompareEmailAddr: app/cert email addrs mismatch");
		return CSSM_FALSE;
	}
}
/*
 * Normalize an RFC822 addr-spec. This consists of converting
 * all characters following the '@' character to lower case.
 * A true normalizeAll results in lower-casing all characters
 * (e.g. for iChat).
 */
void tpNormalizeAddrSpec(
	char		*addr,
	unsigned	addrLen,
	bool		normalizeAll)
{
	if (addr == NULL) {
		tpPolicyError("tpNormalizeAddrSpec: bad addr");
		return;
	}
	if(!normalizeAll) {
		while((addrLen != 0) && (*addr != '@')) {
			addr++;
			addrLen--;
		}
		if(addrLen == 0) {
			tpPolicyError("tpNormalizeAddrSpec: bad addr-spec");
			return;
		}
	}
	tpToLower(addr, addrLen);
}
示例#3
0
/*
 * Fetch issuer cert of specified cert if the cert has an issuerAltName
 * with a URI. If non-NULL cert is returned, it has passed subject/issuer
 * name comparison and signature verification with target cert.
 *
 * Return values:
 *   CSSM_OK - found and returned issuer cert 
 *   CSSMERR_TP_CERTGROUP_INCOMPLETE - no URL in issuerAltName
 *   CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE - found and returned issuer
 *      cert, but signature verification needs subsequent retry.
 *   Anything else - gross error, typically from last LDAP/HTTP attempt
 */
CSSM_RETURN tpFetchIssuerFromNet(
	TPCertInfo			&subject,
	CSSM_CL_HANDLE		clHand,
	CSSM_CSP_HANDLE		cspHand,
	const char			*verifyTime,
	TPCertInfo			*&issuer)		// RETURNED
{
	CSSM_OID_PTR fieldOid = NULL;
	CSSM_DATA_PTR fieldValue = NULL;	// mallocd by CL
	CSSM_RETURN crtn;
	bool hasAIA = false;

	/* look for the Authority Info Access extension first */
	fieldOid = (CSSM_OID_PTR)&CSSMOID_AuthorityInfoAccess;
	crtn = subject.fetchField(fieldOid,
		&fieldValue);
	hasAIA = (crtn == CSSM_OK);
	if (!hasAIA) {
		/* fall back to Issuer Alternative Name extension */
		fieldOid = (CSSM_OID_PTR)&CSSMOID_IssuerAltName;
		crtn = subject.fetchField(fieldOid,
								  &fieldValue);
	}
	switch(crtn) {
		case CSSM_OK:
			break;
		case CSSMERR_CL_NO_FIELD_VALUES:
			/* field not present */
			return CSSMERR_TP_CERTGROUP_INCOMPLETE;
		default:
			/* gross error */
			return crtn;
	}
	if(fieldValue->Length != sizeof(CSSM_X509_EXTENSION)) {
		tpPolicyError("tpFetchIssuerFromNet: malformed CSSM_FIELD");
		return CSSMERR_TP_UNKNOWN_FORMAT;
	}
	CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data;
	CE_GeneralNames *names = (CE_GeneralNames *)cssmExt->value.parsedValue;
	TPCertInfo *rtnCert = NULL;
	if (hasAIA) {	/* authority info access */
		CE_AuthorityInfoAccess *access = (CE_AuthorityInfoAccess *)cssmExt->value.parsedValue;
		for (uint32 index = 0; access && index < access->numAccessDescriptions; index++) {
			CE_AccessDescription *accessDesc = &access->accessDescriptions[index];
			CSSM_OID_PTR methodOid = (CSSM_OID_PTR)&accessDesc->accessMethod;
			/* look for the CA Issuers method */
			if(methodOid->Data != NULL && methodOid->Length == CSSMOID_CA_ISSUERS.Length &&
			   !memcmp(methodOid->Data, CSSMOID_CA_ISSUERS.Data, methodOid->Length)) {
				CE_GeneralNames aiaNames = { 1, &accessDesc->accessLocation };
				/* attempt to fetch cert from named location */
				crtn = tpFetchViaGeneralNames(&aiaNames,
											  subject,
											  NULL,		// issuer - not used
											  NULL,		// verifyContext
											  clHand,
											  cspHand,
											  verifyTime,
											  &rtnCert,
											  NULL);
				if (crtn == CSSM_OK ||
					crtn == CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE) {
					break; // got one
				}
			}
		}
		subject.freeField(fieldOid,	fieldValue);
	}
	else {  /* issuer alt name */
		crtn = tpFetchViaGeneralNames(names,
						subject,
						NULL,		// issuer - not used
						NULL,		// verifyContext
						clHand,
						cspHand,
						verifyTime,
						&rtnCert,
						NULL);
		subject.freeField(fieldOid,	fieldValue);
	}
	switch(crtn) {
		case CSSM_OK:
		case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE:
			issuer = rtnCert;
			break;
		default:
			break;
	}
	return crtn;
}
/*
 * Compare hostname, is presented to the TP in
 * CSSM_APPLE_TP_SSL_OPTIONS.ServerName, to a server name obtained
 * from the server's cert (i.e., from subjectAltName or commonName).
 * Limited wildcard checking is performed here.
 *
 * The incoming hostname is assumed to have been processed by tpToLower();
 * we'll perform that processing on certName here.
 *
 * Trailing '.' characters in both host names will be ignored per Radar 3996792.
 *
 * Returns CSSM_TRUE on match, else CSSM_FALSE.
 */
CSSM_BOOL tpCompareHostNames(
	const char	 	*hostName,		// spec'd by app, tpToLower'd
	uint32			hostNameLen,
	char			*certName,		// from cert, we tpToLower
	uint32			certNameLen)
{
	tpToLower(certName, certNameLen);

	/* tolerate optional NULL terminators for both */
	if(hostNameLen && (hostName[hostNameLen - 1] == '\0')) {
		hostNameLen--;
	}
	if(certNameLen && (certName[certNameLen - 1] == '\0')) {
		certNameLen--;
	}

	if((hostNameLen == 0) || (certNameLen == 0)) {
		/* trivial case with at least one empty name */
		if(hostNameLen == certNameLen) {
			return CSSM_TRUE;
		}
		else {
			return CSSM_FALSE;
		}
	}

	/* trim off trailing dots */
	if(hostName[hostNameLen - 1] == '.') {
		hostNameLen--;
	}
	if(certName[certNameLen - 1] == '.') {
		certNameLen--;
	}

	/* Case 1: exact match */
	if((certNameLen == hostNameLen) &&
	    !memcmp(certName, hostName, certNameLen)) {
		return CSSM_TRUE;
	}

	/*
	 * Case 2: Compare one component at a time, handling wildcards in
	 * cert's server name. The characters implicitly matched by a
	 * wildcard span only one component of a dnsName.
	 */
	do {
		/* get next component from each dnsName */
		char hostComp[MAX_DNS_COMP_LEN];
		char certComp[MAX_DNS_COMP_LEN];
		uint32 hostCompLen;
		uint32 certCompLen;

		bool foundHost = tpNextDnsComp(hostName, hostNameLen,
				hostComp, hostCompLen);
		bool foundCert = tpNextDnsComp(certName, certNameLen,
				certComp, certCompLen);
		if(foundHost != foundCert) {
			/* unequal number of components */
			tpPolicyError("tpCompareHostNames: wildcard mismatch (1)");
			return CSSM_FALSE;
		}
		if(!foundHost) {
			/* normal successful termination */
			return CSSM_TRUE;
		}

		/* compare individual components */
		if(!tpCompareComps(hostComp, hostCompLen,
				certComp, certCompLen)) {
			tpPolicyError("tpCompareHostNames: wildcard mismatch (2)");
			return CSSM_FALSE;
		}

		/* skip over this component
		 * (note: since tpNextDnsComp will first skip over a leading '.',
		 * we must make sure to skip over it here as well.)
		 */
		if(*hostName == '.') hostName++;
		hostName += hostCompLen;
		if(*certName == '.') certName++;
		certName += certCompLen;
	} while(1);
	/* NOT REACHED */
	//assert(0):
	return CSSM_FALSE;
}