美文网首页
从DER格式的X.509证书中提取公钥

从DER格式的X.509证书中提取公钥

作者: 客昂康 | 来源:发表于2021-07-02 11:00 被阅读0次

x509.h

#ifndef _X509_H_
#define _X509_H_ 1

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct x509_t X509_T;

X509_T*   x509_create       (uint8_t *derData, uint32_t derSize);
void      x509_destroy      (X509_T *x509);
uint8_t*  x509_getPublicKey (X509_T *x509, uint32_t *keyLen, uint32_t *exponent);

#ifdef __cplusplus
}
#endif

#endif

x509.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "x509.h"

#define  DER_TAG_Integer           0x02
#define  DER_TAG_BitString         0x03
#define  DER_TAG_ObjectIdentifier  0x06
#define  DER_TAG_UtcTime           0x17
#define  DER_TAG_Sequence          0x30
#define  DER_TAG_Version           0xa0

/*
// 签名算法描述符
AlgorithmIdentifier::=SEQUENCE{
    algorithm   OBJECT IDENTIFIER,                // 算法OID。
    parameters  ANY DEFINED BY algorithm OPTIONAL // 可选的参数,由算法决定。
}

// 算法OID:
1.2.840.113549.1.1.4   MD5 + RSA
1.2.840.113549.1.1.5   SHA1 + RSA

// 属性的类型和值
AttributeTypeAndValue::=SEQUENCE{
    type    AttributeType,  // 属性类型。AttributeType::=OBJECT IDENTIFIER
    value   AttributeValue  // 属性的值。AttributeValue::=ANY DEFINED BY AttributeType
}

// 相对可分辨名称
RelativeDistinguishedName::=SET OF AttributeTypeAndValue

// RDN序列
RDNSequence::=SEQUENCE OF RelativeDistinguishedName

// 名字结构
Name::=CHOICE{
    RDNSequence
}

// 时间结构
Time::=CHOICE{
    utcTime      UTCTime,
    generalTime  GeneralizedTime
}

// 有效期
Validity::=SEQUENCE{
    notBefore  Time,  // 时间段起点时间
    notAfter   Time   // 时间段终点时间
}

// 主体公钥信息
SubjectPublicKeyInfo::=SEQUENCE{
    algorithm           AlgorithmIdentifier,  // 签名算法描述符。
    subjectPublicKey    BIT STRING            // 公钥数据。
}

// 证书内容。
TBSCertificate::=SEQUENCE{
    version           [0]   EXPLICIT Version DEFAULT v1,         // 版本号。 Version::=INTEGER {v1(0),v2(1),v3(2)}
    serialNumber            CertificateSerialNumber,             // 序列号。 CertificateSerialNumber::=INTEGER
    signature               AlgorithmIdentifier,                 // 签名算法描述符。
    issuer                  Name,                                // 证书签发者。
    validity                Validity,                            // 有效期。
    subject                 Name,                                // 证书持有者。
    subjectPublicKeyInfo    SubjectPublicKeyInfo,                // 主体公钥信息。
    issuerUniqueID    [1]   IMPLICIT UniqueIdentifier OPTIONAL,  // 签发者唯一标识符,仅V2和V3有这个字段。 UniqueIdentifier::=BIT STRING
    subjectUniqueID   [2]   IMPLICIT UniqueIdentifier OPTIONAL,  // 主体唯一标识符,仅V2和V3有这个字段。   UniqueIdentifier::=BIT STRING
    extensions        [3]   EXPLICIT Extensions OPTIONAL         // 扩展数据,仅V3版本有此字段。
}

// X.509 证书整体格式
Certificate::=SEQUENCE{
    tbsCertificate      TBSCertificate,       // 证书内容。
    signatureAlgorithm  AlgorithmIdentifier,  // 签名算法描述符。
    signatureValue      BIT STRING            // 签名结果值,位流。
}
*/

struct x509_t {
    uint8_t *serialNumber;       // 序列号
    uint8_t *algorithm;          // 签名算法描述符
    uint8_t *parameters;         // 签名算法所需参数
    uint8_t *notBefore;          // 有效期起始时间
    uint8_t *notAfter;           // 有效期终止时间
    uint8_t *signature;          // 签名结果值数据
    uint8_t *keyModulus;         // RSA公钥模数
    uint16_t version;            // X.509 版本号
    uint16_t serialNumberSize;   // 序列号字节数
    uint16_t algorithmSize;      // 签名算法描述符字节数
    uint16_t parametersSize;     // 签名算法所需参数字节数
    uint16_t notBeforeSize;      // 有效期起始时间字节数
    uint16_t notAfterSize;       // 有效期终止时间字节数
    uint16_t signatureSize;      // 签名结果值数据字节数
    uint16_t keyModulusSize;     // RSA公钥模数字节数
    uint32_t keyExponent;        // RSA公钥指数
    uint8_t  buffer[0];          // 
};

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

static inline uint16_t readU16BE(uint8_t *buffer){
    uint16_t value = 0;
    value = (value << 8) | buffer[0];
    value = (value << 8) | buffer[1];
    return value;
}

static inline uint32_t readU24BE(uint8_t *buffer){
    uint32_t value = 0;
    value = (value << 8) | buffer[0];
    value = (value << 8) | buffer[1];
    value = (value << 8) | buffer[2];
    return value;
}

static inline uint32_t readU32BE(uint8_t *buffer){
    uint32_t value = 0;
    value = (value << 8) | buffer[0];
    value = (value << 8) | buffer[1];
    value = (value << 8) | buffer[2];
    value = (value << 8) | buffer[3];
    return value;
}

static uint8_t getTLV(uint8_t *tag, uint32_t *length, uint8_t *data){
    *tag = data[0];
    if(data[1] < 128){
        *length = data[1];
        return 2;
    }else{
        uint8_t num = data[1] & 0x7f;
        switch(num){
            case 1:
            *length = data[2];
            return 3;
            
            case 2:
            *length = readU16BE(data+2);
            return 4;
            
            case 3:
            *length = readU24BE(data+2);
            return 5;
            
            case 4:
            *length = readU32BE(data+2);
            return 6;
        }
    }
    *tag = 0;
    *length = 0;
    return 0;
}

// 读取算法描述符及其所需参数
static void readSignatureAlgorithm(X509_T *x509, uint8_t *data, uint32_t size){
    // 算法描述符 ObjectIdentifier
    uint8_t  tag;
    uint32_t length;
    uint8_t head = getTLV(&tag, &length, data);
    if((head) && (tag == DER_TAG_ObjectIdentifier)){
        x509->algorithm = data + head;
        x509->algorithmSize = length;
    }else{
        return;
    }
}

// 读取 X.509 版本号
static void readVersion(X509_T *x509, uint8_t *data, uint32_t size){
    uint8_t tag;
    uint32_t length;
    uint8_t head = getTLV(&tag, &length, data);
    if((head) && (tag == DER_TAG_Integer)){
        x509->version = data[head];
    }
}

// 读取有效期
static void readValidity(X509_T *x509, uint8_t *data, uint32_t size){
    uint8_t  head;
    uint8_t  tag;
    uint32_t length;
    uint32_t offset = 0;
    
    // 读取 notBefore
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_UtcTime)){
        x509->notBefore = data + offset + head;
        x509->notBeforeSize = length;
        offset += length + head;
    }else{
        return;
    }
    
    // 读取 notAfter
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_UtcTime)){
        x509->notAfter = data + offset + head;
        x509->notAfterSize = length;
        offset += length + head;
    }else{
        return;
    }
}

// 读取公钥信息
static void readSubjectPublicKeyInfo(X509_T *x509, uint8_t *data, uint32_t size){
    uint8_t  head;
    uint8_t  tag;
    uint32_t length;
    uint32_t offset = 0;
    
    // 读取算法描述符。 略过。
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Sequence)){
        offset += length + head;
    }else{
        return;
    }
    
    // 解开位流包。位流包解开后还有一层序列包。
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_BitString)){
        if(data[offset+head]){
            data = data + offset + head;
            size = length;
        }else{
            data = data + offset + head + 1;
            size = length - 1;
        }
        offset = 0;
    }else{
        return;
    }
    
    // 解开序列包。序列包解开后就是公钥模数和指数。
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Sequence)){
        data = data + offset + head;
        size = length;
        offset = 0;
    }else{
        return;
    }
    
    // 读取 RSA公钥模数
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Integer)){
        if((data[offset+head]) || (length%16 == 0)){
            x509->keyModulus = data + offset + head;
            x509->keyModulusSize = length;
        }else{
            x509->keyModulus = data + offset + head + 1;
            x509->keyModulusSize = length - 1;
        }
        offset += length + head;
    }else{
        return;
    }
    
    // 读取 RSA公钥指数
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Integer)){
        if(length == 1){
            x509->keyExponent = data[offset+head];
        }else if(length == 2){
            x509->keyExponent = readU16BE(data+offset+head);
        }else if(length == 3){
            x509->keyExponent = readU24BE(data+offset+head);
        }else if(length == 4){
            x509->keyExponent = readU32BE(data+offset+head);
        }else{
            return;
        }
    }else{
        return;
    }
}

// 读取证书主体内容
static void readtbsCertificate(X509_T *x509, uint8_t *data, uint32_t size){
    uint8_t  head;
    uint8_t  tag;
    uint32_t length;
    uint32_t offset = 0;
    
    // 读取 X.509 版本号
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Version)){
        readVersion(x509, data+offset+head, length);
        offset += length + head;
    }else{
        return;
    }
    
    // 读取序列号
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Integer)){
        x509->serialNumber = data + offset + head;
        x509->serialNumberSize = length;
        offset += length + head;
    }else{
        return;
    }
    
    // 读取签名算法描述符。 略过,因为后面还有。
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Sequence)){
        offset += length + head;
    }else{
        return;
    }
    
    // 读取证书发行者。 略过。
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Sequence)){
        offset += length + head;
    }else{
        return;
    }
    
    // 读取有效期
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Sequence)){
        readValidity(x509, data+offset+head, length);
        offset += length + head;
    }else{
        return;
    }
    
    // 读取证书持有者。 略过。
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Sequence)){
        offset += length + head;
    }else{
        return;
    }
    
    // 读取公钥信息
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Sequence)){
        readSubjectPublicKeyInfo(x509, data+offset+head, length);
        offset += length + head;
    }else{
        return;
    }
}

// 读取整个证书
static void readCertificate(X509_T *x509, uint8_t *data, uint32_t size){
    uint8_t  head;
    uint8_t  tag;
    uint32_t length;
    uint32_t offset = 0;
    
    // 证书内容 TBSCertificate
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Sequence)){
        readtbsCertificate(x509, data+offset+head, length);
        offset += length + head;
    }else{
        return;
    }
    
    // 签名算法描述符 AlgorithmIdentifier
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_Sequence)){
        readSignatureAlgorithm(x509, data+offset+head, length);
        offset += length + head;
    }else{
        return;
    }
    
    // 签名结果值 BitString
    head = getTLV(&tag, &length, data+offset);
    if((head) && (tag == DER_TAG_BitString)){
        if((data[offset+head]) || (length%16 == 0)){
            x509->signature = data + offset + head;
            x509->signatureSize = length;
        }else{
            x509->signature = data + offset + head + 1;
            x509->signatureSize = length - 1;
        }
    }else{
        return;
    }
}
/*
static void X509_dump(X509_T *x509){
    printf("x509:\n");
    printf("  version: %u\n", x509->version);
    if((x509->serialNumber) && (x509->serialNumberSize)){
        printf("  serialNumberSize: %u\n", x509->serialNumberSize);
        printf("  serialNumberValue:\n");
        common_hex("    ", "\e[32m", x509->serialNumber, x509->serialNumberSize);
    }
    if((x509->algorithm) && (x509->algorithmSize)){
        printf("  algorithmSize: %u\n", x509->algorithmSize);
        printf("  algorithmValue:\n");
        common_hex("    ", "\e[32m", x509->algorithm, x509->algorithmSize);
    }
    if((x509->notBefore) && (x509->notBeforeSize)){
        printf("  notBeforeSize: %u\n", x509->notBeforeSize);
        printf("  notBeforeValue:\n");
        common_hex("    ", "\e[32m", x509->notBefore, x509->notBeforeSize);
    }
    if((x509->notAfter) && (x509->notAfterSize)){
        printf("  notAfterSize: %u\n", x509->notAfterSize);
        printf("  notAfterValue:\n");
        common_hex("    ", "\e[32m", x509->notAfter, x509->notAfterSize);
    }
    if((x509->signature) && (x509->signatureSize)){
        printf("  signatureSize: %u\n", x509->signatureSize);
        printf("  signatureValue:\n");
        common_hex("    ", "\e[32m", x509->signature, x509->signatureSize);
    }
    if((x509->keyModulus) && (x509->keyModulusSize)){
        printf("  keyModulusSize: %u\n", x509->keyModulusSize);
        printf("  keyModulusValue:\n");
        common_hex("    ", "\e[34m", x509->keyModulus, x509->keyModulusSize);
    }
    printf("  keyExponent: %u\n\n", x509->keyExponent);
}
*/
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// 通过DER格式的X.509证书创建X509结构体。
X509_T* x509_create(uint8_t *derData, uint32_t derSize){
    X509_T *x509 = malloc(sizeof(X509_T) + derSize + 8);
    if(x509 == NULL) return NULL;
    memset(x509, 0, sizeof(X509_T));
    memcpy(x509->buffer, derData, derSize);
    
    uint8_t tag;
    uint32_t length;
    uint8_t head = getTLV(&tag, &length, x509->buffer);
    if((head) && (tag == DER_TAG_Sequence) && (length+head <= derSize)){
        readCertificate(x509, x509->buffer+head, length);
        // X509_dump(x509);
        return x509;
    }else{
        free(x509);
        return NULL;
    }
}

// 销毁X509结构
void x509_destroy(X509_T *x509){
    free(x509);
}

// 从X509结构获取RSA公钥
uint8_t* x509_getPublicKey(X509_T *x509, uint32_t *keyLen, uint32_t *exponent){
    *keyLen = x509->keyModulusSize;
    *exponent = x509->keyExponent;
    return x509->keyModulus;
}

相关文章

  • openssl 证书相关

    1、从x509证书中提取公钥 2、PEM证书转DER证书 持续更新中...

  • HTTPS证书相关概念

    X.509 密码学里公钥证书的格式标准。SSL/TLS中的证书格式即采用X.509。是ITU-T标准化部门基于他们...

  • 从DER格式的X.509证书中提取公钥

    x509.h x509.c

  • pem、x509、asn1

    X.509 X.509是密码学里公钥证书的格式标准。 X.509 证书己应用在包括TLS/SSL在内的众多 Int...

  • SSL 证书

    本文介绍 SSL 证书相关标准、格式及转换命令。 证书标准 X.509 是密码学中公钥证书的格式标准,主要定义了证...

  • 用openssl添加https访问并设置客户端信任

    前置知识: x.509 是密码学里面的公钥证书的格式标准. 就是说x.509是一种证书的格式,其实我们经常用这种...

  • 解析X.509证书

    简介 X.509是密码学里公钥证书的格式标准。X.509证书己应用在包括TLS/SSL在内的众多Intenet协议...

  • 11.PKI(公钥基础设施)

    •PKI(公钥基础设施) • 数字证书 •公钥和私钥 •证书颁发机构 •证书撤销列表 X.509由Fabric ...

  • 快速理解CA

    CA简介 CA中心基于X.509公钥证书格式标准,为每个使用公开密钥的用户发放一个数字证书,数字证书的作用是证明证...

  • AFNetworking 3.x 详解三

    AFSecurityPolicy AFSecurityPolicy用于公钥安全连接和对X.509证书的服务器信任验...

网友评论

      本文标题:从DER格式的X.509证书中提取公钥

      本文链接:https://www.haomeiwen.com/subject/wzjeultx.html