tls_verify.c revision 1.3
1/*	$NetBSD: tls_verify.c,v 1.3 2020/03/18 19:05:21 christos Exp $	*/
2
3/*++
4/* NAME
5/*	tls_verify 3
6/* SUMMARY
7/*	peer name and peer certificate verification
8/* SYNOPSIS
9/*	#define TLS_INTERNAL
10/*	#include <tls.h>
11/*
12/*	int	tls_verify_certificate_callback(ok, ctx)
13/*	int	ok;
14/*	X509_STORE_CTX *ctx;
15/*
16/*	int     tls_log_verify_error(TLScontext)
17/*	TLS_SESS_STATE *TLScontext;
18/*
19/*	char *tls_peer_CN(peercert, TLScontext)
20/*	X509   *peercert;
21/*	TLS_SESS_STATE *TLScontext;
22/*
23/*	char *tls_issuer_CN(peercert, TLScontext)
24/*	X509   *peercert;
25/*	TLS_SESS_STATE *TLScontext;
26/*
27/*	const char *tls_dns_name(gn, TLScontext)
28/*	const GENERAL_NAME *gn;
29/*	TLS_SESS_STATE *TLScontext;
30/* DESCRIPTION
31/*	tls_verify_certificate_callback() is called several times (directly
32/*	or indirectly) from crypto/x509/x509_vfy.c. It collects errors
33/*	and trust information at each element of the trust chain.
34/*	The last call at depth 0 sets the verification status based
35/*	on the cumulative winner (lowest depth) of errors vs. trust.
36/*	We always return 1 (continue the handshake) and handle trust
37/*	and peer-name verification problems at the application level.
38/*
39/*	tls_log_verify_error() (called only when we care about the
40/*	peer certificate, that is not when opportunistic) logs the
41/*	reason why the certificate failed to be verified.
42/*
43/*	tls_peer_CN() returns the text CommonName for the peer
44/*	certificate subject, or an empty string if no CommonName was
45/*	found. The result is allocated with mymalloc() and must be
46/*	freed by the caller; it contains UTF-8 without non-printable
47/*	ASCII characters.
48/*
49/*	tls_issuer_CN() returns the text CommonName for the peer
50/*	certificate issuer, or an empty string if no CommonName was
51/*	found. The result is allocated with mymalloc() and must be
52/*	freed by the caller; it contains UTF-8 without non-printable
53/*	ASCII characters.
54/*
55/*	tls_dns_name() returns the string value of a GENERAL_NAME
56/*	from a DNS subjectAltName extension. If non-printable characters
57/*	are found, a null string is returned instead. Further sanity
58/*	checks may be added if the need arises.
59/*
60/*	Arguments:
61/* .IP ok
62/*	Result of prior verification: non-zero means success.  In
63/*	order to reduce the noise level, some tests or error reports
64/*	are disabled when verification failed because of some
65/*	earlier problem.
66/* .IP ctx
67/*	SSL application context. This links to the Postfix TLScontext
68/*	with enforcement and logging options.
69/* .IP gn
70/*	An OpenSSL GENERAL_NAME structure holding a DNS subjectAltName
71/*	to be decoded and checked for validity.
72/* .IP peercert
73/*	Server or client X.509 certificate.
74/* .IP TLScontext
75/*	Server or client context for warning messages.
76/* DIAGNOSTICS
77/*	tls_peer_CN(), tls_issuer_CN() and tls_dns_name() log a warning
78/*	when 1) the requested information is not available in the specified
79/*	certificate, 2) the result exceeds a fixed limit, 3) the result
80/*	contains NUL characters or the result contains non-printable or
81/*	non-ASCII characters.
82/* LICENSE
83/* .ad
84/* .fi
85/*	This software is free. You can do with it whatever you want.
86/*	The original author kindly requests that you acknowledge
87/*	the use of his software.
88/* AUTHOR(S)
89/*	Originally written by:
90/*	Lutz Jaenicke
91/*	BTU Cottbus
92/*	Allgemeine Elektrotechnik
93/*	Universitaetsplatz 3-4
94/*	D-03044 Cottbus, Germany
95/*
96/*	Updated by:
97/*	Wietse Venema
98/*	IBM T.J. Watson Research
99/*	P.O. Box 704
100/*	Yorktown Heights, NY 10598, USA
101/*
102/*	Victor Duchovni
103/*	Morgan Stanley
104/*--*/
105
106/* System library. */
107
108#include <sys_defs.h>
109#include <ctype.h>
110
111#ifdef USE_TLS
112#include <string.h>
113
114/* Utility library. */
115
116#include <msg.h>
117#include <mymalloc.h>
118#include <stringops.h>
119
120/* TLS library. */
121
122#define TLS_INTERNAL
123#include <tls.h>
124
125/* update_error_state - safely stash away error state */
126
127static void update_error_state(TLS_SESS_STATE *TLScontext, int depth,
128			               X509 *errorcert, int errorcode)
129{
130    /* No news is good news */
131    if (TLScontext->errordepth >= 0 && TLScontext->errordepth <= depth)
132	return;
133
134    /*
135     * The certificate pointer is stable during the verification callback,
136     * but may be freed after the callback returns.  Since we delay error
137     * reporting till later, we bump the refcount so we can rely on it still
138     * being there until later.
139     */
140    if (TLScontext->errorcert != 0)
141	X509_free(TLScontext->errorcert);
142    if (errorcert != 0)
143	X509_up_ref(errorcert);
144    TLScontext->errorcert = errorcert;
145    TLScontext->errorcode = errorcode;
146    TLScontext->errordepth = depth;
147}
148
149/* tls_verify_certificate_callback - verify peer certificate info */
150
151int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
152{
153    char    buf[CCERT_BUFSIZ];
154    X509   *cert;
155    int     err;
156    int     depth;
157    int     max_depth;
158    SSL    *con;
159    TLS_SESS_STATE *TLScontext;
160
161    /* May be NULL as of OpenSSL 1.0, thanks for the API change! */
162    cert = X509_STORE_CTX_get_current_cert(ctx);
163    err = X509_STORE_CTX_get_error(ctx);
164    con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
165    TLScontext = SSL_get_ex_data(con, TLScontext_index);
166    depth = X509_STORE_CTX_get_error_depth(ctx);
167
168    /* Don't log the internal root CA unless there's an unexpected error. */
169    if (ok && TLScontext->tadepth > 0 && depth > TLScontext->tadepth)
170	return (1);
171
172    /*
173     * Certificate chain depth limit violations are mis-reported by the
174     * OpenSSL library, from SSL_CTX_set_verify(3):
175     *
176     * The certificate verification depth set with SSL[_CTX]_verify_depth()
177     * stops the verification at a certain depth. The error message produced
178     * will be that of an incomplete certificate chain and not
179     * X509_V_ERR_CERT_CHAIN_TOO_LONG as may be expected.
180     *
181     * We set a limit that is one higher than the user requested limit. If this
182     * higher limit is reached, we raise an error even a trusted root CA is
183     * present at this depth. This disambiguates trust chain truncation from
184     * an incomplete trust chain.
185     */
186    max_depth = SSL_get_verify_depth(con) - 1;
187
188    /*
189     * We never terminate the SSL handshake in the verification callback,
190     * rather we allow the TLS handshake to continue, but mark the session as
191     * unverified. The application is responsible for closing any sessions
192     * with unverified credentials.
193     */
194    if (max_depth >= 0 && depth > max_depth) {
195	X509_STORE_CTX_set_error(ctx, err = X509_V_ERR_CERT_CHAIN_TOO_LONG);
196	ok = 0;
197    }
198    if (ok == 0)
199	update_error_state(TLScontext, depth, cert, err);
200
201    if (TLScontext->log_mask & TLS_LOG_VERBOSE) {
202	if (cert)
203	    X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
204	else
205	    strcpy(buf, "<unknown>");
206	msg_info("%s: depth=%d verify=%d subject=%s",
207		 TLScontext->namaddr, depth, ok, printable(buf, '?'));
208    }
209    return (1);
210}
211
212/* tls_log_verify_error - Report final verification error status */
213
214void    tls_log_verify_error(TLS_SESS_STATE *TLScontext)
215{
216    char    buf[CCERT_BUFSIZ];
217    int     err = TLScontext->errorcode;
218    X509   *cert = TLScontext->errorcert;
219    int     depth = TLScontext->errordepth;
220
221#define PURPOSE ((depth>0) ? "CA": TLScontext->am_server ? "client": "server")
222
223    if (err == X509_V_OK)
224	return;
225
226    /*
227     * Specific causes for verification failure.
228     */
229    switch (err) {
230    case X509_V_ERR_CERT_UNTRUSTED:
231
232	/*
233	 * We expect the error cert to be the leaf, but it is likely
234	 * sufficient to omit it from the log, even less user confusion.
235	 */
236	msg_info("certificate verification failed for %s: "
237		 "not trusted by local or TLSA policy", TLScontext->namaddr);
238	break;
239    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
240	msg_info("certificate verification failed for %s: "
241		 "self-signed certificate", TLScontext->namaddr);
242	break;
243    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
244    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
245
246	/*
247	 * There is no difference between issuing cert not provided and
248	 * provided, but not found in CAfile/CApath. Either way, we don't
249	 * trust it.
250	 */
251	if (cert)
252	    X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
253	else
254	    strcpy(buf, "<unknown>");
255	msg_info("certificate verification failed for %s: untrusted issuer %s",
256		 TLScontext->namaddr, printable(buf, '?'));
257	break;
258    case X509_V_ERR_CERT_NOT_YET_VALID:
259    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
260	msg_info("%s certificate verification failed for %s: certificate not"
261		 " yet valid", PURPOSE, TLScontext->namaddr);
262	break;
263    case X509_V_ERR_CERT_HAS_EXPIRED:
264    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
265	msg_info("%s certificate verification failed for %s: certificate has"
266		 " expired", PURPOSE, TLScontext->namaddr);
267	break;
268    case X509_V_ERR_INVALID_PURPOSE:
269	msg_info("certificate verification failed for %s: not designated for "
270		 "use as a %s certificate", TLScontext->namaddr, PURPOSE);
271	break;
272    case X509_V_ERR_CERT_CHAIN_TOO_LONG:
273	msg_info("certificate verification failed for %s: "
274		 "certificate chain longer than limit(%d)",
275		 TLScontext->namaddr, depth - 1);
276	break;
277    default:
278	msg_info("%s certificate verification failed for %s: num=%d:%s",
279		 PURPOSE, TLScontext->namaddr, err,
280		 X509_verify_cert_error_string(err));
281	break;
282    }
283}
284
285#ifndef DONT_GRIPE
286#define DONT_GRIPE 0
287#define DO_GRIPE 1
288#endif
289
290/* tls_text_name - extract certificate property value by name */
291
292static char *tls_text_name(X509_NAME *name, int nid, const char *label,
293			        const TLS_SESS_STATE *TLScontext, int gripe)
294{
295    const char *myname = "tls_text_name";
296    int     pos;
297    X509_NAME_ENTRY *entry;
298    ASN1_STRING *entry_str;
299    int     asn1_type;
300    int     utf8_length;
301    unsigned char *utf8_value;
302    int     ch;
303    unsigned char *cp;
304
305    if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
306	if (gripe != DONT_GRIPE) {
307	    msg_warn("%s: %s: peer certificate has no %s",
308		     myname, TLScontext->namaddr, label);
309	    tls_print_errors();
310	}
311	return (0);
312    }
313#if 0
314
315    /*
316     * If the match is required unambiguous, insist that that no other values
317     * be present.
318     */
319    if (X509_NAME_get_index_by_NID(name, nid, pos) >= 0) {
320	msg_warn("%s: %s: multiple %ss in peer certificate",
321		 myname, TLScontext->namaddr, label);
322	return (0);
323    }
324#endif
325
326    if ((entry = X509_NAME_get_entry(name, pos)) == 0) {
327	/* This should not happen */
328	msg_warn("%s: %s: error reading peer certificate %s entry",
329		 myname, TLScontext->namaddr, label);
330	tls_print_errors();
331	return (0);
332    }
333    if ((entry_str = X509_NAME_ENTRY_get_data(entry)) == 0) {
334	/* This should not happen */
335	msg_warn("%s: %s: error reading peer certificate %s data",
336		 myname, TLScontext->namaddr, label);
337	tls_print_errors();
338	return (0);
339    }
340
341    /*
342     * XXX Convert everything into UTF-8. This is a super-set of ASCII, so we
343     * don't have to bother with separate code paths for ASCII-like content.
344     * If the payload is ASCII then we won't waste lots of CPU cycles
345     * converting it into UTF-8. It's up to OpenSSL to do something
346     * reasonable when converting ASCII formats that contain non-ASCII
347     * content.
348     *
349     * XXX Don't bother optimizing the string length error check. It is not
350     * worth the complexity.
351     */
352    asn1_type = ASN1_STRING_type(entry_str);
353    if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) {
354	msg_warn("%s: %s: error decoding peer %s of ASN.1 type=%d",
355		 myname, TLScontext->namaddr, label, asn1_type);
356	tls_print_errors();
357	return (0);
358    }
359
360    /*
361     * No returns without cleaning up. A good optimizer will replace multiple
362     * blocks of identical code by jumps to just one such block.
363     */
364#define TLS_TEXT_NAME_RETURN(x) do { \
365	char *__tls_text_name_temp = (x); \
366	OPENSSL_free(utf8_value); \
367	return (__tls_text_name_temp); \
368    } while (0)
369
370    /*
371     * Remove trailing null characters. They would give false alarms with the
372     * length check and with the embedded null check.
373     */
374#define TRIM0(s, l) do { while ((l) > 0 && (s)[(l)-1] == 0) --(l); } while (0)
375
376    TRIM0(utf8_value, utf8_length);
377
378    /*
379     * Enforce the length limit, because the caller will copy the result into
380     * a fixed-length buffer.
381     */
382    if (utf8_length >= CCERT_BUFSIZ) {
383	msg_warn("%s: %s: peer %s too long: %d",
384		 myname, TLScontext->namaddr, label, utf8_length);
385	TLS_TEXT_NAME_RETURN(0);
386    }
387
388    /*
389     * Reject embedded nulls in ASCII or UTF-8 names. OpenSSL is responsible
390     * for producing properly-formatted UTF-8.
391     */
392    if (utf8_length != strlen((char *) utf8_value)) {
393	msg_warn("%s: %s: NULL character in peer %s",
394		 myname, TLScontext->namaddr, label);
395	TLS_TEXT_NAME_RETURN(0);
396    }
397
398    /*
399     * Reject non-printable ASCII characters in UTF-8 content.
400     *
401     * Note: the code below does not find control characters in illegal UTF-8
402     * sequences. It's OpenSSL's job to produce valid UTF-8, and reportedly,
403     * it does validation.
404     */
405    for (cp = utf8_value; (ch = *cp) != 0; cp++) {
406	if (ISASCII(ch) && !ISPRINT(ch)) {
407	    msg_warn("%s: %s: non-printable content in peer %s",
408		     myname, TLScontext->namaddr, label);
409	    TLS_TEXT_NAME_RETURN(0);
410	}
411    }
412    TLS_TEXT_NAME_RETURN(mystrdup((char *) utf8_value));
413}
414
415/* tls_dns_name - Extract valid DNS name from subjectAltName value */
416
417const char *tls_dns_name(const GENERAL_NAME * gn,
418			         const TLS_SESS_STATE *TLScontext)
419{
420    const char *myname = "tls_dns_name";
421    char   *cp;
422    const char *dnsname;
423    int     len;
424
425    /*
426     * Peername checks are security sensitive, carefully scrutinize the
427     * input!
428     */
429    if (gn->type != GEN_DNS)
430	msg_panic("%s: Non DNS input argument", myname);
431
432    /*
433     * We expect the OpenSSL library to construct GEN_DNS extension objects as
434     * ASN1_IA5STRING values. Check we got the right union member.
435     */
436    if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING) {
437	msg_warn("%s: %s: invalid ASN1 value type in subjectAltName",
438		 myname, TLScontext->namaddr);
439	return (0);
440    }
441
442    /*
443     * Safe to treat as an ASCII string possibly holding a DNS name
444     */
445    dnsname = (const char *) ASN1_STRING_get0_data(gn->d.ia5);
446    len = ASN1_STRING_length(gn->d.ia5);
447    TRIM0(dnsname, len);
448
449    /*
450     * Per Dr. Steven Henson of the OpenSSL development team, ASN1_IA5STRING
451     * values can have internal ASCII NUL values in this context because
452     * their length is taken from the decoded ASN1 buffer, a trailing NUL is
453     * always appended to make sure that the string is terminated, but the
454     * ASN.1 length may differ from strlen().
455     */
456    if (len != strlen(dnsname)) {
457	msg_warn("%s: %s: internal NUL in subjectAltName",
458		 myname, TLScontext->namaddr);
459	return 0;
460    }
461
462    /*
463     * XXX: Should we be more strict and call valid_hostname()? So long as
464     * the name is safe to handle, if it is not a valid hostname, it will not
465     * compare equal to the expected peername, so being more strict than
466     * "printable" is likely excessive...
467     */
468    if (*dnsname && !allprint(dnsname)) {
469	cp = mystrdup(dnsname);
470	msg_warn("%s: %s: non-printable characters in subjectAltName: %.100s",
471		 myname, TLScontext->namaddr, printable(cp, '?'));
472	myfree(cp);
473	return 0;
474    }
475    return (dnsname);
476}
477
478/* tls_peer_CN - extract peer common name from certificate */
479
480char   *tls_peer_CN(X509 *peercert, const TLS_SESS_STATE *TLScontext)
481{
482    char   *cn;
483
484    cn = tls_text_name(X509_get_subject_name(peercert), NID_commonName,
485		       "subject CN", TLScontext, DONT_GRIPE);
486    return (cn ? cn : mystrdup(""));
487}
488
489/* tls_issuer_CN - extract issuer common name from certificate */
490
491char   *tls_issuer_CN(X509 *peer, const TLS_SESS_STATE *TLScontext)
492{
493    X509_NAME *name;
494    char   *cn;
495
496    name = X509_get_issuer_name(peer);
497
498    /*
499     * If no issuer CN field, use Organization instead. CA certs without a CN
500     * are common, so we only complain if the organization is also missing.
501     */
502    if ((cn = tls_text_name(name, NID_commonName,
503			    "issuer CN", TLScontext, DONT_GRIPE)) == 0)
504	cn = tls_text_name(name, NID_organizationName,
505			   "issuer Organization", TLScontext, DONT_GRIPE);
506    return (cn ? cn : mystrdup(""));
507}
508
509#endif
510