Skip to content

Commit 2beaa59

Browse files
committed
ssh: add VerifiedPublicKeyCallback
Fixes golang/go#70795 Change-Id: I9b7c91f35f89495d1e9b5f6ec0c036c02a61d774 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/636335 Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: Junyang Shao <shaojunyang@google.com> Reviewed-by: Ilia Mirkin <imirkin@alum.mit.edu> Reviewed-by: Filippo Valsorda <filippo@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Jorge Hernández <jorgehcrda39@gmail.com>
1 parent 66c3d8c commit 2beaa59

File tree

2 files changed

+401
-0
lines changed

2 files changed

+401
-0
lines changed

ssh/server.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ type Permissions struct {
4444
// pass data from the authentication callbacks to the server
4545
// application layer.
4646
Extensions map[string]string
47+
48+
// ExtraData allows to store user defined data.
49+
ExtraData map[any]any
4750
}
4851

4952
type GSSAPIWithMICConfig struct {
@@ -127,6 +130,21 @@ type ServerConfig struct {
127130
// Permissions.Extensions entry.
128131
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
129132

133+
// VerifiedPublicKeyCallback, if non-nil, is called after a client
134+
// successfully confirms having control over a key that was previously
135+
// approved by PublicKeyCallback. The permissions object passed to the
136+
// callback is the one returned by PublicKeyCallback for the given public
137+
// key and its ownership is transferred to the callback. The returned
138+
// Permissions object can be the same object, optionally modified, or a
139+
// completely new object. If VerifiedPublicKeyCallback is non-nil,
140+
// PublicKeyCallback is not allowed to return a PartialSuccessError, which
141+
// can instead be returned by VerifiedPublicKeyCallback.
142+
//
143+
// VerifiedPublicKeyCallback does not affect which authentication methods
144+
// are included in the list of methods that can be attempted by the client.
145+
VerifiedPublicKeyCallback func(conn ConnMetadata, key PublicKey, permissions *Permissions,
146+
signatureAlgorithm string) (*Permissions, error)
147+
130148
// KeyboardInteractiveCallback, if non-nil, is called when
131149
// keyboard-interactive authentication is selected (RFC
132150
// 4256). The client object's Challenge function should be
@@ -653,6 +671,9 @@ userAuthLoop:
653671
candidate.pubKeyData = pubKeyData
654672
candidate.perms, candidate.result = authConfig.PublicKeyCallback(s, pubKey)
655673
_, isPartialSuccessError := candidate.result.(*PartialSuccessError)
674+
if isPartialSuccessError && config.VerifiedPublicKeyCallback != nil {
675+
return nil, errors.New("ssh: invalid library usage: PublicKeyCallback must not return partial success when VerifiedPublicKeyCallback is defined")
676+
}
656677

657678
if (candidate.result == nil || isPartialSuccessError) &&
658679
candidate.perms != nil &&
@@ -723,6 +744,12 @@ userAuthLoop:
723744

724745
authErr = candidate.result
725746
perms = candidate.perms
747+
if authErr == nil && config.VerifiedPublicKeyCallback != nil {
748+
// Only call VerifiedPublicKeyCallback after the key has been accepted
749+
// and successfully verified. If authErr is non-nil, the key is not
750+
// considered verified and the callback must not run.
751+
perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, algo)
752+
}
726753
}
727754
case "gssapi-with-mic":
728755
if authConfig.GSSAPIWithMICConfig == nil {

0 commit comments

Comments
 (0)