Compare commits

...
29 Commits
Author SHA1 Message Date
Heschi Kreinick 325b735346 ssh/test: skip TestSSHCLIAuth on Windows
It's failing with a file permissions error:

sign_and_send_pubkey: signing using rsa-sha2-512 SHA256:Anr3LjZK8YVpjrxu79myrW9Hrb/wpcMNpVvTq/RcBm8\r\nBad permissions. Try removing permissions for user: UNKNOWN\\\\UNKNOWN (S-1-15-2-2) on file C:/b/s/w/ir/x/t/TestSSHCLIAuth1586735692/001/rsa.

For golang/go#64403

Change-Id: Iece8eac4a1ac349f9f7a273ac7389315cb96568e
Cq-Include-Trybots: luci.golang.try:x_crypto-gotip-windows-amd64-longtest,x_crypto-go1.21-windows-amd64-longtest,x_crypto-go1.20-windows-amd64-longtest
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/545135
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Auto-Submit: Heschi Kreinick <heschi@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2023-11-27 16:29:38 +00:00
Gopher Robot 1eadac50a5 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: I7fdfe509173c79a63d006b27d674f869a5baa2af
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/545098
Reviewed-by: Heschi Kreinick <heschi@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2023-11-27 16:00:28 +00:00
Randy Reddig b2d7c26edb ssh: add (*Client).DialContext method
This change adds DialContext to ssh.Client, which opens a TCP-IP
connection tunneled over the SSH connection. This is useful for
proxying network connections, e.g. setting
(net/http.Transport).DialContext.

Fixes golang/go#20288.

Change-Id: I110494c00962424ea803065535ebe2209364ac27
GitHub-Last-Rev: 3176984a71a9a1422702e3a071340ecfff71ff62
GitHub-Pull-Request: golang/crypto#260
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/504735
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Run-TryBot: Han-Wen Nienhuys <hanwen@google.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Han-Wen Nienhuys <hanwen@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Commit-Queue: Nicola Murino <nicola.murino@gmail.com>
2023-11-27 15:35:52 +00:00
Nicola Murino 1c17e20020 ssh: fix certificate authentication with OpenSSH 7.2-7.7
OpenSSH 7.2-7.7 advertises support for rsa-sha2-256 and rsa-sha2-512
in the "server-sig-algs" extension but doesn't support these
algorithms for certificate authentication, so if the server rejects
the key try to use the obtained algorithm as if "server-sig-algs" had
not been implemented.

Fixes golang/go#58371

Change-Id: Id49960d3dedd32a21e2c6c2689b1696e05398286
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/510155
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
2023-11-23 17:23:14 +00:00
Sebastiaan van Stijn 270bf2552c curve25519/internal/field/_asm: go mod tidy to fix x/sys version
Relates to CL 540537, which updated the dependency in the main module.

Change-Id: I9a745f4e03b5cf14fa62c4de63363ddf663b19fd
GitHub-Last-Rev: 836c39364e9fe4302bc26efc9dabc47680cb66d2
GitHub-Pull-Request: golang/crypto#277
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/541276
Auto-Submit: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
2023-11-21 20:13:04 +00:00
Matt Dainty 1cf1811d71 ssh: use the correct token from the client
This fixes the case where AcceptSecContext is always called with the
first token sent by the client instead of the most recently sent one.
Previously, despite being being read from the client and unmarshalled,
it was never actually used.

Fixes golang/go#43875

Change-Id: I1967d9a107af03d6778a9437b48e785d61710ee5
GitHub-Last-Rev: 0d58e4d50014fac0a9ea1eef85489172137eb8aa
GitHub-Pull-Request: golang/crypto#176
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/286252
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2023-11-11 11:26:14 +00:00
Roland Shoemaker a2edfb5072 cryptobyte: fix ReadOptionalASN1Boolean
ReadOptionalASN1Boolean was completely broken, it would only work when
there were two BOOLEAN fields in a row, with the first being OPTIONAL
(which is itself invalid ASN.1 due to the ambiguity). This fixes it
to properly expect a BOOLEAN wrapped in a context-specific tag, as is
the case for all of the other ReadOptionalASN1* methods, and updates
its doc string.

This is a breaking change as it requires adding the tag field to
properly support context-specific tags. Given the method would
previously not work this seems like a reasonable breakage.

Fixes golang/go#43019

Change-Id: I42398256216c59988e249c90bc7aa668f64df945
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/274242
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Roland Shoemaker <roland@golang.org>
2023-11-09 20:53:37 +00:00
Bryan C. Mills ff15cd57d1 ssh: eliminate some goroutine leaks in tests and examples
This should fix the "Log in goroutine" panic seen in
https://build.golang.org/log/e42bf69fc002113dbccfe602a6c67fd52e8f31df,
as well as a few other related leaks. It also helps to verify that
none of the functions under test deadlock unexpectedly.

See https://go.dev/wiki/CodeReviewComments#goroutine-lifetimes.

Updates golang/go#58901.

Change-Id: Ica943444db381ae1accb80b101ea646e28ebf4f9
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/541095
Auto-Submit: Bryan Mills <bcmills@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Heschi Kreinick <heschi@google.com>
2023-11-09 17:49:15 +00:00
Nicola Murino eb61739cd9 ssh: allow to configure public key auth algorithms on the server side
Fixes golang/go#61244

Change-Id: I29b43e379cf0cdb07b0d6935666491b997157e73
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/510775
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Commit-Queue: Nicola Murino <nicola.murino@gmail.com>
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Han-Wen Nienhuys <hanwen@google.com>
2023-11-08 19:10:19 +00:00
Nicola Murino 42c83fffff ssh: try harder to detect incorrect passwords for legacy PEM encryption
Because of deficiencies in the format, DecryptPEMBlock does not always
detect an incorrect password. In these cases decrypted DER bytes is
random noise. If the parsing of the key returns an asn1.StructuralError
we return x509.IncorrectPasswordError.

Fixes golang/go#62265

Change-Id: Ib8b845f2bd01662c1f1421d35859a32ac5b78da7
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/538835
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
2023-11-08 18:01:48 +00:00
Gopher Robot e668aa9b45 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: Ie3a6928d78080ff7d75d6813b1760f1317baa081
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/540537
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
2023-11-08 16:51:37 +00:00
Mauri de Souza Meneguzzo df0bc9e1bb chacha20poly1305: guard PSHUFB usage with GOAMD64_v2
The PSHUFB instruction is part of SSE which is only v2+ but it is being
used without the GOAMD64_v2 guard.

The ROL macros were copied from CL 516859 that adds internal/chacha8rand.

Fixes golang/go#63871

Change-Id: I3c8ba75ff284cda4fc788885643246936e617b85
GitHub-Last-Rev: e235e8eae67f16b3a58817cfdff729693faf2665
GitHub-Pull-Request: golang/crypto#275
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/538786
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Mauri de Souza Meneguzzo <mauri870@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2023-11-07 22:36:17 +00:00
Eric Lagergren 74c2ba9521 crypto/hkdf: remove useless call to Reset
HKDF is commonly used to read keys that are the the same length (or
smaller) than the size of the hash digest, which means the loop inside
Read only runs once.

In that case, calling Reset is unnecesssary overhead.

name                  old time/op    new time/op    delta
16ByteMD5Single-8       1.39µs ± 1%    1.22µs ± 0%  -11.95%  (p=0.000 n=10+9)
20ByteSHA1Single-8       826ns ± 0%     746ns ± 0%   -9.70%  (p=0.000 n=9+10)
32ByteSHA256Single-8     838ns ± 1%     744ns ± 0%  -11.29%  (p=0.000 n=10+10)
64ByteSHA512Single-8    5.12µs ± 0%    4.57µs ± 0%  -10.78%  (p=0.000 n=8+10)
8ByteMD5Stream-8         137ns ± 0%     138ns ± 0%   +0.27%  (p=0.009 n=9+6)
16ByteMD5Stream-8        264ns ± 0%     265ns ± 0%   +0.29%  (p=0.000 n=10+10)
8ByteSHA1Stream-8       64.1ns ± 0%    64.4ns ± 0%   +0.60%  (p=0.000 n=9+9)
20ByteSHA1Stream-8       145ns ± 0%     146ns ± 1%   +0.69%  (p=0.000 n=9+10)
8ByteSHA256Stream-8     42.9ns ± 1%    43.1ns ± 0%   +0.48%  (p=0.005 n=10+10)
32ByteSHA256Stream-8     151ns ± 0%     152ns ± 0%   +0.35%  (p=0.006 n=10+8)
8ByteSHA512Stream-8      139ns ± 0%     139ns ± 0%   +0.08%  (p=0.035 n=9+10)
64ByteSHA512Stream-8    1.07µs ± 0%    1.07µs ± 0%   +0.33%  (p=0.000 n=9+10)

name                  old speed      new speed      delta
16ByteMD5Single-8     11.6MB/s ± 0%  13.1MB/s ± 0%  +13.50%  (p=0.000 n=9+9)
20ByteSHA1Single-8    24.2MB/s ± 0%  26.8MB/s ± 0%  +10.75%  (p=0.000 n=9+10)
32ByteSHA256Single-8  38.2MB/s ± 1%  43.0MB/s ± 0%  +12.72%  (p=0.000 n=10+10)
64ByteSHA512Single-8  12.5MB/s ± 0%  14.0MB/s ± 0%  +12.06%  (p=0.000 n=8+10)
8ByteMD5Stream-8      58.2MB/s ± 0%  58.1MB/s ± 0%   -0.27%  (p=0.004 n=9+9)
16ByteMD5Stream-8     60.6MB/s ± 0%  60.5MB/s ± 0%   -0.27%  (p=0.000 n=9+10)
8ByteSHA1Stream-8      125MB/s ± 0%   124MB/s ± 0%   -0.59%  (p=0.000 n=9+9)
20ByteSHA1Stream-8     138MB/s ± 0%   137MB/s ± 1%   -0.69%  (p=0.000 n=9+10)
8ByteSHA256Stream-8    186MB/s ± 1%   185MB/s ± 0%   -0.47%  (p=0.005 n=10+10)
32ByteSHA256Stream-8   211MB/s ± 0%   211MB/s ± 0%   -0.37%  (p=0.003 n=10+8)
8ByteSHA512Stream-8   57.4MB/s ± 1%  57.4MB/s ± 0%     ~     (p=0.137 n=10+10)
64ByteSHA512Stream-8  59.9MB/s ± 0%  59.7MB/s ± 0%   -0.33%  (p=0.000 n=9+10)

name                  old alloc/op   new alloc/op   delta
16ByteMD5Single-8       1.17kB ± 0%    0.98kB ± 0%  -16.42%  (p=0.000 n=10+10)
20ByteSHA1Single-8      1.25kB ± 0%    1.06kB ± 0%  -15.37%  (p=0.000 n=10+10)
32ByteSHA256Single-8    1.36kB ± 0%    1.14kB ± 0%  -16.46%  (p=0.000 n=10+10)
64ByteSHA512Single-8    2.26kB ± 0%    1.84kB ± 0%  -18.43%  (p=0.000 n=10+10)
8ByteMD5Stream-8         2.00B ± 0%     2.00B ± 0%     ~     (all equal)
16ByteMD5Stream-8        5.00B ± 0%     5.00B ± 0%     ~     (all equal)
8ByteSHA1Stream-8        2.00B ± 0%     2.00B ± 0%     ~     (all equal)
20ByteSHA1Stream-8       5.00B ± 0%     5.00B ± 0%     ~     (all equal)
8ByteSHA256Stream-8      1.00B ± 0%     1.00B ± 0%     ~     (all equal)
32ByteSHA256Stream-8     6.00B ± 0%     6.00B ± 0%     ~     (all equal)
8ByteSHA512Stream-8      1.00B ± 0%     1.00B ± 0%     ~     (all equal)
64ByteSHA512Stream-8     9.00B ± 0%     9.00B ± 0%     ~     (all equal)

name                  old allocs/op  new allocs/op  delta
16ByteMD5Single-8         16.0 ± 0%      14.0 ± 0%  -12.50%  (p=0.000 n=10+10)
20ByteSHA1Single-8        16.0 ± 0%      14.0 ± 0%  -12.50%  (p=0.000 n=10+10)
32ByteSHA256Single-8      16.0 ± 0%      14.0 ± 0%  -12.50%  (p=0.000 n=10+10)
64ByteSHA512Single-8      16.0 ± 0%      14.0 ± 0%  -12.50%  (p=0.000 n=10+10)
8ByteMD5Stream-8          0.00           0.00          ~     (all equal)
16ByteMD5Stream-8         1.00 ± 0%      1.00 ± 0%     ~     (all equal)
8ByteSHA1Stream-8         0.00           0.00          ~     (all equal)
20ByteSHA1Stream-8        1.00 ± 0%      1.00 ± 0%     ~     (all equal)
8ByteSHA256Stream-8       0.00           0.00          ~     (all equal)
32ByteSHA256Stream-8      1.00 ± 0%      1.00 ± 0%     ~     (all equal)
8ByteSHA512Stream-8       0.00           0.00          ~     (all equal)
64ByteSHA512Stream-8      1.00 ± 0%      1.00 ± 0%     ~     (all equal)

Change-Id: I08e5deb7045ce9aa63428e0ac7ae6140226414b4
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/423414
Reviewed-by: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
2023-10-30 15:29:48 +00:00
Nicola Murino cf8dcb0f7d ssh: add test case against ssh CLI
These tests try to ensure better compatibility of our server implementation
with the ssh CLI.

With these tests in place:

1) before merging CL 447757 we would have noticed that our server
   implementation was broken with OpenSSH 8.8+
2) after merging CL 447757 we would have noticed that our server
   implementation was broken with OpenSSH 7.2-7.7

The ssh CLI from $PATH is used by default, but can be overridden using
the SSH_CLI_PATH environment variable.

Change-Id: I93d64be41c7613132b0364afac8397f57c2dcbca
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/506837
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Benny Siegert <bsiegert@gmail.com>
Reviewed-by: Han-Wen Nienhuys <hanwen@google.com>
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
2023-10-24 07:12:59 +00:00
Roland Shoemaker 4f30245552 x509roots: catch the zero-roots case when generating the bundle
If the parser returns zero roots, don't attempt to completely remove
the bundle. This may happen if, i.e., the HTTP response is 200 but has
no content. An example of this may be http://go.dev/cl/535735.

Change-Id: I81fc2b49c8ec813cca17fd1c807296bfb053d992
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/536136
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
2023-10-23 20:02:03 +00:00
Dmitri Shuralyov 1d57292618 x509roots: check HTTP response status code and media type
The HTTP response status code is expected to be 200 OK, and
the certdata.txt file media type is expected to be plain text.
Check that it is before proceeding with parsing it.

Might help avoid repeats of CL 535735.

Change-Id: I1a7896b3e20d33a23fdc53c572ae9700c9eae1ef
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/536717
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Commit-Queue: Roland Shoemaker <roland@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
2023-10-21 03:02:42 +00:00
Dmitri Shuralyov 8779cbd1c9 all: update go directive to 1.18
Done with:

go get go@1.18
go mod tidy
go fix ./...

Using go1.21.3.

Also update avo to v0.5.0 in the curve25519/internal/field/_asm module.
It's newer and produces no diff in the generated code.

For golang/go#60268.

Change-Id: I9bd771ee8561595d7f68aaca76df6e3e33d35013
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/534141
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2023-10-11 22:02:22 +00:00
Nicola Murino 2aeefc3f8a ssh: add support for SSH_AGENT_CONSTRAIN_EXTENSION with id 255
it was changed in the following draft

https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-03

The id 3 is now used for SSH_AGENT_CONSTRAIN_MAXSIGN key constraint,
an OpenSSH extension to the protocol that we do not currently support.
Instead, we added a compatibility layer for
SSH_AGENT_CONSTRAIN_EXTENSION with ID 3.

Fixes golang/go#62311

Change-Id: I421aee92aee9e693e43f66e6a5515c055333cb9b
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/525355
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2023-10-11 10:27:03 +00:00
Gopher Robot e3cc52e598 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: Ib80d50bdd762d1ba04f9267aeddc17272ef8cd66
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/532976
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
2023-10-05 15:12:11 +00:00
Nicola Murino 833695f0a5 ssh: add server side support for ping@openssh.com protocol extension
Fixes golang/go#62390

Change-Id: Ie4dc577fb55b45a0c26a9e2dc5903af2bd382e00
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/524775
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
2023-10-04 16:04:50 +00:00
Sebastiaan van Stijn ec07f4e35b chacha20: drop Go 1.10 compatibility for arm64
Other packages already dropped compatibility with go < 1.12, so it should be safe to remove it for this package as well.

Change-Id: Ib1424763e3aa94d0187a667ebee058100136f53b
GitHub-Last-Rev: 51df9690a5f37ba50d5ae5e84cf31b78fb6c5cd8
GitHub-Pull-Request: golang/crypto#241
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/448241
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Joedian Reid <joedian@golang.org>
2023-09-28 17:58:46 +00:00
Sebastiaan van Stijn b665ba6f6f all: use crypto/ed25519 instead of golang.org/x/crypto/ed25519
This is a follow-up to CL 317169, which dropped go1.12 compatibility,
and made the golang.org/x/crypto/ed25519 package an alias / wrapper for
crypto/ed25519 in stdlib.

This patch updates uses within this repository to use stdlib instead of
depending on the wrapper. With this patch applied, the only remaining
use of the wrapper is in ed25519_test, which appears to be in place to
verify compatibility of the wrapper itself.

Change-Id: I0195396102a75ae20bdd82ca8ab59855c0eb5cea
GitHub-Last-Rev: 24dbec563cbd84bc47bdc7736b0245fc83dd3353
GitHub-Pull-Request: golang/crypto#238
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/448238
Reviewed-by: Bryan Mills <bcmills@google.com>
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Joedian Reid <joedian@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2023-09-27 14:30:17 +00:00
Nicola Murino a1aeb9b34e ssh: add test cases for compatibility with old (buggy) clients
Improved test cases for CL 506835.

Change-Id: If4a98ae4a7b39d2e59b203d10080b71283e1a80e
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/525735
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
2023-09-20 18:10:32 +00:00
Nicola Murino 28c53ff63c ssh: add MultiAlgorithmSigner
MultiAlgorithmSigner allows to restrict client-side, server-side and
certificate signing algorithms.

Fixes golang/go#52132
Fixes golang/go#36261

Change-Id: I295092f1bba647327aaaf294f110e9157d294159
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/508398
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2023-09-20 18:10:30 +00:00
Matthew Dempsky 3f0842a464 sha3: have ShakeHash extend hash.Hash
Package sha3 recommends the SHAKE functions for new uses, but this is
currently somewhat inconvenient because ShakeHash does not implement
hash.Hash. This is understandable, as SHAKE supports arbitrary-length
outputs whereas hash.Hash only supports fixed-length outputs. But
there's a natural fixed-length output to provide: the minimum output
that still provides SHAKE's full-strength generic security.

While here, tweak Sum so that its temporary buffer can be stack
allocated.

Also, tweak the panic message in Write so that the error text is more
readily understandable to Go programmers without needing to be
familiar with crypto jargon, and add a similar check in Sum.

Change-Id: Icf037d3990a71de5630f8825606614443f8c5245
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/526937
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Adam Langley <agl@google.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
2023-09-10 18:25:15 +00:00
Daniel Mangum e90f1e17ee cryptobyte: add uint48 methods
Adds uint48 methods for cryptobyte.Builder and cryptobyte.String.
Supporting 48-bit unsigned integers is useful for working with protocols
that use them for sequence numbers, such as DTLS.

Fixes golang/go#61275

Change-Id: Ibe49422d37644b9212b28b123dc5e01850f7b05b
GitHub-Last-Rev: 11b388c240109c8f4ac23880645c901ce6d2f093
GitHub-Pull-Request: golang/crypto#265
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/508675
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: qiulaidongfeng <2645477756@qq.com>
Run-TryBot: Roland Shoemaker <roland@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
2023-09-07 16:27:37 +00:00
Mariano Cano d359caa4a3 ssh: support for marshaling keys using the OpenSSH format
This adds methods to marshal private keys, encrypted and unencrypted
to the OpenSSH format.

Fixes golang/go#37132

Change-Id: I1a95301f789ce04858e6b147748c6e8b7700384b
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/218620
Run-TryBot: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
2023-09-05 20:25:46 +00:00
Nicola Murino c5370d2cc6 ssh: check the declared public key algo against decoded one
This check will ensure we don't accept e.g. ssh-rsa-cert-v01@openssh.com
algorithm with ssh-rsa public key type.
The algorithm and public key type must be consistent: both must be
certificate algorithms, or neither.

Change-Id: I1d75074fb4d6db3a8796408e98ddffe577a96ab1
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/506836
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
2023-09-05 16:18:45 +00:00
Gopher Robot 0d375be9b6 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: Ib391e4f2f09056cb025de97d5d8f2640859d9163
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/525335
Run-TryBot: Gopher Robot <gobot@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2023-09-05 14:51:56 +00:00
108 changed files with 1826 additions and 373 deletions
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build go1.12
// +build go1.12
package acme
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
package argon2
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
#include "textflag.h"
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !amd64 || purego || !gc
// +build !amd64 purego !gc
package argon2
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build go1.7 && amd64 && gc && !purego
// +build go1.7,amd64,gc,!purego
package blake2b
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build go1.7 && amd64 && gc && !purego
// +build go1.7,amd64,gc,!purego
#include "textflag.h"
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !go1.7 && amd64 && gc && !purego
// +build !go1.7,amd64,gc,!purego
package blake2b
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
#include "textflag.h"
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !amd64 || purego || !gc
// +build !amd64 purego !gc
package blake2b
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build go1.9
// +build go1.9
package blake2b
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build 386 && gc && !purego
// +build 386,gc,!purego
package blake2s
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build 386 && gc && !purego
// +build 386,gc,!purego
#include "textflag.h"
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
package blake2s
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
#include "textflag.h"
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build (!amd64 && !386) || !gc || purego
// +build !amd64,!386 !gc purego
package blake2s
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build go1.9
// +build go1.9
package blake2s
+1 -2
View File
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.11 && gc && !purego
// +build go1.11,gc,!purego
//go:build gc && !purego
package chacha20
+1 -2
View File
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.11 && gc && !purego
// +build go1.11,gc,!purego
//go:build gc && !purego
#include "textflag.h"
+1 -2
View File
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (!arm64 && !s390x && !ppc64le) || (arm64 && !go1.11) || !gc || purego
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 !gc purego
//go:build (!arm64 && !s390x && !ppc64le) || !gc || purego
package chacha20
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
package chacha20
-1
View File
@@ -20,7 +20,6 @@
// due to the calling conventions and initialization of constants.
//go:build gc && !purego
// +build gc,!purego
#include "textflag.h"
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
package chacha20
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
#include "go_asm.h"
#include "textflag.h"
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
package chacha20poly1305
+22 -3
View File
@@ -5,7 +5,6 @@
// This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
//go:build gc && !purego
// +build gc,!purego
#include "textflag.h"
// General register allocation
@@ -184,11 +183,31 @@ GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240
#define shiftD1Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x04 // PALIGNR $4, X10, X10
#define shiftD2Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X11, X11
#define shiftD3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x04 // PALIGNR $4, X15, X15
// Some macros
// ROL rotates the uint32s in register R left by N bits, using temporary T.
#define ROL(N, R, T) \
MOVO R, T; PSLLL $(N), T; PSRLL $(32-(N)), R; PXOR T, R
// ROL16 rotates the uint32s in register R left by 16, using temporary T if needed.
#ifdef GOAMD64_v2
#define ROL16(R, T) PSHUFB ·rol16<>(SB), R
#else
#define ROL16(R, T) ROL(16, R, T)
#endif
// ROL8 rotates the uint32s in register R left by 8, using temporary T if needed.
#ifdef GOAMD64_v2
#define ROL8(R, T) PSHUFB ·rol8<>(SB), R
#else
#define ROL8(R, T) ROL(8, R, T)
#endif
#define chachaQR(A, B, C, D, T) \
PADDD B, A; PXOR A, D; PSHUFB ·rol16<>(SB), D \
PADDD B, A; PXOR A, D; ROL16(D, T) \
PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $12, T; PSRLL $20, B; PXOR T, B \
PADDD B, A; PXOR A, D; PSHUFB ·rol8<>(SB), D \
PADDD B, A; PXOR A, D; ROL8(D, T) \
PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $7, T; PSRLL $25, B; PXOR T, B
#define chachaQR_AVX2(A, B, C, D, T) \
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !amd64 || !gc || purego
// +build !amd64 !gc purego
package chacha20poly1305
+7 -6
View File
@@ -733,13 +733,14 @@ func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag
return true
}
// ReadOptionalASN1Boolean sets *out to the value of the next ASN.1 BOOLEAN or,
// if the next bytes are not an ASN.1 BOOLEAN, to the value of defaultValue.
// It reports whether the operation was successful.
func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) bool {
// ReadOptionalASN1Boolean attempts to read an optional ASN.1 BOOLEAN
// explicitly tagged with tag into out and advances. If no element with a
// matching tag is present, it sets "out" to defaultValue instead. It reports
// whether the read was successful.
func (s *String) ReadOptionalASN1Boolean(out *bool, tag asn1.Tag, defaultValue bool) bool {
var present bool
var child String
if !s.ReadOptionalASN1(&child, &present, asn1.BOOLEAN) {
if !s.ReadOptionalASN1(&child, &present, tag) {
return false
}
@@ -748,7 +749,7 @@ func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) bool {
return true
}
return s.ReadASN1Boolean(out)
return child.ReadASN1Boolean(out)
}
func (s *String) readASN1(out *String, outTag *asn1.Tag, skipHeader bool) bool {
+22
View File
@@ -115,6 +115,28 @@ func TestReadASN1OptionalInteger(t *testing.T) {
}
}
const defaultBool = false
var optionalBoolTestData = []readASN1Test{
{"empty", []byte{}, 0xa0, true, false},
{"invalid", []byte{0xa1, 0x3, 0x1, 0x2, 0x7f}, 0xa1, false, defaultBool},
{"missing", []byte{0xa1, 0x3, 0x1, 0x1, 0x7f}, 0xa0, true, defaultBool},
{"present", []byte{0xa1, 0x3, 0x1, 0x1, 0xff}, 0xa1, true, true},
}
func TestReadASN1OptionalBoolean(t *testing.T) {
for _, test := range optionalBoolTestData {
t.Run(test.name, func(t *testing.T) {
in := String(test.in)
var out bool
ok := in.ReadOptionalASN1Boolean(&out, test.tag, defaultBool)
if ok != test.ok || ok && out != test.out.(bool) {
t.Errorf("in.ReadOptionalASN1Boolean() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
}
})
}
}
func TestReadASN1IntegerSigned(t *testing.T) {
testData64 := []struct {
in []byte
+5
View File
@@ -95,6 +95,11 @@ func (b *Builder) AddUint32(v uint32) {
b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// AddUint48 appends a big-endian, 48-bit value to the byte string.
func (b *Builder) AddUint48(v uint64) {
b.add(byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// AddUint64 appends a big-endian, 64-bit value to the byte string.
func (b *Builder) AddUint64(v uint64) {
b.add(byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
+21
View File
@@ -179,6 +179,27 @@ func TestUint32(t *testing.T) {
}
}
func TestUint48(t *testing.T) {
var b Builder
var u uint64 = 0xfefcff3cfdfc
b.AddUint48(u)
if err := builderBytesEq(&b, 254, 252, 255, 60, 253, 252); err != nil {
t.Error(err)
}
var s String = b.BytesOrPanic()
var v uint64
if !s.ReadUint48(&v) {
t.Error("ReadUint48() = false, want true")
}
if v != u {
t.Errorf("v = %x, want %x", v, u)
}
if len(s) != 0 {
t.Errorf("len(s) = %d, want 0", len(s))
}
}
func TestUint64(t *testing.T) {
var b Builder
b.AddUint64(0xf2fefefcff3cfdfc)
+11
View File
@@ -81,6 +81,17 @@ func (s *String) ReadUint32(out *uint32) bool {
return true
}
// ReadUint48 decodes a big-endian, 48-bit value into out and advances over it.
// It reports whether the read was successful.
func (s *String) ReadUint48(out *uint64) bool {
v := s.read(6)
if v == nil {
return false
}
*out = uint64(v[0])<<40 | uint64(v[1])<<32 | uint64(v[2])<<24 | uint64(v[3])<<16 | uint64(v[4])<<8 | uint64(v[5])
return true
}
// ReadUint64 decodes a big-endian, 64-bit value into out and advances over it.
// It reports whether the read was successful.
func (s *String) ReadUint64(out *uint64) bool {
+10 -4
View File
@@ -1,10 +1,16 @@
module asm
go 1.16
go 1.18
require (
github.com/mmcloughlin/avo v0.4.0
golang.org/x/crypto v0.0.0
github.com/mmcloughlin/avo v0.5.0
golang.org/x/crypto v0.1.0
)
replace golang.org/x/crypto v0.0.0 => ../../../..
require (
golang.org/x/mod v0.8.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/tools v0.6.0 // indirect
)
replace golang.org/x/crypto v0.1.0 => ../../../..
+39 -22
View File
@@ -1,34 +1,51 @@
github.com/mmcloughlin/avo v0.4.0 h1:jeHDRktVD+578ULxWpQHkilor6pkdLF7u7EiTzDbfcU=
github.com/mmcloughlin/avo v0.4.0/go.mod h1:RW9BfYA3TgO9uCdNrKU2h6J8cPD8ZLznvfgHAeszb1s=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
github.com/mmcloughlin/avo v0.5.0 h1:nAco9/aI9Lg2kiuROBY6BhCI/z0t5jEvJfjWbL8qXLU=
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021 h1:giLT+HuUP/gXYrG2Plg9WTjj4qhfgaW424ZIFog3rlk=
golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
-1
View File
@@ -1,7 +1,6 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
package field
-1
View File
@@ -1,7 +1,6 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
#include "textflag.h"
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !amd64 || !gc || purego
// +build !amd64 !gc purego
package field
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build arm64 && gc && !purego
// +build arm64,gc,!purego
package field
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build arm64 && gc && !purego
// +build arm64,gc,!purego
#include "textflag.h"
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !arm64 || !gc || purego
// +build !arm64 !gc purego
package field
+4 -4
View File
@@ -1,11 +1,11 @@
module golang.org/x/crypto
go 1.17
go 1.18
require (
golang.org/x/net v0.10.0 // tagx:ignore
golang.org/x/sys v0.11.0
golang.org/x/term v0.11.0
golang.org/x/sys v0.15.0
golang.org/x/term v0.15.0
)
require golang.org/x/text v0.12.0 // indirect
require golang.org/x/text v0.14.0 // indirect
+6 -39
View File
@@ -1,41 +1,8 @@
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+3 -1
View File
@@ -56,7 +56,9 @@ func (f *hkdf) Read(p []byte) (int, error) {
// Fill the rest of the buffer
for len(p) > 0 {
f.expander.Reset()
if f.counter > 1 {
f.expander.Reset()
}
f.expander.Write(f.prev)
f.expander.Write(f.info)
f.expander.Write([]byte{f.counter})
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !purego
// +build !purego
// Package alias implements memory aliasing tests.
package alias
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build purego
// +build purego
// Package alias implements memory aliasing tests.
package alias
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !go1.13
// +build !go1.13
package poly1305
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build go1.13
// +build go1.13
package poly1305
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego
// +build !amd64,!ppc64le,!s390x !gc purego
package poly1305
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
package poly1305
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
#include "textflag.h"
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
package poly1305
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
#include "textflag.h"
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
package poly1305
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
#include "textflag.h"
+1 -3
View File
@@ -3,14 +3,12 @@
// license that can be found in the LICENSE file.
//go:build go1.13
// +build go1.13
package wycheproof
import (
"crypto/ed25519"
"testing"
"golang.org/x/crypto/ed25519"
)
func TestEddsa(t *testing.T) {
+1 -1
View File
@@ -21,9 +21,9 @@
package sign
import (
"crypto/ed25519"
"io"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/internal/alias"
)
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build go1.7
// +build go1.7
package ocsp
+1 -1
View File
@@ -5,7 +5,7 @@
// This code can be compiled and used to test the otr package against libotr.
// See otr_test.go.
// +build ignore
//go:build ignore
#include <stdio.h>
#include <stdlib.h>
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && !purego && gc
// +build amd64,!purego,gc
package salsa
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && !purego && gc
// +build amd64,!purego,gc
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && !purego && gc
// +build amd64,!purego,gc
package salsa
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !amd64 || purego || !gc
// +build !amd64 purego !gc
package salsa
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !gc || purego || !s390x
// +build !gc purego !s390x
package sha3
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !amd64 || purego || !gc
// +build !amd64 purego !gc
package sha3
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && !purego && gc
// +build amd64,!purego,gc
package sha3
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build amd64 && !purego && gc
// +build amd64,!purego,gc
// This code was translated into a form compatible with 6a from the public
// domain sources at https://github.com/gvanas/KeccakCodePackage
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build go1.4
// +build go1.4
package sha3
+9 -5
View File
@@ -121,11 +121,11 @@ func (d *state) padAndPermute(dsbyte byte) {
copyOut(d, d.buf)
}
// Write absorbs more data into the hash's state. It produces an error
// if more data is written to the ShakeHash after writing
// Write absorbs more data into the hash's state. It panics if any
// output has already been read.
func (d *state) Write(p []byte) (written int, err error) {
if d.state != spongeAbsorbing {
panic("sha3: write to sponge after read")
panic("sha3: Write after Read")
}
if d.buf == nil {
d.buf = d.storage.asBytes()[:0]
@@ -182,12 +182,16 @@ func (d *state) Read(out []byte) (n int, err error) {
}
// Sum applies padding to the hash state and then squeezes out the desired
// number of output bytes.
// number of output bytes. It panics if any output has already been read.
func (d *state) Sum(in []byte) []byte {
if d.state != spongeAbsorbing {
panic("sha3: Sum after Read")
}
// Make a copy of the original hash so that caller can keep writing
// and summing.
dup := d.clone()
hash := make([]byte, dup.outputLen)
hash := make([]byte, dup.outputLen, 64) // explicit cap to allow stack allocation
dup.Read(hash)
return append(in, hash...)
}
+6 -5
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
package sha3
@@ -49,7 +48,7 @@ type asmState struct {
buf []byte // care must be taken to ensure cap(buf) is a multiple of rate
rate int // equivalent to block size
storage [3072]byte // underlying storage for buf
outputLen int // output length if fixed, 0 if not
outputLen int // output length for full security
function code // KIMD/KLMD function code
state spongeDirection // whether the sponge is absorbing or squeezing
}
@@ -72,8 +71,10 @@ func newAsmState(function code) *asmState {
s.outputLen = 64
case shake_128:
s.rate = 168
s.outputLen = 32
case shake_256:
s.rate = 136
s.outputLen = 64
default:
panic("sha3: unrecognized function code")
}
@@ -108,7 +109,7 @@ func (s *asmState) resetBuf() {
// It never returns an error.
func (s *asmState) Write(b []byte) (int, error) {
if s.state != spongeAbsorbing {
panic("sha3: write to sponge after read")
panic("sha3: Write after Read")
}
length := len(b)
for len(b) > 0 {
@@ -192,8 +193,8 @@ func (s *asmState) Read(out []byte) (n int, err error) {
// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
func (s *asmState) Sum(b []byte) []byte {
if s.outputLen == 0 {
panic("sha3: cannot call Sum on SHAKE functions")
if s.state != spongeAbsorbing {
panic("sha3: Sum after Read")
}
// Copy the state to preserve the original.
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gc && !purego
// +build gc,!purego
#include "textflag.h"
+14 -15
View File
@@ -17,26 +17,25 @@ package sha3
import (
"encoding/binary"
"hash"
"io"
)
// ShakeHash defines the interface to hash functions that
// support arbitrary-length output.
// ShakeHash defines the interface to hash functions that support
// arbitrary-length output. When used as a plain [hash.Hash], it
// produces minimum-length outputs that provide full-strength generic
// security.
type ShakeHash interface {
// Write absorbs more data into the hash's state. It panics if input is
// written to it after output has been read from it.
io.Writer
hash.Hash
// Read reads more output from the hash; reading affects the hash's
// state. (ShakeHash.Read is thus very different from Hash.Sum)
// It never returns an error.
// It never returns an error, but subsequent calls to Write or Sum
// will panic.
io.Reader
// Clone returns a copy of the ShakeHash in its current state.
Clone() ShakeHash
// Reset resets the ShakeHash to its initial state.
Reset()
}
// cSHAKE specific context
@@ -81,8 +80,8 @@ func leftEncode(value uint64) []byte {
return b[i-1:]
}
func newCShake(N, S []byte, rate int, dsbyte byte) ShakeHash {
c := cshakeState{state: &state{rate: rate, dsbyte: dsbyte}}
func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}}
// leftEncode returns max 9 bytes
c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
@@ -119,7 +118,7 @@ func NewShake128() ShakeHash {
if h := newShake128Asm(); h != nil {
return h
}
return &state{rate: rate128, dsbyte: dsbyteShake}
return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
}
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
@@ -129,7 +128,7 @@ func NewShake256() ShakeHash {
if h := newShake256Asm(); h != nil {
return h
}
return &state{rate: rate256, dsbyte: dsbyteShake}
return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
}
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
@@ -142,7 +141,7 @@ func NewCShake128(N, S []byte) ShakeHash {
if len(N) == 0 && len(S) == 0 {
return NewShake128()
}
return newCShake(N, S, rate128, dsbyteCShake)
return newCShake(N, S, rate128, 32, dsbyteCShake)
}
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
@@ -155,7 +154,7 @@ func NewCShake256(N, S []byte) ShakeHash {
if len(N) == 0 && len(S) == 0 {
return NewShake256()
}
return newCShake(N, S, rate256, dsbyteCShake)
return newCShake(N, S, rate256, 64, dsbyteCShake)
}
// ShakeSum128 writes an arbitrary-length digest of data into hash.
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !gc || purego || !s390x
// +build !gc purego !s390x
package sha3
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build (!amd64 && !386 && !ppc64le) || purego
// +build !amd64,!386,!ppc64le purego
package sha3
-2
View File
@@ -3,8 +3,6 @@
// license that can be found in the LICENSE file.
//go:build (amd64 || 386 || ppc64le) && !purego
// +build amd64 386 ppc64le
// +build !purego
package sha3
+10 -5
View File
@@ -16,6 +16,7 @@ import (
"bytes"
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"encoding/base64"
@@ -26,7 +27,6 @@ import (
"math/big"
"sync"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh"
)
@@ -141,9 +141,14 @@ const (
agentAddSmartcardKeyConstrained = 26
// 3.7 Key constraint identifiers
agentConstrainLifetime = 1
agentConstrainConfirm = 2
agentConstrainExtension = 3
agentConstrainLifetime = 1
agentConstrainConfirm = 2
// Constraint extension identifier up to version 2 of the protocol. A
// backward incompatible change will be required if we want to add support
// for SSH_AGENT_CONSTRAIN_MAXSIGN which uses the same ID.
agentConstrainExtensionV00 = 3
// Constraint extension identifier in version 3 and later of the protocol.
agentConstrainExtension = 255
)
// maxAgentResponseBytes is the maximum agent reply size that is accepted. This
@@ -205,7 +210,7 @@ type constrainLifetimeAgentMsg struct {
}
type constrainExtensionAgentMsg struct {
ExtensionName string `sshtype:"3"`
ExtensionName string `sshtype:"255|3"`
ExtensionDetails []byte
// Rest is a field used for parsing, not part of message
+2 -2
View File
@@ -7,6 +7,7 @@ package agent
import (
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"encoding/binary"
@@ -16,7 +17,6 @@ import (
"log"
"math/big"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh"
)
@@ -208,7 +208,7 @@ func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse
case agentConstrainConfirm:
confirmBeforeUse = true
constraints = constraints[1:]
case agentConstrainExtension:
case agentConstrainExtension, agentConstrainExtensionV00:
var msg constrainExtensionAgentMsg
if err = ssh.Unmarshal(constraints, &msg); err != nil {
return 0, false, nil, err
+5 -1
View File
@@ -243,7 +243,11 @@ func TestParseConstraints(t *testing.T) {
ExtensionDetails: []byte(fmt.Sprintf("details: %d", i)),
}
expect = append(expect, ext)
data = append(data, agentConstrainExtension)
if i%2 == 0 {
data = append(data, agentConstrainExtension)
} else {
data = append(data, agentConstrainExtensionV00)
}
data = append(data, ssh.Marshal(ext)...)
}
_, _, extensions, err := parseConstraints(data)
+30 -8
View File
@@ -16,8 +16,9 @@ import (
// Certificate algorithm names from [PROTOCOL.certkeys]. These values can appear
// in Certificate.Type, PublicKey.Type, and ClientConfig.HostKeyAlgorithms.
// Unlike key algorithm names, these are not passed to AlgorithmSigner and don't
// appear in the Signature.Format field.
// Unlike key algorithm names, these are not passed to AlgorithmSigner nor
// returned by MultiAlgorithmSigner and don't appear in the Signature.Format
// field.
const (
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
@@ -255,10 +256,17 @@ func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
return nil, errors.New("ssh: signer and cert have different public key")
}
if algorithmSigner, ok := signer.(AlgorithmSigner); ok {
switch s := signer.(type) {
case MultiAlgorithmSigner:
return &multiAlgorithmSigner{
AlgorithmSigner: &algorithmOpenSSHCertSigner{
&openSSHCertSigner{cert, signer}, s},
supportedAlgorithms: s.Algorithms(),
}, nil
case AlgorithmSigner:
return &algorithmOpenSSHCertSigner{
&openSSHCertSigner{cert, signer}, algorithmSigner}, nil
} else {
&openSSHCertSigner{cert, signer}, s}, nil
default:
return &openSSHCertSigner{cert, signer}, nil
}
}
@@ -432,7 +440,9 @@ func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
}
// SignCert signs the certificate with an authority, setting the Nonce,
// SignatureKey, and Signature fields.
// SignatureKey, and Signature fields. If the authority implements the
// MultiAlgorithmSigner interface the first algorithm in the list is used. This
// is useful if you want to sign with a specific algorithm.
func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
c.Nonce = make([]byte, 32)
if _, err := io.ReadFull(rand, c.Nonce); err != nil {
@@ -440,8 +450,20 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
}
c.SignatureKey = authority.PublicKey()
// Default to KeyAlgoRSASHA512 for ssh-rsa signers.
if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA {
if v, ok := authority.(MultiAlgorithmSigner); ok {
if len(v.Algorithms()) == 0 {
return errors.New("the provided authority has no signature algorithm")
}
// Use the first algorithm in the list.
sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), v.Algorithms()[0])
if err != nil {
return err
}
c.Signature = sig
return nil
} else if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA {
// Default to KeyAlgoRSASHA512 for ssh-rsa signers.
// TODO: consider using KeyAlgoRSASHA256 as default.
sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), KeyAlgoRSASHA512)
if err != nil {
return err
+94 -6
View File
@@ -187,10 +187,30 @@ func TestHostKeyCert(t *testing.T) {
}
for _, test := range []struct {
addr string
succeed bool
addr string
succeed bool
certSignerAlgorithms []string // Empty means no algorithm restrictions.
clientHostKeyAlgorithms []string
}{
{addr: "hostname:22", succeed: true},
{
addr: "hostname:22",
succeed: true,
certSignerAlgorithms: []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512},
clientHostKeyAlgorithms: []string{CertAlgoRSASHA512v01},
},
{
addr: "hostname:22",
succeed: false,
certSignerAlgorithms: []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512},
clientHostKeyAlgorithms: []string{CertAlgoRSAv01},
},
{
addr: "hostname:22",
succeed: false,
certSignerAlgorithms: []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512},
clientHostKeyAlgorithms: []string{KeyAlgoRSASHA512}, // Not a certificate algorithm.
},
{addr: "otherhost:22", succeed: false}, // The certificate is valid for 'otherhost' as hostname, but we only recognize the authority of the signer for the address 'hostname:22'
{addr: "lasthost:22", succeed: false},
} {
@@ -207,14 +227,24 @@ func TestHostKeyCert(t *testing.T) {
conf := ServerConfig{
NoClientAuth: true,
}
conf.AddHostKey(certSigner)
if len(test.certSignerAlgorithms) > 0 {
mas, err := NewSignerWithAlgorithms(certSigner.(AlgorithmSigner), test.certSignerAlgorithms)
if err != nil {
errc <- err
return
}
conf.AddHostKey(mas)
} else {
conf.AddHostKey(certSigner)
}
_, _, _, err := NewServerConn(c1, &conf)
errc <- err
}()
config := &ClientConfig{
User: "user",
HostKeyCallback: checker.CheckHostKey,
User: "user",
HostKeyCallback: checker.CheckHostKey,
HostKeyAlgorithms: test.clientHostKeyAlgorithms,
}
_, _, _, err = NewClientConn(c2, test.addr, config)
@@ -242,6 +272,20 @@ func (s *legacyRSASigner) Sign(rand io.Reader, data []byte) (*Signature, error)
}
func TestCertTypes(t *testing.T) {
algorithmSigner, ok := testSigners["rsa"].(AlgorithmSigner)
if !ok {
t.Fatal("rsa test signer does not implement the AlgorithmSigner interface")
}
multiAlgoSignerSHA256, err := NewSignerWithAlgorithms(algorithmSigner, []string{KeyAlgoRSASHA256})
if err != nil {
t.Fatalf("unable to create multi algorithm signer SHA256: %v", err)
}
// Algorithms are in order of preference, we expect rsa-sha2-512 to be used.
multiAlgoSignerSHA512, err := NewSignerWithAlgorithms(algorithmSigner, []string{KeyAlgoRSASHA512, KeyAlgoRSASHA256})
if err != nil {
t.Fatalf("unable to create multi algorithm signer SHA512: %v", err)
}
var testVars = []struct {
name string
signer Signer
@@ -251,8 +295,10 @@ func TestCertTypes(t *testing.T) {
{CertAlgoECDSA384v01, testSigners["ecdsap384"], ""},
{CertAlgoECDSA521v01, testSigners["ecdsap521"], ""},
{CertAlgoED25519v01, testSigners["ed25519"], ""},
{CertAlgoRSAv01, testSigners["rsa"], KeyAlgoRSASHA512},
{CertAlgoRSAv01, testSigners["rsa"], KeyAlgoRSASHA256},
{"legacyRSASigner", &legacyRSASigner{testSigners["rsa"]}, KeyAlgoRSA},
{"multiAlgoRSASignerSHA256", multiAlgoSignerSHA256, KeyAlgoRSASHA256},
{"multiAlgoRSASignerSHA512", multiAlgoSignerSHA512, KeyAlgoRSASHA512},
{CertAlgoDSAv01, testSigners["dsa"], ""},
}
@@ -318,3 +364,45 @@ func TestCertTypes(t *testing.T) {
})
}
}
func TestCertSignWithMultiAlgorithmSigner(t *testing.T) {
type testcase struct {
sigAlgo string
algoritms []string
}
cases := []testcase{
{
sigAlgo: KeyAlgoRSA,
algoritms: []string{KeyAlgoRSA, KeyAlgoRSASHA512},
},
{
sigAlgo: KeyAlgoRSASHA256,
algoritms: []string{KeyAlgoRSASHA256, KeyAlgoRSA, KeyAlgoRSASHA512},
},
{
sigAlgo: KeyAlgoRSASHA512,
algoritms: []string{KeyAlgoRSASHA512, KeyAlgoRSASHA256},
},
}
cert := &Certificate{
Key: testPublicKeys["rsa"],
ValidBefore: CertTimeInfinity,
CertType: UserCert,
}
for _, c := range cases {
t.Run(c.sigAlgo, func(t *testing.T) {
signer, err := NewSignerWithAlgorithms(testSigners["rsa"].(AlgorithmSigner), c.algoritms)
if err != nil {
t.Fatalf("NewSignerWithAlgorithms error: %v", err)
}
if err := cert.SignCert(rand.Reader, signer); err != nil {
t.Fatalf("SignCert error: %v", err)
}
if cert.Signature.Format != c.sigAlgo {
t.Fatalf("got signature format %q, want %q", cert.Signature.Format, c.sigAlgo)
}
})
}
}
+85 -31
View File
@@ -71,7 +71,9 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
for auth := AuthMethod(new(noneAuth)); auth != nil; {
ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions)
if err != nil {
return err
// We return the error later if there is no other method left to
// try.
ok = authFailure
}
if ok == authSuccess {
// success
@@ -101,6 +103,12 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
}
}
}
if auth == nil && err != nil {
// We have an error and there are no other authentication methods to
// try, so we return it.
return err
}
}
return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried)
}
@@ -217,21 +225,45 @@ func (cb publicKeyCallback) method() string {
return "publickey"
}
func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as AlgorithmSigner, algo string) {
func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiAlgorithmSigner, string, error) {
var as MultiAlgorithmSigner
keyFormat := signer.PublicKey().Type()
// Like in sendKexInit, if the public key implements AlgorithmSigner we
// assume it supports all algorithms, otherwise only the key format one.
as, ok := signer.(AlgorithmSigner)
if !ok {
return algorithmSignerWrapper{signer}, keyFormat
// If the signer implements MultiAlgorithmSigner we use the algorithms it
// support, if it implements AlgorithmSigner we assume it supports all
// algorithms, otherwise only the key format one.
switch s := signer.(type) {
case MultiAlgorithmSigner:
as = s
case AlgorithmSigner:
as = &multiAlgorithmSigner{
AlgorithmSigner: s,
supportedAlgorithms: algorithmsForKeyFormat(underlyingAlgo(keyFormat)),
}
default:
as = &multiAlgorithmSigner{
AlgorithmSigner: algorithmSignerWrapper{signer},
supportedAlgorithms: []string{underlyingAlgo(keyFormat)},
}
}
getFallbackAlgo := func() (string, error) {
// Fallback to use if there is no "server-sig-algs" extension or a
// common algorithm cannot be found. We use the public key format if the
// MultiAlgorithmSigner supports it, otherwise we return an error.
if !contains(as.Algorithms(), underlyingAlgo(keyFormat)) {
return "", fmt.Errorf("ssh: no common public key signature algorithm, server only supports %q for key type %q, signer only supports %v",
underlyingAlgo(keyFormat), keyFormat, as.Algorithms())
}
return keyFormat, nil
}
extPayload, ok := extensions["server-sig-algs"]
if !ok {
// If there is no "server-sig-algs" extension, fall back to the key
// format algorithm.
return as, keyFormat
// If there is no "server-sig-algs" extension use the fallback
// algorithm.
algo, err := getFallbackAlgo()
return as, algo, err
}
// The server-sig-algs extension only carries underlying signature
@@ -245,15 +277,22 @@ func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as Alg
}
}
keyAlgos := algorithmsForKeyFormat(keyFormat)
// Filter algorithms based on those supported by MultiAlgorithmSigner.
var keyAlgos []string
for _, algo := range algorithmsForKeyFormat(keyFormat) {
if contains(as.Algorithms(), underlyingAlgo(algo)) {
keyAlgos = append(keyAlgos, algo)
}
}
algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos)
if err != nil {
// If there is no overlap, try the key anyway with the key format
// algorithm, to support servers that fail to list all supported
// algorithms.
return as, keyFormat
// If there is no overlap, return the fallback algorithm to support
// servers that fail to list all supported algorithms.
algo, err := getFallbackAlgo()
return as, algo, err
}
return as, algo
return as, algo, nil
}
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
@@ -267,14 +306,39 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
return authFailure, nil, err
}
var methods []string
for _, signer := range signers {
pub := signer.PublicKey()
as, algo := pickSignatureAlgorithm(signer, extensions)
var errSigAlgo error
origSignersLen := len(signers)
for idx := 0; idx < len(signers); idx++ {
signer := signers[idx]
pub := signer.PublicKey()
as, algo, err := pickSignatureAlgorithm(signer, extensions)
if err != nil && errSigAlgo == nil {
// If we cannot negotiate a signature algorithm store the first
// error so we can return it to provide a more meaningful message if
// no other signers work.
errSigAlgo = err
continue
}
ok, err := validateKey(pub, algo, user, c)
if err != nil {
return authFailure, nil, err
}
// OpenSSH 7.2-7.7 advertises support for rsa-sha2-256 and rsa-sha2-512
// in the "server-sig-algs" extension but doesn't support these
// algorithms for certificate authentication, so if the server rejects
// the key try to use the obtained algorithm as if "server-sig-algs" had
// not been implemented if supported from the algorithm signer.
if !ok && idx < origSignersLen && isRSACert(algo) && algo != CertAlgoRSAv01 {
if contains(as.Algorithms(), KeyAlgoRSA) {
// We retry using the compat algorithm after all signers have
// been tried normally.
signers = append(signers, &multiAlgorithmSigner{
AlgorithmSigner: as,
supportedAlgorithms: []string{KeyAlgoRSA},
})
}
}
if !ok {
continue
}
@@ -317,22 +381,12 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
// contain the "publickey" method, do not attempt to authenticate with any
// other keys. According to RFC 4252 Section 7, the latter can occur when
// additional authentication methods are required.
if success == authSuccess || !containsMethod(methods, cb.method()) {
if success == authSuccess || !contains(methods, cb.method()) {
return success, methods, err
}
}
return authFailure, methods, nil
}
func containsMethod(methods []string, method string) bool {
for _, m := range methods {
if m == method {
return true
}
}
return false
return authFailure, methods, errSigAlgo
}
// validateKey validates the key provided is acceptable to the server.
+206
View File
@@ -1076,3 +1076,209 @@ func TestCompatibleAlgoAndSignatures(t *testing.T) {
}
}
}
func TestPickSignatureAlgorithm(t *testing.T) {
type testcase struct {
name string
extensions map[string][]byte
}
cases := []testcase{
{
name: "server with empty server-sig-algs",
extensions: map[string][]byte{
"server-sig-algs": []byte(``),
},
},
{
name: "server with no server-sig-algs",
extensions: nil,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
signer, ok := testSigners["rsa"].(MultiAlgorithmSigner)
if !ok {
t.Fatalf("rsa test signer does not implement the MultiAlgorithmSigner interface")
}
// The signer supports the public key algorithm which is then returned.
_, algo, err := pickSignatureAlgorithm(signer, c.extensions)
if err != nil {
t.Fatalf("got %v, want no error", err)
}
if algo != signer.PublicKey().Type() {
t.Fatalf("got algo %q, want %q", algo, signer.PublicKey().Type())
}
// Test a signer that uses a certificate algorithm as the public key
// type.
cert := &Certificate{
CertType: UserCert,
Key: signer.PublicKey(),
}
cert.SignCert(rand.Reader, signer)
certSigner, err := NewCertSigner(cert, signer)
if err != nil {
t.Fatalf("error generating cert signer: %v", err)
}
// The signer supports the public key algorithm and the
// public key format is a certificate type so the cerificate
// algorithm matching the key format must be returned
_, algo, err = pickSignatureAlgorithm(certSigner, c.extensions)
if err != nil {
t.Fatalf("got %v, want no error", err)
}
if algo != certSigner.PublicKey().Type() {
t.Fatalf("got algo %q, want %q", algo, certSigner.PublicKey().Type())
}
signer, err = NewSignerWithAlgorithms(signer.(AlgorithmSigner), []string{KeyAlgoRSASHA512, KeyAlgoRSASHA256})
if err != nil {
t.Fatalf("unable to create signer with algorithms: %v", err)
}
// The signer does not support the public key algorithm so an error
// is returned.
_, _, err = pickSignatureAlgorithm(signer, c.extensions)
if err == nil {
t.Fatal("got no error, no common public key signature algorithm error expected")
}
})
}
}
// configurablePublicKeyCallback is a public key callback that allows to
// configure the signature algorithm and format. This way we can emulate the
// behavior of buggy clients.
type configurablePublicKeyCallback struct {
signer AlgorithmSigner
signatureAlgo string
signatureFormat string
}
func (cb configurablePublicKeyCallback) method() string {
return "publickey"
}
func (cb configurablePublicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
pub := cb.signer.PublicKey()
ok, err := validateKey(pub, cb.signatureAlgo, user, c)
if err != nil {
return authFailure, nil, err
}
if !ok {
return authFailure, nil, fmt.Errorf("invalid public key")
}
pubKey := pub.Marshal()
data := buildDataSignedForAuth(session, userAuthRequestMsg{
User: user,
Service: serviceSSH,
Method: cb.method(),
}, cb.signatureAlgo, pubKey)
sign, err := cb.signer.SignWithAlgorithm(rand, data, underlyingAlgo(cb.signatureFormat))
if err != nil {
return authFailure, nil, err
}
s := Marshal(sign)
sig := make([]byte, stringLength(len(s)))
marshalString(sig, s)
msg := publickeyAuthMsg{
User: user,
Service: serviceSSH,
Method: cb.method(),
HasSig: true,
Algoname: cb.signatureAlgo,
PubKey: pubKey,
Sig: sig,
}
p := Marshal(&msg)
if err := c.writePacket(p); err != nil {
return authFailure, nil, err
}
var success authResult
success, methods, err := handleAuthResponse(c)
if err != nil {
return authFailure, nil, err
}
if success == authSuccess || !contains(methods, cb.method()) {
return success, methods, err
}
return authFailure, methods, nil
}
func TestPublicKeyAndAlgoCompatibility(t *testing.T) {
cert := &Certificate{
Key: testPublicKeys["rsa"],
ValidBefore: CertTimeInfinity,
CertType: UserCert,
}
cert.SignCert(rand.Reader, testSigners["ecdsa"])
certSigner, err := NewCertSigner(cert, testSigners["rsa"])
if err != nil {
t.Fatalf("NewCertSigner: %v", err)
}
clientConfig := &ClientConfig{
User: "user",
HostKeyCallback: InsecureIgnoreHostKey(),
Auth: []AuthMethod{
configurablePublicKeyCallback{
signer: certSigner.(AlgorithmSigner),
signatureAlgo: KeyAlgoRSASHA256,
signatureFormat: KeyAlgoRSASHA256,
},
},
}
if err := tryAuth(t, clientConfig); err == nil {
t.Error("cert login passed with incompatible public key type and algorithm")
}
}
func TestClientAuthGPGAgentCompat(t *testing.T) {
clientConfig := &ClientConfig{
User: "testuser",
HostKeyCallback: InsecureIgnoreHostKey(),
Auth: []AuthMethod{
// algorithm rsa-sha2-512 and signature format ssh-rsa.
configurablePublicKeyCallback{
signer: testSigners["rsa"].(AlgorithmSigner),
signatureAlgo: KeyAlgoRSASHA512,
signatureFormat: KeyAlgoRSA,
},
},
}
if err := tryAuth(t, clientConfig); err != nil {
t.Fatalf("unable to dial remote side: %s", err)
}
}
func TestCertAuthOpenSSHCompat(t *testing.T) {
cert := &Certificate{
Key: testPublicKeys["rsa"],
ValidBefore: CertTimeInfinity,
CertType: UserCert,
}
cert.SignCert(rand.Reader, testSigners["ecdsa"])
certSigner, err := NewCertSigner(cert, testSigners["rsa"])
if err != nil {
t.Fatalf("NewCertSigner: %v", err)
}
clientConfig := &ClientConfig{
User: "user",
HostKeyCallback: InsecureIgnoreHostKey(),
Auth: []AuthMethod{
// algorithm ssh-rsa-cert-v01@openssh.com and signature format
// rsa-sha2-256.
configurablePublicKeyCallback{
signer: certSigner.(AlgorithmSigner),
signatureAlgo: CertAlgoRSAv01,
signatureFormat: KeyAlgoRSASHA256,
},
},
}
if err := tryAuth(t, clientConfig); err != nil {
t.Fatalf("unable to dial remote side: %s", err)
}
}
+8 -3
View File
@@ -10,7 +10,6 @@ import (
"fmt"
"io"
"math"
"strings"
"sync"
_ "crypto/sha1"
@@ -128,6 +127,14 @@ func isRSA(algo string) bool {
return contains(algos, underlyingAlgo(algo))
}
func isRSACert(algo string) bool {
_, ok := certKeyAlgoNames[algo]
if !ok {
return false
}
return isRSA(algo)
}
// supportedPubKeyAuthAlgos specifies the supported client public key
// authentication algorithms. Note that this doesn't include certificate types
// since those use the underlying algorithm. This list is sent to the client if
@@ -140,8 +147,6 @@ var supportedPubKeyAuthAlgos = []string{
KeyAlgoDSA,
}
var supportedPubKeyAuthAlgosList = strings.Join(supportedPubKeyAuthAlgos, ",")
// unexpectedMessageError results when the SSH message that we received didn't
// match what we wanted.
func unexpectedMessageError(expected, got uint8) error {
+1
View File
@@ -13,6 +13,7 @@ others.
References:
[PROTOCOL]: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL?rev=HEAD
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
+83 -3
View File
@@ -7,6 +7,8 @@ package ssh_test
import (
"bufio"
"bytes"
"crypto/rand"
"crypto/rsa"
"fmt"
"log"
"net"
@@ -14,6 +16,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
@@ -75,7 +78,6 @@ func ExampleNewServerConn() {
if err != nil {
log.Fatal("Failed to parse private key: ", err)
}
config.AddHostKey(private)
// Once a ServerConfig has been configured, connections can be
@@ -97,8 +99,15 @@ func ExampleNewServerConn() {
}
log.Printf("logged in with key %s", conn.Permissions.Extensions["pubkey-fp"])
var wg sync.WaitGroup
defer wg.Wait()
// The incoming Request channel must be serviced.
go ssh.DiscardRequests(reqs)
wg.Add(1)
go func() {
ssh.DiscardRequests(reqs)
wg.Done()
}()
// Service the incoming Channel channel.
for newChannel := range chans {
@@ -118,16 +127,22 @@ func ExampleNewServerConn() {
// Sessions have out-of-band requests such as "shell",
// "pty-req" and "env". Here we handle only the
// "shell" request.
wg.Add(1)
go func(in <-chan *ssh.Request) {
for req := range in {
req.Reply(req.Type == "shell", nil)
}
wg.Done()
}(requests)
term := terminal.NewTerminal(channel, "> ")
wg.Add(1)
go func() {
defer channel.Close()
defer func() {
channel.Close()
wg.Done()
}()
for {
line, err := term.ReadLine()
if err != nil {
@@ -139,6 +154,36 @@ func ExampleNewServerConn() {
}
}
func ExampleServerConfig_AddHostKey() {
// Minimal ServerConfig supporting only password authentication.
config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
// Should use constant-time compare (or better, salt+hash) in
// a production setting.
if c.User() == "testuser" && string(pass) == "tiger" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
}
privateBytes, err := os.ReadFile("id_rsa")
if err != nil {
log.Fatal("Failed to load private key: ", err)
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
log.Fatal("Failed to parse private key: ", err)
}
// Restrict host key algorithms to disable ssh-rsa.
signer, err := ssh.NewSignerWithAlgorithms(private.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256, ssh.KeyAlgoRSASHA512})
if err != nil {
log.Fatal("Failed to create private key with restricted algorithms: ", err)
}
config.AddHostKey(signer)
}
func ExampleClientConfig_HostKeyCallback() {
// Every client must provide a host key check. Here is a
// simple-minded parse of OpenSSH's known_hosts file
@@ -318,3 +363,38 @@ func ExampleSession_RequestPty() {
log.Fatal("failed to start shell: ", err)
}
}
func ExampleCertificate_SignCert() {
// Sign a certificate with a specific algorithm.
privateKey, err := rsa.GenerateKey(rand.Reader, 3072)
if err != nil {
log.Fatal("unable to generate RSA key: ", err)
}
publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
log.Fatal("unable to get RSA public key: ", err)
}
caKey, err := rsa.GenerateKey(rand.Reader, 3072)
if err != nil {
log.Fatal("unable to generate CA key: ", err)
}
signer, err := ssh.NewSignerFromKey(caKey)
if err != nil {
log.Fatal("unable to generate signer from key: ", err)
}
mas, err := ssh.NewSignerWithAlgorithms(signer.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256})
if err != nil {
log.Fatal("unable to create signer with algoritms: ", err)
}
certificate := ssh.Certificate{
Key: publicKey,
CertType: ssh.UserCert,
}
if err := certificate.SignCert(rand.Reader, mas); err != nil {
log.Fatal("unable to sign certificate: ", err)
}
// Save the public key to a file and check that rsa-sha-256 is used for
// signing:
// ssh-keygen -L -f <path to the file>
fmt.Println(string(ssh.MarshalAuthorizedKey(&certificate)))
}
+37 -14
View File
@@ -11,6 +11,7 @@ import (
"io"
"log"
"net"
"strings"
"sync"
)
@@ -50,6 +51,10 @@ type handshakeTransport struct {
// connection.
hostKeys []Signer
// publicKeyAuthAlgorithms is non-empty if we are the server. In that case,
// it contains the supported client public key authentication algorithms.
publicKeyAuthAlgorithms []string
// hostKeyAlgorithms is non-empty if we are the client. In that case,
// we accept these key types from the server as host key.
hostKeyAlgorithms []string
@@ -141,6 +146,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt
func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport {
t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
t.hostKeys = config.hostKeys
t.publicKeyAuthAlgorithms = config.PublicKeyAuthAlgorithms
go t.readLoop()
go t.kexLoop()
return t
@@ -461,19 +467,24 @@ func (t *handshakeTransport) sendKexInit() error {
isServer := len(t.hostKeys) > 0
if isServer {
for _, k := range t.hostKeys {
// If k is an AlgorithmSigner, presume it supports all signature algorithms
// associated with the key format. (Ideally AlgorithmSigner would have a
// method to advertise supported algorithms, but it doesn't. This means that
// adding support for a new algorithm is a breaking change, as we will
// immediately negotiate it even if existing implementations don't support
// it. If that ever happens, we'll have to figure something out.)
// If k is not an AlgorithmSigner, we can only assume it only supports the
// algorithms that matches the key format. (This means that Sign can't pick
// a different default.)
// If k is a MultiAlgorithmSigner, we restrict the signature
// algorithms. If k is a AlgorithmSigner, presume it supports all
// signature algorithms associated with the key format. If k is not
// an AlgorithmSigner, we can only assume it only supports the
// algorithms that matches the key format. (This means that Sign
// can't pick a different default).
keyFormat := k.PublicKey().Type()
if _, ok := k.(AlgorithmSigner); ok {
switch s := k.(type) {
case MultiAlgorithmSigner:
for _, algo := range algorithmsForKeyFormat(keyFormat) {
if contains(s.Algorithms(), underlyingAlgo(algo)) {
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo)
}
}
case AlgorithmSigner:
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...)
} else {
default:
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat)
}
}
@@ -642,16 +653,21 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
// On the server side, after the first SSH_MSG_NEWKEYS, send a SSH_MSG_EXT_INFO
// message with the server-sig-algs extension if the client supports it. See
// RFC 8308, Sections 2.4 and 3.1.
// RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9.
if !isClient && firstKeyExchange && contains(clientInit.KexAlgos, "ext-info-c") {
supportedPubKeyAuthAlgosList := strings.Join(t.publicKeyAuthAlgorithms, ",")
extInfo := &extInfoMsg{
NumExtensions: 1,
Payload: make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)),
NumExtensions: 2,
Payload: make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)+4+16+4+1),
}
extInfo.Payload = appendInt(extInfo.Payload, len("server-sig-algs"))
extInfo.Payload = append(extInfo.Payload, "server-sig-algs"...)
extInfo.Payload = appendInt(extInfo.Payload, len(supportedPubKeyAuthAlgosList))
extInfo.Payload = append(extInfo.Payload, supportedPubKeyAuthAlgosList...)
extInfo.Payload = appendInt(extInfo.Payload, len("ping@openssh.com"))
extInfo.Payload = append(extInfo.Payload, "ping@openssh.com"...)
extInfo.Payload = appendInt(extInfo.Payload, 1)
extInfo.Payload = append(extInfo.Payload, "0"...)
if err := t.conn.writePacket(Marshal(extInfo)); err != nil {
return err
}
@@ -685,9 +701,16 @@ func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, a
func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner {
for _, k := range hostKeys {
if s, ok := k.(MultiAlgorithmSigner); ok {
if !contains(s.Algorithms(), underlyingAlgo(algo)) {
continue
}
}
if algo == k.PublicKey().Type() {
return algorithmSignerWrapper{k}
}
k, ok := k.(AlgorithmSigner)
if !ok {
continue
+90
View File
@@ -620,3 +620,93 @@ func TestNoSHA2Support(t *testing.T) {
t.Fatal(err)
}
}
func TestMultiAlgoSignerHandshake(t *testing.T) {
algorithmSigner, ok := testSigners["rsa"].(AlgorithmSigner)
if !ok {
t.Fatal("rsa test signer does not implement the AlgorithmSigner interface")
}
multiAlgoSigner, err := NewSignerWithAlgorithms(algorithmSigner, []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512})
if err != nil {
t.Fatalf("unable to create multi algorithm signer: %v", err)
}
c1, c2, err := netPipe()
if err != nil {
t.Fatalf("netPipe: %v", err)
}
defer c1.Close()
defer c2.Close()
serverConf := &ServerConfig{
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
return &Permissions{}, nil
},
}
serverConf.AddHostKey(multiAlgoSigner)
go NewServerConn(c1, serverConf)
clientConf := &ClientConfig{
User: "test",
Auth: []AuthMethod{Password("testpw")},
HostKeyCallback: FixedHostKey(testSigners["rsa"].PublicKey()),
HostKeyAlgorithms: []string{KeyAlgoRSASHA512},
}
if _, _, _, err := NewClientConn(c2, "", clientConf); err != nil {
t.Fatal(err)
}
}
func TestMultiAlgoSignerNoCommonHostKeyAlgo(t *testing.T) {
algorithmSigner, ok := testSigners["rsa"].(AlgorithmSigner)
if !ok {
t.Fatal("rsa test signer does not implement the AlgorithmSigner interface")
}
multiAlgoSigner, err := NewSignerWithAlgorithms(algorithmSigner, []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512})
if err != nil {
t.Fatalf("unable to create multi algorithm signer: %v", err)
}
c1, c2, err := netPipe()
if err != nil {
t.Fatalf("netPipe: %v", err)
}
defer c1.Close()
defer c2.Close()
// ssh-rsa is disabled server side
serverConf := &ServerConfig{
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
return &Permissions{}, nil
},
}
serverConf.AddHostKey(multiAlgoSigner)
go NewServerConn(c1, serverConf)
// the client only supports ssh-rsa
clientConf := &ClientConfig{
User: "test",
Auth: []AuthMethod{Password("testpw")},
HostKeyCallback: FixedHostKey(testSigners["rsa"].PublicKey()),
HostKeyAlgorithms: []string{KeyAlgoRSA},
}
_, _, _, err = NewClientConn(c2, "", clientConf)
if err == nil {
t.Fatal("succeeded connecting with no common hostkey algorithm")
}
}
func TestPickIncompatibleHostKeyAlgo(t *testing.T) {
algorithmSigner, ok := testSigners["rsa"].(AlgorithmSigner)
if !ok {
t.Fatal("rsa test signer does not implement the AlgorithmSigner interface")
}
multiAlgoSigner, err := NewSignerWithAlgorithms(algorithmSigner, []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512})
if err != nil {
t.Fatalf("unable to create multi algorithm signer: %v", err)
}
signer := pickHostKey([]Signer{multiAlgoSigner}, KeyAlgoRSA)
if signer != nil {
t.Fatal("incompatible signer returned")
}
}
+338 -57
View File
@@ -11,13 +11,16 @@ import (
"crypto/cipher"
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"encoding/pem"
"errors"
@@ -26,7 +29,6 @@ import (
"math/big"
"strings"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh/internal/bcrypt_pbkdf"
)
@@ -295,6 +297,18 @@ func MarshalAuthorizedKey(key PublicKey) []byte {
return b.Bytes()
}
// MarshalPrivateKey returns a PEM block with the private key serialized in the
// OpenSSH format.
func MarshalPrivateKey(key crypto.PrivateKey, comment string) (*pem.Block, error) {
return marshalOpenSSHPrivateKey(key, comment, unencryptedOpenSSHMarshaler)
}
// MarshalPrivateKeyWithPassphrase returns a PEM block holding the encrypted
// private key serialized in the OpenSSH format.
func MarshalPrivateKeyWithPassphrase(key crypto.PrivateKey, comment string, passphrase []byte) (*pem.Block, error) {
return marshalOpenSSHPrivateKey(key, comment, passphraseProtectedOpenSSHMarshaler(passphrase))
}
// PublicKey represents a public key using an unspecified algorithm.
//
// Some PublicKeys provided by this package also implement CryptoPublicKey.
@@ -321,7 +335,7 @@ type CryptoPublicKey interface {
// A Signer can create signatures that verify against a public key.
//
// Some Signers provided by this package also implement AlgorithmSigner.
// Some Signers provided by this package also implement MultiAlgorithmSigner.
type Signer interface {
// PublicKey returns the associated PublicKey.
PublicKey() PublicKey
@@ -336,9 +350,9 @@ type Signer interface {
// An AlgorithmSigner is a Signer that also supports specifying an algorithm to
// use for signing.
//
// An AlgorithmSigner can't advertise the algorithms it supports, so it should
// be prepared to be invoked with every algorithm supported by the public key
// format.
// An AlgorithmSigner can't advertise the algorithms it supports, unless it also
// implements MultiAlgorithmSigner, so it should be prepared to be invoked with
// every algorithm supported by the public key format.
type AlgorithmSigner interface {
Signer
@@ -349,6 +363,75 @@ type AlgorithmSigner interface {
SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
}
// MultiAlgorithmSigner is an AlgorithmSigner that also reports the algorithms
// supported by that signer.
type MultiAlgorithmSigner interface {
AlgorithmSigner
// Algorithms returns the available algorithms in preference order. The list
// must not be empty, and it must not include certificate types.
Algorithms() []string
}
// NewSignerWithAlgorithms returns a signer restricted to the specified
// algorithms. The algorithms must be set in preference order. The list must not
// be empty, and it must not include certificate types. An error is returned if
// the specified algorithms are incompatible with the public key type.
func NewSignerWithAlgorithms(signer AlgorithmSigner, algorithms []string) (MultiAlgorithmSigner, error) {
if len(algorithms) == 0 {
return nil, errors.New("ssh: please specify at least one valid signing algorithm")
}
var signerAlgos []string
supportedAlgos := algorithmsForKeyFormat(underlyingAlgo(signer.PublicKey().Type()))
if s, ok := signer.(*multiAlgorithmSigner); ok {
signerAlgos = s.Algorithms()
} else {
signerAlgos = supportedAlgos
}
for _, algo := range algorithms {
if !contains(supportedAlgos, algo) {
return nil, fmt.Errorf("ssh: algorithm %q is not supported for key type %q",
algo, signer.PublicKey().Type())
}
if !contains(signerAlgos, algo) {
return nil, fmt.Errorf("ssh: algorithm %q is restricted for the provided signer", algo)
}
}
return &multiAlgorithmSigner{
AlgorithmSigner: signer,
supportedAlgorithms: algorithms,
}, nil
}
type multiAlgorithmSigner struct {
AlgorithmSigner
supportedAlgorithms []string
}
func (s *multiAlgorithmSigner) Algorithms() []string {
return s.supportedAlgorithms
}
func (s *multiAlgorithmSigner) isAlgorithmSupported(algorithm string) bool {
if algorithm == "" {
algorithm = underlyingAlgo(s.PublicKey().Type())
}
for _, algo := range s.supportedAlgorithms {
if algorithm == algo {
return true
}
}
return false
}
func (s *multiAlgorithmSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if !s.isAlgorithmSupported(algorithm) {
return nil, fmt.Errorf("ssh: algorithm %q is not supported: %v", algorithm, s.supportedAlgorithms)
}
return s.AlgorithmSigner.SignWithAlgorithm(rand, data, algorithm)
}
type rsaPublicKey rsa.PublicKey
func (r *rsaPublicKey) Type() string {
@@ -512,6 +595,10 @@ func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
return k.SignWithAlgorithm(rand, data, k.PublicKey().Type())
}
func (k *dsaPrivateKey) Algorithms() []string {
return []string{k.PublicKey().Type()}
}
func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if algorithm != "" && algorithm != k.PublicKey().Type() {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
@@ -961,13 +1048,16 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
return s.SignWithAlgorithm(rand, data, s.pubKey.Type())
}
func (s *wrappedSigner) Algorithms() []string {
return algorithmsForKeyFormat(s.pubKey.Type())
}
func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if algorithm == "" {
algorithm = s.pubKey.Type()
}
supportedAlgos := algorithmsForKeyFormat(s.pubKey.Type())
if !contains(supportedAlgos, algorithm) {
if !contains(s.Algorithms(), algorithm) {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type())
}
@@ -1142,16 +1232,27 @@ func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{},
return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err)
}
var result interface{}
switch block.Type {
case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey(buf)
result, err = x509.ParsePKCS1PrivateKey(buf)
case "EC PRIVATE KEY":
return x509.ParseECPrivateKey(buf)
result, err = x509.ParseECPrivateKey(buf)
case "DSA PRIVATE KEY":
return ParseDSAPrivateKey(buf)
result, err = ParseDSAPrivateKey(buf)
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
err = fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
// Because of deficiencies in the format, DecryptPEMBlock does not always
// detect an incorrect password. In these cases decrypted DER bytes is
// random noise. If the parsing of the key returns an asn1.StructuralError
// we return x509.IncorrectPasswordError.
if _, ok := err.(asn1.StructuralError); ok {
return nil, x509.IncorrectPasswordError
}
return result, err
}
// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as
@@ -1241,28 +1342,106 @@ func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc {
}
}
func unencryptedOpenSSHMarshaler(privKeyBlock []byte) ([]byte, string, string, string, error) {
key := generateOpenSSHPadding(privKeyBlock, 8)
return key, "none", "none", "", nil
}
func passphraseProtectedOpenSSHMarshaler(passphrase []byte) openSSHEncryptFunc {
return func(privKeyBlock []byte) ([]byte, string, string, string, error) {
salt := make([]byte, 16)
if _, err := rand.Read(salt); err != nil {
return nil, "", "", "", err
}
opts := struct {
Salt []byte
Rounds uint32
}{salt, 16}
// Derive key to encrypt the private key block.
k, err := bcrypt_pbkdf.Key(passphrase, salt, int(opts.Rounds), 32+aes.BlockSize)
if err != nil {
return nil, "", "", "", err
}
// Add padding matching the block size of AES.
keyBlock := generateOpenSSHPadding(privKeyBlock, aes.BlockSize)
// Encrypt the private key using the derived secret.
dst := make([]byte, len(keyBlock))
key, iv := k[:32], k[32:]
block, err := aes.NewCipher(key)
if err != nil {
return nil, "", "", "", err
}
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(dst, keyBlock)
return dst, "aes256-ctr", "bcrypt", string(Marshal(opts)), nil
}
}
const privateKeyAuthMagic = "openssh-key-v1\x00"
type openSSHDecryptFunc func(CipherName, KdfName, KdfOpts string, PrivKeyBlock []byte) ([]byte, error)
type openSSHEncryptFunc func(PrivKeyBlock []byte) (ProtectedKeyBlock []byte, cipherName, kdfName, kdfOptions string, err error)
type openSSHEncryptedPrivateKey struct {
CipherName string
KdfName string
KdfOpts string
NumKeys uint32
PubKey []byte
PrivKeyBlock []byte
}
type openSSHPrivateKey struct {
Check1 uint32
Check2 uint32
Keytype string
Rest []byte `ssh:"rest"`
}
type openSSHRSAPrivateKey struct {
N *big.Int
E *big.Int
D *big.Int
Iqmp *big.Int
P *big.Int
Q *big.Int
Comment string
Pad []byte `ssh:"rest"`
}
type openSSHEd25519PrivateKey struct {
Pub []byte
Priv []byte
Comment string
Pad []byte `ssh:"rest"`
}
type openSSHECDSAPrivateKey struct {
Curve string
Pub []byte
D *big.Int
Comment string
Pad []byte `ssh:"rest"`
}
// parseOpenSSHPrivateKey parses an OpenSSH private key, using the decrypt
// function to unwrap the encrypted portion. unencryptedOpenSSHKey can be used
// as the decrypt function to parse an unencrypted private key. See
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key.
func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.PrivateKey, error) {
const magic = "openssh-key-v1\x00"
if len(key) < len(magic) || string(key[:len(magic)]) != magic {
if len(key) < len(privateKeyAuthMagic) || string(key[:len(privateKeyAuthMagic)]) != privateKeyAuthMagic {
return nil, errors.New("ssh: invalid openssh private key format")
}
remaining := key[len(magic):]
var w struct {
CipherName string
KdfName string
KdfOpts string
NumKeys uint32
PubKey []byte
PrivKeyBlock []byte
}
remaining := key[len(privateKeyAuthMagic):]
var w openSSHEncryptedPrivateKey
if err := Unmarshal(remaining, &w); err != nil {
return nil, err
}
@@ -1284,13 +1463,7 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv
return nil, err
}
pk1 := struct {
Check1 uint32
Check2 uint32
Keytype string
Rest []byte `ssh:"rest"`
}{}
var pk1 openSSHPrivateKey
if err := Unmarshal(privKeyBlock, &pk1); err != nil || pk1.Check1 != pk1.Check2 {
if w.CipherName != "none" {
return nil, x509.IncorrectPasswordError
@@ -1300,18 +1473,7 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv
switch pk1.Keytype {
case KeyAlgoRSA:
// https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773
key := struct {
N *big.Int
E *big.Int
D *big.Int
Iqmp *big.Int
P *big.Int
Q *big.Int
Comment string
Pad []byte `ssh:"rest"`
}{}
var key openSSHRSAPrivateKey
if err := Unmarshal(pk1.Rest, &key); err != nil {
return nil, err
}
@@ -1337,13 +1499,7 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv
return pk, nil
case KeyAlgoED25519:
key := struct {
Pub []byte
Priv []byte
Comment string
Pad []byte `ssh:"rest"`
}{}
var key openSSHEd25519PrivateKey
if err := Unmarshal(pk1.Rest, &key); err != nil {
return nil, err
}
@@ -1360,14 +1516,7 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv
copy(pk, key.Priv)
return &pk, nil
case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
key := struct {
Curve string
Pub []byte
D *big.Int
Comment string
Pad []byte `ssh:"rest"`
}{}
var key openSSHECDSAPrivateKey
if err := Unmarshal(pk1.Rest, &key); err != nil {
return nil, err
}
@@ -1415,6 +1564,131 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv
}
}
func marshalOpenSSHPrivateKey(key crypto.PrivateKey, comment string, encrypt openSSHEncryptFunc) (*pem.Block, error) {
var w openSSHEncryptedPrivateKey
var pk1 openSSHPrivateKey
// Random check bytes.
var check uint32
if err := binary.Read(rand.Reader, binary.BigEndian, &check); err != nil {
return nil, err
}
pk1.Check1 = check
pk1.Check2 = check
w.NumKeys = 1
// Use a []byte directly on ed25519 keys.
if k, ok := key.(*ed25519.PrivateKey); ok {
key = *k
}
switch k := key.(type) {
case *rsa.PrivateKey:
E := new(big.Int).SetInt64(int64(k.PublicKey.E))
// Marshal public key:
// E and N are in reversed order in the public and private key.
pubKey := struct {
KeyType string
E *big.Int
N *big.Int
}{
KeyAlgoRSA,
E, k.PublicKey.N,
}
w.PubKey = Marshal(pubKey)
// Marshal private key.
key := openSSHRSAPrivateKey{
N: k.PublicKey.N,
E: E,
D: k.D,
Iqmp: k.Precomputed.Qinv,
P: k.Primes[0],
Q: k.Primes[1],
Comment: comment,
}
pk1.Keytype = KeyAlgoRSA
pk1.Rest = Marshal(key)
case ed25519.PrivateKey:
pub := make([]byte, ed25519.PublicKeySize)
priv := make([]byte, ed25519.PrivateKeySize)
copy(pub, k[32:])
copy(priv, k)
// Marshal public key.
pubKey := struct {
KeyType string
Pub []byte
}{
KeyAlgoED25519, pub,
}
w.PubKey = Marshal(pubKey)
// Marshal private key.
key := openSSHEd25519PrivateKey{
Pub: pub,
Priv: priv,
Comment: comment,
}
pk1.Keytype = KeyAlgoED25519
pk1.Rest = Marshal(key)
case *ecdsa.PrivateKey:
var curve, keyType string
switch name := k.Curve.Params().Name; name {
case "P-256":
curve = "nistp256"
keyType = KeyAlgoECDSA256
case "P-384":
curve = "nistp384"
keyType = KeyAlgoECDSA384
case "P-521":
curve = "nistp521"
keyType = KeyAlgoECDSA521
default:
return nil, errors.New("ssh: unhandled elliptic curve " + name)
}
pub := elliptic.Marshal(k.Curve, k.PublicKey.X, k.PublicKey.Y)
// Marshal public key.
pubKey := struct {
KeyType string
Curve string
Pub []byte
}{
keyType, curve, pub,
}
w.PubKey = Marshal(pubKey)
// Marshal private key.
key := openSSHECDSAPrivateKey{
Curve: curve,
Pub: pub,
D: k.D,
Comment: comment,
}
pk1.Keytype = keyType
pk1.Rest = Marshal(key)
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
var err error
// Add padding and encrypt the key if necessary.
w.PrivKeyBlock, w.CipherName, w.KdfName, w.KdfOpts, err = encrypt(Marshal(pk1))
if err != nil {
return nil, err
}
b := Marshal(w)
block := &pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: append([]byte(privateKeyAuthMagic), b...),
}
return block, nil
}
func checkOpenSSHKeyPadding(pad []byte) error {
for i, b := range pad {
if int(b) != i+1 {
@@ -1424,6 +1698,13 @@ func checkOpenSSHKeyPadding(pad []byte) error {
return nil
}
func generateOpenSSHPadding(block []byte, blockSize int) []byte {
for i, l := 0, len(block); (l+i)%blockSize != 0; i++ {
block = append(block, byte(i+1))
}
return block
}
// FingerprintLegacyMD5 returns the user presentation of the key's
// fingerprint as described by RFC 4716 section 4.
func FingerprintLegacyMD5(pubKey PublicKey) string {
+114 -4
View File
@@ -8,6 +8,7 @@ import (
"bytes"
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
@@ -15,13 +16,13 @@ import (
"encoding/base64"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"io"
"reflect"
"strings"
"testing"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh/testdata"
)
@@ -111,9 +112,9 @@ func TestKeySignVerify(t *testing.T) {
}
func TestKeySignWithAlgorithmVerify(t *testing.T) {
for _, priv := range testSigners {
if algorithmSigner, ok := priv.(AlgorithmSigner); !ok {
t.Errorf("Signers constructed by ssh package should always implement the AlgorithmSigner interface: %T", priv)
for k, priv := range testSigners {
if algorithmSigner, ok := priv.(MultiAlgorithmSigner); !ok {
t.Errorf("Signers %q constructed by ssh package should always implement the MultiAlgorithmSigner interface: %T", k, priv)
} else {
pub := priv.PublicKey()
data := []byte("sign me")
@@ -221,6 +222,16 @@ func TestParseEncryptedPrivateKeysWithPassphrase(t *testing.T) {
}
}
func TestParseEncryptedPrivateKeysWithIncorrectPassphrase(t *testing.T) {
pem := testdata.PEMEncryptedKeys[0].PEMBytes
for i := 0; i < 4096; i++ {
_, err := ParseRawPrivateKeyWithPassphrase(pem, []byte(fmt.Sprintf("%d", i)))
if !errors.Is(err, x509.IncorrectPasswordError) {
t.Fatalf("expected error: %v, got: %v", x509.IncorrectPasswordError, err)
}
}
}
func TestParseDSA(t *testing.T) {
// We actually exercise the ParsePrivateKey codepath here, as opposed to
// using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go
@@ -281,6 +292,74 @@ func TestMarshalParsePublicKey(t *testing.T) {
}
}
func TestMarshalPrivateKey(t *testing.T) {
tests := []struct {
name string
}{
{"rsa-openssh-format"},
{"ed25519"},
{"p256-openssh-format"},
{"p384-openssh-format"},
{"p521-openssh-format"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expected, ok := testPrivateKeys[tt.name]
if !ok {
t.Fatalf("cannot find key %s", tt.name)
}
block, err := MarshalPrivateKey(expected, "test@golang.org")
if err != nil {
t.Fatalf("cannot marshal %s: %v", tt.name, err)
}
key, err := ParseRawPrivateKey(pem.EncodeToMemory(block))
if err != nil {
t.Fatalf("cannot parse %s: %v", tt.name, err)
}
if !reflect.DeepEqual(expected, key) {
t.Errorf("unexpected marshaled key %s", tt.name)
}
})
}
}
func TestMarshalPrivateKeyWithPassphrase(t *testing.T) {
tests := []struct {
name string
}{
{"rsa-openssh-format"},
{"ed25519"},
{"p256-openssh-format"},
{"p384-openssh-format"},
{"p521-openssh-format"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expected, ok := testPrivateKeys[tt.name]
if !ok {
t.Fatalf("cannot find key %s", tt.name)
}
block, err := MarshalPrivateKeyWithPassphrase(expected, "test@golang.org", []byte("test-passphrase"))
if err != nil {
t.Fatalf("cannot marshal %s: %v", tt.name, err)
}
key, err := ParseRawPrivateKeyWithPassphrase(pem.EncodeToMemory(block), []byte("test-passphrase"))
if err != nil {
t.Fatalf("cannot parse %s: %v", tt.name, err)
}
if !reflect.DeepEqual(expected, key) {
t.Errorf("unexpected marshaled key %s", tt.name)
}
})
}
}
type testAuthResult struct {
pubKey PublicKey
options []string
@@ -616,3 +695,34 @@ func TestSKKeys(t *testing.T) {
}
}
}
func TestNewSignerWithAlgos(t *testing.T) {
algorithSigner, ok := testSigners["rsa"].(AlgorithmSigner)
if !ok {
t.Fatal("rsa test signer does not implement the AlgorithmSigner interface")
}
_, err := NewSignerWithAlgorithms(algorithSigner, nil)
if err == nil {
t.Error("signer with algos created with no algorithms")
}
_, err = NewSignerWithAlgorithms(algorithSigner, []string{KeyAlgoED25519})
if err == nil {
t.Error("signer with algos created with invalid algorithms")
}
_, err = NewSignerWithAlgorithms(algorithSigner, []string{CertAlgoRSASHA256v01})
if err == nil {
t.Error("signer with algos created with certificate algorithms")
}
mas, err := NewSignerWithAlgorithms(algorithSigner, []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512})
if err != nil {
t.Errorf("unable to create signer with valid algorithms: %v", err)
}
_, err = NewSignerWithAlgorithms(mas, []string{KeyAlgoRSA})
if err == nil {
t.Error("signer with algos created with restricted algorithms")
}
}
+14
View File
@@ -349,6 +349,20 @@ type userAuthGSSAPIError struct {
LanguageTag string
}
// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
const msgPing = 192
type pingMsg struct {
Data string `sshtype:"192"`
}
// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
const msgPong = 193
type pongMsg struct {
Data string `sshtype:"193"`
}
// typeTags returns the possible type bytes for the given reflect.Type, which
// should be a struct. The possible values are separated by a '|' character.
func typeTags(structType reflect.Type) (tags []byte) {
+6
View File
@@ -231,6 +231,12 @@ func (m *mux) onePacket() error {
return m.handleChannelOpen(packet)
case msgGlobalRequest, msgRequestSuccess, msgRequestFailure:
return m.handleGlobalPacket(packet)
case msgPing:
var msg pingMsg
if err := Unmarshal(packet, &msg); err != nil {
return fmt.Errorf("failed to unmarshal ping@openssh.com message: %w", err)
}
return m.sendMessage(pongMsg(msg))
}
// assume a channel packet.
+49 -42
View File
@@ -10,7 +10,6 @@ import (
"io"
"sync"
"testing"
"time"
)
func muxPair() (*mux, *mux) {
@@ -112,7 +111,11 @@ func TestMuxReadWrite(t *testing.T) {
magic := "hello world"
magicExt := "hello stderr"
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
wg.Add(1)
go func() {
defer wg.Done()
_, err := s.Write([]byte(magic))
if err != nil {
t.Errorf("Write: %v", err)
@@ -152,13 +155,15 @@ func TestMuxChannelOverflow(t *testing.T) {
defer writer.Close()
defer mux.Close()
wDone := make(chan int, 1)
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
wg.Add(1)
go func() {
defer wg.Done()
if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil {
t.Errorf("could not fill window: %v", err)
}
writer.Write(make([]byte, 1))
wDone <- 1
}()
writer.remoteWin.waitWriterBlocked()
@@ -175,7 +180,6 @@ func TestMuxChannelOverflow(t *testing.T) {
if _, err := reader.SendRequest("hello", true, nil); err == nil {
t.Errorf("SendRequest succeeded.")
}
<-wDone
}
func TestMuxChannelCloseWriteUnblock(t *testing.T) {
@@ -184,20 +188,21 @@ func TestMuxChannelCloseWriteUnblock(t *testing.T) {
defer writer.Close()
defer mux.Close()
wDone := make(chan int, 1)
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
wg.Add(1)
go func() {
defer wg.Done()
if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil {
t.Errorf("could not fill window: %v", err)
}
if _, err := writer.Write(make([]byte, 1)); err != io.EOF {
t.Errorf("got %v, want EOF for unblock write", err)
}
wDone <- 1
}()
writer.remoteWin.waitWriterBlocked()
reader.Close()
<-wDone
}
func TestMuxConnectionCloseWriteUnblock(t *testing.T) {
@@ -206,20 +211,21 @@ func TestMuxConnectionCloseWriteUnblock(t *testing.T) {
defer writer.Close()
defer mux.Close()
wDone := make(chan int, 1)
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
wg.Add(1)
go func() {
defer wg.Done()
if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil {
t.Errorf("could not fill window: %v", err)
}
if _, err := writer.Write(make([]byte, 1)); err != io.EOF {
t.Errorf("got %v, want EOF for unblock write", err)
}
wDone <- 1
}()
writer.remoteWin.waitWriterBlocked()
mux.Close()
<-wDone
}
func TestMuxReject(t *testing.T) {
@@ -227,7 +233,12 @@ func TestMuxReject(t *testing.T) {
defer server.Close()
defer client.Close()
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
wg.Add(1)
go func() {
defer wg.Done()
ch, ok := <-server.incomingChannels
if !ok {
t.Error("cannot accept channel")
@@ -267,6 +278,7 @@ func TestMuxChannelRequest(t *testing.T) {
var received int
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
wg.Add(1)
go func() {
for r := range server.incomingRequests {
@@ -295,7 +307,6 @@ func TestMuxChannelRequest(t *testing.T) {
}
if ok {
t.Errorf("SendRequest(no): %v", ok)
}
client.Close()
@@ -389,13 +400,8 @@ func TestMuxUnknownChannelRequests(t *testing.T) {
// Wait for the server to send the keepalive message and receive back a
// response.
select {
case err := <-kDone:
if err != nil {
t.Fatal(err)
}
case <-time.After(10 * time.Second):
t.Fatalf("server never received ack")
if err := <-kDone; err != nil {
t.Fatal(err)
}
// Confirm client hasn't closed.
@@ -403,13 +409,9 @@ func TestMuxUnknownChannelRequests(t *testing.T) {
t.Fatalf("failed to send keepalive: %v", err)
}
select {
case err := <-kDone:
if err != nil {
t.Fatal(err)
}
case <-time.After(10 * time.Second):
t.Fatalf("server never shut down")
// Wait for the server to shut down.
if err := <-kDone; err != nil {
t.Fatal(err)
}
}
@@ -525,11 +527,7 @@ func TestMuxClosedChannel(t *testing.T) {
defer ch.Close()
// Wait for the server to close the channel and send the keepalive.
select {
case <-kDone:
case <-time.After(10 * time.Second):
t.Fatalf("server never received ack")
}
<-kDone
// Make sure the channel closed.
if _, ok := <-ch.incomingRequests; ok {
@@ -541,22 +539,29 @@ func TestMuxClosedChannel(t *testing.T) {
t.Fatalf("failed to send keepalive: %v", err)
}
select {
case <-kDone:
case <-time.After(10 * time.Second):
t.Fatalf("server never shut down")
}
// Wait for the server to shut down.
<-kDone
}
func TestMuxGlobalRequest(t *testing.T) {
var sawPeek bool
var wg sync.WaitGroup
defer func() {
wg.Wait()
if !sawPeek {
t.Errorf("never saw 'peek' request")
}
}()
clientMux, serverMux := muxPair()
defer serverMux.Close()
defer clientMux.Close()
var seen bool
wg.Add(1)
go func() {
defer wg.Done()
for r := range serverMux.incomingRequests {
seen = seen || r.Type == "peek"
sawPeek = sawPeek || r.Type == "peek"
if r.WantReply {
err := r.Reply(r.Type == "yes",
append([]byte(r.Type), r.Payload...))
@@ -586,10 +591,6 @@ func TestMuxGlobalRequest(t *testing.T) {
t.Errorf("SendRequest(\"no\", true, \"a\"): %v %v %v",
ok, data, err)
}
if !seen {
t.Errorf("never saw 'peek' request")
}
}
func TestMuxGlobalRequestUnblock(t *testing.T) {
@@ -739,7 +740,13 @@ func TestMuxMaxPacketSize(t *testing.T) {
t.Errorf("could not send packet")
}
go a.SendRequest("hello", false, nil)
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
wg.Add(1)
go func() {
a.SendRequest("hello", false, nil)
wg.Done()
}()
_, ok := <-b.incomingRequests
if ok {
+31 -5
View File
@@ -64,6 +64,13 @@ type ServerConfig struct {
// Config contains configuration shared between client and server.
Config
// PublicKeyAuthAlgorithms specifies the supported client public key
// authentication algorithms. Note that this should not include certificate
// types since those use the underlying algorithm. This list is sent to the
// client if it supports the server-sig-algs extension. Order is irrelevant.
// If unspecified then a default set of algorithms is used.
PublicKeyAuthAlgorithms []string
hostKeys []Signer
// NoClientAuth is true if clients are allowed to connect without
@@ -201,6 +208,15 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
if fullConf.MaxAuthTries == 0 {
fullConf.MaxAuthTries = 6
}
if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
fullConf.PublicKeyAuthAlgorithms = supportedPubKeyAuthAlgos
} else {
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
if !contains(supportedPubKeyAuthAlgos, algo) {
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
}
}
}
// Check if the config contains any unsupported key exchanges
for _, kex := range fullConf.KeyExchanges {
if _, ok := serverForbiddenKexAlgos[kex]; ok {
@@ -321,7 +337,7 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
}
func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection,
func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
gssAPIServer := gssapiConfig.Server
defer gssAPIServer.DeleteSecContext()
@@ -331,7 +347,7 @@ func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *c
outToken []byte
needContinue bool
)
outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken)
outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(token)
if err != nil {
return err, nil, nil
}
@@ -353,6 +369,7 @@ func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *c
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
return nil, nil, err
}
token = userAuthGSSAPITokenReq.Token
}
packet, err := s.transport.readPacket()
if err != nil {
@@ -524,7 +541,7 @@ userAuthLoop:
return nil, parseError(msgUserAuthRequest)
}
algo := string(algoBytes)
if !contains(supportedPubKeyAuthAlgos, underlyingAlgo(algo)) {
if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
break
}
@@ -576,13 +593,22 @@ userAuthLoop:
if !ok || len(payload) > 0 {
return nil, parseError(msgUserAuthRequest)
}
// Ensure the declared public key algo is compatible with the
// decoded one. This check will ensure we don't accept e.g.
// ssh-rsa-cert-v01@openssh.com algorithm with ssh-rsa public
// key type. The algorithm and public key type must be
// consistent: both must be certificate algorithms, or neither.
if !contains(algorithmsForKeyFormat(pubKey.Type()), algo) {
authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q",
pubKey.Type(), algo)
break
}
// Ensure the public key algo and signature algo
// are supported. Compare the private key
// algorithm name that corresponds to algo with
// sig.Format. This is usually the same, but
// for certs, the names differ.
if !contains(supportedPubKeyAuthAlgos, sig.Format) {
if !contains(config.PublicKeyAuthAlgorithms, sig.Format) {
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
break
}
+85
View File
@@ -0,0 +1,85 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssh
import (
"testing"
)
func TestClientAuthRestrictedPublicKeyAlgos(t *testing.T) {
for _, tt := range []struct {
name string
key Signer
wantError bool
}{
{"rsa", testSigners["rsa"], false},
{"dsa", testSigners["dsa"], true},
{"ed25519", testSigners["ed25519"], true},
} {
c1, c2, err := netPipe()
if err != nil {
t.Fatalf("netPipe: %v", err)
}
defer c1.Close()
defer c2.Close()
serverConf := &ServerConfig{
PublicKeyAuthAlgorithms: []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512},
PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
return nil, nil
},
}
serverConf.AddHostKey(testSigners["ecdsap256"])
done := make(chan struct{})
go func() {
defer close(done)
NewServerConn(c1, serverConf)
}()
clientConf := ClientConfig{
User: "user",
Auth: []AuthMethod{
PublicKeys(tt.key),
},
HostKeyCallback: InsecureIgnoreHostKey(),
}
_, _, _, err = NewClientConn(c2, "", &clientConf)
if err != nil {
if !tt.wantError {
t.Errorf("%s: got unexpected error %q", tt.name, err.Error())
}
} else if tt.wantError {
t.Errorf("%s: succeeded, but want error", tt.name)
}
<-done
}
}
func TestNewServerConnValidationErrors(t *testing.T) {
c1, c2, err := netPipe()
if err != nil {
t.Fatalf("netPipe: %v", err)
}
defer c1.Close()
defer c2.Close()
serverConf := &ServerConfig{
PublicKeyAuthAlgorithms: []string{CertAlgoRSAv01},
}
_, _, _, err = NewServerConn(c1, serverConf)
if err == nil {
t.Fatal("NewServerConn with invalid public key auth algorithms succeeded")
}
serverConf = &ServerConfig{
Config: Config{
KeyExchanges: []string{kexAlgoDHGEXSHA256},
},
}
_, _, _, err = NewServerConn(c1, serverConf)
if err == nil {
t.Fatal("NewServerConn with unsupported key exchange succeeded")
}
}
+59 -12
View File
@@ -13,6 +13,7 @@ import (
"io"
"math/rand"
"net"
"sync"
"testing"
"golang.org/x/crypto/ssh/terminal"
@@ -27,8 +28,14 @@ func dial(handler serverType, t *testing.T) *Client {
t.Fatalf("netPipe: %v", err)
}
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
wg.Add(1)
go func() {
defer c1.Close()
defer func() {
c1.Close()
wg.Done()
}()
conf := ServerConfig{
NoClientAuth: true,
}
@@ -39,7 +46,11 @@ func dial(handler serverType, t *testing.T) *Client {
t.Errorf("Unable to handshake: %v", err)
return
}
go DiscardRequests(reqs)
wg.Add(1)
go func() {
DiscardRequests(reqs)
wg.Done()
}()
for newCh := range chans {
if newCh.ChannelType() != "session" {
@@ -52,8 +63,10 @@ func dial(handler serverType, t *testing.T) *Client {
t.Errorf("Accept: %v", err)
continue
}
wg.Add(1)
go func() {
handler(ch, inReqs, t)
wg.Done()
}()
}
if err := conn.Wait(); err != io.EOF {
@@ -338,8 +351,13 @@ func TestServerWindow(t *testing.T) {
t.Fatal(err)
}
defer session.Close()
result := make(chan []byte)
serverStdin, err := session.StdinPipe()
if err != nil {
t.Fatalf("StdinPipe failed: %v", err)
}
result := make(chan []byte)
go func() {
defer close(result)
echoedBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes))
@@ -355,10 +373,6 @@ func TestServerWindow(t *testing.T) {
result <- echoedBuf.Bytes()
}()
serverStdin, err := session.StdinPipe()
if err != nil {
t.Fatalf("StdinPipe failed: %v", err)
}
written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestBytes)
if err != nil {
t.Errorf("failed to copy origBuf to serverStdin: %v", err)
@@ -648,29 +662,44 @@ func TestSessionID(t *testing.T) {
User: "user",
}
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
srvErrCh := make(chan error, 1)
wg.Add(1)
go func() {
defer wg.Done()
conn, chans, reqs, err := NewServerConn(c1, serverConf)
srvErrCh <- err
if err != nil {
return
}
serverID <- conn.SessionID()
go DiscardRequests(reqs)
wg.Add(1)
go func() {
DiscardRequests(reqs)
wg.Done()
}()
for ch := range chans {
ch.Reject(Prohibited, "")
}
}()
cliErrCh := make(chan error, 1)
wg.Add(1)
go func() {
defer wg.Done()
conn, chans, reqs, err := NewClientConn(c2, "", clientConf)
cliErrCh <- err
if err != nil {
return
}
clientID <- conn.SessionID()
go DiscardRequests(reqs)
wg.Add(1)
go func() {
DiscardRequests(reqs)
wg.Done()
}()
for ch := range chans {
ch.Reject(Prohibited, "")
}
@@ -738,6 +767,8 @@ func TestHostKeyAlgorithms(t *testing.T) {
serverConf.AddHostKey(testSigners["rsa"])
serverConf.AddHostKey(testSigners["ecdsa"])
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
connect := func(clientConf *ClientConfig, want string) {
var alg string
clientConf.HostKeyCallback = func(h string, a net.Addr, key PublicKey) error {
@@ -751,7 +782,11 @@ func TestHostKeyAlgorithms(t *testing.T) {
defer c1.Close()
defer c2.Close()
go NewServerConn(c1, serverConf)
wg.Add(1)
go func() {
NewServerConn(c1, serverConf)
wg.Done()
}()
_, _, _, err = NewClientConn(c2, "", clientConf)
if err != nil {
t.Fatalf("NewClientConn: %v", err)
@@ -785,7 +820,11 @@ func TestHostKeyAlgorithms(t *testing.T) {
defer c1.Close()
defer c2.Close()
go NewServerConn(c1, serverConf)
wg.Add(1)
go func() {
NewServerConn(c1, serverConf)
wg.Done()
}()
clientConf.HostKeyAlgorithms = []string{"nonexistent-hostkey-algo"}
_, _, _, err = NewClientConn(c2, "", clientConf)
if err == nil {
@@ -818,14 +857,22 @@ func TestServerClientAuthCallback(t *testing.T) {
User: someUsername,
}
var wg sync.WaitGroup
t.Cleanup(wg.Wait)
wg.Add(1)
go func() {
defer wg.Done()
_, chans, reqs, err := NewServerConn(c1, serverConf)
if err != nil {
t.Errorf("server handshake: %v", err)
userCh <- "error"
return
}
go DiscardRequests(reqs)
wg.Add(1)
go func() {
DiscardRequests(reqs)
wg.Done()
}()
for ch := range chans {
ch.Reject(Prohibited, "")
}
+35
View File
@@ -5,6 +5,7 @@
package ssh
import (
"context"
"errors"
"fmt"
"io"
@@ -332,6 +333,40 @@ func (l *tcpListener) Addr() net.Addr {
return l.laddr
}
// DialContext initiates a connection to the addr from the remote host.
//
// The provided Context must be non-nil. If the context expires before the
// connection is complete, an error is returned. Once successfully connected,
// any expiration of the context will not affect the connection.
//
// See func Dial for additional information.
func (c *Client) DialContext(ctx context.Context, n, addr string) (net.Conn, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
type connErr struct {
conn net.Conn
err error
}
ch := make(chan connErr)
go func() {
conn, err := c.Dial(n, addr)
select {
case ch <- connErr{conn, err}:
case <-ctx.Done():
if conn != nil {
conn.Close()
}
}
}()
select {
case res := <-ch:
return res.conn, res.err
case <-ctx.Done():
return nil, ctx.Err()
}
}
// Dial initiates a connection to the addr from the remote host.
// The resulting connection has a zero LocalAddr() and RemoteAddr().
func (c *Client) Dial(n, addr string) (net.Conn, error) {
+33
View File
@@ -5,7 +5,10 @@
package ssh
import (
"context"
"net"
"testing"
"time"
)
func TestAutoPortListenBroken(t *testing.T) {
@@ -18,3 +21,33 @@ func TestAutoPortListenBroken(t *testing.T) {
t.Errorf("version %q marked as broken", works)
}
}
func TestClientImplementsDialContext(t *testing.T) {
type ContextDialer interface {
DialContext(context.Context, string, string) (net.Conn, error)
}
// Belt and suspenders assertion, since package net does not
// declare a ContextDialer type.
var _ ContextDialer = &net.Dialer{}
var _ ContextDialer = &Client{}
}
func TestClientDialContextWithCancel(t *testing.T) {
c := &Client{}
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, err := c.DialContext(ctx, "tcp", "localhost:1000")
if err != context.Canceled {
t.Errorf("DialContext: got nil error, expected %v", context.Canceled)
}
}
func TestClientDialContextWithDeadline(t *testing.T) {
c := &Client{}
ctx, cancel := context.WithDeadline(context.Background(), time.Now())
defer cancel()
_, err := c.DialContext(ctx, "tcp", "localhost:1000")
if err != context.DeadlineExceeded {
t.Errorf("DialContext: got nil error, expected %v", context.DeadlineExceeded)
}
}
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package test
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package test
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package test
+6 -2
View File
@@ -3,13 +3,13 @@
// license that can be found in the LICENSE file.
//go:build !windows && !js && !wasip1
// +build !windows,!js,!wasip1
package test
// direct-tcpip and direct-streamlocal functional tests
import (
"context"
"fmt"
"io"
"net"
@@ -47,7 +47,11 @@ func testDial(t *testing.T, n, listenAddr string, x dialTester) {
}
}()
conn, err := sshConn.Dial(n, l.Addr().String())
ctx, cancel := context.WithCancel(context.Background())
conn, err := sshConn.DialContext(ctx, n, l.Addr().String())
// Canceling the context after dial should have no effect
// on the opened connection.
cancel()
if err != nil {
t.Fatalf("Dial: %v", err)
}
-1
View File
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package test

Some files were not shown because too many files have changed in this diff Show More