xorl %eax, %eax

CVE-2009-0642: Ruby X.509 Certificate Check Bypass

leave a comment »

This vulnerability was reported by Kurt Roeckx on 29 January 2009 and it affects Ruby 1.8 and 1.9 releases. The bug is straightforward, here is the buggy code located in ext/openssl/ossl_ocsp.c.

static VALUE
ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
{
    VALUE certs, store, flags;
    OCSP_BASICRESP *bs;
    STACK_OF(X509) *x509s;
    X509_STORE *x509st;
    int flg, result;

    rb_scan_args(argc, argv, "21", &certs, &store, &flags);
    x509st = GetX509StorePtr(store);
    flg = NIL_P(flags) ? 0 : INT2NUM(flags);
    x509s = ossl_x509_ary2sk(certs);
    GetOCSPBasicRes(self, bs);
    result = OCSP_basic_verify(bs, x509s, x509st, flg);
    sk_X509_pop_free(x509s, X509_free);
    if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));

    return result ? Qtrue : Qfalse;
}

This function is responsible for verifying X.509 certificates. As you can see it initializes ‘x509st’ using GetX509StorePtr() and it verifies it using OCSP_basic_verify(). If this function returns 0, it will fall into the if statement and issue a warning through rb_warn() and at last, if ‘result’ is non-zero it will return Qtrue and if it’s zero it will return Qfalse. OCSP_basic_verify() is an OpenSSL routine which returns 1 on success and 0 or -1 on failure. However, the above routine checks only for 0 and non-zero values. Consequently, if OCSP_basic_verify() returns -1 it will bypass the check and return Qtrue since this is a non-zero value.
To fix this the following patch was applied:

X509_STORE *x509st;
– int flg, result;
+ int flg;
+ VALUE result;

rb_scan_args(argc, argv, “21”, &certs, &store, &flags);
x509st = GetX509StorePtr(store);
flg = NIL_P(flags) ? 0 : INT2NUM(flags);
x509s = ossl_x509_ary2sk(certs);
GetOCSPBasicRes(self, bs);
– result = OCSP_basic_verify(bs, x509s, x509st, flg);
+ result = OCSP_basic_verify(bs, x509s, x509st, flg) <= 0 ? Qfalse : Qtrue; sk_X509_pop_free(x509s, X509_free); - if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL)); + if(!RTEST(result)) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL)); - return result ? Qtrue : Qfalse; + return result; } [/sourcecode] They changed singed integers result and flg to type of VALUE and changed the vulnerable call to set 'result' to Qfalse if OCSP_basic_verify() returns a negative or zero value and Qtrue otherwise.

Written by xorl

July 20, 2009 at 19:35

Posted in bugs

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s