* [PATCH] imap-send: use ASN1_STRING_length @ 2026-10-11 21:09 Xiangfei Ding 2026-10-11 23:05 ` Junio C Hamano 2026-10-12 15:17 ` Aniket Gupta 0 siblings, 2 replies; 5+ messages in thread From: Xiangfei Ding @ 2026-10-11 21:09 UTC (permalink / raw) To: git; +Cc: gitster, dev+git, davidben, xfding, Xiangfei Ding From: xfding <xfding@google.com> X.509 has never stipulated that ASN1_STRING shall be null-terminated in general. In OpenSSL, `ASN1_STRING_get0_data()` returns an internal pointer to the raw string payload, which is lucky for us null-terminated. This is probably about to change as OpenSSL derivatives like BoringSSL would adopt changes so that the data buffer would not be null-terminated anymore. Strictly speaking, printing or accessing `ASN1_STRING` data should always query `ASN1_STRING_length`. This means that we should adapt `host_matches` and `verify_hostname` to use `strncasecmp` and print strings with designated length. Signed-off-by: Xiangfei Ding <dingxiangfei2009@protonmail.ch> Signed-off-by: Xiangfei Ding <xfding@google.com> --- imap-send.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/imap-send.c b/imap-send.c index bf1d2cf74d..bd306b8d0a 100644 --- a/imap-send.c +++ b/imap-send.c @@ -225,19 +225,21 @@ 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); + int pat_len = ASN1_STRING_length(asn1_str); /* embedded NUL characters may open a security hole */ - if (memchr(pattern, '\0', ASN1_STRING_length(asn1_str))) - return 0; + if (memchr(pattern, '\0', pat_len)) + return 0; - if (pattern[0] == '*' && pattern[1] == '.') { + if (pat_len >= 2 && pattern[0] == '*' && pattern[1] == '.') { pattern += 2; + pat_len -= 2; if (!(host = strchr(host, '.'))) return 0; host++; } - return *host && *pattern && !strcasecmp(host, pattern); + return *host && strlen(host) == (size_t)pat_len && !strncasecmp(host, pattern, pat_len); } static int verify_hostname(X509 *cert, const char *hostname) @@ -278,8 +280,9 @@ static int verify_hostname(X509 *cert, const char *hostname) return error("cannot get certificate common name"); if (host_matches(hostname, cname)) return 0; - return error("certificate owner '%s' does not match hostname '%s'", - ASN1_STRING_get0_data(cname), hostname); + return error("certificate owner '%.*s' does not match hostname '%s'", + (int)ASN1_STRING_length(cname), + (const char *)ASN1_STRING_get0_data(cname), hostname); } static int ssl_socket_connect(struct imap_socket *sock, -- 2.56.0.385.gd3acb90ef8-goog ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] imap-send: use ASN1_STRING_length 2026-10-11 21:09 [PATCH] imap-send: use ASN1_STRING_length Xiangfei Ding @ 2026-10-11 23:05 ` Junio C Hamano 2026-10-12 15:17 ` Aniket Gupta 1 sibling, 0 replies; 5+ messages in thread From: Junio C Hamano @ 2026-10-11 23:05 UTC (permalink / raw) To: Xiangfei Ding; +Cc: git, dev+git, davidben, Xiangfei Ding Xiangfei Ding <xfding@google.com> writes: > From: xfding <xfding@google.com> This line is called in-body From: that is used to override the "From:" header your MUA will add. But in this case, I think you do not want to override "Xiangfei Ding <xfding@google.com>", which is what your MUA sent the message as. In any case, either MUA From or in-body From is used as the author identity when this patch e-mail is committed, so it should match your sign-off we see later. > X.509 has never stipulated that ASN1_STRING shall be null-terminated in general. > In OpenSSL, `ASN1_STRING_get0_data()` returns an internal pointer to > the raw string payload, which is lucky for us null-terminated. OK. > This is probably > about to change as OpenSSL derivatives like BoringSSL would adopt changes so > that the data buffer would not be null-terminated anymore. It is unclear from reading the above if you mean only derivatives will adopt changes not to NUL-terminate, or OpenSSL will change ASN1_STRING_get0_data() to return a string that is not NUL-terminated, and derivatives will follow suit. > Strictly speaking, printing or accessing `ASN1_STRING` data should always query > `ASN1_STRING_length`. This means that we should adapt `host_matches` and > `verify_hostname` to use `strncasecmp` and print strings with designated length. Makes sense. I take that the second paragraph to mean "not using ASN1_STRING_length happened to be OK, but that is not true anymore with various implementations of OpenSSL like libraries", illustrating the need and urgency to make this change? In our log message, usually all of the above (i.e., observation of the current situation and pointing out problems in the status quo) are followed by what to do to solve the problem by giving an order to hypothetical somebody to update the code to "make it so", e.g., Update code that assumes ASN1_STRING data are NUL-terminated to use ASN1_STRING_length and treat the data as <pointer, length> pair. but the above description you gave is sufficiently detailed and left no need to make a separate description of the solution. > Signed-off-by: Xiangfei Ding <dingxiangfei2009@protonmail.ch> > Signed-off-by: Xiangfei Ding <xfding@google.com> What are these two separate sign-off lines doing? Unless rules have changed recently, I think Google OSPO tells you as a Google engineer [*] to use your @google.com address when making contributions to open source projects, "unless you have a history of contributing to the repo under a different email before your employment at Google". So only the second one would be what you want to use, I presume? Again, as I mentioned earlier, it matches the address your MUA sent the message as, so you do not need/want the in-body From: line. [Reference] * https://opensource.google/documentation/reference/patching > diff --git a/imap-send.c b/imap-send.c > index bf1d2cf74d..bd306b8d0a 100644 > --- a/imap-send.c > +++ b/imap-send.c > @@ -225,19 +225,21 @@ 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); > + int pat_len = ASN1_STRING_length(asn1_str); > > /* embedded NUL characters may open a security hole */ > - if (memchr(pattern, '\0', ASN1_STRING_length(asn1_str))) > - return 0; > + if (memchr(pattern, '\0', pat_len)) > + return 0; OK, the above is essentially a no-op. But we have the length in a variable so we can reuse it in the rest of the function, which is good. > - if (pattern[0] == '*' && pattern[1] == '.') { > + if (pat_len >= 2 && pattern[0] == '*' && pattern[1] == '.') { > pattern += 2; > + pat_len -= 2; > if (!(host = strchr(host, '.'))) > return 0; > host++; > } OK, we check for "*." only when we have at least two bytes, and consume these two bytes if they match. > - return *host && *pattern && !strcasecmp(host, pattern); > + return *host && strlen(host) == (size_t)pat_len && !strncasecmp(host, pattern, pat_len); LIne-wrap this overly long line. return *host && strlen(host) == (size_t)pat_len && !strncasecmp(host, pattern, pat_len); Curious. If we declare pat_len to be of type size_t, we would no longer need to cast it here. Even though we passed pat_len to memchr() earlier, that call implicitly promoted int to size_t, which would also become unnecessary. > } > > static int verify_hostname(X509 *cert, const char *hostname) > @@ -278,8 +280,9 @@ static int verify_hostname(X509 *cert, const char *hostname) > return error("cannot get certificate common name"); > if (host_matches(hostname, cname)) > return 0; > - return error("certificate owner '%s' does not match hostname '%s'", > - ASN1_STRING_get0_data(cname), hostname); > + return error("certificate owner '%.*s' does not match hostname '%s'", > + (int)ASN1_STRING_length(cname), Because ASN1_STRING_length() is declared to return "int", this cast is not strictly needed, but it is good to be explicit in a case like this, I think. > + (const char *)ASN1_STRING_get0_data(cname), hostname); Great. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] imap-send: use ASN1_STRING_length 2026-10-11 21:09 [PATCH] imap-send: use ASN1_STRING_length Xiangfei Ding 2026-10-11 23:05 ` Junio C Hamano @ 2026-10-12 15:17 ` Aniket Gupta 2026-10-12 17:18 ` Junio C Hamano 1 sibling, 1 reply; 5+ messages in thread From: Aniket Gupta @ 2026-10-12 15:17 UTC (permalink / raw) To: Xiangfei Ding; +Cc: git, gitster, dev+git, davidben, dingxiangfei2009 Hello Xiangfei, > + int pat_len = ASN1_STRING_length(asn1_str); It seems that with OpenSSL 4.1.0-beta2 this is deprecated (ASN1_STRING_get_length() is the replacement), so it warns, and fails with DEVELOPER=1. The patch adds a second use at the error message. Beat Bolli has a series from 7 Sept ("imap-send: future proofing and two correctness fixes") that also touches host_matches(), maybe we can check how the two can fit together? Thanks, Aniket ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] imap-send: use ASN1_STRING_length 2026-10-12 15:17 ` Aniket Gupta @ 2026-10-12 17:18 ` Junio C Hamano 2026-10-12 20:09 ` Beat Bolli 0 siblings, 1 reply; 5+ messages in thread From: Junio C Hamano @ 2026-10-12 17:18 UTC (permalink / raw) To: Aniket Gupta Cc: Xiangfei Ding, brian m. carlson, git, dev+git, davidben, dingxiangfei2009 Aniket Gupta <aniketgupta3001@gmail.com> writes: > Hello Xiangfei, > >> + int pat_len = ASN1_STRING_length(asn1_str); > > It seems that with OpenSSL 4.1.0-beta2 this is deprecated > (ASN1_STRING_get_length() is the replacement), so it warns, and > fails with DEVELOPER=1. The patch adds a second use at the error > message. Beat Bolli has a series from 7 Sept ("imap-send: future > proofing and two correctness fixes") that also touches > host_matches(), maybe we can check how the two can fit together? > > Thanks, > Aniket [jch: rewrapped long unreadable lines] That topic also needs rework, unfortunately. https://lore.kernel.org/git/20260907211210.2621693-1-dev+git@drbeat.li/ I guess we can salvage the patches 1 and 2 with fairly trivial changes, namely with the style fix in [1/3], and pointer arithmetic that breaks later free() fix in [2/3]. I am not sure how involved it would be to fix [3/3] in such a way suggested by brian in the thread. Thanks for reminding us of the old thread. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] imap-send: use ASN1_STRING_length 2026-10-12 17:18 ` Junio C Hamano @ 2026-10-12 20:09 ` Beat Bolli 0 siblings, 0 replies; 5+ messages in thread From: Beat Bolli @ 2026-10-12 20:09 UTC (permalink / raw) To: Junio C Hamano, Aniket Gupta Cc: Xiangfei Ding, brian m. carlson, git, davidben, dingxiangfei2009 On 12.10.2026 19:18, Junio C Hamano wrote: > Aniket Gupta <aniketgupta3001@gmail.com> writes: > >> Hello Xiangfei, >> >>> + int pat_len = ASN1_STRING_length(asn1_str); >> >> It seems that with OpenSSL 4.1.0-beta2 this is deprecated >> (ASN1_STRING_get_length() is the replacement), so it warns, and >> fails with DEVELOPER=1. The patch adds a second use at the error >> message. Beat Bolli has a series from 7 Sept ("imap-send: future >> proofing and two correctness fixes") that also touches >> host_matches(), maybe we can check how the two can fit together? >> >> Thanks, >> Aniket > > [jch: rewrapped long unreadable lines] > > That topic also needs rework, unfortunately. > > https://lore.kernel.org/git/20260907211210.2621693-1-dev+git@drbeat.li/ > > I guess we can salvage the patches 1 and 2 with fairly trivial > changes, namely with the style fix in [1/3], and pointer arithmetic > that breaks later free() fix in [2/3]. I am not sure how involved > it would be to fix [3/3] in such a way suggested by brian in the > thread. > > Thanks for reminding us of the old thread. > I'm working on a new branch that uses OpenSSL's built-in hostname verification. All this low level ASN.1 code will disappear as a result. Best regards, Beat ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-12 20:13 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-11 21:09 [PATCH] imap-send: use ASN1_STRING_length Xiangfei Ding 2026-10-11 23:05 ` Junio C Hamano 2026-10-12 15:17 ` Aniket Gupta 2026-10-12 17:18 ` Junio C Hamano 2026-10-12 20:09 ` Beat Bolli
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox