Home > Backend Development > Golang > How to add DirName and Serial Number to X509v3 Authorization Key Identifier

How to add DirName and Serial Number to X509v3 Authorization Key Identifier

王林
Release: 2024-02-10 10:54:08
forward
1050 people have browsed it

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

php editor Strawberry will introduce you how to add DirName and serial number to the X509v3 authorization key identifier. In network communications, an authorization key identifier (X509v3) is a digital certificate used to verify the identity of the communicating party. DirName refers to the name of the certificate holder, while the serial number is the number used to uniquely identify the certificate. By adding DirName and serial number, the readability and uniqueness of the certificate can be increased, and the security and reliability of communication can be improved. Next, we will explain in detail how to do this.

Question content

I am trying to generate a client certificate using openssl and go code. I have an openssl script that generates a certificate with the required extension and I want to achieve the same result using go code.

Use openssl

options.ext

The options.ext file used by openssl contains the following extensions:

basicconstraints=ca:false
authoritykeyidentifier=keyid,issuer
subjectkeyidentifier=hash
keyusage=digitalsignature
extendedkeyusage=clientauth
Copy after login

Generate-client-cert.sh

The openssl script I currently have is as follows:

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
Copy after login

After generating the certificate, I can view its details using the following command:

openssl x509 -in cert.crt -text -noout
Copy after login

The generated certificate has the following structure:

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
Copy after login

It should look like this:

x509v3 authority key identifier: 
    dirname:cn=xxx
    serial:xx:xx:xx:xx:xx:xx:xx:xx
Copy after login

Execution code

In my go code, I use the x509 package to generate the certificate. However, I'm not sure how to set up the x509v3 authorization key identifier extension. Here is the relevant part of my go code:

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
Copy after login

How do I add the dirname and serial number to the x509v3 authorization key identifier?

Related

  • http://oid-info.com/get/2.5.29.35
  • https://github.com/golang/go/issues/47096 (original issue)

When I try this:

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)...)
...
Copy after login

turn out:

X509v3 Authority Key Identifier:
    0....0...<....).!.r[..F.....".hCN=xxx.....$...D
Copy after login

Solution

authoritykeyidentifiervalue can be generated using asn1.marshal. The following demonstration defines a struct authkeyid > according to rfc 5280

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))
}
Copy after login

The hexadecimal encoding value is:

30548014e58e3c0c9f7a2d05958774bf68d27fe921b2fe3ea12aa4283026310f300d060355040a13064d79204f7267311330110603550403130a4d7920526f6f7420434182101a80a30c937563aac65846d75bc57c30
Copy after login

Hexadecimal strings can be obtained using a javascript decoder such as asn.1 :

The following c# demo gives the same result:

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();
    }
}
Copy after login

renew:

This is an updated version of gen which includes the email address:

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,
    })
}
Copy after login

Please note that oid is deprecated (see http://oid-info.com/get/1.2.840.113549.1.9.1). .net doesn't include it either.

The above is the detailed content of How to add DirName and Serial Number to X509v3 Authorization Key Identifier. For more information, please follow other related articles on the PHP Chinese website!

source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template