]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: Support check_client_fp, check_client_cert_fp, check_client_pubkey_fp fields
authorAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 14:04:39 +0000 (16:04 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Mon, 26 May 2025 05:39:13 +0000 (05:39 +0000)
When set, these are matched against provided fingerprints, and
must be present in the request.

Field check_client_fp matches either certificate or public key fingerprint.

src/auth/auth-request.c

index 981c139ee5601ad27cbbff51cbd0ba040263fab6..dab547f5e89cfd6fd9e698d58fd9d2eee136f494 100644 (file)
@@ -1831,6 +1831,47 @@ auth_request_validate_networks(struct auth_request *request,
                request->failed = TRUE;
 }
 
+static void
+auth_request_validate_client_fp(struct auth_request *request, const char *name,
+                               const char *fp)
+{
+       const char *client_cert_fp = request->fields.ssl_client_cert_fp;
+       const char *client_pubkey_fp = request->fields.ssl_client_cert_pubkey_fp;
+       bool valid;
+
+       /* Can't be valid if the connection is not TLS secured, proxied does not
+          count. */
+       if (request->fields.conn_secured != AUTH_REQUEST_CONN_SECURED_TLS)
+               valid = FALSE;
+       /* check that the fingerprint isn't empty */
+       else if (*fp == '\0') {
+               e_info(authdb_event(request), "%s check failed: value was empty",
+                      name);
+               valid = FALSE;
+               return;
+       } else if (strcmp(name, "check_client_fp") == 0) {
+               valid = strcmp(client_cert_fp, fp) == 0 ||
+                       strcmp(client_pubkey_fp, fp) == 0;
+       } else if (strcmp(name, "check_client_cert_fp") == 0)
+               valid = strcmp(client_cert_fp, fp) == 0;
+       else if (strcmp(name, "check_client_pubkey_fp") == 0)
+               valid = strcmp(client_pubkey_fp, fp) == 0;
+       else
+               i_unreached();
+
+       if (!valid) {
+               e_info(authdb_event(request),
+                      "%s check failed: %s does not match client certificate",
+                      name, fp);
+               request->failed = TRUE;
+       } else {
+               e_debug(authdb_event(request),
+                       "%s check success: %s matches client certificate",
+                       name, fp);
+               auth_request_import(request, "valid-client-cert", "yes");
+       }
+}
+
 static void
 auth_request_set_password(struct auth_request *request, const char *value,
                          const char *default_scheme, bool noscheme)
@@ -1971,6 +2012,10 @@ void auth_request_set_field(struct auth_request *request,
        } else if (strcmp(name, "allow_nets") == 0) {
                auth_request_validate_networks(request, name, value,
                                               &request->fields.remote_ip);
+       } else if (strcmp(name, "check_client_fp") == 0 ||
+                  strcmp(name, "check_client_cert_fp") == 0 ||
+                  strcmp(name, "check_client_pubkey_fp") == 0) {
+               auth_request_validate_client_fp(request, name, value);
        } else if (strcmp(name, "fail") == 0) {
                request->failed = TRUE;
        } else if (strcmp(name, "nodelay") == 0) {