From 37f972d0750a7e739e58bb352a626622954d4098 Mon Sep 17 00:00:00 2001 From: bbedward Date: Wed, 31 Dec 2025 15:42:19 -0500 Subject: [PATCH] vpn: update pksc11 handling --- .../server/network/agent_networkmanager.go | 35 +++++++- .../network/backend_networkmanager_vpn.go | 89 ------------------- 2 files changed, 34 insertions(+), 90 deletions(-) diff --git a/core/internal/server/network/agent_networkmanager.go b/core/internal/server/network/agent_networkmanager.go index 2067f02d..55c7f207 100644 --- a/core/internal/server/network/agent_networkmanager.go +++ b/core/internal/server/network/agent_networkmanager.go @@ -233,6 +233,9 @@ func (a *SecretAgent) GetSecrets( if a.manager != nil && connType == "802-11-wireless" && a.manager.WasRecentlyFailed(ssid) { reason = "wrong-password" } + if settingName == "vpn" && isPKCS11Auth(conn, vpnSvc) { + reason = "pkcs11" + } var connId, connUuid string if c, ok := conn["connection"]; ok { @@ -579,6 +582,15 @@ func inferVPNFields(conn map[string]nmVariantMap, vpnService string) []string { connType := dataMap["connection-type"] switch { + case strings.Contains(vpnService, "openconnect"): + authType := dataMap["authtype"] + userCert := dataMap["usercert"] + if authType == "cert" && strings.HasPrefix(userCert, "pkcs11:") { + return []string{"key_pass"} + } + if dataMap["username"] == "" { + fields = []string{"username", "password"} + } case strings.Contains(vpnService, "openvpn"): if connType == "password" || connType == "password-tls" { if dataMap["username"] == "" { @@ -586,7 +598,7 @@ func inferVPNFields(conn map[string]nmVariantMap, vpnService string) []string { } } case strings.Contains(vpnService, "vpnc"), strings.Contains(vpnService, "l2tp"), - strings.Contains(vpnService, "pptp"), strings.Contains(vpnService, "openconnect"): + strings.Contains(vpnService, "pptp"): if dataMap["username"] == "" { fields = []string{"username", "password"} } @@ -597,6 +609,8 @@ func inferVPNFields(conn map[string]nmVariantMap, vpnService string) []string { func vpnFieldMeta(field, vpnService string) (label string, isSecret bool) { switch field { + case "key_pass": + return "PIN", true case "password": return "Password", true case "Xauth password": @@ -624,6 +638,25 @@ func vpnFieldMeta(field, vpnService string) (label string, isSecret bool) { return titleCaser.String(strings.ReplaceAll(field, "-", " ")), false } +func isPKCS11Auth(conn map[string]nmVariantMap, vpnService string) bool { + if !strings.Contains(vpnService, "openconnect") { + return false + } + vpnSettings, ok := conn["vpn"] + if !ok { + return false + } + dataVariant, ok := vpnSettings["data"] + if !ok { + return false + } + dataMap, ok := dataVariant.Value().(map[string]string) + if !ok { + return false + } + return dataMap["authtype"] == "cert" && strings.HasPrefix(dataMap["usercert"], "pkcs11:") +} + func readVPNPasswordFlags(conn map[string]nmVariantMap, settingName string) uint32 { if settingName != "vpn" { return 0xFFFF diff --git a/core/internal/server/network/backend_networkmanager_vpn.go b/core/internal/server/network/backend_networkmanager_vpn.go index 67f34b28..fd39b58f 100644 --- a/core/internal/server/network/backend_networkmanager_vpn.go +++ b/core/internal/server/network/backend_networkmanager_vpn.go @@ -296,13 +296,6 @@ func (b *NetworkManagerBackend) ConnectVPN(uuidOrName string, singleActive bool) authAction := detectVPNAuthAction(vpnServiceType, vpnData) switch authAction { - case "pkcs11_pin": - if b.promptBroker == nil { - return fmt.Errorf("PKCS11 authentication requires interactive prompt") - } - if err := b.handlePKCS11Auth(targetConn, connName, targetUUID, vpnServiceType); err != nil { - return err - } case "openvpn_username": if b.promptBroker == nil { return fmt.Errorf("OpenVPN password authentication requires interactive prompt") @@ -345,12 +338,6 @@ func detectVPNAuthAction(serviceType string, data map[string]string) string { } switch { - case strings.Contains(serviceType, "openconnect"): - authType := data["authtype"] - userCert := data["usercert"] - if authType == "cert" && strings.HasPrefix(userCert, "pkcs11:") { - return "pkcs11_pin" - } case strings.Contains(serviceType, "openvpn"): connType := data["connection-type"] username := data["username"] @@ -361,82 +348,6 @@ func detectVPNAuthAction(serviceType string, data map[string]string) string { return "" } -func (b *NetworkManagerBackend) handlePKCS11Auth(targetConn gonetworkmanager.Connection, connName, targetUUID, vpnServiceType string) error { - log.Infof("[ConnectVPN] PKCS11 authentication detected - prompting for PIN") - - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - token, err := b.promptBroker.Ask(ctx, PromptRequest{ - Name: connName, - ConnType: "vpn", - VpnService: vpnServiceType, - SettingName: "vpn", - Fields: []string{"key_pass"}, - FieldsInfo: []FieldInfo{{Name: "key_pass", Label: "PIN", IsSecret: true}}, - Reason: "pkcs11", - ConnectionId: connName, - ConnectionUuid: targetUUID, - ConnectionPath: string(targetConn.GetPath()), - }) - if err != nil { - return fmt.Errorf("failed to request PIN: %w", err) - } - - reply, err := b.promptBroker.Wait(ctx, token) - if err != nil { - return fmt.Errorf("PIN prompt failed: %w", err) - } - - if reply.Cancel { - return fmt.Errorf("user cancelled PIN entry") - } - - pin := reply.Secrets["key_pass"] - if pin == "" { - return fmt.Errorf("PIN required for PKCS11 authentication") - } - - connObj := b.dbusConn.Object("org.freedesktop.NetworkManager", targetConn.GetPath()) - var existingSettings map[string]map[string]dbus.Variant - if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil { - return fmt.Errorf("failed to get settings: %w", err) - } - - settings := make(map[string]map[string]dbus.Variant) - if connSection, ok := existingSettings["connection"]; ok { - settings["connection"] = connSection - } - - vpn := existingSettings["vpn"] - var data map[string]string - if dataVariant, ok := vpn["data"]; ok { - if dm, ok := dataVariant.Value().(map[string]string); ok { - data = make(map[string]string) - for k, v := range dm { - data[k] = v - } - } else { - data = make(map[string]string) - } - } else { - data = make(map[string]string) - } - data["key_pass"] = pin - - vpn["data"] = dbus.MakeVariant(data) - settings["vpn"] = vpn - - var result map[string]dbus.Variant - if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0, - settings, uint32(0x2), map[string]dbus.Variant{}).Store(&result); err != nil { - return fmt.Errorf("failed to set PIN: %w", err) - } - - log.Infof("[ConnectVPN] PIN set (in-memory only)") - return nil -} - func (b *NetworkManagerBackend) handleOpenVPNUsernameAuth(targetConn gonetworkmanager.Connection, connName, targetUUID, vpnServiceType string) error { log.Infof("[ConnectVPN] OpenVPN requires username in vpn.data - prompting before activation")