You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用spacemonkeygo/openssl签名证书时SKID与AKID异常问题排查

问题分析与解决:spacemonkeygo/openssl签名证书SKID异常导致自签发判定

问题根源

  1. SKID被错误复用:spacemonkeygo/openssl的SetIssuer方法存在默认逻辑漏洞——直接将颁发者证书的Subject Key Identifier(SKID)复用为新证书的SKID,导致新证书的SKID与颁发者KeyID完全一致,触发自签发判定。
  2. 缺失颁发者标识扩展:如果不调用SetIssuer,新证书的SKID虽能正常生成,但会缺少必要的Authority Key Identifier(AKID)扩展,导致证书链验证不通过,最终显示无效。

解决方法

核心思路是手动控制SKID和AKID扩展的生成,绕过库的默认错误逻辑,确保两个扩展的取值符合X.509规范:

1. 手动生成并设置SKID扩展

从新证书的公钥计算SKID(标准逻辑是取公钥DER编码的SHA-1哈希前20字节),通过AddExtension手动添加,覆盖库的默认错误值。

2. 正确配置AKID扩展

从颁发者证书中提取其SKID作为AKID的keyIdentifier字段,同时补充颁发者的DN和序列号,确保验证逻辑能正确识别证书链。

示例代码

package main

import (
    "crypto/sha1"
    "fmt"
    "strings"

    "github.com/spacemonkeygo/openssl"
)

func SignCSR(csr *openssl.CertificateRequest, issuerCert *openssl.Certificate, issuerKey *openssl.PrivateKey, serial []byte, notBefore, notAfter openssl.Asn1Time) (*openssl.Certificate, error) {
    cert, err := openssl.NewCertificateFromCSR(csr)
    if err != nil {
        return nil, err
    }

    // 设置基础证书字段
    cert.SetIssuer(issuerCert.SubjectName())
    cert.SetSubject(csr.Subject())
    cert.SetNotBefore(notBefore)
    cert.SetNotAfter(notAfter)
    cert.SetSerialNumber(serial)

    // 手动生成SKID:从新证书公钥计算
    pubKey, err := cert.PublicKey()
    if err != nil {
        return nil, err
    }
    pubKeyDER, err := pubKey.MarshalPKIXPublicKey()
    if err != nil {
        return nil, err
    }
    skidHash := sha1.Sum(pubKeyDER)
    skidExt, err := openssl.NewExtension("subjectKeyIdentifier", fmt.Sprintf("hash:%x", skidHash[:]))
    if err != nil {
        return nil, err
    }
    cert.AddExtension(skidExt)

    // 手动生成AKID:从颁发者证书提取SKID,补充颁发者信息
    issuerSkidExt, err := issuerCert.GetExtension("subjectKeyIdentifier")
    if err != nil {
        return nil, err
    }
    issuerSkid := strings.TrimPrefix(issuerSkidExt.Value(), "hash:")
    akidValue := fmt.Sprintf("keyid:%s,issuer:dirName:%s,serial:%x",
        issuerSkid,
        issuerCert.SubjectName().String(),
        issuerCert.SerialNumber().Bytes())
    akidExt, err := openssl.NewExtension("authorityKeyIdentifier", akidValue)
    if err != nil {
        return nil, err
    }
    cert.AddExtension(akidExt)

    // 用颁发者私钥签名证书
    if err := cert.Sign(issuerKey, openssl.EVP_SHA256); err != nil {
        return nil, err
    }

    return cert, nil
}

验证方法

签名完成后,用OpenSSL命令检查证书字段:

openssl x509 -in signed_cert.pem -text -noout

确认:

  • Subject Key Identifier与颁发者证书的Subject Key Identifier不同
  • Authority Key Identifier中的keyid与颁发者证书的SKID一致,且包含正确的颁发者DN和序列号

内容的提问来源于stack exchange,提问作者Sergey Kolesnik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 03:10:48