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