openssl: error: storage size of ‘ctx’ isn’t known

openssl: error: storage size of ‘ctx’ isn’t known

问题 Code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>

void hmac(const char *algorithm, const char *msg, size_t msgLen, const char *key, size_t keyLen) {
	if (algorithm == NULL || msg == NULL || key == NULL) {
		printf("%s %d %s: parameter error\n", __FILE__, __LINE__, __func__);
		exit(1);
	}

	const EVP_MD *md = EVP_get_digestbyname(algorithm);
	if (md == NULL) {
		printf("%s %d %s: unknown message digest: %s\n", __FILE__, __LINE__, __func__, algorithm);
		exit(1);
	}

	unsigned char md_value[EVP_MAX_MD_SIZE] = "";
	unsigned int md_len = 0;

	HMAC_CTX ctx;
	HMAC_CTX_init(&ctx);
	HMAC_Init_ex(&ctx, key, keyLen, md, NULL);
	HMAC_Update(&ctx, msg, msgLen);
	HMAC_Final(&ctx, md_value, &md_len);
	HMAC_CTX_cleanup(&ctx);

	static const char bin2chars[] = "0123456789abcdef";
	char *result = (char *)malloc(md_len*2+1);
	result[md_len*2] = 0;
	for (unsigned int i = 0; i < md_len; i++) {
		result[i*2] = bin2chars[md_value[i] >> 4];
		result[i*2+1] = bin2chars[md_value[i] & 0x0f];
	}
	printf("%s %d %s: %s\t\t%s\n", __FILE__, __LINE__, __func__, algorithm, result);
	free(result);
}

int main() {

	OpenSSL_add_all_digests();

	const char *msg = "0123456789ABCDEF";
	const char *key = "test1280";

	/* msg和key都是可读明文,不包含0x00,因此可以用strlen */
	/* 考虑到通用情况,不应该使用strlen,因为原数据可能包含0x00 */
	hmac("SHA1", msg, strlen(msg), key, strlen(key));
	hmac("SHA224", msg, strlen(msg), key, strlen(key));
	hmac("SHA256", msg, strlen(msg), key, strlen(key));
	hmac("SHA384", msg, strlen(msg), key, strlen(key));
	hmac("SHA512", msg, strlen(msg), key, strlen(key));
	hmac("MD5", msg, strlen(msg), key, strlen(key));

	/* Call this once before exit. */
	EVP_cleanup();

	return 0;
}

OpenSSL 1.0.1e-fips 11 Feb 2013:

[test1280@test1280 ~]$ openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013
[test1280@test1280 ~]$ gcc -o main main.c -lssl -lcrypto -std=c99
[test1280@test1280 ~]$ ./main
main.c 37 hmac: SHA1		e665c280cf27dacd1f1b6b053cb307f32ee32fd0
main.c 37 hmac: SHA224		e72c400c02606686be2a8f7b75dd30234944ba55d7ac60953e848609
main.c 37 hmac: SHA256		b75ddc670bb8c75296d3207bfa8549df81ba3ef33500593c9d644a03dbcc1e0d
main.c 37 hmac: SHA384		809f4653a5cc87ac82eaf3b95d7351406034198c13353b6c6cab8878c3ea2f1c607d5593b635e2d9718e95ba900f2939
main.c 37 hmac: SHA512		44f986af4ca102bfa133e7135994173e120399078e4fdbf2363c4ac975cc3ff67cbe235c7e3667a6120827118dc3ac8e54c949d7f6fdacc704cdf86b1c13a530
main.c 37 hmac: MD5		5539dccd74dffdb0c671cc88c930bc25

编译和运行正常。

OpenSSL 1.1.1c FIPS 28 May 2019:

[test1280@localhost ~]$ openssl version
OpenSSL 1.1.1c FIPS  28 May 2019
[test1280@localhost ~]$ gcc -o main main.c -lssl -lcrypto -std=c99
main.c: In function ‘hmac’:
main.c:23:11: error: storage size of ‘ctx’ isn’t known
  HMAC_CTX ctx;
           ^~~
main.c:24:2: warning: implicit declaration of function ‘HMAC_CTX_init’; did you mean ‘HMAC_CTX_new’? [-Wimplicit-function-declaration]
  HMAC_CTX_init(&ctx);
  ^~~~~~~~~~~~~
  HMAC_CTX_new
main.c:28:2: warning: implicit declaration of function ‘HMAC_CTX_cleanup’; did you mean ‘HMAC_CTX_get_md’? [-Wimplicit-function-declaration]
  HMAC_CTX_cleanup(&ctx);
  ^~~~~~~~~~~~~~~~
  HMAC_CTX_get_md

编译报错:error: storage size of ‘ctx’ isn’t known。

原因是已经在报错中指明:

‘HMAC_CTX_init’ 已经被废弃,应该使用‘HMAC_CTX_new’。

查看man手册:

man HMAC_CTX_new:

HMAC_CTX_init() was replaced with HMAC_CTX_reset() in OpenSSL 1.1.0.
HMAC_CTX_new(), HMAC_CTX_free() and HMAC_CTX_get_md() are new in OpenSSL 1.1.0.

You are using OpenSSL 1.1.0 which made this structure (and many others) opaque - which means you cannot stack allocate it.

Starting with OpenSSL 1.1, the EVP_MD_CTX type is an opaque type so you can’t create an instance of it.

查看openssl 1.1.0变更说明:

https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes

All structures in libssl public header files have been removed so that they are “opaque” to library users. You should use the provided accessor functions instead

Since some structures have become opaque you can’t directly access the member any more. You might need to create backward compatible macros or functions if you still want to support older versions of OpenSSL.

总的来说,就是openssl 1.1.0+版本变更,导致一些struct对应用层“不透明”了,即应用层不能直接声明一个struct到栈中,需要通过函数来间接创建struct指针,由指定的函数分配堆空间等资源给struct对象。

按照提示,用对应的函数来创建struct对象并返回指针,而不是在栈上创建struct即可。

解决 Code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>

void hmac(const char *algorithm, const char *msg, size_t msgLen, const char *key, size_t keyLen) {
	if (algorithm == NULL || msg == NULL || key == NULL) {
		printf("%s %d %s: parameter error\n", __FILE__, __LINE__, __func__);
		exit(1);
	}

	const EVP_MD *md = EVP_get_digestbyname(algorithm);
	if (md == NULL) {
		printf("%s %d %s: unknown message digest: %s\n", __FILE__, __LINE__, __func__, algorithm);
		exit(1);
	}

	unsigned char md_value[EVP_MAX_MD_SIZE] = "";
	unsigned int md_len = 0;

	HMAC_CTX *ctx;
	ctx = HMAC_CTX_new();
	HMAC_Init_ex(ctx, key, keyLen, md, NULL);
	HMAC_Update(ctx, msg, msgLen);
	HMAC_Final(ctx, md_value, &md_len);
	HMAC_CTX_free(ctx);

	static const char bin2chars[] = "0123456789abcdef";
	char *result = (char *)malloc(md_len*2+1);
	result[md_len*2] = 0;
	for (unsigned int i = 0; i < md_len; i++) {
		result[i*2] = bin2chars[md_value[i] >> 4];
		result[i*2+1] = bin2chars[md_value[i] & 0x0f];
	}
	printf("%s %d %s: %s\t\t%s\n", __FILE__, __LINE__, __func__, algorithm, result);
	free(result);
}

int main() {

	OpenSSL_add_all_digests();

	const char *msg = "0123456789ABCDEF";
	const char *key = "test1280";

	/* msg和key都是可读明文,不包含0x00,因此可以用strlen */
	/* 考虑到通用情况,不应该使用strlen,因为原数据可能包含0x00 */
	hmac("SHA1", msg, strlen(msg), key, strlen(key));
	hmac("SHA224", msg, strlen(msg), key, strlen(key));
	hmac("SHA256", msg, strlen(msg), key, strlen(key));
	hmac("SHA384", msg, strlen(msg), key, strlen(key));
	hmac("SHA512", msg, strlen(msg), key, strlen(key));
	hmac("MD5", msg, strlen(msg), key, strlen(key));

	/* Call this once before exit. */
	EVP_cleanup();

	return 0;
}

参考:
1.https://stackoverflow.com/questions/42662733/evp-md-ctx-error-storage-size-of-ctx-isn-t-known/42666983
2.https://stackoverflow.com/questions/55992010/openssl-error-storage-size-of-ctx-isn-t-known

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章