Web Security Homework3
X.509
1. 内容解析
1.1 定义
X.509 是密码学里公钥证书的格式标准。
X.509 证书己应用在包括 TLS/SSL
在内的众多 Intenet 协议里.同时它也用在很多非在线应用场景里,比如电子签名服务。
X.509证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构CA的签名,也可以是自签名)。对于一份经由可信的证书签发机构签名或者可以通过其它方式验证的证书,证书的拥有者就可以用证书及相应的私钥来创建安全的通信,对文档进行数字签名.
另外除了证书本身功能,X.509还附带了证书吊销列表和用于从最终对证书进行签名的证书签发机构直到最终可信点为止的证书合法性验证算法。
1.2 组成结构
证书
版本号
- 作用:【标识证书的版本(版本1、版本2、或是版本3)】
序列号
- 作用:【标识证书的唯一整数,由证书颁发者分配的本证书的唯一标识符】
签名算法
- 作用:【由于签名书的算法标识,由对象标识符加上相关的参数组成,用于说明本证书所用的数字签名算法。例如,SHA-1 和 RSA 的对象标识符就用来说明该数字签名是利用 RSA 对SHA-1 杂凑加密】
颁发者
- 作用:【证书颁发者的可识别名】
证书有效期
- 作用:【证书的有效期时间段】
- “Not Before” 此日期前无效
- “Not After” 此日期后有效
- 以上二者分别由
UTC
时间或一般的时间表示
- 作用:【证书的有效期时间段】
主体
- 作用:【证书拥有者的可识别名,这个字段必须是非空的,除非你在证书扩展中有别名】
主体公钥信息
- 作用:【标识主题的公钥以及算法标识符】
- 公钥算法
- 主题公钥
- 作用:【标识主题的公钥以及算法标识符】
颁发者唯一身份信息(可选项)
- 作用:证书颁发者的唯一标识符,仅在版本 2 与版本 3 中有要求,属于可选项
主题唯一身份信息
- 作用:证书拥有者的唯一标识符,仅在版本 2 和版本 3 中有要求,属于可选项
扩展信息 (次重点部分)
发行者秘钥标识符
- 作用:【证书所含密钥的唯一标识符,用来区分同一证书拥有者的多对密钥】
秘钥使用
作用:【一个比特串,指明(限定)证书的公钥可以完成的功能或服务,如:证书签名、数据加密等。
如果某一证书将 KeyUsage 扩展标记为“极重要”,而且设置为“keyCertSign”,则在 SSL 通信期间该证书出现时将被拒绝,因为该证书扩展表示相关私钥应只用于签写证书,而不应该用于 SSL。】
CRL 分布点
- 作用:【指明 CRL 的分布地点】
私钥的使用期
- 作用:【指明证书中与公钥相联系的私钥的使用期限,它也由 “ Not Before “ 和” Not After “组成。若此项不存在时,公私钥的使用期是一样的】
证书策略
- 作用:【由对象标识符和限定符组成,这些对象标识符说明证书的颁发和使用策略有关】
策略映射
- 作用:【表明两个 CA 域之间的一个或多个策略对象标识符的等价关系,仅在 CA 证书里存在】
主体别名
- 作用:【指出证书拥有者的别名,如电子邮件地址、IP 地址等,别名是和 DN 绑定在一起的】
颁发者别名
- 作用:【指出证书颁发者的别名,如电子邮件地址、IP地址等,但颁发者的 DN 必须出现在证书的颁发者字段】
主体目录属性
- 作用:【指出证书拥有者的一系列属性。可以使用这一项来传递访问控制信息】
证书签名算法
数字签名
1.3 安全性
- 采用黑名单方式的证书吊销列表 CRL 和在线证书状态协议( OCSP )
- 如果客户端仅信任在CRL可用的时候信任证书,那就失去离线信任的需求。因此通常客户端会在CRL不可用的情况下信任证书,因而给了那些可以控制信道的攻击者可乘之机。如谷歌的Adam Langley所说,对CRL的检查有如你期望安全带在出事故事一定能正常使用的
- 在大范围及复杂的分布模式下选用CRL并不明智
- OCSP由于没有吊销状态的历史记录也会出现歧义
- 聚合问题
- 代表问题: 证书颁发机构事没办法限制其下属颁发的证书作出名字及属性方面的限制。而且在Internet上存在着相当多的证书颁发机构,想对他们进行分类和策略上的限制是一项不可能完成的任务。
- 分布问题: 证书链引的下属颁发机构,桥接颁发机构以及交叉认证使得证书验证变得非常复杂,需要付出很大的代价。层次式的第三方信任模型作为一种唯一的模型的话,路径验证也可能出现含糊不明的情况岐义,这对于已经创建双边信任也很不方便。
- 发布一个对主机名的扩展验证并不能防止再发布一个验证要求低一些的适用于同一个主机名的证书。这就造成了不能对中间人攻击的有效保护
1.4 证书文件名扩展类型
X.509有多种常用的扩展名。不过其中的一些还用于其它用途,就是说具有这个扩展名的文件可能并不是证书,比如说可能只是保存了私钥。
.pem
– (隐私增强型电子邮件) DER编码的证书再进行 Base64 编码的数据存放在”——-BEGIN CERTIFICATE——-“和”——-END CERTIFICATE——-“之中.cer, .crt, .der
– 通常是DER二进制格式的,但 Base64 编码后也很常见。.p7b, .p7c
– PKCS#7- 注:
PKCS#7
是签名或加密数据的格式标准,官方称之为容器。由于证书是可验真的签名数据,所以可以用 SignedData 结构表述。 - 注:
P7C
文件是退化的 SignedData 结构,没有包括签名的数据。
- 注:
.p12
– PKCS#12格式,包含证书的同时可能还有带密码保护的私钥- 注:
PKCS#12
由 PFX 进化而来的用于交换公共的和私有的对象的标准格式。
- 注:
.pfx
– PFX,PKCS#12之前的格式(通常用 PKCS#12 格式,比如那些由 IIS 产生的 PFX 文件)
2. 数据结构
2.1 编码
X.509
证书的结构使用ASN1
进行描述数据结构,并进行编码;
ASN1
采用一个个的数据块来描述整个数据结构,整个数据块都由四部分组成:
数据块数据类型标识(一个字节)
数据类型包括简单类型和结构类型
- 简单类型:整型、比特串、日期型等
- 结构类型:顺序类型、选择类型、集合类型
数据块数类型标识的一个字节结构如下:
bit8
-bit7
标识TAG
类型 ,共四种类型,universal(00)、application(01)、context-specific(10)、private(11)
bit6
表示是否为结构类型bit5
-bit1
是类型的 TAG 值,根据bit8 - bit7
值为universal(00)
时,bit5
-bit1
表示不同的universal
值,如图:bit8
-bit7
为context-specific
时,bit5-bit1
的值表示- [0] -> 证书的版本
- [1] -> issuerUniqueID,表示证书发行者的唯一 id
- [2] -> subjectUniqueID,表示证书主体的唯一 id
- [3] -> 表示证书的扩展字段
举例,如:
DER二进制文件的前4个字节构成具有剩余字节的ASN.1序列。
如`30 82 06 E1`根据 `Type-Length-Value`表示,第一个字节30(00110000)表示是一个universal class type,后面接着一个结构化类型的SEQUENCE。
数据块长度( 1 - 128 个字节),有三种编码格式
- 长度小于等于 127 ,用一个字节表示
- 长度大于 127 ,用多个字节表示
- 字节为
0x80
,表示数据块长度不定,由数据块结束标识结束数据块
数据块的值
- 存放数据块的值,具体编码随数据块类型的不同而不同
数据块结束标识(可选)
- 结束标示字段,两个字节(0x000),只有在长度不定时才会出现
2.2 主体结构
1 | Certificate ::= SEQUENCE { |
2.3 Version
证书的版本号:0,1,2
1 | Version ::= INTEGER { |
2.4 CertificateSerialNumber
证书的序列号:一串整数,对于每一张证书,证书序列号均唯一
1 | CertificateSerialNumber ::= INTEGER |
2.5 AlgorithmIdentifier
算法结构标识,用来给定具体的算法类型。
1 | AlgorithmIdentifier ::= SEQUENCE { |
2.6 Validity
有效期:起始与终止时间
1 | Validity ::= SEQUENCE { |
2.7 PublicKey
公钥信息
1 | RSAPublicKey ::= SEQUENCE { -- RSA算法时的公钥值 |
2.8 UniqueIdentifier
由于签发者和使用者的类型都是一样的,是一些DN项(Distinguish Name)的集合
1 | AttributeTypeAndValue ::= SEQUENCE { |
常见的DN项有:
属性类型名称 | 含义 | 简写 |
---|---|---|
Common Name | 通用名称 | CN |
Organizational Unit name | 机构单元名称 | OU |
Organization name | 机构名 | O |
Locality | 地理位置 | L |
State or province name | 州/省名 | S |
Country | 国名 | C |
2.9 SubjectPublicKeyInfo
定义公钥类型信息:
1 | SubjectPublicKeyInfo ::= SEQUENCE { |
2.10 Extension
可省略的扩展类型:
1 | Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension |
3. 读取操作程序
3.1 语言选择
语言:Python
选择原因:
- 第一次在写的时候,由于直接使用了
Java
的基本类库对证书进行操作,虽然能够正常输出所需要的结果,但是并没有达到完成这次作业应有的目的,也没有对X.509
证书的数据结构有一个直观的认识。 - 在查询了
X.509
证书的数据结构之后,从新使用python
进行编程,不依附现有的类库,读入证书并进行文件解析。 - 使用
python
的好处在于可以方便进行字符串的操作,同时使用Spyder
编译器可以显示出程序的函数调用过程,方便debug
3.2 编译环境
操作系统: windows 10
条件:
- 安装 Anaconda(一个大型的
python
集成环境,可以根据需要构建python 2
与python 3
独立的编译环境) - Spyder 编译器
- 生成
der
类型的X.509
证书
3.3 证书读取
使用python
的open()
函数,以可读方式打开证书:
1 | filename = 'test.der' |
3.4 类型判断
X.509证书在存储时候是按照字节存储的,同时我们需要根据2.1
中的数据标识类型来对具体的某个段进行操作,所以方法具体如下:
1 | data = f.read(1) |
3.5 待处理数据长度判断
这步主要是对X.509
中type > 127
的数据进行操作,比如:当我们解析公钥时候,就需要进行多字节操作
1 | if type > 0x80: |
3.6 处理各种类型数据
我们需要根据数据类型的长度,来选定我们在2.3-2.10
中使用的数据类型,进而完成对数据的输出:
比如,Interger
类型:
1 | res_string = "" |
其他类型的转换类似。
3.7 程序输出
在上一步对所有的数据进行处理之后,我们可以将处理过的数据依次输出了,比如对序列号的输出:
1 | choice = INTEGER_CHIOCE.get() |
4. 编译运行
4.1 Spyder下程序运行过程
上图为程序中的函数调用过程;
4.2 运行结果
4.2.1 证书生成
- 生成一个2048位的密钥
- 指令:
openssl genrsa -des3 -out privkey.pem 2048
- 指令:
- 生成一个证书请求
- 指令:
openssl req -new -key privkey.pem -out cert.csr
- 指令:
- 生成
cert.der
证书- 指令:
openssl x509 -outform der -in cert.pem -out cert.der
- 指令:
4.2.2 运行结果
对上一步生成的证书进行解析,结果如图:
注:
- Version : 3
- Serial number : 9d:dd:d1:14:4c:c7:7a:a8:85:55:5c:c0:0d:d6:69:97:7f:f9:92:22:22:26:64:48:84:47:7f:8f
- Signature Algorithm : sha1WithRSAEncryption
- Validity:
- Not Before : 130514000000Z
- Not After : 160518120000Z
- Issuer:
- Country Name:US
- Organization Name:DigiCert Inc
- Organizational Unit Name:www.digicert.com
- Common Name:DigiCert High Assurance CA-3
- Subject Public Key Info RSAEncryption:1.2.840.113549.1.1.1
- Subject Public Key Encryption : 略
- Signature Algorithm:sha1WithRSAEncryption
- SIGNATURE Encryption : 略