Take a look at the sources, hmac.h declares struct hmac_context:
struct hmac_context { char ctx[HMAC_MAX_CONTEXT_SIZE]; char ctxo[HMAC_MAX_CONTEXT_SIZE]; const struct hash_method *hash; };
If compiled for a 32 bit virtual address space, this has an alignment requirement of 4 due to the hash pointer.
In line 171 of auth-token.c, we have following declaration of ctx as a local variable in auth_token_get():
struct hmac_context ctx;
This is put on an address with an alignment requirement of 4. In lines 174 and 175 hmac_init is invoked with hash_method_sha1:
hmac_init(&ctx, (const unsigned char*)username, strlen(username), &hash_method_sha1);
In hmac.c, lines 43 and following, ctx->ctx with an alignment of 4 is passed to meth->init and meth->loop where meth refers to hash_method_sha1:
meth->init(ctx->ctx); meth->loop(ctx->ctx, k_ipad, 64);
These functions refer now to sha1_init and sha1_loop where the first parameter is expected to be a pointer to struct sha1_ctxt, a data structure which is declared in sha1.h:
struct sha1_ctxt { union { uint8_t b8[20]; uint32_t b32[5]; } h; union { uint8_t b8[8]; uint64_t b64[1]; } c; union { uint8_t b8[64]; uint32_t b32[16]; } m; uint8_t count; };
Here we have with b64 one uint64_t which has on a SPARC platform an alignment requirement of 8. In consequence, struct sha1_ctxt has an alignment requirement of 8. With the invocations of meth->init and meth->loop above we pass a pointer to a data structure of alignment 4 to a function expecting a pointer to a data structure of alignment 8. Chances are that the alignment requirement is not met, causing a segmentation violation.
This must be solved by declaring struct hmac_context such that is not just big enough but respects also the highest alignment required for one of the hashing data structures.
There are several options to do this:
Beginning with C11, you are free to use an alignment specifier, i.e. add _Alignas ( uint64_t ) (see section 6.7.5 in ISO 9899-2011)
GCC supports alignment attributes, i.e. add __attribute__ ((aligned (8))) or whatever is required instead of 8, see http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
Do not use a local variable for it, allocate the data structure using malloc instead.
If you want to see a live crash, here is the relevant output of gdb that debugs ${prefix}/libexec/dovecot/auth.
Program received signal SIGSEGV, Segmentation fault.
sha1_loop (ctxt=0xffbff63c, input=0xffbff548, len=64) at sha1.c:224
224 sha1.c: No such file or directory.
(gdb) where
#0 sha1_loop (ctxt=0xffbff63c, input=0xffbff548, len=64) at sha1.c:224
#1 0xff2e218c in hmac_init (ctx=ctx@entry=0xffbff63c,
key=key@entry=0x6a698 "borchert", key_len=8,
meth=0x555d0
As you can see, ctxt is on a 4-byte boundary, not on an 8-byte boundary. The crash happens at sha1.c:224 where the 8-byte-alignment is indeed mandatory on a SPARC architecture:
ctxt->c.b64[0] += copysiz * 8;
The environment is Solaris 10 on SPARCv9. The sources have been compiled using gcc 4.8.0 for 32 bit.
Andreas.