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