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

Cargo built-in Git/SSH client doesn't support @cert-authority #11577

Open
hds opened this issue Jan 13, 2023 · 5 comments · Fixed by #11586
Open

Cargo built-in Git/SSH client doesn't support @cert-authority #11577

hds opened this issue Jan 13, 2023 · 5 comments · Fixed by #11586
Labels
A-diagnostics Area: Error and warning messages generated by Cargo itself. A-documenting-cargo-itself Area: Cargo's documentation A-git Area: anything dealing with git A-networking Area: networking issues, curl, etc. C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` E-medium Experience: Medium S-accepted Status: Issue or feature is accepted, and has a team member available to help mentor or review

Comments

@hds
Copy link
Contributor

hds commented Jan 13, 2023

Edited: for remaining tasks, see #11577 (comment).

Problem

Cargo parses SSH known hosts file. From the Cargo book (https://doc.rust-lang.org/cargo/appendix/git-authentication.html#ssh-known-hosts):

When connecting to an SSH host, Cargo must verify the identity of the host using "known hosts", which are a list of host keys. Cargo can look for these known hosts in OpenSSH-style known_hosts files located in their standard locations ...

However, there are some additional markers supported by at least some SSH clients (e.g. OpenSSH) to handle more complex cases than verifying a host via a single algorithm/key. The known ones are:

  • @cert-authority
  • @revoked

The Cargo SSH client doesn't support these directives. It is quite explicit about this in the code:

// FIXME: @revoked and @cert-authority is currently not supported.
if line.is_empty() || line.starts_with(['#', '@']) {
return None;
}

With the release of Rust 1.66.1 and the fix for CVE-2022-46176 (security advisory), Cargo is now performing host key checking, which will lead to more users needing this functionality because single host key verification may not be practical.

Proposed Solution

The solution to this issue would be to implement the missing support for the @cert-authority or @revoked markers.

There is useful documentation on these markers from the OpenSSH project:

This issue can be mitigated by telling cargo to use the command line Git client (net.git-fetch-with-cli = true) as mentioned by @weihanglo on this Zulip thread: https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/Cargo.20SSH.20host.20key.20verification.20with.20.40cert-authority.20lines

As mentioned on that thread, a good mitigation step would be to add some text to the Cargo book section on SSH Known Hosts to suggest that users try net.git-fetch-with-cli = true if they find that Cargo's SSH behaviour is different to what they expect or different to how their command line Git client behaves.

Notes

Some further useful resources that I found related to creating an SSH Certificate Authority (CA) and then specifying it in the SSH Known Hosts file:

@hds hds added the C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` label Jan 13, 2023
@weihanglo weihanglo added A-documenting-cargo-itself Area: Cargo's documentation A-git Area: anything dealing with git E-help-wanted A-networking Area: networking issues, curl, etc. E-medium Experience: Medium A-diagnostics Area: Error and warning messages generated by Cargo itself. labels Jan 14, 2023
@weihanglo
Copy link
Member

weihanglo commented Jan 14, 2023

Thanks for the beautiful issue report! The manual of OpenSSH sshd is also considered as a reference.

As what aforementioned, there are at least a few independent tasks:

I would help mentor some of them, but for @cert-authority probably not.

@weihanglo weihanglo added E-mentor and removed E-medium Experience: Medium labels Jan 14, 2023
@est31
Copy link
Member

est31 commented Jan 16, 2023

  • Implementing @cert-authority marker

The certificate format is documented here.

There is an implementation of ssh certificates in Rust, from the rust-crypto team, via the ssh-key crate. The library contains also an entire authorized_keys parser. I guess it wasn't used for the CVE addressing because it was a third party component that wasn't audited. I think long term it might be best to move out much of the authorized_keys parsing into a different crate, maybe even a different repo.

hds added a commit to hds/cargo that referenced this issue Jan 16, 2023
Cargo doesn't support the `@cert-authority` or `@revoked` markers in SSH
Known Hosts files. The lines are silently ignored.

If a user is depending on these lines to connect to a Git server via
SSH, then their command line Git client will work, but Cargo will fail
with an error that the host key doesn't match.

This change adds a note explaining that Cargo doesn't support these
markers and suggests that the user change their cargo configuration to
fetch with the CLI client instead.

Refs: rust-lang#11577
@hds
Copy link
Contributor Author

hds commented Jan 16, 2023

Thanks for the comments @weihanglo and @est31! I've added the links you each suggested into the main text of the Issue to make reading it less confusing. I've also switched from calling these lines directives (which seems to be wrong, I don't know where I got that from) to calling them markers.

There's a small docs PR for the first task on the list ready too.

@hds hds changed the title Cargo built-in Git/SSH client doesn't support @cert-authority or @revoked directives Cargo built-in Git/SSH client doesn't support @cert-authority or @revoked markers Jan 16, 2023
@bors bors closed this as completed in 8681a5a Jan 16, 2023
@hds
Copy link
Contributor Author

hds commented Jan 16, 2023

I don't think we want to close this issue, as the referenced PR was only for the first task. Or would you prefer to have separate issues for those?

@weihanglo weihanglo reopened this Jan 16, 2023
@weihanglo
Copy link
Member

Reopen as we can continue tracking sub-tasks here #11577 (comment). Thanks for the suggestion :)

hds added a commit to hds/cargo that referenced this issue Jan 27, 2023
The SSH `known_hosts` file parsing in Cargo did not previously support
markers. Markers are modifiers on the lines (`@cert-authority` and
`@revoked`) which denote special behavior for the details on that line.
Lines were skipped entirely.

This change adds support for the `@revoked` marker. This marker denotes
that a key should be rejected outright. It is of limited use without
`@cert-authority` marker support. However, if it is present in a user's
`known_hosts` file, then Cargo definitely shouldn't accept that key and
probably shouldn't suggest that the user add it to their `known_hosts`
either.

The change also adds support for detecting `@cert-authority` markers in
`known_hosts` files. These lines cannot yet be used for host key
verification, but if one is found for a matching host, the user will be
informed that Cargo doesn't support `@cert-authority` markers in the
error message. Additionally, the user will be advised to use the
`net.git-fetch-with-cli` config option to use the command line git
client for fetching crates from Git.

Refs: rust-lang#11577
hds added a commit to hds/cargo that referenced this issue Jan 27, 2023
The SSH `known_hosts` file parsing in Cargo did not previously support
markers. Markers are modifiers on the lines (`@cert-authority` and
`@revoked`) which denote special behavior for the details on that line.
Lines were skipped entirely.

This silent skipping of marker lines can be confusing to a user, who
sees that their command line Git/SSH client works for some repository,
but Cargo reports that no host key is found.

This change adds support for the `@revoked` marker. This marker denotes
that a key should be rejected outright. It is of limited use without
`@cert-authority` marker support. However, if it is present in a user's
`known_hosts` file, then Cargo definitely shouldn't accept that key and
probably shouldn't suggest that the user add it to their `known_hosts`
either.

The change also adds support for detecting `@cert-authority` markers in
`known_hosts` files. These lines cannot yet be used for host key
verification, but if one is found for a matching host, the user will be
informed that Cargo doesn't support `@cert-authority` markers in the
error message. Additionally, the user will be advised to use the
`net.git-fetch-with-cli` config option to use the command line git
client for fetching crates from Git.

Refs: rust-lang#11577
hds added a commit to hds/cargo that referenced this issue Jan 27, 2023
The SSH `known_hosts` file parsing in Cargo did not previously support
markers. Markers are modifiers on the lines (`@cert-authority` and
`@revoked`) which denote special behavior for the details on that line.
Lines were skipped entirely.

This silent skipping of marker lines can be confusing to a user, who
sees that their command line Git/SSH client works for some repository,
but Cargo reports that no host key is found.

This change adds support for the `@revoked` marker. This marker denotes
that a key should be rejected outright. It is of limited use without
`@cert-authority` marker support. However, if it is present in a user's
`known_hosts` file, then Cargo definitely shouldn't accept that key and
probably shouldn't suggest that the user add it to their `known_hosts`
either.

The change also adds support for detecting `@cert-authority` markers in
`known_hosts` files. These lines cannot yet be used for host key
verification, but if one is found for a matching host, the user will be
informed that Cargo doesn't support `@cert-authority` markers in the
error message. Additionally, the user will be advised to use the
`net.git-fetch-with-cli` config option to use the command line git
client for fetching crates from Git.

Refs: rust-lang#11577
bors added a commit that referenced this issue Feb 1, 2023
Add partial support for SSH known hosts markers

### What does this PR try to resolve?

The SSH `known_hosts` file parsing in Cargo did not previously support
markers. Markers are modifiers on the lines (``@cert-authority`` and
``@revoked`)` which denote special behavior for the details on that line.
Lines were skipped entirely.

This silent skipping of marker lines can be confusing to a user, who
sees that their command line Git/SSH client works for some repository,
but Cargo reports that no host key is found.

This change adds support for the ``@revoked`` marker. This marker denotes
that a key should be rejected outright. It is of limited use without
``@cert-authority`` marker support. However, if it is present in a user's
`known_hosts` file, then Cargo definitely shouldn't accept that key and
probably shouldn't suggest that the user add it to their `known_hosts`
either.

The change also adds support for detecting ``@cert-authority`` markers in
`known_hosts` files. These lines cannot yet be used for host key
verification, but if one is found for a matching host, the user will be
informed that Cargo doesn't support ``@cert-authority`` markers in the
error message. Additionally, the user will be advised to use the
`net.git-fetch-with-cli` config option to use the command line git
client for fetching crates from Git.

Refs: #11577

### How should we test and review this PR?

The changes in this PR are covered by unit tests, all within
`src/cargo/sources/git/known_hosts.rs`.

Additionally, manual testing can be performed. For this you will need
an OpenSSH server (it doesn't need to be a Git server). I'll assume
that you have one running on your local machine at `127.0.0.1`.

#### Setup

1. Create a new Cargo project and add the following line to `[dependencies]`:
```toml
fake-crate = { git = "ssh://127.0.0.1/fake-crate.git" }
```

#### Test missing host key: `HostKeyNotFound` (existing functionality)

1. Back up your `known_hosts` file and then remove any lines for `127.0.0.1`.
2. Verify host key not present: `ssh 127.0.0.1`. SSH should tell you `The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.`
3. Run `cargo build`
4. Expect error from Cargo: `error: unknown SSH host key`

#### Test ``@revoked`` key: `HostKeyRevoked`

1. Back up your `known_hosts` file and then remove any lines for `127.0.0.1`.
2. Add host key: `ssh 127.0.0.1` answer `yes`
3. Find all lines in `known_hosts` beginning with `127.0.0.1` (there may be multiple).
4. Add ``@revoked` ` to the beginning of all lines in (3)
5. Run `cargo build`
6. Expect error from Cargo: error: Key has been revoked for `127.0.0.1`

#### Test `@cert-authority`` (not being supported): `HostHasOnlyCertAuthority`

1. Back up your `known_hosts` file and then remove any lines for `127.0.0.1`.
2. Run `cargo build`
3. Expect error from Cargo: `error: unknown SSH host key`
4. Check the line after ` The key to add is:` in the error message and copy the key type (e.g. `ecdsa-sha2-nistp256`)
5. Add a line to `known_hosts`: ``@cert-authority` 127.0.0.1 <key-type> AAAAB5Wm` (e.g. ``@cert-authority` 127.0.0.1 ecdsa-sha2-nistp256 AAAAB5Wm`)
7. Run `cargo build`
8. Expect error from Cargo: error: Found a ``@cert-authority`` marker for `127.0.0.1`

### Additional information

Cargo doesn't currently support a few things when checking host keys. This may affect the testing described above.
* Multiple host key types (OpenSSH negotiates the host key type and can support matching the one present in the `known_hosts` file even when it's not the preferred type of the server).
* Wildcard matching of host patterns (there's a FIXME for this)

More information about SSH known host markers can be found
on #11577.
ehuss pushed a commit to ehuss/cargo that referenced this issue Mar 26, 2023
Add partial support for SSH known hosts markers

### What does this PR try to resolve?

The SSH `known_hosts` file parsing in Cargo did not previously support
markers. Markers are modifiers on the lines (``@cert-authority`` and
``@revoked`)` which denote special behavior for the details on that line.
Lines were skipped entirely.

This silent skipping of marker lines can be confusing to a user, who
sees that their command line Git/SSH client works for some repository,
but Cargo reports that no host key is found.

This change adds support for the ``@revoked`` marker. This marker denotes
that a key should be rejected outright. It is of limited use without
``@cert-authority`` marker support. However, if it is present in a user's
`known_hosts` file, then Cargo definitely shouldn't accept that key and
probably shouldn't suggest that the user add it to their `known_hosts`
either.

The change also adds support for detecting ``@cert-authority`` markers in
`known_hosts` files. These lines cannot yet be used for host key
verification, but if one is found for a matching host, the user will be
informed that Cargo doesn't support ``@cert-authority`` markers in the
error message. Additionally, the user will be advised to use the
`net.git-fetch-with-cli` config option to use the command line git
client for fetching crates from Git.

Refs: rust-lang#11577

### How should we test and review this PR?

The changes in this PR are covered by unit tests, all within
`src/cargo/sources/git/known_hosts.rs`.

Additionally, manual testing can be performed. For this you will need
an OpenSSH server (it doesn't need to be a Git server). I'll assume
that you have one running on your local machine at `127.0.0.1`.

#### Setup

1. Create a new Cargo project and add the following line to `[dependencies]`:
```toml
fake-crate = { git = "ssh://127.0.0.1/fake-crate.git" }
```

#### Test missing host key: `HostKeyNotFound` (existing functionality)

1. Back up your `known_hosts` file and then remove any lines for `127.0.0.1`.
2. Verify host key not present: `ssh 127.0.0.1`. SSH should tell you `The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.`
3. Run `cargo build`
4. Expect error from Cargo: `error: unknown SSH host key`

#### Test ``@revoked`` key: `HostKeyRevoked`

1. Back up your `known_hosts` file and then remove any lines for `127.0.0.1`.
2. Add host key: `ssh 127.0.0.1` answer `yes`
3. Find all lines in `known_hosts` beginning with `127.0.0.1` (there may be multiple).
4. Add ``@revoked` ` to the beginning of all lines in (3)
5. Run `cargo build`
6. Expect error from Cargo: error: Key has been revoked for `127.0.0.1`

#### Test `@cert-authority`` (not being supported): `HostHasOnlyCertAuthority`

1. Back up your `known_hosts` file and then remove any lines for `127.0.0.1`.
2. Run `cargo build`
3. Expect error from Cargo: `error: unknown SSH host key`
4. Check the line after ` The key to add is:` in the error message and copy the key type (e.g. `ecdsa-sha2-nistp256`)
5. Add a line to `known_hosts`: ``@cert-authority` 127.0.0.1 <key-type> AAAAB5Wm` (e.g. ``@cert-authority` 127.0.0.1 ecdsa-sha2-nistp256 AAAAB5Wm`)
7. Run `cargo build`
8. Expect error from Cargo: error: Found a ``@cert-authority`` marker for `127.0.0.1`

### Additional information

Cargo doesn't currently support a few things when checking host keys. This may affect the testing described above.
* Multiple host key types (OpenSSH negotiates the host key type and can support matching the one present in the `known_hosts` file even when it's not the preferred type of the server).
* Wildcard matching of host patterns (there's a FIXME for this)

More information about SSH known host markers can be found
on rust-lang#11577.
@ehuss ehuss changed the title Cargo built-in Git/SSH client doesn't support @cert-authority or @revoked markers Cargo built-in Git/SSH client doesn't support @cert-authority Apr 3, 2023
@weihanglo weihanglo added S-accepted Status: Issue or feature is accepted, and has a team member available to help mentor or review and removed E-mentor labels Apr 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Error and warning messages generated by Cargo itself. A-documenting-cargo-itself Area: Cargo's documentation A-git Area: anything dealing with git A-networking Area: networking issues, curl, etc. C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` E-medium Experience: Medium S-accepted Status: Issue or feature is accepted, and has a team member available to help mentor or review
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants