class FrontEndBuilds::Utils::SSHPubKeyConvert

This file provides a converter that accepts an SSH public key string and converts it to an OpenSSL::PKey::RSA object for use in verifying received messages. (DSA support pending).

Public Class Methods

convert(keystring) click to toggle source

Convert a string in SSH public key format to a key object suitable for use with OpenSSL. If the key is an RSA key then an OpenSSL::PKey::RSA object is returned. If the key is a DSA key then an OpenSSL::PKey::DSA object is returned. In either case, the object returned is suitable for encrypting data or verifying signatures, but cannot be used for decrypting or signing.

The keystring should be a single line, as per an SSH public key file as generated by ssh-keygen, or a line from an SSH authorized_keys file.

# File lib/front_end_builds/utils/ssh_pubkey_convert.rb, line 57
def self.convert(keystring)
  (_, b64, _) = keystring.split(' ')
  raise ArgumentError, "Invalid SSH public key '#{keystring}'" if b64.nil?

  decoded_key = Base64.decode64(b64)
  (n, bytes) = unpack_u32(decoded_key)
  (keytype, bytes) = unpack_string(bytes, n)

  if keytype == "ssh-rsa"
    (n, bytes) = unpack_u32(bytes)
    (estr, bytes) = unpack_string(bytes, n)
    (n, bytes) = unpack_u32(bytes)
    (nstr, bytes) = unpack_string(bytes, n)

    key = OpenSSL::PKey::RSA.new

    # support SSL 2
    if Gem::Version.new(OpenSSL::VERSION) < Gem::Version.new('2.0.0')
      key.n = OpenSSL::BN.new(nstr, 2)
      key.e = OpenSSL::BN.new(estr, 2)
    else
      # params are n, e, d
      key.set_key(OpenSSL::BN.new(nstr, 2), OpenSSL::BN.new(estr, 2), nil)
    end

    key
  else
    # anything non-RSA is not supported
    # this part edited by TED
    raise "Unsupported key type: #{keytype}"
  end
end
unpack_string(bytes, len) click to toggle source

Unpack a string from the bytes array. Exactly len bytes will be extracted.

Returns a pair (string, bytes), where string is the extracted string (of length len), and bytes is the remainder of the original bytes array that follows string.

# File lib/front_end_builds/utils/ssh_pubkey_convert.rb, line 42
def self.unpack_string(bytes, len)
  return bytes.unpack("A#{len}")[0], bytes[len..-1]
end
unpack_u32(bytes) click to toggle source

Unpack a 4-byte unsigned integer from the bytes array.

Returns a pair (u32, bytes), where u32 is the extracted unsigned integer, and bytes is the remainder of the original bytes array that follows u32.

# File lib/front_end_builds/utils/ssh_pubkey_convert.rb, line 31
def self.unpack_u32(bytes)
  return bytes.unpack("N")[0], bytes[4..-1]
end