ssh/agent: don't accept keys with unsupported constraints

The in-memory keyring cannot enforce constraint extensions, so silently
accepting a key that carries them gave callers a false sense of
restriction. Refuse keys with constraint extensions instead: a key
whose constraints cannot be enforced must not be loaded. This behavior
is consistent with OpenSSH.

This is a deliberate behavior change: keyring.Add previously accepted
and ignored ConstraintExtensions and now returns an error.

This issue was found during a security audit by NCC Group Cryptography
Services, sponsored by Teleport.

Fixes CVE-2026-39832
Fixes golang/go#79435

Change-Id: I6ca4f1c29f8edfabb287fe07299641f70896d5fe
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/778641
Auto-Submit: Neal Patel <nealpatel@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Neal Patel <neal@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Neal Patel <nealpatel@google.com>
This commit is contained in:
Nicola
2026-05-21 10:47:08 -07:00
committed by Gopher Robot
parent a1ce0fee12
commit e3d1254f1e
2 changed files with 33 additions and 3 deletions
+9 -3
View File
@@ -143,15 +143,21 @@ func (r *keyring) List() ([]*Key, error) {
return ids, nil
}
// Insert adds a private key to the keyring. If a certificate
// is given, that certificate is added as public key. Note that
// any constraints given are ignored.
// Add adds a private key to the keyring. If a certificate is given, that
// certificate is added as public key.
//
// Add returns an error if key contains ConstraintExtensions.
func (r *keyring) Add(key AddedKey) error {
r.mu.Lock()
defer r.mu.Unlock()
if r.locked {
return errLocked
}
if len(key.ConstraintExtensions) > 0 {
return errors.New("agent: constraint extensions are present but not supported")
}
signer, err := ssh.NewSignerFromKey(key.PrivateKey)
if err != nil {
+24
View File
@@ -120,3 +120,27 @@ func TestAddDuplicateKey(t *testing.T) {
t.Fatal("key with the updated comment not found")
}
}
func TestAddKeyWithConstraints(t *testing.T) {
// Verifies the keyring refuses keys carrying constraint extensions it
// cannot enforce.
agent, cleanup := startKeyringAgent(t)
defer cleanup()
constraints := []ConstraintExtension{
{
ExtensionName: "extension1",
ExtensionDetails: []byte("details1"),
},
}
key := testPrivateKeys["rsa"]
err := agent.Add(AddedKey{
PrivateKey: key,
ConstraintExtensions: constraints,
})
if err == nil {
t.Fatal("adding a key with unsupported constraints succeeded")
}
}