/* * Host name checking according to RFC 2595. */ static enum okay nss_check_host(const char *server, struct sock *sp) { CERTCertificate *cert; char *cn = NULL; enum okay ok = STOP; PRArenaPool *arena; CERTGeneralName *gn; SECItem altname; CERTAltNameEncodedContext ec; int i; const SEC_ASN1Template gntempl[] = { { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate } }; if ((cert = SSL_PeerCertificate(sp->s_prfd)) == NULL) { fprintf(stderr, "no certificate from \"%s\"\n", server); return STOP; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &altname) == SECSuccess && SEC_ASN1DecodeItem(arena, &ec, gntempl, &altname) == SECSuccess && ec.encodedGenName != NULL) { for (i = 0; ec.encodedGenName[i] != NULL; i++) { gn = CERT_DecodeGeneralName(arena, ec.encodedGenName[i], NULL); if (gn->type == certDNSName) { char *dn = ac_alloc(gn->name.other.len + 1); memcpy(dn, gn->name.other.data, gn->name.other.len); dn[gn->name.other.len] = '\0'; if (verbose) fprintf(stderr, "Comparing DNS name: \"%s\"\n", dn); if (rfc2595_hostname_match(server, dn) == OKAY) { ac_free(dn); goto out; } ac_free(dn); } } } if ((cn = CERT_GetCommonName(&cert->subject)) != NULL) { if (verbose) fprintf(stderr, "Comparing common name: \"%s\"\n", cn); ok = rfc2595_hostname_match(server, cn); } if (ok == STOP) fprintf(stderr, "host certificate does not match \"%s\"\n", server); out: if (cn) PORT_Free(cn); PORT_FreeArena(arena, PR_FALSE); CERT_DestroyCertificate(cert); return ok; }
PRBool CERT_GovtApprovedBitSet(CERTCertificate *cert) { SECStatus rv; SECItem extItem; CERTOidSequence *oidSeq = NULL; PRBool ret; SECItem **oids; SECItem *oid; SECOidTag oidTag; extItem.data = NULL; rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem); if ( rv != SECSuccess ) { goto loser; } oidSeq = CERT_DecodeOidSequence(&extItem); if ( oidSeq == NULL ) { goto loser; } oids = oidSeq->oids; while ( oids != NULL && *oids != NULL ) { oid = *oids; oidTag = SECOID_FindOIDTag(oid); if ( oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED ) { goto success; } oids++; } loser: ret = PR_FALSE; goto done; success: ret = PR_TRUE; done: if ( oidSeq != NULL ) { CERT_DestroyOidSequence(oidSeq); } if (extItem.data != NULL) { PORT_Free(extItem.data); } return(ret); }
// returns TRUE if SAN was used to produce names // return FALSE if nothing was produced // names => a single name or a list of names // multipleNames => whether multiple names were delivered static bool GetSubjectAltNames(CERTCertificate *nssCert, nsINSSComponent *component, nsString &allNames, uint32_t &nameCount) { allNames.Truncate(); nameCount = 0; SECItem altNameExtension = {siBuffer, nullptr, 0 }; CERTGeneralName *sanNameList = nullptr; SECStatus rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME, &altNameExtension); if (rv != SECSuccess) { return false; } ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { return false; } sanNameList = CERT_DecodeAltNameExtension(arena.get(), &altNameExtension); if (!sanNameList) { return false; } SECITEM_FreeItem(&altNameExtension, false); CERTGeneralName *current = sanNameList; do { nsAutoString name; switch (current->type) { case certDNSName: { nsDependentCSubstring nameFromCert(reinterpret_cast<char*> (current->name.other.data), current->name.other.len); // dNSName fields are defined as type IA5String and thus should // be limited to ASCII characters. if (IsASCII(nameFromCert)) { name.Assign(NS_ConvertASCIItoUTF16(nameFromCert)); if (!allNames.IsEmpty()) { allNames.AppendLiteral(", "); } ++nameCount; allNames.Append(name); } } break; case certIPAddress: { char buf[INET6_ADDRSTRLEN]; PRNetAddr addr; if (current->name.other.len == 4) { addr.inet.family = PR_AF_INET; memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len); PR_NetAddrToString(&addr, buf, sizeof(buf)); name.AssignASCII(buf); } else if (current->name.other.len == 16) { addr.ipv6.family = PR_AF_INET6; memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len); PR_NetAddrToString(&addr, buf, sizeof(buf)); name.AssignASCII(buf); } else { /* invalid IP address */ } if (!name.IsEmpty()) { if (!allNames.IsEmpty()) { allNames.AppendLiteral(", "); } ++nameCount; allNames.Append(name); } break; } default: // all other types of names are ignored break; } current = CERT_GetNextGeneralName(current); } while (current != sanNameList); // double linked return true; }
bool cert_VerifySubjectAltName(const CERTCertificate *cert, const char *name) { SECStatus rv; SECItem subAltName; PLArenaPool *arena = NULL; CERTGeneralName *nameList = NULL; CERTGeneralName *current = NULL; bool san_ip = FALSE; unsigned int len = strlen(name); ip_address myip; rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltName); if (rv != SECSuccess) { DBG(DBG_X509, DBG_log("certificate contains no subjectAltName extension")); return FALSE; } if (tnatoaddr(name, 0, AF_UNSPEC, &myip) == NULL) san_ip = TRUE; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); passert(arena != NULL); nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName); passert(current != NULL); do { switch (current->type) { case certDNSName: case certRFC822Name: if (san_ip) break; if (current->name.other.len == len) { if (memcmp(current->name.other.data, name, len) == 0) { DBG(DBG_X509, DBG_log("subjectAltname %s found in certificate", name)); PORT_FreeArena(arena, PR_FALSE); return TRUE; } } if (current->name.other.len != 0 && current->name.other.len < IDTOA_BUF) { char osan[IDTOA_BUF]; memcpy(osan,current->name.other.data, current->name.other.len); osan[current->name.other.len] = '\0'; DBG(DBG_X509, DBG_log("subjectAltname (len=%d) %s not match %s", current->name.other.len, osan, name)); } else { DBG(DBG_X509, DBG_log("subjectAltname <TOO BIG TO PRINT> does not match %s", name)); } break; case certIPAddress: if (!san_ip) break; if ((current->name.other.len == 4) && (addrtypeof(&myip) == AF_INET)) { if (memcmp(current->name.other.data, &myip.u.v4.sin_addr.s_addr, 4) == 0) { DBG(DBG_X509, DBG_log("subjectAltname IPv4 matches %s", name)); PORT_FreeArena(arena, PR_FALSE); return TRUE; } else { DBG(DBG_X509, DBG_log("subjectAltname IPv4 does not match %s", name)); break; } } if ((current->name.other.len == 16) && (addrtypeof(&myip) == AF_INET6)) { if (memcmp(current->name.other.data, &myip.u.v6.sin6_addr.s6_addr, 16) == 0) { DBG(DBG_X509, DBG_log("subjectAltname IPv6 matches %s", name)); PORT_FreeArena(arena, PR_FALSE); return TRUE; } else { DBG(DBG_X509, DBG_log("subjectAltname IPv6 does not match %s", name)); break; } } DBG(DBG_X509, DBG_log("subjectAltnamea IP address family mismatch for %s", name)); break; default: break; } current = CERT_GetNextGeneralName(current); } while (current != nameList); loglog(RC_LOG_SERIOUS, "No matching subjectAltName found"); /* Don't free nameList, it's part of the arena. */ PORT_FreeArena(arena, PR_FALSE); return FALSE; }
char * CERT_GetCertCommentString(CERTCertificate *cert) { char *retstring = NULL; SECStatus rv; SECItem policyItem; CERTCertificatePolicies *policies = NULL; CERTPolicyInfo **policyInfos; CERTPolicyQualifier **policyQualifiers, *qualifier; policyItem.data = NULL; rv = CERT_FindCertExtension(cert, SEC_OID_X509_CERTIFICATE_POLICIES, &policyItem); if ( rv != SECSuccess ) { goto nopolicy; } policies = CERT_DecodeCertificatePoliciesExtension(&policyItem); if ( policies == NULL ) { goto nopolicy; } policyInfos = policies->policyInfos; /* search through policyInfos looking for the verisign policy */ while (*policyInfos != NULL ) { if ( (*policyInfos)->oid == SEC_OID_VERISIGN_USER_NOTICES ) { policyQualifiers = (*policyInfos)->policyQualifiers; /* search through the policy qualifiers looking for user notice */ while ( policyQualifiers != NULL && *policyQualifiers != NULL ) { qualifier = *policyQualifiers; if ( qualifier->oid == SEC_OID_PKIX_USER_NOTICE_QUALIFIER ) { retstring = stringFromUserNotice(&qualifier->qualifierValue); break; } policyQualifiers++; } break; } policyInfos++; } nopolicy: if ( policyItem.data != NULL ) { PORT_Free(policyItem.data); } if ( policies != NULL ) { CERT_DestroyCertificatePoliciesExtension(policies); } if ( retstring == NULL ) { retstring = CERT_FindNSStringExtension(cert, SEC_OID_NS_CERT_EXT_COMMENT); } if ( retstring != NULL ) { breakLines(retstring); } return(retstring); }