使用OpenSSL 1.1 API解析“ OTHER” ASN.1类型

时间:2018-09-05 13:03:05

标签: c openssl

我试图了解如何处理具有特定于应用程序内容的ASN.1类型的解析。给出一个相当简单的模式:

World-Schema DEFINITIONS AUTOMATIC TAGS ::= 
BEGIN
  Rocket ::= SEQUENCE       
  {                                                     
     name      IA5String,
     type      IA5String
  }                                                     
END

和数据:

value Rocket ::= {
  name "Falcon",
  type "Boo"
}

(我使用http://asn1-playground.oss.com/来生成序列化的DER数据)。

我可以使用d2i函数获得外部容器:

ASN1_SEQUENCE_ANY * container = d2i_ASN1_SEQUENCE_ANY(0, (const unsigned char**)&ptr, (long)len);
ASN1_TYPE * el = sk_ASN1_TYPE_value(container, 0);

el的类型为-3,即V_ASN1_OTHER,这对我的架构是正确的。但是,我想尽一切办法使用ASN.1 API钻研IA5Strings内容。我相信内容在el->value.asn1_value中,但是我不应该直接访问它(类型对我来说是不透明的),我只考虑https://www.openssl.org/docs/man1.1.0/crypto/中的函数。是否还有任何文档说明应如何做?

1 个答案:

答案 0 :(得分:1)

关于ASN.1功能,OpenSSL文档非常有限。了解它的最佳方法是检查相关的公共头文件asn1.hasn1t.h。它们定义了一组宏,这些宏使您可以创建自己的ASN.1类型。同样,查看源代码是了解如何使用它们的最佳方法,例如在ts_asn1.c中。 ASN1_ITEM()中提供了基本说明。玩得开心!

幸运的是,您的示例Rocket类型很简单。可以创建具有辅助功能的ASN.1类型定义:

/* Rocket.h */
#include <openssl/asn1.h>

typedef struct Rocket_st {
    ASN1_IA5STRING *name;
    ASN1_IA5STRING *type;
} ROCKET;

DECLARE_ASN1_FUNCTIONS(ROCKET)

该结构是手工编码的,DECLARE_ASN1_FUNCTIONS宏扩展为一组帮助函数,可以通过以下方式实现:

/* Rocket.c */
#include "Rocket.h"
#include <openssl/asn1t.h>

ASN1_SEQUENCE(ROCKET) = {
        ASN1_SIMPLE(ROCKET, name, ASN1_IA5STRING),
        ASN1_SIMPLE(ROCKET, type, ASN1_IA5STRING),
} ASN1_SEQUENCE_END(ROCKET)

IMPLEMENT_ASN1_FUNCTIONS(ROCKET)

编译后,符号表如下所示(我使用的是Mac):

$ objdump -t Rocket.o

Rocket.o:   file format Mach-O 64-bit x86-64

SYMBOL TABLE:
00000000000000d0 l       __DATA,__const _ROCKET_seq_tt
00000000000000a0 g     F __TEXT,__text  _ROCKET_free
0000000000000120 g       __DATA,__const _ROCKET_it
0000000000000080 g     F __TEXT,__text  _ROCKET_new
0000000000000000 g     F __TEXT,__text  _d2i_ROCKET
0000000000000040 g     F __TEXT,__text  _i2d_ROCKET
0000000000000000         *UND*  _ASN1_IA5STRING_it
0000000000000000         *UND*  _ASN1_item_d2i
0000000000000000         *UND*  _ASN1_item_free
0000000000000000         *UND*  _ASN1_item_i2d
0000000000000000         *UND*  _ASN1_item_new

未定义的符号由OpenSSL crypto库提供。您可以将名称中带有ROCKET的函数用于C结构化数据和DER序列化数据之间的来回转换。有关d2ii2d函数的更多信息,可以在称为d2i_X509的OpenSSL文档页面中找到。您的应用程序代码可能类似于以下内容:

ROCKET *rocket;
ROCKET *rocket2;
unsigned char *rocketString;
const unsigned char *ptr;
int len;

rocket = ROCKET_new();
rocket->name = ASN1_IA5STRING_new();
ASN1_STRING_set(rocket->name, "Falcon", -1);
rocket->type = ASN1_IA5STRING_new();
ASN1_STRING_set(rocket->type, "Boo", -1);

len = i2d_ROCKET(rocket, &rocketString);
printf("DER-encoded Rocket has length %d\n", len);

ptr = rocketString;
rocket2 = d2i_ROCKET(NULL, &ptr, len);
printf("rocket2 fields are:\n  name = \"%s\"\n  type = \"%s\"\n",
   ASN1_STRING_get0_data(rocket2->name),
   ASN1_STRING_get0_data(rocket2->type));

结果:

$ ./main
DER-encoded Rocket has length 15
rocket2 fields are:
  name = "Falcon"
  type = "Boo"