/
registry.go
103 lines (85 loc) · 2.35 KB
/
registry.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
package key
import (
"crypto/rand"
"fmt"
"io"
"sync"
)
const (
KeyTypeRSA = "rsa"
KeyTypeECDSA = "ecdsa"
KeyTypeSecret = "secret"
)
// Descriptor holds the configurable options for a key Pair
type Descriptor struct {
// Kid is the key id to use initially. If unset, the name of the key is used. Note that the kid can
// change is the key is rotated or updated during application execution.
Kid string
// Type indicates the type of key. This field dictates both how the key File is read or how the key
// is generated. The default is "rsa".
Type string
// Bits indicates the bit size for a generated key
Bits int
// File is the system path to a file where the key is stored. If set, this file must exist and contain
// either a secret or a PEM-encoded key pair. If this field is not set, a key is generated.
File string
}
// Registry holds zero or more key Pairs
type Registry interface {
// Get returns the Pair associated with a given key identifier
Get(kid string) (Pair, bool)
// Register creates a new Pair from a Descriptor and stores it in this registry
Register(Descriptor) (Pair, error)
}
// NewRegistry creates a new key Registry backed by a given source of randomness for generation.
// If random is nil, crypto/rand.Reader is used.
func NewRegistry(random io.Reader) Registry {
if random == nil {
random = rand.Reader
}
return ®istry{
pairs: make(map[string]Pair),
random: random,
}
}
type registry struct {
lock sync.RWMutex
pairs map[string]Pair
random io.Reader
}
func (r *registry) Get(kid string) (Pair, bool) {
r.lock.RLock()
p, ok := r.pairs[kid]
r.lock.RUnlock()
return p, ok
}
func (r *registry) newPair(d Descriptor) (Pair, error) {
if len(d.File) > 0 {
return ReadPair(d.Kid, d.File)
}
switch d.Type {
case "":
fallthrough
case KeyTypeRSA:
return GenerateRSAPair(d.Kid, r.random, d.Bits)
case KeyTypeECDSA:
return GenerateECDSAPair(d.Kid, r.random, d.Bits)
case KeyTypeSecret:
return GenerateSecretPair(d.Kid, r.random, d.Bits)
default:
return nil, fmt.Errorf("Invalid key type: %s", d.Type)
}
}
func (r *registry) Register(d Descriptor) (Pair, error) {
p, err := r.newPair(d)
if err != nil {
return nil, err
}
defer r.lock.Unlock()
r.lock.Lock()
if _, ok := r.pairs[p.KID()]; ok {
return nil, fmt.Errorf("Key id already used: %s", p.KID())
}
r.pairs[p.KID()] = p
return p, nil
}