Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/crypto: SSH Agent add key with cert not working as expected #55285

Closed
michaeljs1990 opened this issue Sep 20, 2022 · 2 comments
Closed

x/crypto: SSH Agent add key with cert not working as expected #55285

michaeljs1990 opened this issue Sep 20, 2022 · 2 comments

Comments

@michaeljs1990
Copy link

michaeljs1990 commented Sep 20, 2022

What version of Go are you using (go version)?

$ go version
go version go1.18.5 darwin/arm64

Does this issue reproduce with the latest release?

I checked on the master branch in golang crypto and the code path and the function calls have not been changed from the version I am currently looking at locally https://github.com/golang/crypto/blob/master/ssh/agent/client.go#L660

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/mschuett/Library/Caches/go-build"
GOENV="/Users/mschuett/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/mschuett/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/mschuett/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.18.5/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.18.5/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.18.5"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/mschuett/path/code/dk/go.mod"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/cl/gz_1n0hs4f138_5g2qjwm6d40000gn/T/go-build1294949332=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I created a ssh agent add key struct and populated it with both a private key and a cert that need to be added to the ssh-agent. When I call client.Add(AddKey) only the cert is inserted and the private key is ignored.

func (v *SSHAgent) Refresh(force bool, invocation string) error {
	socket := os.Getenv("SSH_AUTH_SOCK")
	if socket == "" {
		return errors.New("SSH_AUTH_SOCK is not set so we can't update your ssh-agent")
	}

	conn, err := net.Dial("unix", socket)
	if err != nil {
		return errors.New(
			fmt.Sprintf("Failed to open SSH_AUTH_SOCK: %v", err))
	}

	pubKeyContent, err := v.ReadFile(v.params["pub_key"])
	if err != nil {
		return err
	}

	pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(pubKeyContent))

	agentClient := agent.NewClient(conn)
	agentClient.Remove(pubKey)

	// Because it's always possible for the cert in the ssh-agent to not be the same cert that is on disk
	// or even the same cert from the last time dk was run we just look over all keys and remove the certs.
	// I think it is reasonable to assume no one else is setting up certs for other uses.
	keys, _ := agentClient.List()
	for _, key := range keys {
		if key.Type() == "ssh-rsa-cert-v01@openssh.com" {
			cert, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key.String()))
			if err != nil {
				return err
			}

			agentClient.Remove(cert)
		}
	}

	privKeyPath, err := v.PubKeyToPrivate(v.params["pub_key"])
	if err != nil {
		return err
	}

	privKeyContent, err := v.ReadFile(privKeyPath)
	if err != nil {
		return err
	}

	privKey, err := ssh.ParseRawPrivateKey([]byte(privKeyContent))
	if err != nil {
		return err
	}

	certPath, err := v.PubKeyToCert(v.params["pub_key"])

	certContent, err := v.ReadFile(certPath)
	if err != nil {
		return err
	}

	certKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(certContent))
	if err != nil {
		return err
	}

	cert, ok := certKey.(*ssh.Certificate)
	if !ok {
		return errors.New("key was not a certificate")
	}

	// Only keep the keys in the agent as long as the cert is good for. The private key by itself
	// is no longer userful in our environment.
	now := time.Now()
	var ttl uint64
	if cert.ValidBefore > uint64(now.Unix()) {
		ttl = cert.ValidBefore - uint64(now.Unix())
	}

	keyToAdd := agent.AddedKey{
		PrivateKey:   privKey,
		Certificate:  cert,
		LifetimeSecs: uint32(ttl),
		Comment:      "managed",
	}

	err = agentClient.Add(keyToAdd)
	if err != nil {
		return err
	}

	return nil
}

Sorry I know this doesn't run out of the box but i'll try and clean this up a little later.

What did you expect to see?

I expected to see both a ssh cert and a private key added. This is also what the documented for the AddedKey struct say will happen unless I am reading it wrong. If I do AddedKey and prepare one with a cert and one with out and call agentClient.Add twice I get the results I am expecting.

What did you see instead?

Only the cert is added to my ssh agent as seen with ssh-add -L. Sorry if I am misunderstanding or using the above code wrong however from the docs it seems like both the private key and cert should be added.

@michaeljs1990 michaeljs1990 changed the title affected/package: x/crypto x/crypto: SSH Agent add key with cert not working as expected Sep 20, 2022
@gopherbot gopherbot added this to the Unreleased milestone Sep 20, 2022
@michaeljs1990
Copy link
Author

Possibly related to this issue. I'll try testing this code on a linux machine with a newer version of SSH to see if that makes any difference.

ssh -V
OpenSSH_8.6p1, LibreSSL 3.3.6

@michaeljs1990
Copy link
Author

Sorry please ignore me. I was trying to verify my golang code vs what happens when ssh-add command adds a key to the agent. When the ssh-add command adds them it shows up as two different identities. However with the golang AddKey struct only the cert shows up.

The proper information however is stored in the agent. Sorry for the noise but hopefully this will help another confused person at some point,.

@golang golang locked and limited conversation to collaborators Sep 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants