[PATCH] rpcd: implement certificate authentication

Luka Logar luka.logar at cifra.si
Fri Feb 19 15:01:51 EST 2021


When the TLS client certificate is used for LuCI authentication, ubus session login is called with

  username = subject name
  password = certificate hash
  mode = 'cert'

Extra parameter 'mode' is needed to differentiate a regular username/password login attempt from the client
certificate auth. Otherwise one could fake the certificate login using the standard username/password
method entering subject name as username and cert hash as password, both of which are public/known/not-secret.
Session login is successful if the password/certificate hash matches the one stored in the /etc/config/rpcd
file.

Signed-off-by: Luka Logar <luka.logar at cifra.si>
---
 session.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/session.c b/session.c
index 908e298..b577475 100644
--- a/session.c
+++ b/session.c
@@ -120,12 +120,14 @@ enum {
 	RPC_L_USERNAME,
 	RPC_L_PASSWORD,
 	RPC_L_TIMEOUT,
+	RPC_L_MODE,
 	__RPC_L_MAX,
 };
 static const struct blobmsg_policy login_policy[__RPC_L_MAX] = {
 	[RPC_L_USERNAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING },
 	[RPC_L_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING },
 	[RPC_L_TIMEOUT]  = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
+	[RPC_L_MODE]     = { .name = "mode", .type = BLOBMSG_TYPE_STRING },
 };
 
 /*
@@ -827,7 +829,7 @@ rpc_login_test_password(const char *hash, const char *password)
 
 static struct uci_section *
 rpc_login_test_login(struct uci_context *uci,
-                     const char *username, const char *password)
+                     const char *username, const char *password, const char *mode)
 {
 	struct uci_package *p = NULL;
 	struct uci_section *s;
@@ -877,6 +879,13 @@ rpc_login_test_login(struct uci_context *uci,
 		if (ptr.o->type != UCI_TYPE_STRING)
 			continue;
 
+		if (mode && !strcmp(mode, "cert"))
+		{
+			if (!strcasecmp(ptr.o->v.string, password))
+				return ptr.s;
+			continue;
+		}
+
 		if (rpc_login_test_password(ptr.o->v.string, password))
 			return ptr.s;
 	}
@@ -1137,7 +1146,8 @@ rpc_handle_login(struct ubus_context *ctx, struct ubus_object *obj,
 	}
 
 	login = rpc_login_test_login(uci, blobmsg_get_string(tb[RPC_L_USERNAME]),
-	                                  blobmsg_get_string(tb[RPC_L_PASSWORD]));
+	                                  blobmsg_get_string(tb[RPC_L_PASSWORD]),
+	                                  blobmsg_get_string(tb[RPC_L_MODE]));
 
 	if (!login) {
 		rv = UBUS_STATUS_PERMISSION_DENIED;
@@ -1296,7 +1306,7 @@ rpc_session_from_blob(struct uci_context *uci, struct blob_attr *attr)
 	}
 
 	if (uci && user) {
-		login = rpc_login_test_login(uci, user, NULL);
+		login = rpc_login_test_login(uci, user, NULL, NULL);
 		if (login)
 			rpc_login_setup_acls(ses, login);
 	}
-- 
2.25.1





More information about the openwrt-devel mailing list