Another Ruby/OpenSSL Patch

I think I've nailed down all the issues that were preventing Net::SSH from being fully SSH2 compliant. I had to add two new methods to OpenSSL::PKey::DSA, to allow processing of raw sigs (since that's what the SSH server is sending, and expecting).

I've attached a patch. With the addition of the DSA#do_verify method that this patch exposes, Net::SSH can now successfully handle ssh-dss server keys.

Please let me know if you need anything further to apply this patch before the freeze on the 7th.

dsa.patch (4.3 KB)

···

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

ruby -ropenssl -e'k="01234567";p((c,c.padding,c.iv,c.key=OpenSSL::Cipher::BF.new,0,k,k*2)[0].decrypt.update("1A81803C452C324619D319F980D5B84DBB45FC0FE2BAA045".scan(/../).map{|n|n.to_i(16).chr}.join))'

In message <40E46DA4.2010105@email.byu.edu>,

···

`Jamis Buck <jgb3@email.byu.edu>' wrote:

I've attached a patch. With the addition of the DSA#do_verify method
that this patch exposes, Net::SSH can now successfully handle ssh-dss
server keys.

I think these methods can be written with existing library.
Could you try the attached code?
--
gotoyuzo

require "openssl"

class OpenSSL::PKey::DSA
  def do_sign(data)
    sig = sign(OpenSSL::Digest::DSS1.new, data)
    a1sig = OpenSSL::ASN1.decode(sig)
    sig_r = sprintf("%.40x", a1sig.value[0].value)
    sig_s = sprintf("%.40x", a1sig.value[1].value)
    if sig_r.length > 40 || sig_s.length > 40
      raise OpenSSL::PKey::DSAError, "bad sig size"
    end
    return [sig_r].pack("H*") + [sig_s].pack("H*")
  end

  def do_verify(sig, data)
    sig_r = sig[0,20].unpack("H*")[0].to_i(16)
    sig_s = sig[20,20].unpack("H*")[0].to_i(16)
    a1sig = OpenSSL::ASN1::Sequence([
      OpenSSL::ASN1::Integer(sig_r),
      OpenSSL::ASN1::Integer(sig_s)
    ])
    return verify(OpenSSL::Digest::DSS1.new, a1sig.to_der, data)
  end
end

dsa = OpenSSL::PKey::DSA.new(512)
data = File.read(__FILE__)
sig = dsa.do_sign(data)
p dsa.do_verify(sig, data)

GOTOU Yuuzou wrote:

In message <40E46DA4.2010105@email.byu.edu>,

I've attached a patch. With the addition of the DSA#do_verify method that this patch exposes, Net::SSH can now successfully handle ssh-dss server keys.

I think these methods can be written with existing library.
Could you try the attached code?

Thank-you! That works wonderfully. Now... could I bother you for an explanation of what the code does? Specifically, the verification code:

         sig_r = sig[0,20].unpack("H*")[0].to_i(16)
         sig_s = sig[20,20].unpack("H*")[0].to_i(16)
         a1sig = OpenSSL::ASN1::Sequence([
            OpenSSL::ASN1::Integer(sig_r),
            OpenSSL::ASN1::Integer(sig_s)
         ])
         return verify(OpenSSL::Digest::DSS1.new, a1sig.to_der, data)

I understand the first two lines, but what is an ASN1::Sequence, and what does converting it to a "der" (on the last line) accomplish?

Thanks again!

···

`Jamis Buck <jgb3@email.byu.edu>' wrote:

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

ruby -ropenssl -e'k="01234567";p((c,c.padding,c.iv,c.key=OpenSSL::Cipher::BF.new,0,k,k*2)[0].decrypt.update("1A81803C452C324619D319F980D5B84DBB45FC0FE2BAA045".scan(/../).map{|n|n.to_i(16).chr}.join))'