ASN语法
简述
ASN.1抽象语法标记(Abstract Syntax Notation One) ASN.1是一种 ISO/ITU-T 标准,描述了一种对数据进行表示、编码、传输和解码的数据格式。它提供了一整套正规的格式用于描述对象的结构,而不管语言上如何执行及这些数据的具体指代,也不用去管到底是什么样的应用程序。
如下:
Report ::= SEQUENCE {
author OCTET STRING,
title OCTET STRING,
body OCTET STRING,
biblio Bibliography
}
常用ASN数据结构
- ASN的语法描述排列就是T(Type).L(Length).V(Value)的格式;如 0x06 08 2A 86 48 86 F7 0D 02 05。V可以是ASN的另外一个T的实例(类型嵌套,形成一套完整的证书元素数据结构)
- 0x06是T(Type): OID,代表这段编码是ASN语言结构描述的唯一对象类型
- 08是L(Length): 代表紧接之后有8个字节的位串集
- 2A 86 48 86 F7 0D 02 05是V(Value),代表就是以上所述的8个字节16进制的位串
- 位填充,计算机以8bit为1个字节,不能被8整除的位串,得做位填充。如位串(BIT_STRING){1,0,0,0,1,1,1,0,1,0,0,1} ,长度除以8余4,得做填充负载字节.
- 第一个字节,取前8位后为10001110= 0x8E;
- 第二个字节不足8位,得填充。填充后为10010000 = 0x90,低位4个0为填充的空位.则,填充后位串为2个字节,结果就是: 8E 90。
- 因为末位不足8位,填充了4个0凑足8位,得展示出这4个0的填充,那么用0x04代表填充个数,放在填充位串前面,即最终结果为总共3个字节,结果就是04 8E 90。
- 那么用ASN.1 TLV表示,已知位串T为0x03,位串长度3,则完整的编码为:0x03 03 04 8E 90.
- OID对象标识类型,数据排列是有规范的,MD5的OID 是 1.2.840.113549.2.5 表示为”iso(1) member-body (2) US (840) rsadsi(113549) digestAlgorithm (2) md5 (5),规定首两位数字是x*40+y的计算逻辑,那么,1.2就是1*40+2=42,排列成10进制那么排列为{42,840,113549,2,5},按照8位排列则排成{{0x2A},{0x86,0x48},{0x86,0xF7,0x0D},{0x02},{0x05}},最后编码位 0x06 08 2A 86 48 86 F7 0D 02 05
类型 | hex | 显示 | 隐式(hex length hex_value) |
Boolean | 0x01 | flag Boolean; flag:: true | 0x01 01 01 |
Integer | 0x02 | Age Integer; Age :: 18 | 0x02 01 12 |
BIT_STRING | 0x03 | Bits BIT String; bits::{1,0,0,0,1,1,1,0,1,0,0,1} | 0x03 03 04 8E 90 |
Octet_string | 0x04 | Octect_string::0x04 length {octect string} | 0x04 length {octect string} |
NULL | 0x05 | Null NULL; | 0x05 00 |
OID | 0x06 | 1.2.840.113549.2.5 | 0x06 08 2A 86 48 86 F7 0D 02 05 |
Sequence | 0x30 | sequence::=0x30 length{asndata}* | 0x30 length {asndata}* |
Set | 0xA3 | Set:: 0xA3 length {sets} | 0xA3 length {sets} |
ASN.1是证书的描述语言
ASN.1是描述证书的语言,包含数据类型和数据结构,同时是有数据结构标准的,不同标准决定了ASN.1结构也不同。
ASN分析工具
- 在线分析工具:http://lapo.it/asn1js/
- 无论是什么标准,什么格式,只要是ASN语法的证书都能分析出来
- 该工具提供离线HTML工程,可下载到本地使用
- openssl asn1parse 指令
JWKS
JWKS介绍
- JWK是json web key,可通过json格式描述证书的一些特征
- ECC证书的核心元素字段x,y,d。其中xy构成公钥
- RSA证书的核心元素字段n,e,qi,dq,q,dp,p,d,其中ne构成公钥
- 可以通过提供的这些特征计算出证书
ASN转JWKS思路
前面说到ASN描述证书,其实包含了jwk需要的这些元素信息,只要解析ASN描述的证书,知道大概的位置就能获取到这些数据
- jwk的数据可通过解析ASN获取的元素值算法是base64_url(hex_to_byte(${hex_string}))
- 当然如果不想那么麻烦,可以通过openssl查看证书信息,再base64_url(hex_to_byte(${hex_string}))
- 记得hexstring得移除”:”冒号
- 方案可行,但这里就不阐述如何用ASN解析器组装JWK了,
- 可选择用openssl工具解析
![RSA](https://img-blog.csdnimg.cn/c875390f28ed43058ddf59d1e8cd49d8.png)
![EC](https://img-blog.csdnimg.cn/6775cf9bb0604f14b6da54afb2f6ddf7.png)
Hex Text与二进制互转
Bytes to hex string
其实就是二进制转16进制。一个字节8位,算法是将8位平均分成2部分,前面补4个0。
比如原始字节10100101,分成2个字节为{00001010, 00000101},再按照2进制转16进制,那么00001010是A,00000101是5,所以10100101的16进制为A5
用java算法表示:
第一步:对11110000取与位运算,意思是保留前4位,再右位移4位,就达到了分2段首段前面补0的目的
10100101 & 11110000 -> 10100000 >>4 -> 00001010
第二步:对00001111取与位运算,意思是保留后4位,就达到了分2段尾端前面补0的目的
10100101 & 00001111 -> 00000101
第三步:
准备下16进制的字符串"0123456789abcdef",将二进制转成10进制数字作为下标找到对应的字符
00001010 -> 10 ---> a
00000101 -> 5 ----> 5
结果:A5
hex不区分大小写,一般用大写表示:
Hex string to bytes
其实就是16进制转2进制,按理说hex text长度应该是偶数,如果是奇数那么应该是异常数据,根据情况判断要不要前面补1位0.
两两一组遍历hex string,每个字符转成对应的10进制数据{0->0,1->1,2->2,3->3,4->4,5->5,6->6,7->7,8->8,9->9,a->10,b->11,c->12,d->13,e->14,f->15},
这样每组中就会有两个10进制数字,将组中的第一位10进制数字做左位移4位之后的10进制数字与组中第二位10进制数字求和,求和后转成二进制。
比如A5B4,两两一组,即{A5, B4}, 每个字符转成10进制就是{{10,5}, {11,4}}, 每组中首位10进制数字左位移4位,10就是160, 11就是176,每组数字相加,那么就是{{160+5=165}, {176+4=180}},最后10进制转成二进制就是{10100101,10110100}
用java算法表示:
第一步:两两遍历
A5B4 -> {{A5, B4}}
第二步:转成10进制, 可以预先准备一套key value,标注字符对应的10进制数据
{A5, B4} -> {{A->10,5}, {B->11,4}} -> {{10,5}, {11,4}}
第三步:左位移4位每组的第一位10进制数字
{{10,5}, {11,4}} -> {{10 << 4 ,5}, {11 << 4,4}} -> {{160,5}, {176,4}}
第四步:每组内的10进制数据相加
{{160,5}, {176,4}} -> {{160+5}, {176+4}} -> {165, 180}
第五步:每组内的10进制数据转为二进制数据
{165, 180} -> {10100101,10110100}
结果: {10100101, 10110100}
会发现字节数比16进制的数据长度减少了一半,这个时候用base64转码这个byte数组,就可以作为文本传递。
Openssl识别ASN.1解析JWKS
EC证书获取JWK
使用openssl ec指令查看证书信息
![](https://img-blog.csdnimg.cn/8543b54ff7c84bc387ea28c78c7883d1.png)
算法描述:如下获取之后,再用base64 safe url编码即可获得jwk数据。
Openssl | Jwk |
Pub, 去掉开头04: , 剩余移除”:”的前一半 | X |
Pub, 去掉开头04: , 剩余移除”:”的后一半 | Y |
priv,去掉开头00: | d |
RSA证书获取JWK
使用openssl rsa指令查看证书信息
![](https://img-blog.csdnimg.cn/c9494a2c316e4f609d9b21e5ce784704.png)
算法描述:如下获取之后,再用base64 safe url编码即可获得jwk数据。
Openssl | Jwk |
Prime1,去掉开头00: | p |
Prime2,去掉开头00: | q |
Exponent1 | dp |
Exponent2 | dq |
coefficient | qi |
privateExponent | d |
modulus,去掉开头00: | n |
publicExponent | e |
小结
如下两篇文章基于这篇文章所编写。