OrbitLens

I really like what you're doing.

I'm trying to do this integration job with cosmic links. I recently added transparent support for StellarGuard. Right now I'm working on integrating transparent signatures sharing.

Recently, I made the cosmic.link website compatible with Ledger Wallets, Stellar Laboratory and future Sep-0007 wallets:

https://cosmic.link/?setOptions&inflationDest=GCCD6AJOYZCUAQLX32ZJF2MKFFAUJ53PVCFQI3RHWKL3V47QYE2BNAUT

I'll be happy to add support for Stellar Expert Id.

I wrote an article that have few proposals about how to work together under a common language: Understanding Cosmic Links

I think that in the near future every wallet will have to offer such features. Would be great to agree upon simple GET/POST scheme that everybody could implement, rather than multiplying custom solutions. The reason I favor GET request despite their lack of privacy is that it works with serverless wallets.

    MisterTicot I saw your work and was really impressed by your approach. Of course it's better to agree on an unified standard than maintain multiple solutions. Your links protocol definitely makes sense for various use-cases, in particular for situations where the initiator (wallet, exchange or any other app) doesn't know user account public key in advance.

      OrbitLens Yes. Now we'll also need a way to pass the public key, and a way to login. You're the first getting there so I hope you'll bring us some neat protocol for that ?

      dzham

      Firefly only sign the pure json string to avoid this kind of scenario.

        @OrbitLens I think i am late for this article and the idea. I wrote some similar APIs for Firefly here (in Chinese only, have not translated in English yet).
        We have created some "dapps" with these APIs.

        Now I must catch up with you. it's better to agree on an unified standard than maintain multiple solutions

        OrbitLens
        dzham
        Eno

        There are other critical things that should not be signed that easily. For example the DKIF protocol allow a tier to manage a federated server on your behalf. To guarantee that the tier can't trick you, you sign the XDR federation response and make the signer key available on your DNS.

        Now I could trick someone into signing a federation response XDR that redirect to my account. This would defeat the purpose of DKIF.

        There could be other critical piece of data that could add up over time and the last thing you want is maintaining a (likely) incomplete list of checks for them.

        Now I'm not sure if we're talking about signing data for login/authentication purpose or signing arbitrary data, like in signing messages or contracts.

        For login purpose I would rather use hash(hash(x)) like Dhzam. As you know signing a text or the hash or a text might end up having a legal value, so one have to be careful here. Maybe we should restrict heavily what we accept in input.

        If the purpose is to sign abritrary data, now that's a bit complicated. Maybe transforming the data will defeat the purpose, and signing a hash of a hash as well. If it's only about signing messages and contract you could reject anything that has no space or that is accepted by JSON.parse().

        I would separate the two things in two different operations:

        ...?login&domain=external.io&callback=dex.html&challenge=...

        ...?signData&domain=external.io&callback=enter.html&data=....

        Not sure if I'm missing something. Probably I do ?

          Is there a design document that describes the protocol, so we can easily analyze its security? If SDF adopted this, we would probably a SEP that is specific enough to allow independent implementations.

          It seems you are relying on informal domain separation for signed messages--basically only sign authentication messages that don't look like transactions. This is not robust to upgrades. Hence, as a first step to integrating with the Stellar ecosystem, you should request a dedicated value of EnvelopeType as a pull request on Stellar-ledger-entries.x. (I'd maybe suggest a higher number like 20 to leave us plenty of room to extend the core protocol with things like a new transaction format.)

            MisterTicot I just checked the sources of JS SDK signing module. It looks like it's not enough to request signing of tx envelope encoded in base 64. The signature requires specifically assembled buffer with mixed in network identifier. Nevertheless, it may be an exploitable attack vector, as a potential attacker may prepare the buffer and send it in byte encoded format resulting in a correct message signature. So @dzham's implementation is safer in this case.

            It seems to me that using keypair.sign(hash(input_message)) will cover all possible implications, including mentioned DKIF signatures and other potentially unsafe cases.

            Another way to achieve such result without hashing is to prepend public key to the message, using it as a salt: keypair.sign(keypair.publicKey() + input_message). It mixes public key into the signature base (somewhat faster than value hashing) and effectively prevents from signing malicious transactions.

              mazieres The documentation is not ready yet. Hopefully, I will publish all source codes and docs in a week or so.

              The flow is quite simple.

              1. A user invokes some action on the third-party website (a wallet, DEX interface, inflation pool etc). Let's say, he wants to create an offer.
              2. The website prepares the requested transaction and it's XDR representation in base64 format.
              3. The website initiates the intent (see intent list in the project description) using js module that provides an interface for all supported intents.
              4. The interface module opens a new pop-up window pointing to id.stellar.expert. All intent parameters are serialized and transmitted in a form of GET parameters. So the full URL will look like https://id.stellar.expert/confirm?intent=sign_tx&network=testnet&txXdr=AAAAALPZeTF82....
              5. Signer application reads parameters from the URL and asks the user for a confirmation.
              6. The user chooses a keypair from the list of stored accounts (or adds a new one) and confirms the action.
              7. The signer app signs the transaction the same way any other wallet do it.
              8. The signed transaction is serialized into XDR as TransactionEnvelope and transmitted back to the opener site in base64 encoding via the built-in browser postMessage mechanism.
              9. The third-party website receives a signed transaction envelope and may choose either to submit it to the network or store somewhere in case if the tx needs more signatures or if it has time bounds set.

              Intent confirmation dialog always contains extended request information, including intent description (like "Sign transaction"), initiator website ("origin: example.com"), risk level ("high", "medium", or "low"), information about personal data disclosure (only for personal_info intent), and safety status ("safe" or "potentially unsafe"). Intent-specific details allow a user to review the request before confirmation. For instance, a dialog with sing_tx intent displays full transaction information including all meaningful properties and the list of operations in a human-friendly format adapted for the ordinary users.

              There are 4 main groups of intents:

              1. Request transaction signing. The calling app receives a signed transaction envelope in XDR format.
              2. Request information. The app may request a user's personal info (email, avatar), Stellar account public key, or Stellar account secret key (required only in rare cases, maybe we should disable this intent at all).
              3. Request specific action. Currently two actions available: "vote for inflation pool" and "establish trustline". The signer app prepares and submits the transaction to the network without returning transaction envelope XDR to the initiator website. It is done to simplify such standard actions; the initiator website does not need JS SDK or any other custom logic.
              4. Request cryptographic signature of the arbitrary data. The website may request a crypto signature to verify a keypair ownership (authentication, secure messages exchange etc).

              If SDF adopted this, we would probably a SEP that is specific enough to allow independent implementations.

              Absolutely agree, I'll prepare detailed documentation.

              It seems you are relying on informal domain separation for signed messages--basically only sign authentication messages that don't look like transactions. This is not robust to upgrades. Hence, as a first step to integrating with the Stellar ecosystem, you should request a dedicated value of EnvelopeType as a pull request on Stellar-ledger-entries.x

              I'm afraid, here you lost me... StellarExpertID is built on top of the existing SDK and it utilizes only the existing standard data formats. It's just a key storage with a simplistic interface allowing other web apps to request predefined actions. I can't see a need for the underlying XDR formats modifications. Everything is already working, we just need a trusted hosting and controlled source codes modification via pool requests. It won't require any code changes for existing SDF-maintained projects.

                OrbitLens Now I'm a bit perplex. You said you didn't want to multiply standards but I can tell your transaction request is neither using cosmic link protocol nor sep-0007. It's nearly using it, but there's a few details that doesn't seems to bring anything except making it different. You're considering making it into another SEP. Then I wonder what's the point of SEP if each one is doing its own?

                  OrbitLens According to <https://stellar.github.io/js-stellar-sdk/Transaction.html>, it is the hash of the buffer you're mentioning that is actually signed, so if you sign the hash of input message, and if any binary value may be passed, it is exploitable.

                  Once again, when it is about login/authentication (automatic signing) I would prevent any kind of text input as it may have legal value in the future.

                    MisterTicot It's my implementation, I designed it 7 months ago, when CosmicLink was not announced yet, and SEP-0007 was not defined. As I mentioned earlier, the application will support CosmicLink format. I spent last month fixing StellarExpert, so I had no time to properly clean up the code and implement the latest specs. If you are going to create your own implementation based on my open-source project and it will be better in terms of usability, I will gradually switch to your project, ditching my codebase.

                    I'm going to update GET params mapping to match your notation (for example, xdr instead of txXdr). I do like the format you proposed, the only thing which seems completely wrong to me is a callback logic. If the browser follows redirects, the initiator application will lose its current state. For example, you prepared a transaction on, say, super-cool-trading-bot.io, then you are redirecting the user to cosmic.link?xdr=...&url=super-cool-trading-bot.io. In this case, a developer of super-cool-trading-bot.io has to save current application state either in URL or in localStorage in order to restore it once the transaction is signed.

                    My implementation works transparently. You just invoke the intent which returns a standard promise. Once the promise is resolved, the application receives the result, and it does not lose the current state.

                      MisterTicot You are absolutely right,

                      sign(...keypairs) {
                          let txHash = this.hash();
                          let newSigs = each(keypairs, kp => {
                            let sig = kp.signDecorated(txHash);
                            this.signatures.push(sig);
                          });
                        }

                      In this situation keypair.sign(keypair.publicKey() + input_message) looks like a better alternative to double-hashing to me.

                      Once again, when it is about login/authentication (automatic signing) I would prevent any kind of text input as it may have legal value in the future.

                      Legal implications definitely should be considered. The signing itself is very simple and robust way to confirm the identity or secret key ownership, so I don't want to give up on it so easily.

                        OrbitLens

                        Legal implications definitely should be considered. The signing itself is very simple and robust way to confirm the identity or secret key ownership, so I don't want to give up on it so easily.

                        You are absolutely right. This is precisely the reason why they start to be considered a legal proof of identity/ownership by administrations.

                        Using it as a login/authentication means is great: it is clearly something we want to do. It is done right only if it doesn't collide with legal use cases that we'll need to support as well at some point (contract signing).

                        For login a number big enough to prevent collision appended to the site domain is enough: you don't need to accept any abritrary data and you can specify the number to be a certain length that is not 256. This also have the benefit that external service would more likely use the feature in a proper way.

                        keypair.sign(keypair.publicKey() + message)

                        This works as long as you enforce message to be non-empty (or the DKIF weakening attack is possible again).

                        Maybe

                        keypair.sign(domain + message)

                        Would do better. It also greatly reduce chances of collision, because no cross-domain collision could happen anymore. This imply that requester website let the document.referer field set. I'm not sure if it can be handled properly by installed software/applications, though.

                          MisterTicot keypair.sign(keypair.publicKey() + message)

                          This works as long as you enforce message to be non-empty (or the DKIF weakening attack is possible again).

                          Maybe

                          keypair.sign(domain + message)

                          Would do better. It also greatly reduce chances of collision, because no cross-domain collision could happen anymore. This imply that requester website let the document.referer field set. I'm not sure if it can be handled properly by installed software/applications, though.

                          Message signing isn't only done for specific domains.

                          MisterTicot Once again, when it is about login/authentication (automatic signing) I would prevent any kind of text input as it may have legal value in the future.

                          What do you mean by this?

                            dzham

                            There's a use case of blockchain that is signing legal contracts and storing signatures on on-chains. Voting can also be implemented as signing a specific piece of data. If your application automatically sign arbitrary messages I can abuse it. This is why I think automatical signing should be restricted to meaningless numbers.

                            Message signing isn't only done for specific domains.

                            Can you please elaborate on that?

                              MisterTicot Can you please elaborate on that?

                              Message signing can be use for absolutely anything. I don't see why you'd want to restrict that.
                              I'm using is for applications that don't come from a specific domain, e.g.

                              MisterTicot This is why I think automatical signing should be restricted to meaningless numbers.

                              How do you differentiate meaningless numbers from meaningful numbers?
                              If I give you a number I want you to sign, it definitely has meaning to me

                                dzham

                                How do you differentiate meaningless numbers from meaningful numbers?
                                If I give you a number I want you to sign, it definitely has meaning to me

                                Not necessarily. Basically I can differentiate 2 use cases:

                                • Signing for the purpose of login/authentification. What you're actually signing doesn't matter in itself. What matters is to prevent collision to ensure that old signatures can't be re-used by illegitimate party. Here, you wouldn't display the data you're signing because it is likely cryptic and meaningless. What you would ask to user is his agreement to authenticate himself to a given service. Here, you could make use automatic signing (such as "automatically log me in").
                                • Signing for the purpose of accepting a contract, claiming authorship, voting and so on. What you sign is what matters. Collision doesn't, in the meaning that you could very sign several time the same statement (typically "I can legally buy securities in my country."). Here, you must display what is about to be signed to the user. What you ask for is his agreement about the data being signed regardless of which service did issue it. This kind of data should never be signed automatically or without user consent.

                                As you can see both use case are symmetrically opposed so I think it would be better handled by two separate interfaces. One should ensure there's no collision between them to prevent abuse.

                                It is still not clear to me which use cases you're trying to cover right now. Could you please give me example of cases were you would sign messages unrelated to a specific domain?

                                15 days later

                                Update 2018-08-31

                                • Publicly released stable development version. Check the repository here.
                                • Improved security: secret (request secret key) intent removed.
                                • New pay intent added.
                                • SEP-0007 support added.
                                • Fixed potential vulnerability with transaction hash signing via sign_msg intent.

                                I faced some problems implementing SEP-0007 standard. Maybe someone knows other SEP-0007 signer open-source implementations?