基于C语言的X.509数字证书解析

X.509 数字证书解析

X.509 证书结构描述

ASN.1 标准 (X.690)

ASN.1 标准是一种描述二进制数据结构的数据格式标准。X.509 数字证书标准采用了 ASN.1 标准来描述 X.509 证书格式。X.509 标准采用了 DER 格式来编码 ASN.1 格式的数据。此外,RSA 的公钥也使用了 DER 规范。

DER 格式的 ASN.1 标准除了 RFC 3641 进行了格式规范外,还可以在 微软 MSDN 找到更加易读的 ASN.1 规范和 DER 格式明确定义。

X.690 规定每个数据单元是一个 TLV 结构,TLV 结构包含三项:
在这里插入图片描述

  1. Identifier Octets:数据单元类型,包含

    1. tag class:数据类型的分类

在这里插入图片描述

  1. constructed:该数据单元是否由别的数据单元构成

  2. tag number:数据类型

    其中,若数据类型为 0x1F,则表示 Identifier Octets 不止一个字节

在这里插入图片描述

  1. Length Octets

    表示数据的长度,如果数据的长度超过 127,则长度域的第一个字节填充 128+长度域字节数 x,接下来的 x 字节共同表示的大整数为数据的长度(大整数为大端模式)

  2. Contents Octets:表示数据单元的数据内容

ASN.1 标准中,通用字符串编码规则(GSER)规定了一些数据格式,每种数据格式的 DER 编码如下:

  1. BOOLEAN

    Tag=0x01,表示布尔数据,长度总是为 1,值为 0xFF 时表示真、0x00 时表示假
    在这里插入图片描述

  2. INTEGER

    Tag=0x02,表示整数(或大整数)数据,长度不限。

  3. BIT_STRING

    Tag=0x03,表示位数据,位数可以不为 8 的位数,由于数据必须以字节为单位,BIT_STRING 的内容中第一个字节表示内容最后一个字节的低位(Least Significant Bit)填充了多少位。因此BIT_STRING 的实际内容字节数总是比 TLV 标记的长度少 1 个字节

    如下图,数据 0A3B5F291CD 表示结果如下,由于数据缺 4 位满 8 位,因此在最开始放 04 表示最后填充 4 位 0 对齐字节,因此最后存储的结果为 040A3B5F291CD0

在这里插入图片描述

  1. OCTET_STRING

    Tag=0x04,表示字节数组

  2. NULL

    Tag=0x05,表示空,对于 ASN.1 中的 OPTIONAL 数据,该项若不存在时用 NULL 填充

在这里插入图片描述

  1. OBJECT_IDENTIFIER

    Tag=0x06,表示对象标识符,通过特定方法存储数据,可通过 OID 表查询对象标识符含义

  2. UTF8_STRING

    Tag=0x0C,表示 UTF-8 格式的字符串

  3. SEQUENCE

    Tag=0x10,表示序列,必为 constructed,包含多个子结构,用于描述一个结构体。对于 SEQUENCE OF,这个序列表示结构体的数组。

在这里插入图片描述

  1. SET

    Tag=0x11,表示集合,必为 constructed,和 SEQUENCE 的区别在于,SET 内的数据类型应该一致。

  2. PRINTABLE_STRING

    Tag=0x13,表示 ASCII 字符串,实际上是字节数组。

  3. UTC_TIME

    Tag=0x17,表示格林威治时间,格式为:

    YYMMDDhhmm(Z|+hhmm|-hhmm)
    

    其中:

    1. YY:年份后两位,如 99 表示 1999,03 表示 2003,一般情况下将 70~99 记为 1970~1999;00~69 记为 2000~2069
    2. MM:月份
    3. DD:日期
    4. hh:小时
    5. mm:分钟
    6. ss:秒
    7. Z:表示格林威治时间
    8. +hhmm:表示离格林威治时间早多少小时多少分钟
    9. -hhmm:表示离格林威治时间晚多少小时多少分钟

    比如 180508000000Z 表示 2018-05-08 00:00:00 UTC

X.509 证书结构

  1. 证书(TBSCertificate)
    1. 版本号(Version):X.509 的版本号,v1(0)、v2(1)、v3(2)
    2. 序列号(SerialNumber):证书唯一识别符
    3. 签名算法(SignatureAlgorithm):证书的签名算法
    4. 颁发机构(Issuer):证书颁发机构的可识别名称
    5. 主体(Subject):证书申请机构的可识别名称
    6. 证书有效期(Validity):证书的有效期
      1. 开始时刻(Not Before)
      2. 结束时刻(Not After)
    7. 主体公钥信息(SubjectPublicKeyInfo)
      1. 公钥算法(algorithm)
      2. 公钥(subjectPublicKey)
    8. 颁发机构唯一身份信息:X.509 V2 起可选,用于标识颁发机构
    9. 主体唯一身份信息:X.509 V2 起可选,用于标识主体机构
    10. 扩展:X.509 V3 起可选,包含一些扩展信息
      1. 颁发者别名(issuerAltName)
      2. 主体别名(subjectAltName)
  2. 签名算法(SignatureAlgorithm):签名算法
  3. 签名值(SignatureValue):存放签名值

数据结构

语法树

我通过递归下降分析法来解析 ASN.1 标准的数据。ASN.1 解析完成后将产生和数据一致的解析树,解析树如下所示:
在这里插入图片描述

这个结构通过语法树来存储,语法树是一个多叉树,通过多叉转二叉的方式利用二叉树的数据结构来存储。

typedef struct tiny_ast_s
{
    uint8_t class;
    uint8_t constructed;
    int tag;
    tiny_lex_token_t token;
    int value_type;
    void (*free)(struct tiny_ast_s *);

    struct tiny_ast_s *child;
    struct tiny_ast_s *sibling;
} tiny_ast_t;

每个节点保存自己的第一个后代和兄弟节点(也就是典型的多叉树的二叉树表示法)。每个节点标记了保存数据的类型,通过区分类型来查找当前语法树节点是如何保存数据的。

比如保存二进制数据的语法树节点结构如下:

typedef struct tiny_data_ast_s
{
    int padding;
    int length;
    void *value;
    tiny_ast_t ast;
} tiny_data_ast_t;

其中包含了原始语法树节点结构体 ast。通过利用 to_struct 实现可以从 ast 恢复出 data_ast

#define to_struct(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))

语法分析器

通过构造一系列的文法原语来组装,以便构造一系列的产生式和对应的文法来描述 ASN.1 语法,从而实现建立 ASN.1 描述方法、源代码和 DER 数据格式的联系,源代码效果如下:

DEFINE(
    TBSCertificate,
    ASN_PARSER_MATCH_SEQUENCE(
        /* version */ GRAMMAR(Version),
        /* serialNumber */ GRAMMAR(CertificateSerialNumber),
        /* signature */ ACTION(tbs_signature_action, GRAMMAR(AlgorithmIdentifier), algorithm_identifier_action),
        /* issuer */ ACTION(issuer_action, GRAMMAR(Name), name_action),
        /* validity */ GRAMMAR(Validity),
        /* subject */ ACTION(subject_action, GRAMMAR(Name), name_action),
        /* subjectPublicKeyInfo */ GRAMMAR(SubjectPublicKeyInfo),
        /* issuerUniqueID */ OPTIONAL(
            ASN_PARSER_TLV(
                ASN_TAG_CLASS_CONTEXT,
                1, // [1]
                GRAMMAR(UniqueIdentifier))),
        /* subjectUniqueID */ OPTIONAL(
            ASN_PARSER_TLV(
                ASN_TAG_CLASS_CONTEXT,
                2, // [2]
                GRAMMAR(UniqueIdentifier))),
        /* extensions */ OPTIONAL(
            ASN_PARSER_TLV(
                ASN_TAG_CLASS_CONTEXT,
                3, // [3]
                GRAMMAR(Extensions)))));

以上的 C 源程序定义了如下的 ASN 描述的结构体:

TBSCertificate  ::=  SEQUENCE  {
     version         [0]  Version DEFAULT v1,
     serialNumber         CertificateSerialNumber,
     signature            AlgorithmIdentifier,
     issuer               Name,
     validity             Validity,
     subject              Name,
     subjectPublicKeyInfo SubjectPublicKeyInfo,
     issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
                          -- If present, version MUST be v2 or v3
     subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
                          -- If present, version MUST be v2 or v3
     extensions      [3]  Extensions OPTIONAL
                          -- If present, version MUST be v3 --  }

可见,语法分析器也采用了多叉树的方式进行组织。

字典树

DER 的 Object Identifier 类型存储的数据在解码后会得到类似 2.5.4.10 的数据,存在一个 Object Identifier 的对应关系表,将 Issuer 中的 2.5.4.10 翻译为 organizationName,也就是证书颁发机构的组织名。

这个对应关系是字符串到 OID 的关系,实现这个关系的数据结构是字典树(Trie),预先准备 OID 的表,或从文件中读入 OID 的对应关系,再加载进字典树中存储。由于这个 OID 表是静态的,因此这个字典树甚至可以并发读取。

链表

在读取数据的时候,为了支持流式读取,采用了链表来存储数据,从而方便语法分析器回退。

源代码

源代码参见压缩包目录,压缩包目录结构中,src 为源文件目录,include 为头文件目录,cert 为样例证书目录。

解析时间

ASN.1 的 UTCTimeGeneralizedName 均通过保存 ASCII 字符串的形式记录时间,因此我们先利用 OctetString 的解析器读取出字符串,再根据格式 YYMMDDhhmmss 解析:

static void parse_time(const char *time, bool shortYear, char *out)
{
    int year, month, day, hour, minute = 0, second = 0, microsecond = 0, d, zoneMonth = 0, zoneMinute = 0;
    if (shortYear)
    {
        year = parse_int(time, time + 2);
        if (year < 70) year += 2000;
        else year += 1900;
        time += 2;
    }
    else
    {
        year = parse_int(time, time + 4);
        time += 4;
    }
    month = parse_int(time, time + 2), time += 2;
    day = parse_int(time, time + 2), time += 2;
    hour = parse_int(time, time + 2), time += 2;
    if (*time) minute = parse_int(time, time + 2), time += 2;
    if (*time) second = parse_int(time, time + 2), time += 2;
    if (*time == '.' || *time == ',')
    {
        time++;
        int len;
        for (len = 0; len <= 3 && isdigit(*(time + len)); ++len);
        microsecond = parse_int(time, time + len), time += len;
    }
    if (*time == 'Z') d = 0, time++;
    else if (*time == '+') d = 1, time++;
    else if (*time == '-') d = -1, time++;

    if (*time && *(time + 1))
        zoneMonth = parse_int(time, time + 2), time += 2;
    if (*time && *(time + 1))
        zoneMinute = parse_int(time, time + 2), time += 2;

    out += sprintf(out, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
    if (microsecond) out += sprintf(out, ".%04d", microsecond);
    if (d == 0) out += sprintf(out, " UTC");
    else out += sprintf(out, " GMT%c%02d:%02d", d > 0 ? '+' : '-', zoneMonth, zoneMinute);
}

解析 OID

根据格式解析 OID 即可,接着根据解析出的字符串在字典树中查找对应的 OID 项即可

static tiny_parser_result_t parser_asn_oid(tiny_parser_ctx_t ctx, tiny_scanner_t *scanner)
{
    char str[128];
    int bits = 0, n = 0, c = 0;
    tiny_lex_token_t token;
    for (int i = 0; i < ctx.length; ++i)
    {
        token = tiny_scanner_next(scanner);
        if (token.error) return tiny_syntax_make_failure_result(token, 0, token.error);
        n = (n << 7) | (token.byte & 0x7F);
        bits += 7;
        if (!(token.byte & 0x80))
        {
            if (c == 0)
            {
                int m = n < 80 ? n < 40 ? 0 : 1 : 2;
                c += snprintf(str + c, 128 - c, "%d.%d", m, (n - m * 40));
            }
            else
            {
                c += snprintf(str + c, 128 - c, ".%d", n);
            }
            n = 0;
            bits = 0;
        }
    }

    void *oid = trie_search(OID_trie, str);
    if (oid)
    {
        tiny_make_data_ast(ast, ASN_TAG_OBJECT_IDENTIFIER, AST_VALUE_STRUCT);
        ast->value = oid;
        return tiny_syntax_make_success_result(&ast->ast);
    }
    else
    {
        return tiny_syntax_make_failure_result(token, 0, ASN_INVALID_OID);
    }
}

解析并输出 X.509 证书内容

我们通过在语义分析阶段,利用语义分析的 ACTION,在语法分析的同时进行语义分析。语法分析是在分析 ASN.1 的 DER 格式数据,那么语义分析就是解读 X.509 证书内容。我们通过在定义文法时插入 ACTION 即可实现边解析边输出证书内容:

static int indent = 0;

static void print_indent()
{
    for (int i = 0; i < indent; ++i)
        printf("  ");
}

static void version_action(tiny_ast_t *ast)
{
    print_indent();
    printf("Version: V%d\n", ast2int_ast(ast)->value + 1);
}

static void certificate_serial_number_action(tiny_ast_t *ast)
{
    print_indent();
    printf("Serial Number: ");
    tiny_data_ast_t *data_ast = ast2data_ast(ast);
    uint8_t *bytes = data_ast->value;
    for (int i = 0; i < data_ast->length; ++i)
    {
        if (i > 0) putchar(' ');
        printf("%02X", bytes[i]);
    }
    putchar('\n');
}

static void algorithm_identifier_action(tiny_ast_t *ast)
{
    tiny_data_ast_t *data_ast = ast2data_ast(ast->child);
    const char *(*oid)[3] = data_ast->value;
    printf("%s\n", (*oid)[1]);
}

static void signature_action()
{
    print_indent();
    printf("Certificate Algorithm: ");
}

static void tbs_signature_action()
{
    print_indent();
    printf("TBS Certificate Algorithm: ");
}

static void not_before_action(tiny_ast_t *ast)
{
    print_indent();
    tiny_data_ast_t *data_ast = ast2data_ast(ast);
    char *string = data_ast->value;
    printf("Not Before: %s\n", string);
}

static void not_after_action(tiny_ast_t *ast)
{
    print_indent();
    tiny_data_ast_t *data_ast = ast2data_ast(ast);
    char *string = data_ast->value;
    printf("Not After: %s\n", string);
}

static void issuer_action()
{
    print_indent();
    printf("Issuer: ");
}

static void subject_action()
{
    print_indent();
    printf("Subject: ");
}

static void subject_public_key_preaction()
{
    print_indent();
    printf("Subject Public Key:\n");
    indent++;
    print_indent();
    printf("Algorithm: ");
}

static void subject_public_key_postaction(tiny_ast_t *ast)
{
    indent--;
}

static void public_key_action()
{
    print_indent();
    printf("Public key: ");
}

static void bit_string_action(tiny_ast_t *ast)
{
    tiny_data_ast_t *data_ast = ast2data_ast(ast);
    uint8_t *bytes = data_ast->value;
    if (data_ast->padding == 0)
    {
        for (int i = 0; i < data_ast->length; ++i)
        {
            if (i > 0) putchar(' ');
            printf("%02X", bytes[i]);
        }
    }
    else
    {
        for (int i = 0; i < data_ast->length; ++i)
        {
            int skip = i + 1 == data_ast->length ? data_ast->padding : 0;
            for (int j = 7; j >= skip; --j)
                printf("%d", (bytes[i] >> j) & 1);
        }
    }
    putchar('\n');
}

static void name_action(tiny_ast_t *ast)
{
    putchar('\n');
    for (tiny_ast_t *rdn = ast->child; rdn; rdn = rdn->sibling)
    {
        for (tiny_ast_t *attr = rdn->child; attr; attr = attr->sibling)
        {
            tiny_data_ast_t *oid_ast = ast2data_ast(attr->child);
            tiny_data_ast_t *str_ast = ast2data_ast(attr->child->sibling);
            OID_entry_t *oid = oid_ast->value;
            const char *value = str_ast->value;
            print_indent();
            if (attr->child->sibling->value_type == AST_VALUE_STRING)
                printf("  %s=%s\n", (*oid)[1], value);
            else
                printf("  %s=?\n", (*oid)[1]);
        }
    }
}

static void reduce_indent()
{
    indent -= 2;
}

struct trie *prepare_parsers()
{
    struct trie *parsers = trie_create();

    DEFINE(
        Certificate,
        ASN_PARSER_MATCH_SEQUENCE(
            GRAMMAR(TBSCertificate),
            ACTION(signature_action, GRAMMAR(AlgorithmIdentifier), algorithm_identifier_action),
            ASN_PARSER_BIT_STRING));

    DEFINE(
        TBSCertificate,
        ASN_PARSER_MATCH_SEQUENCE(
            GRAMMAR(Version),
            GRAMMAR(CertificateSerialNumber),
            ACTION(tbs_signature_action, GRAMMAR(AlgorithmIdentifier), algorithm_identifier_action),
            ACTION(issuer_action, GRAMMAR(Name), name_action),
            GRAMMAR(Validity),
            ACTION(subject_action, GRAMMAR(Name), name_action),
            GRAMMAR(SubjectPublicKeyInfo),
            OPTIONAL( // issuerUniqueID
                ASN_PARSER_TLV(
                    ASN_TAG_CLASS_CONTEXT,
                    1,
                    GRAMMAR(UniqueIdentifier))),
            OPTIONAL( // subjectUniqueID
                ASN_PARSER_TLV(
                    ASN_TAG_CLASS_CONTEXT,
                    2,
                    GRAMMAR(UniqueIdentifier))),
            OPTIONAL(
                ASN_PARSER_TLV(
                    ASN_TAG_CLASS_CONTEXT,
                    3,
                    GRAMMAR(Extensions)))));

    DEFINE(
        Version,
        POST_ACTION(
            ASN_PARSER_TLV(
                ASN_TAG_CLASS_CONTEXT,
                0, // [0]
                ASN_PARSER_INTEGER),
            version_action));

    DEFINE(
        CertificateSerialNumber,
        POST_ACTION(
            ASN_PARSER_BIG_INTEGER,
            certificate_serial_number_action));

    DEFINE(
        AlgorithmIdentifier,
        ASN_PARSER_MATCH_SEQUENCE(
            ASN_PARSER_OBJECT_IDENTIFIER,           // algorithm
            OR(GRAMMAR(DssParams), ASN_PARSER_NULL) // parameters
        ));

    DEFINE(
        DssParams,
        ASN_PARSER_MATCH_SEQUENCE(
            ASN_PARSER_INTEGER, // r
            ASN_PARSER_INTEGER  // s
            ));

    DEFINE(
        Name,
        GRAMMAR(RDNSequence));

    DEFINE(
        RDNSequence,
        ASN_PARSER_SEQUENCE_OF(GRAMMAR(RelativeDistinguishedName)));

    DEFINE(
        RelativeDistinguishedName,
        ASN_PARSER_SET_OF(GRAMMAR(AttributeTypeAndValue)));

    DEFINE(
        AttributeTypeAndValue,
        ASN_PARSER_MATCH_SEQUENCE(
            GRAMMAR(AttributeType), // type
            GRAMMAR(AttributeValue) // value
            ));

    DEFINE(
        AttributeType,
        ASN_PARSER_OBJECT_IDENTIFIER);

    DEFINE(
        AttributeValue,
        ASN_PARSER_ANY);

    DEFINE(
        Validity,
        ASN_PARSER_MATCH_SEQUENCE(
            POST_ACTION(GRAMMAR(Time), not_before_action),
            POST_ACTION(GRAMMAR(Time), not_after_action)));

    DEFINE(
        Time,
        OR(
            ASN_PARSER_UTC_TIME,
            ASN_PARSER_GENERALIZED_TIME));

    DEFINE(
        UniqueIdentifier,
        ASN_PARSER_BIT_STRING);

    DEFINE(
        SubjectPublicKeyInfo,
        ACTION(
            subject_public_key_preaction,
            ASN_PARSER_MATCH_SEQUENCE(
                POST_ACTION(GRAMMAR(AlgorithmIdentifier), algorithm_identifier_action), // algorithm
                ACTION(                                                                 // subjectPublicKey
                    public_key_action,
                    ASN_PARSER_BIT_STRING,
                    bit_string_action)),
            subject_public_key_postaction));

    DEFINE(
        RSAPublicKey,
        ASN_PARSER_MATCH_SEQUENCE(
            ASN_PARSER_INTEGER, // modulus
            ASN_PARSER_INTEGER  // publicExponent
            ));
    
    DEFINE(
        Extensions,
        ASN_PARSER_SEQUENCE_OF(GRAMMAR(Extension))
    );
    
    DEFINE(
        Extension,
        ASN_PARSER_MATCH_SEQUENCE(
            ASN_PARSER_OBJECT_IDENTIFIER,
            OPTIONAL(ASN_PARSER_BOOLEAN),
            ASN_PARSER_OCTET_STRING
        )
    );

    return parsers;
}

运行输出

通过在 Linux 系统下运行 make 命令可产生可执行文件 bin/x509,通过执行 ./bin/x509 X509 cert/github.com.cer 可查看 GitHub X.509 证书内容如下:
在这里插入图片描述

shejizuopin
关注 关注
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
数字证书X.509格式详解
BiigPanda的博客
01-10 6450
X.509是一种非常通用的证书格式。所有的证书都符合ITU-T X.509国际标准,因此(理论上)为一种应用创建的证书可以用于任何其他符合X.509标准的应用。X.509证书的结构是用ASN1(Abstract Syntax Notation One)进行描述数据结构,并使用ASN.1语法进行编码。
c语言写成的取x.509证书公钥
05-10
纯属上级考验,自己下的asn代码查看器,网上找的标准, 和x509证书编码规则
C语言实现X509证书解析
02-22
1.C语言实现完整的X509证书解析方案; 2.解析证书的序列号、公钥;
X509证书解析C语言实现
06-17
1、完整的X509证书解析方案,C语言实现; 2、内含测试程序,在Linux环境下进入目录后make即可编译; 3、内含mbedtls开源库代码; 4、解析证书的序列号、公钥; 5、漂亮的解析ASN1(TLV数据格式)算法及完整解析X509证书逻辑 6、支持对der/pem格式的证书解析 7、内含base64编码/解码的C语言代码
加密、解密、签名、验签、数字证书、CA浅析
最新发布
Master Cui的博客
04-22 1191
加密、解密、签名、验签、数字证书、CA浅析
X.509数字证书的结构与解析
目前专注区块链相关技术的学习与分享
04-05 953
如果不是pkcs8格式的,那么"-----BEGIN PRIVATE KEY-----"和"-----END PRIVATE KEY-----"之间的内容就是私钥的Base64编码。签写证书的实体的 X.500 名称。对于私钥文件,真正的私钥是包含在字符串"-----BEGIN PRIVATE KEY-----"和字符串"-----END PRIVATE KEY-----"之间。从Certificate开始到“-----BEGIN CERTIFICATE-----”为止,中间的内容是证书的明文格式。
证书扩展中的oid
liudong200618的博客
05-09 907
为 X.509 v3 证书定义的扩展提供了将附加属性与用户或公钥相关联以及管理 CA 之间关系的方法。X.509 v3 证书格式还允许社区定义私有扩展以携带这些社区独有的信息。证书中的每个扩展都被指定为关键或非关键。如果使用证书的系统遇到它无法识别的关键扩展或包含它无法处理的信息的关键扩展,则它必须拒绝该证书。非关键扩展如果未被识别则可以被忽略,但如果被识别则必须被处理。以下部分介绍了在 Internet 证书和标准信息位置中使用的推荐扩展。社区可以选择使用额外的扩展;
数字证书中常用OID定义(转)
wjg220000的博客
05-19 1257
数字证书中常用OID定义
X509数字证书学习
mayue_web的博客
06-04 4198
X509证书概念、格式和应用
X509证书详解
weixin_43408952的博客
05-11 2万+
X509证书全面解读
C#实现RSA公钥加密私钥解密、私钥加密公钥解密以及Pcks12、X509证书加解密、签名验签
sky 胡萝卜星星
01-25 1万+
RSA的私钥签名公钥验签可以见http://blog.csdn.net/starfd/article/details/51917916,所以这里就没提供对应代码,具体代码如下: using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; ...
C语言解析证书.rar
05-14
linux下C语言程序解析标准的p7b证书证书转码,获取x509,解析内容,验证证书
X509证书结构及解析
热门推荐
suata
12-19 3万+
一、 X.509证书结构 x.509标准规定了证书可以包含什么信息,并说明了记录信息的方法。 X.509结构中包括版本号(integer)、序列号(integer)、签名算法(object)、颁布者(set)、有效期(utc_time)、主体(set)、主体公钥(bit_string)、主体公钥算法(object)、签名值(bit_string)。 使用ASN.1描述,我们可以将其抽象为以下...
证书拓展域(1)
清涵
03-07 1423
本项列出了由颁发CA认可的证书策略,这些策略适用于证书以及关于这些证书策略的任选的限定符信息。证书策略拓展包含了一系列策略条目信息条目,每个条目都有一个oid和一个可选的限定条件。这个可选的限定条件不能改变策略的定义。qualifier 为枚举常量本项只用于CA证书。它列出了一个多个OID对,每对包括一个issuerDomainPolicy和一个subjectDomaimPolicy。
使用 OpenSSL 和 C 解析 X.509 证书
烫手的热山药的博客
11-24 5218
Parsing X.509 Certificates with OpenSSL and C Zakir Durumeric | October 13, 2013 While OpenSSL has become one of the defacto libraries for performing SSL and TLS operations, the library is surprisingly opaque and its documentation is, at times, abysmal. As
X.509数字证书
觅食小鱼的博客
08-23 2026
本文介绍X.509证书的结构和字段,并介绍了openssl软件生成根证书和颁发证书的步骤和指令。
openssl命令x509证书操作详解
N阶二进制的博客
11-03 4763
OpenSSL 是一个开源的加密和解密工具,它提供了一系列命令来操作证书和密钥。以下是一些常用的 OpenSSL 命令,用于操作证书的详细解释:生成自签名证书是指在没有经过任何第三方证书颁发机构(CA,Certificate Authority)的认证下,由个人或组织自行创建和签名的数字证书。自签名证书可以用于安全通信,但在实际应用中,它们通常用于测试、开发和内部使用,而不是在公共网络中使用,因为它们没有受到可信任 CA 的验证,可能会引发安全问题。在使用自签名证书时,虽然可以加密通信,但客户端在连接时通常
c语言 x509证书提取公钥代码实现
10-23
要提取X.509证书中的公钥,可以使用C语言编写代码实现。以下是一个简单的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <openssl/x509.h> int main() { // 加载证书文件 X509 *cert = NULL; FILE *cert_file = fopen("certificate.pem", "r"); if (cert_file == NULL) { printf("无法打开证书文件\n"); return 1; } cert = PEM_read_X509(cert_file, NULL, NULL, NULL); fclose(cert_file); if (cert == NULL) { printf("无法加载证书\n"); return 1; } // 提取公钥 EVP_PKEY *pub_key = NULL; pub_key = X509_get_pubkey(cert); if (pub_key == NULL) { printf("无法提取公钥\n"); X509_free(cert); return 1; } // 输出公钥 printf("公钥信息:\n"); printf("算法: %s\n", EVP_PKEY_type_str(pub_key->type)); printf("长度: %d\n", EVP_PKEY_bits(pub_key)); // TODO: 这里可根据实际需要做其他处理,如将公钥保存到文件中 // 释放资源 X509_free(cert); EVP_PKEY_free(pub_key); return 0; } ``` 上述代码使用OpenSSL库中的X509函数来读取证书文件并提取公钥。首先,代码尝试打开证书文件,若打开失败则返回错误。然后,代码使用`PEM_read_X509`函数从证书文件中加载证书。如果加载失败,则输出错误信息并返回。接下来,代码使用`X509_get_pubkey`函数从证书中提取公钥。如果提取失败,也会输出错误信息并返回。最后,代码输出公钥的相关信息,如算法和长度,可以根据实际需要对公钥做其他处理。最后,代码释放加载的证书和提取的公钥的相关资源。 注意,这只是一个简单的提取公钥的示例代码,实际应用中还需要进行更多的错误处理和安全措施。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • 学生宿舍管理信息系统 数据库课程设计 52479
  • 基于Python的人脸互换系统设计与实现 35540
  • 教务信息管理系统的设计与实现 24167
  • 基于Python实现的五子棋游戏设计 23226
  • 基于Android的天气预报系统的设计与实现 20675

最新评论

  • 基于JavaWEB+MySQL的二手闲置物品交易网站系统

    weixin_72116959: 想要,我是大学生

  • 校园网络的规划与实施(思科)

    m0_62852362: 思科模拟器

  • 基于JavaWeb+MySQL的图书管理系统

    shejizuopin: 有呢 文末有联系

  • 基于JavaWeb+MySQL的图书管理系统

    2301_76940132: 有压缩包吗

  • 基于JavaWeb+MySQL的图书管理系统

    2301_76940132: 有压缩包吗

大家在看

  • stablediffusion_v2.1_pytorch以文生图推理模型

最新文章

  • 基于机器视觉的果园无人采摘系统开发(任务书)
  • 某大学五层实验楼教学楼建筑结构设计(6560.66平方米)
  • 抓取不规则表面物体机械手的设计
2024
06月 32篇
05月 63篇
04月 68篇
03月 69篇
02月 58篇
01月 62篇
2023年416篇
2022年1044篇
2021年2篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shejizuopin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值

两个鬼故事法律事务所起名免费算生辰八字男起名字猪小孩小名怎么起宝宝起名比较好的网页暗黑破坏神2存档存储容量单位汤粉店起名公众号起名创意武汉汉商集团傅起姓名大全圆癣中国起名软件鬼赌鬼个人店铺名怎么起名山头火起名字科技公司怎么起名大全网上胎儿免费起名大全一般饭店起什么名字好鸦雀无声陈天阳苏沐雨小说全文免费阅读大结局湖北基本药物采购平台藤井美菜起个英文名男孩子海螺沟冰川温泉度假村小孩姓李起名字鹳雀楼女孩起名聪明美丽智慧的名字不要和陌生人说话剧情菊豆下载夜总会起名少年生前被连续抽血16次?多部门介入两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”淀粉肠小王子日销售额涨超10倍高中生被打伤下体休学 邯郸通报单亲妈妈陷入热恋 14岁儿子报警何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言张家界的山上“长”满了韩国人?男孩8年未见母亲被告知被遗忘中国拥有亿元资产的家庭达13.3万户19岁小伙救下5人后溺亡 多方发声315晚会后胖东来又人满为患了张立群任西安交通大学校长“重生之我在北大当嫡校长”男子被猫抓伤后确诊“猫抓病”测试车高速逃费 小米:已补缴周杰伦一审败诉网易网友洛杉矶偶遇贾玲今日春分倪萍分享减重40斤方法七年后宇文玥被薅头发捞上岸许家印被限制高消费萧美琴窜访捷克 外交部回应联合利华开始重组专访95后高颜值猪保姆胖东来员工每周单休无小长假男子被流浪猫绊倒 投喂者赔24万小米汽车超级工厂正式揭幕黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发当地回应沈阳致3死车祸车主疑毒驾恒大被罚41.75亿到底怎么缴妈妈回应孩子在校撞护栏坠楼外国人感慨凌晨的中国很安全杨倩无缘巴黎奥运校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变王树国卸任西安交大校长 师生送别手机成瘾是影响睡眠质量重要因素国产伟哥去年销售近13亿阿根廷将发行1万与2万面值的纸币兔狲“狲大娘”因病死亡遭遇山火的松茸之乡“开封王婆”爆火:促成四五十对奥巴马现身唐宁街 黑色着装引猜测考生莫言也上北大硕士复试名单了德国打算提及普京时仅用姓名天水麻辣烫把捣辣椒大爷累坏了

两个鬼故事 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化