-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathasym_key_verifier.go
117 lines (90 loc) · 2.53 KB
/
asym_key_verifier.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package isokey
import (
"bytes"
"crypto/ecdsa"
"crypto/x509"
"io/ioutil"
"time"
"math/big"
"crypto/sha256"
"github.com/jbenet/go-base58"
)
var _ = Verifier(new(AsymKeyVerifier))
//AsymKeyVerifier verifies ECDSA signed API keys
type AsymKeyVerifier struct {
//GetPublicKey allows you to dynamically use public keys based on the contents of a key.
//Returning nil indicates that no pubkey was found for key
GetPublicKey func(key *Key) *ecdsa.PublicKey
//Invalidator allows you to invalidate certain keys based off the Key's parameters (e.g when it was made.)
//Invalidator is ran after the key's signature has been validated.
//This is useful to deal with cases revolving compromised users.
Invalidator func(*Key) bool
}
//NewAsymKeyVerifier returns an instantiated AsymKeyVerifier which always uses pubkey
func NewAsymKeyVerifier(pubkey *ecdsa.PublicKey) *AsymKeyVerifier {
return &AsymKeyVerifier{
GetPublicKey: func(key *Key) *ecdsa.PublicKey {
return pubkey
},
}
}
//LoadPublicKey loads an ASN.1 ECDSA public key from a file.
func LoadPublicKey(filename string) (publicKey *ecdsa.PublicKey, err error) {
byt, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
pubKeyI, err := x509.ParsePKIXPublicKey(byt)
if err != nil {
return
}
pubKey, ok := pubKeyI.(*ecdsa.PublicKey)
if !ok {
return nil, ErrNotECPublicKey
}
return pubKey, err
}
//Invalidate invalidates a key
func (kv *AsymKeyVerifier) Invalidate(key *Key) bool {
if kv.Invalidator == nil {
return key.ExpiresAt.Before(time.Now())
}
return key.ExpiresAt.Before(time.Now()) || kv.Invalidator(key)
}
//Verify verifies and parses a key.
//It returns an error if the key is invalid.
func (kv *AsymKeyVerifier) Verify(digest string) (key *Key, err error) {
key = &Key{}
rawDigest := base58.Decode(digest)
buf := bytes.NewBuffer(rawDigest)
rLen, err := buf.ReadByte()
if err != nil {
return
}
r := make([]byte, rLen)
buf.Read(r)
sLen, err := buf.ReadByte()
if err != nil {
return
}
s := make([]byte, sLen)
buf.Read(s)
if buf.Len() != 20 {
return nil, ErrAsymMessageSize
}
key = unpack(buf.Bytes())
pubKey := kv.GetPublicKey(key)
if pubKey == nil {
return nil, ErrNoPubKey
}
//fmt.Printf("r %x s %x buf %x pkXY %s %s\n", r, s, buf.Bytes(), pubKey.X, pubKey.Y)
checksum := sha256.Sum256(buf.Bytes())
signhash := checksum[:16]
if !ecdsa.Verify(pubKey, signhash, big.NewInt(0).SetBytes(r), big.NewInt(0).SetBytes(s)) {
return key, ErrBadSignature
}
if kv.Invalidate(key) {
return key, ErrInvalid
}
return key, nil
}