Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  smtp_tls_policy_test.c

  Sprache: C
 

/*++
/* NAME
/*      smtp_tls_policy_test 1t
/* SUMMARY
/*      smtp_tls_policy unit tests
/* SYNOPSIS
/*      ./smtp_tls_policy_test
/* DESCRIPTION
/*      smtp_tls_policy_test runs and logs each configured test, reports
/*      if a test is a PASS or FAIL, and returns an exit status of zero
/*      if all tests are a PASS.
/* LICENSE
/* .ad
/* .fi
/*      The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*      Wietse Venema
/*      porcupine.org
/*--*/


 /*
  * System library.
  */

#include <sys_defs.h>
#include <stdlib.h>

 /*
  * Utility library.
  */

#include <argv.h>
#include <msg.h>
#include <msg_vstream.h>
#include <stringops.h>
#include <vstream.h>
#include <vstring.h>

#ifdef USE_TLS

#define PASS    (0)
#define FAIL    (1)

 /*
  * Global library.
  */

#include <mail_params.h>

 /*
  * TLS library.
  */


 /*
  * SMTP client.
  */

#include <smtp.h>

 /*
  * Surrogate dependencies. Parameters are initialized without $name
  * expansion, and can be changed by tests.
  */

char   *var_smtp_tls_policy;
char   *var_smtp_tls_per_site;
char   *var_smtp_tls_ciph;
bool    var_smtp_tls_conn_reuse;
bool    var_smtp_tls_enable_rpk;
char   *var_smtp_tls_level;
int     smtp_host_lookup_mask;
int     var_smtp_cache_conn;
char   *var_smtp_tls_mand_ciph;
char   *var_smtp_tls_mand_excl;
char   *var_smtp_dns_res_opt;
char   *var_smtp_dns_support;
char   *var_smtp_tls_insecure_mx_policy;
bool    var_ign_mx_lookup_err;
bool    var_smtp_enforce_tls;
bool    var_smtp_tls_enforce_peername;
bool    var_smtp_tls_force_tlsa;
char   *var_smtp_tls_fpt_cmatch;
char   *var_smtp_tls_mand_proto;
char   *var_smtp_tls_proto;
char   *var_smtp_tls_sec_cmatch;
char   *var_smtp_tls_sni;
char   *var_smtp_tls_tafile;
char   *var_smtp_tls_vfy_cmatch;
bool    var_smtp_use_tls;
char   *var_smtp_tls_excl_ciph;
bool    var_smtp_tls_enf_sts_mx_pat;
bool    var_smtp_tls_wrappermode;
bool    var_log_tls_feature_status;

 /*
  * Other globals.
  */

int     smtp_mode;
int     smtp_tls_insecure_mx_policy;
unsigned smtp_dns_res_opt;
int     smtp_dns_support;
int     smtp_host_lookup_mask;

 /*
  * Pre-test initializer to make tests independent.
  */

static void test_setup(void)
{
    var_smtp_tls_policy = DEF_SMTP_TLS_POLICY;
    var_smtp_tls_per_site = DEF_SMTP_TLS_PER_SITE;
    var_smtp_tls_ciph = DEF_SMTP_TLS_CIPH;
    var_smtp_tls_conn_reuse = DEF_SMTP_TLS_CONN_REUSE;
    var_smtp_tls_enable_rpk = DEF_SMTP_TLS_ENABLE_RPK;
    var_smtp_tls_level = "may";
    var_smtp_cache_conn = 2;
    var_smtp_tls_mand_ciph = DEF_SMTP_TLS_MAND_CIPH;
    var_smtp_tls_mand_excl = DEF_SMTP_TLS_MAND_EXCL;
    var_smtp_dns_res_opt = DEF_SMTP_DNS_RES_OPT;
    var_smtp_dns_support = DEF_SMTP_DNS_SUPPORT;
    var_smtp_tls_insecure_mx_policy = DEF_SMTP_TLS_INSECURE_MX_POLICY;
    var_ign_mx_lookup_err = DEF_IGN_MX_LOOKUP_ERR;
    var_smtp_enforce_tls = DEF_SMTP_ENFORCE_TLS;
    var_smtp_tls_enforce_peername = DEF_SMTP_TLS_ENFORCE_PN;
    var_smtp_tls_force_tlsa = DEF_SMTP_TLS_FORCE_TLSA;
    var_smtp_tls_fpt_cmatch = DEF_SMTP_TLS_FPT_CMATCH;
    var_smtp_tls_mand_proto = DEF_SMTP_TLS_MAND_PROTO;
    var_smtp_tls_proto = DEF_SMTP_TLS_PROTO;
    var_smtp_tls_sec_cmatch = DEF_SMTP_TLS_SEC_CMATCH;
    var_smtp_tls_sni = DEF_SMTP_TLS_SNI;
    var_smtp_tls_tafile = DEF_SMTP_TLS_TAFILE;
    var_smtp_tls_vfy_cmatch = DEF_SMTP_TLS_VFY_CMATCH;
    var_smtp_use_tls = DEF_SMTP_USE_TLS;
    var_smtp_tls_excl_ciph = DEF_SMTP_TLS_EXCL_CIPH;
    var_smtp_tls_enf_sts_mx_pat = 1;
    var_smtp_tls_wrappermode = 0;
    var_tls_required_enable = 0;
    var_log_tls_feature_status = 1;

    smtp_mode = 1;

    smtp_tls_policy_cache_flush();
}

 /*
  * Post-test finalizer to help memory leak tests.
  */

static void test_teardown(void)
{
    smtp_tls_policy_cache_flush();
}

 /*
  * Test helpers. TODO(wietse) adopt PTEST which does a nicer job.
  */

static int match_int(const char *what, int want, int got)
{
    if (want != got) {
 msg_warn("%s: got %d, want %d", what, got, want);
 return (0);
    }
    return (1);
}

#define STR_OR_NULL(s) ((s)? (s) : "NULL")

static int match_cstr(const char *what, const char *want, const char *got)
{
    if (!want != !got) {
 msg_warn("%s: got '%s', want '%s'", what, STR_OR_NULL(got),
   STR_OR_NULL(want));
 return (0);
    }
    if (want != 0 && strcmp(got, want) != 0) {
 msg_warn("%s: got '%s', want '%s'", what, got, want);
 return (0);
    }
    return (1);
}

#define WANT_ARGV_MAX 5

struct WANT_ARGV {
    ssize_t argc;
    char   *argv[WANT_ARGV_MAX];
};

#define ARGV_OR_NULL(a) ((a)? ("argv") : "NULL")

static int match_argv(const char *what, const struct WANT_ARGV * want,
                const ARGV *got)
{
    if (!want != !got) {
 msg_warn("%s: got '%s', want '%s'", what, ARGV_OR_NULL(got),
   ARGV_OR_NULL(want));
 return (0);
    }
    if (match_int("argc", want->argc, got->argc) == 0) {
 return (0);
    } else {
 VSTRING *buf;
 int     idx;
 int     equal;

 buf = vstring_alloc(100);
 for (equal = 1, idx = 0; idx < want->argc; idx++) {
     vstring_sprintf(buf, "%s->argv[%d]", what, idx);
     if (match_cstr(STR(buf), want->argv[idx], got->argv[idx]) == 0)
  equal = 0;
 }
 vstring_free(buf);
 return (equal);
    }
}

 /*
  * Limited policy for STS tests.
  */

struct WANT_SMTP_TLS_POLICY {
    int     level;   /* TLS enforcement level */
#if 0
    char   *protocols;   /* Acceptable SSL protocols */
    char   *grade;   /* Cipher grade: "export", ... */
    VSTRING *exclusions;  /* Excluded SSL ciphers */
    char   *protocols;   /* Acceptable SSL protocols */
    char   *grade;   /* Cipher grade: "export", ... */
    VSTRING *exclusions;  /* Excluded SSL ciphers */
#endif
    struct WANT_ARGV matchargv;  /* Cert match patterns */
#if 0
    DSN_BUF *why;   /* Lookup error status */
    TLS_DANE *dane;   /* DANE TLSA digests */
#endif
    char   *sni;   /* Optional SNI name when not DANE */
#if 0
    int     conn_reuse;   /* enable connection reuse */
    int     enable_rpk;   /* Enable server->client RPK */
#endif
    int     ext_policy_ttl;  /* TTL from DNS etc. */
    char   *ext_policy_type;  /* (sts) */
    struct WANT_ARGV ext_policy_strings;/* policy strings from DNS etc. */
    char   *ext_policy_domain;  /* policy scope */
    struct WANT_ARGV ext_mx_host_patterns; /* (sts) MX host patterns */
    char   *ext_policy_failure;  /* (sts) policy failure */
};

#define POLICY_OR_NULL(p) ((p)? ("policy") : "NULL")

static int match_smtp_tls_policy(const char *what,
              const struct WANT_SMTP_TLS_POLICY * want,
             const SMTP_TLS_POLICY *got)
{
    int     equal = 1;

    if (!want != !got) {
 msg_warn("%s: got '%s', want '%s'", what, POLICY_OR_NULL(got),
   POLICY_OR_NULL(want));
 return (0);
    }
    if (match_int("level", want->level, got->level) == 0) {
 msg_warn("%s->level mismatch", what);
 equal = 0;
    }
    if (match_argv("matchargv", &want->matchargv, got->matchargv) == 0) {
 msg_warn("%s->matchargv mismatch", what);
 equal = 0;
    }
    if (match_cstr("sni", want->sni, got->sni) == 0) {
 msg_warn("%s->sni mismatch", what);
 equal = 0;
    }
    if (match_int("ext_policy_ttl", want->ext_policy_ttl, got->ext_policy_ttl) == 0) {
 msg_warn("%s->ext_policy_ttl mismatch", what);
 equal = 0;
    }
    if (match_cstr("ext_policy_type", want->ext_policy_type,
     got->ext_policy_type) == 0) {
 msg_warn("%s->ext_policy_type mismatch", what);
 equal = 0;
    }
    if (match_argv("ext_policy_strings", &want->ext_policy_strings,
     got->ext_policy_strings) == 0) {
 msg_warn("%s->ext_policy_strings mismatch", what);
 equal = 0;
    }
    if (match_cstr("ext_policy_domain", want->ext_policy_domain,
     got->ext_policy_domain) == 0) {
 msg_warn("%s->ext_policy_domain mismatch", what);
 equal = 0;
    }
    if (match_argv("ext_mx_host_patterns", &want->ext_mx_host_patterns,
     got->ext_mx_host_patterns) == 0) {
 msg_warn("%s->ext_mx_host_patterns mismatch", what);
 equal = 0;
    }
    if (match_cstr("ext_policy_failure", want->ext_policy_failure,
     got->ext_policy_failure) == 0) {
 msg_warn("%s->ext_policy_failure mismatch", what);
 equal = 0;
    }
    return (equal);
}

 /*
  * Test structure. Some tests may bring their own.
  */

typedef struct TEST_CASE {
    const char *label;
    int     (*action) (const struct TEST_CASE *);
} TEST_CASE;

 /*
  * Verify that policies from an STS plugin are converted into Postfix TLS
  * policies that match a certificate against the server hostname, and that
  * other policy attributes are stored appropriately. A later test will
  * verify that MX hostnames are matched against the STS policy MX hostname
  * patterns.
  */

static int sts_policy_smoke_test(const struct TEST_CASE *tp)
{
    var_smtp_tls_policy =
    "static:{secure match=example:.example "
    "servername=example policy_ttl=123 "
    "policy_type=sts policy_string=one "
    "policy_string=two policy_domain=example "
    "mx_host_pattern=example mx_host_pattern=*.example}";
    static const struct WANT_SMTP_TLS_POLICY want_policy = {
 .level = TLS_LEV_SECURE,
 .matchargv = {.argc = 1,.argv = {"hostname"}},
 .sni = "example",
 .ext_policy_ttl = 123,
 .ext_policy_type = "sts",
 .ext_policy_strings = {.argc = 2,.argv = {"one""two"}},
 .ext_policy_domain = "example",
 .ext_mx_host_patterns = {.argc = 2,.argv = {"example""*.example"}}
    };
    SMTP_STATE *state = smtp_state_alloc();
    const char *domain = "example";
    const char *host = "mail.example";
    const char *addr = "10.0.1.1";
    int     port = 25;
    int     match;

    var_smtp_tls_enf_sts_mx_pat = 1;
    var_smtp_tls_level = "secure";
    smtp_tls_list_init();
    SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state);
    if ((match = smtp_tls_policy_cache_query(state->why, state->tls,
          state->iterator)) == 0) {
 msg_warn("smtp_tls_policy_cache_query failed: %s",
   STR(state->why->reason));
    } else {
 match = match_smtp_tls_policy("policy", &want_policy, state->tls);
    }
    smtp_state_free(state);
    smtp_tls_policy_cache_flush();
    return (match ? PASS : FAIL);
}

 /*
  * Verify that the historical support for policies from STS plugins is still
  * available. STS plugins generate a policy that will match a certificate
  * against all MX patterns, after converting a pattern "*.domain" to
  * ".domain", and do not constrain the allowed MX hostnames.
  */

static int obs_sts_policy_smoke_test(const struct TEST_CASE *tp)
{
    var_smtp_tls_policy =
    "static:{secure match=example:.example "
    "servername=example policy_ttl=123 "
    "policy_type=sts policy_string=one "
    "policy_string=two policy_domain=example "
    "mx_host_pattern=example mx_host_pattern=*.example}";
    static const struct WANT_SMTP_TLS_POLICY want_policy = {
 .level = TLS_LEV_SECURE,
 .matchargv = {.argc = 2,.argv = {"example"".example"}},
 .sni = "example",
 .ext_policy_ttl = 123,
 .ext_policy_type = "sts",
 .ext_policy_strings = {.argc = 2,.argv = {"one""two"}},
 .ext_policy_domain = "example",
 .ext_mx_host_patterns = {.argc = 2,.argv = {"example""*.example"}}
    };
    SMTP_STATE *state = smtp_state_alloc();
    const char *domain = "example";
    const char *host = "mail.example";
    const char *addr = "10.0.1.1";
    int     port = 25;
    int     match;

    var_smtp_tls_enf_sts_mx_pat = 0;
    var_smtp_tls_level = "secure";
    smtp_tls_list_init();
    SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state);
    if ((match = smtp_tls_policy_cache_query(state->why, state->tls,
          state->iterator)) == 0) {
 msg_warn("smtp_tls_policy_cache_query failed: %s",
   STR(state->why->reason));
    } else {
 match = match_smtp_tls_policy("policy", &want_policy, state->tls);
    }
    smtp_state_free(state);
    smtp_tls_policy_cache_flush();
    return (match ? PASS : FAIL);
}

 /*
  * Test the MX host authorization constraints.
  */

static int test_hostname_authorization(const struct TEST_CASE *tp)
{
    var_smtp_tls_policy =
    "static:{secure match=example.com:.example.com "
    "servername=example.com policy_ttl=123 "
    "policy_type=sts policy_string=one "
    "policy_string=two policy_domain=example.com "
    "mx_host_pattern=example.com mx_host_pattern=*.example.com}";
    static const struct WANT_SMTP_TLS_POLICY want_policy = {
 .level = TLS_LEV_SECURE,
 .matchargv = {.argc = 1,.argv = {"hostname"}},
 .sni = "example.com",
 .ext_policy_ttl = 123,
 .ext_policy_type = "sts",
 .ext_policy_strings = {.argc = 2,.argv = {"one""two"}},
 .ext_policy_domain = "example.com",
 .ext_mx_host_patterns = {.argc = 2,.argv = {"example.com""*.example.com"}}
    };
    SMTP_STATE *state = smtp_state_alloc();
    const char *domain = "example.com";
    const char *host = "mail.example.com";
    const char *addr = "10.0.1.1";
    int     port = 25;
    int     match;
    static const char *permit_domains[] = {
 "example.com""mail.example.com"0,
    };
    static const char *reject_domains[] = {
 ".example.com""foo.bar.example.com"0,
    };
    const char *const * cpp;

    var_smtp_tls_enf_sts_mx_pat = 1;
    var_smtp_tls_level = "secure";
    smtp_tls_list_init();
    SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state);
    if ((match = smtp_tls_policy_cache_query(state->why, state->tls,
          state->iterator)) == 0) {
 msg_warn("smtp_tls_policy_cache_query failed: %s",
   STR(state->why->reason));
    } else {
 match = match_smtp_tls_policy("policy", &want_policy, state->tls);
    }
    if (match == 0)
 return (FAIL);

    /* Verify that 'good' MX host names are authorized. */
    for (cpp = permit_domains; *cpp; cpp++) {
 if (!smtp_tls_authorize_mx_hostname(state->tls, *cpp)) {
     msg_warn("hostname '%s' is not authorized", *cpp);
     match = 0;
 }
    }
    /* Verify that 'wrong' MX host names are not authorized. */
    for (cpp = reject_domains; *cpp; cpp++) {
 if (smtp_tls_authorize_mx_hostname(state->tls, *cpp)) {
     msg_warn("hostname '%s' is authorized", *cpp);
     match = 0;
 }
    }

    smtp_state_free(state);
    smtp_tls_policy_cache_flush();
    return (match ? PASS : FAIL);
}

static int test_tls_reqd_no_sans_header(const struct TEST_CASE *tp)
{
    SMTP_STATE *state = smtp_state_alloc();
    const char *domain = "example.com";
    const char *host = "mail.example.com";
    const char *addr = "10.0.1.1";
    int     port = 25;
    int     want_level;
    int     ret = FAIL;

    var_smtp_tls_level = "secure";
    var_smtp_tls_policy = "static:none";

    /* Test-dependent. */
    state->request = &(DELIVER_REQUEST) {
 .sendopts = 0
    };
    var_smtp_tls_wrappermode = 1;
    var_tls_required_enable = 1;
    want_level = TLS_LEV_NONE;

    smtp_tls_list_init();
    SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state);
    if (smtp_tls_policy_cache_query(state->why, state->tls,
        state->iterator) == 0) {
 msg_warn("smtp_tls_policy_cache_query failed: %s",
   STR(state->why->reason));
    } else if (state->tls->level != want_level) {
 msg_warn("got TLS level '%s', want '%s'",
        str_tls_level(state->tls->level), str_tls_level(want_level));
    } else {
 ret = PASS;
    }
    smtp_tls_policy_cache_flush();
    smtp_state_free(state);
    return (ret);
}

static int test_tls_reqd_no_with_wrappermode(const struct TEST_CASE *tp)
{
    SMTP_STATE *state = smtp_state_alloc();
    const char *domain = "example.com";
    const char *host = "mail.example.com";
    const char *addr = "10.0.1.1";
    int     port = 25;
    int     want_level;
    int     ret = FAIL;

    var_smtp_tls_level = "secure";
    var_smtp_tls_policy = "static:none";

    /* Test-dependent. */
    state->request = &(DELIVER_REQUEST) {
 .sendopts = SOPT_REQUIRETLS_HEADER
    };
    var_smtp_tls_wrappermode = 1;
    var_tls_required_enable = 1;
    want_level = TLS_LEV_ENCRYPT;

    smtp_tls_list_init();
    SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state);
    if (smtp_tls_policy_cache_query(state->why, state->tls,
        state->iterator) == 0) {
 msg_warn("smtp_tls_policy_cache_query failed: %s",
   STR(state->why->reason));
    } else if (state->tls->level != want_level) {
 msg_warn("got TLS level '%s', want '%s'",
        str_tls_level(state->tls->level), str_tls_level(want_level));
    } else {
 ret = PASS;
    }
    smtp_tls_policy_cache_flush();
    smtp_state_free(state);
    return (ret);
}

static int test_tls_reqd_no_sans_wrappermode(const struct TEST_CASE *tp)
{
    SMTP_STATE *state = smtp_state_alloc();
    const char *domain = "example.com";
    const char *host = "mail.example.com";
    const char *addr = "10.0.1.1";
    int     port = 25;
    int     want_level;
    int     ret = FAIL;

    var_smtp_tls_level = "secure";
    var_smtp_tls_policy = "static:none";

    /* Test-dependent. */
    state->request = &(DELIVER_REQUEST) {
 .sendopts = SOPT_REQUIRETLS_HEADER
    };
    var_smtp_tls_wrappermode = 0;
    var_tls_required_enable = 1;
    want_level = TLS_LEV_MAY;

    smtp_tls_list_init();
    SMTP_ITER_INIT(state->iterator, domain, host, addr, port, state);
    if (smtp_tls_policy_cache_query(state->why, state->tls,
        state->iterator) == 0) {
 msg_warn("smtp_tls_policy_cache_query failed: %s",
   STR(state->why->reason));
    } else if (state->tls->level != want_level) {
 msg_warn("got TLS level '%s', want '%s'",
        str_tls_level(state->tls->level), str_tls_level(want_level));
    } else {
 ret = PASS;
    }
    smtp_tls_policy_cache_flush();
    smtp_state_free(state);
    return (ret);
}

static const struct TEST_CASE test_cases[] = {
    {"sts_policy_smoke_test", sts_policy_smoke_test,},
    {"obs_sts_policy_smoke_test", obs_sts_policy_smoke_test,},
    {"test_hostname_authorization", test_hostname_authorization},
    {"test_tls_reqd_no_sans_header", test_tls_reqd_no_sans_header},
    {"test_tls_reqd_no_with_wrappermode", test_tls_reqd_no_with_wrappermode},
    {"test_tls_reqd_no_sans_wrappermode", test_tls_reqd_no_sans_wrappermode},
    {0},
};

int     main(int argc, char **argv)
{
    static int tests_passed = 0;
    static int tests_failed = 0;
    const struct TEST_CASE *tp;

    msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);

    for (tp = test_cases; tp->label; tp++) {
 msg_info("RUN  %s", tp->label);
 test_setup();
 if (tp->action(tp) == PASS) {
     msg_info("PASS %s", tp->label);
     tests_passed += 1;
 } else {
     msg_info("FAIL %s", tp->label);
     tests_failed += 1;
 }
 test_teardown();
    }
    msg_info("PASS=%d FAIL=%d", tests_passed, tests_failed);
    exit(tests_failed != 0);
}

#else

int     main(int argc, char **argv)
{
    msg_fatal("this program requires `#define USE_TLS'");
}

#endif

Messung V0.5 in Prozent
C=72 H=94 G=83

¤ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002