Posted by emboss on 9 May 2014
We were recently informed about a possible security vulnerability that has been published as CVE-2014-2734. However, based on our detailed analysis below, we do not consider Ruby to be vulnerable.
This vulnerability could possibly allow an attacker to forge arbitrary root certificates by modifying the certificate’s signature, effectively replacing the certificate’s original private key with one chosen by the attacker.
Proof of Concept
The following is our analysis of CVE-2014-2734, we were able to reduce the original PoC, which we believe captures the essence of the proof of concept:
require 'openssl' forge_key = OpenSSL::PKey::RSA.new(2048) raw_certificate = File.read("arbitrary.cer") cert = OpenSSL::X509::Certificate.new(raw_certificate) resigned_cert = cert.sign(spoof, OpenSSL::Digest::SHA1.new) resigned_cert.verify(key) #=> true
It may come as a surprise that
The original certificate may contain a
Subject Public Key Info
pointing to the original public key which is different from the public key of
forge_key. Clearly, the public / private key pair that was used to re-sign
the certificate no longer matches the original public key referenced in the
Subject Public Key Info. Why does
How keys are verified
X509Certificate#verify uses OpenSSL’s
function internally, which delegates to
These functions establish the validity of the signature given the public key
that was presented. However, they will not verify if the given key
actually matches any subject public key referenced in the certificate.
This means that returning
true is expected behavior for
in this scenario. Omitting this check has no significant impact on the overall
security of the X.509 trust model.
Section 126.96.36.199 of RFC 5280 explicitly states that by computing a certificate’s signature, the CA confirms the correctness of the information contained in the certificate. While this principle is violated in the above example code, it poses no threat to security. A certificate forged or modified in this way cannot be exploited unless someone is able to convince you to explicitly trust a certificate that violates this principle.
There are two cases to consider:
Re-signing a root certificate
As users, we trust root certificates unconditionally. Even if they do not contain valid information, the status of being a publicly acknowledged root certificate alone is what keeps them pristine. They are preconfigured values in the trust stores of our browsers or operating systems. Simply possessing them establishes their status as valid trust anchors. For example, OpenSSL itself does not check the signature of self-signed root certificates by default for the same reasons, cf. X509_V_FLAG_CHECK_SS_SIGNATURE documentation.
A re-signed root certificate becomes a de facto “self-signed” certificate (albeit with incorrect Subject Public Key Info). This is not any more dangerous than a normal self-signed root certificate. In fact, anyone can produce self-signed root certificates which may completely match that of a valid root certificate - except for the signature. Since we trust root certificates merely by possession, such an imposter certificate is meaningless without a client’s active consent to trust it.
Re-signing an intermediate or leaf certificate
Also, re-signing a non-root certificate does not violate the security of the X.509 trust model. While we usually do not possess these kinds of certificates in advance, their forgery would be detected during the path validation procedure. Here, any non-root certificate’s signature is verified using the public key of the issuing certificate. At some point in the certificate chain, the forgery would be ultimately detected in the form of an invalid certificate signature value.
In conclusion, we believe that
X509Certificate#verify operates as expected.
Others have independently arrived at the
and we have therefore disputed CVE-2014-2734, and asked for its revocation.
You can find our complete analysis of the
original proof of concept