一、先去GitHub上asn1c官网上下载asn1c编译器
GitHub官网地址:
https://github.com/vlm/asn1c
在releases里的最新版本v0.9.28只支持BER/XER/PER格式的asn1c数据
在官网主页上的master版本支持BER/OER/PER/XER格式的asn1c数据
二、下载完之后根据帮助文档安装
1.解压下载好的asn1c安装包
2.安装asn1c
INSTALL.md是安装的帮助文档
在安装之前先查看REQUIREMENTS.md文件以获取所有的依赖项列表,并进行相应的安装。
在linux系统下需要安装以下环境
- automake-1.15(最少要安装1.15版本)
- libtool
- bison=2.x(必须要安装2.x的版本,x为任意)
- flex
确认安装无误后,使用以下命令在linux系统下进行安装
test -f configure || autoreconf -iv
./configure
make
make check
make install
三、编写asn1c文件并且编译
1.根据V2X帮助文档编写asn1c文件
文件名以 .asn1c 结尾
例如 test.asn1c(下面以此为例子)
例子:
RectangleTest DEFINITIONS ::= BEGIN
Rectangle ::= SEQUENCE {
height INTEGER, -- Height of the rectangle
width INTEGER -- Width of the rectangle
}
END
2.编译asn1c文件
使用以下命令
asn1c test.asn1c
编译asn1c文件后会生成很多 .c .h 等文件
里面有你文件里自己定义的原始的结构体名字的文件,例如上面编写的asn1c文件里的结构体名字为Rectangle,在经过asn1c编译器编译后生成的所对应的文件为Rectangle.c、Rectangle.h。
里面还会生成一个例子文件converter-example.c 还有一个Makefile文件converter-example.mk
四、解码V2X证书
1.编写解码文件
文件可以直接命名为converter-example.c替换原本的例子文件
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <asn_application.h>
#include <sys/types.h>
#include <Certificate.h> // 假设该头文件包含了 Certificate_t 类型的定义
//Certificate_t
Certificate_t * simple_deserializer(const void *buffer, size_t buf_size)
{
asn_dec_rval_t rval;
Certificate_t *rect = 0; /* Note this 01! */
rval = oer_decode(0, &asn_DEF_Certificate, (void **)&rect, buffer, buf_size);
if(rval.code == RC_OK)
{
return rect; /* Decoding succeeded */
}
else
{
/* Free the partially decoded Certificate */
ASN_STRUCT_FREE(asn_DEF_Certificate, rect);
return 0;
}
}
int main()
{
//打开文件Certificate
FILE *file = fopen("Certificate.oer", "rb");
if(file == NULL)
{
printf("无法打开文件!\n");
return 1;
}
// 获取文件大小
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
fseek(file, 0, SEEK_SET);
// 分配缓冲区
uint8_t *buffer = (uint8_t *)malloc(file_size);
if (buffer == NULL)
{
printf("内存分配失败!\n");
fclose(file);
return 1;
}
// 从文件中读取数据
size_t bytes_read = fread(buffer, 1, file_size, file);
fclose(file);
if (bytes_read != file_size)
{
printf("从文件中读取数据失败!\n");
free(buffer);
return 1;
}
// 调用解码函数进行解码
Certificate_t *decoded_rect = simple_deserializer(buffer, file_size);
if (decoded_rect != NULL)
{
printf("解码成功!\n");
printf("version = %ld\n",decoded_rect->version);
printf("CertificateType = %ld\n",decoded_rect->type);
printf("issuer_sm3AndDigest_size = %lu\n",decoded_rect->issuer.choice.sm3AndDigest.size);
printf("issuer_sm3AndDigest_buf = ");
for(int i=0; i<decoded_rect->issuer.choice.sm3AndDigest.size; i++)
{
printf("%02x ",decoded_rect->issuer.choice.sm3AndDigest.buf[i]);
}
printf("\n");
printf("iCert = %ld\n",decoded_rect->toBeSigned.id.choice.linkageData.iCert);
printf("linkage_value_size = %lu\n",decoded_rect->toBeSigned.id.choice.linkageData.linkage_value.size);
printf("linkage_value_buf = ");
for(int i=0; i<decoded_rect->toBeSigned.id.choice.linkageData.linkage_value.size; i++)
{
printf("%02x ",decoded_rect->toBeSigned.id.choice.linkageData.linkage_value.buf[i]);
}
printf("\n");
printf("cracaId_size = %lu\n",decoded_rect->toBeSigned.cracaId.size);
printf("cracaId_buf = ");
for(int i=0; i<decoded_rect->toBeSigned.cracaId.size; i++)
{
printf("%02x ",decoded_rect->toBeSigned.cracaId.buf[i]);
}
printf("\n");
printf("crlSeries = %ld\n",decoded_rect->toBeSigned.crlSeries);
printf("validityPeriod_start = %lu\n",decoded_rect->toBeSigned.validityPeriod.start);
printf("hours = %ld\n",decoded_rect->toBeSigned.validityPeriod.duration.choice.hours);
printf("compressed_y_0_size = %lu\n",decoded_rect->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecsigSm2.choice.compressed_y_0.size);
printf("compressed_y_0_buf = ");
for(int i=0; i<decoded_rect->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecsigSm2.choice.compressed_y_0.size; i++)
{
printf("%02x ",decoded_rect->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecsigSm2.choice.compressed_y_0.buf[i]);
}
printf("\n");
printf("rSig_size = %lu\n",decoded_rect->signature->choice.sm2Signature.rSig.size);
printf("rSig_buf = ");
for(int i=0; i<decoded_rect->signature->choice.sm2Signature.rSig.size; i++)
{
printf("%02x ",decoded_rect->signature->choice.sm2Signature.rSig.buf[i]);
}
printf("\n");
printf("sSig_size = %lu\n",decoded_rect->signature->choice.sm2Signature.sSig.size);
printf("sSig_buf = ");
for(int i=0; i<decoded_rect->signature->choice.sm2Signature.sSig.size; i++)
{
printf("%02x ",decoded_rect->signature->choice.sm2Signature.sSig.buf[i]);
}
printf("\n");
// 使用完后记得释放内存
ASN_STRUCT_FREE(asn_DEF_Certificate, decoded_rect);
}
else
{
printf("解码失败!\n");
}
// 释放缓冲区
free(buffer);
return 0;
}
编译命令为
make -f converter-example.mk
如果更改的话需要清除之后重新编译
清除命令
make -f converter-example.mk clean
执行命令
./converter-example
也可以不使用编译器生成的例子自己编译。
gcc -o converter-example -I. file1.c file2.c asn_module_file.c -lm -L. -lasncodec
这个编译命令假设你的源文件为file1.c、file2.c和asn_module_file.c,并且需要链接数学库(libm)和ASN.1编解码库(libasncodec)。
解释一下各个选项的含义:
-o converter-example:指定输出的可执行文件名为converter-example。
-I.:指定头文件搜索路径,这里.表示当前目录。
file1.c file2.c asn_module_file.c:将你的源文件列在命令中。
-lm:链接数学库(libm)。
-L.:指定库文件搜索路径,这里.表示当前目录。
-lasncodec:链接ASN.1编解码库(libasncodec)。
请注意,你需要根据实际的源文件和库文件名称进行相应的调整,并确保编译过程中所需的头文件和库文件正确设置。