From b4e31feb63967ecb95ba41de3ef4a03076426fc6 Mon Sep 17 00:00:00 2001 From: Heiko Besemann Date: Thu, 7 Dec 2023 22:10:58 +0100 Subject: [PATCH 1/6] fix(asymkey): verify token + CRLF input Window-based shells will add a CRLF when piping the token into ssh-keygen command resulting in verification error. This resolves #21527. --- models/asymkey/ssh_key_verify.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go index e9f433248aaa9..72d75aed54d5a 100644 --- a/models/asymkey/ssh_key_verify.go +++ b/models/asymkey/ssh_key_verify.go @@ -30,7 +30,9 @@ func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signat return "", ErrKeyNotExist{} } - if err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea"); err != nil { + // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command + errcrlf := sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") + if err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea"); err != nil && errcrlf != nil { log.Error("Unable to validate token signature. Error: %v", err) return "", ErrSSHInvalidTokenSignature{ Fingerprint: key.Fingerprint, From d2b4900033c44f054c2885a0ad383595a5af7a5b Mon Sep 17 00:00:00 2001 From: nekrondev Date: Fri, 8 Dec 2023 09:10:17 +0100 Subject: [PATCH 2/6] asymkey: postpone verification for windows CRLF token This will reduce the signature verification call by attempting to check the Windows CRLFed token only if the former check failed. Co-authored-by: wxiaoguang --- models/asymkey/ssh_key_verify.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go index 72d75aed54d5a..7e36197bbe94a 100644 --- a/models/asymkey/ssh_key_verify.go +++ b/models/asymkey/ssh_key_verify.go @@ -30,9 +30,14 @@ func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signat return "", ErrKeyNotExist{} } - // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command - errcrlf := sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") - if err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea"); err != nil && errcrlf != nil { + err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea") + if err != nil { + // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command + if sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") == nil { + err = nil + } + } + if err != nil { log.Error("Unable to validate token signature. Error: %v", err) return "", ErrSSHInvalidTokenSignature{ Fingerprint: key.Fingerprint, From 3c388dd31c577991c3c4842d5cd2942ab089512e Mon Sep 17 00:00:00 2001 From: Heiko Besemann Date: Fri, 8 Dec 2023 09:28:05 +0100 Subject: [PATCH 3/6] asymkey: reduce clutter for CRLF token check --- models/asymkey/ssh_key_verify.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go index 72d75aed54d5a..42f5c068dfeb7 100644 --- a/models/asymkey/ssh_key_verify.go +++ b/models/asymkey/ssh_key_verify.go @@ -31,8 +31,8 @@ func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signat } // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command - errcrlf := sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") - if err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea"); err != nil && errcrlf != nil { + if err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea"); err != nil && + sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") != nil { log.Error("Unable to validate token signature. Error: %v", err) return "", ErrSSHInvalidTokenSignature{ Fingerprint: key.Fingerprint, From 6457cd299f91f6141db3a5253dca045cd526a8a1 Mon Sep 17 00:00:00 2001 From: Heiko Besemann Date: Tue, 12 Dec 2023 21:13:37 +0100 Subject: [PATCH 4/6] chore(asymkey): add reference to Powershell issue --- models/asymkey/ssh_key_verify.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go index 42f5c068dfeb7..ba5c45b079f48 100644 --- a/models/asymkey/ssh_key_verify.go +++ b/models/asymkey/ssh_key_verify.go @@ -31,6 +31,7 @@ func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signat } // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command + // see https://github.com/PowerShell/PowerShell/issues/5974 if err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea"); err != nil && sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") != nil { log.Error("Unable to validate token signature. Error: %v", err) From 8fe68a82afa4eaf48e70dd4dd4bae3d69c500e82 Mon Sep 17 00:00:00 2001 From: Heiko Besemann Date: Wed, 13 Dec 2023 14:01:07 +0100 Subject: [PATCH 5/6] fix(asymkey): changed coding to be more explicit --- models/asymkey/ssh_key_verify.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go index ba5c45b079f48..b1e56641e480a 100644 --- a/models/asymkey/ssh_key_verify.go +++ b/models/asymkey/ssh_key_verify.go @@ -30,13 +30,18 @@ func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signat return "", ErrKeyNotExist{} } - // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command - // see https://github.com/PowerShell/PowerShell/issues/5974 - if err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea"); err != nil && - sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") != nil { - log.Error("Unable to validate token signature. Error: %v", err) - return "", ErrSSHInvalidTokenSignature{ - Fingerprint: key.Fingerprint, + err = sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea") + if err != nil { + // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command + // see https://github.com/PowerShell/PowerShell/issues/5974 + if sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") == nil { + err = nil + } + if err != nil { + log.Error("Unable to validate token signature. Error: %v", err) + return "", ErrSSHInvalidTokenSignature{ + Fingerprint: key.Fingerprint, + } } } From 3e409373978f91f744d78a82854d90f7c3ec4486 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 13 Dec 2023 23:23:23 +0800 Subject: [PATCH 6/6] Update models/asymkey/ssh_key_verify.go --- models/asymkey/ssh_key_verify.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go index b1e56641e480a..208288c77b689 100644 --- a/models/asymkey/ssh_key_verify.go +++ b/models/asymkey/ssh_key_verify.go @@ -34,10 +34,7 @@ func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signat if err != nil { // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command // see https://github.com/PowerShell/PowerShell/issues/5974 - if sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") == nil { - err = nil - } - if err != nil { + if sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") != nil { log.Error("Unable to validate token signature. Error: %v", err) return "", ErrSSHInvalidTokenSignature{ Fingerprint: key.Fingerprint,