EVP_CipherInit_ex because cipher->do_cipher is NULL

View: New views
8 Messages — Rating Filter:   Alert me  

EVP_CipherInit_ex because cipher->do_cipher is NULL

by Ambarish Mitra :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi all,

I am using the EVP API for encryption and decryption (Code snippet below).
The encrypion works fine, but the decryption fails in EVP_CipherInit_ex.
Both the codes are identical except that the said function uses 1 as the
last argument for encryption and 0 for decryption.

I am on Redhat Linux, OpenSSL 0.9.8h 28 May 2008, and g++ 3.3.2 compiler.
(C++ compiler)


The EVP_CipherInit_ex function returned 0 - indicating failure. Upon
investigation, I found out that the context cipher function pointer
"do_cipher" is NULL. I have no clue why this will be NULL. In encryption,
do_cipher is not NULL; only in decryption, this pointer is NULL.

Is there any way to resolve/fix this issue? Do I need to do anything else?

I could not find the definition of EVP_des_ede3_cbc() in the openssl
codebase.



        unsigned char initVector[8] =
{0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};    //The init vector will be
derived from this
        unsigned char iv[EVP_MAX_IV_LENGTH], key[EVP_MAX_KEY_LENGTH];

        EVP_CIPHER_CTX ctx;

        unsigned char keyInput[24] =
{0x3F,0x6F,0x6B,0x69,0x20,0x5E,0x5F,0x45,0x65,0x54,0x5D,0x56,0x63,0x68,0x6E,
0x6F,0x14,0x32,0x2C,0x41,0x3F,0xD3,0x9B,0xA3};

        memcpy(iv,initVector,sizeof(iv));


        EVP_CIPHER_CTX_init(&ctx);


        int r2 = EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, keyInput,
iv, 0);
        fprintf(stderr, "cipher initEX ret =%d\n",r2);

          if (ctx.cipher->do_cipher == NULL)
                fprintf(stderr, "do_cipher is NULL!!\n");  // This prints,
meaning do_cipher is NULL!!

//
//.. CipherUpdate/Final follow. Not shown here.
//


DISCLAIMER
==========
This e-mail may contain privileged and confidential information which is the property of Persistent Systems Ltd. It is intended only for the use of the individual or entity to which it is addressed. If you are not the intended recipient, you are not authorized to read, retain, copy, print, distribute or use this message. If you have received this communication in error, please notify the sender and delete all copies of this message. Persistent Systems Ltd. does not accept any liability for virus infected mails.
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@...
Automated List Manager                           majordomo@...

Re: EVP_CipherInit_ex because cipher->do_cipher is NULL

by Ger Hobbelt-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Aug 7, 2008 at 8:13 AM, Ambarish Mitra
<ambarish_mitra@...> wrote:
> The EVP_CipherInit_ex function returned 0 - indicating failure. Upon

What does OpenSSL report as error code/description? (E.g. when using
ERR_print_errors() - see the documentation for how to use)

Ger







--
Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web: http://www.hobbelt.com/
 http://www.hebbut.net/
mail: ger@...
mobile: +31-6-11 120 978
--------------------------------------------------
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@...
Automated List Manager                           majordomo@...

RE: EVP_CipherInit_ex because cipher->do_cipher is NULL

by Ambarish Mitra :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



-----Original Message-----
From: owner-openssl-users@...
[mailto:owner-openssl-users@...]On Behalf Of Ger Hobbelt
Sent: Friday, August 08, 2008 3:54 PM
To: openssl-users@...
Subject: Re: EVP_CipherInit_ex because cipher->do_cipher is NULL


On Thu, Aug 7, 2008 at 8:13 AM, Ambarish Mitra
<ambarish_mitra@...> wrote:
> The EVP_CipherInit_ex function returned 0 - indicating failure. Upon

What does OpenSSL report as error code/description? (E.g. when using
ERR_print_errors() - see the documentation for how to use)

Ger


Hi Ger,

I tried your suggestion:
  ...
  ...
  int r2 = EVP_CipherInit_ex(&ctx, cipher, NULL, key, iv, DECRYPT);
  ERR_print_errors_fp(stderr);
  ...
  ...

The output was:
933945:error:0607C084:lib(6):func(124):reason(132):evp_enc.c:523:
933945:error:0607B086:lib(6):func(123):reason(134):evp_enc.c:170:

[ambarish@ps2844]$ openssl errstr 0607C084
error:0607C084:digital envelope routines:EVP_CIPHER_CTX_ctrl:ctrl not
implemented

[ambarish@ps2844]$ openssl errstr 0607B086
error:0607B086:digital envelope routines:EVP_CipherInit:initialization error



It says "ctrl not implemented". This looks very strange to me because the
same function (EVP_CipherInit_ex) works okay in the encryption stage, this
fails only in the decryption stage. What is the meaning of "ctrl not
implemented"? And why would this be not implemented in decryption stage, but
be implemented in encryption stage?

Any pointers on how to resolve or fix this problem?


Thanks.



DISCLAIMER
==========
This e-mail may contain privileged and confidential information which is the property of Persistent Systems Ltd. It is intended only for the use of the individual or entity to which it is addressed. If you are not the intended recipient, you are not authorized to read, retain, copy, print, distribute or use this message. If you have received this communication in error, please notify the sender and delete all copies of this message. Persistent Systems Ltd. does not accept any liability for virus infected mails.
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@...
Automated List Manager                           majordomo@...

Re: EVP_CipherInit_ex because cipher->do_cipher is NULL

by Ger Hobbelt-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Response below:

On Tue, Aug 12, 2008 at 7:27 AM, Ambarish Mitra
<ambarish_mitra@...> wrote:

> The output was:
> 933945:error:0607C084:lib(6):func(124):reason(132):evp_enc.c:523:
> 933945:error:0607B086:lib(6):func(123):reason(134):evp_enc.c:170:
>
> [ambarish@ps2844]$ openssl errstr 0607C084
> error:0607C084:digital envelope routines:EVP_CIPHER_CTX_ctrl:ctrl not
> implemented
>
> [ambarish@ps2844]$ openssl errstr 0607B086
> error:0607B086:digital envelope routines:EVP_CipherInit:initialization error
>
>
>
> It says "ctrl not implemented". This looks very strange to me because the
> same function (EVP_CipherInit_ex) works okay in the encryption stage, this
> fails only in the decryption stage. What is the meaning of "ctrl not
> implemented"? And why would this be not implemented in decryption stage, but
> be implemented in encryption stage?
>
> Any pointers on how to resolve or fix this problem?

Well, this looks like I am barking up the wrong tree as well. Because
this is OpenSSL's way of saying "you don't have a 'ctrl' method' for
your cipher" which is exactly the thing that caused the crash (ctrl is
a NULL instead of a function pointer), but the /why/ must originate
from /before/ you even called EVP_CipherInit_ex() as you feed that one
a 'cipher', where, I /assume/, these conditions apply:

assert(cipher != NULL); /* expected and okay */
assert(cipher->ctrl == NULL); /* this will cause CipherInit_ex() to
fail and is definitely NOT what one would expect */

The second one is the fault and must be caused by code /preceeding/
EVP_CipherInit_ex(). Which, when I refer back to the original email of
yours, is the
  EVP_des_ede3_cbc()
call.

This is starting to get weird (or I am looking at it from a completely
/wrong/ angle here). Anyway, I'll just describe what I see in the code
and what you should expect and can test for.

(Note that I am looking at 0.9.9 latest CVS so things may be slightly
different for you; the process should be the same however...)
When you grep for EVP_des_ede3_cbc() in the OpenSSL code you will only
find the function prototype.
That is because the definition is part of a macro called
BLOCK_CIPHER_defs in e_des3.c.
That macro expands into a call to (among others) the
BLOCK_CIPHER_def_cbc() macro in evp_locl.h (and NOTICE the 'ctrl'
parameter being passed along: that's a reference to the des3_ctrl()
function)
This macro in turn expands to a macro called BLOCK_CIPHER_def1() which
generates a static const data object and a 'get' function, constructed
from the parts passed: that 'get' function (which returns the address
(pointer to) that static object) is your EVP_ ## des_ede3 ## _cbc()
--> EVP_des_ede3_cbc() function (notice how I wrote that first: that's
to show what the C preprocessor does: ## is a parameter concatenation
operator; I have found that few people know this, hence the explicit
mention here.
This also explains (in code) why your linker will find the function
EVP_des_ede3_cbc() but when you grep for it, you only get the
prototype: its name is constructed by an OPenSSL macro.

So far, nothing weird.

Now, considering your case, it means that cipher->ctrl == NULL (or
OPenSSL wouldn't have spit out that error you reported), which means
that /either/ des3_ctrl() suddenly and miraculously turned into a NULL
pointer OR that the data object pointed at by EVP_des_ede3_cbc() has
been corrupted in some way by previous actions.


Which leads me to the next thought:

is this the very first time you call EVP_des_ede3_cbc() directly or
indirectly in your code? (Because this has got the stink of 'data
corruption' if I am any judge.)


Hm, one way to find out if the des_ede3_cbc cipher definition object
gets corrupted somewhere /before/ you get to EVP_CipherInit_ex(), you
may need to debug the code using a debugger which can breakpoint on
data changes (i.e. break on change of byte/bytes at address X, where
address to monitor is &EVP_des_ede3_cbc()->cipher (note the & here).

The fun bit here is that it doesn't look like a missing case of is
does not look like a case of missing SSL_library_init() or
OpenSSL_add_all_ciphers() -- both common mistakes -- as
EVP_des_ede3_cbc() should work perfectly without either of those setup
calls.

So, assuming I am correct in guessing that
  assert(cipher->ctrl != NULL);
fails immediately before you call EVP_CipherInit_ex(..., cipher, ...),
you can either go the debugger route or do the same in code:

create a global variable like this:


typedef int dbg_ctrl_func_t(EVP_CIPHER_CTX *, int, int, void *);

/* global var */
dbg_ctrl_func_t *dbg_var = 0;


then somewhere at the start of your app, do this:

dbg_var = &(EVP_des_ede3_cbc()->ctrl);
assert(*dbg_var != NULL); /* *dbg_var == EVP...()->cipher */
assert(*dbg_var == EVP_des_ede3_cbc()->ctrl);

and plonk the next asserts in all spots where you think it might get touched:

assert(*dbg_var != NULL);
assert(*dbg_var == EVP_des_ede3_cbc()->ctrl);

as somewhere along those assert()s should barf a hairball (== report
an error and abort).


The above code is for when you don't have a debugger which can watch
for data changes at address &EVP_des_ede3_cbc()->ctrl




I hope I didn't loose you in there; if you have questions though, just ask.


Caveat: I am not 100% sure this is the right direction to take, but if
it isn't, I don't see where my analysis went pear shaped. Better
thoughts are always welcome.

--
Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web: http://www.hobbelt.com/
 http://www.hebbut.net/
mail: ger@...
mobile: +31-6-11 120 978
--------------------------------------------------
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@...
Automated List Manager                           majordomo@...

RE: EVP_CipherInit_ex because cipher->do_cipher is NULL

by Ambarish Mitra :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Ger,

Thanks for your detailed response. My counter-responses are inlined.


Response below:

On Tue, Aug 12, 2008 at 7:27 AM, Ambarish Mitra
<ambarish_mitra@...> wrote:

> The output was:
> 933945:error:0607C084:lib(6):func(124):reason(132):evp_enc.c:523:
> 933945:error:0607B086:lib(6):func(123):reason(134):evp_enc.c:170:
>
> [ambarish@ps2844]$ openssl errstr 0607C084
> error:0607C084:digital envelope routines:EVP_CIPHER_CTX_ctrl:ctrl not
> implemented
>
> [ambarish@ps2844]$ openssl errstr 0607B086
> error:0607B086:digital envelope routines:EVP_CipherInit:initialization
error
>
>
>
> It says "ctrl not implemented". This looks very strange to me because the
> same function (EVP_CipherInit_ex) works okay in the encryption stage, this
> fails only in the decryption stage. What is the meaning of "ctrl not
> implemented"? And why would this be not implemented in decryption stage,
but
> be implemented in encryption stage?
>
> Any pointers on how to resolve or fix this problem?

Well, this looks like I am barking up the wrong tree as well. Because
this is OpenSSL's way of saying "you don't have a 'ctrl' method' for
your cipher" which is exactly the thing that caused the crash (ctrl is
a NULL instead of a function pointer), but the /why/ must originate
from /before/ you even called EVP_CipherInit_ex() as you feed that one
a 'cipher', where, I /assume/, these conditions apply:

assert(cipher != NULL); /* expected and okay */
assert(cipher->ctrl == NULL); /* this will cause CipherInit_ex() to
fail and is definitely NOT what one would expect */


---------
AM: Yes, this is the problem. I see this assert holds (meaning cipher->ctrl
is NULL).
Whereas in the encryption part, it is correct.
---------



The second one is the fault and must be caused by code /preceeding/
EVP_CipherInit_ex(). Which, when I refer back to the original email of
yours, is the
  EVP_des_ede3_cbc()
call.


------------
AM: Either the corruption happens in this call, or in the preceeding
EVP_CIPHER_CTX_init call.
------------


This is starting to get weird (or I am looking at it from a completely
/wrong/ angle here). Anyway, I'll just describe what I see in the code
and what you should expect and can test for.

(Note that I am looking at 0.9.9 latest CVS so things may be slightly
different for you; the process should be the same however...)

---------
AM: I am on OpenSSL 0.9.8h 28 May 2008. So, reasonably recent.
---------

When you grep for EVP_des_ede3_cbc() in the OpenSSL code you will only
find the function prototype.
That is because the definition is part of a macro called
BLOCK_CIPHER_defs in e_des3.c.
That macro expands into a call to (among others) the
BLOCK_CIPHER_def_cbc() macro in evp_locl.h (and NOTICE the 'ctrl'
parameter being passed along: that's a reference to the des3_ctrl()
function)
This macro in turn expands to a macro called BLOCK_CIPHER_def1() which
generates a static const data object and a 'get' function, constructed
from the parts passed: that 'get' function (which returns the address
(pointer to) that static object) is your EVP_ ## des_ede3 ## _cbc()
--> EVP_des_ede3_cbc() function (notice how I wrote that first: that's
to show what the C preprocessor does: ## is a parameter concatenation
operator; I have found that few people know this, hence the explicit
mention here.
This also explains (in code) why your linker will find the function
EVP_des_ede3_cbc() but when you grep for it, you only get the
prototype: its name is constructed by an OPenSSL macro.

------
AM: This is now very clear. Thanks for explaining how the function is being
defined.
Initial doubts on this function is gone.
-------



So far, nothing weird.

Now, considering your case, it means that cipher->ctrl == NULL (or
OPenSSL wouldn't have spit out that error you reported), which means
that /either/ des3_ctrl() suddenly and miraculously turned into a NULL
pointer OR that the data object pointed at by EVP_des_ede3_cbc() has
been corrupted in some way by previous actions.


Which leads me to the next thought:

is this the very first time you call EVP_des_ede3_cbc() directly or
indirectly in your code? (Because this has got the stink of 'data
corruption' if I am any judge.)


Hm, one way to find out if the des_ede3_cbc cipher definition object
gets corrupted somewhere /before/ you get to EVP_CipherInit_ex(), you
may need to debug the code using a debugger which can breakpoint on
data changes (i.e. break on change of byte/bytes at address X, where
address to monitor is &EVP_des_ede3_cbc()->cipher (note the & here).

The fun bit here is that it doesn't look like a missing case of is
does not look like a case of missing SSL_library_init() or
OpenSSL_add_all_ciphers() -- both common mistakes -- as
EVP_des_ede3_cbc() should work perfectly without either of those setup
calls.

So, assuming I am correct in guessing that
  assert(cipher->ctrl != NULL);
fails immediately before you call EVP_CipherInit_ex(..., cipher, ...),
you can either go the debugger route or do the same in code:

create a global variable like this:


typedef int dbg_ctrl_func_t(EVP_CIPHER_CTX *, int, int, void *);

/* global var */
dbg_ctrl_func_t *dbg_var = 0;


then somewhere at the start of your app, do this:

dbg_var = &(EVP_des_ede3_cbc()->ctrl);

----------
AM: error: cannot convert `int (* const*)(EVP_CIPHER_CTX*, int, int,
   void*)' to `int (*)(EVP_CIPHER_CTX*, int, int, void*)' in assignment


dbg_var is a function pointer variable, so I do:dbg_var =
(EVP_des_ede3_cbc()->ctrl);
----------


assert(*dbg_var != NULL); /* *dbg_var == EVP...()->cipher */
assert(*dbg_var == EVP_des_ede3_cbc()->ctrl);

and plonk the next asserts in all spots where you think it might get
touched:

assert(*dbg_var != NULL);
assert(*dbg_var == EVP_des_ede3_cbc()->ctrl);

as somewhere along those assert()s should barf a hairball (== report
an error and abort).

------------------
AM: The assert fails right at the start of the function. If I remove that
and put it after the
EVP_CIPHER_CTX_init call, even then it fails. It means, that somehow this is
not taking. I will have
to investigate more.
------------------


The above code is for when you don't have a debugger which can watch
for data changes at address &EVP_des_ede3_cbc()->ctrl



I hope I didn't loose you in there; if you have questions though, just ask.


Caveat: I am not 100% sure this is the right direction to take, but if
it isn't, I don't see where my analysis went pear shaped. Better
thoughts are always welcome.

--
Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web: http://www.hobbelt.com/
 http://www.hebbut.net/
mail: ger@...
mobile: +31-6-11 120 978


DISCLAIMER
==========
This e-mail may contain privileged and confidential information which is the property of Persistent Systems Ltd. It is intended only for the use of the individual or entity to which it is addressed. If you are not the intended recipient, you are not authorized to read, retain, copy, print, distribute or use this message. If you have received this communication in error, please notify the sender and delete all copies of this message. Persistent Systems Ltd. does not accept any liability for virus infected mails.
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@...
Automated List Manager                           majordomo@...

Re: EVP_CipherInit_ex because cipher->do_cipher is NULL

by Ger Hobbelt-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Aug 14, 2008 at 3:30 PM, Ambarish Mitra
<ambarish_mitra@...> wrote:
> ------------
> AM: Either the corruption happens in this call, or in the preceeding
> EVP_CIPHER_CTX_init call.
> ------------

Since the assert() already fails before the init_ex call, it looks
like my guess is probably correct: the point in my last email is that
the 'cipher' struct must already be incorrect /some time before/ the
init_ex() call. In other words: the error is not in the init_ex() call
(thast's why I said I was barking up the wrong tree) but in the code
that precedes it. I do not know where the 'cipher' variable starts
it's life in your code, but right when it starts, I would put the
first
  assert(cipher->ctrl != NULL)
check. If THAT assert() fails (which I expect it will), it means the
OpenSSL internal (constant!) data pointed at by the EVP_des_ede3_cbc()
gets corrupted permanently even earlier. Which is why I said you might
want to (a) use a debugger which can break on data change -- so you
can detect which bit of code is changing the 'ctrl' pointer value --
or use the global var + assert() set as described lateron in my last
email.

I am fairly certain now that we are looking at some sort of memory
corruption issue - and the trouble is locating where that corruption
is caused. One thing I am willing to bet on by now: the corruption
will have taken place before you reach that last
EVP_CipherInit_ex(...,cipher,...) call and my guess is that it already
happened /before/ your last call to EVP_des_ede3_cbc() as well.


> ---------
> AM: I am on OpenSSL 0.9.8h 28 May 2008. So, reasonably recent.
> ---------

Good. Shouldn't be too different then when you look at the source code
of OpenSSL itself.

> ------
> AM: This is now very clear. Thanks for explaining how the function is being
> defined.
> Initial doubts on this function is gone.
> -------

Excellent. You have a type of bug which (IMO) requires the ability to
see what's going on under the hood as well; not because OpenSSL is at
fault (my guess it's something hidden in your application code, but we
need to check further to find out who and where exactly).



> typedef int dbg_ctrl_func_t(EVP_CIPHER_CTX *, int, int, void *);
[...]
> ----------
> AM: error: cannot convert `int (* const*)(EVP_CIPHER_CTX*, int, int,
>   void*)' to `int (*)(EVP_CIPHER_CTX*, int, int, void*)' in assignment

My mistake. Make sure the typedef matches the type for the 'ctrl'
member in the 'cipher' struct type exactly. I forgot one level of
indirection ('*'), hence the error.

What the global var should store is a pointer to the DATA space of
'EVP_des_ede3_cbc()->ctrl', i.e. the bytes which store the value in
'EVP_des_ede3_cbc()->ctrl'.
When that value changes, it means someone/something just assigned a
new value to 'EVP_des_ede3_cbc()->ctrl' and THAT is wrong (as
'EVP_des_ede3_cbc()->ctrl' is a constant value, which is set at
run-time start (pointer to function) before main() is called and
should NEVER be changed afterwards.

That's what all the
> assert(*dbg_var != NULL); /* *dbg_var == EVP...()->cipher */
> assert(*dbg_var == EVP_des_ede3_cbc()->ctrl);
should be able to find out: the error occurs before the first assert()
that reports a failure, so you see that using these assert()s is
really the hard way of finding the offending code where a
memory-breakpoint able debugger can do this much faster.

>From the fact that you use the assert()s in your code, I take it that
you do not have such a debugger?

--- side track -----------------------------
If you use gdb, see
http://sourceware.org/gdb/current/onlinedocs/gdb_6.html#SEC34
for info how to set such 'watchpoints'.

Just in case you use gdb, here's a bit of howto:

at the start of main(), make sure you get the proper address to watch,
which is '&EVP_des_ede3_cbc()->ctrl' (note the &; just as with the
global var and asserts).
Then add a watchpoint for that value like this: *(int *)0xabcd1234
where 0xabcd1234 is the value of the '&EVP_des_ede3_cbc()->ctrl'
expression right at the start of main().
*(int *)0xabcd1234 should not be a NULL value, by the way.

Read up on gdb at that URL if you use it and did not use it like this before.
It's faster than tracking down this bugger using a series of assert()s
as the assert()s can only 'narrow down the area' where the illegal
ctrl field overwrite occurs, so you will need an increasing number of
assert()s in your code to pinpoint the offending statement(s).
-----------------------------------

> ------------------
> AM: The assert fails right at the start of the function. If I remove that
> and put it after the
> EVP_CIPHER_CTX_init call, even then it fails. It means, that somehow this is
> not taking. I will have
> to investigate more.
> ------------------

You misunderstood. The assert()s should go in the code /preceding/ the
init_ex call as we must find who (re)set that ->ctrl member value to
NULL. EVP...init_ex() there is only the /receiver/ of the damage
already done /before/.


I hope you can use gdb or another debugger instead as that would speed
up tracking down the offending code bit quite a bit. If you can't,
copy those two assert() lines throughout the code, more is better,
because we are looking for a moment since start of main() when the
assert()s start to fail. When they fail, it means the bit of code that
was prior (before) that and after the previous assert() block is the
culprit. Add more assert()s in there to narrow down to a single line
of code.

As you see this is hard to do when you don't have a debugger around
which can watch memory breakpoints (I checked the manual and gdb calls
these 'watchpoints'; if you use another debugger, it may have this
feature as all modern hardware can do this, but the name to identify
it may be different, so checking your debugger's manual may help here
-- the 'assert()' approach is the very last ditch and very basic
approach if you don't have a debugger on the target system (which can
happen to you when you develop on smaller embedded hardware)).




Anyway: the important bit is: the bug is in the code /before/ the call
to that OpenSSL init_ex function. Now all we need to do is find where
the cipher static struct object gets corrupted.


--
Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web: http://www.hobbelt.com/
 http://www.hebbut.net/
mail: ger@...
mobile: +31-6-11 120 978
--------------------------------------------------
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@...
Automated List Manager                           majordomo@...

RE: [Resolved] EVP_CipherInit_ex because cipher->do_cipher is NULL

by Ambarish Mitra :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

(Top-posting since this mail is not a direct reply)

Hi Ger,

Thanks for leading me in the right direction. The problem is solved. It was
my silly mistake.

Actually, my main build was also linking with another library that in turn
was linking with openssl. This is a 3rd party library, and I did not know
that it indeed had openssl symbols.

Linking:
g++ -o output.bin appssl.o /dir/libssl.a
/dir/libcrypto.a -L/dir/lib -laccess

The above linking is correct. It statically links the ssl and crypto
library, and shared links with a library called libaccess. Now, this library
also has openssl symbols, which I checked by doing "nm". If I link both of
these in a shared library manner (-l), then there is symbols conflict, and
so it deos not work according to expectation. Now, with static linkage, it
works.

Thanks!



-----Original Message-----
From: owner-openssl-users@...
[mailto:owner-openssl-users@...]On Behalf Of Ger Hobbelt
Sent: Thursday, August 14, 2008 8:33 PM
To: openssl-users@...
Subject: Re: EVP_CipherInit_ex because cipher->do_cipher is NULL


On Thu, Aug 14, 2008 at 3:30 PM, Ambarish Mitra
<ambarish_mitra@...> wrote:
> ------------
> AM: Either the corruption happens in this call, or in the preceeding
> EVP_CIPHER_CTX_init call.
> ------------

Since the assert() already fails before the init_ex call, it looks
like my guess is probably correct: the point in my last email is that
the 'cipher' struct must already be incorrect /some time before/ the
init_ex() call. In other words: the error is not in the init_ex() call
(thast's why I said I was barking up the wrong tree) but in the code
that precedes it. I do not know where the 'cipher' variable starts
it's life in your code, but right when it starts, I would put the
first
  assert(cipher->ctrl != NULL)
check. If THAT assert() fails (which I expect it will), it means the
OpenSSL internal (constant!) data pointed at by the EVP_des_ede3_cbc()
gets corrupted permanently even earlier. Which is why I said you might
want to (a) use a debugger which can break on data change -- so you
can detect which bit of code is changing the 'ctrl' pointer value --
or use the global var + assert() set as described lateron in my last
email.

I am fairly certain now that we are looking at some sort of memory
corruption issue - and the trouble is locating where that corruption
is caused. One thing I am willing to bet on by now: the corruption
will have taken place before you reach that last
EVP_CipherInit_ex(...,cipher,...) call and my guess is that it already
happened /before/ your last call to EVP_des_ede3_cbc() as well.


> ---------
> AM: I am on OpenSSL 0.9.8h 28 May 2008. So, reasonably recent.
> ---------

Good. Shouldn't be too different then when you look at the source code
of OpenSSL itself.

> ------
> AM: This is now very clear. Thanks for explaining how the function is
being
> defined.
> Initial doubts on this function is gone.
> -------

Excellent. You have a type of bug which (IMO) requires the ability to
see what's going on under the hood as well; not because OpenSSL is at
fault (my guess it's something hidden in your application code, but we
need to check further to find out who and where exactly).



> typedef int dbg_ctrl_func_t(EVP_CIPHER_CTX *, int, int, void *);
[...]
> ----------
> AM: error: cannot convert `int (* const*)(EVP_CIPHER_CTX*, int, int,
>   void*)' to `int (*)(EVP_CIPHER_CTX*, int, int, void*)' in assignment

My mistake. Make sure the typedef matches the type for the 'ctrl'
member in the 'cipher' struct type exactly. I forgot one level of
indirection ('*'), hence the error.

What the global var should store is a pointer to the DATA space of
'EVP_des_ede3_cbc()->ctrl', i.e. the bytes which store the value in
'EVP_des_ede3_cbc()->ctrl'.
When that value changes, it means someone/something just assigned a
new value to 'EVP_des_ede3_cbc()->ctrl' and THAT is wrong (as
'EVP_des_ede3_cbc()->ctrl' is a constant value, which is set at
run-time start (pointer to function) before main() is called and
should NEVER be changed afterwards.

That's what all the
> assert(*dbg_var != NULL); /* *dbg_var == EVP...()->cipher */
> assert(*dbg_var == EVP_des_ede3_cbc()->ctrl);
should be able to find out: the error occurs before the first assert()
that reports a failure, so you see that using these assert()s is
really the hard way of finding the offending code where a
memory-breakpoint able debugger can do this much faster.

>From the fact that you use the assert()s in your code, I take it that
you do not have such a debugger?

--- side track -----------------------------
If you use gdb, see
http://sourceware.org/gdb/current/onlinedocs/gdb_6.html#SEC34
for info how to set such 'watchpoints'.

Just in case you use gdb, here's a bit of howto:

at the start of main(), make sure you get the proper address to watch,
which is '&EVP_des_ede3_cbc()->ctrl' (note the &; just as with the
global var and asserts).
Then add a watchpoint for that value like this: *(int *)0xabcd1234
where 0xabcd1234 is the value of the '&EVP_des_ede3_cbc()->ctrl'
expression right at the start of main().
*(int *)0xabcd1234 should not be a NULL value, by the way.

Read up on gdb at that URL if you use it and did not use it like this
before.
It's faster than tracking down this bugger using a series of assert()s
as the assert()s can only 'narrow down the area' where the illegal
ctrl field overwrite occurs, so you will need an increasing number of
assert()s in your code to pinpoint the offending statement(s).
-----------------------------------

> ------------------
> AM: The assert fails right at the start of the function. If I remove that
> and put it after the
> EVP_CIPHER_CTX_init call, even then it fails. It means, that somehow this
is
> not taking. I will have
> to investigate more.
> ------------------

You misunderstood. The assert()s should go in the code /preceding/ the
init_ex call as we must find who (re)set that ->ctrl member value to
NULL. EVP...init_ex() there is only the /receiver/ of the damage
already done /before/.


I hope you can use gdb or another debugger instead as that would speed
up tracking down the offending code bit quite a bit. If you can't,
copy those two assert() lines throughout the code, more is better,
because we are looking for a moment since start of main() when the
assert()s start to fail. When they fail, it means the bit of code that
was prior (before) that and after the previous assert() block is the
culprit. Add more assert()s in there to narrow down to a single line
of code.

As you see this is hard to do when you don't have a debugger around
which can watch memory breakpoints (I checked the manual and gdb calls
these 'watchpoints'; if you use another debugger, it may have this
feature as all modern hardware can do this, but the name to identify
it may be different, so checking your debugger's manual may help here
-- the 'assert()' approach is the very last ditch and very basic
approach if you don't have a debugger on the target system (which can
happen to you when you develop on smaller embedded hardware)).




Anyway: the important bit is: the bug is in the code /before/ the call
to that OpenSSL init_ex function. Now all we need to do is find where
the cipher static struct object gets corrupted.


--
Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web: http://www.hobbelt.com/
 http://www.hebbut.net/
mail: ger@...
mobile: +31-6-11 120 978
--------------------------------------------------
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@...
Automated List Manager                           majordomo@...


DISCLAIMER
==========
This e-mail may contain privileged and confidential information which is the property of Persistent Systems Ltd. It is intended only for the use of the individual or entity to which it is addressed. If you are not the intended recipient, you are not authorized to read, retain, copy, print, distribute or use this message. If you have received this communication in error, please notify the sender and delete all copies of this message. Persistent Systems Ltd. does not accept any liability for virus infected mails.
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@...
Automated List Manager                           majordomo@...

Re: [Resolved] EVP_CipherInit_ex because cipher->do_cipher is NULL

by Ger Hobbelt-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Good to hear it worked out okay. Had not anticipated the symbol
collision, so I am really glad you found is was due to that.

Take care and good luck,

Ger


On Mon, Aug 18, 2008 at 6:49 AM, Ambarish Mitra
<ambarish_mitra@...> wrote:

> (Top-posting since this mail is not a direct reply)
>
> Hi Ger,
>
> Thanks for leading me in the right direction. The problem is solved. It was
> my silly mistake.
>
> Actually, my main build was also linking with another library that in turn
> was linking with openssl. This is a 3rd party library, and I did not know
> that it indeed had openssl symbols.
>
> Linking:
> g++ -o output.bin appssl.o /dir/libssl.a
> /dir/libcrypto.a -L/dir/lib -laccess
>
> The above linking is correct. It statically links the ssl and crypto
> library, and shared links with a library called libaccess. Now, this library
> also has openssl symbols, which I checked by doing "nm". If I link both of
> these in a shared library manner (-l), then there is symbols conflict, and
> so it deos not work according to expectation. Now, with static linkage, it
> works.
>
> Thanks!


--
Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web: http://www.hobbelt.com/
 http://www.hebbut.net/
mail: ger@...
mobile: +31-6-11 120 978
--------------------------------------------------
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@...
Automated List Manager                           majordomo@...
LightInTheBox - Buy quality products at wholesale price!