首頁 >後端開發 >Golang >如何將 DirName 和序號新增至 X509v3 授權金鑰標識符

如何將 DirName 和序號新增至 X509v3 授權金鑰標識符

王林
王林轉載
2024-02-10 10:54:081044瀏覽

如何将 DirName 和序列号添加到 X509v3 授权密钥标识符

php小編草莓將為您介紹如何將DirName和序號加入X509v3授權金鑰標識符。在網路通訊中,授權金鑰標識符(X509v3)是一種數位證書,用於驗證通訊方的身分。 DirName指的是憑證持有者的名稱,而序號是用於唯一識別憑證的編號。透過新增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 定义了 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 也不包含它。

以上是如何將 DirName 和序號新增至 X509v3 授權金鑰標識符的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除