---
title: Public key algorithm
layout: page
parent: Tutorial
nav_order: 4
---
# {{ page.title }}
This chapter will build on the [previous chapter]({% link tutorial/3-pubkey-auth.md %}) by selecting the public key algorithm more robustly.
## Get the list of supported algorithms
We can use the [`Privkey::pubkey()`][privkey-pubkey] method to obtain the [`Pubkey`][pubkey] from the [`Privkey`][privkey] that we have read from PEM in the previous chapter:
[privkey-pubkey]: https://docs.rs/makiko/latest/makiko/pubkey/enum.Privkey.html#method.pubkey
[pubkey]: https://docs.rs/makiko/latest/makiko/pubkey/enum.Pubkey.html
[privkey]: https://docs.rs/makiko/latest/makiko/pubkey/enum.Privkey.html
```rust
// Get the public key from the private key.
let pubkey = privkey.pubkey();
```
And to obtain the list of algorithms that Makiko supports for this public key, we can use the [`Pubkey::algos()`][pubkey-algos] method:
[pubkey-algos]: https://docs.rs/makiko/latest/makiko/pubkey/enum.Pubkey.html#method.algos
```rust
// Get the public key algorithms supported by the key.
let available_algos = pubkey.algos();
```
Next, we need to find out which of these algorithms is also supported by the server.
## Check public keys and an algorithms
Armed with the private key and a list of algorithms, we could simply try to call [`Client::auth_pubkey()`][client-auth-pubkey] with each algorithm in turn. This is a reasonable approach, but it has two disadvantages:
1. SSH servers typically limit the number of failed authentication attempts to a small number and will close the connection when this limit is exceeded.
2. The signing operation that is required for authentication might be expensive in terms of CPU time.
[client-auth-pubkey]: https://docs.rs/makiko/latest/makiko/struct.Client.html#method.auth_pubkey
Fortunately, the SSH protocol provides a mechanism to ask the server whether it would accept a given combination of public key and algorithm, without actually attempting the authentication. We can use this mechanism by calling [`Client::check_pubkey()`][client-check-pubkey], which takes the username, public key and public key algorithm, and returns a bool:
[client-check-pubkey]: https://docs.rs/makiko/latest/makiko/struct.Client.html#method.check_pubkey
```rust
// Try the algorithms one by one.
let username: String = "ruth".into();
for pubkey_algo in available_algos.iter().copied() {
// Check whether this combination of a public key and algorithm would be acceptable to the
// server.
let check_ok = client.check_pubkey(username.clone(), &pubkey, pubkey_algo).await
.expect("Error when checking a public key");
...
}
```
If the server says that it will not accept this public key and algorithm, we can try the next algorithm:
```rust
for pubkey_algo in ... {
let check_ok = ...;
// Skip this algorithm if the server rejected it.
if !check_ok {
println!("Server rejected public key and algorithm {:?}", pubkey_algo.name);
continue;
}
...
}
```
Otherwise, we can try to authenticate:
```rust
for pubkey_algo in ... {
...
// Try to authenticate using this algorithm.
let auth_res = client.auth_pubkey(username.clone(), privkey.clone(), pubkey_algo).await
.expect("Error when trying to authenticate");
match auth_res {
makiko::AuthPubkeyResult::Success => {
println!("We have successfully authenticated using algorithm {:?}", pubkey_algo.name);
break;
},
makiko::AuthPubkeyResult::Failure(_) => {
println!("Authentication using public key and algorithm {:?} failed", pubkey_algo.name);
},
}
}
```
Finally, we can use the [`Client::is_authenticated()`][client-is-authenticated] method to check whether we have been successful:
[client-is-authenticated]: https://docs.rs/makiko/latest/makiko/struct.Client.html#method.is_authenticated
```rust
// Check that we have been authenticated.
if !client.is_authenticated().unwrap() {
panic!("Could not authenticate");
}
```
---
Full code for this tutorial can be found in [`examples/tutorial_4.rs`][tutorial-4]. The program will print messages about the authentication attemps, and it will panic if authentication fails. If you don't use the [example server for this tutorial][example-server], you may need to change the code to use a different username and private key.
[tutorial-4]: https://github.com/honzasp/makiko/blob/master/examples/tutorial_4.rs
[example-server]: {% link tutorial/1-connect.md %}#example-server
{% include tutorial_next.html link="tutorial/5-execute-command.md" title="Execute a command" %}