* [PATCH 0/4] imap-send: modernize the OpenSSL API
@ 2026-03-11 12:11 Beat Bolli
2026-03-11 12:11 ` [PATCH 1/4] imap-send: use the OpenSSL API to access the subject alternative names Beat Bolli
` (7 more replies)
0 siblings, 8 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 12:11 UTC (permalink / raw)
To: git; +Cc: Beat Bolli, Oswald Buddenhagen
OpenSSL recently released version 4.0.0-alpha1 [1]. Compiling with this
version revealed some erroneous and deprecated code.
This series aims to update this code to use the documented OpenSSL APIs.
All of the newly used APIs have existed since OpenSSL 1.1.0, the latest
version of which was released in September 2019 [2]. IMHO there is no
need to support even older OpenSSL versions.
- The first two commits are needed to make imap-send.c compile against
OpenSSL 4.0 (and older!).
- The remaining two are follow-up cleanups that are not strictly
necessary.
Cc-ing Oswald as the original author of the affected code.
[1] https://github.com/openssl/openssl/tree/openssl-4.0.0-alpha1
[2] https://openssl-library.org/source/old/1.1.0/index.html
Beat Bolli (4):
imap-send: use the OpenSSL API to access the subject alternative names
imap-send: use the OpenSSL API to access the subject common name
imap-send: remove two string length checks
imap-send: refactor function host_matches()
imap-send.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/4] imap-send: use the OpenSSL API to access the subject alternative names
2026-03-11 12:11 [PATCH 0/4] imap-send: modernize the OpenSSL API Beat Bolli
@ 2026-03-11 12:11 ` Beat Bolli
2026-03-11 12:11 ` [PATCH 2/4] imap-send: use the OpenSSL API to access the subject common name Beat Bolli
` (6 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 12:11 UTC (permalink / raw)
To: git; +Cc: Beat Bolli, Oswald Buddenhagen
The OpenSSL 4.0 branch has made the ASN1_STRING structure opaque,
forbidding access to its internal fields. Use the official accessor
functions instead. They have existed since OpenSSL 1.1.0.
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
imap-send.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 26dda7f328..1c934c2487 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -244,10 +244,14 @@ static int verify_hostname(X509 *cert, const char *hostname)
if ((subj_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL))) {
int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names);
for (i = 0; !found && i < num_subj_alt_names; i++) {
+ int ntype;
GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
- if (subj_alt_name->type == GEN_DNS &&
- strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length &&
- host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data)))
+ ASN1_STRING *subj_alt_str = GENERAL_NAME_get0_value(subj_alt_name, &ntype);
+
+ if (ntype == GEN_DNS &&
+ strlen((const char *)ASN1_STRING_get0_data(subj_alt_str)) ==
+ ASN1_STRING_length(subj_alt_str) &&
+ host_matches(hostname, (const char *)ASN1_STRING_get0_data(subj_alt_str)))
found = 1;
}
sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free);
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/4] imap-send: use the OpenSSL API to access the subject common name
2026-03-11 12:11 [PATCH 0/4] imap-send: modernize the OpenSSL API Beat Bolli
2026-03-11 12:11 ` [PATCH 1/4] imap-send: use the OpenSSL API to access the subject alternative names Beat Bolli
@ 2026-03-11 12:11 ` Beat Bolli
2026-03-11 12:11 ` [PATCH 3/4] imap-send: remove two string length checks Beat Bolli
` (5 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 12:11 UTC (permalink / raw)
To: git; +Cc: Beat Bolli, Oswald Buddenhagen
The OpenSSL 4.0 branch has deprecated the X509_NAME_get_text_by_NID
function. Use the recommended replacement APIs instead. They have
existed since OpenSSL 1.1.0.
Pre-4.0 versions of X509_get_subject_name() return a non-const pointer
and more importantly only accept a non-const pointer in
X509_NAME_get_index_by_NID(), so we need a version check to handle both
cases.
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
imap-send.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 1c934c2487..2a904314dd 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -233,9 +233,13 @@ static int host_matches(const char *host, const char *pattern)
static int verify_hostname(X509 *cert, const char *hostname)
{
- int len;
+#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
+ const X509_NAME *subj;
+#else
X509_NAME *subj;
- char cname[1000];
+#endif
+ const X509_NAME_ENTRY *cname_entry;
+ const ASN1_STRING *cname;
int i, found;
STACK_OF(GENERAL_NAME) *subj_alt_names;
@@ -262,12 +266,15 @@ static int verify_hostname(X509 *cert, const char *hostname)
/* try the common name */
if (!(subj = X509_get_subject_name(cert)))
return error("cannot get certificate subject");
- if ((len = X509_NAME_get_text_by_NID(subj, NID_commonName, cname, sizeof(cname))) < 0)
+ if ((i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1)) < 0 ||
+ (cname_entry = X509_NAME_get_entry(subj, i)) == NULL ||
+ (cname = X509_NAME_ENTRY_get_data(cname_entry)) == NULL)
return error("cannot get certificate common name");
- if (strlen(cname) == (size_t)len && host_matches(hostname, cname))
+ if (strlen((const char *)ASN1_STRING_get0_data(cname)) == ASN1_STRING_length(cname) &&
+ host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
return 0;
return error("certificate owner '%s' does not match hostname '%s'",
- cname, hostname);
+ ASN1_STRING_get0_data(cname), hostname);
}
static int ssl_socket_connect(struct imap_socket *sock,
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/4] imap-send: remove two string length checks
2026-03-11 12:11 [PATCH 0/4] imap-send: modernize the OpenSSL API Beat Bolli
2026-03-11 12:11 ` [PATCH 1/4] imap-send: use the OpenSSL API to access the subject alternative names Beat Bolli
2026-03-11 12:11 ` [PATCH 2/4] imap-send: use the OpenSSL API to access the subject common name Beat Bolli
@ 2026-03-11 12:11 ` Beat Bolli
2026-03-11 13:41 ` Oswald Buddenhagen
2026-03-11 18:55 ` Junio C Hamano
2026-03-11 12:11 ` [PATCH 4/4] imap-send: refactor function host_matches() Beat Bolli
` (4 subsequent siblings)
7 siblings, 2 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 12:11 UTC (permalink / raw)
To: git; +Cc: Beat Bolli, Oswald Buddenhagen
At this point, these two checks verify that the ASN1_STRINGs are
internally consistent. This may have been ok when the fields were
accessed directly, but now that the API is used, is unnecessary.
Remove the two checks.
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
imap-send.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 2a904314dd..2bb0003f08 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -253,8 +253,6 @@ static int verify_hostname(X509 *cert, const char *hostname)
ASN1_STRING *subj_alt_str = GENERAL_NAME_get0_value(subj_alt_name, &ntype);
if (ntype == GEN_DNS &&
- strlen((const char *)ASN1_STRING_get0_data(subj_alt_str)) ==
- ASN1_STRING_length(subj_alt_str) &&
host_matches(hostname, (const char *)ASN1_STRING_get0_data(subj_alt_str)))
found = 1;
}
@@ -270,8 +268,7 @@ static int verify_hostname(X509 *cert, const char *hostname)
(cname_entry = X509_NAME_get_entry(subj, i)) == NULL ||
(cname = X509_NAME_ENTRY_get_data(cname_entry)) == NULL)
return error("cannot get certificate common name");
- if (strlen((const char *)ASN1_STRING_get0_data(cname)) == ASN1_STRING_length(cname) &&
- host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
+ if (host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
return 0;
return error("certificate owner '%s' does not match hostname '%s'",
ASN1_STRING_get0_data(cname), hostname);
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/4] imap-send: refactor function host_matches()
2026-03-11 12:11 [PATCH 0/4] imap-send: modernize the OpenSSL API Beat Bolli
` (2 preceding siblings ...)
2026-03-11 12:11 ` [PATCH 3/4] imap-send: remove two string length checks Beat Bolli
@ 2026-03-11 12:11 ` Beat Bolli
2026-03-11 22:10 ` [PATCH v2 0/3] imap-send: modernize the OpenSSL API Beat Bolli
` (3 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 12:11 UTC (permalink / raw)
To: git; +Cc: Beat Bolli, Oswald Buddenhagen
Move the ASN1_STRING access and the associated cast into host_matches()
to simplify both callers.
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
imap-send.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 2bb0003f08..789055d7fd 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -219,8 +219,9 @@ static int ssl_socket_connect(struct imap_socket *sock UNUSED,
#else
-static int host_matches(const char *host, const char *pattern)
+static int host_matches(const char *host, const ASN1_STRING *asn1_str)
{
+ const char *pattern = (const char *)ASN1_STRING_get0_data(asn1_str);
if (pattern[0] == '*' && pattern[1] == '.') {
pattern += 2;
if (!(host = strchr(host, '.')))
@@ -252,8 +253,7 @@ static int verify_hostname(X509 *cert, const char *hostname)
GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
ASN1_STRING *subj_alt_str = GENERAL_NAME_get0_value(subj_alt_name, &ntype);
- if (ntype == GEN_DNS &&
- host_matches(hostname, (const char *)ASN1_STRING_get0_data(subj_alt_str)))
+ if (ntype == GEN_DNS && host_matches(hostname, subj_alt_str))
found = 1;
}
sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free);
@@ -268,7 +268,7 @@ static int verify_hostname(X509 *cert, const char *hostname)
(cname_entry = X509_NAME_get_entry(subj, i)) == NULL ||
(cname = X509_NAME_ENTRY_get_data(cname_entry)) == NULL)
return error("cannot get certificate common name");
- if (host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
+ if (host_matches(hostname, cname))
return 0;
return error("certificate owner '%s' does not match hostname '%s'",
ASN1_STRING_get0_data(cname), hostname);
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] imap-send: remove two string length checks
2026-03-11 12:11 ` [PATCH 3/4] imap-send: remove two string length checks Beat Bolli
@ 2026-03-11 13:41 ` Oswald Buddenhagen
2026-03-11 21:49 ` Beat Bolli
2026-03-11 18:55 ` Junio C Hamano
1 sibling, 1 reply; 14+ messages in thread
From: Oswald Buddenhagen @ 2026-03-11 13:41 UTC (permalink / raw)
To: Beat Bolli; +Cc: git
On Wed, Mar 11, 2026 at 01:11:06PM +0100, Beat Bolli wrote:
>At this point, these two checks verify that the ASN1_STRINGs are
>internally consistent. This may have been ok when the fields were
>accessed directly, but now that the API is used, is unnecessary.
>
that argumentation makes no sense.
the purpose of this check is to ensure that there are no embedded nulls,
which the matcher would be unable to deal with, which may be a security
hole.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] imap-send: remove two string length checks
2026-03-11 12:11 ` [PATCH 3/4] imap-send: remove two string length checks Beat Bolli
2026-03-11 13:41 ` Oswald Buddenhagen
@ 2026-03-11 18:55 ` Junio C Hamano
2026-03-11 22:00 ` Beat Bolli
1 sibling, 1 reply; 14+ messages in thread
From: Junio C Hamano @ 2026-03-11 18:55 UTC (permalink / raw)
To: Beat Bolli; +Cc: git, Oswald Buddenhagen
Beat Bolli <dev+git@drbeat.li> writes:
> At this point, these two checks verify that the ASN1_STRINGs are
> internally consistent. This may have been ok when the fields were
> accessed directly, but now that the API is used, is unnecessary.
>
> Remove the two checks.
Oswald already gave a similar comment, but
* I am not sure what you meant by "ok" in "may have been ok". Do
you mean "with raw access to the fields, it may have been made
send to ensure validity of ASN1_STRING"?
* I am also not sure what you meant by "now that the API is used".
Who in the code uses which API function so that we do not have to
do our sanity checking?
The call to host_matches() that these extra checks protect are
still passing raw "const char *" in this step, and the change to
pass ASN1_STRING does not happen until [4/4], so you did not mean
host_matches(). I am not sure what it is.
Thanks.
>
> Signed-off-by: Beat Bolli <dev+git@drbeat.li>
> ---
> imap-send.c | 5 +----
> 1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/imap-send.c b/imap-send.c
> index 2a904314dd..2bb0003f08 100644
> --- a/imap-send.c
> +++ b/imap-send.c
> @@ -253,8 +253,6 @@ static int verify_hostname(X509 *cert, const char *hostname)
> ASN1_STRING *subj_alt_str = GENERAL_NAME_get0_value(subj_alt_name, &ntype);
>
> if (ntype == GEN_DNS &&
> - strlen((const char *)ASN1_STRING_get0_data(subj_alt_str)) ==
> - ASN1_STRING_length(subj_alt_str) &&
> host_matches(hostname, (const char *)ASN1_STRING_get0_data(subj_alt_str)))
> found = 1;
> }
> @@ -270,8 +268,7 @@ static int verify_hostname(X509 *cert, const char *hostname)
> (cname_entry = X509_NAME_get_entry(subj, i)) == NULL ||
> (cname = X509_NAME_ENTRY_get_data(cname_entry)) == NULL)
> return error("cannot get certificate common name");
> - if (strlen((const char *)ASN1_STRING_get0_data(cname)) == ASN1_STRING_length(cname) &&
> - host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
> + if (host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
> return 0;
> return error("certificate owner '%s' does not match hostname '%s'",
> ASN1_STRING_get0_data(cname), hostname);
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] imap-send: remove two string length checks
2026-03-11 13:41 ` Oswald Buddenhagen
@ 2026-03-11 21:49 ` Beat Bolli
0 siblings, 0 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 21:49 UTC (permalink / raw)
To: Oswald Buddenhagen; +Cc: git
Hi Oswald
On 11.03.2026 14:41, Oswald Buddenhagen wrote:
> On Wed, Mar 11, 2026 at 01:11:06PM +0100, Beat Bolli wrote:
>> At this point, these two checks verify that the ASN1_STRINGs are
>> internally consistent. This may have been ok when the fields were
>> accessed directly, but now that the API is used, is unnecessary.
>>
> that argumentation makes no sense.
> the purpose of this check is to ensure that there are no embedded nulls,
> which the matcher would be unable to deal with, which may be a security
> hole.
Thanks for the clarification; this was the piece that I was missing.
I'll send a v2 shortly that removes this change.
Cheers, Beat
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] imap-send: remove two string length checks
2026-03-11 18:55 ` Junio C Hamano
@ 2026-03-11 22:00 ` Beat Bolli
0 siblings, 0 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 22:00 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Oswald Buddenhagen
Hi Junio
On 11.03.2026 19:55, Junio C Hamano wrote:
> Beat Bolli <dev+git@drbeat.li> writes:
>
>> At this point, these two checks verify that the ASN1_STRINGs are
>> internally consistent. This may have been ok when the fields were
>> accessed directly, but now that the API is used, is unnecessary.
>>
>> Remove the two checks.
>
> Oswald already gave a similar comment, but
>
> * I am not sure what you meant by "ok" in "may have been ok". Do
> you mean "with raw access to the fields, it may have been made
> send to ensure validity of ASN1_STRING"?
>
> * I am also not sure what you meant by "now that the API is used".
> Who in the code uses which API function so that we do not have to
> do our sanity checking?
>
> The call to host_matches() that these extra checks protect are
> still passing raw "const char *" in this step, and the change to
> pass ASN1_STRING does not happen until [4/4], so you did not mean
> host_matches(). I am not sure what it is.
>
> Thanks.
I didn't realize that the strlen() comparison was meant to check for
embedded NULs. I'll send v2 shortly that keeps this check.
Cheers, Beat
>> Signed-off-by: Beat Bolli <dev+git@drbeat.li>
>> ---
>> imap-send.c | 5 +----
>> 1 file changed, 1 insertion(+), 4 deletions(-)
>>
>> diff --git a/imap-send.c b/imap-send.c
>> index 2a904314dd..2bb0003f08 100644
>> --- a/imap-send.c
>> +++ b/imap-send.c
>> @@ -253,8 +253,6 @@ static int verify_hostname(X509 *cert, const char *hostname)
>> ASN1_STRING *subj_alt_str = GENERAL_NAME_get0_value(subj_alt_name, &ntype);
>>
>> if (ntype == GEN_DNS &&
>> - strlen((const char *)ASN1_STRING_get0_data(subj_alt_str)) ==
>> - ASN1_STRING_length(subj_alt_str) &&
>> host_matches(hostname, (const char *)ASN1_STRING_get0_data(subj_alt_str)))
>> found = 1;
>> }
>> @@ -270,8 +268,7 @@ static int verify_hostname(X509 *cert, const char *hostname)
>> (cname_entry = X509_NAME_get_entry(subj, i)) == NULL ||
>> (cname = X509_NAME_ENTRY_get_data(cname_entry)) == NULL)
>> return error("cannot get certificate common name");
>> - if (strlen((const char *)ASN1_STRING_get0_data(cname)) == ASN1_STRING_length(cname) &&
>> - host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
>> + if (host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
>> return 0;
>> return error("certificate owner '%s' does not match hostname '%s'",
>> ASN1_STRING_get0_data(cname), hostname);
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 0/3] imap-send: modernize the OpenSSL API
2026-03-11 12:11 [PATCH 0/4] imap-send: modernize the OpenSSL API Beat Bolli
` (3 preceding siblings ...)
2026-03-11 12:11 ` [PATCH 4/4] imap-send: refactor function host_matches() Beat Bolli
@ 2026-03-11 22:10 ` Beat Bolli
2026-03-12 0:25 ` Junio C Hamano
2026-03-11 22:10 ` [PATCH v2 1/3] imap-send: use the OpenSSL API to access the subject alternative names Beat Bolli
` (2 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 22:10 UTC (permalink / raw)
To: git; +Cc: Beat Bolli, Oswald Buddenhagen
OpenSSL recently released version 4.0.0-alpha1 [1]. Compiling with this
version revealed some erroneous and deprecated code.
This series aims to update this code to use the documented OpenSSL APIs.
All of the newly used APIs have existed since OpenSSL 1.1.0, the latest
version of which was released in September 2019 [2]. IMHO there is no
need to support even older OpenSSL versions.
Cc-ing Oswald as the original author of the affected code.
[1] https://github.com/openssl/openssl/tree/openssl-4.0.0-alpha1
[2] https://openssl-library.org/source/old/1.1.0/index.html
Beat Bolli (3):
imap-send: use the OpenSSL API to access the subject alternative names
imap-send: use the OpenSSL API to access the subject common name
imap-send: move common code into function host_matches()
imap-send.c | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
---
Changes vs v1:
- keep the check for embedded NUL characters
--
2.51.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 1/3] imap-send: use the OpenSSL API to access the subject alternative names
2026-03-11 12:11 [PATCH 0/4] imap-send: modernize the OpenSSL API Beat Bolli
` (4 preceding siblings ...)
2026-03-11 22:10 ` [PATCH v2 0/3] imap-send: modernize the OpenSSL API Beat Bolli
@ 2026-03-11 22:10 ` Beat Bolli
2026-03-11 22:10 ` [PATCH v2 2/3] imap-send: use the OpenSSL API to access the subject common name Beat Bolli
2026-03-11 22:10 ` [PATCH v2 3/3] imap-send: move common code into function host_matches() Beat Bolli
7 siblings, 0 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 22:10 UTC (permalink / raw)
To: git; +Cc: Beat Bolli, Oswald Buddenhagen
The OpenSSL 4.0 master branch has made the ASN1_STRING structure opaque,
forbidding access to its internal fields. Use the official accessor
functions instead. They have existed since OpenSSL v1.1.0.
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
imap-send.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 26dda7f328..1c934c2487 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -244,10 +244,14 @@ static int verify_hostname(X509 *cert, const char *hostname)
if ((subj_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL))) {
int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names);
for (i = 0; !found && i < num_subj_alt_names; i++) {
+ int ntype;
GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
- if (subj_alt_name->type == GEN_DNS &&
- strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length &&
- host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data)))
+ ASN1_STRING *subj_alt_str = GENERAL_NAME_get0_value(subj_alt_name, &ntype);
+
+ if (ntype == GEN_DNS &&
+ strlen((const char *)ASN1_STRING_get0_data(subj_alt_str)) ==
+ ASN1_STRING_length(subj_alt_str) &&
+ host_matches(hostname, (const char *)ASN1_STRING_get0_data(subj_alt_str)))
found = 1;
}
sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free);
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 2/3] imap-send: use the OpenSSL API to access the subject common name
2026-03-11 12:11 [PATCH 0/4] imap-send: modernize the OpenSSL API Beat Bolli
` (5 preceding siblings ...)
2026-03-11 22:10 ` [PATCH v2 1/3] imap-send: use the OpenSSL API to access the subject alternative names Beat Bolli
@ 2026-03-11 22:10 ` Beat Bolli
2026-03-11 22:10 ` [PATCH v2 3/3] imap-send: move common code into function host_matches() Beat Bolli
7 siblings, 0 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 22:10 UTC (permalink / raw)
To: git; +Cc: Beat Bolli, Oswald Buddenhagen
The OpenSSL 4.0 master branch has deprecated the
X509_NAME_get_text_by_NID function. Use the recommended replacement APIs
instead. They have existed since OpenSSL v1.1.0.
Take care to get the constness right for pre-4.0 versions.
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
imap-send.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 1c934c2487..2a904314dd 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -233,9 +233,13 @@ static int host_matches(const char *host, const char *pattern)
static int verify_hostname(X509 *cert, const char *hostname)
{
- int len;
+#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
+ const X509_NAME *subj;
+#else
X509_NAME *subj;
- char cname[1000];
+#endif
+ const X509_NAME_ENTRY *cname_entry;
+ const ASN1_STRING *cname;
int i, found;
STACK_OF(GENERAL_NAME) *subj_alt_names;
@@ -262,12 +266,15 @@ static int verify_hostname(X509 *cert, const char *hostname)
/* try the common name */
if (!(subj = X509_get_subject_name(cert)))
return error("cannot get certificate subject");
- if ((len = X509_NAME_get_text_by_NID(subj, NID_commonName, cname, sizeof(cname))) < 0)
+ if ((i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1)) < 0 ||
+ (cname_entry = X509_NAME_get_entry(subj, i)) == NULL ||
+ (cname = X509_NAME_ENTRY_get_data(cname_entry)) == NULL)
return error("cannot get certificate common name");
- if (strlen(cname) == (size_t)len && host_matches(hostname, cname))
+ if (strlen((const char *)ASN1_STRING_get0_data(cname)) == ASN1_STRING_length(cname) &&
+ host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
return 0;
return error("certificate owner '%s' does not match hostname '%s'",
- cname, hostname);
+ ASN1_STRING_get0_data(cname), hostname);
}
static int ssl_socket_connect(struct imap_socket *sock,
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 3/3] imap-send: move common code into function host_matches()
2026-03-11 12:11 [PATCH 0/4] imap-send: modernize the OpenSSL API Beat Bolli
` (6 preceding siblings ...)
2026-03-11 22:10 ` [PATCH v2 2/3] imap-send: use the OpenSSL API to access the subject common name Beat Bolli
@ 2026-03-11 22:10 ` Beat Bolli
7 siblings, 0 replies; 14+ messages in thread
From: Beat Bolli @ 2026-03-11 22:10 UTC (permalink / raw)
To: git; +Cc: Beat Bolli, Oswald Buddenhagen
Move the ASN1_STRING access, the associated cast and the check for
embedded NUL bytes into host_matches() to simplify both callers.
Reformulate the NUL check using memchr() and add a comment to make it
more obvious what it is about.
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
imap-send.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 2a904314dd..af02c6a689 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -219,8 +219,14 @@ static int ssl_socket_connect(struct imap_socket *sock UNUSED,
#else
-static int host_matches(const char *host, const char *pattern)
+static int host_matches(const char *host, const ASN1_STRING *asn1_str)
{
+ const char *pattern = (const char *)ASN1_STRING_get0_data(asn1_str);
+
+ /* embedded NUL characters may open a security hole */
+ if (memchr(pattern, '\0', ASN1_STRING_length(asn1_str)))
+ return 0;
+
if (pattern[0] == '*' && pattern[1] == '.') {
pattern += 2;
if (!(host = strchr(host, '.')))
@@ -252,10 +258,7 @@ static int verify_hostname(X509 *cert, const char *hostname)
GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
ASN1_STRING *subj_alt_str = GENERAL_NAME_get0_value(subj_alt_name, &ntype);
- if (ntype == GEN_DNS &&
- strlen((const char *)ASN1_STRING_get0_data(subj_alt_str)) ==
- ASN1_STRING_length(subj_alt_str) &&
- host_matches(hostname, (const char *)ASN1_STRING_get0_data(subj_alt_str)))
+ if (ntype == GEN_DNS && host_matches(hostname, subj_alt_str))
found = 1;
}
sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free);
@@ -270,8 +273,7 @@ static int verify_hostname(X509 *cert, const char *hostname)
(cname_entry = X509_NAME_get_entry(subj, i)) == NULL ||
(cname = X509_NAME_ENTRY_get_data(cname_entry)) == NULL)
return error("cannot get certificate common name");
- if (strlen((const char *)ASN1_STRING_get0_data(cname)) == ASN1_STRING_length(cname) &&
- host_matches(hostname, (const char *)ASN1_STRING_get0_data(cname)))
+ if (host_matches(hostname, cname))
return 0;
return error("certificate owner '%s' does not match hostname '%s'",
ASN1_STRING_get0_data(cname), hostname);
--
2.51.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 0/3] imap-send: modernize the OpenSSL API
2026-03-11 22:10 ` [PATCH v2 0/3] imap-send: modernize the OpenSSL API Beat Bolli
@ 2026-03-12 0:25 ` Junio C Hamano
0 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2026-03-12 0:25 UTC (permalink / raw)
To: Beat Bolli; +Cc: git, Oswald Buddenhagen
Beat Bolli <dev+git@drbeat.li> writes:
> Changes vs v1:
> - keep the check for embedded NUL characters
... which amounts to this difference, which is a lot more explicit
way to express what is going on. I like it.
Thanks.
diff --git a/imap-send.c b/imap-send.c
index 789055d7fd..af02c6a689 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -222,6 +222,11 @@ static int ssl_socket_connect(struct imap_socket *sock UNUSED,
static int host_matches(const char *host, const ASN1_STRING *asn1_str)
{
const char *pattern = (const char *)ASN1_STRING_get0_data(asn1_str);
+
+ /* embedded NUL characters may open a security hole */
+ if (memchr(pattern, '\0', ASN1_STRING_length(asn1_str)))
+ return 0;
+
if (pattern[0] == '*' && pattern[1] == '.') {
pattern += 2;
if (!(host = strchr(host, '.')))
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-03-12 0:25 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-11 12:11 [PATCH 0/4] imap-send: modernize the OpenSSL API Beat Bolli
2026-03-11 12:11 ` [PATCH 1/4] imap-send: use the OpenSSL API to access the subject alternative names Beat Bolli
2026-03-11 12:11 ` [PATCH 2/4] imap-send: use the OpenSSL API to access the subject common name Beat Bolli
2026-03-11 12:11 ` [PATCH 3/4] imap-send: remove two string length checks Beat Bolli
2026-03-11 13:41 ` Oswald Buddenhagen
2026-03-11 21:49 ` Beat Bolli
2026-03-11 18:55 ` Junio C Hamano
2026-03-11 22:00 ` Beat Bolli
2026-03-11 12:11 ` [PATCH 4/4] imap-send: refactor function host_matches() Beat Bolli
2026-03-11 22:10 ` [PATCH v2 0/3] imap-send: modernize the OpenSSL API Beat Bolli
2026-03-12 0:25 ` Junio C Hamano
2026-03-11 22:10 ` [PATCH v2 1/3] imap-send: use the OpenSSL API to access the subject alternative names Beat Bolli
2026-03-11 22:10 ` [PATCH v2 2/3] imap-send: use the OpenSSL API to access the subject common name Beat Bolli
2026-03-11 22:10 ` [PATCH v2 3/3] imap-send: move common code into function host_matches() Beat Bolli
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox