Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Latest commit

 

History

History
History
149 lines (137 loc) · 5.02 KB

File metadata and controls

149 lines (137 loc) · 5.02 KB
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
package cryptokeys
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"time"
"golang.org/x/xerrors"
)
const (
caCertPEMBlockType = "CERTIFICATE"
caKeyPEMBlockType = "EC PRIVATE KEY"
// clockSkewTolerance backdates the CA certificate's NotBefore and extends
// its NotAfter so that replicas with mildly skewed clocks still accept it.
clockSkewTolerance = time.Hour
)
// NATSCA is the decoded form of a single nats_ca crypto key row, produced by
// the generic crypto key cache (see idSecret). The CA signs the ephemeral leaf
// certificates that replicas use for NATS cluster mTLS.
//
// The active CA is served by a SigningKeycache.SigningKey call for the nats_ca
// feature; a specific historical CA (for verifying a peer leaf minted under an
// earlier CA during a rotation overlap) is served by VerifyingKey with that
// row's sequence.
type NATSCA struct {
// Sequence is the crypto_keys sequence of the row this CA came from.
Sequence int32
// Cert is the CA certificate used to sign or verify leaf certificates.
Cert *x509.Certificate
// Key is the CA private key, used to sign leaves.
Key crypto.Signer
}
// generateCASecret generates a new self-signed CA certificate and private key
// for signing NATS cluster leaf certificates, PEM-encoded into a single
// bundle for storage in the crypto_keys secret column.
//
// anchorTime is the key row's starts_at (which may be in the future for a
// rotated-in key). keyDuration is the rotator's key duration: the row stays the
// active signer for that long. The certificate stays valid for NATSCAOverlap
// past that window so that, once the next CA becomes the active signer, this CA
// is still valid while replicas' key caches refresh onto the new one. Leaves
// are separately clamped to expire before this NotAfter (see coderd/x/nats
// mintLeaf), so the overlap only needs to cover the cache-refresh transition.
func generateCASecret(anchorTime time.Time, keyDuration time.Duration) (string, error) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return "", xerrors.Errorf("generate key: %w", err)
}
// 128-bit random serial per CA/Browser Forum conventions.
serial, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
if err != nil {
return "", xerrors.Errorf("generate serial: %w", err)
}
template := &x509.Certificate{
SerialNumber: serial,
Subject: pkix.Name{
CommonName: "coder-nats-ca",
},
NotBefore: anchorTime.Add(-clockSkewTolerance),
NotAfter: anchorTime.Add(keyDuration + NATSCAOverlap),
KeyUsage: x509.KeyUsageCertSign,
BasicConstraintsValid: true,
IsCA: true,
MaxPathLenZero: true,
}
der, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key)
if err != nil {
return "", xerrors.Errorf("create certificate: %w", err)
}
keyDER, err := x509.MarshalECPrivateKey(key)
if err != nil {
return "", xerrors.Errorf("marshal private key: %w", err)
}
var secret []byte
secret = append(secret, pem.EncodeToMemory(&pem.Block{Type: caCertPEMBlockType, Bytes: der})...)
secret = append(secret, pem.EncodeToMemory(&pem.Block{Type: caKeyPEMBlockType, Bytes: keyDER})...)
return string(secret), nil
}
// parseCASecret parses a PEM bundle produced by generateCASecret back into
// the CA certificate and private key.
func parseCASecret(secret string) (*x509.Certificate, crypto.Signer, error) {
var (
cert *x509.Certificate
key *ecdsa.PrivateKey
)
rest := []byte(secret)
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil {
break
}
switch block.Type {
case caCertPEMBlockType:
if cert != nil {
return nil, nil, xerrors.New("multiple certificates in CA secret")
}
var err error
cert, err = x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, nil, xerrors.Errorf("parse certificate: %w", err)
}
case caKeyPEMBlockType:
if key != nil {
return nil, nil, xerrors.New("multiple private keys in CA secret")
}
var err error
key, err = x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return nil, nil, xerrors.Errorf("parse private key: %w", err)
}
default:
return nil, nil, xerrors.Errorf("unexpected PEM block type: %q", block.Type)
}
}
if cert == nil {
return nil, nil, xerrors.New("no certificate in CA secret")
}
if key == nil {
return nil, nil, xerrors.New("no private key in CA secret")
}
if !key.PublicKey.Equal(cert.PublicKey) {
return nil, nil, xerrors.New("private key does not match certificate")
}
// Reject a structurally valid bundle whose certificate cannot act as a
// signing CA. Without this, a corrupted secret could yield a non-CA cert
// that silently becomes the active signer; leaves signed under it would
// then fail x509 verification on every replica.
if !cert.IsCA || !cert.BasicConstraintsValid || cert.KeyUsage&x509.KeyUsageCertSign == 0 {
return nil, nil, xerrors.New("certificate is not a valid signing CA")
}
return cert, key, nil
}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.