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

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