/* * 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); }
/* * 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; }