Example #1
0
        public string KeyChallengeResponse2(string cc, string cr, KeyContainerClass kc, int securityLevel, out bool authorised)
        {
            string response = null;

            this.cc = cc;
            this.cr = KeePassLib.Utility.MemUtil.ByteArrayToHexString(Utils.Hash("1" + kc.Key + this.sc + this.cc)).ToLower();
            if (cr != this.cr)
            {
                authorised = false;
                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "setup";
                data2client.version  = ProtocolVersion;
                data2client.error    = new Error(ErrorCode.AUTH_FAILED, new string[] { "Keys do not match" });
                response             = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
            }
            else
            {
                this.sr    = KeePassLib.Utility.MemUtil.ByteArrayToHexString(Utils.Hash("0" + kc.Key + this.sc + this.cc)).ToLower();
                authorised = true;

                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol          = "setup";
                data2client.key               = new KeyParams();
                data2client.key.sr            = this.sr;
                data2client.key.securityLevel = securityLevel;
                data2client.version           = ProtocolVersion;
                response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
            }
            return(response);
        }
Example #2
0
        void KPRPCReceiveJSONRPC(JSONRPCContainer jsonrpcEncrypted, KeePassRPCService service)
        {
            string        jsonrpc = Decrypt(jsonrpcEncrypted);
            StringBuilder sb      = new StringBuilder();

            JsonRpcDispatcher dispatcher = JsonRpcDispatcherFactory.CreateDispatcher(service);

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

            KPRPCMessage data2client = new KPRPCMessage();

            data2client.protocol = "jsonrpc";
            data2client.version  = ProtocolVersion;
            data2client.jsonrpc  = Encrypt(output);

            // If there was a problem encrypting our message, respond to the
            // client with a non-encrypted error message
            if (data2client.jsonrpc == null)
            {
                data2client          = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.version  = ProtocolVersion;
                data2client.error    = new Error(ErrorCode.AUTH_RESTART, new string[] { "Encryption error" });
                this.Authorised      = false;
                if (KPRPC.logger != null)
                {
                    KPRPC.logger.WriteLine("Encryption error when trying to reply to client message");
                }
            }
            _webSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
        }
Example #3
0
        public string KeyChallengeResponse2(string cc, string cr, KeyContainerClass kc, int securityLevel, out bool authorised)
        {
            string response = null;
            this.cc = cc;
            this.cr = KeePassLib.Utility.MemUtil.ByteArrayToHexString(Utils.Hash("1" + kc.Key + this.sc + this.cc)).ToLower();
            if (cr != this.cr)
            {
                authorised = false;
                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "setup";
                data2client.version = ProtocolVersion;
                data2client.error = new Error(ErrorCode.AUTH_FAILED, new string[] { "Keys do not match" });
                response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
            }
            else
            {
                this.sr = KeePassLib.Utility.MemUtil.ByteArrayToHexString(Utils.Hash("0" + kc.Key + this.sc + this.cc)).ToLower();
                authorised = true;

                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "setup";
                data2client.key = new KeyParams();
                data2client.key.sr = this.sr;
                data2client.key.securityLevel = securityLevel;
                data2client.version = ProtocolVersion;
                response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
            }
            return response;
        }
Example #4
0
        private void AbortWithMessageToClient(KPRPCMessage data2client)
        {
            Authorised     = false;
            clientFeatures = null;
            string response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);

            WebSocketConnection.Send(response);
        }
Example #5
0
        public void ReceiveMessage(string message, KeePassRPCService service)
        {
            // Inspect incoming message
            KPRPCMessage kprpcm;

            try
            {
                kprpcm = (KPRPCMessage)Jayrock.Json.Conversion.JsonConvert.Import(typeof(KPRPCMessage), message);
            }
            catch (Exception)
            {
                kprpcm = null;
            }

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

                data2client.error = new Error(ErrorCode.INVALID_MESSAGE, new string[] { "Contents can't be interpreted as an SRPEncapsulatedMessage" });

                AbortWithMessageToClient(data2client);
                return;
            }

            if (kprpcm.version != ProtocolVersion)
            {
                if (!ClientSupportsRequiredFeatures(kprpcm.features))
                {
                    RejectClientVersion(kprpcm);
                    return;
                }
            }

            switch (kprpcm.protocol)
            {
            case "setup": KPRPCReceiveSetup(kprpcm); break;

            case "jsonrpc": KPRPCReceiveJSONRPC(kprpcm.jsonrpc, service); break;

            default: KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.srp      = new SRPParams();
                data2client.version  = ProtocolVersion;

                data2client.error = new Error(ErrorCode.UNRECOGNISED_PROTOCOL, new string[] { "Use setup or jsonrpc" });

                AbortWithMessageToClient(data2client);
                return;
            }
        }
Example #6
0
        private void RejectClientVersion(KPRPCMessage kprpcm)
        {
            KPRPCMessage data2client = new KPRPCMessage();

            data2client.protocol = "error";
            data2client.srp      = new SRPParams();
            data2client.version  = ProtocolVersion;

            // From 1.7 onwards, the client can never be too new but can be too low if we find that it is missing essential features
            data2client.error = new Error(ErrorCode.VERSION_CLIENT_TOO_LOW, new string[] { ProtocolVersion.ToString() });
            AbortWithMessageToClient(data2client);
            return;
        }
Example #7
0
        string SRPProofToServer(KPRPCMessage srpem)
        {
            SRPParams srp = srpem.srp;

            KPRPCMessage data2client = new KPRPCMessage();

            data2client.protocol  = "setup";
            data2client.srp       = new SRPParams();
            data2client.srp.stage = "proofToClient";
            data2client.version   = ProtocolVersion;

            if (string.IsNullOrEmpty(srp.M))
            {
                data2client.error = new Error(ErrorCode.AUTH_MISSING_PARAM, new string[] { "M" });
            }
            else
            {
                _srp.Authenticate(srp.M);

                if (!_srp.Authenticated)
                {
                    data2client.error = new Error(ErrorCode.AUTH_FAILED, new string[] { "Keys do not match" });
                }
                else
                {
                    data2client.srp.M2            = _srp.M2;
                    data2client.srp.securityLevel = securityLevel;
                    KeyContainer = new KeyContainerClass(_srp.Key, DateTime.UtcNow.AddSeconds(KeyExpirySeconds), userName, clientName);
                    Authorised   = true;
                    // We assume the user has checked 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, clientName);
                    KPRPC.InvokeMainThread(new HideAuthDialogDelegate(HideAuthDialog));

                    // If we've never shown the user the welcome screen and have never
                    // known a KeeFox add-on from the previous KPRPC protocol, show it now
                    bool welcomeDisplayed = KPRPC._host.CustomConfig.GetBool("KeePassRPC.KeeFoxWelcomeDisplayed", false);
                    if (!welcomeDisplayed &&
                        string.IsNullOrEmpty(KPRPC._host.CustomConfig.GetString("KeePassRPC.knownClients.KeeFox Firefox add-on")))
                    {
                        KPRPC.InvokeMainThread(new KeePassRPCExt.WelcomeKeeFoxUserDelegate(KPRPC.WelcomeKeeFoxUser));
                    }
                    if (!welcomeDisplayed)
                    {
                        KPRPC._host.CustomConfig.SetBool("KeePassRPC.KeeFoxWelcomeDisplayed", true);
                    }
                }
            }

            return(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
        }
Example #8
0
        public string KeyChallengeResponse1(string userName, int securityLevel)
        {
            BigInteger scTemp = new BigInteger();
            scTemp.genRandomBits(256, new Random((int)DateTime.Now.Ticks));
            sc = scTemp.ToString().ToLower();

            KPRPCMessage data2client = new KPRPCMessage();
            data2client.protocol = "setup";
            data2client.key = new KeyParams();
            data2client.key.sc = sc;
            data2client.key.securityLevel = securityLevel;
            data2client.version = ProtocolVersion;

            string response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
            return response;
        }
Example #9
0
        public string KeyChallengeResponse1(string userName, int securityLevel)
        {
            BigInteger scTemp = new BigInteger(Utils.GetRandomBytes(32));

            sc = scTemp.ToString().ToLower();

            KPRPCMessage data2client = new KPRPCMessage();

            data2client.protocol          = "setup";
            data2client.key               = new KeyParams();
            data2client.key.sc            = sc;
            data2client.key.securityLevel = securityLevel;
            data2client.version           = ProtocolVersion;
            data2client.features          = features;

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

            return(response);
        }
Example #10
0
        public string KeyChallengeResponse1(string userName, int securityLevel)
        {
            BigInteger scTemp = new BigInteger();

            scTemp.genRandomBits(256, new Random((int)DateTime.Now.Ticks));
            sc = scTemp.ToString().ToLower();


            KPRPCMessage data2client = new KPRPCMessage();

            data2client.protocol          = "setup";
            data2client.key               = new KeyParams();
            data2client.key.sc            = sc;
            data2client.key.securityLevel = securityLevel;
            data2client.version           = ProtocolVersion;


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

            return(response);
        }
Example #11
0
        string SRPIdentifyToServer(KPRPCMessage srpem)
        {
            SRPParams srp = srpem.srp;
            Error error;
            KPRPCMessage data2client = new KPRPCMessage();
            data2client.protocol = "setup";
            data2client.srp = new SRPParams();
            data2client.srp.stage = "identifyToClient";
            data2client.version = ProtocolVersion;

            // Generate a new random password
            // SRP isn't very susceptible to brute force attacks but we get 32 bits worth of randomness just in case
            byte[] password = Utils.GetRandomBytes(4);
            string plainTextPassword = Utils.GetTypeablePassword(password);

            // caclulate the hash of our randomly generated password
            _srp.CalculatePasswordHash(plainTextPassword);

            if (string.IsNullOrEmpty(srp.I))
            {
                data2client.error = new Error(ErrorCode.AUTH_MISSING_PARAM, new string[] { "I" });
            }
            else if (string.IsNullOrEmpty(srp.A))
            {
                data2client.error = new Error(ErrorCode.AUTH_MISSING_PARAM, new string[] { "A" });
            }
            else
            {

                // Init relevant SRP protocol variables
                _srp.Setup();

                // Begin the SRP handshake
                error = _srp.Handshake(srp.I, srp.A);

                if (error.code > 0)
                    data2client.error = error;
                else
                {
                    // store the username and client name for future reference
                    userName = _srp.I;
                    clientName = srpem.clientDisplayName;

                    data2client.srp.s = _srp.s;
                    data2client.srp.B = _srp.Bstr;

                    data2client.srp.securityLevel = securityLevel;

                    //pass the params through to the main kprpcext thread via begininvoke - that function will then create and show the form as a modal dialog
                    string secLevel = "low";
                    if (srp.securityLevel == 2)
                        secLevel = "medium";
                    else if (srp.securityLevel == 3)
                        secLevel = "high";
                    KPRPC.InvokeMainThread (new ShowAuthDialogDelegate(ShowAuthDialog), secLevel, srpem.clientDisplayName, srpem.clientDisplayDescription, plainTextPassword);
                }
            }

            return Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
        }
Example #12
0
        /// <summary>
        /// Sends the specified signal to the client.
        /// </summary>
        /// <param name="signal">The signal.</param>
        public void Signal(KeePassRPC.DataExchangeModel.Signal signal, string methodName)
        {
            try
            {
                Jayrock.Json.JsonObject call = new Jayrock.Json.JsonObject();
                call["id"] = ++_currentCallBackId;
                call["method"] = methodName;
                call["params"] = new int[] { (int)signal };

                StringBuilder sb = new StringBuilder();
                Jayrock.Json.Conversion.JsonConvert.Export(call, sb);
                KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "jsonrpc";
                data2client.version = ProtocolVersion;
                data2client.jsonrpc = Encrypt(sb.ToString());

                // If there was a problem encrypting our message, just abort - the
                // client won't be able to do anything useful with an error message
                if (data2client.jsonrpc == null)
                {
                    if (KPRPC.logger != null) KPRPC.logger.WriteLine("Encryption error when trying to send signal: " + signal);
                    return;
                }

                // Signalling through the websocket needs to be processed on a different thread becuase handling the incoming messages results in a lock on the list of known connections (which also happens before this Signal function is called) so we want to process this as quickly as possible and avoid deadlocks.

                // Respond to each message on a different thread
                ThreadStart work = delegate
                {
                    WebSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
                };
                Thread messageHandler = new Thread(work);
                messageHandler.Name = "signalDispatcher";
                messageHandler.Start();
            }
            catch (System.IO.IOException)
            {
                // Sometimes a connection is unexpectedly closed e.g. by Firefox
                // or (more likely) dodgy security "protection". From one year's
                // worth of bug reports (35) 100% of unexpected application
                // exceptions were IOExceptions.
                //
                // We will now ignore this type of exception and allow KeeFox to
                // re-establish the link to KeePass as part of its regular polling loop.
                //
                // The requested KPRPC signal will never be recieved by KeeFox
                // but this should be OK in practice becuase KeeFox will
                // re-establish the relevant state information as soon as it reconnects.
                //
                // BUT: the exception to this rule is when KeeFox fails to receive the
                // "shutdown" signal - it then gets itself in an inconsistent state
                // and has no opportunity to recover until KeePass is running again.
                return;
            }
            catch (Exception ex)
            {
                System.Windows.Forms.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: " + ex.ToString());
            }
        }
Example #13
0
        public void ReceiveMessage(string message, KeePassRPCService service)
        {
            // Inspect incoming message
            KPRPCMessage kprpcm;

            try
            {
                kprpcm = (KPRPCMessage)Jayrock.Json.Conversion.JsonConvert.Import(typeof(KPRPCMessage), message);
            }
            catch (Exception )
            {
                kprpcm = null;
            }

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

                data2client.error = new Error(ErrorCode.INVALID_MESSAGE, new string[] { "Contents can't be interpreted as an SRPEncapsulatedMessage" });
                this.Authorised = false;

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

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

                data2client.error = new Error(kprpcm.version > ProtocolVersion ? ErrorCode.VERSION_CLIENT_TOO_HIGH : ErrorCode.VERSION_CLIENT_TOO_LOW, new string[] { ProtocolVersion.ToString() });
                this.Authorised = false;

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

            //1: Is it an SRP message?
            switch (kprpcm.protocol)
            {
                case "setup": KPRPCReceiveSetup(kprpcm); break;
                case "jsonrpc": KPRPCReceiveJSONRPC(kprpcm.jsonrpc, service); break;
                default: KPRPCMessage data2client = new KPRPCMessage();
                    data2client.protocol = "error";
                    data2client.srp = new SRPParams();
                    data2client.version = ProtocolVersion;

                    data2client.error = new Error(ErrorCode.UNRECOGNISED_PROTOCOL, new string[] { "Use setup or jsonrpc" });
                    this.Authorised = false;

                    string response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
                    this.WebSocketConnection.Send(response);
                    return;
            }
        }
Example #14
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);
                        }
                    }
                }
            }
        }
Example #15
0
        string SRPIdentifyToServer(KPRPCMessage srpem)
        {
            SRPParams    srp = srpem.srp;
            Error        error;
            KPRPCMessage data2client = new KPRPCMessage();

            data2client.protocol  = "setup";
            data2client.srp       = new SRPParams();
            data2client.srp.stage = "identifyToClient";
            data2client.version   = ProtocolVersion;

            // Generate a new random password
            // SRP isn't very susceptible to brute force attacks but we get 32 bits worth of randomness just in case
            byte[] password          = Utils.GetRandomBytes(4);
            string plainTextPassword = Utils.GetTypeablePassword(password);

            // caclulate the hash of our randomly generated password
            _srp.CalculatePasswordHash(plainTextPassword);


            if (string.IsNullOrEmpty(srp.I))
            {
                data2client.error = new Error(ErrorCode.AUTH_MISSING_PARAM, new string[] { "I" });
            }
            else if (string.IsNullOrEmpty(srp.A))
            {
                data2client.error = new Error(ErrorCode.AUTH_MISSING_PARAM, new string[] { "A" });
            }
            else
            {
                // Init relevant SRP protocol variables
                _srp.Setup();

                // Begin the SRP handshake
                error = _srp.Handshake(srp.I, srp.A);

                if (error.code > 0)
                {
                    data2client.error = error;
                }
                else
                {
                    // store the username and client name for future reference
                    userName   = _srp.I;
                    clientName = srpem.clientDisplayName;

                    data2client.srp.s = _srp.s;
                    data2client.srp.B = _srp.Bstr;

                    data2client.srp.securityLevel = securityLevel;

                    //pass the params through to the main kprpcext thread via begininvoke - that function will then create and show the form as a modal dialog
                    string secLevel = "low";
                    if (srp.securityLevel == 2)
                    {
                        secLevel = "medium";
                    }
                    else if (srp.securityLevel == 3)
                    {
                        secLevel = "high";
                    }
                    KPRPC.InvokeMainThread(new ShowAuthDialogDelegate(ShowAuthDialog), secLevel, srpem.clientDisplayName, srpem.clientDisplayDescription, plainTextPassword);
                }
            }

            return(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
        }
Example #16
0
        public void ReceiveMessage(string message, KeePassRPCService service)
        {
            // Inspect incoming message
            KPRPCMessage kprpcm;
            int          requiredCommsVersion = 1;

            try
            {
                kprpcm = (KPRPCMessage)Jayrock.Json.Conversion.JsonConvert.Import(typeof(KPRPCMessage), message);
            }
            catch (Exception)
            {
                kprpcm = null;
            }

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

                data2client.error = new Error(ErrorCode.INVALID_MESSAGE, new string[] { "Contents can't be interpreted as an SRPEncapsulatedMessage" });
                this.Authorised   = false;

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

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

                data2client.error = new Error(kprpcm.version > ProtocolVersion ? ErrorCode.VERSION_CLIENT_TOO_HIGH : ErrorCode.VERSION_CLIENT_TOO_LOW, new string[] { ProtocolVersion.ToString() });
                this.Authorised   = false;

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

            //1: Is it an SRP message?
            switch (kprpcm.protocol)
            {
            case "setup": KPRPCReceiveSetup(kprpcm); break;

            case "jsonrpc": KPRPCReceiveJSONRPC(kprpcm.jsonrpc, service); break;

            default: KPRPCMessage data2client = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.srp      = new SRPParams();
                data2client.version  = ProtocolVersion;

                data2client.error = new Error(ErrorCode.UNRECOGNISED_PROTOCOL, new string[] { "Use setup or jsonrpc" });
                this.Authorised   = false;

                string response = Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
                this.WebSocketConnection.Send(response);
                return;
            }
        }
Example #17
0
        /// <summary>
        /// Sends the specified signal to the client.
        /// </summary>
        /// <param name="signal">The signal.</param>
        public void Signal(KeePassRPC.DataExchangeModel.Signal signal, string methodName)
        {
            try
            {
                Jayrock.Json.JsonObject call = new Jayrock.Json.JsonObject();
                call["id"]     = ++_currentCallBackId;
                call["method"] = methodName;
                call["params"] = new int[] { (int)signal };

                StringBuilder sb = new StringBuilder();
                Jayrock.Json.Conversion.JsonConvert.Export(call, sb);
                if (WebSocketConnection != null)
                {
                    KPRPCMessage data2client = new KPRPCMessage();
                    data2client.protocol = "jsonrpc";
                    data2client.version  = ProtocolVersion;
                    data2client.jsonrpc  = Encrypt(sb.ToString());

                    // If there was a problem encrypting our message, just abort - the
                    // client won't be able to do anything useful with an error message
                    if (data2client.jsonrpc == null)
                    {
                        if (KPRPC.logger != null)
                        {
                            KPRPC.logger.WriteLine("Encryption error when trying to send signal: " + signal);
                        }
                        return;
                    }

                    // Signalling through the websocket needs to be processed on a different thread becuase handling the incoming messages results in a lock on the list of known connections (which also happens before this Signal function is called) so we want to process this as quickly as possible and avoid deadlocks.
                    // Not sure why this doesn't happen on the standard network port implementation in previous versions (maybe the networking stack created threads automatically before passing on the incoming messages?)

                    //TODO1.3: Does this work in .NET 2?
                    // Respond to each message on a different thread
                    ThreadStart work = delegate
                    {
                        WebSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
                    };
                    Thread messageHandler = new Thread(work);
                    messageHandler.Name = "signalDispatcher";
                    messageHandler.Start();
                }
                else
                {
                    byte[] bytes = System.Text.Encoding.UTF8.GetBytes(sb.ToString());
                    this.ConnectionStreamWrite(bytes);
                }
            }
            catch (System.IO.IOException)
            {
                // Sometimes a connection is unexpectedly closed e.g. by Firefox
                // or (more likely) dodgy security "protection". From one year's
                // worth of bug reports (35) 100% of unexpected application
                // exceptions were IOExceptions.
                //
                // We will now ignore this type of exception and allow KeeFox to
                // re-establish the link to KeePass as part of its regular polling loop.
                //
                // The requested KPRPC signal will never be recieved by KeeFox
                // but this should be OK in practice becuase KeeFox will
                // re-establish the relevant state information as soon as it reconnects.
                //
                // BUT: the exception to this rule is when KeeFox fails to receive the
                // "shutdown" signal - it then gets itself in an inconsistent state
                // and has no opportunity to recover until KeePass is running again.
                return;
            }
            catch (Exception ex)
            {
                System.Windows.Forms.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: " + ex.ToString());
            }
        }
Example #18
0
        string SRPProofToServer(KPRPCMessage srpem)
        {
            SRPParams srp = srpem.srp;

            KPRPCMessage data2client = new KPRPCMessage();
            data2client.protocol = "setup";
            data2client.srp = new SRPParams();
            data2client.srp.stage = "proofToClient";
            data2client.version = ProtocolVersion;

            if (string.IsNullOrEmpty(srp.M))
            {
                data2client.error = new Error(ErrorCode.AUTH_MISSING_PARAM, new string[] { "M" });
            }
            else
            {
                _srp.Authenticate(srp.M);

                if (!_srp.Authenticated)
                    data2client.error = new Error(ErrorCode.AUTH_FAILED, new string[] { "Keys do not match" });
                else
                {
                    data2client.srp.M2 = _srp.M2;
                    data2client.srp.securityLevel = securityLevel;
                    KeyContainer = new KeyContainerClass(_srp.Key,DateTime.UtcNow.AddSeconds(KeyExpirySeconds),userName,clientName);
                    Authorised = true;
                    // We assume the user has checked 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, clientName);
                    KPRPC.InvokeMainThread(new HideAuthDialogDelegate(HideAuthDialog));

                    // If we've never shown the user the welcome screen and have never
                    // known a KeeFox add-on from the previous KPRPC protocol, show it now
                    bool welcomeDisplayed = KPRPC._host.CustomConfig.GetBool("KeePassRPC.KeeFoxWelcomeDisplayed",false);
                    if (!welcomeDisplayed
                        && string.IsNullOrEmpty(KPRPC._host.CustomConfig.GetString("KeePassRPC.knownClients.KeeFox Firefox add-on")))
                        KPRPC.InvokeMainThread(new KeePassRPCExt.WelcomeKeeFoxUserDelegate(KPRPC.WelcomeKeeFoxUser));
                    if (!welcomeDisplayed)
                        KPRPC._host.CustomConfig.SetBool("KeePassRPC.KeeFoxWelcomeDisplayed",true);
                }
            }

            return Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client);
        }
Example #19
0
        void KPRPCReceiveJSONRPC(JSONRPCContainer jsonrpcEncrypted, KeePassRPCService service)
        {
            string jsonrpc = Decrypt(jsonrpcEncrypted);
            StringBuilder sb = new StringBuilder();

            JsonRpcDispatcher dispatcher = JsonRpcDispatcherFactory.CreateDispatcher(service);

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

            KPRPCMessage data2client = new KPRPCMessage();
            data2client.protocol = "jsonrpc";
            data2client.version = ProtocolVersion;
            data2client.jsonrpc = Encrypt(output);

            // If there was a problem encrypting our message, respond to the
            // client with a non-encrypted error message
            if (data2client.jsonrpc == null)
            {
                data2client = new KPRPCMessage();
                data2client.protocol = "error";
                data2client.version = ProtocolVersion;
                data2client.error = new Error(ErrorCode.AUTH_RESTART, new string[] { "Encryption error" });
                this.Authorised = false;
                if (KPRPC.logger != null) KPRPC.logger.WriteLine("Encryption error when trying to reply to client message");
            }
            _webSocketConnection.Send(Jayrock.Json.Conversion.JsonConvert.ExportToString(data2client));
        }
Example #20
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);
                        }
                    }
                }
            }
        }