Module: PuTTY::Key::OpenSSL::ClassMethods

Defined in:
lib/putty/key/openssl.rb

Overview

The ClassMethods module is used to extend OpenSSL::PKey when using the PuTTY::Key refinement or calling PuTTY::Key.global_install. This adds a from_ppk class method to OpenSSL::PKey.

Instance Method Summary collapse

Instance Method Details

#from_ppk(ppk) ⇒ Object

Creates a new OpenSSL::PKey from a PuTTY private key (instance of PPK).

This method is called using OpenSSL::PKey.from_ppk(ppk).

PuTTY keys using the algorithms ssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384 and ecdsa-sha2-nistp521 are supported.

Returns:

  • (Object)

    An instance of either OpenSSL::PKey::DSA, OpenSSL::PKey::RSA or OpenSSL::PKey::EC depending on the algorithm of ppk.

Raises:

  • (ArgumentError)

    If ppk is nil.

  • (ArgumentError)

    If the algorithm of ppk is not supported.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/putty/key/openssl.rb', line 48

def from_ppk(ppk)
  raise ArgumentError, 'ppk must not be nil' unless ppk

  case ppk.algorithm
  when 'ssh-dss'
    ::OpenSSL::PKey::DSA.new.tap do |pkey|
      _, p, q, g, pub_key = Util.ssh_unpack(ppk.public_blob, :string, :mpint, :mpint, :mpint, :mpint)
      priv_key = Util.ssh_unpack(ppk.private_blob, :mpint).first

      if pkey.respond_to?(:set_key)
        # :nocov_no_openssl_pkey_dsa_set_key:
        pkey.set_key(pub_key, priv_key)
        pkey.set_pqg(p, q, g)
        # :nocov_no_openssl_pkey_dsa_set_key:
      else
        # :nocov_openssl_pkey_dsa_set_key:
        pkey.p, pkey.q, pkey.g, pkey.pub_key, pkey.priv_key = p, q, g, pub_key, priv_key
        # :nocov_openssl_pkey_dsa_set_key:
      end
    end
  when 'ssh-rsa'
    ::OpenSSL::PKey::RSA.new.tap do |pkey|
      _, e, n = Util.ssh_unpack(ppk.public_blob, :string, :mpint, :mpint)
      d, p, q, iqmp = Util.ssh_unpack(ppk.private_blob, :mpint, :mpint, :mpint, :mpint)

      dmp1 = d % (p - 1)
      dmq1 = d % (q - 1)

      if pkey.respond_to?(:set_factors)
        # :nocov_no_openssl_pkey_rsa_set_factors:
        pkey.set_factors(p, q)
        pkey.set_key(n, e, d)
        pkey.set_crt_params(dmp1, dmq1, iqmp)
        # :nocov_no_openssl_pkey_rsa_set_factors:
      else
        # :nocov_openssl_pkey_rsa_set_factors:
        pkey.e, pkey.n, pkey.d, pkey.p, pkey.q, pkey.iqmp, pkey.dmp1, pkey.dmq1 = e, n, d, p, q, iqmp, dmp1, dmq1
        # :nocov_openssl_pkey_rsa_set_factors:
      end
    end
  when /\Aecdsa-sha2-(nistp(?:256|384|521))\z/
    curve = OPENSSL_CURVES[$1]

    # Old versions of jruby-openssl don't include an EC class (version 0.9.16).
    ec_class = (::OpenSSL::PKey::EC rescue raise ArgumentError, "Unsupported algorithm: #{ppk.algorithm}")

    ec_class.new(curve).tap do |pkey|
      _, _, point = Util.ssh_unpack(ppk.public_blob, :string, :string, :mpint)
      group = pkey.group || ::OpenSSL::PKey::EC::Group.new(curve)
      pkey.public_key = ::OpenSSL::PKey::EC::Point.new(group, point)
      pkey.private_key = Util.ssh_unpack(ppk.private_blob, :mpint).first
    end
  else
    raise ArgumentError, "Unsupported algorithm: #{ppk.algorithm}"
  end
end