~ubuntu-branches/ubuntu/vivid/dovecot/vivid

« back to all changes in this revision

Viewing changes to src/login-common/ssl-proxy-openssl.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-12-08 14:34:36 UTC
  • Revision ID: package-import@ubuntu.com-20111208143436-9scnmh9l46vo9opk
Tags: 1:2.0.15-1ubuntu5
* SECURITY UPDATE: Incorrect cert Common Name verification when proxying
  - debian/patches/CVE-2011-4318.patch: correctly validate Common Name
    when a hostname is specified in src/login-common/{login-proxy.c,
    ssl-proxy.*,ssl-proxy-openssl.c}.
  - CVE-2011-4318

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
#include <openssl/crypto.h>
23
23
#include <openssl/x509.h>
 
24
#include <openssl/x509v3.h>
24
25
#include <openssl/pem.h>
25
26
#include <openssl/ssl.h>
26
27
#include <openssl/err.h>
661
662
        return proxy->cert_received && proxy->cert_broken;
662
663
}
663
664
 
 
665
static const char *asn1_string_to_c(ASN1_STRING *asn_str)
 
666
{
 
667
        const char *cstr;
 
668
        unsigned int len;
 
669
 
 
670
        len = ASN1_STRING_length(asn_str);
 
671
        cstr = t_strndup(ASN1_STRING_data(asn_str), len);
 
672
        if (strlen(cstr) != len) {
 
673
                /* NULs in the name - could be some MITM attack.
 
674
                   never allow. */
 
675
                return "";
 
676
        }
 
677
        return cstr;
 
678
}
 
679
 
 
680
static const char *get_general_dns_name(const GENERAL_NAME *name)
 
681
{
 
682
        if (ASN1_STRING_type(name->d.ia5) != V_ASN1_IA5STRING)
 
683
                return "";
 
684
 
 
685
        return asn1_string_to_c(name->d.ia5);
 
686
}
 
687
 
 
688
static const char *get_cname(X509 *cert)
 
689
{
 
690
        X509_NAME *name;
 
691
        X509_NAME_ENTRY *entry;
 
692
        ASN1_STRING *str;
 
693
        int cn_idx;
 
694
 
 
695
        name = X509_get_subject_name(cert);
 
696
        if (name == NULL)
 
697
                return "";
 
698
        cn_idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
 
699
        if (cn_idx == -1)
 
700
                return "";
 
701
        entry = X509_NAME_get_entry(name, cn_idx);
 
702
        i_assert(entry != NULL);
 
703
        str = X509_NAME_ENTRY_get_data(entry);
 
704
        i_assert(str != NULL);
 
705
        return asn1_string_to_c(str);
 
706
}
 
707
 
 
708
static int openssl_cert_match_name(SSL *ssl, const char *verify_name)
 
709
{
 
710
        X509 *cert;
 
711
        STACK_OF(GENERAL_NAME) *gnames;
 
712
        const GENERAL_NAME *gn;
 
713
        const char *dnsname;
 
714
        bool dns_names = FALSE;
 
715
        unsigned int i, count;
 
716
 
 
717
        cert = SSL_get_peer_certificate(ssl);
 
718
        i_assert(cert != NULL);
 
719
 
 
720
        /* verify against SubjectAltNames */
 
721
        gnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 
722
        count = gnames == NULL ? 0 : sk_GENERAL_NAME_num(gnames);
 
723
        for (i = 0; i < count; i++) {
 
724
                gn = sk_GENERAL_NAME_value(gnames, i);
 
725
                if (gn->type == GEN_DNS) {
 
726
                        dns_names = TRUE;
 
727
                        dnsname = get_general_dns_name(gn);
 
728
                        if (strcmp(dnsname, verify_name) == 0)
 
729
                                break;
 
730
                }
 
731
        }
 
732
        sk_GENERAL_NAME_pop_free(gnames, GENERAL_NAME_free);
 
733
        /* verify against CommonName only when there wasn't any DNS
 
734
           SubjectAltNames */
 
735
        if (dns_names)
 
736
                return i < count ? 0 : -1;
 
737
 
 
738
        return strcmp(get_cname(cert), verify_name) == 0 ? 0 : -1;
 
739
}
 
740
 
 
741
int ssl_proxy_cert_match_name(struct ssl_proxy *proxy, const char *verify_name)
 
742
{
 
743
        return openssl_cert_match_name(proxy->ssl, verify_name);
 
744
}
 
745
 
664
746
const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy)
665
747
{
666
748
        X509 *x509;
847
929
                else
848
930
                        i_info("Valid certificate: %s", buf);
849
931
        }
 
932
        if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL && proxy->client_proxy) {
 
933
                /* no CRL given with the CA list. don't worry about it. */
 
934
                preverify_ok = 1;
 
935
        }
850
936
        if (!preverify_ok)
851
937
                proxy->cert_broken = TRUE;
852
938