-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Expand file tree
/
Copy pathhardware_attestation.go
More file actions
181 lines (155 loc) · 5.22 KB
/
hardware_attestation.go
File metadata and controls
181 lines (155 loc) · 5.22 KB
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
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
package key
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/subtle"
"encoding/json"
"fmt"
"io"
"go4.org/mem"
)
var ErrUnsupported = fmt.Errorf("key type not supported on this platform")
const hardwareAttestPublicHexPrefix = "hwattestpub:"
const pubkeyLength = 65 // uncompressed P-256
// HardwareAttestationKey describes a hardware-backed key that is used to
// identify a node. Implementation details will
// vary based on the platform in use (SecureEnclave for Apple, TPM for
// Windows/Linux, Android Hardware-backed Keystore).
// This key can only be marshalled and unmarshaled on the same machine.
type HardwareAttestationKey interface {
crypto.Signer
json.Marshaler
json.Unmarshaler
io.Closer
Clone() HardwareAttestationKey
IsZero() bool
}
// HardwareAttestationPublicFromPlatformKey creates a HardwareAttestationPublic
// for communicating the public component of the hardware attestation key
// with control and other nodes.
func HardwareAttestationPublicFromPlatformKey(k HardwareAttestationKey) HardwareAttestationPublic {
if k == nil {
return HardwareAttestationPublic{}
}
pub := k.Public()
ecdsaPub, ok := pub.(*ecdsa.PublicKey)
if !ok {
panic("hardware attestation key is not ECDSA")
}
bytes, err := ecdsaPub.Bytes()
if err != nil {
panic(err)
}
if len(bytes) != pubkeyLength {
panic("hardware attestation key is not uncompressed ECDSA P-256")
}
var ecdsaPubArr [pubkeyLength]byte
copy(ecdsaPubArr[:], bytes)
return HardwareAttestationPublic{k: ecdsaPubArr}
}
// HardwareAttestationPublic is the public key counterpart to
// HardwareAttestationKey.
type HardwareAttestationPublic struct {
k [pubkeyLength]byte
}
func (k *HardwareAttestationPublic) Clone() *HardwareAttestationPublic {
if k == nil {
return nil
}
var out HardwareAttestationPublic
copy(out.k[:], k.k[:])
return &out
}
func (k HardwareAttestationPublic) Equal(o HardwareAttestationPublic) bool {
return subtle.ConstantTimeCompare(k.k[:], o.k[:]) == 1
}
// IsZero reports whether k is the zero value.
func (k HardwareAttestationPublic) IsZero() bool {
var zero [pubkeyLength]byte
return k.k == zero
}
// String returns the hex-encoded public key with a type prefix.
func (k HardwareAttestationPublic) String() string {
bs, err := k.MarshalText()
if err != nil {
panic(err)
}
return string(bs)
}
// MarshalText implements encoding.TextMarshaler.
func (k HardwareAttestationPublic) MarshalText() ([]byte, error) {
if k.IsZero() {
return nil, nil
}
return k.AppendText(nil)
}
// UnmarshalText implements encoding.TextUnmarshaler. It expects a typed prefix
// followed by a hex encoded representation of k.
func (k *HardwareAttestationPublic) UnmarshalText(b []byte) error {
if len(b) == 0 {
*k = HardwareAttestationPublic{}
return nil
}
kb := make([]byte, pubkeyLength)
if err := parseHex(kb, mem.B(b), mem.S(hardwareAttestPublicHexPrefix)); err != nil {
return err
}
_, err := ecdsa.ParseUncompressedPublicKey(elliptic.P256(), kb)
if err != nil {
return err
}
copy(k.k[:], kb)
return nil
}
func (k HardwareAttestationPublic) AppendText(dst []byte) ([]byte, error) {
return appendHexKey(dst, hardwareAttestPublicHexPrefix, k.k[:]), nil
}
// Verifier returns the ECDSA public key for verifying signatures made by k.
func (k HardwareAttestationPublic) Verifier() *ecdsa.PublicKey {
pk, err := ecdsa.ParseUncompressedPublicKey(elliptic.P256(), k.k[:])
if err != nil {
panic(err)
}
return pk
}
// emptyHardwareAttestationKey is a function that returns an empty
// HardwareAttestationKey suitable for use with JSON unmarshaling.
var emptyHardwareAttestationKey func() HardwareAttestationKey
// createHardwareAttestationKey is a function that creates a new
// HardwareAttestationKey for the current platform.
var createHardwareAttestationKey func() (HardwareAttestationKey, error)
// HardwareAttestationKeyFn is a callback function type that returns a HardwareAttestationKey
// and an error. It is used to register platform-specific implementations of
// HardwareAttestationKey.
type HardwareAttestationKeyFn func() (HardwareAttestationKey, error)
// RegisterHardwareAttestationKeyFns registers a hardware attestation
// key implementation for the current platform.
func RegisterHardwareAttestationKeyFns(emptyFn func() HardwareAttestationKey, createFn HardwareAttestationKeyFn) {
if emptyHardwareAttestationKey != nil {
panic("emptyPlatformHardwareAttestationKey already registered")
}
emptyHardwareAttestationKey = emptyFn
if createHardwareAttestationKey != nil {
panic("createPlatformHardwareAttestationKey already registered")
}
createHardwareAttestationKey = createFn
}
// NewEmptyHardwareAttestationKey returns an empty HardwareAttestationKey
// suitable for JSON unmarshaling.
func NewEmptyHardwareAttestationKey() (HardwareAttestationKey, error) {
if emptyHardwareAttestationKey == nil {
return nil, ErrUnsupported
}
return emptyHardwareAttestationKey(), nil
}
// NewHardwareAttestationKey returns a newly created HardwareAttestationKey for
// the current platform.
func NewHardwareAttestationKey() (HardwareAttestationKey, error) {
if createHardwareAttestationKey == nil {
return nil, ErrUnsupported
}
return createHardwareAttestationKey()
}