166 karma · joined December 2, 2013
First off, at some point I became the person that would dig into a PoC for Ruby/OpenSSL/X509 bugs for hours. I've become a monster.
Secondly, I think that this is entirely wrong.
Standard disclaimer: I'm not a professional cryptographer. I have had to beat my head against ruby and the OpenSSL x509 bindings, so I know enough to probably make some very wrong statements.
That being said, the PoC is full of glaring errors. The ctx and cipher objects are created but never used. the Extension Factory is created and then entirely ignored because it's only used for the #issuer_certificate method. In addition, x509v3 extensions aren't used in any way during this PoC, so it has no reason to be there. And that's just the beginning.
I went through and picked apart the code in small bits to remove obfuscation and unnecessary actions while preserving the displayed output. Here's the massively cleaned up version:
#!/usr/bin/env ruby
require 'openssl'
key = OpenSSL::PKey::RSA.new(2048)
puts "Spoof must be in PEM format and saved as ca.pem"
raw = File.read "ca.pem"
ca_cert = OpenSSL::X509::Certificate.new raw
puts "before we sign the cert: #{ca_cert.verify(key)}"
ca_cert.sign(key, OpenSSL::Digest::SHA1.new)
puts "after we sign the cert: #{ca_cert.verify(key)}"
puts "Hijacked Certificate with chainloaded key saved @ #{ca_cert.serial}.pem"
printf "Verifying Keys Intergity: "
puts ca_cert.verify(key)
This removes all the variable duplications, doesn't write files because they have absolutely no impact on the behavior, and still displays the same output as the given PoC.With a few final modifications it looks like this:
#!/usr/bin/env ruby
require 'openssl'
key = OpenSSL::PKey::RSA.new(2048)
ca_cert = OpenSSL::X509::Certificate.new(File.read("ca.pem"))
puts "before we sign the cert: #{ca_cert.verify(key)}"
ca_cert.sign(key, OpenSSL::Digest::SHA1.new)
puts "after we sign the cert: #{ca_cert.verify(key)}"
So what we've managed to demonstrate is that you can as a matter of fact sign SSL certificates with a private key.Once again I may have _entirely_ missed the point on this and deleted a subtle line that had a major effect on the code. However with the sheer number of lines that were purely cargo culted for SSL implementations, I really think that this isn't an issue. I have an entire history of how I started with the original PoC and how I converted it to the above examples at https://github.com/adrienthebo/cve-2014-2734 ; please check it out if you think I made a mistake in my work.
I wrote this blog post about a year and a half ago when Puppet 2.7.17 was freshly released, and I was doing operations at Puppet Labs and was trying to do some gnarly stuff with Puppet internals. I have a pretty bad memory, and blogging about things I read was the only way to keep everything in my head.
Since I wrote this post, a number of things have changed. For one we've prioritized clear documentation and we work hard to make sure that the code itself is clear and understandable. Since I've been the one whining about poor inline documentation, I've taken a swing at improving things myself (https://github.com/puppetlabs/puppet/commit/447d24403f461743...), because if I'm going to whine I better put up and make a change myself. In addition Nan Liu/Dan Bode released the Types and Providers book (http://goo.gl/DEJoAd) which does a great job of explaining that layer of Puppet; if you're interested in extending that layer of Puppet I would highly recommend it.
If anyone has questions I would be very happy to answer, and always if anyone is interested on developing on Puppet I and the rest of the platform team would be very happy to help out. We have #puppet-dev on irc.freenode.net; you can ping me directly (nick is finch) and the rest of the devs are also very helpful!