static void smtpd_start_tls(SMTPD_STATE *state)
{
int rate;
+ tls_server_start_props props;
/*
* Wrapper mode uses a dedicated port and always requires TLS.
* perform SMTP transactions when the client does not use the STARTTLS
* command. For this reason, Postfix does not require client certificate
* verification unless TLS is required.
+ *
+ * XXX We append the service name to the session cache ID, so that there
+ * won't be collisions between multiple master.cf entries that use
+ * different roots of trust. This does not eliminate collisions between
+ * multiple inetd.conf entries that use different roots of trust. For a
+ * universal solution we would have to append the local IP address + port
+ * number information.
*/
- state->tls_context =
- tls_server_start(smtpd_tls_ctx, state->client,
- var_smtpd_starttls_tmout, var_smtpd_tls_loglevel,
- state->name, state->addr,
- (var_smtpd_tls_req_ccert && state->tls_enforce_tls));
+ memset((char *) &props, 0, sizeof(props));
+ props.ctx = smtpd_tls_ctx;
+ props.stream = state->client;
+ props.log_level = var_smtpd_tls_loglevel;
+ props.timeout = var_smtpd_starttls_tmout;
+ props.requirecert = (var_smtpd_tls_req_ccert && state->tls_enforce_tls);
+ props.serverid = state->service;
+ props.peername = state->name;
+ props.peeraddr = state->addr;
+ state->tls_context = tls_server_start(&props);
/*
* XXX The client event count/rate control must be consistent in its use
/* SSL_CTX *tls_server_init(props)
/* const tls_server_props *props;
/*
-/* TLScontext_t *tls_server_start(server_ctx, stream, timeout, log_level,
-/* peername, peeraddr, requirecert)
-/* SSL_CTX *server_ctx;
-/* VSTREAM *stream;
-/* int timeout;
-/* int log_level;
-/* const char *peername;
-/* const char *peeraddr;
-/* int requirecert;
+/* TLScontext_t *tls_server_start(props)
+/* const tls_server_start_props *props;
/*
/* void tls_server_stop(server_ctx, stream, failure, TLScontext)
/* SSL_CTX *server_ctx;
if ((TLScontext = SSL_get_ex_data(ssl, TLScontext_index)) == 0)
msg_panic("%s: null TLScontext in session lookup callback", myname);
-#define HEX_CACHE_ID(id, len) \
- hex_encode(vstring_alloc(2 * (len) + 1), (char *) (id), (len))
+#define GEN_CACHE_ID(buf, id, len, service) \
+ do { \
+ buf = vstring_alloc(2 * (len) + 1 + strlen(service) + 3); \
+ hex_encode(buf, (char *) (id), (len)); \
+ vstring_sprintf_append(buf, "&s=%s", (service)); \
+ } while (0)
- cache_id = HEX_CACHE_ID(session_id, session_id_length);
+
+ GEN_CACHE_ID(cache_id, session_id, session_id_length, TLScontext->serverid);
if (TLScontext->log_level >= 2)
msg_info("looking up session %s in %s cache",
if (TLScontext->cache_type == 0)
return;
- cache_id = HEX_CACHE_ID(session->session_id, session->session_id_length);
+ GEN_CACHE_ID(cache_id, session->session_id, session->session_id_length,
+ TLScontext->serverid);
+
if (TLScontext->log_level >= 2)
msg_info("remove session %s from %s cache",
STR(cache_id), TLScontext->cache_type);
if ((TLScontext = SSL_get_ex_data(ssl, TLScontext_index)) == 0)
msg_panic("%s: null TLScontext in new session callback", myname);
- cache_id = HEX_CACHE_ID(session->session_id, session->session_id_length);
+ GEN_CACHE_ID(cache_id, session->session_id, session->session_id_length,
+ TLScontext->serverid);
if (TLScontext->log_level >= 2)
msg_info("save session %s to %s cache",
* the SMTP buffers are flushed and the "220 Ready to start TLS" was sent to
* the client, so that we can immediately start the TLS handshake process.
*/
-TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream,
- int timeout, int log_level,
- const char *peername,
- const char *peeraddr, int requirecert)
+TLScontext_t *tls_server_start(const tls_server_start_props *props)
{
int sts;
int j;
unsigned char md[EVP_MAX_MD_SIZE];
char buf[CCERT_BUFSIZ];
- if (log_level >= 1)
- msg_info("setting up TLS connection from %s[%s]", peername, peeraddr);
+ if (props->log_level >= 1)
+ msg_info("setting up TLS connection from %s[%s]",
+ props->peername, props->peeraddr);
/*
* Allocate a new TLScontext for the new connection and get an SSL
* structure. Add the location of TLScontext to the SSL to later retrieve
* the information inside the tls_verify_certificate_callback().
*/
- TLScontext = tls_alloc_context(log_level, peername);
- TLScontext->cache_type = SSL_CTX_get_ex_data(server_ctx, TLSscache_index);
+ TLScontext = tls_alloc_context(props->log_level, props->peername);
+ TLScontext->cache_type = SSL_CTX_get_ex_data(props->ctx, TLSscache_index);
+ TLScontext->serverid = mystrdup(props->serverid);
- if ((TLScontext->con = (SSL *) SSL_new(server_ctx)) == NULL) {
+ if ((TLScontext->con = (SSL *) SSL_new(props->ctx)) == NULL) {
msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
tls_print_errors();
tls_free_context(TLScontext);
* Set the verification parameters to be checked in
* tls_verify_certificate_callback().
*/
- if (requirecert) {
+ if (props->requirecert) {
verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
verify_flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
TLScontext->enforce_verify_errors = 1;
* Well there is a BIO below the SSL routines that is automatically
* created for us, so we can use it for debugging purposes.
*/
- if (log_level >= 3)
+ if (props->log_level >= 3)
BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
/*
* Error handling: If the SSL handhake fails, we print out an error message
* and remove all TLS state concerning this session.
*/
- sts = tls_bio_accept(vstream_fileno(stream), timeout, TLScontext);
+ sts = tls_bio_accept(vstream_fileno(props->stream), props->timeout,
+ TLScontext);
if (sts <= 0) {
- msg_info("SSL_accept error from %s[%s]: %d", peername, peeraddr, sts);
+ msg_info("SSL_accept error from %s[%s]: %d",
+ props->peername, props->peeraddr, sts);
tls_print_errors();
tls_free_context(TLScontext);
return (0);
}
/* Only loglevel==4 dumps everything */
- if (log_level < 4)
+ if (props->log_level < 4)
BIO_set_callback(SSL_get_rbio(TLScontext->con), 0);
/*
* session was negotiated.
*/
TLScontext->session_reused = SSL_session_reused(TLScontext->con);
- if (log_level >= 2 && TLScontext->session_reused)
+ if (props->log_level >= 2 && TLScontext->session_reused)
msg_info("Reusing old session");
/*
if (SSL_get_verify_result(TLScontext->con) == X509_V_OK)
TLScontext->peer_verified = 1;
- if (log_level >= 2) {
+ if (props->log_level >= 2) {
X509_NAME_oneline(X509_get_subject_name(peer),
buf, sizeof(buf));
msg_info("subject=%s", buf);
else
TLScontext->peer_fingerprint[(j * 3) + 2] = '\0';
}
- if (log_level >= 1)
+ if (props->log_level >= 1)
msg_info("fingerprint=%s", TLScontext->peer_fingerprint);
}
if ((TLScontext->peer_CN = tls_peer_CN(peer)) == 0)
if ((TLScontext->issuer_CN = tls_issuer_CN(peer)) == 0)
TLScontext->issuer_CN = mystrdup("");
- if (log_level >= 1) {
+ if (props->log_level >= 1) {
if (TLScontext->peer_verified)
msg_info("Verified: subject_CN=%s, issuer=%s",
TLScontext->peer_CN, TLScontext->issuer_CN);
* If this is a cached session, we have to check by hand if the cached
* session peer was verified.
*/
- if (requirecert) {
+ if (props->requirecert) {
if (!TLScontext->peer_verified || !TLScontext->peer_CN) {
if (TLScontext->session_reused == 0)
msg_panic("tls_server_start: peer was not verified");
msg_info("Re-used session without peer certificate removed");
- uncache_session(server_ctx, TLScontext);
+ uncache_session(props->ctx, TLScontext);
tls_free_context(TLScontext);
return (0);
}
* The TLS engine is active. Switch to the tls_timed_read/write()
* functions and make the TLScontext available to those functions.
*/
- tls_stream_start(stream, TLScontext);
+ tls_stream_start(props->stream, TLScontext);
- if (log_level >= 1)
+ if (props->log_level >= 1)
msg_info("TLS connection established from %s[%s]: %s with cipher %s (%d/%d bits)",
- peername, peeraddr,
+ props->peername, props->peeraddr,
TLScontext->protocol, TLScontext->cipher_name,
TLScontext->cipher_usebits, TLScontext->cipher_algbits);
tls_int_seed();