数字证书实战经验——ASN.1语法及JWKS

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)
Boolean0x01flag Boolean; flag:: true0x01 01 01
Integer0x02Age Integer; Age :: 180x02 01 12
BIT_STRING0x03Bits BIT String; bits::{1,0,0,0,1,1,1,0,1,0,0,1}0x03 03 04 8E 90
Octet_string0x04Octect_string::0x04 length {octect string}0x04 length {octect string}
NULL0x05Null NULL; 0x05 00
OID0x061.2.840.113549.2.50x06 08 2A 86 48 86 F7 0D 02 05
Sequence0x30sequence::=0x30 length{asndata}*0x30 length {asndata}*
Set0xA3Set:: 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
RSA

EC
EC

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指令查看证书信息

EC获取hex_string(priv, pub)

算法描述:如下获取之后,再用base64 safe url编码即可获得jwk数据。

OpensslJwk
Pub, 去掉开头04: , 剩余移除”:”的前一半X
Pub, 去掉开头04: , 剩余移除”:”的后一半Y
priv,去掉开头00:d

RSA证书获取JWK

使用openssl rsa指令查看证书信息

RSA获取hex_string

算法描述:如下获取之后,再用base64 safe url编码即可获得jwk数据。

Openssl Jwk
Prime1,去掉开头00:p
Prime2,去掉开头00:q
Exponent1dp
Exponent2dq
coefficientqi
privateExponentd
modulus,去掉开头00:n
publicExponente

小结

如下两篇文章基于这篇文章所编写。

Java SunEC实现JWT JWK ES256 导入导出PEM

Lua openssl 实现 EC JWT JWK ES256

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

车联网服务端架构

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

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

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

打赏作者

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

抵扣说明:

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

余额充值