2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 05:38:06 +00:00

postfix-2.6-20080510

This commit is contained in:
Wietse Venema 2008-05-10 00:00:00 -05:00 committed by Viktor Dukhovni
parent aa25e2edae
commit d3c01305cb
17 changed files with 377 additions and 291 deletions

View File

@ -14439,7 +14439,26 @@ Apologies for any names omitted.
(Postfix 2.1) and smtp/lmtp_generic_maps (Postfix 2.3). (Postfix 2.1) and smtp/lmtp_generic_maps (Postfix 2.3).
File: global/mail_params.h. File: global/mail_params.h.
Cleanup: the SMTP server's XFORWARD and XCLIENT support Cleanup: the SMTP server's XFORWARD and XCLIENT support was
was not updated when the smtpd_client_port_logging configuration not updated when the smtpd_client_port_logging configuration
parameter was added. Code by Victor Duchovni. Files: parameter was added. Code by Victor Duchovni. Files:
smtpd/smtpd.c, smtpd/smtpd_peer.c. smtpd/smtpd.c, smtpd/smtpd_peer.c.
20080508
Cleanup: delivery status notifications now prepend a
Return-Path: message header to the returned message.
File: bounce/bounce_notify_util.c.
20080509
Bugfix: null-terminate CN comment string after sanitization.
File: smtpd/smtpd.c.
20080510
Cleanup: when extracting common name and issuer name from
TLS certificates, convert the result into UTF-8, and use
RFC 2047 encoding when logging these as Received: header
comment fields. Based remotely on code by Victor Duchovni.
Files: smtpd/smtpd.c, tls/tls_verify.c.

View File

@ -126,7 +126,10 @@ Notes:
how the client was authenticated via TLS. These attributes are empty in how the client was authenticated via TLS. These attributes are empty in
case of no certificate authentication. As of Postfix 2.2.11 these attribute case of no certificate authentication. As of Postfix 2.2.11 these attribute
values are encoded as xtext: some characters are represented by +XX, where values are encoded as xtext: some characters are represented by +XX, where
XX is the two-digit hexadecimal representation of the character value. XX is the two-digit hexadecimal representation of the character value. With
Postfix 2.5 and later, the decoded string may contain non-ASCII characters.
If so, this is a UTF-8 string; xtext encoding works with the bytes of the
UTF-8 string, not the characters.
* The "encryption_*" attributes (Postfix 2.3 and later) specify information * The "encryption_*" attributes (Postfix 2.3 and later) specify information
about how the connection is encrypted. With plaintext connections the about how the connection is encrypted. With plaintext connections the

View File

@ -17,6 +17,13 @@ Incompatibility with Postfix 2.4 and earlier
If you upgrade from Postfix 2.4 or earlier, read RELEASE_NOTES-2.5 If you upgrade from Postfix 2.4 or earlier, read RELEASE_NOTES-2.5
before proceeding. before proceeding.
Incompatibility with snapshot 20080510
======================================
In the policy delegation protocol, certificate common name attributes
are now xtext encoded UTF-8. The xtext decoded attributes may contain
any UTF-8 value including control characters.
Incompatibility with snapshot 20080428 Incompatibility with snapshot 20080428
====================================== ======================================

View File

@ -192,14 +192,14 @@
# #
# REJECT optional text... # REJECT optional text...
# Reject the address etc. that matches the pattern. # Reject the address etc. that matches the pattern.
# Reply with $reject_code optional text... when the # Reply with "$access_map_reject_code optional
# optional text is specified, otherwise reply with a # text..." when the optional text is specified, oth-
# generic error response message. # erwise reply with a generic error response message.
# #
# DEFER_IF_REJECT optional text... # DEFER_IF_REJECT optional text...
# Defer the request if some later restriction would # Defer the request if some later restriction would
# result in a REJECT action. Reply with "450 4.7.1 # result in a REJECT action. Reply with "450 4.7.1
# optional text... when the optional text is speci- # optional text..." when the optional text is speci-
# fied, otherwise reply with a generic error response # fied, otherwise reply with a generic error response
# message. # message.
# #
@ -208,7 +208,7 @@
# DEFER_IF_PERMIT optional text... # DEFER_IF_PERMIT optional text...
# Defer the request if some later restriction would # Defer the request if some later restriction would
# result in a an explicit or implicit PERMIT action. # result in a an explicit or implicit PERMIT action.
# Reply with "450 4.7.1 optional text... when the # Reply with "450 4.7.1 optional text..." when the
# optional text is specified, otherwise reply with a # optional text is specified, otherwise reply with a
# generic error response message. # generic error response message.
# #

View File

@ -173,7 +173,10 @@ stress=
These attributes are empty in case of no certificate authentication. These attributes are empty in case of no certificate authentication.
As of Postfix 2.2.11 these attribute values are encoded as As of Postfix 2.2.11 these attribute values are encoded as
xtext: some characters are represented by +XX, where XX is the xtext: some characters are represented by +XX, where XX is the
two-digit hexadecimal representation of the character value. two-digit hexadecimal representation of the character value. With
Postfix 2.5 and later, the decoded string may contain non-ASCII
characters. If so, this is a UTF-8 string; xtext encoding works
with the bytes of the UTF-8 string, not the characters.
</p> </p>
<li> <p> The "encryption_*" attributes (Postfix 2.3 and later) <li> <p> The "encryption_*" attributes (Postfix 2.3 and later)

View File

@ -198,14 +198,14 @@ ACCESS(5) ACCESS(5)
<b>REJECT</b> <i>optional text...</i> <b>REJECT</b> <i>optional text...</i>
Reject the address etc. that matches the pattern. Reject the address etc. that matches the pattern.
Reply with <i>$reject</i><b>_</b><i>code optional text...</i> when the Reply with "<b>$<a href="postconf.5.html#access_map_reject_code">access_map_reject_code</a></b> <i>optional</i>
optional text is specified, otherwise reply with a <i>text...</i>" when the optional text is specified, oth-
generic error response message. erwise reply with a generic error response message.
<b>DEFER_IF_REJECT</b> <i>optional text...</i> <b>DEFER_IF_REJECT</b> <i>optional text...</i>
Defer the request if some later restriction would Defer the request if some later restriction would
result in a REJECT action. Reply with "<b>450 4.7.1</b> result in a REJECT action. Reply with "<b>450 4.7.1</b>
<i>optional text...</i> when the optional text is speci- <i>optional text...</i>" when the optional text is speci-
fied, otherwise reply with a generic error response fied, otherwise reply with a generic error response
message. message.
@ -214,7 +214,7 @@ ACCESS(5) ACCESS(5)
<b>DEFER_IF_PERMIT</b> <i>optional text...</i> <b>DEFER_IF_PERMIT</b> <i>optional text...</i>
Defer the request if some later restriction would Defer the request if some later restriction would
result in a an explicit or implicit PERMIT action. result in a an explicit or implicit PERMIT action.
Reply with "<b>450 4.7.1</b> <i>optional text...</i> when the Reply with "<b>450 4.7.1</b> <i>optional text...</i>" when the
optional text is specified, otherwise reply with a optional text is specified, otherwise reply with a
generic error response message. generic error response message.

View File

@ -479,7 +479,7 @@ esac
: ${CC='gcc $(WARN)'} ${OPT='-O'} ${DEBUG='-g'} ${AWK=awk} \ : ${CC='gcc $(WARN)'} ${OPT='-O'} ${DEBUG='-g'} ${AWK=awk} \
${WARN='-Wall -Wno-comment -Wformat -Wimplicit -Wmissing-prototypes \ ${WARN='-Wall -Wno-comment -Wformat -Wimplicit -Wmissing-prototypes \
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
-Wunused'} -Wunused -Wno-missing-braces'}
export SYSTYPE AR ARFL RANLIB SYSLIBS CC OPT DEBUG AWK OPTS export SYSTYPE AR ARFL RANLIB SYSLIBS CC OPT DEBUG AWK OPTS

View File

@ -190,12 +190,13 @@ The reply code "421" causes Postfix to disconnect immediately
(Postfix version 2.3 and later). (Postfix version 2.3 and later).
.IP "\fBREJECT \fIoptional text...\fR .IP "\fBREJECT \fIoptional text...\fR
Reject the address etc. that matches the pattern. Reply with Reject the address etc. that matches the pattern. Reply with
\fI$reject_code optional text...\fR when the optional text is "\fB$access_map_reject_code \fIoptional text...\fR" when the
optional text is
specified, otherwise reply with a generic error response message. specified, otherwise reply with a generic error response message.
.IP "\fBDEFER_IF_REJECT \fIoptional text...\fR .IP "\fBDEFER_IF_REJECT \fIoptional text...\fR
Defer the request if some later restriction would result in a Defer the request if some later restriction would result in a
REJECT action. Reply with "\fB450 4.7.1 \fI optional REJECT action. Reply with "\fB450 4.7.1 \fI optional
text...\fR when the text...\fR" when the
optional text is specified, otherwise reply with a generic error optional text is specified, otherwise reply with a generic error
response message. response message.
.sp .sp
@ -203,7 +204,7 @@ This feature is available in Postfix 2.1 and later.
.IP "\fBDEFER_IF_PERMIT \fIoptional text...\fR .IP "\fBDEFER_IF_PERMIT \fIoptional text...\fR
Defer the request if some later restriction would result in a Defer the request if some later restriction would result in a
an explicit or implicit PERMIT action. an explicit or implicit PERMIT action.
Reply with "\fB450 4.7.1 \fI optional text...\fR when the Reply with "\fB450 4.7.1 \fI optional text...\fR" when the
optional text is specified, otherwise reply with a generic error optional text is specified, otherwise reply with a generic error
response message. response message.
.sp .sp

View File

@ -173,7 +173,10 @@ stress=
These attributes are empty in case of no certificate authentication. These attributes are empty in case of no certificate authentication.
As of Postfix 2.2.11 these attribute values are encoded as As of Postfix 2.2.11 these attribute values are encoded as
xtext: some characters are represented by +XX, where XX is the xtext: some characters are represented by +XX, where XX is the
two-digit hexadecimal representation of the character value. two-digit hexadecimal representation of the character value. With
Postfix 2.5 and later, the decoded string may contain non-ASCII
characters. If so, this is a UTF-8 string; xtext encoding works
with the bytes of the UTF-8 string, not the characters.
</p> </p>
<li> <p> The "encryption_*" attributes (Postfix 2.3 and later) <li> <p> The "encryption_*" attributes (Postfix 2.3 and later)

View File

@ -170,12 +170,13 @@
# (Postfix version 2.3 and later). # (Postfix version 2.3 and later).
# .IP "\fBREJECT \fIoptional text...\fR # .IP "\fBREJECT \fIoptional text...\fR
# Reject the address etc. that matches the pattern. Reply with # Reject the address etc. that matches the pattern. Reply with
# \fI$reject_code optional text...\fR when the optional text is # "\fB$access_map_reject_code \fIoptional text...\fR" when the
# optional text is
# specified, otherwise reply with a generic error response message. # specified, otherwise reply with a generic error response message.
# .IP "\fBDEFER_IF_REJECT \fIoptional text...\fR # .IP "\fBDEFER_IF_REJECT \fIoptional text...\fR
# Defer the request if some later restriction would result in a # Defer the request if some later restriction would result in a
# REJECT action. Reply with "\fB450 4.7.1 \fI optional # REJECT action. Reply with "\fB450 4.7.1 \fI optional
# text...\fR when the # text...\fR" when the
# optional text is specified, otherwise reply with a generic error # optional text is specified, otherwise reply with a generic error
# response message. # response message.
# .sp # .sp
@ -183,7 +184,7 @@
# .IP "\fBDEFER_IF_PERMIT \fIoptional text...\fR # .IP "\fBDEFER_IF_PERMIT \fIoptional text...\fR
# Defer the request if some later restriction would result in a # Defer the request if some later restriction would result in a
# an explicit or implicit PERMIT action. # an explicit or implicit PERMIT action.
# Reply with "\fB450 4.7.1 \fI optional text...\fR when the # Reply with "\fB450 4.7.1 \fI optional text...\fR" when the
# optional text is specified, otherwise reply with a generic error # optional text is specified, otherwise reply with a generic error
# response message. # response message.
# .sp # .sp

View File

@ -772,6 +772,16 @@ int bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
return (vstream_ferror(bounce)); return (vstream_ferror(bounce));
} }
/*
* XXX The cleanup server removes Return-Path: headers. This should be
* done only with mail that enters via a non-SMTP channel, but changing
* this now could break other software. Removing Return-Path: could break
* digital signatures, though this is unlikely. In any case,
* header_checks are more effective when the Return-Path: header is
* present, so we prepend one to the bounce message.
*/
post_mail_fprintf(bounce, "Return-Path: <%s>", STR(bounce_info->sender));
/* /*
* Copy the original message contents. We're doing raw record output here * Copy the original message contents. We're doing raw record output here
* so that we don't throw away binary transparency yet. * so that we don't throw away binary transparency yet.

View File

@ -47,6 +47,10 @@
/* /*
* Header names are given in the preferred capitalization. The lookups are * Header names are given in the preferred capitalization. The lookups are
* case-insensitive. * case-insensitive.
*
* XXX Removing Return-Path: headers should probably be done only with mail
* that enters via a non-SMTP channel. Changing this now could break other
* software. See also comments in bounce_notify_util.c.
*/ */
static const HEADER_OPTS header_opts[] = { static const HEADER_OPTS header_opts[] = {
"Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP, "Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP,

View File

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

View File

@ -2496,6 +2496,60 @@ static void rcpt_reset(SMTPD_STATE *state)
state->rcpt_overshoot = 0; state->rcpt_overshoot = 0;
} }
/* rfc2047_comment_encode - encode comment string */
static VSTRING *rfc2047_comment_encode(const char *str, const char *charset)
{
VSTRING *buf = vstring_alloc(30);
const unsigned char *cp;
int ch;
/*
* XXX Most of the RFC 2047 "especials" are not special in RFC*822
* comments, but we encode them anyway to avoid complaints.
*
* XXX In Received: header comments we enclose peer and issuer common names
* with "" quotes. This is the cause of several quirks.
*
* 1) We encode text that contains the " character, even though that
* character is not special for RFC*822.
*
* 2) Long comments look ugly when folded in-between quotes, so we ignore
* the recommended limit of 75 characters per encoded word.
*
* 3) We must encode the the enclosing quotes, to avoid producing invalid
* encoded words.
*/
#define ESPECIALS "()<>@,;:\"/[]?.=" /* Special in RFC 2047 */
#define CSPECIALS "\\\"()" /* Special in our comments */
/* Don't encode if not needed. */
for (cp = (unsigned char *) str; /* see below */ ; ++cp) {
if ((ch = *cp) == 0) {
vstring_sprintf(buf, "\"%s\"", str);
return (buf);
}
if (!ISPRINT(ch) || strchr(CSPECIALS, ch))
break;
}
/*
* Use quoted-printable (like) encoding with spaces mapped to underscore.
*/
vstring_sprintf(buf, "=?%s?Q?=%02X", charset, '"');
for (cp = (unsigned char *) str; (ch = *cp) != 0; ++cp) {
if (!ISPRINT(ch) || strchr(ESPECIALS CSPECIALS, ch)) {
vstring_sprintf_append(buf, "=%02X", ch);
} else if (ch == ' ') {
VSTRING_ADDCH(buf, '_');
} else {
VSTRING_ADDCH(buf, ch);
}
}
vstring_sprintf_append(buf, "=%02X?=", '"');
return (buf);
}
/* comment_sanitize - clean up comment string */ /* comment_sanitize - clean up comment string */
static void comment_sanitize(VSTRING *comment_string) static void comment_sanitize(VSTRING *comment_string)
@ -2526,6 +2580,7 @@ static void comment_sanitize(VSTRING *comment_string)
} }
while (pc-- > 0) while (pc-- > 0)
VSTRING_ADDCH(comment_string, ')'); VSTRING_ADDCH(comment_string, ')');
VSTRING_TERMINATE(comment_string);
} }
/* data_cmd - process DATA command */ /* data_cmd - process DATA command */
@ -2654,6 +2709,10 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
#define VSTRING_STRDUP(s) vstring_strcpy(vstring_alloc(strlen(s) + 1), (s)) #define VSTRING_STRDUP(s) vstring_strcpy(vstring_alloc(strlen(s) + 1), (s))
/*
* Certificate CN information is arbitrary content in the UTF-8
* character set.
*/
#ifdef USE_TLS #ifdef USE_TLS
if (var_smtpd_tls_received_header && state->tls_context) { if (var_smtpd_tls_received_header && state->tls_context) {
out_fprintf(out_stream, REC_TYPE_NORM, out_fprintf(out_stream, REC_TYPE_NORM,
@ -2663,13 +2722,14 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
state->tls_context->cipher_usebits, state->tls_context->cipher_usebits,
state->tls_context->cipher_algbits); state->tls_context->cipher_algbits);
if (TLS_CERT_IS_PRESENT(state->tls_context)) { if (TLS_CERT_IS_PRESENT(state->tls_context)) {
peer_CN = VSTRING_STRDUP(state->tls_context->peer_CN); peer_CN =
comment_sanitize(peer_CN); rfc2047_comment_encode(state->tls_context->peer_CN,
issuer_CN = VSTRING_STRDUP(state->tls_context->issuer_CN ? "utf-8");
state->tls_context->issuer_CN : ""); issuer_CN =
comment_sanitize(issuer_CN); rfc2047_comment_encode(state->tls_context->issuer_CN,
"utf-8");
out_fprintf(out_stream, REC_TYPE_NORM, out_fprintf(out_stream, REC_TYPE_NORM,
"\t(Client CN \"%s\", Issuer \"%s\" (%s))", "\t(Client CN %s, Issuer %s (%s))",
STR(peer_CN), STR(issuer_CN), STR(peer_CN), STR(issuer_CN),
TLS_CERT_IS_TRUSTED(state->tls_context) ? TLS_CERT_IS_TRUSTED(state->tls_context) ?
"verified OK" : "not verified"); "verified OK" : "not verified");

View File

@ -180,14 +180,6 @@ typedef struct SMTPD_STATE {
ssize_t milter_argc; ssize_t milter_argc;
} SMTPD_STATE; } SMTPD_STATE;
/*
* Construct name[addr] or name[addr]:port as appropriate
*/
#define SMTPD_BUILD_NAMADDRPORT(name, addr, port) \
concatenate((name), "[", (addr), "]", \
var_smtpd_client_port_log ? ":" : (char *) 0, \
(port), (char *) 0)
#define SMTPD_FLAG_HANGUP (1<<0) /* disconnect */ #define SMTPD_FLAG_HANGUP (1<<0) /* disconnect */
#define SMTPD_STATE_XFORWARD_INIT (1<<0) /* xforward preset done */ #define SMTPD_STATE_XFORWARD_INIT (1<<0) /* xforward preset done */
@ -287,6 +279,14 @@ extern void smtpd_peer_reset(SMTPD_STATE *state);
#define SMTPD_PEER_CODE_PERM 5 #define SMTPD_PEER_CODE_PERM 5
#define SMTPD_PEER_CODE_FORGED 6 #define SMTPD_PEER_CODE_FORGED 6
/*
* Construct name[addr] or name[addr]:port as appropriate
*/
#define SMTPD_BUILD_NAMADDRPORT(name, addr, port) \
concatenate((name), "[", (addr), "]", \
var_smtpd_client_port_log ? ":" : (char *) 0, \
(port), (char *) 0)
/* /*
* Choose between normal or forwarded attributes. * Choose between normal or forwarded attributes.
* *

View File

@ -1813,7 +1813,6 @@ static int reject_unverified_address(SMTPD_STATE *state, const char *addr,
SND_DSN : "4.1.1", SND_DSN : "4.1.1",
"<%s>: %s rejected: address verification problem", "<%s>: %s rejected: address verification problem",
reply_name, reply_class); reply_name, reply_class);
rqst_status = SMTPD_CHECK_DUNNO;
} else { } else {
switch (rcpt_status) { switch (rcpt_status) {
default: default:

View File

@ -30,12 +30,12 @@
/* tls_peer_CN() returns the text CommonName for the peer /* tls_peer_CN() returns the text CommonName for the peer
/* certificate subject, or an empty string if no CommonName was /* certificate subject, or an empty string if no CommonName was
/* found. The result is allocated with mymalloc() and must be /* found. The result is allocated with mymalloc() and must be
/* freed by the caller. /* freed by the caller; it is arbitrary UTF-8 content.
/* /*
/* tls_issuer_CN() returns the text CommonName for the peer /* tls_issuer_CN() returns the text CommonName for the peer
/* certificate issuer, or an empty string if no CommonName was /* certificate issuer, or an empty string if no CommonName was
/* found. The result is allocated with mymalloc() and must be /* found. The result is allocated with mymalloc() and must be
/* freed by the caller. /* freed by the caller; it is arbitrary UTF-8 content.
/* /*
/* tls_dns_name() returns the string value of a GENERAL_NAME /* tls_dns_name() returns the string value of a GENERAL_NAME
/* from a DNS subjectAltName extension. If non-printable characters /* from a DNS subjectAltName extension. If non-printable characters
@ -278,11 +278,9 @@ static char *tls_text_name(X509_NAME *name, int nid, const char *label,
int pos; int pos;
X509_NAME_ENTRY *entry; X509_NAME_ENTRY *entry;
ASN1_STRING *entry_str; ASN1_STRING *entry_str;
int typ; int asn1_type;
int len; int utf8_length;
unsigned char *val; unsigned char *utf8_value;
unsigned char *utf;
char *cp;
if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) { if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
if (gripe != DONT_GRIPE) { if (gripe != DONT_GRIPE) {
@ -321,96 +319,72 @@ static char *tls_text_name(X509_NAME *name, int nid, const char *label,
} }
/* /*
* Peername checks are security sensitive, carefully scrutinize the * XXX Convert everything into UTF-8. This is a super-set of ASCII, so we
* input! * don't have to bother with separate code paths for ASCII-like content.
* If the payload is ASCII then we won't waste lots of CPU cycles
* converting it into UTF-8. It's up to OpenSSL to do something
* reasonable when converting ASCII formats that contain non-ASCII
* content.
*
* XXX Don't bother optimizing the string length error check. It is not
* worth the complexity.
*/ */
typ = ASN1_STRING_type(entry_str); asn1_type = ASN1_STRING_type(entry_str);
len = ASN1_STRING_length(entry_str); if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) {
val = ASN1_STRING_data(entry_str);
/*
* http://www.apps.ietf.org/rfc/rfc3280.html#sec-4.1.2.4 Quick Summary:
*
* The DirectoryString type is defined as a choice of PrintableString,
* TeletexString, BMPString, UTF8String, and UniversalString. The
* UTF8String encoding is the preferred encoding, and all certificates
* issued after December 31, 2003 MUST use the UTF8String encoding of
* DirectoryString (except as noted below).
*
* XXX: 2007, the above has not happened yet (of course), and we continue to
* see new certificates with T61STRING (Teletex) attribute values.
*
* XXX: 2007, at this time there are only two ASN.1 fixed width multi-byte
* string encodings, BMPSTRING (16 bit Unicode) and UniversalString
* (32-bit Unicode). The only variable width ASN.1 string encoding is
* UTF8 with all the other encodings being 1 byte wide subsets or subsets
* of ASCII.
*
* Relying on this could simplify the code, because we would never convert
* unexpected single-byte encodings, but is involves too many cases to be
* sure that we have a complete set and the assumptions may become false.
* So, we pessimistically convert encodings not blessed by RFC 2459, and
* filter out all types that are not string types as a side-effect of
* UTF8 conversion (the ASN.1 library knows which types are string types
* and how wide they are...).
*
* XXX: Two possible states after switch, either "utf == val" and it MUST
* NOT be freed with OPENSSL_free(), or "utf != val" and it MUST be freed
* with OPENSSL_free().
*/
switch (typ) {
case V_ASN1_PRINTABLESTRING: /* X.500 portable ASCII
* printables */
case V_ASN1_IA5STRING: /* ISO 646 ~ ASCII */
case V_ASN1_T61STRING: /* Essentially ISO-Latin */
case V_ASN1_UTF8STRING: /* UTF8 */
utf = val;
break;
default:
/*
* May shrink in wash, but BMPSTRING only shrinks by 50%. Others may
* shrink by up to 75%. We Sanity check the length before bothering
* to copy any large strings to convert to UTF8, only to find out
* they don't fit. So long as no new MB types are introduced, and
* weird string encodings unsanctioned by RFC 3280, are used in the
* issuer or subject DN, this "conservative" estimate will be exact.
*/
len >>= (typ == V_ASN1_BMPSTRING) ? 1 : 2;
if (len >= CCERT_BUFSIZ) {
msg_warn("%s: %s: peer %s too long: %d",
myname, TLScontext->namaddr, label, len);
return (0);
}
if ((len = ASN1_STRING_to_UTF8(&utf, entry_str)) < 0) {
msg_warn("%s: %s: error decoding peer %s of ASN.1 type=%d", msg_warn("%s: %s: error decoding peer %s of ASN.1 type=%d",
myname, TLScontext->namaddr, label, typ); myname, TLScontext->namaddr, label, asn1_type);
tls_print_errors(); tls_print_errors();
return (0); return (0);
} }
}
#define RETURN(x) do { if (utf!=val) OPENSSL_free(utf); return (x); } while (0)
if (len >= CCERT_BUFSIZ) { /*
* No returns without cleaning up. A good optimizer will replace multiple
* blocks of identical code by jumps to just one such block.
*/
#define TLS_TEXT_NAME_RETURN(x) do { \
char *__tls_text_name_temp = (x); \
OPENSSL_free(utf8_value); \
return (__tls_text_name_temp); \
} while (0)
#if 0
for (cp = utf8_value; (ch = *cp) != 0; cp++) {
if (ISASCII(ch) && !ISPRINT(ch)) {
msg_warn("%s: %s: non-printable content in peer %s",
myname, TLScontext->namaddr, label);
TLS_TEXT_NAME_RETURN(0);
}
}
#endif
/*
* Remove trailing null characters. They would give false alarms with the
* length check and with the embedded null check.
*/
#define TRIM0(s, l) do { while ((l) > 0 && (s)[(l)-1] == 0) --(l); } while (0)
TRIM0(utf8_value, utf8_length);
/*
* Enforce the length limit, because the caller will copy the result into
* a fixed-length buffer.
*/
if (utf8_length >= CCERT_BUFSIZ) {
msg_warn("%s: %s: peer %s too long: %d", msg_warn("%s: %s: peer %s too long: %d",
myname, TLScontext->namaddr, label, len); myname, TLScontext->namaddr, label, utf8_length);
RETURN(0); TLS_TEXT_NAME_RETURN(0);
} }
if (len != strlen((char *) utf)) {
msg_warn("%s: %s: internal NUL in peer %s", /*
* Don't allow embedded nulls in ASCII or UTF-8 names. OpenSSL is
* responsible for producing properly-formatted UTF-8.
*/
if (utf8_length != strlen((char *) utf8_value)) {
msg_warn("%s: %s: NULL character in peer %s",
myname, TLScontext->namaddr, label); myname, TLScontext->namaddr, label);
RETURN(0); TLS_TEXT_NAME_RETURN(0);
} }
for (cp = (char *) utf; *cp; cp++) { TLS_TEXT_NAME_RETURN(mystrdup((char *) utf8_value));
if (!ISASCII(*cp) || !ISPRINT(*cp)) {
msg_warn("%s: %s: non-printable characters in peer %s",
myname, TLScontext->namaddr, label);
RETURN(0);
}
}
cp = mystrdup((char *) utf);
RETURN(cp);
} }
/* tls_dns_name - Extract valid DNS name from subjectAltName value */ /* tls_dns_name - Extract valid DNS name from subjectAltName value */
@ -421,6 +395,7 @@ const char *tls_dns_name(const GENERAL_NAME * gn,
const char *myname = "tls_dns_name"; const char *myname = "tls_dns_name";
char *cp; char *cp;
const char *dnsname; const char *dnsname;
int len;
/* /*
* Peername checks are security sensitive, carefully scrutinize the * Peername checks are security sensitive, carefully scrutinize the
@ -443,6 +418,8 @@ const char *tls_dns_name(const GENERAL_NAME * gn,
* Safe to treat as an ASCII string possibly holding a DNS name * Safe to treat as an ASCII string possibly holding a DNS name
*/ */
dnsname = (char *) ASN1_STRING_data(gn->d.ia5); dnsname = (char *) ASN1_STRING_data(gn->d.ia5);
len = ASN1_STRING_length(gn->d.ia5);
TRIM0(dnsname, len);
/* /*
* Per Dr. Steven Henson of the OpenSSL development team, ASN1_IA5STRING * Per Dr. Steven Henson of the OpenSSL development team, ASN1_IA5STRING
@ -451,7 +428,7 @@ const char *tls_dns_name(const GENERAL_NAME * gn,
* always appended to make sure that the string is terminated, but the * always appended to make sure that the string is terminated, but the
* ASN.1 length may differ from strlen(). * ASN.1 length may differ from strlen().
*/ */
if (ASN1_STRING_length(gn->d.ia5) != strlen(dnsname)) { if (len != strlen(dnsname)) {
msg_warn("%s: %s: internal NUL in subjectAltName", msg_warn("%s: %s: internal NUL in subjectAltName",
myname, TLScontext->namaddr); myname, TLScontext->namaddr);
return 0; return 0;
@ -463,10 +440,9 @@ const char *tls_dns_name(const GENERAL_NAME * gn,
* compare equal to the expected peername, so being more strict than * compare equal to the expected peername, so being more strict than
* "printable" is likely excessive... * "printable" is likely excessive...
*/ */
for (cp = (char *) dnsname; cp && *cp; cp++) if (*dnsname && !allprint(dnsname)) {
if (!ISASCII(*cp) || !ISPRINT(*cp)) {
cp = mystrdup(dnsname); cp = mystrdup(dnsname);
msg_warn("%s: %s: non-printable characters in subjectAltName: %s", msg_warn("%s: %s: non-printable characters in subjectAltName: %.100s",
myname, TLScontext->namaddr, printable(cp, '?')); myname, TLScontext->namaddr, printable(cp, '?'));
myfree(cp); myfree(cp);
return 0; return 0;