- fix broken match_component() - fix \0 in CN and subjAltname - don't use CN if dNSName in subjAltname - use most specific (=last) CN instead of the first Index: libesmtp-1.0.4/smtp-tls.c =================================================================== --- libesmtp-1.0.4.orig/smtp-tls.c +++ libesmtp-1.0.4/smtp-tls.c @@ -439,16 +439,24 @@ static int match_component (const char *dom, const char *edom, const char *ref, const char *eref) { + int wildcard = 0; + while (dom < edom && ref < eref) { /* Accept a final '*' in the reference as a wildcard */ if (*ref == '*' && ref + 1 == eref) - break; + { + wildcard = 1; + break; + } /* compare the domain name case insensitive */ if (!(*dom == *ref || tolower (*dom) == tolower (*ref))) return 0; ref++, dom++; } + if (!wildcard && (dom < edom || ref < eref)) + return 0; + return 1; } @@ -492,7 +500,6 @@ static int check_acceptable_security (smtp_session_t session, SSL *ssl) { X509 *cert; - char buf[256]; int bits; long vfy_result; int ok; @@ -541,65 +548,71 @@ check_acceptable_security (smtp_session_ } else { - int i, j, extcount; + char buf[256] = {0}; + STACK_OF(GENERAL_NAME) *altnames; + int hasaltname = 0; - extcount = X509_get_ext_count (cert); - for (i = 0; i < extcount; i++) + altnames = X509_get_ext_d2i (cert, NID_subject_alt_name, NULL, NULL); + if (altnames != NULL) { - const char *extstr; - X509_EXTENSION *ext = X509_get_ext (cert, i); - - extstr = OBJ_nid2sn (OBJ_obj2nid (X509_EXTENSION_get_object (ext))); - if (strcmp (extstr, "subjectAltName") == 0) + int i; + for (i = 0; i < sk_GENERAL_NAME_num (altnames); ++i) { - unsigned char *data; - STACK_OF(CONF_VALUE) *val; - CONF_VALUE *nval; - X509V3_EXT_METHOD *meth; - void *ext_str = NULL; - int stack_len; - - meth = X509V3_EXT_get (ext); - if (meth == NULL) - break; - data = ext->value->data; -#if (OPENSSL_VERSION_NUMBER > 0x00907000L) - if (meth->it) - ext_str = ASN1_item_d2i (NULL, &data, ext->value->length, - ASN1_ITEM_ptr (meth->it)); - else -#endif - ext_str = meth->d2i (NULL, &data, ext->value->length); - val = meth->i2v (meth, ext_str, NULL); - stack_len = sk_CONF_VALUE_num (val); - for (j = 0; j < stack_len; j++) + GENERAL_NAME *name = sk_GENERAL_NAME_value (altnames, i); + if (name->type == GEN_DNS) { - nval = sk_CONF_VALUE_value (val, j); - if (strcmp (nval->name, "DNS") == 0 - && match_domain (session->host, nval->value)) + const ASN1_IA5STRING* ia5str = name->d.ia5; + hasaltname = 1; + if (strlen ((const char *)ia5str->data) == ia5str->length + && match_domain (session->host, (const char *)ia5str->data)) + ok = 1; + else { - ok = 1; - break; + *buf = 0; + strncat(buf, (const char *)ia5str->data, sizeof(buf)-1); } } + // TODO: handle GEN_IPADD } - if (ok) - break; + sk_GENERAL_NAME_pop_free (altnames, GENERAL_NAME_free); } - if (!ok) + + if (!hasaltname) { - /* Matching by subjectAltName failed, try commonName */ - X509_NAME_get_text_by_NID (X509_get_subject_name (cert), - NID_commonName, buf, sizeof buf); - if (!match_domain (session->host, buf) != 0) + X509_NAME *subj = X509_get_subject_name(cert); + if (subj) { - if (session->event_cb != NULL) - (*session->event_cb) (session, SMTP_EV_WRONG_PEER_CERTIFICATE, - session->event_cb_arg, &ok, buf, ssl); + ASN1_STRING *cn; + int idx, i = -1; + do + { + idx = i; + } + while((i = X509_NAME_get_index_by_NID(subj, NID_commonName, i)) >= 0); + + if (idx >= 0 && (cn = X509_NAME_ENTRY_get_data (X509_NAME_get_entry (subj, idx)))) + { + unsigned char* str = NULL; + int len = ASN1_STRING_to_UTF8 (&str, cn); + if (str) + { + if (strlen((char*)str) == len && match_domain(session->host, (char*)str)) + ok = 1; + else + { + *buf = 0; + strncat(buf, (char *)str, sizeof(buf)-1); + } + OPENSSL_free(str); + } + } } - else - ok = 1; } + + if (!ok && session->event_cb != NULL) + (*session->event_cb) (session, SMTP_EV_WRONG_PEER_CERTIFICATE, + session->event_cb_arg, &ok, buf, ssl); + X509_free (cert); } return ok;