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

问题描述 投票:0回答:1

我正在尝试使用 OpenSSL 和 Go 代码生成客户端证书。我有一个 OpenSSL 脚本,可以生成具有所需扩展名的证书,我想使用 Go 代码实现相同的结果。

使用 OpenSSL

options.ext

OpenSSL 使用的 options.ext 文件包含以下扩展名:

basicConstraints=CA:FALSE
authorityKeyIdentifier=keyid,issuer
subjectKeyIdentifier=hash
keyUsage=digitalSignature
extendedKeyUsage=clientAuth

生成客户端证书.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 Authority Key Identifier 扩展。这是我的 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 和 serial 添加到 X509v3 Authority Key Identifier?

相关

当我尝试这个时:

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
go x509certificate asn.1 authoritykeyidentifier
1个回答
0
投票

authorityKeyIdentifierValue
可以用asn1.Marshal生成。下面的演示根据
RFC 5280
定义结构 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解码器等工具解码

© www.soinside.com 2019 - 2024. All rights reserved.