Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
78375608
Commit
78375608
authored
Feb 22, 2018
by
Nick Johnson
Committed by
Guillaume Ballet
Apr 08, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
accounts, internal: Changes in response to review
parent
f7027dd6
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
137 additions
and
118 deletions
+137
-118
hd.go
accounts/hd.go
+4
-4
apdu.go
accounts/scwallet/apdu.go
+12
-12
hub.go
accounts/scwallet/hub.go
+28
-11
securechannel.go
accounts/scwallet/securechannel.go
+36
-36
wallet.go
accounts/scwallet/wallet.go
+55
-55
api.go
internal/ethapi/api.go
+2
-0
No files found.
accounts/hd.go
View file @
78375608
...
...
@@ -139,12 +139,12 @@ func (path DerivationPath) MarshalJSON() ([]byte, error) {
return
[]
byte
(
fmt
.
Sprintf
(
"
\"
%s
\"
"
,
path
.
String
())),
nil
}
func
(
dp
*
DerivationPath
)
UnmarshalJSON
(
b
[]
byte
)
error
{
var
path
string
func
(
path
*
DerivationPath
)
UnmarshalJSON
(
b
[]
byte
)
error
{
var
dp
string
var
err
error
if
err
=
json
.
Unmarshal
(
b
,
&
path
);
err
!=
nil
{
if
err
=
json
.
Unmarshal
(
b
,
&
dp
);
err
!=
nil
{
return
err
}
*
dp
,
err
=
ParseDerivationPath
(
path
)
*
path
,
err
=
ParseDerivationPath
(
dp
)
return
err
}
accounts/scwallet/apdu.go
View file @
78375608
...
...
@@ -22,20 +22,20 @@ import (
)
const
(
CLA_
ISO7816
=
0
cla
ISO7816
=
0
INS_SELECT
=
0xA4
INS_GET_RESPONSE
=
0xC0
INS_PAIR
=
0x12
INS_UNPAIR
=
0x13
INS_OPEN_SECURE_CHANNEL
=
0x10
INS_MUTUALLY_AUTHENTICATE
=
0x11
insSelect
=
0xA4
insGetResponse
=
0xC0
insPair
=
0x12
insUnpair
=
0x13
insOpenSecureChannel
=
0x10
insMutuallyAuthenticate
=
0x11
SW1_GET_RESPONSE
=
0x61
SW1_OK
=
0x90
sw1GetResponse
=
0x61
sw1Ok
=
0x90
)
// CommandAPDU represents an application data unit sent to a smartcard
// CommandAPDU represents an application data unit sent to a smartcard
.
type
CommandAPDU
struct
{
Cla
,
Ins
,
P1
,
P2
uint8
// Class, Instruction, Parameter 1, Parameter 2
Data
[]
byte
// Command data
...
...
@@ -72,13 +72,13 @@ func (ca CommandAPDU) serialize() ([]byte, error) {
return
buf
.
Bytes
(),
nil
}
// ResponseAPDU represents an application data unit received from a smart card
// ResponseAPDU represents an application data unit received from a smart card
.
type
ResponseAPDU
struct
{
Data
[]
byte
// response data
Sw1
,
Sw2
uint8
// status words 1 and 2
}
// deserialize deserializes a response APDU
// deserialize deserializes a response APDU
.
func
(
ra
*
ResponseAPDU
)
deserialize
(
data
[]
byte
)
error
{
ra
.
Data
=
make
([]
byte
,
len
(
data
)
-
2
)
...
...
accounts/scwallet/hub.go
View file @
78375608
...
...
@@ -14,6 +14,22 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// This package implements support for smartcard-based hardware wallets such as
// the one written by Status: https://github.com/status-im/hardware-wallet
//
// This implementation of smartcard wallets have a different interaction process
// to other types of hardware wallet. The process works like this:
//
// 1. (First use with a given client) Establish a pairing between hardware
// wallet and client. This requires a secret value called a 'PUK'. You can
// pair with an unpaired wallet with `personal.openWallet(URI, PUK)`.
// 2. (First use only) Initialize the wallet, which generates a keypair, stores
// it on the wallet, and returns it so the user can back it up. You can
// initialize a wallet with `personal.initializeWallet(URI)`.
// 3. Connect to the wallet using the pairing information established in step 1.
// You can connect to a paired wallet with `personal.openWallet(URI, PIN)`.
// 4. Interact with the wallet as normal.
package
scwallet
import
(
...
...
@@ -32,6 +48,7 @@ import (
"github.com/ethereum/go-ethereum/log"
)
// Scheme is the URI prefix for smartcard wallets.
const
Scheme
=
"pcsc"
// refreshCycle is the maximum time between wallet refreshes (if USB hotplug
...
...
@@ -41,9 +58,9 @@ const refreshCycle = 5 * time.Second
// refreshThrottling is the minimum time between wallet refreshes to avoid thrashing.
const
refreshThrottling
=
500
*
time
.
Millisecond
//
S
martcardPairing contains information about a smart card we have paired with
// or might pair withub.
type
S
martcardPairing
struct
{
//
s
martcardPairing contains information about a smart card we have paired with
// or might pair with
the h
ub.
type
s
martcardPairing
struct
{
PublicKey
[]
byte
`json:"publicKey"`
PairingIndex
uint8
`json:"pairingIndex"`
PairingKey
[]
byte
`json:"pairingKey"`
...
...
@@ -56,7 +73,7 @@ type Hub struct {
context
*
scard
.
Context
datadir
string
pairings
map
[
string
]
S
martcardPairing
pairings
map
[
string
]
s
martcardPairing
refreshed
time
.
Time
// Time instance when the list of wallets was last refreshed
wallets
map
[
string
]
*
Wallet
// Mapping from reader names to wallet instances
updateFeed
event
.
Feed
// Event feed to notify wallet additions/removals
...
...
@@ -71,7 +88,7 @@ type Hub struct {
var
HubType
=
reflect
.
TypeOf
(
&
Hub
{})
func
(
hub
*
Hub
)
readPairings
()
error
{
hub
.
pairings
=
make
(
map
[
string
]
S
martcardPairing
)
hub
.
pairings
=
make
(
map
[
string
]
s
martcardPairing
)
pairingFile
,
err
:=
os
.
Open
(
hub
.
datadir
+
"/smartcards.json"
)
if
err
!=
nil
{
if
os
.
IsNotExist
(
err
)
{
...
...
@@ -84,7 +101,7 @@ func (hub *Hub) readPairings() error {
if
err
!=
nil
{
return
err
}
var
pairings
[]
S
martcardPairing
var
pairings
[]
s
martcardPairing
if
err
:=
json
.
Unmarshal
(
pairingData
,
&
pairings
);
err
!=
nil
{
return
err
}
...
...
@@ -101,7 +118,7 @@ func (hub *Hub) writePairings() error {
return
err
}
pairings
:=
make
([]
S
martcardPairing
,
0
,
len
(
hub
.
pairings
))
pairings
:=
make
([]
s
martcardPairing
,
0
,
len
(
hub
.
pairings
))
for
_
,
pairing
:=
range
hub
.
pairings
{
pairings
=
append
(
pairings
,
pairing
)
}
...
...
@@ -118,7 +135,7 @@ func (hub *Hub) writePairings() error {
return
pairingFile
.
Close
()
}
func
(
hub
*
Hub
)
getPairing
(
wallet
*
Wallet
)
*
S
martcardPairing
{
func
(
hub
*
Hub
)
getPairing
(
wallet
*
Wallet
)
*
s
martcardPairing
{
pairing
,
ok
:=
hub
.
pairings
[
string
(
wallet
.
PublicKey
)]
if
ok
{
return
&
pairing
...
...
@@ -126,7 +143,7 @@ func (hub *Hub) getPairing(wallet *Wallet) *SmartcardPairing {
return
nil
}
func
(
hub
*
Hub
)
setPairing
(
wallet
*
Wallet
,
pairing
*
S
martcardPairing
)
error
{
func
(
hub
*
Hub
)
setPairing
(
wallet
*
Wallet
,
pairing
*
s
martcardPairing
)
error
{
if
pairing
==
nil
{
delete
(
hub
.
pairings
,
string
(
wallet
.
PublicKey
))
}
else
{
...
...
@@ -158,7 +175,7 @@ func NewHub(scheme string, datadir string) (*Hub, error) {
return
hub
,
nil
}
// Wallets implements accounts.Backend, returning all the currently tracked
USB
// Wallets implements accounts.Backend, returning all the currently tracked
// devices that appear to be hardware wallets.
func
(
hub
*
Hub
)
Wallets
()
[]
accounts
.
Wallet
{
// Make sure the list of wallets is up to date
...
...
@@ -176,7 +193,7 @@ func (hub *Hub) Wallets() []accounts.Wallet {
return
cpy
}
// refreshWallets scans the
USB
devices attached to the machine and updates the
// refreshWallets scans the devices attached to the machine and updates the
// list of wallets based on the found devices.
func
(
hub
*
Hub
)
refreshWallets
()
{
elapsed
:=
time
.
Since
(
hub
.
refreshed
)
...
...
accounts/scwallet/securechannel.go
View file @
78375608
...
...
@@ -32,15 +32,15 @@ import (
)
const
(
MAX_PAYLOAD_SIZE
=
223
PAIR_P1_FIRST_STEP
=
0
PAIR_P1_LAST_STEP
=
1
maxPayloadSize
=
223
pairP1FirstStep
=
0
pairP1LastStep
=
1
SC_SECRET_LENGTH
=
32
SC_BLOCK_SIZE
=
16
scSecretLength
=
32
scBlockSize
=
16
)
// SecureChannelSession enables secure communication with a hardware wallet
// SecureChannelSession enables secure communication with a hardware wallet
.
type
SecureChannelSession
struct
{
card
*
scard
.
Card
// A handle to the smartcard for communication
secret
[]
byte
// A shared secret generated from our ECDSA keys
...
...
@@ -52,7 +52,7 @@ type SecureChannelSession struct {
PairingIndex
uint8
// The pairing index
}
// NewSecureChannelSession creates a new secure channel for the given card and public key
// NewSecureChannelSession creates a new secure channel for the given card and public key
.
func
NewSecureChannelSession
(
card
*
scard
.
Card
,
keyData
[]
byte
)
(
*
SecureChannelSession
,
error
)
{
// Generate an ECDSA keypair for ourselves
gen
:=
ecdh
.
NewEllipticECDH
(
crypto
.
S256
())
...
...
@@ -78,7 +78,7 @@ func NewSecureChannelSession(card *scard.Card, keyData []byte) (*SecureChannelSe
},
nil
}
// Pair establishes a new pairing with the smartcard
// Pair establishes a new pairing with the smartcard
.
func
(
s
*
SecureChannelSession
)
Pair
(
sharedSecret
[]
byte
)
error
{
secretHash
:=
sha256
.
Sum256
(
sharedSecret
)
...
...
@@ -87,7 +87,7 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
return
err
}
response
,
err
:=
s
.
pair
(
PAIR_P1_FIRST_STEP
,
challenge
)
response
,
err
:=
s
.
pair
(
pairP1FirstStep
,
challenge
)
if
err
!=
nil
{
return
err
}
...
...
@@ -107,7 +107,7 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
md
.
Reset
()
md
.
Write
(
secretHash
[
:
])
md
.
Write
(
cardChallenge
)
response
,
err
=
s
.
pair
(
PAIR_P1_LAST_STEP
,
md
.
Sum
(
nil
))
response
,
err
=
s
.
pair
(
pairP1LastStep
,
md
.
Sum
(
nil
))
if
err
!=
nil
{
return
err
}
...
...
@@ -121,13 +121,13 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error {
return
nil
}
// Unpair disestablishes an existing pairing
// Unpair disestablishes an existing pairing
.
func
(
s
*
SecureChannelSession
)
Unpair
()
error
{
if
s
.
PairingKey
==
nil
{
return
fmt
.
Errorf
(
"Cannot unpair: not paired"
)
}
_
,
err
:=
s
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_UNPAIR
,
s
.
PairingIndex
,
0
,
[]
byte
{})
_
,
err
:=
s
.
TransmitEncrypted
(
claSCWallet
,
insUnpair
,
s
.
PairingIndex
,
0
,
[]
byte
{})
if
err
!=
nil
{
return
err
}
...
...
@@ -137,7 +137,7 @@ func (s *SecureChannelSession) Unpair() error {
return
nil
}
// Open initializes the secure channel
// Open initializes the secure channel
.
func
(
s
*
SecureChannelSession
)
Open
()
error
{
if
s
.
iv
!=
nil
{
return
fmt
.
Errorf
(
"Session already opened"
)
...
...
@@ -153,13 +153,13 @@ func (s *SecureChannelSession) Open() error {
md
:=
sha512
.
New
()
md
.
Write
(
s
.
secret
)
md
.
Write
(
s
.
PairingKey
)
md
.
Write
(
response
.
Data
[
:
SC_SECRET_LENGTH
])
md
.
Write
(
response
.
Data
[
:
scSecretLength
])
keyData
:=
md
.
Sum
(
nil
)
s
.
sessionEncKey
=
keyData
[
:
SC_SECRET_LENGTH
]
s
.
sessionMacKey
=
keyData
[
SC_SECRET_LENGTH
:
SC_SECRET_LENGTH
*
2
]
s
.
sessionEncKey
=
keyData
[
:
scSecretLength
]
s
.
sessionMacKey
=
keyData
[
scSecretLength
:
scSecretLength
*
2
]
// The IV is the last bytes returned from the Open APDU.
s
.
iv
=
response
.
Data
[
SC_SECRET_LENGTH
:
]
s
.
iv
=
response
.
Data
[
scSecretLength
:
]
if
err
:=
s
.
mutuallyAuthenticate
();
err
!=
nil
{
return
err
...
...
@@ -171,12 +171,12 @@ func (s *SecureChannelSession) Open() error {
// mutuallyAuthenticate is an internal method to authenticate both ends of the
// connection.
func
(
s
*
SecureChannelSession
)
mutuallyAuthenticate
()
error
{
data
:=
make
([]
byte
,
SC_SECRET_LENGTH
)
data
:=
make
([]
byte
,
scSecretLength
)
if
_
,
err
:=
rand
.
Read
(
data
);
err
!=
nil
{
return
err
}
response
,
err
:=
s
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_MUTUALLY_AUTHENTICATE
,
0
,
0
,
data
)
response
,
err
:=
s
.
TransmitEncrypted
(
claSCWallet
,
insMutuallyAuthenticate
,
0
,
0
,
data
)
if
err
!=
nil
{
return
err
}
...
...
@@ -184,18 +184,18 @@ func (s *SecureChannelSession) mutuallyAuthenticate() error {
return
fmt
.
Errorf
(
"Got unexpected response from MUTUALLY_AUTHENTICATE: 0x%x%x"
,
response
.
Sw1
,
response
.
Sw2
)
}
if
len
(
response
.
Data
)
!=
SC_SECRET_LENGTH
{
return
fmt
.
Errorf
(
"Response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d"
,
len
(
response
.
Data
),
SC_SECRET_LENGTH
)
if
len
(
response
.
Data
)
!=
scSecretLength
{
return
fmt
.
Errorf
(
"Response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d"
,
len
(
response
.
Data
),
scSecretLength
)
}
return
nil
}
// open is an internal method that sends an open APDU
// open is an internal method that sends an open APDU
.
func
(
s
*
SecureChannelSession
)
open
()
(
*
ResponseAPDU
,
error
)
{
return
transmit
(
s
.
card
,
&
CommandAPDU
{
Cla
:
CLA_SCWALLET
,
Ins
:
INS_OPEN_SECURE_CHANNEL
,
Cla
:
claSCWallet
,
Ins
:
insOpenSecureChannel
,
P1
:
s
.
PairingIndex
,
P2
:
0
,
Data
:
s
.
publicKey
,
...
...
@@ -203,11 +203,11 @@ func (s *SecureChannelSession) open() (*ResponseAPDU, error) {
})
}
// pair is an internal method that sends a pair APDU
// pair is an internal method that sends a pair APDU
.
func
(
s
*
SecureChannelSession
)
pair
(
p1
uint8
,
data
[]
byte
)
(
*
ResponseAPDU
,
error
)
{
return
transmit
(
s
.
card
,
&
CommandAPDU
{
Cla
:
CLA_SCWALLET
,
Ins
:
INS_PAIR
,
Cla
:
claSCWallet
,
Ins
:
insPair
,
P1
:
p1
,
P2
:
0
,
Data
:
data
,
...
...
@@ -215,7 +215,7 @@ func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*ResponseAPDU, error
})
}
// TransmitEncrypted sends an encrypted message, and decrypts and returns the response
// TransmitEncrypted sends an encrypted message, and decrypts and returns the response
.
func
(
s
*
SecureChannelSession
)
TransmitEncrypted
(
cla
,
ins
,
p1
,
p2
byte
,
data
[]
byte
)
(
*
ResponseAPDU
,
error
)
{
if
s
.
iv
==
nil
{
return
nil
,
fmt
.
Errorf
(
"Channel not open"
)
...
...
@@ -225,7 +225,7 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
if
err
!=
nil
{
return
nil
,
err
}
meta
:=
[]
byte
{
cla
,
ins
,
p1
,
p2
,
byte
(
len
(
data
)
+
SC_BLOCK_SIZE
),
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
}
meta
:=
[]
byte
{
cla
,
ins
,
p1
,
p2
,
byte
(
len
(
data
)
+
scBlockSize
),
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
}
if
err
=
s
.
updateIV
(
meta
,
data
);
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -263,17 +263,17 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
rapdu
:=
&
ResponseAPDU
{}
rapdu
.
deserialize
(
plainData
)
if
rapdu
.
Sw1
!=
SW1_OK
{
if
rapdu
.
Sw1
!=
sw1Ok
{
return
nil
,
fmt
.
Errorf
(
"Unexpected response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x"
,
cla
,
ins
,
rapdu
.
Sw1
,
rapdu
.
Sw2
)
}
return
rapdu
,
nil
}
// encryptAPDU is an internal method that serializes and encrypts an APDU
// encryptAPDU is an internal method that serializes and encrypts an APDU
.
func
(
s
*
SecureChannelSession
)
encryptAPDU
(
data
[]
byte
)
([]
byte
,
error
)
{
if
len
(
data
)
>
MAX_PAYLOAD_SIZE
{
return
nil
,
fmt
.
Errorf
(
"Payload of %d bytes exceeds maximum of %d"
,
len
(
data
),
MAX_PAYLOAD_SIZE
)
if
len
(
data
)
>
maxPayloadSize
{
return
nil
,
fmt
.
Errorf
(
"Payload of %d bytes exceeds maximum of %d"
,
len
(
data
),
maxPayloadSize
)
}
data
=
pad
(
data
,
0x80
)
...
...
@@ -288,7 +288,7 @@ func (s *SecureChannelSession) encryptAPDU(data []byte) ([]byte, error) {
return
ret
,
nil
}
// pad applies message padding to a 16 byte boundary
// pad applies message padding to a 16 byte boundary
.
func
pad
(
data
[]
byte
,
terminator
byte
)
[]
byte
{
padded
:=
make
([]
byte
,
(
len
(
data
)
/
16
+
1
)
*
16
)
copy
(
padded
,
data
)
...
...
@@ -296,7 +296,7 @@ func pad(data []byte, terminator byte) []byte {
return
padded
}
// decryptAPDU is an internal method that decrypts and deserializes an APDU
// decryptAPDU is an internal method that decrypts and deserializes an APDU
.
func
(
s
*
SecureChannelSession
)
decryptAPDU
(
data
[]
byte
)
([]
byte
,
error
)
{
a
,
err
:=
aes
.
NewCipher
(
s
.
sessionEncKey
)
if
err
!=
nil
{
...
...
@@ -310,7 +310,7 @@ func (s *SecureChannelSession) decryptAPDU(data []byte) ([]byte, error) {
return
unpad
(
ret
,
0x80
)
}
// unpad strips padding from a message
// unpad strips padding from a message
.
func
unpad
(
data
[]
byte
,
terminator
byte
)
([]
byte
,
error
)
{
for
i
:=
1
;
i
<=
16
;
i
++
{
switch
data
[
len
(
data
)
-
i
]
{
...
...
accounts/scwallet/wallet.go
View file @
78375608
...
...
@@ -42,7 +42,7 @@ import (
)
var
(
APPLET_AID
=
[]
byte
{
0x53
,
0x74
,
0x61
,
0x74
,
0x75
,
0x73
,
0x57
,
0x61
,
0x6C
,
0x6C
,
0x65
,
0x74
,
0x41
,
0x70
,
0x70
}
appletAID
=
[]
byte
{
0x53
,
0x74
,
0x61
,
0x74
,
0x75
,
0x73
,
0x57
,
0x61
,
0x6C
,
0x6C
,
0x65
,
0x74
,
0x41
,
0x70
,
0x70
}
AlreadyOpenError
=
errors
.
New
(
"Wallet already open"
)
PairingRequiredError
=
errors
.
New
(
"Pairing required with personal.openWallet(puk)"
)
PinRequiredError
=
errors
.
New
(
"Must unlock with personal.openWallet(pin)"
)
...
...
@@ -52,23 +52,23 @@ var (
)
const
(
CLA_SCWALLET
=
0x80
INS_VERIFY_PIN
=
0x20
INS_EXPORT_KEY
=
0xC2
INS_SIGN
=
0xC0
INS_LOAD_KEY
=
0xD0
INS_DERIVE_KEY
=
0xD1
INS_STATUS
=
0xF2
DERIVE_P1_ASSISTED
=
uint8
(
0x01
)
DERIVE_P1_APPEND
=
uint8
(
0x80
)
DERIVE_P2_KEY_PATH
=
uint8
(
0x00
)
DERIVE_P2_PUBLIC_KEY
=
uint8
(
0x01
)
STATUS_P1_WALLET_STATUS
=
uint8
(
0x00
)
STATUS_P1_PATH
=
uint8
(
0x01
)
SIGN_P1_PRECOMPUTED_HASH
=
uint8
(
0x01
)
SIGN_P2_ONLY_BLOCK
=
uint8
(
0x81
)
EXPORT_P1_ANY
=
uint8
(
0x00
)
EXPORT_P2_PUBKEY
=
uint8
(
0x01
)
claSCWallet
=
0x80
insVerifyPin
=
0x20
insExportKey
=
0xC2
insSign
=
0xC0
insLoadKey
=
0xD0
insDeriveKey
=
0xD1
insStatus
=
0xF2
deriveP1Assisted
=
uint8
(
0x01
)
deriveP1Append
=
uint8
(
0x80
)
deriveP2KeyPath
=
uint8
(
0x00
)
deriveP2PublicKey
=
uint8
(
0x01
)
statusP1WalletStatus
=
uint8
(
0x00
)
statusP1Path
=
uint8
(
0x01
)
signP1PrecomputedHash
=
uint8
(
0x01
)
signP2OnlyBlock
=
uint8
(
0x81
)
exportP1Any
=
uint8
(
0x00
)
exportP2Pubkey
=
uint8
(
0x01
)
// Minimum time to wait between self derivation attempts, even it the user is
// requesting accounts like crazy.
...
...
@@ -120,10 +120,10 @@ func transmit(card *scard.Card, command *CommandAPDU) (*ResponseAPDU, error) {
}
// Are we being asked to fetch the response separately?
if
response
.
Sw1
==
SW1_GET_RESPONSE
&&
(
command
.
Cla
!=
CLA_ISO7816
||
command
.
Ins
!=
INS_GET_RESPONSE
)
{
if
response
.
Sw1
==
sw1GetResponse
&&
(
command
.
Cla
!=
claISO7816
||
command
.
Ins
!=
insGetResponse
)
{
return
transmit
(
card
,
&
CommandAPDU
{
Cla
:
CLA_
ISO7816
,
Ins
:
INS_GET_RESPONSE
,
Cla
:
cla
ISO7816
,
Ins
:
insGetResponse
,
P1
:
0
,
P2
:
0
,
Data
:
nil
,
...
...
@@ -131,7 +131,7 @@ func transmit(card *scard.Card, command *CommandAPDU) (*ResponseAPDU, error) {
})
}
if
response
.
Sw1
!=
SW1_OK
{
if
response
.
Sw1
!=
sw1Ok
{
return
nil
,
fmt
.
Errorf
(
"Unexpected insecure response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x"
,
command
.
Cla
,
command
.
Ins
,
response
.
Sw1
,
response
.
Sw2
)
}
...
...
@@ -173,11 +173,11 @@ func (w *Wallet) connect() error {
// doselect is an internal (unlocked) function to send a SELECT APDU to the card.
func
(
w
*
Wallet
)
doselect
()
(
*
applicationInfo
,
error
)
{
response
,
err
:=
transmit
(
w
.
card
,
&
CommandAPDU
{
Cla
:
CLA_
ISO7816
,
Ins
:
INS_SELECT
,
Cla
:
cla
ISO7816
,
Ins
:
insSelect
,
P1
:
4
,
P2
:
0
,
Data
:
APPLET_
AID
,
Data
:
applet
AID
,
})
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -685,7 +685,7 @@ func (w *Wallet) findAccountPath(account accounts.Account) (accounts.DerivationP
return
accounts
.
ParseDerivationPath
(
parts
[
1
])
}
// Session represents a secured communication session with the wallet
// Session represents a secured communication session with the wallet
.
type
Session
struct
{
Wallet
*
Wallet
// A handle to the wallet that opened the session
Channel
*
SecureChannelSession
// A secure channel for encrypted messages
...
...
@@ -693,13 +693,13 @@ type Session struct {
}
// pair establishes a new pairing over this channel, using the provided secret.
func
(
s
*
Session
)
pair
(
secret
[]
byte
)
(
S
martcardPairing
,
error
)
{
func
(
s
*
Session
)
pair
(
secret
[]
byte
)
(
s
martcardPairing
,
error
)
{
err
:=
s
.
Channel
.
Pair
(
secret
)
if
err
!=
nil
{
return
S
martcardPairing
{},
err
return
s
martcardPairing
{},
err
}
return
S
martcardPairing
{
return
s
martcardPairing
{
PublicKey
:
s
.
Wallet
.
PublicKey
,
PairingIndex
:
s
.
Channel
.
PairingIndex
,
PairingKey
:
s
.
Channel
.
PairingKey
,
...
...
@@ -707,7 +707,7 @@ func (s *Session) pair(secret []byte) (SmartcardPairing, error) {
},
nil
}
// unpair deletes an existing pairing
// unpair deletes an existing pairing
.
func
(
s
*
Session
)
unpair
()
error
{
if
!
s
.
verified
{
return
fmt
.
Errorf
(
"Unpair requires that the PIN be verified"
)
...
...
@@ -715,27 +715,27 @@ func (s *Session) unpair() error {
return
s
.
Channel
.
Unpair
()
}
// verifyPin unlocks a wallet with the provided pin
// verifyPin unlocks a wallet with the provided pin
.
func
(
s
*
Session
)
verifyPin
(
pin
[]
byte
)
error
{
if
_
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_VERIFY_PIN
,
0
,
0
,
pin
);
err
!=
nil
{
if
_
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insVerifyPin
,
0
,
0
,
pin
);
err
!=
nil
{
return
err
}
s
.
verified
=
true
return
nil
}
// release releases resources associated with the channel
// release releases resources associated with the channel
.
func
(
s
*
Session
)
release
()
error
{
return
s
.
Wallet
.
card
.
Disconnect
(
scard
.
LeaveCard
)
}
// paired returns true if a valid pairing exists
// paired returns true if a valid pairing exists
.
func
(
s
*
Session
)
paired
()
bool
{
return
s
.
Channel
.
PairingKey
!=
nil
}
// authenticate uses an existing pairing to establish a secure channel
func
(
s
*
Session
)
authenticate
(
pairing
S
martcardPairing
)
error
{
// authenticate uses an existing pairing to establish a secure channel
.
func
(
s
*
Session
)
authenticate
(
pairing
s
martcardPairing
)
error
{
if
!
bytes
.
Equal
(
s
.
Wallet
.
PublicKey
,
pairing
.
PublicKey
)
{
return
fmt
.
Errorf
(
"Cannot pair using another wallet's pairing; %x != %x"
,
s
.
Wallet
.
PublicKey
,
pairing
.
PublicKey
)
}
...
...
@@ -744,7 +744,7 @@ func (s *Session) authenticate(pairing SmartcardPairing) error {
return
s
.
Channel
.
Open
()
}
// walletStatus describes a smartcard wallet's status information
// walletStatus describes a smartcard wallet's status information
.
type
walletStatus
struct
{
PinRetryCount
int
// Number of remaining PIN retries
PukRetryCount
int
// Number of remaining PUK retries
...
...
@@ -756,9 +756,9 @@ func (w walletStatus) String() string {
return
fmt
.
Sprintf
(
"pinRetryCount=%d, pukRetryCount=%d, initialized=%t, supportsPkDerivation=%t"
,
w
.
PinRetryCount
,
w
.
PukRetryCount
,
w
.
Initialized
,
w
.
SupportsPKDerivation
)
}
// getWalletStatus fetches the wallet's status from the card
// getWalletStatus fetches the wallet's status from the card
.
func
(
s
*
Session
)
getWalletStatus
()
(
*
walletStatus
,
error
)
{
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_STATUS
,
STATUS_P1_WALLET_STATUS
,
0
,
nil
)
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insStatus
,
statusP1WalletStatus
,
0
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -771,9 +771,9 @@ func (s *Session) getWalletStatus() (*walletStatus, error) {
return
status
,
nil
}
// getDerivationPath fetches the wallet's current derivation path from the card
// getDerivationPath fetches the wallet's current derivation path from the card
.
func
(
s
*
Session
)
getDerivationPath
()
(
accounts
.
DerivationPath
,
error
)
{
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_STATUS
,
STATUS_P1_PATH
,
0
,
nil
)
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insStatus
,
statusP1Path
,
0
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -783,14 +783,14 @@ func (s *Session) getDerivationPath() (accounts.DerivationPath, error) {
return
path
,
binary
.
Read
(
buf
,
binary
.
BigEndian
,
&
path
)
}
// initializeData contains data needed to initialize the smartcard wallet
// initializeData contains data needed to initialize the smartcard wallet
.
type
initializeData
struct
{
PublicKey
[]
byte
`asn1:"tag:0"`
PrivateKey
[]
byte
`asn1:"tag:1"`
ChainCode
[]
byte
`asn1:"tag:2"`
}
// initialize initializes the card with new key data
// initialize initializes the card with new key data
.
func
(
s
*
Session
)
initialize
(
seed
[]
byte
)
error
{
// HMAC the seed to produce the private key and chain code
mac
:=
hmac
.
New
(
sha512
.
New
,
[]
byte
(
"Bitcoin seed"
))
...
...
@@ -814,11 +814,11 @@ func (s *Session) initialize(seed []byte) error {
// Nasty hack to force the top-level struct tag to be context-specific
data
[
0
]
=
0xA1
_
,
err
=
s
.
Channel
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_LOAD_KEY
,
0x02
,
0
,
data
)
_
,
err
=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insLoadKey
,
0x02
,
0
,
data
)
return
err
}
// derive derives a new HD key path on the card
// derive derives a new HD key path on the card
.
func
(
s
*
Session
)
derive
(
path
accounts
.
DerivationPath
)
(
accounts
.
Account
,
error
)
{
// If the current path is a prefix of the desired path, we don't have to
// start again.
...
...
@@ -858,7 +858,7 @@ func (s *Session) derive(path accounts.DerivationPath) (accounts.Account, error)
return
s
.
Wallet
.
makeAccount
(
crypto
.
PubkeyToAddress
(
*
crypto
.
ToECDSAPub
(
pubkey
)),
path
),
nil
}
// keyDerivationInfo contains information on the current key derivation step
// keyDerivationInfo contains information on the current key derivation step
.
type
keyDerivationInfo
struct
{
PublicKeyX
[]
byte
`asn1:"tag:3"`
// The X coordinate of the current public key
Signature
struct
{
...
...
@@ -871,16 +871,16 @@ type keyDerivationInfo struct {
// a specific path, and performing the necessary computations to finish the public key
// generation step.
func
(
s
*
Session
)
deriveKeyAssisted
(
reset
bool
,
pathComponent
uint32
)
([]
byte
,
error
)
{
p1
:=
DERIVE_P1_ASSISTED
p1
:=
deriveP1Assisted
if
!
reset
{
p1
|=
DERIVE_P1_APPEND
p1
|=
deriveP1Append
}
buf
:=
new
(
bytes
.
Buffer
)
if
err
:=
binary
.
Write
(
buf
,
binary
.
BigEndian
,
pathComponent
);
err
!=
nil
{
return
nil
,
err
}
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_DERIVE_KEY
,
p1
,
DERIVE_P2_KEY_PATH
,
buf
.
Bytes
())
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insDeriveKey
,
p1
,
deriveP2KeyPath
,
buf
.
Bytes
())
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -900,7 +900,7 @@ func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, e
return
nil
,
err
}
_
,
err
=
s
.
Channel
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_DERIVE_KEY
,
DERIVE_P1_ASSISTED
|
DERIVE_P1_APPEND
,
DERIVE_P2_PUBLIC_KEY
,
pubkey
)
_
,
err
=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insDeriveKey
,
deriveP1Assisted
|
deriveP1Append
,
deriveP2PublicKey
,
pubkey
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -908,15 +908,15 @@ func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, e
return
pubkey
,
nil
}
// keyExport contains information on an exported keypair
// keyExport contains information on an exported keypair
.
type
keyExport
struct
{
PublicKey
[]
byte
`asn1:"tag:0"`
PrivateKey
[]
byte
`asn1:"tag:1,optional"`
}
// getPublicKey returns the public key for the current derivation path
// getPublicKey returns the public key for the current derivation path
.
func
(
s
*
Session
)
getPublicKey
()
([]
byte
,
error
)
{
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_EXPORT_KEY
,
EXPORT_P1_ANY
,
EXPORT_P2_PUBKEY
,
nil
)
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insExportKey
,
exportP1Any
,
exportP2Pubkey
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -930,7 +930,7 @@ func (s *Session) getPublicKey() ([]byte, error) {
}
// signatureData contains information on a signature - the signature itself and
// the corresponding public key
// the corresponding public key
.
type
signatureData
struct
{
PublicKey
[]
byte
`asn1:"tag:0"`
Signature
struct
{
...
...
@@ -949,7 +949,7 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error
}
deriveTime
:=
time
.
Now
()
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
CLA_SCWALLET
,
INS_SIGN
,
SIGN_P1_PRECOMPUTED_HASH
,
SIGN_P2_ONLY_BLOCK
,
hash
)
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insSign
,
signP1PrecomputedHash
,
signP2OnlyBlock
,
hash
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
internal/ethapi/api.go
View file @
78375608
...
...
@@ -473,6 +473,7 @@ func (s *PrivateAccountAPI) SignAndSendTransaction(ctx context.Context, args Sen
return
s
.
SendTransaction
(
ctx
,
args
,
passwd
)
}
// InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key.
func
(
s
*
PrivateAccountAPI
)
InitializeWallet
(
ctx
context
.
Context
,
url
string
)
(
string
,
error
)
{
wallet
,
err
:=
s
.
am
.
Wallet
(
url
)
if
err
!=
nil
{
...
...
@@ -499,6 +500,7 @@ func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (s
}
}
// Unpair deletes a pairing between wallet and geth.
func
(
s
*
PrivateAccountAPI
)
Unpair
(
ctx
context
.
Context
,
url
string
,
pin
string
)
error
{
wallet
,
err
:=
s
.
am
.
Wallet
(
url
)
if
err
!=
nil
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment