I am attaching a small utility which does all possible checks we can do.
On 05/10/2013 12:01 AM, Alex Rousskov wrote:
> On 05/09/2013 01:10 PM, Tsantilas Christos wrote:
>> On 05/09/2013 05:50 PM, Alex Rousskov wrote:
>> I can reporoduce the bug with the following simple program:
>>
>> int main(int argc, char *argv[])
>> {
>> SSLeay_add_ssl_algorithms();
>> SSL_CTX *sslContext = SSL_CTX_new(SSLv3_method());
>> SSL *ssl = SSL_new(sslContext);
>> X509 * cert = SSL_get_certificate(ssl);
>> return 0;
>> }
>>
>> This program crashes inside a function called by SSL_get_certificate.
>> I suppose we can check if the program exited normally or not, to decide
>> if the openSSL SDK is OK or have the bug.
>
> That sounds like a good idea to me. I would extend that test code to
> also include code to test that our workaround compiles. Here is a sketch:
>
> int main() {
> ...
> X509 *cert1 = workaroundCode(...);
> X509 *cert2 = directCode(...); // may crash!
> return cert1 == cert2 ? 0 : 1;
> }
>
> I assume that both cert1 and cert2 will be nil in your test case when
> everything works correctly, but that does not matter.
Well checking with null certificates maybe is not enough good to detect
problems. The SSL and SSL_CTX structures used here mostly uninitialized
so it is possible to get a wrong field which is just zeroed.
But maybe we can add in the check program a hard coded certificate. I am
using it in the check toll I am attaching.
Then to check if the workaround code works required the following:
const char *certTxt = "-----BEGIN CERTIFICATE----\n" .....;
SSLeay_add_ssl_algorithms();
BIO *certBio = BIO_new(BIO_s_mem());
BIO_puts(certBio, certTxt);
X509 * cert = NULL;
PEM_read_bio_X509(certBio, &cert, 0, 0));
SSL_CTX *sslContext = SSL_CTX_new(SSLv3_method());
SSL_CTX_use_certificate(sslContext, cert));
X509 ***pCert = (X509 ***)sslContext->cert;
X509 *sslCtxCert = pCert && *pCert ? **pCert : NULL;
return (sslCtxCert != cert ? 1 : 0);
>
> Then, we can use one of the following two strategies:
>
> Conservative (work around the bug if possible and clearly necessary):
> If the test compiles but crashes, enable workaround.
> Otherwise, disable workaround.
>
> Midway (work around the bug if necessary or if work around works):
> If the test compiles but crashes, enable workaround.
> If the test compiles and returns 0, enable workaround.
> Otherwise, disable workaround.
>
> Aggressive (work around the bug if possible):
> If the test compiles, enable workaround.
> Otherwise, disable workaround.
>
>
> I think we should use either the Midway or the Aggressive approach to
> accommodate more cases, but I am not sure. What do you think?
I think the best is the aggressive with some additions:
- Check if the workaround work, using a code similar to the above.
- If not work try to use SSL object and SSL_get_certificate function. If
this one crashes, disable SSL bumping (only here needed).
We can implement it using two scripts/checks as Amos suggest.
>
>
> If it is easy, we could also allow folks to define the corresponding
> decision macro manually, when building Squid, so that they can overwrite
> our automation when needed (e.g., when compiling Squid for use with a
> different OpenSSL version). I do not think we need to make that choice
> an explicit ./configure option though.
>
>
> Thank you,
>
> Alex.
>
>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
const char *certTxt = "-----BEGIN CERTIFICATE-----\n"\
"MIICMTCCAZoCCQD+KQjThaQoEDANBgkqhkiG9w0BAQUFADBdMQswCQYDVQQGEwJV\n"\
"UzETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwETm9uZTEOMAwGA1UECgwF\n"\
"U3F1aWQxCzAJBgNVBAsMAml0MQ0wCwYDVQQDDARub25lMB4XDTEzMDUxMDE0MjUz\n"\
"N1oXDTE0MDUxMDE0MjUzN1owXTELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUt\n"\
"U3RhdGUxDTALBgNVBAcMBE5vbmUxDjAMBgNVBAoMBVNxdWlkMQswCQYDVQQLDAJp\n"\
"dDENMAsGA1UEAwwEbm9uZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtSz4\n"\
"dQExZQ8mseCr9fwYD3OsIE7p0QvEb8QVQlrLeJ3nqalUb415cg+eyVn1ZAPU52si\n"\
"VebNlKRhIilZfyiwSEuxyyvfmcAVbAMjhwjAuPod8LtQneF9qbxRa4OjytQ1+v7h\n"\
"GFMmZECLvwF5+UUXgPPbFhcBd9gu32YdWs8ADJMCAwEAATANBgkqhkiG9w0BAQUF\n"\
"AAOBgQAqxsFSwhSJkolHtOev4jlk2JqpLcUHq6IpVbfpou7YM2Ca5sSKMf9/mjoY\n"\
"kRyhg6TX/1ymde1V1tA80DjIZYiF/m4YLwsSJVV2hE4lja/e8CvBLzeTSPe3S0rH\n"\
"cWcRnuH9ts0PRPUD0NxZejib4F8m7hI2emm5d56xizvYooZzzg==\n"\
"-----END CERTIFICATE-----";
int main(int argc, char *argv[])
{
// SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
BIO *certBio = BIO_new(BIO_s_mem());
BIO_puts(certBio, certTxt);
X509 * cert = NULL;
if (!PEM_read_bio_X509(certBio, &cert, 0, 0)) {
fprintf(stderr, "Error building certificate\n");
return -1;
}
SSL_CTX *sslContext = SSL_CTX_new(SSLv3_method());
if (!sslContext) {
fprintf(stderr, "Error creating ssl context\n");
return -1;
}
if (!SSL_CTX_use_certificate(sslContext, cert)) {
fprintf(stderr, "Error attaching certificate to ssl context\n");
return -1;
}
X509 ***pCert = (X509 ***)sslContext->cert;
X509 *sslCtxCert = pCert && *pCert ? **pCert : NULL;
if (sslCtxCert != cert) {
fprintf(stderr, "Geting certificate dicectly from SSL_CTX object failed!\n");
return 1;
}
SSL *ssl = SSL_new(sslContext);
if (!ssl) {
fprintf(stderr, "Error creating ssl object\n");
return -1;
}
X509 * sslCert = SSL_get_certificate(ssl);
if (sslCert != cert) {
fprintf(stderr, "SSL_get_certificate failed!\n");
return 1;
}
pCert = (X509 ***)ssl->cert;
sslCert = pCert && *pCert ? **pCert : NULL;
if (sslCert != cert) {
fprintf(stderr, "Geting certificate dicectly from ssl object failed!\n");
return 1;
}
return 0;
}