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