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))'