diff --git a/ssh/server.go b/ssh/server.go index dd1c327..0192a67 100644 --- a/ssh/server.go +++ b/ssh/server.go @@ -837,6 +837,13 @@ userAuthLoop: // considered verified and the callback must not run. perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, algo) } + if authErr == nil && perms != nil && perms.CriticalOptions != nil { + if saco := perms.CriticalOptions[sourceAddressCriticalOption]; saco != "" { + if err := checkSourceAddress(s.RemoteAddr(), saco); err != nil { + authErr = err + } + } + } } case "gssapi-with-mic": if authConfig.GSSAPIWithMICConfig == nil { diff --git a/ssh/server_test.go b/ssh/server_test.go index 2982ca3..2900b61 100644 --- a/ssh/server_test.go +++ b/ssh/server_test.go @@ -669,6 +669,44 @@ func TestVerifiedPubKeyCallbackError(t *testing.T) { } } +func TestVerifiedPubKeyCallbackSourceAddress(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverConf := &ServerConfig{ + PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + return nil, nil + }, + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + return &Permissions{ + CriticalOptions: map[string]string{ + sourceAddressCriticalOption: "192.168.99.99", + }, + }, nil + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + + clientConf := ClientConfig{ + User: "user", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + go NewServerConn(c1, serverConf) + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err == nil { + t.Fatal("client login succeed with VerifiedPublicKeyCallback returning mismatching source-address") + } +} + func TestVerifiedPublicCallbackPartialSuccessBadUsage(t *testing.T) { c1, c2, err := netPipe() if err != nil {