| 591 | | static int check_certificate_hostname(X509 *peercert, const char *host) |
| 592 | | { |
| 593 | | char cert_CN[STRING]; |
| 594 | | |
| 595 | | if (!host || !*host) |
| 596 | | return 0; |
| 597 | | |
| 598 | | X509_NAME_get_text_by_NID (X509_get_subject_name (peercert), |
| 599 | | NID_commonName, cert_CN, sizeof (cert_CN)); |
| 600 | | |
| 601 | | dprint (2, (debugfile, "check_certificate_hostname: cert=[%s] host=[%s]\n", |
| 602 | | cert_CN, host)); |
| 603 | | |
| 604 | | return strcmp (cert_CN, host) == 0; |
| | 593 | /* port to mutt from msmtp's tls.c */ |
| | 594 | static int hostname_match (const char *hostname, const char *certname) |
| | 595 | { |
| | 596 | const char *cmp1, *cmp2; |
| | 597 | |
| | 598 | if (strncmp(certname, "*.", 2) == 0) |
| | 599 | { |
| | 600 | cmp1 = certname + 2; |
| | 601 | cmp2 = strchr(hostname, '.'); |
| | 602 | if (!cmp2) |
| | 603 | { |
| | 604 | return 0; |
| | 605 | } |
| | 606 | else |
| | 607 | { |
| | 608 | cmp2++; |
| | 609 | } |
| | 610 | } |
| | 611 | else |
| | 612 | { |
| | 613 | cmp1 = certname; |
| | 614 | cmp2 = hostname; |
| | 615 | } |
| | 616 | |
| | 617 | if (*cmp1 == '\0' || *cmp2 == '\0') |
| | 618 | { |
| | 619 | return 0; |
| | 620 | } |
| | 621 | |
| | 622 | if (strcasecmp(cmp1, cmp2) != 0) |
| | 623 | { |
| | 624 | return 0; |
| | 625 | } |
| | 626 | |
| | 627 | return 1; |
| | 628 | } |
| | 629 | |
| | 630 | /* port to mutt from msmtp's tls.c */ |
| | 631 | static int check_host (X509 *x509cert, const char *hostname, char *err, size_t errlen) |
| | 632 | { |
| | 633 | int i, rc = 0; |
| | 634 | /* hostname in ASCII format: */ |
| | 635 | char *hostname_ascii = NULL; |
| | 636 | /* needed to get the common name: */ |
| | 637 | X509_NAME *x509_subject; |
| | 638 | char *buf = NULL; |
| | 639 | int bufsize; |
| | 640 | /* needed to get the DNS subjectAltNames: */ |
| | 641 | STACK *subj_alt_names; |
| | 642 | int subj_alt_names_count; |
| | 643 | GENERAL_NAME *subj_alt_name; |
| | 644 | /* did we find a name matching hostname? */ |
| | 645 | int match_found; |
| | 646 | |
| | 647 | /* Check if 'hostname' matches the one of the subjectAltName extensions of |
| | 648 | * type DNS or the Common Name (CN). */ |
| | 649 | |
| | 650 | #ifdef HAVE_LIBIDN |
| | 651 | if (idna_to_ascii_lz(hostname, &hostname_ascii, 0) != IDNA_SUCCESS) |
| | 652 | { |
| | 653 | hostname_ascii = safe_strdup(hostname); |
| | 654 | } |
| | 655 | #else |
| | 656 | hostname_ascii = safe_strdup(hostname); |
| | 657 | #endif |
| | 658 | |
| | 659 | /* Try the DNS subjectAltNames. */ |
| | 660 | match_found = 0; |
| | 661 | if ((subj_alt_names = X509_get_ext_d2i(x509cert, NID_subject_alt_name, |
| | 662 | NULL, NULL))) |
| | 663 | { |
| | 664 | subj_alt_names_count = sk_GENERAL_NAME_num(subj_alt_names); |
| | 665 | for (i = 0; i < subj_alt_names_count; i++) |
| | 666 | { |
| | 667 | subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i); |
| | 668 | if (subj_alt_name->type == GEN_DNS) |
| | 669 | { |
| | 670 | if ((match_found = hostname_match(hostname_ascii, |
| | 671 | (char *)(subj_alt_name->d.ia5->data)))) |
| | 672 | { |
| | 673 | break; |
| | 674 | } |
| | 675 | } |
| | 676 | } |
| | 677 | } |
| | 678 | |
| | 679 | if (!match_found) |
| | 680 | { |
| | 681 | /* Try the common name */ |
| | 682 | if (!(x509_subject = X509_get_subject_name(x509cert))) |
| | 683 | { |
| | 684 | if (err && errlen) |
| | 685 | strfcpy (err, _("cannot get certificate subject"), errlen); |
| | 686 | goto out; |
| | 687 | } |
| | 688 | |
| | 689 | bufsize = X509_NAME_get_text_by_NID(x509_subject, NID_commonName, |
| | 690 | NULL, 0); |
| | 691 | bufsize++; |
| | 692 | buf = safe_malloc((size_t)bufsize); |
| | 693 | if (X509_NAME_get_text_by_NID(x509_subject, NID_commonName, |
| | 694 | buf, bufsize) == -1) |
| | 695 | { |
| | 696 | if (err && errlen) |
| | 697 | strfcpy (err, _("cannot get certificate common name"), errlen); |
| | 698 | goto out; |
| | 699 | } |
| | 700 | match_found = hostname_match(hostname_ascii, buf); |
| | 701 | } |
| | 702 | |
| | 703 | if (!match_found) |
| | 704 | { |
| | 705 | if (err && errlen) |
| | 706 | snprintf (err, errlen, _("certificate owner does not match hostname %s"), |
| | 707 | hostname); |
| | 708 | goto out; |
| | 709 | } |
| | 710 | |
| | 711 | rc = 1; |
| | 712 | |
| | 713 | out: |
| | 714 | FREE(&buf); |
| | 715 | FREE(&hostname_ascii); |
| | 716 | |
| | 717 | return rc; |