I’ve implemented all of this in AsyncSSH, and there I chose to break out the 
authorized_key parsing from public key parsing. More specifically, AsyncSSH 
provides the following functions for reading SSH public keys:
import_public_key 
<http://asyncssh.readthedocs.io/en/latest/api.html#import-public-key>
asyncssh.import_public_key(data)[source] 
<http://asyncssh.readthedocs.io/en/latest/_modules/asyncssh/public_key.html#import_public_key>
 <http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.import_public_key>
Import a public key

This function imports a public key encoded in OpenSSH, RFC4716, or PKCS#1 or 
PKCS#8 DER or PEM format.

Parameters:     data (bytes or ASCII string) – The data to import.
Returns:        An SSHKey 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.SSHKey> public key
read_public_key 
<http://asyncssh.readthedocs.io/en/latest/api.html#read-public-key>
asyncssh.read_public_key(filename)[source] 
<http://asyncssh.readthedocs.io/en/latest/_modules/asyncssh/public_key.html#read_public_key>
 <http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.read_public_key>
Read a public key from a file

This function reads a public key from a file. See the function 
import_public_key() 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.import_public_key> 
for information about the formats supported.

Parameters:     filename (str 
<https://docs.python.org/3/library/stdtypes.html#str>) – The file to read the 
key from.
Returns:        An SSHKey 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.SSHKey> public key
read_public_key_list 
<http://asyncssh.readthedocs.io/en/latest/api.html#read-public-key-list>
asyncssh.read_public_key_list(filename)[source] 
<http://asyncssh.readthedocs.io/en/latest/_modules/asyncssh/public_key.html#read_public_key_list>
 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.read_public_key_list>
Read a list of public keys from a file

This function reads a list of public keys from a file. See the function 
import_public_key() 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.import_public_key> 
for information about the formats supported.

Parameters:     filename (str 
<https://docs.python.org/3/library/stdtypes.html#str>) – The file to read the 
keys from.
Returns:        A list of SSHKey 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.SSHKey> public keys

Similar functions are also available for operating on SSH private keys and 
certificates.

Then, I have a separate set of functions for operating on data in 
authorized_key format:
import_authorized_keys 
<http://asyncssh.readthedocs.io/en/latest/api.html#import-authorized-keys>
asyncssh.import_authorized_keys(data)[source] 
<http://asyncssh.readthedocs.io/en/latest/_modules/asyncssh/auth_keys.html#import_authorized_keys>
 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.import_authorized_keys>
Import SSH authorized keys

This function imports public keys and associated options in OpenSSH authorized 
keys format.

Parameters:     data (str 
<https://docs.python.org/3/library/stdtypes.html#str>) – The key data to import.
Returns:        An SSHAuthorizedKeys 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.SSHAuthorizedKeys> 
object
read_authorized_keys 
<http://asyncssh.readthedocs.io/en/latest/api.html#read-authorized-keys>
asyncssh.read_authorized_keys(filename)[source] 
<http://asyncssh.readthedocs.io/en/latest/_modules/asyncssh/auth_keys.html#read_authorized_keys>
 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.read_authorized_keys>
Read SSH authorized keys from a file

This function reads public keys and associated options in OpenSSH 
authorized_keys format from a file.

Parameters:     filename (str 
<https://docs.python.org/3/library/stdtypes.html#str>) – The file to read the 
keys from.
Returns:        An SSHAuthorizedKeys 
<http://asyncssh.readthedocs.io/en/latest/api.html#asyncssh.SSHAuthorizedKeys> 
object
Internally, the authorized_key functions use the public key functions, but only 
after stripping any prefix like “cert-authority” or the various options for 
limiting when the keys can be used or what SSH actions are allowed when using 
that key. Then, given an SSH key and some other parameters like the client IP 
and certificate information the resulting SSHAuthorizedKeys object can then 
perform matching against all these constraints and return if a key is allowed 
to be used and what permissions it grants if so.


On Aug 18, 2016, at 4:04 PM, Chris Hines <chris.hi...@monash.edu> wrote:
> Hi Paul,
> Options are specified in the sshd man page
> 
> https://www.freebsd.org/cgi/man.cgi?sshd(8) 
> <https://www.freebsd.org/cgi/man.cgi?sshd(8)>
> 
> Under the section Authorized Keys File Format.
> 
> Technically options are not part of the public key (so are not covered by  
> RFC4253) but are part of the OpenSSHD authorized_keys file format (which 
> includes everything that can appear in an id_rsa.pub etc and extends it with 
> the options defined in the man page).
> 
> Sadly I don't think there is an RFC for the authorized_keys file (I suspect 
> its OpenSSH specific) but I think we all assume its a de-facto standard :-)
> 
> So at question is whether python-cryptography primitives support only the 
> RFC4253 spec for public key formats or more generally processes lines from an 
> authorized_keys file.
> 
> The fix should be relatively simple. When you split the data into  fields 
> (key-type, data and comment) don't assume the first field is key-type, but 
> instead search all fields.
> 
> The particular option *I* am most concerned with is the cert-authority option 
> (a relatively new feature in OpenSSH, but a pretty awesome one IMHO). It gets 
> pre-pended to the key before going in authorized_keys, so a typical entry 
> looks like:
> 
> cert-authority ssh-rsa 
> AAAAB3NzaC1yc2EAAAADAQABAAABAQDMnxAxjwoCQsFJ1SC7+LJeSQCmUi8plJ9nKVmAjKlDr5Z240doRVIBr7+6veFJDPkaFzDxxa4dDn4O1ITXXVrr/JUCQbo4nF3ln4LSGWdDniJxH5uhc7PDYe2FDiiUYLrl4I+n1cB5YSOTDjxERcvXORKKGjPoyYNVuv343a5n7ygIOVTnI9VwTlxKj8gNyMm7wRg+aIJ8yiDwaDqestL9qTGMc+bb8Q0w0OJn8KZoGBYGl7LvS0QNyXsp+5J0GGEuE1c0lp1d5HpgvqRdWeWrlGY5alyQ2BchfJLbUbWQGBP/+kmVZCR022jbEo13/SznECr8ym8cXZzYg+hC1Err
>  hines@tun
> 
> This particular option brings some of the functionality of x509 certificates 
> used for TLS communications (i.e. certifying authorities generating 
> certificates that can be trusted becase you trust the CA) to SSH without 
> bringing the full attack surface of x509 to ssh (at least that was the 
> justification from the OpenSSH authors for not just using x509 :-)
> 
> Other interesting options include command="..." and 
> no-agent-forwarding,no-port-forwarding
> 
> Ironically I'm not actually certain if this support should be added to 
> python-cryptography, or if it should be added downstream in openstack nova. 
> Technically its part of the authorized_keys file format, not part of the pub 
> key format, and the function in question is pretty clearly named 
> "load_ssh_public_key". On the other hand, it is clear there is some confusion 
> in the wider community of users on the difference between a public key and a 
> line in an authorized_keys file, and perhaps it would be a nice feature to 
> add.
> 
> Cheers,
> --
> Chris.
> 
> On 18 August 2016 at 23:08, Paul Kehrer <paul.l.keh...@gmail.com 
> <mailto:paul.l.keh...@gmail.com>> wrote:
> Hi Chris,
> 
> I don't think we've tried to specifically bound it. In general the assumption 
> has been that the keys it loads would be OpenSSH public keys in the form that 
> you get from an "id_rsa.pub" file (for example).
> 
> What do the options look like? Are they put into the line at the end as 
> comments?
> 
> -Paul (reaperhulk)
> 
> 
> On August 18, 2016 at 8:15:16 AM, Chris Hines (chris.hi...@monash.edu 
> <mailto:chris.hi...@monash.edu>) wrote:
> 
>> Hi List,
>> I have a question about the function
>> cryptography.hazmat.primatives.serialization.load_ssh_public_key
>> 
>> Basically is the function inteornded to load only the public key or is it 
>> intended that it be able to process any like out of an authorized_keys_file
>> 
>> Source code shows that the function is prepared to strip of the key-type (eg 
>> ssh-rsa) and use it for comparison against the inner_key_type but is not 
>> prepared to strip off any options that can be passed in an authorized_keys 
>> file (For example SSH_FORCE_COMMAND or no-port-forwarding).
>> 
>> I ask because the downstream project OpenStack Nova uses load_ssh_public_key 
>> to verify contents intended for authorized_keys is valid. Its easy enough to 
>> remove ssh options in Nova before passing to load_ssh_public_key, but I 
>> though if load_ssh_public_key already deals with the key-type header, 
>> perhaps it should also deal with the other options.
>> 
>> I can create issues and merge requests if that is helpful, just looking for 
>> clarification on the intention (i.e. does load_ssh_public_key load contents 
>> intended for authorized_keys or just the public key part)

-- 
Ron Frederick
r...@timeheart.net



_______________________________________________
Cryptography-dev mailing list
Cryptography-dev@python.org
https://mail.python.org/mailman/listinfo/cryptography-dev

Reply via email to