向 X509v3 授权密钥标识符添加 DirName 和序列号的方法
来源:stackoverflow
时间:2024-02-10 16:18:24 137浏览 收藏
本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《向 X509v3 授权密钥标识符添加 DirName 和序列号的方法》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~
我正在尝试使用 openssl 和 go 代码生成客户端证书。我有一个 openssl 脚本,可以生成具有所需扩展名的证书,并且我想使用 go 代码实现相同的结果。
使用 openssl
选项.ext
openssl 使用的 options.ext 文件包含以下扩展名:
basicconstraints=ca:false authoritykeyidentifier=keyid,issuer subjectkeyidentifier=hash keyusage=digitalsignature extendedkeyusage=clientauth
生成-client-cert.sh
我目前拥有的openssl脚本如下:
openssl req \ -newkey rsa:2048 \ -keyout cert.crt \ -out cert.csr \ -nodes \ -sha256 openssl x509 \ -req \ -ca ca.crt \ -cakey ca.key \ -in cert.csr \ -out cert.crt \ -days 365 \ -cacreateserial \ -extfile options.ext \ -sha256
生成证书后,我可以使用以下命令查看其详细信息:
openssl x509 -in cert.crt -text -noout
生成的证书具有以下结构:
certificate:
data:
version: 3 (0x2)
serial number:
xx:xx:xx:xx:xx:xx:xx:xx
signature algorithm: sha256withrsaencryption
issuer: cn=xxx
validity
not before: jan 1 00:00:00 2023 gmt
not after : jan 1 00:00:00 2024 gmt
subject: cn=xxx
subject public key info:
public key algorithm: rsaencryption
rsa public-key: (2048 bit)
modulus:
...
exponent: 65537 (0x10001)
x509v3 extensions:
x509v3 basic constraints:
ca:false
x509v3 authority key identifier:
dirname:cn=xxx
serial:xx:xx:xx:xx:xx:xx:xx:xx
x509v3 subject key identifier:
...
x509v3 key usage:
digital signature
x509v3 extended key usage:
tls web client authentication
signature algorithm: sha256withrsaencryption
它应该看起来像这样:
x509v3 authority key identifier:
dirname:cn=xxx
serial:xx:xx:xx:xx:xx:xx:xx:xx
执行代码
在我的 go 代码中,我使用 x509 包来生成证书。但是,我不确定如何设置 x509v3 授权密钥标识符扩展。这是我的 go 代码的相关部分:
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"os"
"time"
)
...
var cacertificate *x509.certificate
var caprivatekey *rsa.privatekey
var authoritykeyidentifiervalue []byte // how to write this?
template := &x509.certificate{
subject: pkix.name{
commonname: "xxx",
},
extraextensions: []pkix.extension{
{
id: asn1.objectidentifier{2, 5, 29, 35},
value: authoritykeyidentifiervalue,
},
},
keyusage: x509.keyusagedigitalsignature,
extkeyusage: []x509.extkeyusage{x509.extkeyusageclientauth},
notbefore: time.now(),
notafter: time.now().adddate(0, 0, 365),
isca: false,
basicconstraintsvalid: true,
}
privatekey, err := rsa.generatekey(rand.reader, 2048)
if err != nil {
// err
}
certificatebytes, err := x509.createcertificate(rand.reader, template, cacertificate, &privatekey.publickey, caprivatekey)
if err != nil {
// err
}
// out
如何将 dirname 和序列号添加到 x509v3 授权密钥标识符?
相关
- http://oid-info.com/get/2.5.29.35
- https://github.com/golang/go/issues/47096(原始问题)
当我尝试这个时:
var capublickeybytes []byte
publickeyhash := (sha1.sum(capublickeybytes))[:]
var dirname string
authoritykeyidentifiervalue := []byte{0x30, len(publickeyhash)}
authoritykeyidentifiervalue = append(authoritykeyidentifiervalue, publickeyhash...)
authoritykeyidentifiervalue = append(authoritykeyidentifiervalue, 0x80, len(dirname))
authoritykeyidentifiervalue = append(authoritykeyidentifiervalue, []byte(dirname)...)
...
结果是:
X509v3 Authority Key Identifier:
0....0...<....).!.r[..F.....".hCN=xxx.....$...D正确答案
authoritykeyidentifiervalue 可以使用 asn1.marshal 生成。下面的演示根据 rfc 5280定义了 struct authkeyid > 并使用此结构生成值:
package main
import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/hex"
"encoding/pem"
"fmt"
"math/big"
)
// rfc 5280, a.2. implicitly tagged module, 1988 syntax
//
// authoritykeyidentifier ::= sequence {
// keyidentifier [0] keyidentifier optional,
// authoritycertissuer [1] generalnames optional,
// authoritycertserialnumber [2] certificateserialnumber optional }
// -- authoritycertissuer and authoritycertserialnumber must both
// -- be present or both be absent
type authkeyid struct {
keyidentifier []byte `asn1:"optional,tag:0"`
authoritycertissuer generalnames `asn1:"optional,tag:1"`
authoritycertserialnumber *big.int `asn1:"optional,tag:2"`
}
// rfc 5280, a.2. implicitly tagged module, 1988 syntax
//
// generalnames ::= sequence size (1..max) of generalname
//
// generalname ::= choice {
// othername [0] anothername,
// rfc822name [1] ia5string,
// dnsname [2] ia5string,
// x400address [3] oraddress,
// directoryname [4] name,
// edipartyname [5] edipartyname,
// uniformresourceidentifier [6] ia5string,
// ipaddress [7] octet string,
// registeredid [8] object identifier }
type generalnames struct {
name []pkix.rdnsequence `asn1:"tag:4"`
}
func gen(issuer *x509.certificate) ([]byte, error) {
return asn1.marshal(authkeyid{
keyidentifier: issuer.subjectkeyid,
authoritycertissuer: generalnames{name: []pkix.rdnsequence{issuer.issuer.tordnsequence()}},
authoritycertserialnumber: issuer.serialnumber,
})
}
func main() {
cacert := `-----begin certificate-----
miibotccauegawibagiqgocjdjn1y6rgwebxw8v8mdakbggqhkjopqqdajammq8w
dqydvqqkewznesbpcmcxezarbgnvbamtck15ifjvb3qgq0ewhhcnmjmwnte2mtqy
ntuwwhcnmjmwnte3mtuyntuwwjammq8wdqydvqqkewznesbpcmcxezarbgnvbamt
ck15ifjvb3qgq0ewwtatbgcqhkjopqibbggqhkjopqmbbwncaarzqz2ka7fi6w9/
32sjhtajrke+vqyx7hfnmtx1inpbajnfvonf2silh5nqms50jpnvgivehtbfl0a0
dcurufhno1cwvtaobgnvhq8baf8ebamcaqqwewydvr0lbawwcgyikwybbquhawew
dwydvr0taqh/bauwaweb/zadbgnvhq4efgqu5y48dj96lqwvh3s/anj/6sgy/j4w
cgyikozizj0eawidsaawrqihanqdh6sgz014wvfdh0zhbeghdb2tqxzujxa7ymo3
80unaiapzp4wlzqlb+j4fipnep+txru01jgfaksml2yhv3mewg==
-----end certificate-----`
b, _ := pem.decode([]byte(cacert))
if b == nil {
panic("couldn't decode test certificate")
}
issuer, err := x509.parsecertificate(b.bytes)
if err != nil {
panic(err)
}
authoritykeyidentifiervalue, err := gen(issuer)
if err != nil {
panic(err)
}
fmt.println(hex.encodetostring(authoritykeyidentifiervalue))
}
十六进制编码值为:
30548014e58e3c0c9f7a2d05958774bf68d27fe921b2fe3ea12aa4283026310f300d060355040a13064d79204f7267311330110603550403130a4d7920526f6f7420434182101a80a30c937563aac65846d75bc57c30
十六进制字符串可以使用诸如 asn.1 javascript 解码器:
以下 c# 演示给出相同的结果:
using system.security.cryptography.x509certificates;
using system.text;
internal class program
{
private static void main(string[] args)
{
var certbytes = encoding.ascii.getbytes(@"-----begin certificate-----
miibotccauegawibagiqgocjdjn1y6rgwebxw8v8mdakbggqhkjopqqdajammq8w
dqydvqqkewznesbpcmcxezarbgnvbamtck15ifjvb3qgq0ewhhcnmjmwnte2mtqy
ntuwwhcnmjmwnte3mtuyntuwwjammq8wdqydvqqkewznesbpcmcxezarbgnvbamt
ck15ifjvb3qgq0ewwtatbgcqhkjopqibbggqhkjopqmbbwncaarzqz2ka7fi6w9/
32sjhtajrke+vqyx7hfnmtx1inpbajnfvonf2silh5nqms50jpnvgivehtbfl0a0
dcurufhno1cwvtaobgnvhq8baf8ebamcaqqwewydvr0lbawwcgyikwybbquhawew
dwydvr0taqh/bauwaweb/zadbgnvhq4efgqu5y48dj96lqwvh3s/anj/6sgy/j4w
cgyikozizj0eawidsaawrqihanqdh6sgz014wvfdh0zhbeghdb2tqxzujxa7ymo3
80unaiapzp4wlzqlb+j4fipnep+txru01jgfaksml2yhv3mewg==
-----end certificate-----");
using var issuer = new x509certificate2(certbytes);
var e = x509authoritykeyidentifierextension.createfromcertificate(issuer, true, true);
console.writeline(bytearraytohex(e.rawdata));
}
private static string bytearraytohex(byte[] bytes)
{
var builder = new stringbuilder(bytes.length * 2);
for (int i = 0; i < bytes.length; i++)
{
builder.append($"{bytes[i]:x2}");
}
return builder.tostring();
}
}
更新:
这是 gen 的更新版本,其中包含电子邮件地址:
func gen(issuer *x509.Certificate) ([]byte, error) {
rdnSequence := issuer.Issuer.ToRDNSequence()
if len(issuer.EmailAddresses) > 0 {
oidEmail := asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}
emails := make([]pkix.AttributeTypeAndValue, len(issuer.EmailAddresses))
for i, value := range issuer.EmailAddresses {
emails[i].Type = oidEmail
emails[i].Value = value
}
rdnSequence = append(rdnSequence, emails)
}
return asn1.Marshal(authKeyId{
KeyIdentifier: issuer.SubjectKeyId,
AuthorityCertIssuer: generalNames{Name: []pkix.RDNSequence{rdnSequence}},
AuthorityCertSerialNumber: issuer.SerialNumber,
})
}
请注意,oid 已弃用(请参阅 http://oid- info.com/get/1.2.840.113549.1.9.1)。 .net 也不包含它。
理论要掌握,实操不能落!以上关于《向 X509v3 授权密钥标识符添加 DirName 和序列号的方法》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
139 收藏
-
204 收藏
-
325 收藏
-
478 收藏
-
486 收藏
-
439 收藏
-
357 收藏
-
352 收藏
-
101 收藏
-
440 收藏
-
212 收藏
-
143 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习