ssl_certificate.c (25826B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 1999-2016 Colin Leroy and the Claws Mail team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <gnutls/gnutls.h> 20 #include <gnutls/x509.h> 21 #include <gnutls/pkcs12.h> 22 #include <sys/stat.h> 23 #include <unistd.h> 24 #include <string.h> 25 #include <sys/types.h> 26 #include <stdio.h> 27 #include <glib.h> 28 #include <glib/gi18n.h> 29 #include <errno.h> 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 #include "ssl_certificate.h" 33 #include "utils.h" 34 #include "log.h" 35 #include "socket.h" 36 #include "hooks.h" 37 #include "defs.h" 38 #include "file-utils.h" 39 40 static GHashTable *warned_expired = NULL; 41 42 gboolean prefs_common_unsafe_ssl_certs(void); 43 44 static gchar *get_certificate_path(const gchar *host, const gchar *port, const gchar *fp) 45 { 46 gchar *ret; 47 gchar *filename; 48 49 if (fp != NULL && prefs_common_unsafe_ssl_certs()) { 50 filename = g_strconcat(host, ".", port, ".", fp, ".cert", NULL); 51 } else { 52 filename = g_strconcat(host, ".", port, ".cert", NULL); 53 } 54 subst_for_filename(filename); 55 56 ret = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, 57 "certs", G_DIR_SEPARATOR_S, 58 filename, NULL); 59 60 g_free(filename); 61 return ret; 62 } 63 64 static gchar *get_certificate_chain_path(const gchar *host, const gchar *port, const gchar *fp) 65 { 66 gchar *tmp = get_certificate_path(host, port, fp); 67 gchar *result = g_strconcat(tmp, ".chain", NULL); 68 69 g_free(tmp); 70 71 return result; 72 } 73 74 char * readable_fingerprint(unsigned char *src, int len) 75 { 76 int i=0; 77 char * ret; 78 79 if (src == NULL) 80 return NULL; 81 ret = g_strdup(""); 82 while (i < len) { 83 char *tmp2; 84 if(i>0) 85 tmp2 = g_strdup_printf("%s:%02X", ret, src[i]); 86 else 87 tmp2 = g_strdup_printf("%02X", src[i]); 88 g_free(ret); 89 ret = g_strdup(tmp2); 90 g_free(tmp2); 91 i++; 92 } 93 return ret; 94 } 95 96 static gnutls_x509_crt_t x509_crt_copy(gnutls_x509_crt_t src) 97 { 98 int ret; 99 size_t size; 100 gnutls_datum_t tmp; 101 gnutls_x509_crt_t dest; 102 size = 0; 103 104 if (gnutls_x509_crt_init(&dest) != 0) { 105 g_warning("couldn't gnutls_x509_crt_init"); 106 return NULL; 107 } 108 109 if (gnutls_x509_crt_export(src, GNUTLS_X509_FMT_DER, NULL, &size) 110 != GNUTLS_E_SHORT_MEMORY_BUFFER) { 111 g_warning("couldn't gnutls_x509_crt_export to get size"); 112 gnutls_x509_crt_deinit(dest); 113 return NULL; 114 } 115 116 tmp.data = malloc(size); 117 memset(tmp.data, 0, size); 118 ret = gnutls_x509_crt_export(src, GNUTLS_X509_FMT_DER, tmp.data, &size); 119 if (ret == 0) { 120 tmp.size = size; 121 ret = gnutls_x509_crt_import(dest, &tmp, GNUTLS_X509_FMT_DER); 122 if (ret) { 123 g_warning("couldn't gnutls_x509_crt_import for real (%d %s)", ret, gnutls_strerror(ret)); 124 gnutls_x509_crt_deinit(dest); 125 dest = NULL; 126 } 127 } else { 128 g_warning("couldn't gnutls_x509_crt_export for real (%d %s)", ret, gnutls_strerror(ret)); 129 gnutls_x509_crt_deinit(dest); 130 dest = NULL; 131 } 132 133 free(tmp.data); 134 return dest; 135 } 136 137 static SSLCertificate *ssl_certificate_new(gnutls_x509_crt_t x509_cert, const gchar *host, gushort port) 138 { 139 SSLCertificate *cert = g_new0(SSLCertificate, 1); 140 size_t n; 141 unsigned char md[128]; 142 143 if (host == NULL || x509_cert == NULL) { 144 ssl_certificate_destroy(cert); 145 return NULL; 146 } 147 cert->x509_cert = x509_crt_copy(x509_cert); 148 cert->status = (guint)-1; 149 cert->host = g_strdup(host); 150 cert->port = port; 151 152 /* fingerprint */ 153 n = sizeof(md); 154 gnutls_x509_crt_get_fingerprint(cert->x509_cert, GNUTLS_DIG_MD5, md, &n); 155 cert->fingerprint = readable_fingerprint(md, (int)n); 156 return cert; 157 } 158 159 static void gnutls_export_X509_fp(FILE *fp, gnutls_x509_crt_t x509_cert, gnutls_x509_crt_fmt_t format) 160 { 161 char output[10*1024]; 162 size_t cert_size = 10*1024; 163 int r; 164 165 if ((r = gnutls_x509_crt_export(x509_cert, format, output, &cert_size)) < 0) { 166 g_warning("couldn't export cert %s (%"G_GSIZE_FORMAT")", gnutls_strerror(r), cert_size); 167 return; 168 } 169 debug_print("writing %" G_GSIZE_FORMAT " bytes\n",cert_size); 170 if (fwrite(&output, 1, cert_size, fp) < cert_size) { 171 g_warning("failed to write cert: %d %s", errno, g_strerror(errno)); 172 } 173 } 174 175 size_t gnutls_i2d_X509(gnutls_x509_crt_t x509_cert, unsigned char **output) 176 { 177 size_t cert_size = 10*1024; 178 int r; 179 180 if (output == NULL) 181 return 0; 182 183 *output = malloc(cert_size); 184 185 if ((r = gnutls_x509_crt_export(x509_cert, GNUTLS_X509_FMT_DER, *output, &cert_size)) < 0) { 186 g_warning("couldn't export cert %s (%"G_GSIZE_FORMAT")", gnutls_strerror(r), cert_size); 187 free(*output); 188 *output = NULL; 189 return 0; 190 } 191 return cert_size; 192 } 193 194 size_t gnutls_i2d_PrivateKey(gnutls_x509_privkey_t pkey, unsigned char **output) 195 { 196 size_t key_size = 10*1024; 197 int r; 198 199 if (output == NULL) 200 return 0; 201 202 *output = malloc(key_size); 203 204 if ((r = gnutls_x509_privkey_export(pkey, GNUTLS_X509_FMT_DER, *output, &key_size)) < 0) { 205 g_warning("couldn't export key %s (%"G_GSIZE_FORMAT")", gnutls_strerror(r), key_size); 206 free(*output); 207 *output = NULL; 208 return 0; 209 } 210 return key_size; 211 } 212 213 static int gnutls_import_X509_list_fp(FILE *fp, gnutls_x509_crt_fmt_t format, 214 gnutls_x509_crt_t **cert_list, gint *num_certs) 215 { 216 gnutls_x509_crt_t *crt_list; 217 unsigned int max = 512; 218 unsigned int flags = 0; 219 gnutls_datum_t tmp; 220 struct stat s; 221 int r; 222 223 *cert_list = NULL; 224 *num_certs = 0; 225 226 if (fp == NULL) 227 return -ENOENT; 228 229 if (fstat(fileno(fp), &s) < 0) { 230 perror("fstat"); 231 return -errno; 232 } 233 234 crt_list=(gnutls_x509_crt_t*)malloc(max*sizeof(gnutls_x509_crt_t)); 235 tmp.data = malloc(s.st_size); 236 memset(tmp.data, 0, s.st_size); 237 tmp.size = s.st_size; 238 if (fread (tmp.data, 1, s.st_size, fp) < s.st_size) { 239 perror("fread"); 240 free(tmp.data); 241 free(crt_list); 242 return -EIO; 243 } 244 245 if ((r = gnutls_x509_crt_list_import(crt_list, &max, 246 &tmp, format, flags)) < 0) { 247 debug_print("cert import failed: %s\n", gnutls_strerror(r)); 248 free(tmp.data); 249 free(crt_list); 250 return r; 251 } 252 free(tmp.data); 253 debug_print("got %d certs in crt_list! %p\n", max, &crt_list); 254 255 *cert_list = crt_list; 256 *num_certs = max; 257 258 return r; 259 } 260 261 /* return one certificate, read from file */ 262 static gnutls_x509_crt_t gnutls_import_X509_fp(FILE *fp, gnutls_x509_crt_fmt_t format) 263 { 264 gnutls_x509_crt_t *certs = NULL; 265 gnutls_x509_crt_t cert = NULL; 266 int i, ncerts, r; 267 268 if ((r = gnutls_import_X509_list_fp(fp, format, &certs, &ncerts)) < 0) { 269 return NULL; 270 } 271 272 if (ncerts == 0) 273 return NULL; 274 275 for (i = 1; i < ncerts; i++) 276 gnutls_x509_crt_deinit(certs[i]); 277 278 cert = certs[0]; 279 free(certs); 280 281 return cert; 282 } 283 284 static gnutls_x509_privkey_t gnutls_import_key_fp(FILE *fp, gnutls_x509_crt_fmt_t format) 285 { 286 gnutls_x509_privkey_t key = NULL; 287 gnutls_datum_t tmp; 288 struct stat s; 289 int r; 290 if (fstat(fileno(fp), &s) < 0) { 291 perror("fstat"); 292 return NULL; 293 } 294 tmp.data = malloc(s.st_size); 295 memset(tmp.data, 0, s.st_size); 296 tmp.size = s.st_size; 297 if (fread (tmp.data, 1, s.st_size, fp) < s.st_size) { 298 perror("fread"); 299 free(tmp.data); 300 return NULL; 301 } 302 303 gnutls_x509_privkey_init(&key); 304 if ((r = gnutls_x509_privkey_import(key, &tmp, format)) < 0) { 305 debug_print("key import failed: %s\n", gnutls_strerror(r)); 306 gnutls_x509_privkey_deinit(key); 307 key = NULL; 308 } 309 free(tmp.data); 310 debug_print("got key! %p\n", key); 311 return key; 312 } 313 314 static gnutls_pkcs12_t gnutls_import_PKCS12_fp(FILE *fp, gnutls_x509_crt_fmt_t format) 315 { 316 gnutls_pkcs12_t p12 = NULL; 317 gnutls_datum_t tmp; 318 struct stat s; 319 int r; 320 if (fstat(fileno(fp), &s) < 0) { 321 log_error(LOG_PROTOCOL, _("Cannot stat P12 certificate file (%s)\n"), 322 g_strerror(errno)); 323 return NULL; 324 } 325 tmp.data = malloc(s.st_size); 326 memset(tmp.data, 0, s.st_size); 327 tmp.size = s.st_size; 328 if (fread (tmp.data, 1, s.st_size, fp) < s.st_size) { 329 log_error(LOG_PROTOCOL, _("Cannot read P12 certificate file (%s)\n"), 330 g_strerror(errno)); 331 free(tmp.data); 332 return NULL; 333 } 334 335 gnutls_pkcs12_init(&p12); 336 337 if ((r = gnutls_pkcs12_import(p12, &tmp, format, 0)) < 0) { 338 log_error(LOG_PROTOCOL, _("Cannot import P12 certificate file (%s)\n"), 339 gnutls_strerror(r)); 340 gnutls_pkcs12_deinit(p12); 341 p12 = NULL; 342 } 343 free(tmp.data); 344 debug_print("got p12! %p\n", p12); 345 return p12; 346 } 347 348 static void ssl_certificate_save (SSLCertificate *cert) 349 { 350 gchar *file, *port; 351 FILE *fp; 352 353 file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, 354 "certs", G_DIR_SEPARATOR_S, NULL); 355 356 if (!is_dir_exist(file)) 357 make_dir_hier(file); 358 g_free(file); 359 360 port = g_strdup_printf("%d", cert->port); 361 file = get_certificate_path(cert->host, port, cert->fingerprint); 362 363 g_free(port); 364 fp = g_fopen(file, "wb"); 365 if (fp == NULL) { 366 g_free(file); 367 debug_print("Can't save certificate !\n"); 368 return; 369 } 370 371 gnutls_export_X509_fp(fp, cert->x509_cert, GNUTLS_X509_FMT_DER); 372 373 g_free(file); 374 fclose(fp); 375 376 } 377 378 void ssl_certificate_destroy(SSLCertificate *cert) 379 { 380 if (cert == NULL) 381 return; 382 383 if (cert->x509_cert) 384 gnutls_x509_crt_deinit(cert->x509_cert); 385 g_free(cert->host); 386 g_free(cert->fingerprint); 387 g_free(cert); 388 cert = NULL; 389 } 390 391 void ssl_certificate_delete_from_disk(SSLCertificate *cert) 392 { 393 gchar *buf; 394 gchar *file; 395 buf = g_strdup_printf("%d", cert->port); 396 file = get_certificate_path(cert->host, buf, cert->fingerprint); 397 unlink (file); 398 g_free(file); 399 file = get_certificate_chain_path(cert->host, buf, cert->fingerprint); 400 unlink (file); 401 g_free(file); 402 g_free(buf); 403 } 404 405 SSLCertificate *ssl_certificate_find (const gchar *host, gushort port, const gchar *fingerprint) 406 { 407 gchar *file = NULL; 408 gchar *buf; 409 SSLCertificate *cert = NULL; 410 gnutls_x509_crt_t tmp_x509; 411 FILE *fp = NULL; 412 gboolean must_rename = FALSE; 413 414 buf = g_strdup_printf("%d", port); 415 416 if (fingerprint != NULL) { 417 file = get_certificate_path(host, buf, fingerprint); 418 fp = g_fopen(file, "rb"); 419 } 420 if (fp == NULL) { 421 /* see if we have the old one */ 422 debug_print("didn't get %s\n", file); 423 g_free(file); 424 file = get_certificate_path(host, buf, NULL); 425 fp = g_fopen(file, "rb"); 426 427 if (fp) { 428 debug_print("got %s\n", file); 429 must_rename = (fingerprint != NULL); 430 } 431 } else { 432 debug_print("got %s first try\n", file); 433 } 434 if (fp == NULL) { 435 g_free(file); 436 g_free(buf); 437 return NULL; 438 } 439 440 if ((tmp_x509 = gnutls_import_X509_fp(fp, GNUTLS_X509_FMT_DER)) != NULL) { 441 cert = ssl_certificate_new(tmp_x509, host, port); 442 debug_print("got cert %p\n", cert); 443 gnutls_x509_crt_deinit(tmp_x509); 444 } 445 446 fclose(fp); 447 g_free(file); 448 449 if (must_rename) { 450 gchar *old = get_certificate_path(host, buf, NULL); 451 gchar *new = get_certificate_path(host, buf, fingerprint); 452 if (strcmp(old, new)) 453 rename(old, new); 454 g_free(old); 455 g_free(new); 456 } 457 g_free(buf); 458 459 return cert; 460 } 461 462 static gboolean ssl_certificate_compare (SSLCertificate *cert_a, SSLCertificate *cert_b) 463 { 464 char *output_a; 465 char *output_b; 466 size_t cert_size_a = 0, cert_size_b = 0; 467 int r; 468 469 if (cert_a == NULL || cert_b == NULL) 470 return FALSE; 471 472 if ((r = gnutls_x509_crt_export(cert_a->x509_cert, GNUTLS_X509_FMT_DER, NULL, &cert_size_a)) 473 != GNUTLS_E_SHORT_MEMORY_BUFFER) { 474 g_warning("couldn't gnutls_x509_crt_export to get size a %s", gnutls_strerror(r)); 475 return FALSE; 476 } 477 478 if ((r = gnutls_x509_crt_export(cert_b->x509_cert, GNUTLS_X509_FMT_DER, NULL, &cert_size_b)) 479 != GNUTLS_E_SHORT_MEMORY_BUFFER) { 480 g_warning("couldn't gnutls_x509_crt_export to get size b %s", gnutls_strerror(r)); 481 return FALSE; 482 } 483 484 if (cert_size_a != cert_size_b) { 485 debug_print("sizes differ: %"G_GSIZE_FORMAT" != %"G_GSIZE_FORMAT"\n", cert_size_a, cert_size_b); 486 return FALSE; 487 } 488 489 output_a = g_malloc(cert_size_a); 490 output_b = g_malloc(cert_size_b); 491 if ((r = gnutls_x509_crt_export(cert_a->x509_cert, GNUTLS_X509_FMT_DER, output_a, &cert_size_a)) < 0) { 492 g_warning("couldn't gnutls_x509_crt_export a %s", gnutls_strerror(r)); 493 g_free(output_a); 494 g_free(output_b); 495 return FALSE; 496 } 497 if ((r = gnutls_x509_crt_export(cert_b->x509_cert, GNUTLS_X509_FMT_DER, output_b, &cert_size_b)) < 0) { 498 g_warning("couldn't gnutls_x509_crt_export b %s", gnutls_strerror(r)); 499 g_free(output_a); 500 g_free(output_b); 501 return FALSE; 502 } 503 if (memcmp(output_a, output_b, cert_size_a)) { 504 debug_print("contents differ\n"); 505 g_free(output_a); 506 g_free(output_b); 507 return FALSE; 508 } 509 g_free(output_a); 510 g_free(output_b); 511 512 return TRUE; 513 } 514 515 static guint check_cert(SSLCertificate *cert) 516 { 517 gnutls_x509_crt_t *ca_list = NULL; 518 gnutls_x509_crt_t *chain = NULL; 519 unsigned int max_ca = 512, max_certs; 520 unsigned int flags = 0; 521 int r, i; 522 unsigned int status; 523 gchar *chain_file = NULL, *buf = NULL; 524 FILE *fp; 525 526 if (claws_ssl_get_cert_file()) 527 fp = g_fopen(claws_ssl_get_cert_file(), "r"); 528 else 529 return (guint)-1; 530 531 if (fp == NULL) 532 return (guint)-1; 533 534 if ((r = gnutls_import_X509_list_fp(fp, GNUTLS_X509_FMT_PEM, &ca_list, &max_ca)) < 0) { 535 debug_print("CA import failed: %s\n", gnutls_strerror(r)); 536 fclose(fp); 537 return (guint)-1; 538 } 539 fclose(fp); 540 fp = NULL; 541 542 buf = g_strdup_printf("%d", cert->port); 543 chain_file = get_certificate_chain_path(cert->host, buf, cert->fingerprint); 544 g_free(buf); 545 if (is_file_exist(chain_file)) { 546 unsigned char md[128]; 547 size_t n = 128; 548 char *fingerprint; 549 550 fp = g_fopen(chain_file, "r"); 551 if (fp == NULL) { 552 debug_print("g_fopen %s failed: %s\n", chain_file, g_strerror(errno)); 553 g_free(chain_file); 554 return (guint)-1; 555 } 556 if ((r = gnutls_import_X509_list_fp(fp, GNUTLS_X509_FMT_PEM, &chain, &max_certs)) < 0) { 557 debug_print("chain import failed: %s\n", gnutls_strerror(r)); 558 fclose(fp); 559 g_free(chain_file); 560 return (guint)-1; 561 } 562 g_free(chain_file); 563 fclose(fp); 564 fp = NULL; 565 566 gnutls_x509_crt_get_fingerprint(chain[0], GNUTLS_DIG_MD5, md, &n); 567 fingerprint = readable_fingerprint(md, n); 568 if (!fingerprint || strcmp(fingerprint, cert->fingerprint)) { 569 debug_print("saved chain fingerprint does not match current : %s / %s\n", 570 cert->fingerprint, fingerprint); 571 572 return (guint)-1; 573 } 574 g_free(fingerprint); 575 576 r = gnutls_x509_crt_list_verify (chain, 577 max_certs, 578 ca_list, max_ca, 579 NULL, 0, 580 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, 581 &status); 582 if (r < 0) 583 debug_print("chain check failed: %s\n", gnutls_strerror(r)); 584 585 for (i = 0; i < max_certs; i++) 586 gnutls_x509_crt_deinit(chain[i]); 587 free(chain); 588 589 } else { 590 r = gnutls_x509_crt_verify(cert->x509_cert, ca_list, max_ca, flags, &status); 591 if (r < 0) 592 debug_print("cert check failed: %s\n", gnutls_strerror(r)); 593 } 594 595 for (i = 0; i < max_ca; i++) 596 gnutls_x509_crt_deinit(ca_list[i]); 597 free(ca_list); 598 599 if (r < 0) 600 return (guint)-1; 601 else 602 return status; 603 604 } 605 606 static gboolean ssl_certificate_is_valid(SSLCertificate *cert, guint status) 607 { 608 gchar *str_status = ssl_certificate_check_signer(cert, status); 609 610 if (str_status != NULL) { 611 g_free(str_status); 612 return FALSE; 613 } 614 return ssl_certificate_check_subject_cn(cert); 615 } 616 617 char *ssl_certificate_check_signer (SSLCertificate *cert, guint status) 618 { 619 gnutls_x509_crt_t x509_cert = cert ? cert->x509_cert : NULL; 620 621 if (!cert) 622 return g_strdup(_("Internal error")); 623 624 if (status == (guint)-1) { 625 status = check_cert(cert); 626 if (status == -1) 627 return g_strdup(_("Uncheckable")); 628 } 629 if (status & GNUTLS_CERT_INVALID) { 630 if (gnutls_x509_crt_check_issuer(x509_cert, x509_cert)) 631 return g_strdup(_("Self-signed certificate")); 632 } 633 if (status & GNUTLS_CERT_REVOKED) 634 return g_strdup(_("Revoked certificate")); 635 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) 636 return g_strdup(_("No certificate issuer found")); 637 if (status & GNUTLS_CERT_SIGNER_NOT_CA) 638 return g_strdup(_("Certificate issuer is not a CA")); 639 640 641 return NULL; 642 } 643 644 static void ssl_certificate_save_chain(gnutls_x509_crt_t *certs, gint len, const gchar *host, gushort port) 645 { 646 gint i; 647 gchar *file = NULL; 648 FILE *fp = NULL; 649 650 for (i = 0; i < len; i++) { 651 size_t n; 652 unsigned char md[128]; 653 gnutls_x509_crt_t cert = certs[i]; 654 655 if (i == 0) { 656 n = sizeof(md); 657 gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, md, &n); 658 gchar *fingerprint = readable_fingerprint(md, n); 659 gchar *buf = g_strdup_printf("%d", port); 660 661 file = get_certificate_chain_path(host, buf, fingerprint); 662 g_free(fingerprint); 663 664 g_free(buf); 665 666 fp = g_fopen(file, "wb"); 667 if (fp == NULL) { 668 g_free(file); 669 debug_print("Can't save certificate !\n"); 670 return; 671 } 672 g_free(file); 673 } 674 675 gnutls_export_X509_fp(fp, cert, GNUTLS_X509_FMT_PEM); 676 677 } 678 if (fp) 679 fclose(fp); 680 } 681 682 gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, 683 const gchar *host, gushort port, 684 gboolean accept_if_valid) 685 { 686 SSLCertificate *current_cert = NULL; 687 SSLCertificate *known_cert; 688 SSLCertHookData cert_hook_data; 689 gchar *fingerprint; 690 size_t n; 691 unsigned char md[128]; 692 gboolean valid = FALSE; 693 694 current_cert = ssl_certificate_new(x509_cert, host, port); 695 696 if (current_cert == NULL) { 697 debug_print("Buggy certificate !\n"); 698 return FALSE; 699 } 700 701 current_cert->status = status; 702 /* fingerprint */ 703 n = sizeof(md); 704 gnutls_x509_crt_get_fingerprint(x509_cert, GNUTLS_DIG_MD5, md, &n); 705 fingerprint = readable_fingerprint(md, n); 706 707 known_cert = ssl_certificate_find(host, port, fingerprint); 708 709 g_free(fingerprint); 710 711 if (accept_if_valid) 712 valid = ssl_certificate_is_valid(current_cert, status); 713 else 714 valid = FALSE; /* Force check */ 715 716 if (known_cert == NULL) { 717 if (valid) { 718 ssl_certificate_save(current_cert); 719 ssl_certificate_destroy(current_cert); 720 return TRUE; 721 } 722 723 cert_hook_data.cert = current_cert; 724 cert_hook_data.old_cert = NULL; 725 cert_hook_data.expired = FALSE; 726 cert_hook_data.accept = FALSE; 727 728 hooks_invoke(SSLCERT_ASK_HOOKLIST, &cert_hook_data); 729 730 if (!cert_hook_data.accept) { 731 ssl_certificate_destroy(current_cert); 732 return FALSE; 733 } else { 734 ssl_certificate_save(current_cert); 735 ssl_certificate_destroy(current_cert); 736 return TRUE; 737 } 738 } else if (!ssl_certificate_compare (current_cert, known_cert)) { 739 if (valid) { 740 ssl_certificate_save(current_cert); 741 ssl_certificate_destroy(current_cert); 742 ssl_certificate_destroy(known_cert); 743 return TRUE; 744 } 745 746 cert_hook_data.cert = current_cert; 747 cert_hook_data.old_cert = known_cert; 748 cert_hook_data.expired = FALSE; 749 cert_hook_data.accept = FALSE; 750 751 hooks_invoke(SSLCERT_ASK_HOOKLIST, &cert_hook_data); 752 753 if (!cert_hook_data.accept) { 754 ssl_certificate_destroy(current_cert); 755 ssl_certificate_destroy(known_cert); 756 return FALSE; 757 } else { 758 ssl_certificate_save(current_cert); 759 ssl_certificate_destroy(current_cert); 760 ssl_certificate_destroy(known_cert); 761 return TRUE; 762 } 763 } else if (gnutls_x509_crt_get_expiration_time(current_cert->x509_cert) < time(NULL)) { 764 gchar *tmp = g_strdup_printf("%s:%d", current_cert->host, current_cert->port); 765 766 if (warned_expired == NULL) 767 warned_expired = g_hash_table_new(g_str_hash, g_str_equal); 768 769 if (g_hash_table_lookup(warned_expired, tmp)) { 770 g_free(tmp); 771 ssl_certificate_destroy(current_cert); 772 ssl_certificate_destroy(known_cert); 773 return TRUE; 774 } 775 776 cert_hook_data.cert = current_cert; 777 cert_hook_data.old_cert = NULL; 778 cert_hook_data.expired = TRUE; 779 cert_hook_data.accept = FALSE; 780 781 hooks_invoke(SSLCERT_ASK_HOOKLIST, &cert_hook_data); 782 783 if (!cert_hook_data.accept) { 784 g_free(tmp); 785 ssl_certificate_destroy(current_cert); 786 ssl_certificate_destroy(known_cert); 787 return FALSE; 788 } else { 789 g_hash_table_insert(warned_expired, tmp, GINT_TO_POINTER(1)); 790 ssl_certificate_destroy(current_cert); 791 ssl_certificate_destroy(known_cert); 792 return TRUE; 793 } 794 } 795 796 ssl_certificate_destroy(current_cert); 797 ssl_certificate_destroy(known_cert); 798 return TRUE; 799 } 800 801 gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, 802 const gchar *host, gushort port, 803 gboolean accept_if_valid) 804 { 805 int ncas = 0; 806 gnutls_x509_crt_t *cas = NULL; 807 gboolean result = FALSE; 808 int i; 809 gint status; 810 811 if (claws_ssl_get_cert_file()) { 812 FILE *fp = g_fopen(claws_ssl_get_cert_file(), "rb"); 813 int r = -errno; 814 815 if (fp) { 816 r = gnutls_import_X509_list_fp(fp, GNUTLS_X509_FMT_PEM, &cas, &ncas); 817 fclose(fp); 818 } 819 820 if (r < 0) 821 g_warning("read certificate file '%s': %s", 822 claws_ssl_get_cert_file(), 823 gnutls_strerror(r)); 824 } else { 825 debug_print("Can't find SSL ca-certificates file\n"); 826 } 827 828 829 gnutls_x509_crt_list_verify (certs, 830 chain_len, 831 cas, ncas, 832 NULL, 0, 833 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, 834 &status); 835 836 result = ssl_certificate_check(certs[0], status, host, port, 837 accept_if_valid); 838 839 if (result == TRUE) { 840 ssl_certificate_save_chain(certs, chain_len, host, port); 841 } 842 843 for (i = 0; i < ncas; i++) 844 gnutls_x509_crt_deinit(cas[i]); 845 free(cas); 846 847 return result; 848 } 849 850 gnutls_x509_crt_t ssl_certificate_get_x509_from_pem_file(const gchar *file) 851 { 852 gnutls_x509_crt_t x509 = NULL; 853 if (!file) 854 return NULL; 855 856 if (is_file_exist(file)) { 857 FILE *fp = g_fopen(file, "r"); 858 if (fp) { 859 x509 = gnutls_import_X509_fp(fp, GNUTLS_X509_FMT_PEM); 860 fclose(fp); 861 return x509; 862 } else { 863 log_error(LOG_PROTOCOL, _("Cannot open certificate file %s: %s\n"), 864 file, g_strerror(errno)); 865 } 866 } else { 867 log_error(LOG_PROTOCOL, _("Certificate file %s missing (%s)\n"), 868 file, g_strerror(errno)); 869 } 870 return NULL; 871 } 872 873 gnutls_x509_privkey_t ssl_certificate_get_pkey_from_pem_file(const gchar *file) 874 { 875 gnutls_x509_privkey_t key = NULL; 876 if (!file) 877 return NULL; 878 879 if (is_file_exist(file)) { 880 FILE *fp = g_fopen(file, "r"); 881 if (fp) { 882 key = gnutls_import_key_fp(fp, GNUTLS_X509_FMT_PEM); 883 fclose(fp); 884 return key; 885 } else { 886 log_error(LOG_PROTOCOL, _("Cannot open key file %s (%s)\n"), 887 file, g_strerror(errno)); 888 } 889 } else { 890 log_error(LOG_PROTOCOL, _("Key file %s missing (%s)\n"), file, 891 g_strerror(errno)); 892 } 893 return NULL; 894 } 895 896 /* From GnuTLS lib/gnutls_x509.c */ 897 static int 898 parse_pkcs12 (gnutls_pkcs12_t p12, 899 const char *password, 900 gnutls_x509_privkey_t * key, 901 gnutls_x509_crt_t * cert) 902 { 903 gnutls_pkcs12_bag_t bag = NULL; 904 int index = 0; 905 int ret; 906 907 for (;;) 908 { 909 int elements_in_bag; 910 int i; 911 912 ret = gnutls_pkcs12_bag_init (&bag); 913 if (ret < 0) 914 { 915 bag = NULL; 916 goto done; 917 } 918 919 ret = gnutls_pkcs12_get_bag (p12, index, bag); 920 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) 921 break; 922 if (ret < 0) 923 { 924 goto done; 925 } 926 927 ret = gnutls_pkcs12_bag_get_type (bag, 0); 928 if (ret < 0) 929 { 930 goto done; 931 } 932 933 if (ret == GNUTLS_BAG_ENCRYPTED) 934 { 935 ret = gnutls_pkcs12_bag_decrypt (bag, password); 936 if (ret < 0) 937 { 938 goto done; 939 } 940 } 941 942 elements_in_bag = gnutls_pkcs12_bag_get_count (bag); 943 if (elements_in_bag < 0) 944 { 945 goto done; 946 } 947 948 for (i = 0; i < elements_in_bag; i++) 949 { 950 int type; 951 gnutls_datum_t data; 952 953 type = gnutls_pkcs12_bag_get_type (bag, i); 954 if (type < 0) 955 { 956 goto done; 957 } 958 959 ret = gnutls_pkcs12_bag_get_data (bag, i, &data); 960 if (ret < 0) 961 { 962 goto done; 963 } 964 965 switch (type) 966 { 967 case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: 968 case GNUTLS_BAG_PKCS8_KEY: 969 ret = gnutls_x509_privkey_init (key); 970 if (ret < 0) 971 { 972 goto done; 973 } 974 975 ret = gnutls_x509_privkey_import_pkcs8 976 (*key, &data, GNUTLS_X509_FMT_DER, password, 977 type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0); 978 if (ret < 0) 979 { 980 goto done; 981 } 982 break; 983 984 case GNUTLS_BAG_CERTIFICATE: 985 ret = gnutls_x509_crt_init (cert); 986 if (ret < 0) 987 { 988 goto done; 989 } 990 991 ret = 992 gnutls_x509_crt_import (*cert, &data, GNUTLS_X509_FMT_DER); 993 if (ret < 0) 994 { 995 goto done; 996 } 997 break; 998 999 case GNUTLS_BAG_ENCRYPTED: 1000 /* XXX Bother to recurse one level down? Unlikely to 1001 use the same password anyway. */ 1002 case GNUTLS_BAG_EMPTY: 1003 default: 1004 break; 1005 } 1006 } 1007 1008 index++; 1009 gnutls_pkcs12_bag_deinit (bag); 1010 } 1011 1012 ret = 0; 1013 1014 done: 1015 if (bag) 1016 gnutls_pkcs12_bag_deinit (bag); 1017 1018 return ret; 1019 } 1020 void ssl_certificate_get_x509_and_pkey_from_p12_file(const gchar *file, const gchar *password, 1021 gnutls_x509_crt_t *x509, gnutls_x509_privkey_t *pkey) 1022 { 1023 gnutls_pkcs12_t p12 = NULL; 1024 1025 int r; 1026 1027 *x509 = NULL; 1028 *pkey = NULL; 1029 if (!file) 1030 return; 1031 1032 if (is_file_exist(file)) { 1033 FILE *fp = g_fopen(file, "r"); 1034 if (fp) { 1035 p12 = gnutls_import_PKCS12_fp(fp, GNUTLS_X509_FMT_DER); 1036 fclose(fp); 1037 if (!p12) { 1038 log_error(LOG_PROTOCOL, _("Failed to read P12 certificate file %s\n"), file); 1039 } 1040 } else { 1041 log_error(LOG_PROTOCOL, _("Cannot open P12 certificate file %s (%s)\n"), 1042 file, g_strerror(errno)); 1043 } 1044 } else { 1045 log_error(LOG_PROTOCOL, _("P12 Certificate file %s missing (%s)\n"), file, 1046 g_strerror(errno)); 1047 } 1048 if (p12 != NULL) { 1049 if ((r = parse_pkcs12(p12, password, pkey, x509)) == 0) { 1050 debug_print("got p12\n"); 1051 } else { 1052 log_error(LOG_PROTOCOL, "%s\n", gnutls_strerror(r)); 1053 } 1054 gnutls_pkcs12_deinit(p12); 1055 } 1056 } 1057 1058 gboolean ssl_certificate_check_subject_cn(SSLCertificate *cert) 1059 { 1060 return gnutls_x509_crt_check_hostname(cert->x509_cert, cert->host) != 0; 1061 } 1062 1063 gchar *ssl_certificate_get_subject_cn(SSLCertificate *cert) 1064 { 1065 gchar subject_cn[BUFFSIZE]; 1066 size_t n = BUFFSIZE; 1067 1068 if(gnutls_x509_crt_get_dn_by_oid(cert->x509_cert, 1069 GNUTLS_OID_X520_COMMON_NAME, 0, 0, subject_cn, &n)) 1070 return g_strdup(_("<not in certificate>")); 1071 1072 return g_strdup(subject_cn); 1073 }