From: Theo Buehler Subject: md5(1): avoid undefined function pointer casts To: tech@openbsd.org Date: Wed, 16 Jul 2025 21:46:22 +0200 This is a bit of a stupid diff with lots of ugly boilerplate, but I don't see a better way. The problem is the second sentence of C99 6.3.2.3, 8: A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined. The notion of compatibility for the functions here boils down to compatible return type and compatible argument list, which in particular means the same number of arguments. See 6.7.5.3, 15 for the gory details. There's also a version understandable to a human being lacking the brain damage necessary for successfully deciphering the C99 standard's language: https://en.cppreference.com/w/c/language/type.html So calling 'void CKSUM_Final(CKSUM_CTX *);' through the final member of struct hash_function is clearly UB since the numbers of parameters don't match. If that was all, the fix would be trivial. But the same goes for void MD5Final(MD5_CTX *, char *); because MD5_CTX * and void * aren't compatible in this sense: by definition, two pointer types are compatible if they point to compatible types. Or, if you prefer: void * has looser alignment requirements than MD5_CTX *, so they aren't compatible. The below avoids this by adding wrappers that have the correct types and that then propagate their parameters in a defined way. As I said, it's stupid and ugly and the one upside apart from appeasing the language lawyers I can see is that we no longer have function pointer casts. PS: there is similar code in isakmpd/hash.c. Index: md5.c =================================================================== RCS file: /cvs/src/bin/md5/md5.c,v diff -u -p -r1.98 md5.c --- md5.c 31 Oct 2023 19:37:17 -0000 1.98 +++ md5.c 12 Jul 2025 09:10:17 -0000 @@ -63,6 +63,222 @@ union ANY_CTX { SHA2_CTX sha2; }; +static void +cksum_init(void *ctx) +{ + CKSUM_Init(ctx); +} + +static void +cksum_update(void *ctx, const unsigned char *data, size_t len) +{ + CKSUM_Update(ctx, data, len); +} + +static void +cksum_final(unsigned char *digest, void *ctx) +{ + CKSUM_Final(ctx); +} + +static char * +cksum_end(void *ctx, char *digest) +{ + return CKSUM_End(ctx, digest); +} + +static void +md5_init(void *ctx) +{ + MD5Init(ctx); +} + +static void +md5_update(void *ctx, const unsigned char *data, size_t len) +{ + MD5Update(ctx, data, len); +} + +static void +md5_final(unsigned char *digest, void *ctx) +{ + MD5Final(digest, ctx); +} + +static char * +md5_end(void *ctx, char *digest) +{ + return MD5End(ctx, digest); +} + +static void +rmd160_init(void *ctx) +{ + RMD160Init(ctx); +} + +static void +rmd160_update(void *ctx, const unsigned char *data, size_t len) +{ + RMD160Update(ctx, data, len); +} + +static void +rmd160_final(unsigned char *digest, void *ctx) +{ + RMD160Final(digest, ctx); +} + +static char * +rmd160_end(void *ctx, char *digest) +{ + return RMD160End(ctx, digest); +} + +static void +sha1_init(void *ctx) +{ + SHA1Init(ctx); +} + +static void +sha1_update(void *ctx, const unsigned char *data, size_t len) +{ + SHA1Update(ctx, data, len); +} + +static void +sha1_final(unsigned char *digest, void *ctx) +{ + SHA1Final(digest, ctx); +} + +static char * +sha1_end(void *ctx, char *digest) +{ + return SHA1End(ctx, digest); +} + +static void +sha224_init(void *ctx) +{ + SHA224Init(ctx); +} + +static void +sha224_update(void *ctx, const unsigned char *data, size_t len) +{ + SHA224Update(ctx, data, len); +} + +static void +sha224_final(unsigned char *digest, void *ctx) +{ + SHA224Final(digest, ctx); +} + +static char * +sha224_end(void *ctx, char *digest) +{ + return SHA224End(ctx, digest); +} + +static void +sha256_init(void *ctx) +{ + SHA256Init(ctx); +} + +static void +sha256_update(void *ctx, const unsigned char *data, size_t len) +{ + SHA256Update(ctx, data, len); +} + +static void +sha256_final(unsigned char *digest, void *ctx) +{ + SHA256Final(digest, ctx); +} + +static char * +sha256_end(void *ctx, char *digest) +{ + return SHA256End(ctx, digest); +} + +static void +sha384_init(void *ctx) +{ + SHA384Init(ctx); +} + +static void +sha384_update(void *ctx, const unsigned char *data, size_t len) +{ + SHA384Update(ctx, data, len); +} + +static void +sha384_final(unsigned char *digest, void *ctx) +{ + SHA384Final(digest, ctx); +} + +static char * +sha384_end(void *ctx, char *digest) +{ + return SHA384End(ctx, digest); +} + +static void +sha512_256_init(void *ctx) +{ + SHA512_256Init(ctx); +} + +static void +sha512_256_update(void *ctx, const unsigned char *data, size_t len) +{ + SHA512_256Update(ctx, data, len); +} + +static void +sha512_256_final(unsigned char *digest, void *ctx) +{ + SHA512_256Final(digest, ctx); +} + +static char * +sha512_256_end(void *ctx, char *digest) +{ + return SHA512_256End(ctx, digest); +} + +static void +sha512_init(void *ctx) +{ + SHA512Init(ctx); +} + +static void +sha512_update(void *ctx, const unsigned char *data, size_t len) +{ + SHA512Update(ctx, data, len); +} + +static void +sha512_final(unsigned char *digest, void *ctx) +{ + SHA512Final(digest, ctx); +} + +static char * +sha512_end(void *ctx, char *digest) +{ + return SHA512End(ctx, digest); +} + struct hash_function { const char *name; size_t digestlen; @@ -82,10 +298,10 @@ struct hash_function { STYLE_CKSUM, -1, NULL, - (void (*)(void *))CKSUM_Init, - (void (*)(void *, const unsigned char *, size_t))CKSUM_Update, - (void (*)(unsigned char *, void *))CKSUM_Final, - (char *(*)(void *, char *))CKSUM_End + cksum_init, + cksum_update, + cksum_final, + cksum_end, }, { "MD5", @@ -93,10 +309,10 @@ struct hash_function { STYLE_MD5, 0, NULL, - (void (*)(void *))MD5Init, - (void (*)(void *, const unsigned char *, size_t))MD5Update, - (void (*)(unsigned char *, void *))MD5Final, - (char *(*)(void *, char *))MD5End + md5_init, + md5_update, + md5_final, + md5_end, }, { "RMD160", @@ -104,10 +320,10 @@ struct hash_function { STYLE_MD5, 0, NULL, - (void (*)(void *))RMD160Init, - (void (*)(void *, const unsigned char *, size_t))RMD160Update, - (void (*)(unsigned char *, void *))RMD160Final, - (char *(*)(void *, char *))RMD160End + rmd160_init, + rmd160_update, + rmd160_final, + rmd160_end, }, { "SHA1", @@ -115,10 +331,10 @@ struct hash_function { STYLE_MD5, 0, NULL, - (void (*)(void *))SHA1Init, - (void (*)(void *, const unsigned char *, size_t))SHA1Update, - (void (*)(unsigned char *, void *))SHA1Final, - (char *(*)(void *, char *))SHA1End + sha1_init, + sha1_update, + sha1_final, + sha1_end, }, { "SHA224", @@ -126,10 +342,10 @@ struct hash_function { STYLE_MD5, 0, NULL, - (void (*)(void *))SHA224Init, - (void (*)(void *, const unsigned char *, size_t))SHA224Update, - (void (*)(unsigned char *, void *))SHA224Final, - (char *(*)(void *, char *))SHA224End + sha224_init, + sha224_update, + sha224_final, + sha224_end, }, #endif /* !defined(SHA2_ONLY) */ { @@ -138,10 +354,10 @@ struct hash_function { STYLE_MD5, 0, NULL, - (void (*)(void *))SHA256Init, - (void (*)(void *, const unsigned char *, size_t))SHA256Update, - (void (*)(unsigned char *, void *))SHA256Final, - (char *(*)(void *, char *))SHA256End + sha256_init, + sha256_update, + sha256_final, + sha256_end, }, #if !defined(SHA2_ONLY) { @@ -150,10 +366,10 @@ struct hash_function { STYLE_MD5, 0, NULL, - (void (*)(void *))SHA384Init, - (void (*)(void *, const unsigned char *, size_t))SHA384Update, - (void (*)(unsigned char *, void *))SHA384Final, - (char *(*)(void *, char *))SHA384End + sha384_init, + sha384_update, + sha384_final, + sha384_end, }, { "SHA512/256", @@ -161,10 +377,10 @@ struct hash_function { STYLE_MD5, 0, NULL, - (void (*)(void *))SHA512_256Init, - (void (*)(void *, const unsigned char *, size_t))SHA512_256Update, - (void (*)(unsigned char *, void *))SHA512_256Final, - (char *(*)(void *, char *))SHA512_256End + sha512_256_init, + sha512_256_update, + sha512_256_final, + sha512_256_end, }, #endif /* !defined(SHA2_ONLY) */ { @@ -173,10 +389,10 @@ struct hash_function { STYLE_MD5, 0, NULL, - (void (*)(void *))SHA512Init, - (void (*)(void *, const unsigned char *, size_t))SHA512Update, - (void (*)(unsigned char *, void *))SHA512Final, - (char *(*)(void *, char *))SHA512End + sha512_init, + sha512_update, + sha512_final, + sha512_end, }, { NULL,