代码之家  ›  专栏  ›  技术社区  ›  Pawel Veselov Samarpan Patel

用OpenSSL 1.1 API解析“其他”ASN.1类型

  •  1
  • Pawel Veselov Samarpan Patel  · 技术社区  · 6 年前

    我试图理解如何用应用程序特定的内容解析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 is有一个-3类型,它是 V_ASN1_OTHER ,这对于我的架构是正确的。但我正在用asn.1api来研究如何钻取ia5strings的内容。我相信里面有 el->value.asn1_value ,但我不应该直接访问它(类型对我来说是不透明的),我只考虑 https://www.openssl.org/docs/man1.1.0/crypto/ . 还有什么文件可以解释怎么做吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Reinier Torenbeek    6 年前

    当谈到ASN.1功能时,OpenSSL文档是相当有限的。了解它的最好方法是检查关联的头文件 asn1.h asn1t.h ,这是公开的。它们定义了一组宏,允许您创建自己的ASN.1类型。同样,查看源代码是理解如何使用它们的最好方法,例如 ts_asn1.c . 基本解释见 ASN1_ITEM() . 玩得高兴!

    幸运的是,你的例子 Rocket 类型很简单。它的asn.1类型定义和helper函数可以创建如下:

    /* 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结构和顺序序列化数据之间进行来回转换。关于 d2i i2d 函数可以在openssl文档页面中找到 d2i_X509 . 您的应用程序代码可能类似于以下内容:

    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"