A certificate is issued once and kept
Every signing carries a fresh random serial, so a mesh that signed per composition composed a different declaration every time it was asked what a machine should be. Every machine carrying a certificate then stood eternally "waiting" — pushed seconds ago and already behind — and the forge test, the first to wait for settledness on such a machine, failed four runs in a row wearing three other faults' clothes. Found live on a kept mesh, which is what settled it: two plans seconds apart, identical to the byte but for one serial, in the certificate file. Deduction had four theories; the diff had one line. The keeping columns had existed since the serving key's migration — "and what was issued for it" — and were written by nothing, the same shape ReleasePorts was found in this morning. Kept beside the serving key it certifies, and it stands while the name, the key and the clock agree: a node rejoining with a new key or renamed gets a fresh signing, exactly as if nothing were kept, and so does one whose certificate is into its last stretch of life. The port's rule and the secret's, applied to the third thing composed fresh each time.
This commit is contained in:
@@ -117,6 +117,25 @@ func (i *Identity) Certify(ctx context.Context, node, name, servingKey string) (
|
||||
return "", fmt.Errorf("%s presented something that is not a serving key", node)
|
||||
}
|
||||
|
||||
// **Issued once and kept** — the port's rule and the secret's, applied to the certificate.
|
||||
// Every signing carries a fresh random serial, so a mesh that signed per composition
|
||||
// composed a different declaration every time it was asked what a machine should be — and
|
||||
// every machine carrying a certificate stood eternally "waiting", pushed seconds ago and
|
||||
// already behind. Found live on a kept mesh: two plans seconds apart, identical to the byte
|
||||
// but for one serial. The columns for keeping it had existed since the serving key's
|
||||
// migration — "and what was issued for it" — and were written by nothing, which is the same
|
||||
// shape ReleasePorts was found in.
|
||||
var kept *string
|
||||
err = i.store.Pool().QueryRow(ctx,
|
||||
`select certificate from node_key where serving_key = $1 and revoked is null`,
|
||||
servingKey).Scan(&kept)
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return "", err
|
||||
}
|
||||
if kept != nil && stillStands(*kept, name, public) {
|
||||
return *kept, nil
|
||||
}
|
||||
|
||||
authority, err := i.EstablishAuthority(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -147,7 +166,34 @@ func (i *Identity) Certify(ctx context.Context, node, name, servingKey string) (
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})), nil
|
||||
issued := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}))
|
||||
// Kept beside the key it certifies. A serving key nothing recorded keeps nothing, and is
|
||||
// certified fresh each time — which only a test does.
|
||||
if _, err := i.store.Pool().Exec(ctx,
|
||||
`update node_key set certificate = $2, certified_at = now()
|
||||
where serving_key = $1 and revoked is null`, servingKey, issued); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return issued, nil
|
||||
}
|
||||
|
||||
// stillStands says whether a kept certificate is still the one Certify would issue: same name,
|
||||
// same key, and enough life left that nothing downstream will meet its expiry. Any mismatch means
|
||||
// the world moved — the node rejoined with a new key, or its name changed — and the answer is a
|
||||
// fresh signing, exactly as if nothing were kept.
|
||||
func stillStands(kept, name string, public []byte) bool {
|
||||
parsed, err := parse(kept)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if len(parsed.DNSNames) != 1 || parsed.DNSNames[0] != name {
|
||||
return false
|
||||
}
|
||||
held, ok := parsed.PublicKey.(ed25519.PublicKey)
|
||||
if !ok || !held.Equal(ed25519.PublicKey(public)) {
|
||||
return false
|
||||
}
|
||||
return time.Until(parsed.NotAfter) > forever/10
|
||||
}
|
||||
|
||||
func parse(certificate string) (*x509.Certificate, error) {
|
||||
|
||||
Reference in New Issue
Block a user