-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
policy.go
105 lines (91 loc) · 3.64 KB
/
policy.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
/*
Copyright 2022 Gravitational, Inc.
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 keys
import (
"fmt"
"regexp"
"github.com/gravitational/trace"
)
// PrivateKeyPolicy is a requirement for client private key storage.
type PrivateKeyPolicy string
const (
// PrivateKeyPolicyNone means that the client can store their private keys
// anywhere (usually on disk).
PrivateKeyPolicyNone PrivateKeyPolicy = "none"
// PrivateKeyPolicyHardwareKey means that the client must use a valid
// hardware key to generate and store their private keys securely.
PrivateKeyPolicyHardwareKey PrivateKeyPolicy = "hardware_key"
// PrivateKeyPolicyHardwareKeyTouch means that the client must use a valid
// hardware key to generate and store their private keys securely, and
// this key must require touch to be accessed and used.
PrivateKeyPolicyHardwareKeyTouch PrivateKeyPolicy = "hardware_key_touch"
)
// VerifyPolicy verifies that the given policy meets the requirements of this policy.
// If not, it will return a private key policy error, which can be parsed to retrieve
// the unmet policy.
func (p PrivateKeyPolicy) VerifyPolicy(policy PrivateKeyPolicy) error {
switch p {
case PrivateKeyPolicyNone:
return nil
case PrivateKeyPolicyHardwareKey:
if policy == PrivateKeyPolicyHardwareKey || policy == PrivateKeyPolicyHardwareKeyTouch {
return nil
}
case PrivateKeyPolicyHardwareKeyTouch:
if policy == PrivateKeyPolicyHardwareKeyTouch {
return nil
}
}
return NewPrivateKeyPolicyError(p)
}
// IsHardwareKeyVerified return true if this private key policy requires a hardware key.
func (p PrivateKeyPolicy) IsHardwareKeyVerified() bool {
switch p {
case PrivateKeyPolicyHardwareKey, PrivateKeyPolicyHardwareKeyTouch:
return true
}
return false
}
// MFAVerified checks that meet this private key policy counts towards MFA verification.
func (p PrivateKeyPolicy) MFAVerified() bool {
return p == PrivateKeyPolicyHardwareKeyTouch
}
func (p PrivateKeyPolicy) validate() error {
switch p {
case PrivateKeyPolicyNone, PrivateKeyPolicyHardwareKey, PrivateKeyPolicyHardwareKeyTouch:
return nil
}
return trace.BadParameter("%q is not a valid key policy", p)
}
var privateKeyPolicyErrRegex = regexp.MustCompile(`private key policy not met: (\w+)`)
func NewPrivateKeyPolicyError(p PrivateKeyPolicy) error {
return trace.BadParameter(fmt.Sprintf("private key policy not met: %s", p))
}
// ParsePrivateKeyPolicyError checks if the given error is a private key policy
// error and returns the contained unmet PrivateKeyPolicy.
func ParsePrivateKeyPolicyError(err error) (PrivateKeyPolicy, error) {
// subMatches should have two groups - the full string and the policy "(\w+)"
subMatches := privateKeyPolicyErrRegex.FindStringSubmatch(err.Error())
if subMatches == nil || len(subMatches) != 2 {
return "", trace.BadParameter("provided error is not a key policy error")
}
policy := PrivateKeyPolicy(subMatches[1])
if err := policy.validate(); err != nil {
return "", trace.Wrap(err)
}
return policy, nil
}
// IsPrivateKeyPolicyError returns true if the given error is a private key policy error.
func IsPrivateKeyPolicyError(err error) bool {
return privateKeyPolicyErrRegex.MatchString(err.Error())
}