当前位置:首页 > 文章列表 > Golang > Go问答 > 向 X509v3 授权密钥标识符添加 DirName 和序列号的方法

向 X509v3 授权密钥标识符添加 DirName 和序列号的方法

来源:stackoverflow 2024-02-10 16:18:24 0浏览 收藏

本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《向 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学习网公众号吧!

版本声明
本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
mac文件格式转换技巧mac文件格式转换技巧
上一篇
mac文件格式转换技巧
了解 Go 中的 net 包中使用的“接口”一词的含义
下一篇
了解 Go 中的 net 包中使用的“接口”一词的含义
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • PPTFake答辩PPT生成器:一键生成高效专业的答辩PPT
    PPTFake答辩PPT生成器
    PPTFake答辩PPT生成器,专为答辩准备设计,极致高效生成PPT与自述稿。智能解析内容,提供多样模板,数据可视化,贴心配套服务,灵活自主编辑,降低制作门槛,适用于各类答辩场景。
    23次使用
  • SEO标题Lovart AI:全球首个设计领域AI智能体,实现全链路设计自动化
    Lovart
    SEO摘要探索Lovart AI,这款专注于设计领域的AI智能体,通过多模态模型集成和智能任务拆解,实现全链路设计自动化。无论是品牌全案设计、广告与视频制作,还是文创内容创作,Lovart AI都能满足您的需求,提升设计效率,降低成本。
    21次使用
  • 美图AI抠图:行业领先的智能图像处理技术,3秒出图,精准无误
    美图AI抠图
    美图AI抠图,依托CVPR 2024竞赛亚军技术,提供顶尖的图像处理解决方案。适用于证件照、商品、毛发等多场景,支持批量处理,3秒出图,零PS基础也能轻松操作,满足个人与商业需求。
    34次使用
  • SEO标题PetGPT:智能桌面宠物程序,结合AI对话的个性化陪伴工具
    PetGPT
    SEO摘要PetGPT 是一款基于 Python 和 PyQt 开发的智能桌面宠物程序,集成了 OpenAI 的 GPT 模型,提供上下文感知对话和主动聊天功能。用户可高度自定义宠物的外观和行为,支持插件热更新和二次开发。适用于需要陪伴和效率辅助的办公族、学生及 AI 技术爱好者。
    34次使用
  • 可图AI图片生成:快手可灵AI2.0引领图像创作新时代
    可图AI图片生成
    探索快手旗下可灵AI2.0发布的可图AI2.0图像生成大模型,体验从文本生成图像、图像编辑到风格转绘的全链路创作。了解其技术突破、功能创新及在广告、影视、非遗等领域的应用,领先于Midjourney、DALL-E等竞品。
    56次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码