示例#1
0
        void KPRPCReceiveSetup(KPRPCMessage kprpcm)
        {
            if (this.Authorised)
            {
                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "setup";
                data2client.srp      = new SRPParams();
                data2client.version  = ProtocolVersion;

                data2client.error = new Error(ErrorCode.AUTH_RESTART, new string[] { "Already authorised" });
                this.Authorised   = false;

                string response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
                this.WebSocketConnection.Send(response);

                return;
            }



            if (kprpcm.srp != null)
            {
                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "setup";
                data2client.version  = ProtocolVersion;

                int clientSecurityLevel = kprpcm.srp.securityLevel;

                if (clientSecurityLevel < securityLevelClientMinimum)
                {
                    data2client.error = new Error(ErrorCode.AUTH_CLIENT_SECURITY_LEVEL_TOO_LOW, new string[] { securityLevelClientMinimum.ToString() });

                    /* TODO1.3: need to disconnect/delete/reset this connection once we've decided we are not interested in letting the client connect. Maybe
                     * tie in to finding a way to abort if user clicks a "cancel" button on the auth form.
                     */
                    this.WebSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
                }
                else
                {
                    switch (kprpcm.srp.stage)
                    {
                    case "identifyToServer": this.WebSocketConnection.Send(SRPIdentifyToServer(kprpcm)); break;

                    case "proofToServer": this.WebSocketConnection.Send(SRPProofToServer(kprpcm)); break;

                    default: return;
                    }
                }
            }
            else
            {
                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "setup";
                data2client.version  = ProtocolVersion;

                int clientSecurityLevel = kprpcm.key.securityLevel;

                if (clientSecurityLevel < securityLevelClientMinimum)
                {
                    data2client.error = new Error(ErrorCode.AUTH_CLIENT_SECURITY_LEVEL_TOO_LOW, new string[] { securityLevelClientMinimum.ToString() });

                    /* TODO1.3: need to disconnect/delete/reset this connection once we've decided we are not interested in letting the client connect. Maybe
                     * tie in to finding a way to abort if user clicks a "cancel" button on the auth form.
                     */
                    this.WebSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
                }
                else
                {
                    if (!string.IsNullOrEmpty(kprpcm.key.username))
                    {
                        // confirm username
                        this.userName = kprpcm.key.username;
                        KeyContainerClass kc = this.KeyContainer;

                        if (kc == null)
                        {
                            this.userName     = null;
                            data2client.error = new Error(ErrorCode.AUTH_FAILED, new string[] { "Stored key not found - Caused by changed Firefox profile or KeePass instance; changed OS user credentials; or KeePass config file may be corrupt" });

                            /* TODO1.3: need to disconnect/delete/reset this connection once we've decided we are not interested in letting the client connect. Maybe
                             * tie in to finding a way to abort if user clicks a "cancel" button on the auth form.
                             */
                            this.WebSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
                            return;
                        }
                        if (kc.Username != this.userName)
                        {
                            this.userName     = null;
                            data2client.error = new Error(ErrorCode.AUTH_FAILED, new string[] { "Username mismatch - KeePass config file is probably corrupt" });

                            /* TODO1.3: need to disconnect/delete/reset this connection once we've decided we are not interested in letting the client connect. Maybe
                             * tie in to finding a way to abort if user clicks a "cancel" button on the auth form.
                             */
                            this.WebSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
                            return;
                        }
                        if (kc.AuthExpires < DateTime.UtcNow)
                        {
                            this.userName     = null;
                            data2client.error = new Error(ErrorCode.AUTH_EXPIRED);

                            /* TODO1.3: need to disconnect/delete/reset this connection once we've decided we are not interested in letting the client connect. Maybe
                             * tie in to finding a way to abort if user clicks a "cancel" button on the auth form.
                             */
                            this.WebSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
                            return;
                        }

                        this.WebSocketConnection.Send(Kcp.KeyChallengeResponse1(this.userName, securityLevel));
                    }
                    else if (!string.IsNullOrEmpty(kprpcm.key.cc) && !string.IsNullOrEmpty(kprpcm.key.cr))
                    {
                        bool authorised = false;
                        this.WebSocketConnection.Send(Kcp.KeyChallengeResponse2(kprpcm.key.cc, kprpcm.key.cr, KeyContainer, securityLevel, out authorised));
                        Authorised = authorised;
                        if (authorised)
                        {
                            // We assume the user has manually verified the client name as part of the initial SRP setup so it's fairly safe to use it to determine the type of client connection to which we want to promote our null connection
                            KPRPC.PromoteNullRPCClient(this, KeyContainer.ClientName);
                        }
                    }
                }
            }
        }
示例#2
0
        /// <summary>
        /// Does some basic authentication checks and then
        /// dispatches to the JayRock RPC system.
        /// </summary>
        /// <param name="message">The JSON-RPC formatted message.</param>
        /// <param name="keePassRPCClient">The client we're communicating with.</param>
        private void DispatchToRPCService(string message, KeePassRPCClientConnection keePassRPCClientConnection)
        {
            if (KeePassRPCPlugin.logger != null)
            {
                KeePassRPCPlugin.logger.WriteLine("Preparing to dispatch: " + message);
            }
            StringBuilder sb = new StringBuilder();
            string        requiredResultRegex    = "";
            long          authorisationAttemptId = -1;

            if (!keePassRPCClientConnection.Authorised && _authorisationRequired)
            {
                Match match = Regex.Match(message,
                                          "^\\{.*?\\\"method\\\"\\:\\\"Idle\\\".*?,.*?\\\"id\\\"\\:(\\d+).*?\\}$");
                if (match.Success)
                {
                    if (KeePassRPCPlugin.logger != null)
                    {
                        KeePassRPCPlugin.logger.WriteLine("Got Idle method- ignoring.");
                    }
                    // Do nothing
                    return;
                }
                else   // Check for alternative Idle message structure
                {
                    match = Regex.Match(message,
                                        "^\\{.*?\\\"id\\\"\\:(\\d+).*?,.*?\\\"method\\\"\\:\\\"Idle\\\".*?\\}$");
                    if (match.Success)
                    {
                        if (KeePassRPCPlugin.logger != null)
                        {
                            KeePassRPCPlugin.logger.WriteLine("Got Idle method- ignoring.");
                        }
                        // Do nothing
                        return;
                    }
                }
            }

            if (!keePassRPCClientConnection.Authorised && _authorisationRequired)
            {
                // We only accept one type of request if the client has not
                // already authenticated. Maybe it's not nice having to do this
                // outside of the main JayRockJsonRpc library but it'll be good enough

                Match match = Regex.Match(message,
                                          "^\\{.*?\\\"method\\\"\\:\\\"Authenticate\\\".*?,.*?\\\"id\\\"\\:(\\d+).*?\\}$");
                if (!match.Success)
                {
                    match = Regex.Match(message,
                                        "^\\{.*?\\\"id\\\"\\:(\\d+).*?,.*?\\\"method\\\"\\:\\\"Authenticate\\\".*?\\}$");
                    if (!match.Success)
                    {
                        throw new AuthorisationException("Authentication required. You must send a properly formed JSON Authenticate request before using this connection.", -1, 1);
                    }
                }

                authorisationAttemptId = int.Parse(match.Groups[1].Value);
                requiredResultRegex    = "^\\{\\\"id\\\"\\:" + authorisationAttemptId + ",\\\"result\\\"\\:\\{\\\"result\\\"\\:0,\\\"name\\\"\\:\\\"(.*)\\\"\\}\\}$";
            }

            //Stream clientStream = keePassRPCClientConnection.ConnectionStream;

            //TODO2: is this Jayrock stuff thread-safe or do I need new instances of the Service each time?
            JsonRpcDispatcher dispatcher = JsonRpcDispatcherFactory.CreateDispatcher(Service);

            dispatcher.Process(new StringReader(message),
                               new StringWriter(sb), keePassRPCClientConnection.Authorised);
            string output = sb.ToString();

            //MessageBox.Show("result: " + output);
            if (_authorisationRequired && !keePassRPCClientConnection.Authorised)
            {
                string authenticatedClientName;

                // Process the output from the JsonRpcDispatcher which
                // should tell us if the authorisation was successful
                Match match = Regex.Match(output, requiredResultRegex);
                if (match.Success)
                {
                    authenticatedClientName = match.Groups[1].Value;
                    keePassRPCClientConnection.Authorised = true;
                    KeePassRPCPlugin.PromoteNullRPCClient(keePassRPCClientConnection, authenticatedClientName);
                }
                else
                {
                    // If the result follows an accepted syntax we will send
                    // it back to the client so they know why it failed but otherwise...
                    if (!Regex.IsMatch(output,
                                       "^\\{\\\"id\\\"\\:(\\d+),\\\"result\\\"\\:\\{\\\"result\\\"\\:(\\d+),\\\"name\\\"\\:\\\".*\\\"\\}\\}$"))
                    {
                        MessageBox.Show("ERROR! Please click on this box, press CTRL-C on your keyboard and paste into a new post on the KeeFox forum (http://keefox.org/help/forum). Doing this will help other people to use KeeFox without any unexpected error messages like this. Please briefly describe what you were doing when the problem occurred, which version of KeeFox, KeePass and Firefox you use and what other security software you run on your machine. Thanks! Technical detail follows: " + output);
                        return; // maybe could return a proper result indicating failure
                        //but user might get annoyed with this popup appearing every 10 seconds!
                    }
                }
            }

            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(output);
            keePassRPCClientConnection.ConnectionStreamWrite(bytes);
        }