2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 05:07:58 +00:00

postfix-2.3-20050920

This commit is contained in:
Wietse Venema 2005-09-20 00:00:00 -05:00 committed by Viktor Dukhovni
parent 04571e906b
commit b406b5fe04
30 changed files with 356 additions and 377 deletions

2
postfix/.indent.pro vendored
View File

@ -224,6 +224,8 @@
-TWAIT_STATUS_T
-TWATCHDOG
-TWATCH_FD
-TX509
-TX509_NAME
-TX509_STORE_CTX
-Tregex_t
-Tregmatch_t

View File

@ -11115,6 +11115,15 @@ Apologies for any names omitted.
needed before cleanup_bounce() can seek to the start of the
queue file after a file size error. File: util/vstream.c.
20050920
Cleanup: removed the legacy "tls_info" structure, factored
out common code for peer_CN and issuer_CN lookup, and added
sanity check to not verify subject common names that contain
nulls or that are execessively long. Patch by Victor Duchovni.
Files: tls_client.c, tls_server.c, tls_session.c, tls_misc.c,
tls_verify.c.
Open problems:
Look for systems with XPG basename() declared in <libgen.h>,

View File

@ -13,7 +13,7 @@ The main feature of interest is that IPv6 uses 128-bit IP addresses instead of
the 32-bit addresses used by IPv4. It can therefore accommodate a much larger
number of hosts and networks without ugly kluges such as NAT. A side benefit of
the much larger address space is that it makes random network scanning
unpractical.
impractical.
Postfix uses the same SMTP protocol over IPv6 as it already uses over the older
IPv4 network, and does AAAA record lookups in the DNS in addition to the older

View File

@ -20,6 +20,10 @@ When receiving mail, Postfix logs the client-provided username, authentication
method, and sender address to the maillog file, and optionally grants mail
access via the permit_sasl_authenticated UCE restriction.
When sending mail, Postfix can look up the server hostname or destination
domain (the address right-hand part) in a table, and if a username/password is
found, it will use that username and password to authenticate to the server.
This document covers the following topics:
* What SASL versions are supported
@ -31,10 +35,6 @@ This document covers the following topics:
* Enabling SASL authentication in the Postfix SMTP client
* Credits
When sending mail, Postfix can look up the server hostname or destination
domain (the address right-hand part) in a table, and if a username/password is
found, it will use that username and password to authenticate to the server.
WWhhaatt SSAASSLL vveerrssiioonnss aarree ssuuppppoorrtteedd
Postfix+SASL 1.5.5 was seen working on RedHat 6.1 (pwcheck_method set to shadow

View File

@ -422,7 +422,7 @@ Example:
...
The Postfix list manipulation routines give special treatment to whitespace and
some other characters, making the use of certificate names unpractical. Instead
some other characters, making the use of certificate names impractical. Instead
we use the certificate fingerprints as they are difficult to fake but easy to
use for lookup. Postfix lookup tables are in the form of (key, value) pairs.
Since we only need the key, the value can be chosen freely, e.g. the name of

View File

@ -30,7 +30,7 @@ between these implementations. </p>
addresses instead of the 32-bit addresses used by IPv4. It can
therefore accommodate a much larger number of hosts and networks
without ugly kluges such as NAT. A side benefit of the much larger
address space is that it makes random network scanning unpractical.
address space is that it makes random network scanning impractical.
</p>
<p> Postfix uses the same SMTP protocol over IPv6 as it already

View File

@ -37,6 +37,11 @@ authentication method, and sender address to the maillog file, and
optionally grants mail access via the <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a>
UCE restriction. </p>
<p> When sending mail, Postfix can look up the server hostname or
destination domain (the address right-hand part) in a table, and if a
username/password is found, it will use that username and password
to authenticate to the server. </p>
<p>This document covers the following topics: </p>
<ul>
@ -63,11 +68,6 @@ Postfix SMTP client</a></li>
</ul>
<p> When sending mail, Postfix can look up the server hostname or
destination domain (the address right-hand part) in a table, and if a
username/password is found, it will use that username and password
to authenticate to the server. </p>
<h2><a name="versions">What SASL versions are supported</a></h2>
<p> Postfix+SASL 1.5.5 was seen working on RedHat 6.1 (pwcheck_method

View File

@ -591,7 +591,7 @@ Postfix SMTP server access control: </p>
<dt> <a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a> </dt> <dd> <p> Allow the remote SMTP
client SMTP request if the client certificate passes verification,
and if its fingerprint is listed in the list of client certificates
(see relay_clientcerts discussion below). </p> </dd>
(see <a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a> discussion below). </p> </dd>
<dt> <a href="postconf.5.html#permit_tls_all_clientcerts">permit_tls_all_clientcerts</a> </dt> <dd> <p> Allow the remote
client SMTP request if the client certificate passes verification.
@ -614,7 +614,7 @@ The <a href="postconf.5.html#permit_tls_all_clientcerts">permit_tls_all_clientce
specially created email relay server. </p>
<p> It is however recommended to stay with the <a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a>
feature and list all certificates via $relay_clientcerts, as
feature and list all certificates via $<a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a>, as
<a href="postconf.5.html#permit_tls_all_clientcerts">permit_tls_all_clientcerts</a> does not permit any control when a
certificate must no longer be used (e.g. an employee leaving). </p>
@ -633,7 +633,7 @@ certificate must no longer be used (e.g. an employee leaving). </p>
<p> The Postfix list manipulation routines give special treatment
to whitespace and some other characters, making the use of certificate
names unpractical. Instead we use the certificate fingerprints as
names impractical. Instead we use the certificate fingerprints as
they are difficult to fake but easy to use for lookup. Postfix
lookup tables are in the form of (key, value) pairs. Since we only
need the key, the value can be chosen freely, e.g. the name of
@ -644,7 +644,7 @@ the user or host.</p>
<blockquote>
<pre>
/etc/postfix/main.cf:
relay_clientcerts = hash:/etc/postfix/relay_clientcerts
<a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a> = hash:/etc/postfix/relay_clientcerts
/etc/postfix/relay_clientcerts:
D7:04:2F:A7:0B:8C:A5:21:FA:31:77:E1:41:8A:EE:80 lutzpc.at.home

View File

@ -324,7 +324,7 @@ LDAP_TABLE(5) LDAP_TABLE(5)
NOTE: DO NOT define this parameter for <a href="local.8.html">local(8)</a>
aliases.
This feature is available in Postfix 2.1 and later.
This feature is available in Postfix 1.0 and later.
<b>result_attribute (default: maildrop)</b>
The attribute(s) Postfix will read from any direc-

View File

@ -305,7 +305,7 @@ for LDAP lookups.
NOTE: DO NOT define this parameter for local(8) aliases.
This feature is available in Postfix 2.1 and later.
This feature is available in Postfix 1.0 and later.
.IP "\fBresult_attribute (default: maildrop)\fR"
The attribute(s) Postfix will read from any directory
entries returned by the lookup, to be resolved to an email

View File

@ -30,7 +30,7 @@ between these implementations. </p>
addresses instead of the 32-bit addresses used by IPv4. It can
therefore accommodate a much larger number of hosts and networks
without ugly kluges such as NAT. A side benefit of the much larger
address space is that it makes random network scanning unpractical.
address space is that it makes random network scanning impractical.
</p>
<p> Postfix uses the same SMTP protocol over IPv6 as it already

View File

@ -37,6 +37,11 @@ authentication method, and sender address to the maillog file, and
optionally grants mail access via the permit_sasl_authenticated
UCE restriction. </p>
<p> When sending mail, Postfix can look up the server hostname or
destination domain (the address right-hand part) in a table, and if a
username/password is found, it will use that username and password
to authenticate to the server. </p>
<p>This document covers the following topics: </p>
<ul>
@ -63,11 +68,6 @@ Postfix SMTP client</a></li>
</ul>
<p> When sending mail, Postfix can look up the server hostname or
destination domain (the address right-hand part) in a table, and if a
username/password is found, it will use that username and password
to authenticate to the server. </p>
<h2><a name="versions">What SASL versions are supported</a></h2>
<p> Postfix+SASL 1.5.5 was seen working on RedHat 6.1 (pwcheck_method

View File

@ -633,7 +633,7 @@ certificate must no longer be used (e.g. an employee leaving). </p>
<p> The Postfix list manipulation routines give special treatment
to whitespace and some other characters, making the use of certificate
names unpractical. Instead we use the certificate fingerprints as
names impractical. Instead we use the certificate fingerprints as
they are difficult to fake but easy to use for lookup. Postfix
lookup tables are in the form of (key, value) pairs. Since we only
need the key, the value can be chosen freely, e.g. the name of

View File

@ -293,7 +293,7 @@
#
# NOTE: DO NOT define this parameter for local(8) aliases.
#
# This feature is available in Postfix 2.1 and later.
# This feature is available in Postfix 1.0 and later.
# .IP "\fBresult_attribute (default: maildrop)\fR"
# The attribute(s) Postfix will read from any directory
# entries returned by the lookup, to be resolved to an email

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20050829"
#define MAIL_RELEASE_DATE "20050920"
#define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT

View File

@ -217,7 +217,6 @@ typedef struct SMTP_SESSION {
int tls_enforce_tls; /* must do TLS */
int tls_enforce_peername; /* cert must match */
TLScontext_t *tls_context; /* TLS session state */
tls_info_t tls_info; /* legacy */
#endif
} SMTP_SESSION;

View File

@ -626,8 +626,7 @@ static int smtp_start_tls(SMTP_STATE *state, int misc_flags)
var_smtp_starttls_tmout,
session->tls_enforce_peername,
session->host,
lowercase(vstring_str(serverid)),
&(session->tls_info));
lowercase(vstring_str(serverid)));
vstring_free(serverid);
if (session->tls_context == 0)
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
@ -815,6 +814,7 @@ static void smtp_header_rewrite(void *context, int header_class,
}
}
}
/* smtp_mime_fail - MIME problem */
static void smtp_mime_fail(SMTP_STATE *state, int mime_errs)

View File

@ -233,7 +233,6 @@ SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest,
session->tls_use_tls = session->tls_enforce_tls = 0;
session->tls_enforce_peername = 0;
session->tls_context = 0;
session->tls_info = tls_info_zero;
/*
* Override the main.cf TLS policy with an optional per-site policy.
@ -282,8 +281,7 @@ void smtp_session_free(SMTP_SESSION *session)
vstream_fflush(session->stream);
if (session->tls_context)
tls_client_stop(smtp_tls_ctx, session->stream,
var_smtp_starttls_tmout, 0,
&(session->tls_info));
var_smtp_starttls_tmout, 0, session->tls_context);
}
#endif
if (session->stream)

View File

@ -2142,15 +2142,17 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
if (var_smtpd_tls_received_header && state->tls_context) {
out_fprintf(out_stream, REC_TYPE_NORM,
"\t(using %s with cipher %s (%d/%d bits))",
state->tls_info.protocol, state->tls_info.cipher_name,
state->tls_info.cipher_usebits,
state->tls_info.cipher_algbits);
if (state->tls_info.peer_CN) {
peer_CN = VSTRING_STRDUP(state->tls_info.peer_CN);
state->tls_context->protocol,
state->tls_context->cipher_name,
state->tls_context->cipher_usebits,
state->tls_context->cipher_algbits);
if (state->tls_context->peer_CN) {
peer_CN = VSTRING_STRDUP(state->tls_context->peer_CN);
comment_sanitize(peer_CN);
issuer_CN = VSTRING_STRDUP(state->tls_info.issuer_CN);
issuer_CN = VSTRING_STRDUP(state->tls_context->issuer_CN ?
state->tls_context->issuer_CN : "");
comment_sanitize(issuer_CN);
if (state->tls_info.peer_verified)
if (state->tls_context->peer_verified)
out_fprintf(out_stream, REC_TYPE_NORM,
"\t(Client CN \"%s\", Issuer \"%s\" (verified OK))",
STR(peer_CN), STR(issuer_CN));
@ -3036,8 +3038,7 @@ static void smtpd_start_tls(SMTPD_STATE *state)
*/
state->tls_context =
tls_server_start(smtpd_tls_ctx, state->client,
var_smtpd_starttls_tmout,
state->name, state->addr, &(state->tls_info),
var_smtpd_starttls_tmout, state->name, state->addr,
(var_smtpd_tls_req_ccert && state->tls_enforce_tls));
/*
@ -3121,7 +3122,7 @@ static void tls_reset(SMTPD_STATE *state)
failure = 1;
vstream_fflush(state->client); /* NOT: smtp_flush() */
tls_server_stop(smtpd_tls_ctx, state->client, var_smtpd_starttls_tmout,
failure, &(state->tls_info));
failure, state->tls_context);
state->tls_context = 0;
}
}

View File

@ -175,7 +175,6 @@ typedef struct SMTPD_STATE {
int tls_enforce_tls; /* must use TLS */
int tls_auth_only; /* use SASL over TLS only */
TLScontext_t *tls_context; /* TLS session state */
tls_info_t tls_info; /* legacy */
#endif
} SMTPD_STATE;

View File

@ -1216,13 +1216,17 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
char *low_name;
const char *found;
if (state->tls_info.peer_verified && permit_all_certs) {
if (!state->tls_context)
return SMTPD_CHECK_DUNNO;
if (state->tls_context->peer_verified && permit_all_certs) {
if (msg_verbose)
msg_info("Relaying allowed for all verified client certificates");
return (SMTPD_CHECK_OK);
}
if (state->tls_info.peer_verified && state->tls_info.peer_fingerprint) {
low_name = lowercase(mystrdup(state->tls_info.peer_fingerprint));
if (state->tls_context->peer_verified
&& state->tls_context->peer_fingerprint) {
low_name = lowercase(mystrdup(state->tls_context->peer_fingerprint));
found = maps_find(relay_ccerts, low_name, DICT_FLAG_FIXED);
myfree(low_name);
if (found) {
@ -1231,7 +1235,7 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
return (SMTPD_CHECK_OK);
} else if (msg_verbose)
msg_info("relay_clientcerts: No match for fingerprint '%s'",
state->tls_info.peer_fingerprint);
state->tls_context->peer_fingerprint);
}
return (SMTPD_CHECK_DUNNO);
}
@ -2496,9 +2500,13 @@ static int check_ccert_access(SMTPD_STATE *state, const char *table,
char *myname = "check_ccert_access";
int found;
if (state->tls_info.peer_verified && state->tls_info.peer_fingerprint) {
if (!state->tls_context)
return SMTPD_CHECK_DUNNO;
if (state->tls_context->peer_verified
&& state->tls_context->peer_fingerprint) {
if (msg_verbose)
msg_info("%s: %s", myname, state->tls_info.peer_fingerprint);
msg_info("%s: %s", myname, state->tls_context->peer_fingerprint);
/*
* Regexp tables don't make sense for certificate fingerprints. That
@ -2510,8 +2518,10 @@ static int check_ccert_access(SMTPD_STATE *state, const char *table,
* client name and address are always syslogged as part of a "reject"
* event.
*/
return (check_access(state, table, state->tls_info.peer_fingerprint,
DICT_FLAG_NONE, &found, state->tls_info.peer_CN,
return (check_access(state, table,
state->tls_context->peer_fingerprint,
DICT_FLAG_NONE, &found,
state->tls_context->peer_CN,
SMTPD_NAME_CCERT, def_acl));
}
return (SMTPD_CHECK_DUNNO);
@ -3228,15 +3238,15 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
state->sasl_sender : "",
#endif
#ifdef USE_TLS
#define IF_VERIFIED(x) \
((state->tls_context && \
state->tls_context->peer_verified && ((x) != 0)) ? (x) : "")
ATTR_TYPE_STR, MAIL_ATTR_CCERT_SUBJECT,
state->tls_info.peer_verified ?
state->tls_info.peer_CN : "",
IF_VERIFIED(state->tls_context->peer_CN),
ATTR_TYPE_STR, MAIL_ATTR_CCERT_ISSSUER,
state->tls_info.peer_verified ?
state->tls_info.issuer_CN : "",
IF_VERIFIED(state->tls_context->issuer_CN),
ATTR_TYPE_STR, MAIL_ATTR_CCERT_FINGERPRINT,
state->tls_info.peer_verified ?
state->tls_info.peer_fingerprint : "",
IF_VERIFIED(state->tls_context->peer_fingerprint),
#endif
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */

View File

@ -138,7 +138,6 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream,
state->tls_enforce_tls = 0;
state->tls_auth_only = 0;
state->tls_context = 0;
state->tls_info = tls_info_zero;
#endif
#ifdef USE_SASL_AUTH

View File

@ -1,11 +1,11 @@
SHELL = /bin/sh
SRCS = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c \
tls_prng_exch.c tls_stream.c tls_bio_ops.c tls_misc.c tls_dh.c \
tls_rsa.c tls_verify.c tls_certkey.c tls_session.c tls_temp.c \
tls_rsa.c tls_verify.c tls_certkey.c tls_session.c \
tls_client.c tls_server.c tls_scache.c tls_mgr.c tls_seed.c
OBJS = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o \
tls_prng_exch.o tls_stream.o tls_bio_ops.o tls_misc.o tls_dh.o \
tls_rsa.o tls_verify.o tls_certkey.o tls_session.o tls_temp.o \
tls_rsa.o tls_verify.o tls_certkey.o tls_session.o \
tls_client.o tls_server.o tls_scache.o tls_mgr.o tls_seed.o
HDRS = tls.h tls_prng.h tls_scache.h tls_mgr.h
TESTSRC =
@ -222,12 +222,6 @@ tls_stream.o: ../../include/vstream.h
tls_stream.o: ../../include/vstring.h
tls_stream.o: tls.h
tls_stream.o: tls_stream.c
tls_temp.o: ../../include/sys_defs.h
tls_temp.o: ../../include/vbuf.h
tls_temp.o: ../../include/vstream.h
tls_temp.o: ../../include/vstring.h
tls_temp.o: tls.h
tls_temp.o: tls_temp.c
tls_verify.o: ../../include/msg.h
tls_verify.o: ../../include/sys_defs.h
tls_verify.o: ../../include/vbuf.h

View File

@ -35,15 +35,6 @@
/*
* TLS session context, also used by the VSTREAM call-back routines for SMTP
* input/output, and by OpenSSL call-back routines for key verification.
*
* XXX Eliminate fixed-length buffers where possible.
*
* XXX Eliminate the tls_info structure; it is no longer needed now that the
* TLScontext structure is exposed to the caller. If the caller's TLScontext
* pointer is null, there is no TLS session. This change (plus other
* changes) eliminated global variables that were shared between TLS client
* and server code. Multiple clients and/or servers can now co-exist in the
* same process.
*/
#define CCERT_BUFSIZ 256
#define HOST_BUFSIZ 255 /* RFC 1035 */
@ -53,63 +44,48 @@ typedef struct {
BIO *internal_bio; /* postfix/TLS side of pair */
BIO *network_bio; /* network side of pair */
char *serverid; /* unique server identifier */
char peer_subject[CCERT_BUFSIZ];
char peer_issuer[CCERT_BUFSIZ];
char peer_CN[CCERT_BUFSIZ];
char issuer_CN[CCERT_BUFSIZ];
unsigned char md[EVP_MAX_MD_SIZE];
char fingerprint[EVP_MAX_MD_SIZE * 3];
char *peer_CN; /* Peer Common Name */
char *issuer_CN; /* Issuer Common Name */
char *peer_fingerprint; /* ASCII fingerprint */
char *peername;
int enforce_verify_errors;
int enforce_CN;
int hostname_matched;
int log_level;
} TLScontext_t;
#define TLS_BIO_BUFSIZE 8192
typedef struct {
int peer_verified;
int hostname_matched;
char *peer_subject;
char *peer_issuer;
char *peer_fingerprint;
char *peer_CN;
char *issuer_CN;
const char *protocol;
const char *cipher_name;
int cipher_usebits;
int cipher_algbits;
} tls_info_t;
int log_level;
} TLScontext_t;
extern const tls_info_t tls_info_zero;
#define TLS_BIO_BUFSIZE 8192
/*
* tls_client.c
*/
extern SSL_CTX *tls_client_init(int);
extern TLScontext_t *tls_client_start(SSL_CTX *, VSTREAM *, int, int,
const char *, const char *,
tls_info_t *);
const char *, const char *);
#define tls_client_stop(ctx , stream, timeout, failure, tls_info) \
tls_session_stop((ctx), (stream), (timeout), (failure), (tls_info))
#define tls_client_stop(ctx , stream, timeout, failure, TLScontext) \
tls_session_stop((ctx), (stream), (timeout), (failure), (TLScontext))
/*
* tls_server.c
*/
extern SSL_CTX *tls_server_init(int, int);
extern TLScontext_t *tls_server_start(SSL_CTX *, VSTREAM *, int,
const char *, const char *,
tls_info_t *, int);
const char *, const char *, int);
#define tls_server_stop(ctx , stream, timeout, failure, tls_info) \
tls_session_stop((ctx), (stream), (timeout), (failure), (tls_info))
#define tls_server_stop(ctx , stream, timeout, failure, TLScontext) \
tls_session_stop((ctx), (stream), (timeout), (failure), (TLScontext))
/*
* tls_session.c
*/
extern void tls_session_stop(SSL_CTX *, VSTREAM *, int, int, tls_info_t *);
extern void tls_session_stop(SSL_CTX *, VSTREAM *, int, int,
TLScontext_t *);
#ifdef TLS_INTERNAL
@ -167,6 +143,8 @@ extern RSA *tls_tmp_rsa_cb(SSL *, int, int);
/*
* tls_verify.c
*/
extern char *tls_peer_CN(X509 *);
extern char *tls_issuer_CN(X509 *);
extern int tls_verify_certificate_callback(int, X509_STORE_CTX *);
/*

View File

@ -11,23 +11,48 @@
/*
/* TLScontext_t *tls_client_start(client_ctx, stream, timeout,
/* enforce_peername, peername,
/* serverid, tls_info)
/* serverid)
/* SSL_CTX *client_ctx;
/* VSTREAM *stream;
/* int timeout;
/* int enforce_peername;
/* const char *peername;
/* const char *serverid;
/* tls_info_t *tls_info;
/*
/* void tls_client_stop(client_ctx, stream, failure, tls_info)
/* void tls_client_stop(client_ctx, stream, failure, TLScontext)
/* SSL_CTX *client_ctx;
/* VSTREAM *stream;
/* int failure;
/* tls_info_t *tls_info;
/* TLScontext_t *TLScontext;
/* DESCRIPTION
/* This module is the interface between Postfix TLS clients
/* and the OpenSSL library and TLS entropy and cache manager.
/* This module is the interface between Postfix TLS clients,
/* the OpenSSL library and the TLS entropy and cache manager.
/*
/* The SMTP client will attempt to verify the server hostname
/* against the names listed in the server certificate. When
/* a hostname match is required, the verification fails
/* on certificate verification or hostname mis-match errors.
/* When no hostname match is required, hostname verification
/* failures are logged but they do not affect the TLS handshake
/* or the SMTP session.
/*
/* The rules for peer name wild-card matching differ between
/* RFC 2818 (HTTP over TLS) and RFC 2830 (LDAP over TLS), while
/* RFC RFC3207 (SMTP over TLS) does not specify a rule at all.
/* Postfix uses a restrictive match algorithm. One asterisk
/* ('*') is allowed as the left-most component of a wild-card
/* certificate name; it matches the left-most component of
/* the peer hostname.
/*
/* Another area where RFCs aren't always explicit is the
/* handling of dNSNames in peer certificates. RFC 3207 (SMTP
/* over TLS) does not mention dNSNames. Postfix follows the
/* strict rules in RFC 2818 (HTTP over TLS), section 3.1: The
/* Subject Alternative Name/dNSName has precedence over
/* CommonName. If at least one dNSName is provided, Postfix
/* verifies those against the peer hostname and ignores the
/* CommonName, otherwise Postfix verifies the CommonName
/* against the peer hostname.
/*
/* tls_client_init() is called once when the SMTP client
/* initializes.
@ -35,12 +60,10 @@
/* so that peer-specific behavior is not possible.
/*
/* tls_client_start() activates the TLS feature for the VSTREAM
/* passed as argument. We expect that network buffers are flushed and the
/* TLS handshake can begin immediately. Information about the peer
/* is stored into the tls_info structure passed as argument.
/* The serverid argument specifies a string that hopefully
/* uniquely identifies a server. It is used as the client
/* session cache lookup key.
/* passed as argument. We expect that network buffers are flushed and
/* the TLS handshake can begin immediately. The serverid argument
/* specifies a string that hopefully uniquely identifies a server.
/* It is used as the client session cache lookup key.
/*
/* tls_client_stop() sends the "close notify" alert via
/* SSL_shutdown() to the peer and resets all connection specific
@ -51,34 +74,32 @@
/* If the failure flag is set, no SSL_shutdown() handshake is performed.
/*
/* Once the TLS connection is initiated, information about the TLS
/* state is available via the tls_info structure:
/* .IP tls_info->protocol
/* state is available via the TLScontext structure:
/* .IP TLScontext->protocol
/* the protocol name (SSLv2, SSLv3, TLSv1),
/* .IP tls_info->cipher_name
/* .IP TLScontext->cipher_name
/* the cipher name (e.g. RC4/MD5),
/* .IP tls_info->cipher_usebits
/* .IP TLScontext->cipher_usebits
/* the number of bits actually used (e.g. 40),
/* .IP tls_info->cipher_algbits
/* .IP TLScontext->cipher_algbits
/* the number of bits the algorithm is based on (e.g. 128).
/* .PP
/* The last two values may differ from each other when export-strength
/* encryption is used.
/*
/* The status of the peer certificate verification is available in
/* tls_info->peer_verified. It is set to 1 when the certificate could
/* TLScontext->peer_verified. It is set to 1 when the certificate could
/* be verified.
/* If the peer offered a certificate, part of the certificate data are
/* available as:
/* .IP tls_info->peer_subject
/* X509v3-oneline with the DN of the peer
/* .IP tls_info->peer_CN
/* extracted CommonName of the peer
/* .IP tls_info->peer_issuer
/* X509v3-oneline with the DN of the issuer
/* .IP tls_info->issuer_CN
/* extracted CommonName of the issuer
/* .IP tls_info->peer_fingerprint
/* fingerprint of the certificate
/* .IP TLScontext->peer_CN
/* Extracted CommonName of the peer, or zero-length string if the
/* information could not be extracted.
/* .IP TLScontext->issuer_CN
/* extracted CommonName of the issuer, or zero-length string if the
/* information could not be extracted.
/* .PP
/* Otherwise these fields are set to null pointers.
/* LICENSE
/* .ad
/* .fi
@ -130,11 +151,6 @@
#define STR vstring_str
#define LEN VSTRING_LEN
/*
* To convert binary to fingerprint.
*/
static const char hexcodes[] = "0123456789ABCDEF";
/*
* Do or don't we cache client sessions?
*/
@ -438,28 +454,28 @@ static int match_hostname(const char *pattern, const char *hostname)
/* verify_extract_peer - verify peer name and extract peer information */
static void verify_extract_peer(const char *peername, X509 * peercert,
TLScontext_t *TLScontext, tls_info_t *tls_info)
TLScontext_t *TLScontext)
{
char buf[1024];
int i;
int r;
int hostname_matched;
int dNSName_found;
int hostname_matched = 0;
int dNSName_found = 0;
int verify_peername;
STACK_OF(GENERAL_NAME) * gens;
tls_info->peer_verified =
TLScontext->peer_verified =
(SSL_get_verify_result(TLScontext->con) == X509_V_OK);
if (TLScontext->enforce_CN != 0 && tls_info->peer_verified != 0) {
verify_peername =
(TLScontext->enforce_CN != 0 && TLScontext->peer_verified != 0);
if (verify_peername) {
/*
* Verify the name(s) in the peer certificate against the peer
* hostname. Log peer hostname/certificate mis-matches. If a match is
* required but fails, bail out with a verification error.
* Verify the dNSName(s) in the peer certificate against the
* peername.
*/
hostname_matched = dNSName_found = 0;
gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
if (gens) {
for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i) {
@ -474,61 +490,37 @@ static void verify_extract_peer(const char *peername, X509 * peercert,
}
sk_GENERAL_NAME_free(gens);
}
if (dNSName_found) {
}
if (dNSName_found) {
if (!hostname_matched)
msg_info("certificate peer name verification failed for "
"%s: %d dNSNames in certificate found, "
"but none match", peername, dNSName_found);
}
if ((TLScontext->peer_CN = tls_peer_CN(peercert)) == 0)
TLScontext->peer_CN = mystrdup("");
if ((TLScontext->issuer_CN = tls_issuer_CN(peercert)) == 0)
TLScontext->issuer_CN = mystrdup("");
if (!dNSName_found && verify_peername) {
/*
* Verify the CommonName in the peer certificate against the
* peername.
*/
if (TLScontext->peer_CN[0] != '\0') {
hostname_matched = match_hostname(TLScontext->peer_CN, peername);
if (!hostname_matched)
msg_info("certificate peer name verification failed for "
"%s: %d dNSNames in certificate found, "
"but none matches", peername, dNSName_found);
} else {
buf[0] = '\0';
if (!X509_NAME_get_text_by_NID(X509_get_subject_name(peercert),
NID_commonName, buf,
sizeof(buf))) {
msg_info("certificate peer name verification failed for"
" %s: cannot parse subject CommonName", peername);
tls_print_errors();
} else {
hostname_matched = match_hostname(buf, peername);
if (!hostname_matched)
msg_info("certificate peer name verification failed "
"for %s: CommonName mis-match: %s",
peername, buf);
}
}
TLScontext->hostname_matched = hostname_matched;
}
tls_info->hostname_matched = TLScontext->hostname_matched;
TLScontext->peer_CN[0] = '\0';
if (!X509_NAME_get_text_by_NID(X509_get_subject_name(peercert),
NID_commonName, TLScontext->peer_CN,
sizeof(TLScontext->peer_CN))) {
msg_info("Could not parse server's subject CN");
tls_print_errors();
}
tls_info->peer_CN = TLScontext->peer_CN;
TLScontext->issuer_CN[0] = '\0';
if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peercert),
NID_commonName, TLScontext->issuer_CN,
sizeof(TLScontext->issuer_CN))) {
msg_info("Could not parse server's issuer CN");
tls_print_errors();
}
if (!TLScontext->issuer_CN[0]) {
/* No issuer CN field, use Organization instead */
if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peercert),
NID_organizationName, TLScontext->issuer_CN,
sizeof(TLScontext->issuer_CN))) {
msg_info("Could not parse server's issuer Organization");
tls_print_errors();
msg_info("certificate peer name verification failed "
"for %s: CommonName mis-match: %s",
peername, TLScontext->peer_CN);
}
}
tls_info->issuer_CN = TLScontext->issuer_CN;
TLScontext->hostname_matched = hostname_matched;
if (var_smtp_tls_loglevel >= 1) {
if (tls_info->peer_verified
if (TLScontext->peer_verified
&& (!TLScontext->enforce_CN || TLScontext->hostname_matched))
msg_info("Verified: subject_CN=%s, issuer=%s",
TLScontext->peer_CN, TLScontext->issuer_CN);
@ -547,8 +539,7 @@ TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream,
int timeout,
int enforce_peername,
const char *peername,
const char *serverid,
tls_info_t *tls_info)
const char *serverid)
{
int sts;
SSL_SESSION *session;
@ -707,30 +698,30 @@ TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream,
* from the certificate for later use.
*/
if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) {
verify_extract_peer(peername, peercert, TLScontext, tls_info);
verify_extract_peer(peername, peercert, TLScontext);
X509_free(peercert);
}
if (enforce_peername && !TLScontext->hostname_matched) {
msg_info("Server certificate could not be verified for %s:"
" hostname mismatch", peername);
tls_client_stop(client_ctx, stream, timeout, 0, tls_info);
tls_client_stop(client_ctx, stream, timeout, 0, TLScontext);
return (0);
}
/*
* Finally, collect information about protocol and cipher for logging
*/
tls_info->protocol = SSL_get_version(TLScontext->con);
TLScontext->protocol = SSL_get_version(TLScontext->con);
cipher = SSL_get_current_cipher(TLScontext->con);
tls_info->cipher_name = SSL_CIPHER_get_name(cipher);
tls_info->cipher_usebits = SSL_CIPHER_get_bits(cipher,
&(tls_info->cipher_algbits));
TLScontext->cipher_name = SSL_CIPHER_get_name(cipher);
TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher,
&(TLScontext->cipher_algbits));
if (var_smtp_tls_loglevel >= 1)
msg_info("TLS connection established to %s: %s with cipher %s"
" (%d/%d bits)", peername,
tls_info->protocol, tls_info->cipher_name,
tls_info->cipher_usebits, tls_info->cipher_algbits);
TLScontext->protocol, TLScontext->cipher_name,
TLScontext->cipher_usebits, TLScontext->cipher_algbits);
tls_int_seed();

View File

@ -110,6 +110,8 @@ TLScontext_t *tls_alloc_context(int log_level, const char *peername)
*
* See the C language FAQ item 5.17, or if you have time to burn,
* http://www.google.com/search?q=zero+bit+null+pointer
*
* However, it's OK to use memset() to zero integer values.
*/
TLScontext = (TLScontext_t *) mymalloc(sizeof(TLScontext_t));
memset((char *) TLScontext, 0, sizeof(*TLScontext));
@ -117,6 +119,11 @@ TLScontext_t *tls_alloc_context(int log_level, const char *peername)
TLScontext->internal_bio = 0;
TLScontext->network_bio = 0;
TLScontext->serverid = 0;
TLScontext->peer_CN = 0;
TLScontext->issuer_CN = 0;
TLScontext->peer_fingerprint = 0;
TLScontext->protocol = 0;
TLScontext->cipher_name = 0;
TLScontext->log_level = log_level;
TLScontext->peername = lowercase(mystrdup(peername));
@ -137,10 +144,19 @@ void tls_free_context(TLScontext_t *TLScontext)
SSL_free(TLScontext->con);
if (TLScontext->network_bio)
BIO_free(TLScontext->network_bio);
if (TLScontext->peername)
myfree(TLScontext->peername);
if (TLScontext->serverid)
myfree(TLScontext->serverid);
if (TLScontext->peer_CN)
myfree(TLScontext->peer_CN);
if (TLScontext->issuer_CN)
myfree(TLScontext->issuer_CN);
if (TLScontext->peer_fingerprint)
myfree(TLScontext->peer_fingerprint);
myfree((char *) TLScontext);
}

View File

@ -11,24 +11,22 @@
/* int askcert;
/*
/* TLScontext_t *tls_server_start(server_ctx, stream, timeout,
/* peername, peeraddr,
/* tls_info, requirecert)
/* peername, peeraddr, requirecert)
/* SSL_CTX *server_ctx;
/* VSTREAM *stream;
/* int timeout;
/* const char *peername;
/* const char *peeraddr;
/* tls_info_t *tls_info;
/* int requirecert;
/*
/* void tls_server_stop(server_ctx, stream, failure, tls_info)
/* void tls_server_stop(server_ctx, stream, failure, TLScontext)
/* SSL_CTX *server_ctx;
/* VSTREAM *stream;
/* int failure;
/* tls_info_t *tls_info;
/* TLScontext_t *TLScontext;
/* DESCRIPTION
/* This module is the interface between Postfix TLS servers
/* and the OpenSSL library and TLS entropy and cache manager.
/* This module is the interface between Postfix TLS servers,
/* the OpenSSL library, and the TLS entropy and cache manager.
/*
/* tls_server_init() is called once when the SMTP server
/* initializes.
@ -36,9 +34,8 @@
/* so that peer-specific behavior is not possible.
/*
/* tls_server_start() activates the TLS feature for the VSTREAM
/* passed as argument. We assume that network buffers are flushed and the
/* TLS handshake can begin immediately. Information about the peer
/* is stored into the tls_info structure passed as argument.
/* passed as argument. We assume that network buffers are flushed
/* and the TLS handshake can begin immediately.
/*
/* tls_server_stop() sends the "close notify" alert via
/* SSL_shutdown() to the peer and resets all connection specific
@ -49,34 +46,35 @@
/* If the failure flag is set, no SSL_shutdown() handshake is performed.
/*
/* Once the TLS connection is initiated, information about the TLS
/* state is available via the tls_info structure:
/* .IP tls_info->protocol
/* state is available via the TLScontext structure:
/* .IP TLScontext->protocol
/* the protocol name (SSLv2, SSLv3, TLSv1),
/* .IP tls_info->cipher_name
/* .IP TLScontext->cipher_name
/* the cipher name (e.g. RC4/MD5),
/* .IP tls_info->cipher_usebits
/* .IP TLScontext->cipher_usebits
/* the number of bits actually used (e.g. 40),
/* .IP tls_info->cipher_algbits
/* .IP TLScontext->cipher_algbits
/* the number of bits the algorithm is based on (e.g. 128).
/* .PP
/* The last two values may differ from each other when export-strength
/* encryption is used.
/*
/* The status of the peer certificate verification is available in
/* tls_info->peer_verified. It is set to 1 when the certificate could
/* TLScontext->peer_verified. It is set to 1 when the certificate could
/* be verified.
/* If the peer offered a certificate, part of the certificate data are
/* available as:
/* .IP tls_info->peer_subject
/* X509v3-oneline with the DN of the peer
/* .IP tls_info->peer_CN
/* extracted CommonName of the peer
/* .IP tls_info->peer_issuer
/* X509v3-oneline with the DN of the issuer
/* .IP tls_info->issuer_CN
/* extracted CommonName of the issuer
/* .IP tls_info->peer_fingerprint
/* fingerprint of the certificate
/* .IP TLScontext->peer_CN
/* Extracted CommonName of the peer, or zero-length string
/* when information could not be extracted.
/* .IP TLScontext->issuer_CN
/* Extracted CommonName of the issuer, or zero-length string
/* when information could not be extracted.
/* .IP TLScontext->peer_fingerprint
/* Fingerprint of the certificate, or null pointer when no
/* certificate digest is available.
/* .PP
/* Otherwise these fields are set to null pointers.
/* LICENSE
/* .ad
/* .fi
@ -450,9 +448,7 @@ SSL_CTX *tls_server_init(int unused_verifydepth, int askcert)
*/
TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream,
int timeout, const char *peername,
const char *peeraddr,
tls_info_t *tls_info,
int requirecert)
const char *peeraddr, int requirecert)
{
int sts;
int j;
@ -461,6 +457,8 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream,
TLScontext_t *TLScontext;
SSL_CIPHER *cipher;
X509 *peer;
unsigned char md[EVP_MAX_MD_SIZE];
char buf[CCERT_BUFSIZ];
if (var_smtpd_tls_loglevel >= 1)
msg_info("setting up TLS connection from %s[%s]", peername, peeraddr);
@ -573,66 +571,38 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream,
peer = SSL_get_peer_certificate(TLScontext->con);
if (peer != NULL) {
if (SSL_get_verify_result(TLScontext->con) == X509_V_OK)
tls_info->peer_verified = 1;
TLScontext->peer_verified = 1;
X509_NAME_oneline(X509_get_subject_name(peer),
TLScontext->peer_subject,
sizeof(TLScontext->peer_subject));
if (var_smtpd_tls_loglevel >= 2)
msg_info("subject=%s", TLScontext->peer_subject);
tls_info->peer_subject = TLScontext->peer_subject;
X509_NAME_oneline(X509_get_issuer_name(peer),
TLScontext->peer_issuer,
sizeof(TLScontext->peer_issuer));
if (var_smtpd_tls_loglevel >= 2)
msg_info("issuer=%s", TLScontext->peer_issuer);
tls_info->peer_issuer = TLScontext->peer_issuer;
if (X509_digest(peer, EVP_md5(), TLScontext->md, &n)) {
if (var_smtpd_tls_loglevel >= 2) {
X509_NAME_oneline(X509_get_subject_name(peer),
buf, sizeof(buf));
msg_info("subject=%s", buf);
X509_NAME_oneline(X509_get_issuer_name(peer),
buf, sizeof(buf));
msg_info("issuer=%s", buf);
}
if (X509_digest(peer, EVP_md5(), md, &n) && n > 0) {
TLScontext->peer_fingerprint = mymalloc(n * 3);
for (j = 0; j < (int) n; j++) {
TLScontext->fingerprint[j * 3] =
hexcodes[(TLScontext->md[j] & 0xf0) >> 4U];
TLScontext->fingerprint[(j * 3) + 1] =
hexcodes[(TLScontext->md[j] & 0x0f)];
TLScontext->peer_fingerprint[j * 3] =
hexcodes[(md[j] & 0xf0) >> 4U];
TLScontext->peer_fingerprint[(j * 3) + 1] =
hexcodes[(md[j] & 0x0f)];
if (j + 1 != (int) n)
TLScontext->fingerprint[(j * 3) + 2] = ':';
TLScontext->peer_fingerprint[(j * 3) + 2] = ':';
else
TLScontext->fingerprint[(j * 3) + 2] = '\0';
TLScontext->peer_fingerprint[(j * 3) + 2] = '\0';
}
if (var_smtpd_tls_loglevel >= 1)
msg_info("fingerprint=%s", TLScontext->fingerprint);
tls_info->peer_fingerprint = TLScontext->fingerprint;
msg_info("fingerprint=%s", TLScontext->peer_fingerprint);
}
TLScontext->peer_CN[0] = '\0';
if (!X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
NID_commonName, TLScontext->peer_CN,
sizeof(TLScontext->peer_CN))) {
msg_info("Could not parse client's subject CN");
tls_print_errors();
}
tls_info->peer_CN = TLScontext->peer_CN;
TLScontext->issuer_CN[0] = '\0';
if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer),
NID_commonName, TLScontext->issuer_CN,
sizeof(TLScontext->issuer_CN))) {
msg_info("Could not parse client's issuer CN");
tls_print_errors();
}
if (!TLScontext->issuer_CN[0]) {
/* No issuer CN field, use Organization instead */
if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer),
NID_organizationName, TLScontext->issuer_CN,
sizeof(TLScontext->issuer_CN))) {
msg_info("Could not parse client's issuer Organization");
tls_print_errors();
}
}
tls_info->issuer_CN = TLScontext->issuer_CN;
if ((TLScontext->peer_CN = tls_peer_CN(peer)) == 0)
TLScontext->peer_CN = mystrdup("");
if ((TLScontext->issuer_CN = tls_issuer_CN(peer)) == 0)
TLScontext->issuer_CN = mystrdup("");
if (var_smtpd_tls_loglevel >= 1) {
if (tls_info->peer_verified)
if (TLScontext->peer_verified)
msg_info("Verified: subject_CN=%s, issuer=%s",
TLScontext->peer_CN, TLScontext->issuer_CN);
else
@ -647,7 +617,7 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream,
* session peer was verified.
*/
if (requirecert) {
if (!tls_info->peer_verified || !tls_info->peer_CN) {
if (!TLScontext->peer_verified || !TLScontext->peer_CN) {
msg_info("Re-used session without peer certificate removed");
uncache_session(server_ctx, TLScontext);
tls_free_context(TLScontext);
@ -658,11 +628,11 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream,
/*
* Finally, collect information about protocol and cipher for logging
*/
tls_info->protocol = SSL_get_version(TLScontext->con);
TLScontext->protocol = SSL_get_version(TLScontext->con);
cipher = SSL_get_current_cipher(TLScontext->con);
tls_info->cipher_name = SSL_CIPHER_get_name(cipher);
tls_info->cipher_usebits = SSL_CIPHER_get_bits(cipher,
&(tls_info->cipher_algbits));
TLScontext->cipher_name = SSL_CIPHER_get_name(cipher);
TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher,
&(TLScontext->cipher_algbits));
/*
* The TLS engine is active. Switch to the tls_timed_read/write()
@ -673,8 +643,8 @@ TLScontext_t *tls_server_start(SSL_CTX *server_ctx, VSTREAM *stream,
if (var_smtpd_tls_loglevel >= 1)
msg_info("TLS connection established from %s[%s]: %s with cipher %s (%d/%d bits)",
peername, peeraddr,
tls_info->protocol, tls_info->cipher_name,
tls_info->cipher_usebits, tls_info->cipher_algbits);
TLScontext->protocol, TLScontext->cipher_name,
TLScontext->cipher_usebits, TLScontext->cipher_algbits);
tls_int_seed();
return (TLScontext);

View File

@ -6,12 +6,12 @@
/* SYNOPSIS
/* #include <tls.h>
/*
/* int tls_session_stop(ctx, stream, timeout, failure, tls_info)
/* void tls_session_stop(ctx, stream, timeout, failure, TLScontext)
/* SSL_CTX *ctx;
/* VSTREAM *stream;
/* int timeout;
/* int failure;
/* tls_info_t *tls_info;
/* TLScontext_t *TLScontext;
/*
/* VSTRING *tls_session_passivate(session)
/* SSL_SESSION *session;
@ -75,16 +75,14 @@
/* tls_session_stop - shut down the TLS connection and reset state */
void tls_session_stop(SSL_CTX *ctx, VSTREAM *stream, int timeout,
int failure, tls_info_t *tls_info)
int failure, TLScontext_t *TLScontext)
{
const char *myname = "tls_session_stop";
TLScontext_t *TLScontext;
int retval;
/*
* Sanity check.
*/
TLScontext = (TLScontext_t *) vstream_context(stream);
if (TLScontext == 0)
msg_panic("%s: stream has no active TLS context", myname);
@ -103,7 +101,6 @@ void tls_session_stop(SSL_CTX *ctx, VSTREAM *stream, int timeout,
}
tls_free_context(TLScontext);
tls_stream_stop(stream);
*tls_info = tls_info_zero;
}
/* tls_session_passivate - passivate SSL_SESSION object */

View File

@ -1,49 +0,0 @@
/*++
/* NAME
/* tls_temp 3
/* SUMMARY
/* code that is to be replaced
/* SYNOPSIS
/* #define TLS_INTERNAL
/* #include <tls.h>
/* DESCRIPTION
/* As the summary says.
/* LICENSE
/* .ad
/* .fi
/* This software is free. You can do with it whatever you want.
/* The original author kindly requests that you acknowledge
/* the use of his software.
/* AUTHOR(S)
/* Originally written by:
/* Lutz Jaenicke
/* BTU Cottbus
/* Allgemeine Elektrotechnik
/* Universitaetsplatz 3-4
/* D-03044 Cottbus, Germany
/*
/* Updated by:
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#ifdef USE_TLS
/* TLS library. */
#define TLS_INTERNAL
#include <tls.h>
/* Application-specific. */
const tls_info_t tls_info_zero = {
0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0
};
#endif

View File

@ -7,10 +7,26 @@
/* #define TLS_INTERNAL
/* #include <tls.h>
/*
/* char *tls_peer_CN(peercert)
/* X509 *peercert;
/*
/* char *tls_issuer_CN(peercert)
/* X509 *peercert;
/*
/* int tls_verify_certificate_callback(ok, ctx)
/* int ok;
/* X509_STORE_CTX *ctx;
/* DESCRIPTION
/* tls_peer_CN() returns the text CommonName for the peer
/* certificate subject, or a null pointer if no CommonName was
/* found. The result is allocated with mymalloc() and must be
/* freed by the caller.
/*
/* tls_issuer_CN() returns the text CommonName for the peer
/* certificate issuer, or a null pointer if no CommonName was
/* found. The result is allocated with mymalloc() and must be
/* freed by the caller.
/*
/* tls_verify_callback() is called several times (directly or
/* indirectly) from crypto/x509/x509_vfy.c. It is called as
/* a final check, and if it returns "0", the handshake is
@ -32,32 +48,6 @@
/* certificate verification failure will result in immediate
/* termination (return 0).
/*
/* The SMTP client will attempt to verify the server hostname
/* against the names listed in the server certificate. When
/* a hostname match is required, the verification fails
/* on certificate verification or hostname mis-match errors.
/* When no hostname match is required, hostname verification
/* failures are logged but they do not affect the TLS handshake
/* or the SMTP session.
/*
/* The rules for peer name wild-card matching differ between
/* RFC 2818 (HTTP over TLS) and RFC 2830 (LDAP over TLS), while
/* RFC RFC3207 (SMTP over TLS) does not specify a rule at all.
/* Postfix uses a restrictive match algorithm. One asterisk
/* ('*') is allowed as the left-most component of a wild-card
/* certificate name; it matches the left-most component of
/* the peer hostname.
/*
/* Another area where RFCs aren't always explicit is the
/* handling of dNSNames in peer certificates. RFC 3207 (SMTP
/* over TLS) does not mention dNSNames. Postfix follows the
/* strict rules in RFC 2818 (HTTP over TLS), section 3.1: The
/* Subject Alternative Name/dNSName has precedence over
/* CommonName. If at least one dNSName is provided, Postfix
/* verifies those against the peer hostname and ignores the
/* CommonName, otherwise Postfix verifies the CommonName
/* against the peer hostname.
/*
/* The only error condition not handled inside the OpenSSL
/* library is the case of a too-long certificate chain. We
/* test for this condition only if "ok = 1", that is, if
@ -72,6 +62,12 @@
/* .IP ctx
/* TLS client or server context. This also specifies the
/* TLScontext with enforcement options.
/* DIAGNOSTICS
/* tls_peer_CN() and tls_issuer_CN() log a warning and return
/* a null pointer when 1) the requested information is not
/* available in the specified certificate, 2) the result
/* exceeds a fixed limit, or 3) the result contains null
/* characters.
/* LICENSE
/* .ad
/* .fi
@ -107,6 +103,7 @@
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
/* TLS library. */
@ -196,4 +193,72 @@ int tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
return (1);
}
#ifndef DONT_GRIPE
#define DONT_GRIPE 0
#define DO_GRIPE 1
#endif
/* tls_text_name - extract certificate property value by name */
static char *tls_text_name(X509_NAME *name, int nid, char *label, int gripe)
{
int len;
char *text;
if ((len = X509_NAME_get_text_by_NID(name, nid, 0, 0)) < 0) {
if (gripe != DONT_GRIPE) {
msg_warn("peer certificate has no %s", label);
tls_print_errors();
}
return (0);
}
/*
* Since the peer CN is used in peer verification, take care to detect
* truncation due to excessive length or internal NULs.
*/
if (len >= CCERT_BUFSIZ) {
msg_warn("peer %s too long: %d", label, (int) len);
return (0);
}
text = mymalloc(len + 1);
X509_NAME_get_text_by_NID(name, nid, text, len + 1);
if (strlen(text) != len) {
msg_warn("internal NUL in peer %s", label);
myfree(text);
text = 0;
}
return (text);
}
/* tls_peer_CN - extract peer common name from certificate */
char *tls_peer_CN(X509 *peercert)
{
char *cn;
cn = tls_text_name(X509_get_subject_name(peercert),
NID_commonName, "CN", DO_GRIPE);
return (cn);
}
/* tls_text_name - extract issuer common name from certificate */
char *tls_issuer_CN(X509 *peer)
{
X509_NAME *name;
char *cn;
name = X509_get_issuer_name(peer);
/*
* If no issuer CN field, use Organization instead. CA certs without a CN
* are common, so we only complain if the organization is also missing.
*/
if (!(cn = tls_text_name(name, NID_commonName, "issuer CN", DONT_GRIPE)))
cn = tls_text_name(name, NID_organizationName,
"issuer Organization", DO_GRIPE);
return (cn);
}
#endif