Example #1
0
/*
 * 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;
}
Example #2
0
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;
}
Example #4
0
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;
}
Example #5
0
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);
}