[erlang-patches] EEP Light: Option to override private key lookup when using Erlang ssh client

Hans Nilsson R hans.r.nilsson@REDACTED
Mon Nov 9 18:10:14 CET 2015


On 11/08/2015 04:01 PM, Vipin Nair wrote:
> EEP Light: Option to override private key lookup when using Erlang ssh client
> 
> 
>  * Why do we need this new feature?
> 
>    Currently, ssh:connect/3,4 gets the user's private key from either the
>    default directory (~/.ssh) of the user or from the directory specified in the
>    'user_dir' ssh connect option. The files names are always assumed to be
>    openssh default file names, for example, `id_rsa` or `id_dsa`. This makes the
>    API inflexible as we are required to create a directory and write the key
>    data to the file system when we are connecting to a SSH server as a third
>    party. An API to specify the private key is immensely useful when the
>    private keys are stored in, say, a database.

You seem unaware of that both the client and the server get the keys
from callbacks defined by the ssh_client_key_api and the
ssh_server_key_api.  The option key_cb defines the module to use for
ssh:connect or ssh:daemon.

The default callback module is ssh_file, which implements reading and
writing of keys to and from files compatible with OpenSSH.

You can write plugins to fetch keys from a database, fetch from files
with names of your choice or even hard code them using those behaviours.

See
  http://www.erlang.org/doc/man/ssh_client_key_api.html
  http://www.erlang.org/doc/man/ssh_server_key_api.html

-Hans

> 
> 
>  * How did you solve it?
> 
>    - Implementation description
> 
>        To address the above problem, new ssh connect options `rsa_priv_key` and
>        `dsa_priv_key` are proposed. The connect API will look like:
> 
>          ssh:connect("localhost", 22, [{user, "[USERNAME]"},
>                                        {rsa_priv_key,
> <<"[BINARY_KEY_DATA]">>}]).
> 
>        If `rsa_priv_key` is specified and RSA is used for ssh negotiation,
>        instead of reading the key from the `id_rsa` file, we use the key
>        specified above. (This key could be protected by a passphrase and it is
>        the system's responsibility to decrypt it.) `dsa_priv_key` will work
>        similarly. See below for handling of ECDSA keys and known_hosts file.
> 
>        A pull request with a partial implementation of this proposal along with
>        tests is on github[1].
> 
>    - Why you choose to implement it the way you did?
> 
>        The above solution is in the similar vein as some of the existing API's.
>        For example, when password authentication is used to connect to a server,
>        the ssh connect option `password` is used to specify the password.
>        Similarly, for encrypted private keys, the passphrase is specified using
>        ssh connect options `rsa_pass_phrase` and `dsa_pass_phrase`.
> 
>    - Other possible implementations considered
> 
>        Binary(iodata) key data can be passed onto file:open with `ram` mode
>        specified which lets us treat an object in memory as a file. We can build
>        a solution around this feature.
> 
>        SSH connect option only lets specify the user directory using the
>        `user_dir` option and *not* the individual files. File names are assumed
>        to be openssh defaults. We could change user dir to also accept a
>        proplist of individual file names/iodata.
> 
>        Current definition ->  user_dir() :: string()
> 
>        Proposed definition -> user_dir() :: string() |
>                               [{key_file() :: string() | iodata()}]
> 
>                               Where
> 
>                               key_file() :: id_rsa | id_dsa | id_ecdsa |
>                                             known_hosts
> 
>        Considering we can pass either the file name or iodata with key contents,
>        we'll have to limit file API usage to the ones that work with both of
>        them. For example, ssh_file:read_ssh_file/1 uses file:read_file/1 which
>        is not compatible with iodata() input.
> 
>        I haven't given enough thought to this solution so it is possible that I
>        could be missing something obvious. In my opinion, the first solution
>        proposed above is cleaner way to solve this problem.
> 
> 
>  * Risks or uncertain artifacts?
> 
>    - Describe known incompatibilities
> 
>        Introducing the new connect options does not introduce an
>        incompatibility, is fully backward compatible and does not affect
>        consumers of the existing API in any way.
> 
>    - Describe uncertainties that are not fully understood or unclear.
> 
>        ECDSA keys can be handled by introducing similar options above. The
>        proposed options names are `ecdsa_sha2_nistp256_priv_key`,
>        `ecdsa_sha2_nistp384_priv_key` and `ecdsa_sha2_nistp521_priv_key`.
> 
>        A new option `known_hosts` can be introduced for specifying known_hosts
>        as an API. The value corresponding to this key would be a list of known
>        server public keys.
> 
> </proposal>
> 
> Some background: I am implementing a ssh multiplexer[2] and as a consumer of
> this API, I wasn't very happy. I thought about what a better API (IMO) could
> look like and took a stab at implementing it.
> 
> [1]: https://github.com/erlang/otp/pull/884
> [2]: https://github.com/swvist/hss
> 
> 



More information about the erlang-patches mailing list