コード例 #1
0
static void session_tls_init(SMTP_SESSION *session, const char *dest,
			             const char *host, int flags)
{
    const char *myname = "session_tls_init";
    int     global_level;
    int     site_level;

    /*
     * Initialize all TLS related session properties.
     */
    session->tls_context = 0;
    session->tls_nexthop = 0;
    session->tls_level = TLS_LEV_NONE;
    session->tls_retry_plain = 0;
    session->tls_protocols = 0;
    session->tls_grade = 0;
    session->tls_exclusions = 0;
    session->tls_matchargv = 0;

    /*
     * Compute the global TLS policy. This is the default policy level when
     * no per-site policy exists. It also is used to override a wild-card
     * per-site policy.
     */
    if (*var_smtp_tls_level) {
	/* Require that var_smtp_tls_level is sanitized upon startup. */
	global_level = tls_level_lookup(var_smtp_tls_level);
	if (global_level == TLS_LEV_INVALID)
	    msg_panic("%s: invalid TLS security level: \"%s\"",
		      myname, var_smtp_tls_level);
    } else if (var_smtp_enforce_tls) {
	global_level = var_smtp_tls_enforce_peername ?
	    TLS_LEV_VERIFY : TLS_LEV_ENCRYPT;
    } else {
	global_level = var_smtp_use_tls ?
	    TLS_LEV_MAY : TLS_LEV_NONE;
    }
    if (msg_verbose)
	msg_info("%s TLS level: %s", "global", policy_name(global_level));

    /*
     * Compute the per-site TLS enforcement level. For compatibility with the
     * original TLS patch, this algorithm is gives equal precedence to host
     * and next-hop policies.
     */
    site_level = TLS_LEV_NOTFOUND;

    if (tls_policy) {
	tls_policy_lookup(session, &site_level, dest, "next-hop destination");
    } else if (tls_per_site) {
	tls_site_lookup(&site_level, dest, "next-hop destination");
	if (strcasecmp(dest, host) != 0)
	    tls_site_lookup(&site_level, host, "server hostname");
	if (msg_verbose)
	    msg_info("%s TLS level: %s", "site", policy_name(site_level));

	/*
	 * Override a wild-card per-site policy with a more specific global
	 * policy.
	 * 
	 * With the original TLS patch, 1) a per-site ENCRYPT could not override
	 * a global VERIFY, and 2) a combined per-site (NONE+MAY) policy
	 * produced inconsistent results: it changed a global VERIFY into
	 * NONE, while producing MAY with all weaker global policy settings.
	 * 
	 * With the current implementation, a combined per-site (NONE+MAY)
	 * consistently overrides global policy with NONE, and global policy
	 * can override only a per-site MAY wildcard. That is, specific
	 * policies consistently override wildcard policies, and
	 * (non-wildcard) per-site policies consistently override global
	 * policies.
	 */
	if (site_level == TLS_LEV_MAY && global_level > TLS_LEV_MAY)
	    site_level = global_level;
    }
    if (site_level == TLS_LEV_NOTFOUND)
	session->tls_level = global_level;
    else
	session->tls_level = site_level;

    /*
     * Use main.cf protocols setting if not set in per-destination table.
     */
    if (session->tls_level > TLS_LEV_NONE && session->tls_protocols == 0)
	session->tls_protocols =
	    mystrdup((session->tls_level == TLS_LEV_MAY) ?
		     var_smtp_tls_proto : var_smtp_tls_mand_proto);

    /*
     * Compute cipher grade (if set in per-destination table, else
     * set_cipher() uses main.cf settings) and security level dependent
     * cipher exclusion list.
     */
    set_cipher_grade(session);

    /*
     * Use main.cf cert_match setting if not set in per-destination table.
     */
    if (session->tls_matchargv == 0) {
	switch (session->tls_level) {
	case TLS_LEV_INVALID:
	case TLS_LEV_NONE:
	case TLS_LEV_MAY:
	case TLS_LEV_ENCRYPT:
	    break;
	case TLS_LEV_FPRINT:
	    session->tls_matchargv =
		argv_split(var_smtp_tls_fpt_cmatch, "\t\n\r, |");
	    break;
	case TLS_LEV_VERIFY:
	    session->tls_matchargv =
		argv_split(var_smtp_tls_vfy_cmatch, "\t\n\r, :");
	    break;
	case TLS_LEV_SECURE:
	    session->tls_matchargv =
		argv_split(var_smtp_tls_sec_cmatch, "\t\n\r, :");
	    break;
	default:
	    msg_panic("unexpected TLS security level: %d",
		      session->tls_level);
	}
    }
    if (msg_verbose && (tls_policy || tls_per_site))
	msg_info("%s TLS level: %s", "effective",
		 policy_name(session->tls_level));
}
コード例 #2
0
static void *policy_create(const char *unused_key, void *context)
{
    SMTP_ITERATOR *iter = (SMTP_ITERATOR *) context;
    int     site_level;
    const char *dest = STR(iter->dest);
    const char *host = STR(iter->host);

    /*
     * Prepare a pristine policy object.
     */
    SMTP_TLS_POLICY *tls = (SMTP_TLS_POLICY *) mymalloc(sizeof(*tls));

    smtp_tls_policy_init(tls, dsb_create());

    /*
     * Compute the per-site TLS enforcement level. For compatibility with the
     * original TLS patch, this algorithm is gives equal precedence to host
     * and next-hop policies.
     */
    tls->level = global_tls_level();
    site_level = TLS_LEV_NOTFOUND;

    if (tls_policy) {
	tls_policy_lookup(tls, &site_level, dest, "next-hop destination");
    } else if (tls_per_site) {
	tls_site_lookup(tls, &site_level, dest, "next-hop destination");
	if (site_level != TLS_LEV_INVALID
	    && strcasecmp(dest, host) != 0)
	    tls_site_lookup(tls, &site_level, host, "server hostname");

	/*
	 * Override a wild-card per-site policy with a more specific global
	 * policy.
	 * 
	 * With the original TLS patch, 1) a per-site ENCRYPT could not override
	 * a global VERIFY, and 2) a combined per-site (NONE+MAY) policy
	 * produced inconsistent results: it changed a global VERIFY into
	 * NONE, while producing MAY with all weaker global policy settings.
	 * 
	 * With the current implementation, a combined per-site (NONE+MAY)
	 * consistently overrides global policy with NONE, and global policy
	 * can override only a per-site MAY wildcard. That is, specific
	 * policies consistently override wildcard policies, and
	 * (non-wildcard) per-site policies consistently override global
	 * policies.
	 */
	if (site_level == TLS_LEV_MAY && tls->level > TLS_LEV_MAY)
	    site_level = tls->level;
    }
    switch (site_level) {
    default:
	tls->level = site_level;
    case TLS_LEV_NOTFOUND:
	break;
    case TLS_LEV_INVALID:
	return ((void *) tls);
    }

    /*
     * DANE initialization may change the security level to something else,
     * so do this early, so that we use the right level below.  Note that
     * "dane-only" changes to "dane" once we obtain the requisite TLSA
     * records.
     */
    if (tls->level == TLS_LEV_DANE || tls->level == TLS_LEV_DANE_ONLY)
	dane_init(tls, iter);
    if (tls->level == TLS_LEV_INVALID)
	return ((void *) tls);

    /*
     * Use main.cf protocols setting if not set in per-destination table.
     */
    if (tls->level > TLS_LEV_NONE && tls->protocols == 0)
	tls->protocols =
	    mystrdup((tls->level == TLS_LEV_MAY) ?
		     var_smtp_tls_proto : var_smtp_tls_mand_proto);

    /*
     * Compute cipher grade (if set in per-destination table, else
     * set_cipher() uses main.cf settings) and security level dependent
     * cipher exclusion list.
     */
    set_cipher_grade(tls);

    /*
     * Use main.cf cert_match setting if not set in per-destination table.
     */
    switch (tls->level) {
    case TLS_LEV_INVALID:
    case TLS_LEV_NONE:
    case TLS_LEV_MAY:
    case TLS_LEV_ENCRYPT:
    case TLS_LEV_DANE:
	break;
    case TLS_LEV_FPRINT:
	if (tls->dane == 0)
	    tls->dane = tls_dane_alloc();
	if (!TLS_DANE_HASEE(tls->dane)) {
	    tls_dane_add_ee_digests(tls->dane, var_smtp_tls_fpt_dgst,
				    var_smtp_tls_fpt_cmatch, "\t\n\r, ");
	    if (!TLS_DANE_HASEE(tls->dane)) {
		msg_warn("nexthop domain %s: configured at fingerprint "
		       "security level, but with no fingerprints to match.",
			 dest);
		MARK_INVALID(tls->why, &tls->level);
		return ((void *) tls);
	    }
	}
	break;
    case TLS_LEV_VERIFY:
    case TLS_LEV_SECURE:
	if (tls->matchargv == 0)
	    tls->matchargv =
		argv_split(tls->level == TLS_LEV_VERIFY ?
			   var_smtp_tls_vfy_cmatch : var_smtp_tls_sec_cmatch,
			   "\t\n\r, :");
	if (*var_smtp_tls_tafile) {
	    if (tls->dane == 0)
		tls->dane = tls_dane_alloc();
	    if (!TLS_DANE_HASTA(tls->dane)
		&& !load_tas(tls->dane, var_smtp_tls_tafile)) {
		MARK_INVALID(tls->why, &tls->level);
		return ((void *) tls);
	    }
	}
	break;
    default:
	msg_panic("unexpected TLS security level: %d", tls->level);
    }

    if (msg_verbose && tls->level != global_tls_level())
	msg_info("%s TLS level: %s", "effective", policy_name(tls->level));

    return ((void *) tls);
}