From 368352dfa4f7a81125b12f29461e66ee740a1575 Mon Sep 17 00:00:00 2001
From: Damien Diederen
Date: Wed, 17 May 2023 11:11:40 +0200
Subject: [PATCH] http-binary-cache-store: Add 'ssl-cert' and 'ssl-key'
settings
Those are set via the store's URI, e.g.:
https://substituter.invalid?ssl-cert=/path/to/cert.pem&ssl-key=/path/to/key.pem
---
doc/manual/rl-next/mtls-substituter.md | 13 ++++++++++++
src/libstore/filetransfer.cc | 6 ++++++
src/libstore/http-binary-cache-store.cc | 21 +++++++++++++++++--
.../include/nix/store/filetransfer.hh | 2 ++
.../nix/store/http-binary-cache-store.hh | 6 ++++++
5 files changed, 46 insertions(+), 2 deletions(-)
create mode 100644 doc/manual/rl-next/mtls-substituter.md
diff --git a/doc/manual/rl-next/mtls-substituter.md b/doc/manual/rl-next/mtls-substituter.md
new file mode 100644
index 000000000..21f5401e4
--- /dev/null
+++ b/doc/manual/rl-next/mtls-substituter.md
@@ -0,0 +1,13 @@
+---
+synopsis: Support substituters using mTLS (client certificate) authentication
+issues: []
+prs: [13030]
+---
+
+Added support for `ssl-cert` and `ssl-key` options in substituter URLs.
+
+Example:
+
+ https://substituter.invalid?ssl-cert=/path/to/cert.pem&ssl-key=/path/to/key.pem
+
+When these options are configured, Nix will use this certificate/private key pair to authenticate to the server.
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index 8080fcfdd..ed1f4cbb5 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -410,6 +410,12 @@ struct curlFileTransfer : public FileTransfer
if (writtenToSink)
curl_easy_setopt(req, CURLOPT_RESUME_FROM_LARGE, writtenToSink);
+ if (!request.sslCert.empty())
+ curl_easy_setopt(req, CURLOPT_SSLCERT, request.sslCert.c_str());
+
+ if (!request.sslKey.empty())
+ curl_easy_setopt(req, CURLOPT_SSLKEY, request.sslKey.c_str());
+
curl_easy_setopt(req, CURLOPT_ERRORBUFFER, errbuf);
errbuf[0] = 0;
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 2b591dda9..43519cd00 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -152,11 +152,28 @@ protected:
FileTransferRequest makeRequest(const std::string & path)
{
- return FileTransferRequest(
- hasPrefix(path, "https://") || hasPrefix(path, "http://") || hasPrefix(path, "file://")
+ bool absolute = hasPrefix(path, "https://") || hasPrefix(path, "http://") || hasPrefix(path, "file://");
+
+ FileTransferRequest request(
+ absolute
? path
: config->cacheUri + "/" + path);
+ if (!absolute) {
+ Path sslCert = config->sslCert.get();
+ if (!sslCert.empty()) {
+ debug("configuring SSL client certificate '%s' for '%s'", sslCert, request.uri);
+ request.sslCert = sslCert;
+ }
+
+ Path sslKey = config->sslKey.get();
+ if (!sslKey.empty()) {
+ debug("configuring SSL client certificate key '%s' for '%s'", sslKey, request.uri);
+ request.sslKey = sslKey;
+ }
+ }
+
+ return request;
}
void getFile(const std::string & path, Sink & sink) override
diff --git a/src/libstore/include/nix/store/filetransfer.hh b/src/libstore/include/nix/store/filetransfer.hh
index 10c3ec7ef..1567e055f 100644
--- a/src/libstore/include/nix/store/filetransfer.hh
+++ b/src/libstore/include/nix/store/filetransfer.hh
@@ -65,6 +65,8 @@ struct FileTransferRequest
std::string uri;
Headers headers;
std::string expectedETag;
+ Path sslCert;
+ Path sslKey;
bool verifyTLS = true;
bool head = false;
bool post = false;
diff --git a/src/libstore/include/nix/store/http-binary-cache-store.hh b/src/libstore/include/nix/store/http-binary-cache-store.hh
index 66ec5f8d2..fe2bde144 100644
--- a/src/libstore/include/nix/store/http-binary-cache-store.hh
+++ b/src/libstore/include/nix/store/http-binary-cache-store.hh
@@ -13,6 +13,12 @@ struct HttpBinaryCacheStoreConfig : std::enable_shared_from_this sslCert{
+ this, "", "ssl-cert", "An optional SSL client certificate in PEM format; see CURLOPT_SSLCERT."};
+
+ const Setting sslKey{
+ this, "", "ssl-key", "The SSL client certificate key in PEM format; see CURLOPT_SSLKEY."};
+
static const std::string name()
{
return "HTTP Binary Cache Store";