Commit Diff


commit - 280fd79b8f5d42097d2a1a315338559261cb1e74
commit + ba94a608a89110740cb24ef098c476c84d371918
blob - 92f6985ae691b1d31f5aeb3421516ef2e02af9d9
blob + 9e8415dc232bc054d956e379bc1b53808ba25c9d
--- gmid.h
+++ gmid.h
@@ -112,6 +112,7 @@ struct proxy {
 	size_t		 certlen;
 	uint8_t		*key;
 	size_t		 keylen;
+	X509_STORE	*reqca;
 
 	TAILQ_ENTRY(proxy) proxies;
 };
blob - 43a7b15c80d3c94252642ca2f81c727b4f53f720
blob + 57cf3f5c72c7f07008879881d2a19bf18cb0cbb0
--- parse.y
+++ parse.y
@@ -351,6 +351,13 @@ proxy_opt	: CERT string {
 			free(proxy->host);
 			parsehp($2, &proxy->host, &proxy->port, "1965");
 		}
+		| REQUIRE CLIENT CA string {
+			only_once(proxy->reqca, "require client ca");
+			ensure_absolute_path($4);
+			if ((proxy->reqca = load_ca($4)) == NULL)
+				yyerror("couldn't load ca cert: %s", $4);
+			free($4);
+		}
 		| USE_TLS bool {
 			proxy->notls = !$2;
 		}
blob - 991e126f99721dd111e9225158cbba52b7557d6a
blob + 2faf79278168b55fb373c3e5b5cce7f9b8c0e898
--- server.c
+++ server.c
@@ -628,6 +628,26 @@ matched_proxy(struct client *c)
 	}
 
 	return NULL;
+}
+
+static int
+check_matching_certificate(X509_STORE *store, struct client *c)
+{
+	const uint8_t	*cert;
+	size_t		 len;
+
+	if (!tls_peer_cert_provided(c->ctx)) {
+		start_reply(c, CLIENT_CERT_REQ, "client certificate required");
+		return 1;
+	}
+
+	cert = tls_peer_cert_chain_pem(c->ctx, &len);
+	if (!validate_against_ca(store, cert, len)) {
+		start_reply(c, CERT_NOT_AUTH, "certificate not authorised");
+		return 1;
+	}
+
+	return 0;
 }
 
 /* 1 if matching a proxy relay-to (and apply it), 0 otherwise */
@@ -642,6 +662,9 @@ apply_reverse_proxy(struct client *c)
 
 	c->proxy = p;
 
+	if (p->reqca != NULL && check_matching_certificate(p->reqca, c))
+		return 1;
+
 	log_debug(c, "opening proxy connection for %s:%s",
 	    p->host, p->port);
 
@@ -680,24 +703,10 @@ static int
 apply_require_ca(struct client *c)
 {
 	X509_STORE	*store;
-	const uint8_t	*cert;
-	size_t		 len;
 
 	if ((store = vhost_require_ca(c->host, c->iri.path)) == NULL)
 		return 0;
-
-	if (!tls_peer_cert_provided(c->ctx)) {
-		start_reply(c, CLIENT_CERT_REQ, "client certificate required");
-		return 1;
-	}
-
-	cert = tls_peer_cert_chain_pem(c->ctx, &len);
-	if (!validate_against_ca(store, cert, len)) {
-		start_reply(c, CERT_NOT_AUTH, "certificate not authorised");
-		return 1;
-	}
-
-	return 0;
+	return check_matching_certificate(store, c);
 }
 
 static size_t