在 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,都能夠通過,運行結果如下圖: