使用ASN1C库解码V2X证书

一、先去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)。
请注意,你需要根据实际的源文件和库文件名称进行相应的调整,并确保编译过程中所需的头文件和库文件正确设置。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值