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
7d5886dc
Commit
7d5886dc
authored
Apr 20, 2018
by
Péter Szilágyi
Committed by
Guillaume Ballet
Apr 08, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
accounts, console: frendly card errors, support pin unblock
parent
38694394
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
169 additions
and
112 deletions
+169
-112
apdu.go
accounts/scwallet/apdu.go
+6
-20
hub.go
accounts/scwallet/hub.go
+4
-9
securechannel.go
accounts/scwallet/securechannel.go
+14
-10
wallet.go
accounts/scwallet/wallet.go
+96
-73
sort.go
accounts/sort.go
+31
-0
bridge.go
console/bridge.go
+18
-0
No files found.
accounts/scwallet/apdu.go
View file @
7d5886dc
...
@@ -21,29 +21,15 @@ import (
...
@@ -21,29 +21,15 @@ import (
"encoding/binary"
"encoding/binary"
)
)
const
(
// commandAPDU represents an application data unit sent to a smartcard.
claISO7816
=
0
type
commandAPDU
struct
{
insSelect
=
0xA4
insGetResponse
=
0xC0
insPair
=
0x12
insUnpair
=
0x13
insOpenSecureChannel
=
0x10
insMutuallyAuthenticate
=
0x11
sw1GetResponse
=
0x61
sw1Ok
=
0x90
)
// CommandAPDU represents an application data unit sent to a smartcard.
type
CommandAPDU
struct
{
Cla
,
Ins
,
P1
,
P2
uint8
// Class, Instruction, Parameter 1, Parameter 2
Cla
,
Ins
,
P1
,
P2
uint8
// Class, Instruction, Parameter 1, Parameter 2
Data
[]
byte
// Command data
Data
[]
byte
// Command data
Le
uint8
// Command data length
Le
uint8
// Command data length
}
}
// serialize serializes a command APDU.
// serialize serializes a command APDU.
func
(
ca
C
ommandAPDU
)
serialize
()
([]
byte
,
error
)
{
func
(
ca
c
ommandAPDU
)
serialize
()
([]
byte
,
error
)
{
buf
:=
new
(
bytes
.
Buffer
)
buf
:=
new
(
bytes
.
Buffer
)
if
err
:=
binary
.
Write
(
buf
,
binary
.
BigEndian
,
ca
.
Cla
);
err
!=
nil
{
if
err
:=
binary
.
Write
(
buf
,
binary
.
BigEndian
,
ca
.
Cla
);
err
!=
nil
{
...
@@ -72,14 +58,14 @@ func (ca CommandAPDU) serialize() ([]byte, error) {
...
@@ -72,14 +58,14 @@ func (ca CommandAPDU) serialize() ([]byte, error) {
return
buf
.
Bytes
(),
nil
return
buf
.
Bytes
(),
nil
}
}
//
R
esponseAPDU represents an application data unit received from a smart card.
//
r
esponseAPDU represents an application data unit received from a smart card.
type
R
esponseAPDU
struct
{
type
r
esponseAPDU
struct
{
Data
[]
byte
// response data
Data
[]
byte
// response data
Sw1
,
Sw2
uint8
// status words 1 and 2
Sw1
,
Sw2
uint8
// status words 1 and 2
}
}
// deserialize deserializes a response APDU.
// deserialize deserializes a response APDU.
func
(
ra
*
R
esponseAPDU
)
deserialize
(
data
[]
byte
)
error
{
func
(
ra
*
r
esponseAPDU
)
deserialize
(
data
[]
byte
)
error
{
ra
.
Data
=
make
([]
byte
,
len
(
data
)
-
2
)
ra
.
Data
=
make
([]
byte
,
len
(
data
)
-
2
)
buf
:=
bytes
.
NewReader
(
data
)
buf
:=
bytes
.
NewReader
(
data
)
...
...
accounts/scwallet/hub.go
View file @
7d5886dc
...
@@ -36,6 +36,7 @@ import (
...
@@ -36,6 +36,7 @@ import (
"encoding/json"
"encoding/json"
"io/ioutil"
"io/ioutil"
"os"
"os"
"sort"
"sync"
"sync"
"time"
"time"
...
@@ -51,7 +52,7 @@ const Scheme = "pcsc"
...
@@ -51,7 +52,7 @@ const Scheme = "pcsc"
// refreshCycle is the maximum time between wallet refreshes (if USB hotplug
// refreshCycle is the maximum time between wallet refreshes (if USB hotplug
// notifications don't work).
// notifications don't work).
const
refreshCycle
=
5
*
time
.
Second
const
refreshCycle
=
time
.
Second
// refreshThrottling is the minimum time between wallet refreshes to avoid thrashing.
// refreshThrottling is the minimum time between wallet refreshes to avoid thrashing.
const
refreshThrottling
=
500
*
time
.
Millisecond
const
refreshThrottling
=
500
*
time
.
Millisecond
...
@@ -132,7 +133,7 @@ func (hub *Hub) writePairings() error {
...
@@ -132,7 +133,7 @@ func (hub *Hub) writePairings() error {
return
pairingFile
.
Close
()
return
pairingFile
.
Close
()
}
}
func
(
hub
*
Hub
)
getP
airing
(
wallet
*
Wallet
)
*
smartcardPairing
{
func
(
hub
*
Hub
)
p
airing
(
wallet
*
Wallet
)
*
smartcardPairing
{
pairing
,
ok
:=
hub
.
pairings
[
string
(
wallet
.
PublicKey
)]
pairing
,
ok
:=
hub
.
pairings
[
string
(
wallet
.
PublicKey
)]
if
ok
{
if
ok
{
return
&
pairing
return
&
pairing
...
@@ -182,13 +183,7 @@ func (hub *Hub) Wallets() []accounts.Wallet {
...
@@ -182,13 +183,7 @@ func (hub *Hub) Wallets() []accounts.Wallet {
for
_
,
wallet
:=
range
hub
.
wallets
{
for
_
,
wallet
:=
range
hub
.
wallets
{
cpy
=
append
(
cpy
,
wallet
)
cpy
=
append
(
cpy
,
wallet
)
}
}
for
i
:=
0
;
i
<
len
(
cpy
);
i
++
{
sort
.
Sort
(
accounts
.
WalletsByURL
(
cpy
))
for
j
:=
i
+
1
;
j
<
len
(
cpy
);
j
++
{
if
cpy
[
i
]
.
URL
()
.
Cmp
(
cpy
[
j
]
.
URL
())
>
0
{
cpy
[
i
],
cpy
[
j
]
=
cpy
[
j
],
cpy
[
i
]
}
}
}
return
cpy
return
cpy
}
}
...
...
accounts/scwallet/securechannel.go
View file @
7d5886dc
...
@@ -17,7 +17,6 @@
...
@@ -17,7 +17,6 @@
package
scwallet
package
scwallet
import
(
import
(
//"crypto/ecdsa"
"bytes"
"bytes"
"crypto/aes"
"crypto/aes"
"crypto/cipher"
"crypto/cipher"
...
@@ -25,10 +24,10 @@ import (
...
@@ -25,10 +24,10 @@ import (
"crypto/sha256"
"crypto/sha256"
"crypto/sha512"
"crypto/sha512"
"fmt"
"fmt"
//"math/big"
"github.com/ebfe/scard"
"github.com/ebfe/scard"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
ecdh
"github.com/wsddn/go-ecdh"
"github.com/wsddn/go-ecdh"
)
)
const
(
const
(
...
@@ -38,6 +37,11 @@ const (
...
@@ -38,6 +37,11 @@ const (
scSecretLength
=
32
scSecretLength
=
32
scBlockSize
=
16
scBlockSize
=
16
insOpenSecureChannel
=
0x10
insMutuallyAuthenticate
=
0x11
insPair
=
0x12
insUnpair
=
0x13
)
)
// SecureChannelSession enables secure communication with a hardware wallet.
// SecureChannelSession enables secure communication with a hardware wallet.
...
@@ -192,8 +196,8 @@ func (s *SecureChannelSession) mutuallyAuthenticate() error {
...
@@ -192,8 +196,8 @@ func (s *SecureChannelSession) mutuallyAuthenticate() error {
}
}
// open is an internal method that sends an open APDU.
// open is an internal method that sends an open APDU.
func
(
s
*
SecureChannelSession
)
open
()
(
*
R
esponseAPDU
,
error
)
{
func
(
s
*
SecureChannelSession
)
open
()
(
*
r
esponseAPDU
,
error
)
{
return
transmit
(
s
.
card
,
&
C
ommandAPDU
{
return
transmit
(
s
.
card
,
&
c
ommandAPDU
{
Cla
:
claSCWallet
,
Cla
:
claSCWallet
,
Ins
:
insOpenSecureChannel
,
Ins
:
insOpenSecureChannel
,
P1
:
s
.
PairingIndex
,
P1
:
s
.
PairingIndex
,
...
@@ -204,8 +208,8 @@ func (s *SecureChannelSession) open() (*ResponseAPDU, error) {
...
@@ -204,8 +208,8 @@ 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
)
(
*
R
esponseAPDU
,
error
)
{
func
(
s
*
SecureChannelSession
)
pair
(
p1
uint8
,
data
[]
byte
)
(
*
r
esponseAPDU
,
error
)
{
return
transmit
(
s
.
card
,
&
C
ommandAPDU
{
return
transmit
(
s
.
card
,
&
c
ommandAPDU
{
Cla
:
claSCWallet
,
Cla
:
claSCWallet
,
Ins
:
insPair
,
Ins
:
insPair
,
P1
:
p1
,
P1
:
p1
,
...
@@ -216,7 +220,7 @@ func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*ResponseAPDU, error
...
@@ -216,7 +220,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
)
(
*
R
esponseAPDU
,
error
)
{
func
(
s
*
SecureChannelSession
)
TransmitEncrypted
(
cla
,
ins
,
p1
,
p2
byte
,
data
[]
byte
)
(
*
r
esponseAPDU
,
error
)
{
if
s
.
iv
==
nil
{
if
s
.
iv
==
nil
{
return
nil
,
fmt
.
Errorf
(
"Channel not open"
)
return
nil
,
fmt
.
Errorf
(
"Channel not open"
)
}
}
...
@@ -234,7 +238,7 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
...
@@ -234,7 +238,7 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
copy
(
fulldata
,
s
.
iv
)
copy
(
fulldata
,
s
.
iv
)
copy
(
fulldata
[
len
(
s
.
iv
)
:
],
data
)
copy
(
fulldata
[
len
(
s
.
iv
)
:
],
data
)
response
,
err
:=
transmit
(
s
.
card
,
&
C
ommandAPDU
{
response
,
err
:=
transmit
(
s
.
card
,
&
c
ommandAPDU
{
Cla
:
cla
,
Cla
:
cla
,
Ins
:
ins
,
Ins
:
ins
,
P1
:
p1
,
P1
:
p1
,
...
@@ -260,7 +264,7 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
...
@@ -260,7 +264,7 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
return
nil
,
fmt
.
Errorf
(
"Invalid MAC in response"
)
return
nil
,
fmt
.
Errorf
(
"Invalid MAC in response"
)
}
}
rapdu
:=
&
R
esponseAPDU
{}
rapdu
:=
&
r
esponseAPDU
{}
rapdu
.
deserialize
(
plainData
)
rapdu
.
deserialize
(
plainData
)
if
rapdu
.
Sw1
!=
sw1Ok
{
if
rapdu
.
Sw1
!=
sw1Ok
{
...
...
accounts/scwallet/wallet.go
View file @
7d5886dc
...
@@ -27,6 +27,7 @@ import (
...
@@ -27,6 +27,7 @@ import (
"errors"
"errors"
"fmt"
"fmt"
"math/big"
"math/big"
"sort"
"strings"
"strings"
"sync"
"sync"
"time"
"time"
...
@@ -51,6 +52,12 @@ var ErrPUKNeeded = errors.New("smartcard: puk needed")
...
@@ -51,6 +52,12 @@ var ErrPUKNeeded = errors.New("smartcard: puk needed")
// and send it back.
// and send it back.
var
ErrPINNeeded
=
errors
.
New
(
"smartcard: pin needed"
)
var
ErrPINNeeded
=
errors
.
New
(
"smartcard: pin needed"
)
// ErrPINUnblockNeeded is returned if opening the smart card requires a PIN code,
// but all PIN attempts have already been exhausted. In this case the calling
// application should request user input for the PUK and a new PIN code to set
// fo the card.
var
ErrPINUnblockNeeded
=
errors
.
New
(
"smartcard: pin unblock needed"
)
// ErrAlreadyOpen is returned if the smart card is attempted to be opened, but
// ErrAlreadyOpen is returned if the smart card is attempted to be opened, but
// there is already a paired and unlocked session.
// there is already a paired and unlocked session.
var
ErrAlreadyOpen
=
errors
.
New
(
"smartcard: already open"
)
var
ErrAlreadyOpen
=
errors
.
New
(
"smartcard: already open"
)
...
@@ -65,8 +72,16 @@ var (
...
@@ -65,8 +72,16 @@ var (
)
)
const
(
const
(
claISO7816
=
0
claSCWallet
=
0x80
claSCWallet
=
0x80
insSelect
=
0xA4
insGetResponse
=
0xC0
sw1GetResponse
=
0x61
sw1Ok
=
0x90
insVerifyPin
=
0x20
insVerifyPin
=
0x20
insUnblockPin
=
0x22
insExportKey
=
0xC2
insExportKey
=
0xC2
insSign
=
0xC0
insSign
=
0xC0
insLoadKey
=
0xD0
insLoadKey
=
0xD0
...
@@ -117,7 +132,7 @@ func NewWallet(hub *Hub, card *scard.Card) *Wallet {
...
@@ -117,7 +132,7 @@ func NewWallet(hub *Hub, card *scard.Card) *Wallet {
// transmit sends an APDU to the smartcard and receives and decodes the response.
// transmit sends an APDU to the smartcard and receives and decodes the response.
// It automatically handles requests by the card to fetch the return data separately,
// It automatically handles requests by the card to fetch the return data separately,
// and returns an error if the response status code is not success.
// and returns an error if the response status code is not success.
func
transmit
(
card
*
scard
.
Card
,
command
*
CommandAPDU
)
(
*
R
esponseAPDU
,
error
)
{
func
transmit
(
card
*
scard
.
Card
,
command
*
commandAPDU
)
(
*
r
esponseAPDU
,
error
)
{
data
,
err
:=
command
.
serialize
()
data
,
err
:=
command
.
serialize
()
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
...
@@ -128,14 +143,14 @@ func transmit(card *scard.Card, command *CommandAPDU) (*ResponseAPDU, error) {
...
@@ -128,14 +143,14 @@ func transmit(card *scard.Card, command *CommandAPDU) (*ResponseAPDU, error) {
return
nil
,
err
return
nil
,
err
}
}
response
:=
new
(
R
esponseAPDU
)
response
:=
new
(
r
esponseAPDU
)
if
err
=
response
.
deserialize
(
responseData
);
err
!=
nil
{
if
err
=
response
.
deserialize
(
responseData
);
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
// Are we being asked to fetch the response separately?
// Are we being asked to fetch the response separately?
if
response
.
Sw1
==
sw1GetResponse
&&
(
command
.
Cla
!=
claISO7816
||
command
.
Ins
!=
insGetResponse
)
{
if
response
.
Sw1
==
sw1GetResponse
&&
(
command
.
Cla
!=
claISO7816
||
command
.
Ins
!=
insGetResponse
)
{
return
transmit
(
card
,
&
C
ommandAPDU
{
return
transmit
(
card
,
&
c
ommandAPDU
{
Cla
:
claISO7816
,
Cla
:
claISO7816
,
Ins
:
insGetResponse
,
Ins
:
insGetResponse
,
P1
:
0
,
P1
:
0
,
...
@@ -186,7 +201,7 @@ func (w *Wallet) connect() error {
...
@@ -186,7 +201,7 @@ func (w *Wallet) connect() error {
// doselect is an internal (unlocked) function to send a SELECT APDU to the card.
// doselect is an internal (unlocked) function to send a SELECT APDU to the card.
func
(
w
*
Wallet
)
doselect
()
(
*
applicationInfo
,
error
)
{
func
(
w
*
Wallet
)
doselect
()
(
*
applicationInfo
,
error
)
{
response
,
err
:=
transmit
(
w
.
card
,
&
C
ommandAPDU
{
response
,
err
:=
transmit
(
w
.
card
,
&
c
ommandAPDU
{
Cla
:
claISO7816
,
Cla
:
claISO7816
,
Ins
:
insSelect
,
Ins
:
insSelect
,
P1
:
4
,
P1
:
4
,
...
@@ -209,13 +224,11 @@ func (w *Wallet) ping() error {
...
@@ -209,13 +224,11 @@ func (w *Wallet) ping() error {
w
.
lock
.
Lock
()
w
.
lock
.
Lock
()
defer
w
.
lock
.
Unlock
()
defer
w
.
lock
.
Unlock
()
if
!
w
.
session
.
paired
()
{
// We can't ping if not paired
// We can't ping if not paired
if
!
w
.
session
.
paired
()
{
return
nil
return
nil
}
}
if
_
,
err
:=
w
.
session
.
walletStatus
();
err
!=
nil
{
_
,
err
:=
w
.
session
.
getWalletStatus
()
if
err
!=
nil
{
return
err
return
err
}
}
return
nil
return
nil
...
@@ -235,16 +248,13 @@ func (w *Wallet) pair(puk []byte) error {
...
@@ -235,16 +248,13 @@ func (w *Wallet) pair(puk []byte) error {
if
w
.
session
.
paired
()
{
if
w
.
session
.
paired
()
{
return
fmt
.
Errorf
(
"Wallet already paired"
)
return
fmt
.
Errorf
(
"Wallet already paired"
)
}
}
pairing
,
err
:=
w
.
session
.
pair
(
puk
)
pairing
,
err
:=
w
.
session
.
pair
(
puk
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
if
err
=
w
.
Hub
.
setPairing
(
w
,
&
pairing
);
err
!=
nil
{
if
err
=
w
.
Hub
.
setPairing
(
w
,
&
pairing
);
err
!=
nil
{
return
err
return
err
}
}
return
w
.
session
.
authenticate
(
pairing
)
return
w
.
session
.
authenticate
(
pairing
)
}
}
...
@@ -285,19 +295,26 @@ func (w *Wallet) Status() (string, error) {
...
@@ -285,19 +295,26 @@ func (w *Wallet) Status() (string, error) {
w
.
lock
.
Lock
()
w
.
lock
.
Lock
()
defer
w
.
lock
.
Unlock
()
defer
w
.
lock
.
Unlock
()
// If the card is not paired, we can only wait
if
!
w
.
session
.
paired
()
{
if
!
w
.
session
.
paired
()
{
return
"Unpaired"
,
nil
return
"Unpaired
, waiting for PUK
"
,
nil
}
}
// Yay, we have an encrypted session, retrieve the actual status
status
,
err
:=
w
.
session
.
getW
alletStatus
()
status
,
err
:=
w
.
session
.
w
alletStatus
()
if
err
!=
nil
{
if
err
!=
nil
{
return
"Error"
,
err
return
fmt
.
Sprintf
(
"Failed: %v"
,
err
),
err
}
}
switch
{
if
w
.
session
.
verified
{
case
!
w
.
session
.
verified
&&
status
.
PinRetryCount
==
0
:
return
fmt
.
Sprintf
(
"Open, %s"
,
status
),
nil
return
fmt
.
Sprintf
(
"Blocked, waiting for PUK and new PIN"
),
nil
}
else
{
case
!
w
.
session
.
verified
:
return
fmt
.
Sprintf
(
"Locked, %s"
,
status
),
nil
return
fmt
.
Sprintf
(
"Locked, waiting for PIN (%d attempts left)"
,
status
.
PinRetryCount
),
nil
case
!
status
.
Initialized
:
return
fmt
.
Sprintf
(
"Empty, waiting for initialization"
),
nil
case
status
.
SupportsPKDerivation
:
return
fmt
.
Sprintf
(
"Online, can derive public keys"
),
nil
default
:
return
fmt
.
Sprintf
(
"Online, cannot derive public keys"
),
nil
}
}
}
}
...
@@ -324,12 +341,12 @@ func (w *Wallet) Open(passphrase string) error {
...
@@ -324,12 +341,12 @@ func (w *Wallet) Open(passphrase string) error {
// pairing key or form the supplied PUK code.
// pairing key or form the supplied PUK code.
if
!
w
.
session
.
paired
()
{
if
!
w
.
session
.
paired
()
{
// If a previous pairing exists, only ever try to use that
// If a previous pairing exists, only ever try to use that
if
pairing
:=
w
.
Hub
.
getP
airing
(
w
);
pairing
!=
nil
{
if
pairing
:=
w
.
Hub
.
p
airing
(
w
);
pairing
!=
nil
{
if
err
:=
w
.
session
.
authenticate
(
*
pairing
);
err
!=
nil
{
if
err
:=
w
.
session
.
authenticate
(
*
pairing
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to authenticate card %x: %s"
,
w
.
PublicKey
[
:
4
],
err
)
return
fmt
.
Errorf
(
"failed to authenticate card %x: %s"
,
w
.
PublicKey
[
:
4
],
err
)
}
}
return
ErrPINNeeded
// Pairing still ok, fall through to PIN checks
}
}
else
{
// If no passphrase was supplied, request the PUK from the user
// If no passphrase was supplied, request the PUK from the user
if
passphrase
==
""
{
if
passphrase
==
""
{
return
ErrPUKNeeded
return
ErrPUKNeeded
...
@@ -338,16 +355,33 @@ func (w *Wallet) Open(passphrase string) error {
...
@@ -338,16 +355,33 @@ func (w *Wallet) Open(passphrase string) error {
if
err
:=
w
.
pair
([]
byte
(
passphrase
));
err
!=
nil
{
if
err
:=
w
.
pair
([]
byte
(
passphrase
));
err
!=
nil
{
return
err
return
err
}
}
return
ErrPINNeeded
// We always need the PIN after the PUK
// Pairing succeeded, fall through to PIN checks. This will of course fail,
// but we can't return ErrPINNeeded directly here becase we don't know whether
// a PIN check or a PIN reset is needed.
passphrase
=
""
}
}
// The smart card was successfully paired, request a PIN code or use the one
// supplied by the user
if
passphrase
==
""
{
return
ErrPINNeeded
}
}
// The smart card was successfully paired, retrieve its status to check whether
// PIN verification or unblocking is needed.
status
,
err
:=
w
.
session
.
walletStatus
()
if
err
!=
nil
{
return
err
}
// Request the appropriate next authentication data, or use the one supplied
switch
{
case
passphrase
==
""
&&
status
.
PinRetryCount
>
0
:
return
ErrPINNeeded
case
passphrase
==
""
:
return
ErrPINUnblockNeeded
case
status
.
PinRetryCount
>
0
:
if
err
:=
w
.
session
.
verifyPin
([]
byte
(
passphrase
));
err
!=
nil
{
if
err
:=
w
.
session
.
verifyPin
([]
byte
(
passphrase
));
err
!=
nil
{
return
err
return
err
}
}
default
:
if
err
:=
w
.
session
.
unblockPin
([]
byte
(
passphrase
));
err
!=
nil
{
return
err
}
}
// Smart card paired and unlocked, initialize and register
// Smart card paired and unlocked, initialize and register
w
.
deriveReq
=
make
(
chan
chan
struct
{})
w
.
deriveReq
=
make
(
chan
chan
struct
{})
w
.
deriveQuit
=
make
(
chan
chan
error
)
w
.
deriveQuit
=
make
(
chan
chan
error
)
...
@@ -415,7 +449,7 @@ func (w *Wallet) selfDerive() {
...
@@ -415,7 +449,7 @@ func (w *Wallet) selfDerive() {
reqc
<-
struct
{}{}
reqc
<-
struct
{}{}
continue
continue
}
}
pairing
:=
w
.
Hub
.
getP
airing
(
w
)
pairing
:=
w
.
Hub
.
p
airing
(
w
)
// Device lock obtained, derive the next batch of accounts
// Device lock obtained, derive the next batch of accounts
var
(
var
(
...
@@ -519,18 +553,12 @@ func (w *Wallet) Accounts() []accounts.Account {
...
@@ -519,18 +553,12 @@ func (w *Wallet) Accounts() []accounts.Account {
w
.
lock
.
Lock
()
w
.
lock
.
Lock
()
defer
w
.
lock
.
Unlock
()
defer
w
.
lock
.
Unlock
()
if
pairing
:=
w
.
Hub
.
getP
airing
(
w
);
pairing
!=
nil
{
if
pairing
:=
w
.
Hub
.
p
airing
(
w
);
pairing
!=
nil
{
ret
:=
make
([]
accounts
.
Account
,
0
,
len
(
pairing
.
Accounts
))
ret
:=
make
([]
accounts
.
Account
,
0
,
len
(
pairing
.
Accounts
))
for
address
,
path
:=
range
pairing
.
Accounts
{
for
address
,
path
:=
range
pairing
.
Accounts
{
ret
=
append
(
ret
,
w
.
makeAccount
(
address
,
path
))
ret
=
append
(
ret
,
w
.
makeAccount
(
address
,
path
))
}
}
for
i
:=
0
;
i
<
len
(
ret
);
i
++
{
sort
.
Sort
(
accounts
.
AccountsByURL
(
ret
))
for
j
:=
i
+
1
;
j
<
len
(
ret
);
j
++
{
if
ret
[
i
]
.
URL
.
Cmp
(
ret
[
j
]
.
URL
)
>
0
{
ret
[
i
],
ret
[
j
]
=
ret
[
j
],
ret
[
i
]
}
}
}
return
ret
return
ret
}
}
return
nil
return
nil
...
@@ -548,7 +576,7 @@ func (w *Wallet) makeAccount(address common.Address, path accounts.DerivationPat
...
@@ -548,7 +576,7 @@ func (w *Wallet) makeAccount(address common.Address, path accounts.DerivationPat
// Contains returns whether an account is part of this particular wallet or not.
// Contains returns whether an account is part of this particular wallet or not.
func
(
w
*
Wallet
)
Contains
(
account
accounts
.
Account
)
bool
{
func
(
w
*
Wallet
)
Contains
(
account
accounts
.
Account
)
bool
{
if
pairing
:=
w
.
Hub
.
getP
airing
(
w
);
pairing
!=
nil
{
if
pairing
:=
w
.
Hub
.
p
airing
(
w
);
pairing
!=
nil
{
_
,
ok
:=
pairing
.
Accounts
[
account
.
Address
]
_
,
ok
:=
pairing
.
Accounts
[
account
.
Address
]
return
ok
return
ok
}
}
...
@@ -576,7 +604,7 @@ func (w *Wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Accoun
...
@@ -576,7 +604,7 @@ func (w *Wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Accoun
}
}
if
pin
{
if
pin
{
pairing
:=
w
.
Hub
.
getP
airing
(
w
)
pairing
:=
w
.
Hub
.
p
airing
(
w
)
pairing
.
Accounts
[
account
.
Address
]
=
path
pairing
.
Accounts
[
account
.
Address
]
=
path
if
err
:=
w
.
Hub
.
setPairing
(
w
,
pairing
);
err
!=
nil
{
if
err
:=
w
.
Hub
.
setPairing
(
w
,
pairing
);
err
!=
nil
{
return
accounts
.
Account
{},
err
return
accounts
.
Account
{},
err
...
@@ -684,7 +712,7 @@ func (w *Wallet) SignTxWithPassphrase(account accounts.Account, passphrase strin
...
@@ -684,7 +712,7 @@ func (w *Wallet) SignTxWithPassphrase(account accounts.Account, passphrase strin
// It first checks for the address in the list of pinned accounts, and if it is
// It first checks for the address in the list of pinned accounts, and if it is
// not found, attempts to parse the derivation path from the account's URL.
// not found, attempts to parse the derivation path from the account's URL.
func
(
w
*
Wallet
)
findAccountPath
(
account
accounts
.
Account
)
(
accounts
.
DerivationPath
,
error
)
{
func
(
w
*
Wallet
)
findAccountPath
(
account
accounts
.
Account
)
(
accounts
.
DerivationPath
,
error
)
{
pairing
:=
w
.
Hub
.
getP
airing
(
w
)
pairing
:=
w
.
Hub
.
p
airing
(
w
)
if
path
,
ok
:=
pairing
.
Accounts
[
account
.
Address
];
ok
{
if
path
,
ok
:=
pairing
.
Accounts
[
account
.
Address
];
ok
{
return
path
,
nil
return
path
,
nil
}
}
...
@@ -745,6 +773,16 @@ func (s *Session) verifyPin(pin []byte) error {
...
@@ -745,6 +773,16 @@ func (s *Session) verifyPin(pin []byte) error {
return
nil
return
nil
}
}
// unblockPin unblocks a wallet with the provided puk and resets the pin to the
// new one specified.
func
(
s
*
Session
)
unblockPin
(
pukpin
[]
byte
)
error
{
if
_
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insUnblockPin
,
0
,
0
,
pukpin
);
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
{
func
(
s
*
Session
)
release
()
error
{
return
s
.
Wallet
.
card
.
Disconnect
(
scard
.
LeaveCard
)
return
s
.
Wallet
.
card
.
Disconnect
(
scard
.
LeaveCard
)
...
@@ -773,32 +811,25 @@ type walletStatus struct {
...
@@ -773,32 +811,25 @@ type walletStatus struct {
SupportsPKDerivation
bool
// Whether the card supports doing public key derivation itself
SupportsPKDerivation
bool
// Whether the card supports doing public key derivation itself
}
}
func
(
w
walletStatus
)
String
()
string
{
// walletStatus fetches the wallet's status from the card.
return
fmt
.
Sprintf
(
"pinRetryCount=%d, pukRetryCount=%d, initialized=%t, supportsPkDerivation=%t"
,
w
.
PinRetryCount
,
w
.
PukRetryCount
,
w
.
Initialized
,
w
.
SupportsPKDerivation
)
func
(
s
*
Session
)
walletStatus
()
(
*
walletStatus
,
error
)
{
}
// getWalletStatus fetches the wallet's status from the card.
func
(
s
*
Session
)
getWalletStatus
()
(
*
walletStatus
,
error
)
{
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insStatus
,
statusP1WalletStatus
,
0
,
nil
)
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insStatus
,
statusP1WalletStatus
,
0
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
status
:=
new
(
walletStatus
)
status
:=
new
(
walletStatus
)
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
status
,
"tag:3"
);
err
!=
nil
{
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
status
,
"tag:3"
);
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
status
,
nil
return
status
,
nil
}
}
//
getD
erivationPath fetches the wallet's current derivation path from the card.
//
d
erivationPath fetches the wallet's current derivation path from the card.
func
(
s
*
Session
)
getD
erivationPath
()
(
accounts
.
DerivationPath
,
error
)
{
func
(
s
*
Session
)
d
erivationPath
()
(
accounts
.
DerivationPath
,
error
)
{
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insStatus
,
statusP1Path
,
0
,
nil
)
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insStatus
,
statusP1Path
,
0
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
buf
:=
bytes
.
NewReader
(
response
.
Data
)
buf
:=
bytes
.
NewReader
(
response
.
Data
)
path
:=
make
(
accounts
.
DerivationPath
,
len
(
response
.
Data
)
/
4
)
path
:=
make
(
accounts
.
DerivationPath
,
len
(
response
.
Data
)
/
4
)
return
path
,
binary
.
Read
(
buf
,
binary
.
BigEndian
,
&
path
)
return
path
,
binary
.
Read
(
buf
,
binary
.
BigEndian
,
&
path
)
...
@@ -845,11 +876,11 @@ func (s *Session) derive(path accounts.DerivationPath) (accounts.Account, error)
...
@@ -845,11 +876,11 @@ func (s *Session) derive(path accounts.DerivationPath) (accounts.Account, error)
// start again.
// start again.
remainingPath
:=
path
remainingPath
:=
path
pubkey
,
err
:=
s
.
getP
ublicKey
()
pubkey
,
err
:=
s
.
p
ublicKey
()
if
err
!=
nil
{
if
err
!=
nil
{
return
accounts
.
Account
{},
err
return
accounts
.
Account
{},
err
}
}
currentPath
,
err
:=
s
.
getD
erivationPath
()
currentPath
,
err
:=
s
.
d
erivationPath
()
if
err
!=
nil
{
if
err
!=
nil
{
return
accounts
.
Account
{},
err
return
accounts
.
Account
{},
err
}
}
...
@@ -910,7 +941,6 @@ func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, e
...
@@ -910,7 +941,6 @@ func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, e
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
keyinfo
,
"tag:2"
);
err
!=
nil
{
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
keyinfo
,
"tag:2"
);
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
rbytes
,
sbytes
:=
keyinfo
.
Signature
.
R
.
Bytes
(),
keyinfo
.
Signature
.
S
.
Bytes
()
rbytes
,
sbytes
:=
keyinfo
.
Signature
.
R
.
Bytes
(),
keyinfo
.
Signature
.
S
.
Bytes
()
sig
:=
make
([]
byte
,
65
)
sig
:=
make
([]
byte
,
65
)
copy
(
sig
[
32
-
len
(
rbytes
)
:
32
],
rbytes
)
copy
(
sig
[
32
-
len
(
rbytes
)
:
32
],
rbytes
)
...
@@ -920,12 +950,10 @@ func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, e
...
@@ -920,12 +950,10 @@ func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, e
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
_
,
err
=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insDeriveKey
,
deriveP1Assisted
|
deriveP1Append
,
deriveP2PublicKey
,
pubkey
)
_
,
err
=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insDeriveKey
,
deriveP1Assisted
|
deriveP1Append
,
deriveP2PublicKey
,
pubkey
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
pubkey
,
nil
return
pubkey
,
nil
}
}
...
@@ -935,18 +963,16 @@ type keyExport struct {
...
@@ -935,18 +963,16 @@ type keyExport struct {
PrivateKey
[]
byte
`asn1:"tag:1,optional"`
PrivateKey
[]
byte
`asn1:"tag:1,optional"`
}
}
//
getP
ublicKey returns the public key for the current derivation path.
//
p
ublicKey returns the public key for the current derivation path.
func
(
s
*
Session
)
getP
ublicKey
()
([]
byte
,
error
)
{
func
(
s
*
Session
)
p
ublicKey
()
([]
byte
,
error
)
{
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insExportKey
,
exportP1Any
,
exportP2Pubkey
,
nil
)
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insExportKey
,
exportP1Any
,
exportP2Pubkey
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
keys
:=
new
(
keyExport
)
keys
:=
new
(
keyExport
)
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
keys
,
"tag:1"
);
err
!=
nil
{
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
keys
,
"tag:1"
);
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
keys
.
PublicKey
,
nil
return
keys
.
PublicKey
,
nil
}
}
...
@@ -974,12 +1000,10 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error
...
@@ -974,12 +1000,10 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
sigdata
:=
new
(
signatureData
)
sigdata
:=
new
(
signatureData
)
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
sigdata
,
"tag:0"
);
err
!=
nil
{
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
sigdata
,
"tag:0"
);
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
// Serialize the signature
// Serialize the signature
rbytes
,
sbytes
:=
sigdata
.
Signature
.
R
.
Bytes
(),
sigdata
.
Signature
.
S
.
Bytes
()
rbytes
,
sbytes
:=
sigdata
.
Signature
.
R
.
Bytes
(),
sigdata
.
Signature
.
S
.
Bytes
()
sig
:=
make
([]
byte
,
65
)
sig
:=
make
([]
byte
,
65
)
...
@@ -991,7 +1015,6 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error
...
@@ -991,7 +1015,6 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
log
.
Debug
(
"Signed using smartcard"
,
"deriveTime"
,
deriveTime
.
Sub
(
startTime
),
"signingTime"
,
time
.
Since
(
deriveTime
))
log
.
Debug
(
"Signed using smartcard"
,
"deriveTime"
,
deriveTime
.
Sub
(
startTime
),
"signingTime"
,
time
.
Since
(
deriveTime
))
return
sig
,
nil
return
sig
,
nil
...
...
accounts/sort.go
0 → 100644
View file @
7d5886dc
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// 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/>.
package
accounts
// AccountsByURL implements sort.Interface for []Account based on the URL field.
type
AccountsByURL
[]
Account
func
(
a
AccountsByURL
)
Len
()
int
{
return
len
(
a
)
}
func
(
a
AccountsByURL
)
Swap
(
i
,
j
int
)
{
a
[
i
],
a
[
j
]
=
a
[
j
],
a
[
i
]
}
func
(
a
AccountsByURL
)
Less
(
i
,
j
int
)
bool
{
return
a
[
i
]
.
URL
.
Cmp
(
a
[
j
]
.
URL
)
<
0
}
// WalletsByURL implements sort.Interface for []Wallet based on the URL field.
type
WalletsByURL
[]
Wallet
func
(
w
WalletsByURL
)
Len
()
int
{
return
len
(
w
)
}
func
(
w
WalletsByURL
)
Swap
(
i
,
j
int
)
{
w
[
i
],
w
[
j
]
=
w
[
j
],
w
[
i
]
}
func
(
w
WalletsByURL
)
Less
(
i
,
j
int
)
bool
{
return
w
[
i
]
.
URL
()
.
Cmp
(
w
[
j
]
.
URL
())
<
0
}
console/bridge.go
View file @
7d5886dc
...
@@ -141,6 +141,24 @@ func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) {
...
@@ -141,6 +141,24 @@ func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) {
}
}
}
}
case
strings
.
HasSuffix
(
err
.
Error
(),
scwallet
.
ErrPINUnblockNeeded
.
Error
())
:
// PIN unblock requested, fetch PUK and new PIN from the user
var
pukpin
string
if
input
,
err
:=
b
.
prompter
.
PromptPassword
(
"Please enter current PUK: "
);
err
!=
nil
{
throwJSException
(
err
.
Error
())
}
else
{
pukpin
=
input
}
if
input
,
err
:=
b
.
prompter
.
PromptPassword
(
"Please enter new PIN: "
);
err
!=
nil
{
throwJSException
(
err
.
Error
())
}
else
{
pukpin
+=
input
}
passwd
,
_
=
otto
.
ToValue
(
pukpin
)
if
val
,
err
=
call
.
Otto
.
Call
(
"jeth.openWallet"
,
nil
,
wallet
,
passwd
);
err
!=
nil
{
throwJSException
(
err
.
Error
())
}
case
strings
.
HasSuffix
(
err
.
Error
(),
scwallet
.
ErrPINNeeded
.
Error
())
:
case
strings
.
HasSuffix
(
err
.
Error
(),
scwallet
.
ErrPINNeeded
.
Error
())
:
// PIN input requested, fetch from the user and call open again
// PIN input requested, fetch from the user and call open again
if
input
,
err
:=
b
.
prompter
.
PromptPassword
(
"Please enter current PIN: "
);
err
!=
nil
{
if
input
,
err
:=
b
.
prompter
.
PromptPassword
(
"Please enter current PIN: "
);
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