Discussion:
[bitcoin-dev] Hardware Wallet Standard
Jonas Schnelli via bitcoin-dev
2016-08-16 14:10:04 UTC
Permalink
Hi

Unfortunately, there is no standard in how desktop- or mobile-wallets
can interact with a hardware device resulting in wallet vendors adding
plugins with proprietary code for non-standardized interfaces.

I started a BIP (extreme draft, feel free to improve language, grammar
and content) to address this missing part of the ecosystem.

I think it would be extremely helpful if @ledger, @trezor,
@voisin/@breadwallet, @electrum, @bitpay (and more?!) would help working
on a such standard.

The BIP describes two approaches how to communicate (pipe and
URI-scheme) with the signing-devices app, although, in my opinion, all
major platform do support the URI approach (maybe we could drop the pipe
approach then).
The URI approach means that there is no need to configure the
application location in order to start a inter-process(-app) communication.

Mediawiki:
https://github.com/jonasschnelli/bips/blob/8abb51f0b21b6664388f6e88f6fd642c90d25dca/bip-undef-0.mediawiki

</jonas>


---- BIP (rough early stage draft)

<pre>
BIP: ???
Title: Detached Signing
Author: Jonas Schnelli <***@jonasschnelli.ch>
Status: Draft (early stage!)
Type: Standards Track
Created: 2016-08-02
</pre>

== Abstract ==

This BIP describes a way how wallet applications can decouple sensitive
privatekeys from the internal keychain and interact with a
signing-devices (hardware wallet, "cold" storage) over a generic
interface in order to get signatures.

== Motivation ==

It seems like that the current approach for allowing signing-devices to
interact with third party wallets is to build a plugin [1][2][3]. Adding
plugins for each hardware wallet type will increase possible security
issues and result in multiple proprietary-third-party code within the
wallet application with very similar structures.

A generic interface how wallets can interact with signing-devices would
result in better user experience, less critical code and simpler
adaption for various signing-devices.

== Specification ==

In order to support desktop- and smartphone-wallet-applications, this
BIP describes two slightly different approaches (process pipe and URI
call) in how to interact with the signing-devices. If possible, the
modern URI approach should be chosen.

=== Signing-Device-Controller-Application ===

To allow a generic interface while still allowing different ways how to
internally communicate with the signing device itself (USB, TCP/IP,
air-gapped Qr-Code scanning, etc.) a controller-application is required.

=== General signing process ===

The wallets signing process must be according the following principal:
* Wallet prepares signing-request-object including bitcoin-transaction
or message together with metadata (scriptPubKey, hd-keypath of the inputs)
* Wallet passes signing-request-object to the
signing-device-controller-application
* Signing-device-controller-application processes
signing-request-object, eventually shows UI, user can sign or cancel
* Signing-device-controller-application sends back
signing-response-object with signatures or an error
* Wallet processes signing-response-object and completes data-object
creating process (example: add signatures to transaction and broadcast)

=== Desktop Process Intercommunication ===

Desktop wallets can interact with a signing device over process
intercommunication (pipe) together with a
signing-device-controller-application.
As specified below, the signing-request-object is a URI string passed
through the pipe. The desktop wallet needs to wait (with a recommended
timeout between 1 and 5 minutes) until the signing-response-object will
be sent back by the signing-device-controller-application.

=== Smartphone/URI App Intercommunication ===

Smartphones and modern operating systems are trying to sandbox
applications and interprocess communication (on pipe level) is mostly
disallowed.
On smartphones, we must use URI-schemes.
The wallet can pass information to the
signing-device-controller-application by using a predefined URI scheme.

<code>detatchedsigning://<command>?<querystring>&returnurischeme=<returnurischeme://></code>

The <code>querystring</code> must be URI encoded.
RFC 2616 does not specify a maximum length of URIs (get request). Most
modern smartphone operating system allow URIs up to serval megabytes.
Signing complex data-structure is therefore possible.

The <code>returnurischeme</code> must contain a URI schema where the
result of the signing process should be returned to.
The returnurischeme must be populated and "opened" once the signing
process has been completed (or cancled).

=== Signing Request ===

The signing request is a flexible URI-Query-String that will be used by
the Signing-device-controller-application for user confirmation as well
as for creating the signature.

The URI-query-string must conform to the following format:

<code>detatchedsigning://sign?type=<bitcoin-p2pkh|bitcoin-p2sh|bitcoin-msg>&data=<raw-transaction|message>&inputscripts=<scriptPubKey-input0>,<scriptPubKey-input1>,...&inputhdkeypath=<hdkeypath0>,<hdkeypath1>,...&returnscheme=<returnurischeme></code>

type = type of the data to sign
data = raw unsigned bitcoin transaction or text-message
(optional)inputscripts = scriptPubKey(s) of the inputs in exact order
(optional)inputhdkeypath = hd-keypath of the inputs in exact order
(optional)returnscheme = a URI scheme where the response must be sent to
(smartphone approach)

* inputhdkeypath or inputscripts must be provided.

=== Signing Response ===

The signing response is a flexible URI-Query-String that will be sent
back to the wallet application and must contain the signatures or an
error code.
The URI-query-string can be opened (smartphone approach) or will be sent
back though the interprocess pipe.

<code><returnurischeme>://signresponse?errorcode=<errorcode>&signatures=<signature-input0>,<signature-input0>,...</code>

In case of ECDSA, the returned signatures must be normalized compact
signatures with the size of 64bytes (128 hex chars).

==== Possible error code ====

0 = no error
1 = user canceled
2 = timeout
10 = missing key identifier (missing HD keypath or input scriptpubkey)
11 = unsupported signing type
12 = could not resolve script
50 = unknown internal error


==== Examples ====

===== Simple p2pkh transaction =====
Unsigned raw transaction:
<code>0100000001fd3cd19d0fb7dbb5bff148e6d3e18bc42cc49a76ed2bfd7d760ad1d7907fd9ce0100000000ffffffff0100e1f505000000001976a9149062e542a78d4fe00dcf7cca89c24a8013c381a388ac00000000</code>
(input ced97f90d7d10a767dfd2bed769ac42cc48be1d3e648f1bfb5dbb70f9dd13cfd
vout:1, output: P2PKH mtgQ54Uf3iRTc9kq18rw9SJznngvF5ryZn 1 BTC)

signing-request URI must be:
<code>detatchedsigning://sign?type=bitcoin-p2pkh&data=0100000001fd3cd19d0fb7dbb5bff148e6d3e18bc42cc49a76ed2bfd7d760ad1d7907fd9ce0100000000ffffffff0100e1f505000000001976a9149062e542a78d4fe00dcf7cca89c24a8013c381a388ac00000000&inputscripts=76a914531148ad17fdbffd4bac72d43deea6c7cf0387d088ac&inputhdkeypath=m/0'/0'/1&returnscheme=myapp</code>
The <code>inputhdkeypath</code> is optional in this case

signing-response URI must be:
<code>detatchedsigning://signresponse?error=0&signatures=<128hex-chars></code>

===== Simple a bitcoin message =====
Message: <code>Lorem ipsum dolor sit amet</code>

signing-request URI must be:
<code>detatchedsigning://sign?type=bitcoinmsg&data=Lorem+ipsum+dolor+sit+amet&inputhdkeypath=m/0'/0'/2</code>

signing-response URI must be:
<code>detatchedsigning://signresponse?error=0&signatures=<128hex-chars></code>

=== Support for multiple signing-devices ===
Must operating systems allow only one registered application per
URI-scheme. To support multiple signing-devices, wallets and
signing-devices can optional add support for brand based URI-schemes.

In addition to the standard URI scheme,
signing-devices-controller-applications can register an additional URI
scheme (with the identical request/response syntax and logic) including
a brand-identifier.

Registering a brand-identifier based URI scheme without registering the
default URI scheme is not allowed.

Wallets can detect if a certain brand based URI scheme is supported and
therefore gives user a selection if multiple signing-devices where
detected [4][5].

<code>detatchedsigning<brandid>://</code>

Supported brand-identifiers are:
* trezor
* ledger
* keepkey
* digitalbitbix

== References ==
[1] https://github.com/spesmilo/electrum/pull/1662
[2] https://github.com/spesmilo/electrum/pull/1391
[3] https://github.com/bitpay/copay/pull/3143
[4]
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/
[5]
https://developer.android.com/reference/android/content/pm/PackageManager.html
== Acknowledgements ==

== Copyright ==
This work is placed in the public domain.
Pavol Rusnak via bitcoin-dev
2016-08-16 14:48:53 UTC
Permalink
I think it does not make sense to try to get this standardized for
current Bitcoin transactions. They are just too complex.

What might be interesting is to have something similar for Segwit and
Lightning transactions.

* TREZOR performs extended validation of the inputs, when all of
prev-txs are streamed into the device and validated. Your standard does
not tackle this at all and I don't think it's worthy to make this
standard unnecessarily complicated.
--
Best Regards / S pozdravom,

Pavol "stick" Rusnak
SatoshiLabs.com
Jonas Schnelli via bitcoin-dev
2016-08-16 15:13:33 UTC
Permalink
Post by Pavol Rusnak via bitcoin-dev
I think it does not make sense to try to get this standardized for
current Bitcoin transactions. They are just too complex.
What might be interesting is to have something similar for Segwit and
Lightning transactions.
* TREZOR performs extended validation of the inputs, when all of
prev-txs are streamed into the device and validated. Your standard does
not tackle this at all and I don't think it's worthy to make this
standard unnecessarily complicated.
I'm aware of this approach but I don't think this makes sense long term.
We need a better way on the protocol level to validate inputs amounts
(where segwit is a first step towards this).

IMO, not having a standard for hardware wallet interfaces/communication
will long term result in reducing the end user experience.

I think we should collaborate together and work out a standard.

My goal is to add hardware wallet support in Bitcoin-Core where adding
proprietary code (plugin-ish) is something we don't want to do for the
sake of security and compatibility.

As said, the "BIP" is very draft and I'm happy to include the input
streaming as part of it (or you could add it if you want because you
have more experience with it).

</jonas>
Pavol Rusnak via bitcoin-dev
2016-08-16 15:21:57 UTC
Permalink
Post by Jonas Schnelli via bitcoin-dev
I'm aware of this approach but I don't think this makes sense long term.
We need a better way on the protocol level to validate inputs amounts
(where segwit is a first step towards this).
So you basically rephrased what I am saying but in another words.
Post by Jonas Schnelli via bitcoin-dev
I think we should collaborate together and work out a standard.
I am for it. I am just saying we should create a standard for new forms
of transactions (Segwit and maybe Lightning), not the current "ugly" ones.
--
Best Regards / S pozdravom,

Pavol "stick" Rusnak
SatoshiLabs.com
Jochen Hoenicke via bitcoin-dev
2016-08-16 17:48:27 UTC
Permalink
Hello Jonas,

thanks for your efforts of writing the draft for the standard.

First, this only describes detached signing. A wallet also needs to
connect with a hardware wallet at some time to learn the xpubs
controlled by the hardware. Do you plan to have this in a separate
standard or should this also be included here? Basically one needs one
operation: get xpub for an HD path.

From a first read over the specification I found the following points
missing, that a fully checking hardware wallet needs to know:

- the amount spent by each input (necessary for segwit).
- the full serialized input transactions (without witness informations)
to prove that the amount really matches (this is not necessary for segwit)
- the position of the change output and its HD Path (to verify that it
really is a change output).
- For multisig change addresses, there are more extensive checks
necessary: All inputs must be multisig addresses signed with public
keys derived from the same set of xpubs as the change address and use
the same "m of n" scheme. So for multisig inputs and multisig change
address the standard should allow to give the parent xpubs of the other
public keys and their derivation paths.

It is also a bit ambiguous what the "inputscript" is especially for p2sh
transactions. Is this always the scriptPubKey of the transaction output
that is spent by this input? For p2wsh nested in BIP16 p2sh transactions
there are three scripts

witness: 0 <signature1> <1 <pubkey1> <pubkey2> 2 CHECKMULTISIG>
scriptSig: <0 <32-byte-hash>>
(0x220020{32-byte-hash})
scriptPubKey: HASH160 <20-byte-hash> EQUAL
(0xA914{20-byte-hash}87)
(quoted from BIP-141).

In principle one could put witness and scriptSig (with "OP_FALSE" in
places of the signatures) in the raw transaction and make inputscript
always the scriptPubKey of the corresponding output. Then one also
doesn't need to distinguish between p2pkh or p2sh or p2wpkh or "p2wpkh
nested in bip16 p2sh" transactions.

Regards,
Jochen
Thomas Kerin via bitcoin-dev
2016-08-17 00:25:29 UTC
Permalink
Hi all,

Thanks again Jonas for starting this!

I worked on a similar proposal a while back (never posted), approaching
the same problem as if a merchant's website accepted xpubs/public keys,
created multi-signature addresses, and wanted the user to easily sign
offline instead of using some javascript code / using Core's debug
console / coinb.in

Happily the procedure is largely the same, though I would echo Jochen's
point that there needs to be a way to request an xpub/public key.

The redeemScript and witnessScript are also required fields for full
validation & signing a transaction input if it's P2SH, or just the
witnessScript if it's bare V0_P2WSH

Since the output amounts are required, so maybe instead provide
serialized TxOut's? or Utxo's i.e: [txid, vout, amount, scriptPubKey].

The protocol ought to be as stateless as possible - it can't be assumed
whether the redeemScript and other details will ever be saved on the
device - so perhaps provide the redeemScript + witnessScript as the
final fields on the Utxo structure above.

I do think it enables two important choices for bitcoin users:

* it might be preferable to provide your own xpub vs generating a brand
new HD key to potentially lose.

* you could leverage the services provided by [random example]
GreenAddress without necessarily having to rely on signing code provided
by them, and so end up only having to trust only one ECDSA
implementation when interacting with a wide number of services

All the best

Thomas
Post by Jochen Hoenicke via bitcoin-dev
Hello Jonas,
thanks for your efforts of writing the draft for the standard.
First, this only describes detached signing. A wallet also needs to
connect with a hardware wallet at some time to learn the xpubs
controlled by the hardware. Do you plan to have this in a separate
standard or should this also be included here? Basically one needs one
operation: get xpub for an HD path.
From a first read over the specification I found the following points
- the amount spent by each input (necessary for segwit).
- the full serialized input transactions (without witness informations)
to prove that the amount really matches (this is not necessary for segwit)
- the position of the change output and its HD Path (to verify that it
really is a change output).
- For multisig change addresses, there are more extensive checks
necessary: All inputs must be multisig addresses signed with public
keys derived from the same set of xpubs as the change address and use
the same "m of n" scheme. So for multisig inputs and multisig change
address the standard should allow to give the parent xpubs of the other
public keys and their derivation paths.
It is also a bit ambiguous what the "inputscript" is especially for p2sh
transactions. Is this always the scriptPubKey of the transaction output
that is spent by this input? For p2wsh nested in BIP16 p2sh transactions
there are three scripts
witness: 0 <signature1> <1 <pubkey1> <pubkey2> 2 CHECKMULTISIG>
scriptSig: <0 <32-byte-hash>>
(0x220020{32-byte-hash})
scriptPubKey: HASH160 <20-byte-hash> EQUAL
(0xA914{20-byte-hash}87)
(quoted from BIP-141).
In principle one could put witness and scriptSig (with "OP_FALSE" in
places of the signatures) in the raw transaction and make inputscript
always the scriptPubKey of the corresponding output. Then one also
doesn't need to distinguish between p2pkh or p2sh or p2wpkh or "p2wpkh
nested in bip16 p2sh" transactions.
Regards,
Jochen
_______________________________________________
bitcoin-dev mailing list
https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
Hello Jonas,
thanks for your efforts of writing the draft for the standard.
First, this only describes detached signing. A wallet also needs to
connect with a hardware wallet at some time to learn the xpubs
controlled by the hardware. Do you plan to have this in a separate
standard or should this also be included here? Basically one needs one
operation: get xpub for an HD path.
From a first read over the specification I found the following points
- the amount spent by each input (necessary for segwit).
- the full serialized input transactions (without witness informations)
to prove that the amount really matches (this is not necessary for segwit)
- the position of the change output and its HD Path (to verify that it
really is a change output).
- For multisig change addresses, there are more extensive checks
necessary: All inputs must be multisig addresses signed with public
keys derived from the same set of xpubs as the change address and use
the same "m of n" scheme. So for multisig inputs and multisig change
address the standard should allow to give the parent xpubs of the other
public keys and their derivation paths.
It is also a bit ambiguous what the "inputscript" is especially for p2sh
transactions. Is this always the scriptPubKey of the transaction output
that is spent by this input? For p2wsh nested in BIP16 p2sh transactions
there are three scripts
witness: 0 <signature1> <1 <pubkey1> <pubkey2> 2 CHECKMULTISIG>
scriptSig: <0 <32-byte-hash>>
(0x220020{32-byte-hash})
scriptPubKey: HASH160 <20-byte-hash> EQUAL
(0xA914{20-byte-hash}87)
(quoted from BIP-141).
In principle one could put witness and scriptSig (with "OP_FALSE" in
places of the signatures) in the raw transaction and make inputscript
always the scriptPubKey of the corresponding output. Then one also
doesn't need to distinguish between p2pkh or p2sh or p2wpkh or "p2wpkh
nested in bip16 p2sh" transactions.
Regards,
Jochen
_______________________________________________
bitcoin-dev mailing list
https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
Jonas Schnelli via bitcoin-dev
2016-08-17 07:24:46 UTC
Permalink
Hi all

Thanks for the response.


Jochen's points:
===============
Indeed. There are some missing points and I'd like to work this into the
BIP. Thanks for bringing this up.

Along with a support for wallet-creation with a xpub from the signing
device, we might also want to support loading multiple pubkeys into a
keypool from the device (in case someone likes to use hardened
derivation at all levels). I guess this would not be over-complex to
achieve.

Luke's points:
=============

USB / Plugin/Driver problematic
-------------------------------
I don't think it would be wise to set Trezors USB communication
(hardware interface) as "the standard". A) A USB stack/interaction in
wallets should be avoided IMO. B) This approach won't work for some
platforms (like iOS) due to technical and legal restrictions.

In my opinion, each hardware wallet has to provide custom software in
any case. We don't want to standardize how a hardware wallet has to do
backups, recovers, firmware upgrade, etc. and if we agree on that, then
hardware wallets must provide an application (mostly Chrome extensions
today) to implement theses processes.

Also diversity at the hardware interface will reduce centralized risks
for weak security/vulnerabilities.

The proposed URI scheme approach does not require any sorts of
libraries/dependencies. USB HID can be a problem for cross platform
desktop wallets as well as it won't work of one of the major mobile
platform (iOS). USB HID interaction can be restricted or disabled in non
superuser setups where I'm not aware of any restriction on URI-Scheme level.

URI scheme instead of stdio/pipe
--------------------------------
The URI scheme is not ugly. Its a modern way – implemented in almost all
platforms – how applications can interact with each other while not
directly knowing each other. Registering a URI scheme like "bitcoin://"
has some concrete advantages over just piping through stdio.

Also, the stdio/piping approach does not work for mobile platforms
(where the URI scheme works).

The URI scheme does not require any sorts of wallet app level
configuration (where the stdio/pipe approach would require to configure
some details about the used hardware wallet).


Thomase D.'s points:
===================
Standardizing to many layers of the interaction stack (including the
hardware interaction) will very likely result in vendors not sticking to
the standard.

I agree, the URI scheme has some fragility, but at a level where we can
handle it and with the advantage of abstracting the used brand/device
for privacy and security reasons.
Post by Thomas Daede via bitcoin-dev
The existing URI scheme, while allowing disambiguate by manufacturer,
provides no way to to enumerate available manufacturers or enabled
wallets.

Most operating systems allow to check if a certain URL-Scheme is
supported (registered), this would allow at least to check for known
major vendors (like trezor, etc.) which should solve most
multi-hardware-wallet use-cases.

The URI return scheme does work fine and with the correct set timeouts
it should result in a neat user experience.
It's the proposed way of application intercommunication in Apple iOS [1]
and Google Android [2].

Conclusion:
===========
* Non of the points convinced me that there is a better alternative to
the proposed URI scheme interaction (please tell me if I'm stubborn).
* Also, we should move the end users UX in the center of the
problems-to-solve (and not overweight the ideal
code-/API-/hardware-interaction-design while ignoring the end user
experience).
* We should try to not over-standardize the interaction with the device
itself to allow flexibility on the hardware wallet vendor side.

[1]
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html
[2] https://developer.android.com/training/basics/intents/sending.html

</jonas>
Nicolas Bacca via bitcoin-dev
2016-08-17 07:40:58 UTC
Permalink
On Wed, Aug 17, 2016 at 9:24 AM, Jonas Schnelli via bitcoin-dev <
Post by Jonas Schnelli via bitcoin-dev
===========
* Non of the points convinced me that there is a better alternative to
the proposed URI scheme interaction (please tell me if I'm stubborn).
I'd also agree with this - and it's convenient to test against simulators /
mock