diff --git a/docs/cmdline-opts/write-out.md b/docs/cmdline-opts/write-out.md
index bae185b1b9..f1cca60ad2 100644
--- a/docs/cmdline-opts/write-out.md
+++ b/docs/cmdline-opts/write-out.md
@@ -62,7 +62,7 @@ The variables available are:
## `certs`
Output the certificate chain with details. Supported only by the OpenSSL,
-GnuTLS, Schannel and Secure Transport backends. (Added in 7.88.0)
+GnuTLS, Schannel, Rustls, and Secure Transport backends. (Added in 7.88.0)
## `conn_id`
The connection identifier last used by the transfer. The connection id is
@@ -128,7 +128,7 @@ The http method used in the most recent HTTP request. (Added in 7.72.0)
## `num_certs`
Number of server certificates received in the TLS handshake. Supported only by
-the OpenSSL, GnuTLS, Schannel and Secure Transport backends.
+the OpenSSL, GnuTLS, Schannel, Rustls and Secure Transport backends.
(Added in 7.88.0)
## `num_connects`
diff --git a/docs/libcurl/opts/CURLINFO_CERTINFO.md b/docs/libcurl/opts/CURLINFO_CERTINFO.md
index 39f403ec7e..0bf6ab0dc1 100644
--- a/docs/libcurl/opts/CURLINFO_CERTINFO.md
+++ b/docs/libcurl/opts/CURLINFO_CERTINFO.md
@@ -15,6 +15,7 @@ TLS-backend:
- GnuTLS
- Schannel
- Secure Transport
+ - rustls
Added-in: 7.19.1
---
diff --git a/docs/libcurl/opts/CURLOPT_CERTINFO.md b/docs/libcurl/opts/CURLOPT_CERTINFO.md
index 2ac7f89966..755367b3c8 100644
--- a/docs/libcurl/opts/CURLOPT_CERTINFO.md
+++ b/docs/libcurl/opts/CURLOPT_CERTINFO.md
@@ -17,6 +17,7 @@ TLS-backend:
- GnuTLS
- Schannel
- Secure Transport
+ - rustls
Added-in: 7.19.1
---
diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c
index 450a0bb9c6..529d6b9c1c 100644
--- a/lib/vtls/rustls.c
+++ b/lib/vtls/rustls.c
@@ -43,6 +43,7 @@
#include "connect.h" /* for the connect timeout */
#include "cipher_suite.h"
#include "rand.h"
+#include "x509asn1.h"
struct rustls_ssl_backend_data
{
@@ -845,6 +846,43 @@ cr_connect(struct Curl_cfilter *cf,
infof(data, "rustls: handshake complete, %s, cipher: %s",
ver, buf);
}
+ if(data->set.ssl.certinfo) {
+ size_t num_certs = 0;
+ while(rustls_connection_get_peer_certificate(rconn, (int)num_certs)) {
+ num_certs++;
+ }
+ result = Curl_ssl_init_certinfo(data, (int)num_certs);
+ if(result)
+ return result;
+ for(size_t i = 0; i < num_certs; i++) {
+ const rustls_certificate *cert;
+ const unsigned char *der_data;
+ size_t der_len;
+ rustls_result rresult = RUSTLS_RESULT_OK;
+ cert = rustls_connection_get_peer_certificate(rconn, i);
+ DEBUGASSERT(cert); /* Should exist since we counted already */
+ rresult = rustls_certificate_get_der(cert, &der_data, &der_len);
+ if(rresult != RUSTLS_RESULT_OK) {
+ char errorbuf[255];
+ size_t errorlen;
+ rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
+ failf(data,
+ "Failed getting DER of server certificate #%ld: %.*s", i,
+ (int)errorlen, errorbuf);
+ return map_error(rresult);
+ }
+ {
+ const char *beg;
+ const char *end;
+ beg = (const char *)der_data;
+ end = (const char *)(der_data + der_len);
+ result = Curl_extract_certinfo(data, (int)i, beg, end);
+ if(result)
+ return result;
+ }
+ }
+ }
+
connssl->state = ssl_connection_complete;
*done = TRUE;
return CURLE_OK;
@@ -1011,7 +1049,8 @@ const struct Curl_ssl Curl_ssl_rustls = {
SSLSUPP_CAINFO_BLOB | /* supports */
SSLSUPP_HTTPS_PROXY |
SSLSUPP_CIPHER_LIST |
- SSLSUPP_TLS13_CIPHERSUITES,
+ SSLSUPP_TLS13_CIPHERSUITES |
+ SSLSUPP_CERTINFO,
sizeof(struct rustls_ssl_backend_data),
NULL, /* init */
diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c
index d10dd09578..62f2a3cf41 100644
--- a/lib/vtls/x509asn1.c
+++ b/lib/vtls/x509asn1.c
@@ -26,15 +26,15 @@
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+ defined(USE_MBEDTLS) || defined(USE_RUSTLS)
#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS) || defined(USE_WOLFSSL)
+ defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_RUSTLS)
#define WANT_PARSEX509 /* uses Curl_parseX509() */
#endif
#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+ defined(USE_MBEDTLS) || defined(USE_RUSTLS)
#define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
#endif
@@ -1277,4 +1277,5 @@ done:
#endif /* WANT_EXTRACT_CERTINFO */
-#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP
+ or USE_MBEDTLS or USE_RUSTLS */
diff --git a/lib/vtls/x509asn1.h b/lib/vtls/x509asn1.h
index 5de8f18e9c..e1abff06c8 100644
--- a/lib/vtls/x509asn1.h
+++ b/lib/vtls/x509asn1.h
@@ -29,7 +29,7 @@
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+ defined(USE_MBEDTLS) || defined(USE_RUSTLS)
#include "cfilters.h"
#include "urldata.h"
@@ -80,7 +80,7 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data,
#ifdef UNITTESTS
#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+ defined(USE_MBEDTLS) || defined(USE_RUSTLS)
/* used by unit1656.c */
CURLcode Curl_x509_GTime2str(struct dynbuf *store,
@@ -91,5 +91,6 @@ CURLcode Curl_x509_getASN1Element(struct Curl_asn1Element *elem,
#endif
#endif
-#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP
+ or USE_MBEDTLS or USE_RUSTLS */
#endif /* HEADER_CURL_X509ASN1_H */
diff --git a/tests/data/test3102 b/tests/data/test3102
index 7635e65432..013d0c73ef 100644
--- a/tests/data/test3102
+++ b/tests/data/test3102
@@ -20,7 +20,6 @@ HTTP GET
SSL
!bearssl
-!rustls
!wolfssl
diff --git a/tests/data/test417 b/tests/data/test417
index 50f4b479b4..6c5dfe5bfe 100644
--- a/tests/data/test417
+++ b/tests/data/test417
@@ -25,7 +25,6 @@ SSL
!wolfssl
!bearssl
!mbedtls
-!rustls
http