-
Notifications
You must be signed in to change notification settings - Fork 11
/
key.go
197 lines (166 loc) · 4.97 KB
/
key.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Copyright (c) Facebook, Inc. and its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sks
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/sha1"
"errors"
"fmt"
"io"
"strings"
"github.com/facebookincubator/sks/attest"
)
// Key is an interface that implements the crypto.Signer interface along with
// extra functions specific to SKS
type Key interface {
crypto.Signer
// Remove removes that key from SKS
Remove() error
// Hash returns the SHA1 hash of the public portion of the key
Hash() []byte
// Label returns the label of the key
Label() string
// Tag returns the tag of the key
Tag() string
// Encrypted returns the encrypted blob of TPM2.0 transient keys
EncryptedBlob() ([]byte, []byte, error)
// AttestKey will cryptographically attest the key
Attest() error
// Close closes the key
Close() error
}
// regularKey is an ECDSA P-256 key whose private portion is stored in SKS
type regularKey struct {
pubKey *ecdsa.PublicKey
label string
tag string
}
// LoadKey returns an existing key backed by SKS given the corresponding label, tag, and hash
func LoadKey(label, tag string, hash []byte) (Key, error) {
if pubKey, err := findPubKey(label, tag, hash); err != nil {
return nil, err
} else if pubKey != nil {
return ®ularKey{
pubKey: rawToEcdsa(pubKey),
label: label,
tag: tag,
}, nil
}
return nil, fmt.Errorf(ErrFindPubKeyNil, label, tag)
}
// AttestKey will attest the provided SKS key
func AttestKey(label, tag string, attestor attest.Attestor) (*attest.Resp, error) {
return attestKey(label, tag, attestor)
}
// NewKey returns a new key backed by SKS given the corresponding label and tag
// useBiometrics and accessibleWhenUnlockedOnly are not taken into account if the key already exist
func NewKey(label, tag string, useBiometrics, accessibleWhenUnlockedOnly bool, hash []byte) (Key, error) {
if pubKey, err := findPubKey(label, tag, hash); err != nil {
return nil, err
} else if pubKey != nil {
return ®ularKey{
pubKey: rawToEcdsa(pubKey),
label: label,
tag: tag,
}, nil
}
pubKey, err := genKeyPair(label, tag, useBiometrics, accessibleWhenUnlockedOnly)
if err != nil {
return nil, err
}
return ®ularKey{
pubKey: rawToEcdsa(pubKey),
label: label,
tag: tag,
}, nil
}
// Remove removes the key from the SKS
func (k *regularKey) Remove() error {
if k.label == "" || k.tag == "" {
return errors.New(ErrLabelOrTagUnspecified)
}
_, err := removeKey(k.label, k.tag, k.Hash())
return err
}
// Public returns the public key of this key
func (k *regularKey) Public() crypto.PublicKey {
if k.pubKey != nil {
return k.pubKey
}
pubKey, err := findPubKey(k.label, k.tag, nil)
if err != nil {
return nil
}
if pubKey == nil {
return nil
}
return rawToEcdsa(pubKey)
}
// Sign signs the arbitrary data in digest with the key
// The first argument `rand` is discarded in favour of the internal implementation
func (k *regularKey) Sign(_ io.Reader, digest []byte, _ crypto.SignerOpts) ([]byte, error) {
return signWithKey(k.label, k.tag, k.Hash(), digest)
}
// HashKey returns the SHA1 hash of the key
func (k *regularKey) Hash() []byte {
if k.pubKey == nil {
return nil
}
rawKey := elliptic.Marshal(k.pubKey.Curve, k.pubKey.X, k.pubKey.Y)
h := sha1.Sum(rawKey)
return h[:]
}
// Label returns the label of the key
func (k *regularKey) Label() string {
return k.label
}
// Tag returns the tag of the key
func (k *regularKey) Tag() string {
return k.tag
}
// Close closes the key
func (k *regularKey) Close() error {
return nil
}
// Attest cryptographically attests the key
func (k *regularKey) Attest() error {
return fmt.Errorf(ErrNotImplemented, "Attest")
}
// EncryptedBlob returns the encrypted blob of the TPM2.0 transient key
func (k *regularKey) EncryptedBlob() ([]byte, []byte, error) {
return nil, nil, fmt.Errorf(ErrNotImplemented, "EncryptedBlob")
}
// FromLabelTag constructs a Key identified by label and tag
// without looking up the key in SKS so the public key of the
// structure is not populated.
func FromLabelTag(labelTag string) Key {
f := strings.SplitN(labelTag, ":", 2)
k := ®ularKey{
label: f[0],
}
if len(f) > 1 {
k.tag = f[1]
}
return k
}
// rawToEcdsa turns an ASN.1 encoded byte stream to an ecdsa public key
// It is assumed that the curve of the key is P-256
func rawToEcdsa(raw []byte) *ecdsa.PublicKey {
ecKey := new(ecdsa.PublicKey)
ecKey.Curve = elliptic.P256()
ecKey.X, ecKey.Y = elliptic.Unmarshal(ecKey.Curve, raw)
return ecKey
}