Hi, I'm using the ASN1_item_d2i method for getting extension info out of an 
x509 certificate. It _appears_ that it's changing the dereferenced address of 
the 'in' parameter, even though it's supposed to be const. This can cause 
memory corruption later, as it seems that "in" usually corresponds to a 
member of the X509_EXTENSION struct (which needs to be freed later along with 
the X509 struct), at least in all of the example code that I've seen.

For reference, here's the method structure:

ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, long 
len, const ASN1_ITEM *it);

I've attached an example program which demonstrates the problem (along with a 
demonstration of how to work around it). Here's the output that I get when I 
try both the default and the workaround:

[EMAIL PROTECTED]:~$ g++ test.cc -o test `pkg-config --cflags --libs libcrypto 
libssl`
[EMAIL PROTECTED]:~$ ./test test2.pem 
ext_value_data: 0x8056510
ext_value_data: 0x805654f
[EMAIL PROTECTED]:~$ g++ test.cc -o test `pkg-config --cflags --libs libcrypto 
libssl` -DUSE_ALTERNATE_CAST
[EMAIL PROTECTED]:~$ ./test test2.pem 
ext_value_data: 0x8056510
ext_value_data: 0x8056510

If you try to run the test program above through valgrind (when compiled 
without -DUSE_ALTERNATE_CAST), you get an error even if openssl is compiled 
with -DPURIFY.

Would appreciate any insight as to whether this is expected or not. If it is 
expected, I must say that it's very confusing for a method to override the 
dereferenced value of a const pointer.

Thanks!

Will
#include <assert.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/pkcs12.h>
#include <openssl/sha.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>

int main(int argc, char *argv[])
{
    SSL_library_init();
    SSL_load_error_strings();
    ERR_load_BIO_strings();
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    OpenSSL_add_all_ciphers();
    OpenSSL_add_all_digests();

    BIO *bio = BIO_new(BIO_s_file());
    if (BIO_read_filename(bio, argv[1]) <= 0)
    {
        printf("Can't read file.\n");
        exit(-1);
    }

    X509 *cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);

    BIO_free(bio);

    int index = X509_get_ext_by_NID(cert, NID_info_access, -1);
    assert(index >= 0);

    X509_EXTENSION *ext = X509_get_ext(cert, index);
    assert(ext);
    
    X509V3_EXT_METHOD *method = X509V3_EXT_get(ext);
    assert(method);
    
    void *ext_data = NULL;
    
    const unsigned char **ext_value_data;
    ext_value_data = (const_cast<const unsigned char **>
                      (&ext->value->data));
    const unsigned char *ext_value_data_1 = ext->value->data;

    assert(method->it);
    fprintf(stderr, "ext_value_data: %p\n", ext->value->data);
#if USE_ALTERNATE_CAST
    ext_data = ASN1_item_d2i(NULL, &ext_value_data_1, ext->value->length,
                             ASN1_ITEM_ptr(method->it));
#else
    ext_data = ASN1_item_d2i(NULL, ext_value_data, ext->value->length,
                             ASN1_ITEM_ptr(method->it));
#endif
    fprintf(stderr, "ext_value_data: %p\n", ext->value->data);

    ASN1_item_free((ASN1_VALUE *)ext_data, 
                   ASN1_ITEM_ptr(method->it));
    X509_free(cert);
    ERR_free_strings();
    EVP_cleanup();
}

Attachment: test2.pem
Description: application/x509-ca-cert

Attachment: pgpVBPwGodQkR.pgp
Description: PGP signature

Reply via email to