• ASN.1与数字证书


    基于BouncyCastle的ASN.1分析工具设计与实现

    X.509证书内容

    • X.509是一种通用的证书格式,所有有效证书都符合ITU-T X.509国际标准;
    • (理论上)为一种应用创建的证书可用于任何其他符合X.509标准的应用,在一份证书中必须证明公钥及其所有者的姓名一致;
    • X.509证书认证者总是CA或由CA指定的人,X.509证书是一些标准字段的集合,包含关用户或设备及其相应公钥的信息;
    • X.509标准定义了证书中应该包含哪些信息,并描述了这些信息是如何编码的(即数据格式),所有的X.509证书包含以下数据:
      • X.509版本号 指出该证书使用了哪种版本的 X.509标准,版本号会影响证书中的一些特定信息。目前的版本是3;
      • 证书持有人的公钥 包括证书持有人的公钥、算法(指明密钥属于哪种密码系统)的标识符和其他相关的密钥参数;
      • 证书的序列号 由CA给予每一个证书分配的唯一的数字型编号,当证书被取消时,实际上是将此证书序列号放入由CA签发的CRL(Certificate Revocation List证书作废表或证书黑名单表)中,这也是序列号唯一的原因;
      • 主题信息 证书持有人唯一的标识符(或称DN-distinguished name)这个名字在 Internet上应该是唯一的,DN由许多部分组成;这些信息指出该科目的通用名、组织单位、组织和国家或者证书持有人的姓名、服务处所等信息;
        CN=Bob Allen, OU=Total Network Security Division
        O=Network Associates, Inc.
        C=US
        
      • 证书的有效期 证书起始日期和时间以及终止日期和时间;指明证书在这两个时间内有效;
      • 认证机构 证书发布者,是签发该证书的实体唯一的CA的X.500名字。使用该证书意味着信任签发证书的实体。(注意:在某些情况下,比如根或顶级CA证书,发布者自己签发证书);
      • 发布者的数字签名 这是使用发布者私钥生成的签名,以确保这个证书在发放之后没有被撰改过;
      • 签名算法标识符 用来指定CA签署证书时所使用的签名算法。算法标识符用来指定CA签发证书时所使用的公开密钥算法和HASH算法。

    ASN.1

    • Abstract Syntax Natation One,用来描述抽象类型抽象数据的语法. 类似于XML,JSON等, 主要用于编码数据以便于在网络中交换数据,比如X.509证书
    • ASN.1定义四种类型,每个类型都对应与一个class和非负的tag number,用来区别不同的ASN.1类型
      • 简单类型Simple types用于编码基本的数据类型. 如 整形,字符串,二进制数据等
      • 结构类型Structured types用于编码复杂数据类型. 如, X509 证书中的公钥
      • 标记的类型Tagged types用于编码从其他几种类型引申而来的类型
      • 其他类型Other typesCHOICE 或 Any
    • ASN.1定义四种class,具体的规定某个数据的具体ASN.1结构,对于每个数据的每个字段也都有严格的规定
      • Universal用来表示在所有应用中都会具有相同意义的类型,这些类型定义在X.208
      • Application用来表示针对于具体应用的类型. 在不同的应用中这些类型的意义往往不同
      • Private用来表示针对用于具体企业的类型
      • Context-specific用来表示针对于具体上下文该类型意义会变化的类型

    X.509证书格式

    • 为了利用公共密钥这种密码系统,必须将公共密钥分发出去,最通用的一种签名证书格式 被称为X.509格式;
    • X.509格式的证书被VeriSign和微软等许多公司广泛应用于对电子邮件消息进行签名,对程序代码进行认证,以及对许多其他类型的数据进行认证等等;
    • X.509标准是由国际电话标准机构,即国际电报电话咨询委员会(CCITT)提出的用于目录服务的X.500系列建议的组成部分;
    • X.509证书的具体结构是用一种形式化表示来描述的,称为抽象语法表示法#1即ASN.1;
    • ASN.1为证书文件的结构给出了精确的定义,基本编码规则(basic encoding rules)即BER,精确地描述了如何将该结构保存为二进制文件;
    • BER描述了如何对整数、字符串、位串以及诸如SEQUENCE、CHOICE和OPTIONAL的结构进行编码的方法。
      [Certificate ::= SEQUENCE {
      tbsCertificate TBSCertificate,
      signatureAlgorithm AlgorithmIdentifier,
      signature BIT STRING
      }
      TBSCertificate ::= SEQUENCE {
      version [0] EXPLICIT 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 v2or v3
      subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
      -- If present, version must be v2or v3
      extensions [3] EXPLICIT Extensions OPTIONAL
      -- If present, version must be v3
      }
      Version ::= INTEGER {
      v1(0), v2(1), v3(2)
      }
      CertificateSerialNumber ::= INTEGER
      Validity ::= SEQUENCE {
      notBefore CertificateValidityDate,
      notAfter CertificateValidityDate
      }
      CertificateValidityDate ::= CHOICE {
      utcTime UTCTime,
      generalTime GeneralizedTime
      }
      UniqueIdentifier ::= BIT STRING
      SubjectPublicKeyInfo ::= SEQUENCE {
      algorithm AlgorithmIdentifier,
      subjectPublicKey BIT STRING
      }
      Extensions ::= SEQUENCE OF Extension
      Extension ::= SEQUENCE {
      extnID OBJECT IDENTIFIER,
      critical BOOLEAN DEFAULT FALSE,
      extnValue OCTET STRING
      }
      

    ASN.1编码

    BIT STRING

    • 00000110011011100101110111000000进行编码,

    • Identifier字段仅考虑tag number不考虑 class,应该为03

    • Length字段因为每个1或者0代表一个bit, 因此该值需要4字节进行编码, 因此Length字段应该为04

    • 编码结果

    BER short form encoding/DER encoding: 03 04 06 6e 5d c0
    BER long form encoding: 03 81 04 06 6e 5d c0
    

    IA5String

    • test1@rsa.com进行编码, 编码结果为
    BER short form encoding/DER encoding: 16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d
    BER long form encoding: 16 81 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d
    
    • 假设将test1@rsa.com编码为一个IA5String的集合,该集合中由三个IA5String构成test1 @ rsa.com
    • 编码一个复杂类型Identifier的bit6应为1,代表复杂类型
    • IA5String的tag number为 0x16, 因此Identifier的值应该为0x36,因此编码结果为
       36 13                         
       16 05 74 65 73 74 31
       16 01 40
       16 07 72 73 61 2e 63 6f 6d
    

    INTEGER

    • 对0进行编码,编码结果为02 01 00
    • 对127进行编码,编码结果为02 01 7F
    • 对128进行编码,编码结果为02 02 00 80

    NULL

    • 编码结果为05 0005 81 00

    OCTET STRING

    • 01 23 45 67 89 ab cd ef进行编码
    • 编码结果为04 08 01 23 45 67 89 ab cd ef

    UTCTime

    • 将要进行ANS1编码的UTCTime应该是以下形式之一
    YYMMDDhhmmZ
    YYMMDDhhmm+hh'mm'
    YYMMDDhhmm-hh'mm'
    YYMMDDhhmmssZ
    YYMMDDhhmmss+hh'mm'
    YYMMDDhhmmss-hh'mm'
    
    where:
    
    YY is the least significant two digits of the year
    MM is the month (01 to 12)
    DD is the day (01 to 31)
    hh is the hour (00 to 23)
    mm are the minutes (00 to 59)
    ss are the seconds (00 to 59)
    Z indicates that local time is GMT, + indicates that local time is later than GMT, and - indicates that local time is earlier than GMT
    hh' is the absolute value of the offset from GMT in hours
    mm' is the absolute value of the offset from GMT in minutes
    
    • 对于时间4:45:40 p.m. Pacific Daylight Time on May 6, 1991进行编码
    • 所有表示形式中存在以下两种:
    "910506164540-0700"
    "910506234540Z"
    
    • 编码结果为:
    17 11 39 31 30 35 30 36 31 36 34 35 34 30 2D 30 37 30 30
    17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a
    

    OBJECT IDENTIFIER

    • registration authorities
    Object identifier value Meaning
    {1 2} ISOmember bodies
    {1 2 840} US (ANSI)
    {1 2 840 113549} RSA Data Security, Inc.
    {1 2 840 113549 1} RSA Data Security, Inc. PKCS
    {2 5} directory services (X.500)
    {2 5 8} directory services-algorithm
    • 编码后的第一个字节的值为40 * value1 + value2
    • value3, value4,…,valuen以128为base进行编码(高字节在前),每个数字编码后除了最后一个字节外其他字节的bit8均为1

    解析X.509证书

    • 从磁盘上的证书文件中读取证书数据

      unsigned char* pbX509Data;   // 证书数据
      unsigned long ulX509DataLen; // 证书数据长度
      
    • 获取CertContext

      PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, pbX509Data, ulX509DataLen);
      
    • 获取证书信息

      pCertContext->pCertInfo->dwVersion;                                 // 证书版本号
      CRYPT_INTEGER_BLOB snBlob = pCertContext->pCertInfo->SerialNumber;  // 证书SN
      CERT_NAME_BLOB issuerBlob = pCertContext->pCertInfo->Issuer;        // 证书颁发者
      CERT_NAME_BLOB subjectBlob = pCertContext->pCertInfo->Subject;      // 证书主题
      // 证书有效起始日期
      SYSTEMTIME sysTime;
      memset(&sysTime, 0, sizeof(sysTime));
      FileTimeToSystemTime(&pCertContext->pCertInfo->NotBefore, &sysTime);
      char szTime[128] = {0};
      sprintf_s(szTime, 128, "%d年%d月%d日 %d:%d:%d", sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond);
      // 证书有效终止日期
      memset(&sysTime, 0, sizeof(sysTime));
      FileTimeToSystemTime(&pCertContext->pCertInfo->NotAfter, &sysTime);
      memset(szTime, 0, sizeof(szTime));
      sprintf_s(szTime, 128, "%d年%d月%d日 %d:%d:%d", sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond);
      
    • 创建临时密钥容器

      HCRYPTPROV hTmpProv = NULL;
      CryptAcquireContext(&hTmpProv, "My_Temporary_Container", NULL, PROV_RSA_AES, 0); // NULL表示使用系统默认CSP
      
    • 向容器中导入公钥,获取公钥句柄

      HCRYPTKEY hKey = NULL;
      CERT_PUBLIC_KEY_INFO certPubKeyInfo = pCertContext->pCertInfo->SubjectPublicKeyInfo;
      CryptImportPublic KeyInfo(hTmpProv, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, &certPubKeyInfo, &hKey);
      
    • 导出公钥(最好采用二次调用方式)

      unsigned char* pBuf = NULL;
      unsigned long ulBufLen = 0;
      CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, pBuf, &ulBufLen);
      pBuf = new unsigned char[ulBufLen];
      memset(pBuf, 0, ulBufLen);
      CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, pBuf, &ulBufLen);
      
    • 获取公钥信息

      unsigned char* p = pBuf + sizeof(PUBLICKEYSTRUC);
      (*(RSAPUBKEY*)p).bitlen; // 公钥模长(以bit为单位)
      (*(RSAPUBKEY*)p).pubexp; // 公钥的e(注意字节顺序)
      p += sizeof(RSAPUBKEY); // 公钥的n(注意字节顺序)
      
    • 清理工作

      delete[] pBuf;
      pBuf = NULL;
      CryptDestroyKey(hKey);
      CryptReleaseContext(hTmpProv, 0);
      CertFreeCertificateContext(pCertContext);
      
  • 相关阅读:
    有关需求规格说明
    软件导论第五周作业-------简单小结
    初用sqlite3.exe
    软件开发与模型
    Difference **面向过程(或者叫结构化)分析方法**面向对象分析方法
    当下互联网创业公司采用增量模型的原因
    第七周作业
    第六周作业
    第五周作业
    第四周作业
  • 原文地址:https://www.cnblogs.com/SANFENs/p/12747529.html
Copyright © 2020-2023  润新知