xref: /netbsd-src/external/ibm-public/postfix/dist/src/tls/tls_verify.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: tls_verify.c,v 1.4 2022/10/08 16:12:50 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 /* DESCRIPTION
27 /*	tls_verify_certificate_callback() is called several times (directly
28 /*	or indirectly) from crypto/x509/x509_vfy.c. It collects errors
29 /*	and trust information at each element of the trust chain.
30 /*	The last call at depth 0 sets the verification status based
31 /*	on the cumulative winner (lowest depth) of errors vs. trust.
32 /*	We always return 1 (continue the handshake) and handle trust
33 /*	and peer-name verification problems at the application level.
34 /*
35 /*	tls_log_verify_error() (called only when we care about the
36 /*	peer certificate, that is not when opportunistic) logs the
37 /*	reason why the certificate failed to be verified.
38 /*
39 /*	tls_peer_CN() returns the text CommonName for the peer
40 /*	certificate subject, or an empty string if no CommonName was
41 /*	found. The result is allocated with mymalloc() and must be
42 /*	freed by the caller; it contains UTF-8 without non-printable
43 /*	ASCII characters.
44 /*
45 /*	tls_issuer_CN() returns the text CommonName for the peer
46 /*	certificate issuer, or an empty string if no CommonName was
47 /*	found. The result is allocated with mymalloc() and must be
48 /*	freed by the caller; it contains UTF-8 without non-printable
49 /*	ASCII characters.
50 /*
51 /*	Arguments:
52 /* .IP ok
53 /*	Result of prior verification: non-zero means success.  In
54 /*	order to reduce the noise level, some tests or error reports
55 /*	are disabled when verification failed because of some
56 /*	earlier problem.
57 /* .IP ctx
58 /*	SSL application context. This links to the Postfix TLScontext
59 /*	with enforcement and logging options.
60 /* .IP gn
61 /*	An OpenSSL GENERAL_NAME structure holding a DNS subjectAltName
62 /*	to be decoded and checked for validity.
63 /* .IP peercert
64 /*	Server or client X.509 certificate.
65 /* .IP TLScontext
66 /*	Server or client context for warning messages.
67 /* DIAGNOSTICS
68 /*	tls_peer_CN() and tls_issuer_CN() log a warning when 1) the requested
69 /*	information is not available in the specified certificate, 2) the
70 /*	result exceeds a fixed limit, 3) the result contains NUL characters or
71 /*	the result contains non-printable or non-ASCII characters.
72 /* LICENSE
73 /* .ad
74 /* .fi
75 /*	This software is free. You can do with it whatever you want.
76 /*	The original author kindly requests that you acknowledge
77 /*	the use of his software.
78 /* AUTHOR(S)
79 /*	Originally written by:
80 /*	Lutz Jaenicke
81 /*	BTU Cottbus
82 /*	Allgemeine Elektrotechnik
83 /*	Universitaetsplatz 3-4
84 /*	D-03044 Cottbus, Germany
85 /*
86 /*	Updated by:
87 /*	Wietse Venema
88 /*	IBM T.J. Watson Research
89 /*	P.O. Box 704
90 /*	Yorktown Heights, NY 10598, USA
91 /*
92 /*	Victor Duchovni
93 /*	Morgan Stanley
94 /*--*/
95 
96 /* System library. */
97 
98 #include <sys_defs.h>
99 #include <ctype.h>
100 
101 #ifdef USE_TLS
102 #include <string.h>
103 
104 /* Utility library. */
105 
106 #include <msg.h>
107 #include <mymalloc.h>
108 #include <stringops.h>
109 
110 /* TLS library. */
111 
112 #define TLS_INTERNAL
113 #include <tls.h>
114 
115 /* update_error_state - safely stash away error state */
116 
update_error_state(TLS_SESS_STATE * TLScontext,int depth,X509 * errorcert,int errorcode)117 static void update_error_state(TLS_SESS_STATE *TLScontext, int depth,
118 			               X509 *errorcert, int errorcode)
119 {
120     /* No news is good news */
121     if (TLScontext->errordepth >= 0 && TLScontext->errordepth <= depth)
122 	return;
123 
124     /*
125      * The certificate pointer is stable during the verification callback,
126      * but may be freed after the callback returns.  Since we delay error
127      * reporting till later, we bump the refcount so we can rely on it still
128      * being there until later.
129      */
130     if (TLScontext->errorcert != 0)
131 	X509_free(TLScontext->errorcert);
132     if (errorcert != 0)
133 	X509_up_ref(errorcert);
134     TLScontext->errorcert = errorcert;
135     TLScontext->errorcode = errorcode;
136     TLScontext->errordepth = depth;
137 }
138 
139 /* tls_verify_certificate_callback - verify peer certificate info */
140 
tls_verify_certificate_callback(int ok,X509_STORE_CTX * ctx)141 int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
142 {
143     char    buf[CCERT_BUFSIZ];
144     X509   *cert;
145     int     err;
146     int     depth;
147     SSL    *con;
148     TLS_SESS_STATE *TLScontext;
149 
150     /* May be NULL as of OpenSSL 1.0, thanks for the API change! */
151     cert = X509_STORE_CTX_get_current_cert(ctx);
152     err = X509_STORE_CTX_get_error(ctx);
153     con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
154     TLScontext = SSL_get_ex_data(con, TLScontext_index);
155     depth = X509_STORE_CTX_get_error_depth(ctx);
156 
157     /*
158      * Transient failures to load the (DNS or synthetic TLSA) trust settings
159      * must poison certificate verification, since otherwise the default
160      * trust store may bless a certificate that would have failed
161      * verification with the preferred trust anchors (or fingerprints).
162      *
163      * Since we unconditionally continue, or in any case if verification is
164      * about to succeed, there is eventually a final depth 0 callback, at
165      * which point we force an "unspecified" error.  The failure to load the
166      * trust settings was logged earlier.
167      */
168     if (TLScontext->must_fail) {
169 	if (depth == 0) {
170 	    X509_STORE_CTX_set_error(ctx, err = X509_V_ERR_UNSPECIFIED);
171 	    update_error_state(TLScontext, depth, cert, err);
172 	}
173 	return (1);
174     }
175     if (ok == 0)
176 	update_error_state(TLScontext, depth, cert, err);
177 
178     if (TLScontext->log_mask & TLS_LOG_VERBOSE) {
179 	if (cert)
180 	    X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
181 	else
182 	    strcpy(buf, "<unknown>");
183 	msg_info("%s: depth=%d verify=%d subject=%s",
184 		 TLScontext->namaddr, depth, ok, printable(buf, '?'));
185     }
186     return (1);
187 }
188 
189 /* tls_log_verify_error - Report final verification error status */
190 
tls_log_verify_error(TLS_SESS_STATE * TLScontext)191 void    tls_log_verify_error(TLS_SESS_STATE *TLScontext)
192 {
193     char    buf[CCERT_BUFSIZ];
194     int     err = TLScontext->errorcode;
195     X509   *cert = TLScontext->errorcert;
196     int     depth = TLScontext->errordepth;
197 
198 #define PURPOSE ((depth>0) ? "CA": TLScontext->am_server ? "client": "server")
199 
200     if (err == X509_V_OK)
201 	return;
202 
203     /*
204      * Specific causes for verification failure.
205      */
206     switch (err) {
207     case X509_V_ERR_CERT_UNTRUSTED:
208 
209 	/*
210 	 * We expect the error cert to be the leaf, but it is likely
211 	 * sufficient to omit it from the log, even less user confusion.
212 	 */
213 	msg_info("certificate verification failed for %s: "
214 		 "not trusted by local or TLSA policy", TLScontext->namaddr);
215 	break;
216     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
217 	msg_info("certificate verification failed for %s: "
218 		 "self-signed certificate", TLScontext->namaddr);
219 	break;
220     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
221     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
222 
223 	/*
224 	 * There is no difference between issuing cert not provided and
225 	 * provided, but not found in CAfile/CApath. Either way, we don't
226 	 * trust it.
227 	 */
228 	if (cert)
229 	    X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
230 	else
231 	    strcpy(buf, "<unknown>");
232 	msg_info("certificate verification failed for %s: untrusted issuer %s",
233 		 TLScontext->namaddr, printable(buf, '?'));
234 	break;
235     case X509_V_ERR_CERT_NOT_YET_VALID:
236     case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
237 	msg_info("%s certificate verification failed for %s: certificate not"
238 		 " yet valid", PURPOSE, TLScontext->namaddr);
239 	break;
240     case X509_V_ERR_CERT_HAS_EXPIRED:
241     case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
242 	msg_info("%s certificate verification failed for %s: certificate has"
243 		 " expired", PURPOSE, TLScontext->namaddr);
244 	break;
245     case X509_V_ERR_INVALID_PURPOSE:
246 	msg_info("certificate verification failed for %s: not designated for "
247 		 "use as a %s certificate", TLScontext->namaddr, PURPOSE);
248 	break;
249     case X509_V_ERR_CERT_CHAIN_TOO_LONG:
250 	msg_info("certificate verification failed for %s: "
251 		 "certificate chain longer than limit(%d)",
252 		 TLScontext->namaddr, depth - 1);
253 	break;
254     default:
255 	msg_info("%s certificate verification failed for %s: num=%d:%s",
256 		 PURPOSE, TLScontext->namaddr, err,
257 		 X509_verify_cert_error_string(err));
258 	break;
259     }
260 }
261 
262 #ifndef DONT_GRIPE
263 #define DONT_GRIPE 0
264 #define DO_GRIPE 1
265 #endif
266 
267 /* tls_text_name - extract certificate property value by name */
268 
tls_text_name(X509_NAME * name,int nid,const char * label,const TLS_SESS_STATE * TLScontext,int gripe)269 static char *tls_text_name(X509_NAME *name, int nid, const char *label,
270 			        const TLS_SESS_STATE *TLScontext, int gripe)
271 {
272     const char *myname = "tls_text_name";
273     int     pos;
274     X509_NAME_ENTRY *entry;
275     ASN1_STRING *entry_str;
276     int     asn1_type;
277     int     utf8_length;
278     unsigned char *utf8_value;
279     int     ch;
280     unsigned char *cp;
281 
282     if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
283 	if (gripe != DONT_GRIPE) {
284 	    msg_warn("%s: %s: peer certificate has no %s",
285 		     myname, TLScontext->namaddr, label);
286 	    tls_print_errors();
287 	}
288 	return (0);
289     }
290 #if 0
291 
292     /*
293      * If the match is required unambiguous, insist that that no other values
294      * be present.
295      */
296     if (X509_NAME_get_index_by_NID(name, nid, pos) >= 0) {
297 	msg_warn("%s: %s: multiple %ss in peer certificate",
298 		 myname, TLScontext->namaddr, label);
299 	return (0);
300     }
301 #endif
302 
303     if ((entry = X509_NAME_get_entry(name, pos)) == 0) {
304 	/* This should not happen */
305 	msg_warn("%s: %s: error reading peer certificate %s entry",
306 		 myname, TLScontext->namaddr, label);
307 	tls_print_errors();
308 	return (0);
309     }
310     if ((entry_str = X509_NAME_ENTRY_get_data(entry)) == 0) {
311 	/* This should not happen */
312 	msg_warn("%s: %s: error reading peer certificate %s data",
313 		 myname, TLScontext->namaddr, label);
314 	tls_print_errors();
315 	return (0);
316     }
317 
318     /*
319      * XXX Convert everything into UTF-8. This is a super-set of ASCII, so we
320      * don't have to bother with separate code paths for ASCII-like content.
321      * If the payload is ASCII then we won't waste lots of CPU cycles
322      * converting it into UTF-8. It's up to OpenSSL to do something
323      * reasonable when converting ASCII formats that contain non-ASCII
324      * content.
325      *
326      * XXX Don't bother optimizing the string length error check. It is not
327      * worth the complexity.
328      */
329     asn1_type = ASN1_STRING_type(entry_str);
330     if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) {
331 	msg_warn("%s: %s: error decoding peer %s of ASN.1 type=%d",
332 		 myname, TLScontext->namaddr, label, asn1_type);
333 	tls_print_errors();
334 	return (0);
335     }
336 
337     /*
338      * No returns without cleaning up. A good optimizer will replace multiple
339      * blocks of identical code by jumps to just one such block.
340      */
341 #define TLS_TEXT_NAME_RETURN(x) do { \
342 	char *__tls_text_name_temp = (x); \
343 	OPENSSL_free(utf8_value); \
344 	return (__tls_text_name_temp); \
345     } while (0)
346 
347     /*
348      * Remove trailing null characters. They would give false alarms with the
349      * length check and with the embedded null check.
350      */
351 #define TRIM0(s, l) do { while ((l) > 0 && (s)[(l)-1] == 0) --(l); } while (0)
352 
353     TRIM0(utf8_value, utf8_length);
354 
355     /*
356      * Enforce the length limit, because the caller will copy the result into
357      * a fixed-length buffer.
358      */
359     if (utf8_length >= CCERT_BUFSIZ) {
360 	msg_warn("%s: %s: peer %s too long: %d",
361 		 myname, TLScontext->namaddr, label, utf8_length);
362 	TLS_TEXT_NAME_RETURN(0);
363     }
364 
365     /*
366      * Reject embedded nulls in ASCII or UTF-8 names. OpenSSL is responsible
367      * for producing properly-formatted UTF-8.
368      */
369     if (utf8_length != strlen((char *) utf8_value)) {
370 	msg_warn("%s: %s: NULL character in peer %s",
371 		 myname, TLScontext->namaddr, label);
372 	TLS_TEXT_NAME_RETURN(0);
373     }
374 
375     /*
376      * Reject non-printable ASCII characters in UTF-8 content.
377      *
378      * Note: the code below does not find control characters in illegal UTF-8
379      * sequences. It's OpenSSL's job to produce valid UTF-8, and reportedly,
380      * it does validation.
381      */
382     for (cp = utf8_value; (ch = *cp) != 0; cp++) {
383 	if (ISASCII(ch) && !ISPRINT(ch)) {
384 	    msg_warn("%s: %s: non-printable content in peer %s",
385 		     myname, TLScontext->namaddr, label);
386 	    TLS_TEXT_NAME_RETURN(0);
387 	}
388     }
389     TLS_TEXT_NAME_RETURN(mystrdup((char *) utf8_value));
390 }
391 
392 /* tls_peer_CN - extract peer common name from certificate */
393 
tls_peer_CN(X509 * peercert,const TLS_SESS_STATE * TLScontext)394 char   *tls_peer_CN(X509 *peercert, const TLS_SESS_STATE *TLScontext)
395 {
396     char   *cn;
397     const char *san;
398 
399     /* Absent a commonName, return a validated DNS-ID SAN */
400     cn = tls_text_name(X509_get_subject_name(peercert), NID_commonName,
401 		       "subject CN", TLScontext, DONT_GRIPE);
402     if (cn == 0 && (san = SSL_get0_peername(TLScontext->con)) != 0)
403 	cn = mystrdup(san);
404     return (cn ? cn : mystrdup(""));
405 }
406 
407 /* tls_issuer_CN - extract issuer common name from certificate */
408 
tls_issuer_CN(X509 * peer,const TLS_SESS_STATE * TLScontext)409 char   *tls_issuer_CN(X509 *peer, const TLS_SESS_STATE *TLScontext)
410 {
411     X509_NAME *name;
412     char   *cn;
413 
414     name = X509_get_issuer_name(peer);
415 
416     /*
417      * If no issuer CN field, use Organization instead. CA certs without a CN
418      * are common, so we only complain if the organization is also missing.
419      */
420     if ((cn = tls_text_name(name, NID_commonName,
421 			    "issuer CN", TLScontext, DONT_GRIPE)) == 0)
422 	cn = tls_text_name(name, NID_organizationName,
423 			   "issuer Organization", TLScontext, DONT_GRIPE);
424     return (cn ? cn : mystrdup(""));
425 }
426 
427 #endif
428