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 (
"encoding/binary"
)
const
(
claISO7816
=
0
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
{
// 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
Le
uint8
// Command data length
}
// serialize serializes a command APDU.
func
(
ca
C
ommandAPDU
)
serialize
()
([]
byte
,
error
)
{
func
(
ca
c
ommandAPDU
)
serialize
()
([]
byte
,
error
)
{
buf
:=
new
(
bytes
.
Buffer
)
if
err
:=
binary
.
Write
(
buf
,
binary
.
BigEndian
,
ca
.
Cla
);
err
!=
nil
{
...
...
@@ -72,14 +58,14 @@ func (ca CommandAPDU) serialize() ([]byte, error) {
return
buf
.
Bytes
(),
nil
}
//
R
esponseAPDU represents an application data unit received from a smart card.
type
R
esponseAPDU
struct
{
//
r
esponseAPDU represents an application data unit received from a smart card.
type
r
esponseAPDU
struct
{
Data
[]
byte
// response data
Sw1
,
Sw2
uint8
// status words 1 and 2
}
// 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
)
buf
:=
bytes
.
NewReader
(
data
)
...
...
accounts/scwallet/hub.go
View file @
7d5886dc
...
...
@@ -36,6 +36,7 @@ import (
"encoding/json"
"io/ioutil"
"os"
"sort"
"sync"
"time"
...
...
@@ -51,7 +52,7 @@ const Scheme = "pcsc"
// refreshCycle is the maximum time between wallet refreshes (if USB hotplug
// notifications don't work).
const
refreshCycle
=
5
*
time
.
Second
const
refreshCycle
=
time
.
Second
// refreshThrottling is the minimum time between wallet refreshes to avoid thrashing.
const
refreshThrottling
=
500
*
time
.
Millisecond
...
...
@@ -132,7 +133,7 @@ func (hub *Hub) writePairings() error {
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
)]
if
ok
{
return
&
pairing
...
...
@@ -182,13 +183,7 @@ func (hub *Hub) Wallets() []accounts.Wallet {
for
_
,
wallet
:=
range
hub
.
wallets
{
cpy
=
append
(
cpy
,
wallet
)
}
for
i
:=
0
;
i
<
len
(
cpy
);
i
++
{
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
]
}
}
}
sort
.
Sort
(
accounts
.
WalletsByURL
(
cpy
))
return
cpy
}
...
...
accounts/scwallet/securechannel.go
View file @
7d5886dc
...
...
@@ -17,7 +17,6 @@
package
scwallet
import
(
//"crypto/ecdsa"
"bytes"
"crypto/aes"
"crypto/cipher"
...
...
@@ -25,10 +24,10 @@ import (
"crypto/sha256"
"crypto/sha512"
"fmt"
//"math/big"
"github.com/ebfe/scard"
"github.com/ethereum/go-ethereum/crypto"
ecdh
"github.com/wsddn/go-ecdh"
"github.com/wsddn/go-ecdh"
)
const
(
...
...
@@ -38,6 +37,11 @@ const (
scSecretLength
=
32
scBlockSize
=
16
insOpenSecureChannel
=
0x10
insMutuallyAuthenticate
=
0x11
insPair
=
0x12
insUnpair
=
0x13
)
// SecureChannelSession enables secure communication with a hardware wallet.
...
...
@@ -192,8 +196,8 @@ func (s *SecureChannelSession) mutuallyAuthenticate() error {
}
// open is an internal method that sends an open APDU.
func
(
s
*
SecureChannelSession
)
open
()
(
*
R
esponseAPDU
,
error
)
{
return
transmit
(
s
.
card
,
&
C
ommandAPDU
{
func
(
s
*
SecureChannelSession
)
open
()
(
*
r
esponseAPDU
,
error
)
{
return
transmit
(
s
.
card
,
&
c
ommandAPDU
{
Cla
:
claSCWallet
,
Ins
:
insOpenSecureChannel
,
P1
:
s
.
PairingIndex
,
...
...
@@ -204,8 +208,8 @@ func (s *SecureChannelSession) open() (*ResponseAPDU, error) {
}
// pair is an internal method that sends a pair APDU.
func
(
s
*
SecureChannelSession
)
pair
(
p1
uint8
,
data
[]
byte
)
(
*
R
esponseAPDU
,
error
)
{
return
transmit
(
s
.
card
,
&
C
ommandAPDU
{
func
(
s
*
SecureChannelSession
)
pair
(
p1
uint8
,
data
[]
byte
)
(
*
r
esponseAPDU
,
error
)
{
return
transmit
(
s
.
card
,
&
c
ommandAPDU
{
Cla
:
claSCWallet
,
Ins
:
insPair
,
P1
:
p1
,
...
...
@@ -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.
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
{
return
nil
,
fmt
.
Errorf
(
"Channel not open"
)
}
...
...
@@ -234,7 +238,7 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
copy
(
fulldata
,
s
.
iv
)
copy
(
fulldata
[
len
(
s
.
iv
)
:
],
data
)
response
,
err
:=
transmit
(
s
.
card
,
&
C
ommandAPDU
{
response
,
err
:=
transmit
(
s
.
card
,
&
c
ommandAPDU
{
Cla
:
cla
,
Ins
:
ins
,
P1
:
p1
,
...
...
@@ -260,7 +264,7 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b
return
nil
,
fmt
.
Errorf
(
"Invalid MAC in response"
)
}
rapdu
:=
&
R
esponseAPDU
{}
rapdu
:=
&
r
esponseAPDU
{}
rapdu
.
deserialize
(
plainData
)
if
rapdu
.
Sw1
!=
sw1Ok
{
...
...
accounts/scwallet/wallet.go
View file @
7d5886dc
...
...
@@ -27,6 +27,7 @@ import (
"errors"
"fmt"
"math/big"
"sort"
"strings"
"sync"
"time"
...
...
@@ -51,6 +52,12 @@ var ErrPUKNeeded = errors.New("smartcard: puk needed")
// and send it back.
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
// there is already a paired and unlocked session.
var
ErrAlreadyOpen
=
errors
.
New
(
"smartcard: already open"
)
...
...
@@ -65,8 +72,16 @@ var (
)
const
(
claISO7816
=
0
claSCWallet
=
0x80
insSelect
=
0xA4
insGetResponse
=
0xC0
sw1GetResponse
=
0x61
sw1Ok
=
0x90
insVerifyPin
=
0x20
insUnblockPin
=
0x22
insExportKey
=
0xC2
insSign
=
0xC0
insLoadKey
=
0xD0
...
...
@@ -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.
// 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.
func
transmit
(
card
*
scard
.
Card
,
command
*
CommandAPDU
)
(
*
R
esponseAPDU
,
error
)
{
func
transmit
(
card
*
scard
.
Card
,
command
*
commandAPDU
)
(
*
r
esponseAPDU
,
error
)
{
data
,
err
:=
command
.
serialize
()
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -128,14 +143,14 @@ func transmit(card *scard.Card, command *CommandAPDU) (*ResponseAPDU, error) {
return
nil
,
err
}
response
:=
new
(
R
esponseAPDU
)
response
:=
new
(
r
esponseAPDU
)
if
err
=
response
.
deserialize
(
responseData
);
err
!=
nil
{
return
nil
,
err
}
// Are we being asked to fetch the response separately?
if
response
.
Sw1
==
sw1GetResponse
&&
(
command
.
Cla
!=
claISO7816
||
command
.
Ins
!=
insGetResponse
)
{
return
transmit
(
card
,
&
C
ommandAPDU
{
return
transmit
(
card
,
&
c
ommandAPDU
{
Cla
:
claISO7816
,
Ins
:
insGetResponse
,
P1
:
0
,
...
...
@@ -186,7 +201,7 @@ 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
,
&
C
ommandAPDU
{
response
,
err
:=
transmit
(
w
.
card
,
&
c
ommandAPDU
{
Cla
:
claISO7816
,
Ins
:
insSelect
,
P1
:
4
,
...
...
@@ -209,13 +224,11 @@ func (w *Wallet) ping() error {
w
.
lock
.
Lock
()
defer
w
.
lock
.
Unlock
()
if
!
w
.
session
.
paired
()
{
// We can't ping if not paired
if
!
w
.
session
.
paired
()
{
return
nil
}
_
,
err
:=
w
.
session
.
getWalletStatus
()
if
err
!=
nil
{
if
_
,
err
:=
w
.
session
.
walletStatus
();
err
!=
nil
{
return
err
}
return
nil
...
...
@@ -235,16 +248,13 @@ func (w *Wallet) pair(puk []byte) error {
if
w
.
session
.
paired
()
{
return
fmt
.
Errorf
(
"Wallet already paired"
)
}
pairing
,
err
:=
w
.
session
.
pair
(
puk
)
if
err
!=
nil
{
return
err
}
if
err
=
w
.
Hub
.
setPairing
(
w
,
&
pairing
);
err
!=
nil
{
return
err
}
return
w
.
session
.
authenticate
(
pairing
)
}
...
...
@@ -285,19 +295,26 @@ func (w *Wallet) Status() (string, error) {
w
.
lock
.
Lock
()
defer
w
.
lock
.
Unlock
()
// If the card is not paired, we can only wait
if
!
w
.
session
.
paired
()
{
return
"Unpaired"
,
nil
return
"Unpaired
, waiting for PUK
"
,
nil
}
status
,
err
:=
w
.
session
.
getW
alletStatus
()
// Yay, we have an encrypted session, retrieve the actual status
status
,
err
:=
w
.
session
.
w
alletStatus
()
if
err
!=
nil
{
return
"Error"
,
err
}
if
w
.
session
.
verified
{
return
fmt
.
Sprintf
(
"Open, %s"
,
status
),
nil
}
else
{
return
fmt
.
Sprintf
(
"Locked, %s"
,
status
),
nil
return
fmt
.
Sprintf
(
"Failed: %v"
,
err
),
err
}
switch
{
case
!
w
.
session
.
verified
&&
status
.
PinRetryCount
==
0
:
return
fmt
.
Sprintf
(
"Blocked, waiting for PUK and new PIN"
),
nil
case
!
w
.
session
.
verified
:
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 {
// pairing key or form the supplied PUK code.
if
!
w
.
session
.
paired
()
{
// 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
{
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
passphrase
==
""
{
return
ErrPUKNeeded
...
...
@@ -338,16 +355,33 @@ func (w *Wallet) Open(passphrase string) error {
if
err
:=
w
.
pair
([]
byte
(
passphrase
));
err
!=
nil
{
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
{
return
err
}
default
:
if
err
:=
w
.
session
.
unblockPin
([]
byte
(
passphrase
));
err
!=
nil
{
return
err
}
}
// Smart card paired and unlocked, initialize and register
w
.
deriveReq
=
make
(
chan
chan
struct
{})
w
.
deriveQuit
=
make
(
chan
chan
error
)
...
...
@@ -415,7 +449,7 @@ func (w *Wallet) selfDerive() {
reqc
<-
struct
{}{}
continue
}
pairing
:=
w
.
Hub
.
getP
airing
(
w
)
pairing
:=
w
.
Hub
.
p
airing
(
w
)
// Device lock obtained, derive the next batch of accounts
var
(
...
...
@@ -519,18 +553,12 @@ func (w *Wallet) Accounts() []accounts.Account {
w
.
lock
.
Lock
()
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
))
for
address
,
path
:=
range
pairing
.
Accounts
{
ret
=
append
(
ret
,
w
.
makeAccount
(
address
,
path
))
}
for
i
:=
0
;
i
<
len
(
ret
);
i
++
{
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
]
}
}
}
sort
.
Sort
(
accounts
.
AccountsByURL
(
ret
))
return
ret
}
return
nil
...
...
@@ -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.
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
]
return
ok
}
...
...
@@ -576,7 +604,7 @@ func (w *Wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Accoun
}
if
pin
{
pairing
:=
w
.
Hub
.
getP
airing
(
w
)
pairing
:=
w
.
Hub
.
p
airing
(
w
)
pairing
.
Accounts
[
account
.
Address
]
=
path
if
err
:=
w
.
Hub
.
setPairing
(
w
,
pairing
);
err
!=
nil
{
return
accounts
.
Account
{},
err
...
...
@@ -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
// not found, attempts to parse the derivation path from the account's URL.
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
{
return
path
,
nil
}
...
...
@@ -745,6 +773,16 @@ func (s *Session) verifyPin(pin []byte) error {
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.
func
(
s
*
Session
)
release
()
error
{
return
s
.
Wallet
.
card
.
Disconnect
(
scard
.
LeaveCard
)
...
...
@@ -773,32 +811,25 @@ type walletStatus struct {
SupportsPKDerivation
bool
// Whether the card supports doing public key derivation itself
}
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.
func
(
s
*
Session
)
getWalletStatus
()
(
*
walletStatus
,
error
)
{
// walletStatus fetches the wallet's status from the card.
func
(
s
*
Session
)
walletStatus
()
(
*
walletStatus
,
error
)
{
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insStatus
,
statusP1WalletStatus
,
0
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
status
:=
new
(
walletStatus
)
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
status
,
"tag:3"
);
err
!=
nil
{
return
nil
,
err
}
return
status
,
nil
}
//
getD
erivationPath fetches the wallet's current derivation path from the card.
func
(
s
*
Session
)
getD
erivationPath
()
(
accounts
.
DerivationPath
,
error
)
{
//
d
erivationPath fetches the wallet's current derivation path from the card.
func
(
s
*
Session
)
d
erivationPath
()
(
accounts
.
DerivationPath
,
error
)
{
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insStatus
,
statusP1Path
,
0
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
buf
:=
bytes
.
NewReader
(
response
.
Data
)
path
:=
make
(
accounts
.
DerivationPath
,
len
(
response
.
Data
)
/
4
)
return
path
,
binary
.
Read
(
buf
,
binary
.
BigEndian
,
&
path
)
...
...
@@ -845,11 +876,11 @@ func (s *Session) derive(path accounts.DerivationPath) (accounts.Account, error)
// start again.
remainingPath
:=
path
pubkey
,
err
:=
s
.
getP
ublicKey
()
pubkey
,
err
:=
s
.
p
ublicKey
()
if
err
!=
nil
{
return
accounts
.
Account
{},
err
}
currentPath
,
err
:=
s
.
getD
erivationPath
()
currentPath
,
err
:=
s
.
d
erivationPath
()
if
err
!=
nil
{
return
accounts
.
Account
{},
err
}
...
...
@@ -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
{
return
nil
,
err
}
rbytes
,
sbytes
:=
keyinfo
.
Signature
.
R
.
Bytes
(),
keyinfo
.
Signature
.
S
.
Bytes
()
sig
:=
make
([]
byte
,
65
)
copy
(
sig
[
32
-
len
(
rbytes
)
:
32
],
rbytes
)
...
...
@@ -920,12 +950,10 @@ func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, e
if
err
!=
nil
{
return
nil
,
err
}
_
,
err
=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insDeriveKey
,
deriveP1Assisted
|
deriveP1Append
,
deriveP2PublicKey
,
pubkey
)
if
err
!=
nil
{
return
nil
,
err
}
return
pubkey
,
nil
}
...
...
@@ -935,18 +963,16 @@ type keyExport struct {
PrivateKey
[]
byte
`asn1:"tag:1,optional"`
}
//
getP
ublicKey returns the public key for the current derivation path.
func
(
s
*
Session
)
getP
ublicKey
()
([]
byte
,
error
)
{
//
p
ublicKey returns the public key for the current derivation path.
func
(
s
*
Session
)
p
ublicKey
()
([]
byte
,
error
)
{
response
,
err
:=
s
.
Channel
.
TransmitEncrypted
(
claSCWallet
,
insExportKey
,
exportP1Any
,
exportP2Pubkey
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
keys
:=
new
(
keyExport
)
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
keys
,
"tag:1"
);
err
!=
nil
{
return
nil
,
err
}
return
keys
.
PublicKey
,
nil
}
...
...
@@ -974,12 +1000,10 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error
if
err
!=
nil
{
return
nil
,
err
}
sigdata
:=
new
(
signatureData
)
if
_
,
err
:=
asn1
.
UnmarshalWithParams
(
response
.
Data
,
sigdata
,
"tag:0"
);
err
!=
nil
{
return
nil
,
err
}
// Serialize the signature
rbytes
,
sbytes
:=
sigdata
.
Signature
.
R
.
Bytes
(),
sigdata
.
Signature
.
S
.
Bytes
()
sig
:=
make
([]
byte
,
65
)
...
...
@@ -991,7 +1015,6 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error
if
err
!=
nil
{
return
nil
,
err
}
log
.
Debug
(
"Signed using smartcard"
,
"deriveTime"
,
deriveTime
.
Sub
(
startTime
),
"signingTime"
,
time
.
Since
(
deriveTime
))
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) {
}
}
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
())
:
// PIN input requested, fetch from the user and call open again
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