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