Hello. Wietse Venema wrote in <4bbwrb5qbbzj...@spike.porcupine.org>: |What is the trust model: can anyone send email as long as they have |a valid certificate that is signed by one of hundreds of CAs, and
I am a political person and can only response to this politically. Other than that i do not know, Wietse Venema. Twenty years ago i was an angry young man because the new German passports did not include S/MIME++ certificates and PGP keys, signed by the German government. In the meantime the "Bundesdruckerei" (which has become more or less private until then, what a mess, in my opinion) actually acts as a certificate authority. The IETF pushes per-DNS-zone authorities. DNS can now go over encrypted transport, and the content itself is also (though differently, unfortunately) cryptographically verifiable, if the zone does that. The Internet of Things produces devices which want to call home and take part in the internet. If you buy a light bulb today it may want to contact home when you use it first in five years from now on. The past has shown passports are important, i also say this in particular as a German (others could chime in of course), people even kill for passports eventually. I do not see a particular difference in between digital and paper passports. I know for sure however that with client certificates there is a little bit of security and affirmation where otherwise there is nothing. My MUA for example was treated as a lesser secure application by a big free mail provider, because it does not use OAuth. Even though my password is in an encrypted .netrc file, and that in turn exists on an encrypted partition on an unencrypted block device (and also that will change in the future). The partition is unmounted on lid close. The data transport is secured via TLS. Why is this lesser secure? Especially since XOAUTH2 / OAUTHBEARER is not lesser secure. But in how far is that different than just offering the possibility to specify per-application passwords, for example. I.e., diversify that, do not use the account master password for logins via SMTP / POP3 / IMAP? And then i have to go over HTTPS to refresh my temporary password. Why is that necessary, the XOAUTH2 / OAUTHBEARER JSON hashmasp used during login could very well be used to update refresh tokens on the fly, too. Maybe in the future there will be advertisements when updating the token, i do not know. I cannot time out this token, different to Kerberos/GSSAPI, where my local kdestroy(1) program can be used to disable the ticket. With client certificates people are, or could be, responsible themselves. We have programs like GPG agent and ssh-agent, there are USB sticks like yubikey and such, which help in storing their private counterparts securely (unless the scene is getting real tough, at least, but this cannot be helped anyhow, i would say). Their content is standardized, the algorithms are standardized and well-tested, and open for any mathematician / cryptographer who is dedicated enough to go for it. This is as good as it can get. |as long as their certificate contains an email address that matches |smtpd_sender_login_maps? Oh, sorry, i am not an administrator. I have read the postfix documentation once in 2015, to setup my server VM. Until then only externally managed accounts. And the server does not support any login mechanism at all, the message enters the postfix there via ssh and sendmail. That is enough for me. (It even drives mailing lists, but that via aliases.) But in the meantime i have become conscious that this login-test setup is totally broken, i am already reading the documentation anew in another window. Thank you! By the way, there is a little improvement in the patch: diff --git a/src/xsasl/xsasl_dovecot_server.c b/src/xsasl/xsasl_dovecot_server.c -index 601f787..9b849b4 100644 +index 601f787..780fd91 100644 --- a/src/xsasl/xsasl_dovecot_server.c +++ b/src/xsasl/xsasl_dovecot_server.c @@ -166,7 +166,8 @@ typedef struct { @@ -98,8 +97,8 @@ index 601f787..9b849b4 100644 server->mechanism_argv = 0; - server->tls_flag = args->tls_flag; + server->tls_flags = args->tls_flags; -+ server->tls_cert_username = (args->tls_flags && args->tls_cert_username) -+ ? mystrdup(args->tls_cert_username) : 0; ++ server->tls_cert_username = ((args->tls_flags & XSASL_TLS_CLIENT_CERT) ++ && args->tls_cert_username) ? mystrdup(args->tls_cert_username) : 0; It does not really fix a bug, but is more explicit. (I have not compiled this, i only recognized it would be more explicit like this.) I will attach this version, ok? | Wietse --End of <4bbwrb5qbbzj...@spike.porcupine.org> Ciao, Mr. Venema, --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt)
diff --git a/src/smtpd/smtpd_sasl_glue.c b/src/smtpd/smtpd_sasl_glue.c index 020c830..8a4f1fd 100644 --- a/src/smtpd/smtpd_sasl_glue.c +++ b/src/smtpd/smtpd_sasl_glue.c @@ -185,9 +185,9 @@ void smtpd_sasl_initialize(void) void smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name, const char *sasl_opts_val) { - const char *mechanism_list; + const char *tls_cert_username, *mechanism_list; XSASL_SERVER_CREATE_ARGS create_args; - int tls_flag; + int tls_flags; /* * Sanity check. @@ -207,10 +207,14 @@ void smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name, /* * Set up a new server context for this connection. */ + tls_flags = 0; + tls_cert_username = 0; #ifdef USE_TLS - tls_flag = state->tls_context != 0; -#else - tls_flag = 0; + tls_flags = (state->tls_context != 0) ? XSASL_TLS_SECURED : 0; + if (tls_flags && TLS_CERT_IS_PRESENT(state->tls_context)) { + tls_flags |= XSASL_TLS_CLIENT_CERT; + tls_cert_username = state->tls_context->peer_CN; + } #endif #define ADDR_OR_EMPTY(addr, unknown) (strcmp(addr, unknown) ? addr : "") #define REALM_OR_NULL(realm) (*(realm) ? (realm) : (char *) 0) @@ -228,9 +232,10 @@ void smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name, client_port = ADDR_OR_EMPTY(state->port, CLIENT_PORT_UNKNOWN), service = var_smtpd_sasl_service, - user_realm = REALM_OR_NULL(var_smtpd_sasl_realm), + user_realm = REALM_OR_NULL(var_smtpd_sasl_realm), security_options = sasl_opts_val, - tls_flag = tls_flag)) == 0) + tls_flags = tls_flags, + tls_cert_username = tls_cert_username)) == 0) msg_fatal("SASL per-connection initialization failed"); /* diff --git a/src/xsasl/xsasl.h b/src/xsasl/xsasl.h index b494d7e..2cbff64 100644 --- a/src/xsasl/xsasl.h +++ b/src/xsasl/xsasl.h @@ -54,7 +54,8 @@ typedef struct XSASL_SERVER_CREATE_ARGS { const char *service; const char *user_realm; const char *security_options; - int tls_flag; + int tls_flags; + const char *tls_cert_username; /* (Or 0; only used if tls_flags!=0!) */ } XSASL_SERVER_CREATE_ARGS; typedef struct XSASL_SERVER_IMPL { @@ -65,12 +66,15 @@ typedef struct XSASL_SERVER_IMPL { extern XSASL_SERVER_IMPL *xsasl_server_init(const char *, const char *); extern ARGV *xsasl_server_types(void); +#define XSASL_TLS_SECURED (1<<0) /* (In fact: .tls_flags not 0) */ +#define XSASL_TLS_CLIENT_CERT (1<<1) + #define xsasl_server_create(impl, args) \ (impl)->create((impl), (args)) -#define XSASL_SERVER_CREATE(impl, args, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ +#define XSASL_SERVER_CREATE(impl, args, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) \ xsasl_server_create((impl), (((args)->a1), ((args)->a2), ((args)->a3), \ ((args)->a4), ((args)->a5), ((args)->a6), ((args)->a7), ((args)->a8), \ - ((args)->a9), ((args)->a10), (args))) + ((args)->a9), ((args)->a10), ((args)->a11), (args))) #define xsasl_server_done(impl) (impl)->done((impl)); /* diff --git a/src/xsasl/xsasl_dovecot_server.c b/src/xsasl/xsasl_dovecot_server.c index 601f787..780fd91 100644 --- a/src/xsasl/xsasl_dovecot_server.c +++ b/src/xsasl/xsasl_dovecot_server.c @@ -166,7 +166,8 @@ typedef struct { char *username; /* authenticated user */ VSTRING *sasl_line; unsigned int sec_props; /* Postfix mechanism filter */ - int tls_flag; /* TLS enabled in this session */ + int tls_flags; /* TLS flags of this session */ + char *tls_cert_username; /* If .tls_flags, maybe commonName */ char *mechanism_list; /* filtered mechanism list */ ARGV *mechanism_argv; /* ditto */ char *client_addr; /* remote IP address */ @@ -450,7 +451,9 @@ static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *impl, server->last_request_id = 0; server->mechanism_list = 0; server->mechanism_argv = 0; - server->tls_flag = args->tls_flag; + server->tls_flags = args->tls_flags; + server->tls_cert_username = ((args->tls_flags & XSASL_TLS_CLIENT_CERT) + && args->tls_cert_username) ? mystrdup(args->tls_cert_username) : 0; server->sec_props = name_mask_opt(myname, xsasl_dovecot_conf_sec_props, args->security_options, @@ -502,6 +505,8 @@ static void xsasl_dovecot_server_free(XSASL_SERVER *xp) vstring_free(server->sasl_line); if (server->username) myfree(server->username); + if (server->tls_cert_username) + myfree(server->tls_cert_username); if (server->mechanism_list) { myfree(server->mechanism_list); argv_free(server->mechanism_argv); @@ -680,9 +685,20 @@ int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, server->last_request_id, sasl_method, server->service, server->server_addr, server->client_addr); - if (server->tls_flag) + if (server->tls_flags) { /* XXX Encapsulate for logging. */ vstream_fputs("\tsecured", server->impl->sasl_stream); + if (server->tls_flags & XSASL_TLS_CLIENT_CERT) { + /* XXX Encapsulate for logging. */ + vstream_fputs("\tvalid-client-cert", + server->impl->sasl_stream); + if (server->tls_cert_username) + /* XXX Encapsulate for logging. */ + vstream_fprintf(server->impl->sasl_stream, + "\tcert_username=%s", + server->tls_cert_username); + } + } if (init_response) { /* diff --git a/src/xsasl/xsasl_server.c b/src/xsasl/xsasl_server.c index e8d7e16..dfdde0c 100644 --- a/src/xsasl/xsasl_server.c +++ b/src/xsasl/xsasl_server.c @@ -18,12 +18,16 @@ /* .in +4 /* typedef struct XSASL_SERVER_CREATE_ARGS { /* VSTREAM *stream; +/* int addr_family; /* const char *server_addr; +/* const char *server_port; /* const char *client_addr; +/* const char *client_port; /* const char *service; /* const char *user_realm; /* const char *security_options; -/* int tls_flag; +/* int tls_flags; +/* const char *tls_cert_username; /* } XSASL_SERVER_CREATE_ARGS; /* .in -4 /* @@ -34,7 +38,7 @@ /* XSASL_SERVER *XSASL_SERVER_CREATE(implementation, args, /* stream = stream_value, /* ..., -/* tls_flag = tls_flag_value) +/* tls_cert_username = tls_cert_username_value) /* XSASL_SERVER_IMPL *implementation; /* XSASL_SERVER_CREATE_ARGS *args; /* @@ -169,6 +173,16 @@ /* The connection between client and server. When SASL /* encryption is negotiated, the plug-in will transparently /* intercept the socket read/write operations. +/* .IP tls_flags +/* 0 or with XSASL_TLS_SECURED bit set if the connection is over +/* secured transport. +/* If the XSASL_TLS_CLIENT_CERT bit is also set then the client +/* presented a valid client certificate. +/* .IP tls_cert_username +/* Only inspected during session authentication if +/* XSASL_TLS_CLIENT_CERT is set in tls_flags, this is the +/* commonName presented by the client certificate. +/* The storage must be duplicated. /* .IP user_realm /* Authentication domain or null pointer. /* SECURITY