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

Vipin Nair swvist@REDACTED
Sun Nov 8 16:01:54 CET 2015


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.


 * 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


-- 
Regards,
Vipin



More information about the erlang-patches mailing list