使用 OpenSSL 對 Octet String 類型數據進行 ASN.1 編碼和解碼

        在 ASN.1 編碼規則中,對於 Octet String 類型數據編碼的方式是比較簡單的,編碼結果由三部分級聯組成,如下圖:


        其中標誌位取值爲0x4,負載部分的值就是原始的 Octet String 數據。
        調用 OpenSSL 對 Octet String 類型數據進行 ASN.1 編碼和解碼,應使用 i2d_ASN1_OCTET_STRING( ) 及 d2i_ASN1_OCTET_STRING( ) 函數。函數 i2d_ASN1_OCTET_STRING( ) 的第一個輸入參數的類型是指向指針的指針,即指針的地址,在函數內部的執行過程中,如果傳入的第二個參數不是空指針,此時將執行實際的 ASN.1 編碼操作,會修改輸入的第一個指針參數的指向,即讓輸入的指針指向另一個地址,因此通常要使用一個臨時變量指針,將這個臨時指針的地址作爲第一個輸入參數輸入值,這一點是需要特別注意的。對於 d2i_ASN1_OCTET_STRING( ) 函數,它的第二個參數是一個指針的地址,也會在執行解碼時修改這個指針的指向,因此也要將一個臨時指針的地址傳入。具體的編碼和解碼過程可以看下面的示例程序:

/**************************************************
* File name: octet_string_enc_and_dec.c
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: Oct. 30th, 2019
* Description: demonstrate how to implement ASN.1 
    encode and decode on octet string data with 
	OpenSSL
**************************************************/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/asn1t.h>
 
int main()
{
	unsigned char sample_string[] = {0xE5, 0x02, 0x7C, 0xEF, 0xFF, 0x6d, 0x1A, 0xF9};
	ASN1_OCTET_STRING my_asn1_octet_string, *test_asn1_octet_string;
	int encode_len, ret;
	unsigned char *p1, *p2;
	int sample_string_len, i;
 
	ASN1_OCTET_STRING *decode_result_pointer;
	unsigned char *decode_result;
	unsigned char *p3;
 
        sample_string_len = (int)sizeof(sample_string);
	printf("Sample octect string:\n");
	for (i = 0; i < sample_string_len; i++)
	{
		printf("0x%x  ", sample_string[i]);
	}
	printf("\n");
	test_asn1_octet_string = &(my_asn1_octet_string);
	test_asn1_octet_string->length = sample_string_len;
	test_asn1_octet_string->data = sample_string;
 
	encode_len = i2d_ASN1_OCTET_STRING(test_asn1_octet_string, NULL);
	if ( encode_len < 0)
	{
		printf("Compute ASN.1 encode length failed!\n");
		return (-1);
	}
	printf("ASN.1 encode length is %d bytes.\n", encode_len);
	if ( !(p1 = (unsigned char *)malloc(encode_len)) )
	{
		printf("Memory allocation failed!\n");
		return (-1);
	}
	p2 = p1;
 
        printf("Before ASN.1 encoding the pointer p2 points to the address: 0x%x\n", p2);
	ret = i2d_ASN1_OCTET_STRING(test_asn1_octet_string, &p2);
	if (ret < 0)
	{
		printf("ASN.1 encode failed!\n");
		free(p1);
		return (-1);
	}
	printf("After ASN.1 encoding the pointer p2 points to the address: 0x%x\n", p2);
 
        printf("ASN.1 encode:\n");
	for (i = 0; i < encode_len; i++)
	{
		printf("0x%x  ", p1[i]);
	}
	printf("\n\n");
 
	p3 = p1;
	decode_result_pointer = NULL;
	printf("Before ASN.1 decoding the pointer p3 points to the address: 0x%x\n", p3);
	if ( !(d2i_ASN1_OCTET_STRING(&decode_result_pointer, &p3, encode_len)) )
	{
		printf("ASN.1 decode failed!\n");
		free(p1);
		return (-1);
	}
	printf("After ASN.1 decoding the pointer p3 points to the address: 0x%x\n", p3);
	printf("Decoding result:\n");
	printf("  length: 0x%x\n",decode_result_pointer->length);
	printf("  type: 0x%x\n",decode_result_pointer->type);
	printf("  flags: 0x%x\n",decode_result_pointer->flags);
 
	if ( !(decode_result = (unsigned char *)malloc(decode_result_pointer->length)) ) 
	{
		printf("Memory allocation failed!\n");
		ASN1_OCTET_STRING_free(decode_result_pointer);
		free(p1);
		return (-1);
	}
 
	if (decode_result_pointer->length != sample_string_len)
	{
		printf("Decode result length is wrong!\n");
		free(decode_result);
		ASN1_OCTET_STRING_free(decode_result_pointer);
		free(p1);
		return (-1);
	}
 
        memcpy(decode_result, decode_result_pointer->data,decode_result_pointer->length);
	printf("Decoded octet string:\n");
	for (i = 0; i < decode_result_pointer->length; i++)
	{
		printf("0x%x  ", decode_result[i]);
	}
	printf("\n");
	free(decode_result);
	ASN1_OCTET_STRING_free(decode_result_pointer);
	free(p1);
	return 0;
}

        這個示例程序在編譯和鏈接時,不管使用 OpenSSL 1.0.2d還是使用 OpenSSL 1.1.1,都能夠通過,運行結果如下圖:

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