搜尋
首頁後端開發Golang無法使用自訂 crypto.Signer 實作產生 X.509 證書

无法使用自定义 crypto.Signer 实现生成 X.509 证书

php小編柚子在這裡為大家介紹一個關於產生 X.509 憑證的問題。有時在使用自訂 crypto.Signer 實作產生憑證的過程中,可能會遇到一個無法使用的問題。這個問題可能會讓開發者感到困惑,不知道該如何解決。在本文中,我們將探討這個問題的原因,並提供一些解決方案,以幫助開發者順利產生自己的 X.509 憑證。

問題內容

我正在嘗試根據儲存在 hsm 中的 rsa 金鑰對產生 x.509 憑證。我使用此 pkcs #11 實作與我的 hsm 進行通訊。

由於我的加密物件儲存在後者中,如果我想要執行的操作需要私鑰(例如簽署),我必須實作 crypto.signer 介面才能「存取私鑰」 。這是這個實作。

type rsasigner struct {
    privatekey p11.privatekey
    publickey  *rsa.publickey
}

func (s rsasigner) public() crypto.publickey {
    return s.publickey
}

func (s rsasigner) sign(_ io.reader, digest []byte, _ crypto.signeropts) ([]byte, error) {
    return s.privatekey.sign(pkcs11.mechanism{mechanism: pkcs11.ckm_sha512_rsa_pkcs}, digest)
}

func newrsasigner(privatekey p11.privatekey) (*rsasigner, error) {
    var (
        modulus, publicexponent []byte
        err                     error
    )

    // retrieve modulus n from the private key
    // reminder: n = p * q
    modulus, err = p11.object(privatekey).attribute(pkcs11.cka_modulus)
    if err != nil {
        return nil, err
    }

    // retrieve public exponent (e: "always" 65537) from the private key
    // reminder: φ(n) = (p - 1) * (q - 1), e such that 1 < e < φ(n) and e and φ(n) are co prime
    publicexponent, err = p11.object(privatekey).attribute(pkcs11.cka_public_exponent)
    if err != nil {
        return nil, err
    }

    // public key is (e, n)
    publickey := &rsa.publickey{
        n: new(big.int).setbytes(modulus),
        e: int(big.newint(0).setbytes(publicexponent).uint64()),
    }

    return &rsasigner{privatekey: privatekey, publickey: publickey}, nil
}

這個實作有效。例如,要建立 csr,createcertificaterequest 函數需要私鑰來簽署 csr(priv any 參數),這是我提供 rsasigner 實例的地方。

createcertificate函數有些類似,參數pub是要產生的憑證的公鑰,priv是簽署者的私鑰。

在下面的程式碼中,我嘗試產生自簽名的x.509證書,因此根據api,templateparent參數是相同的。

func (t *token) x509(id, objecttype, output string) ([]time.duration, error) {
    startfunction := time.now()

    var (
        keytype            int
        privatekeytemplate []*pkcs11.attribute
        privatekeyobject   p11.object
        err                error
        timings            []time.duration
        signer             *rsasigner
        cert               []byte
        file               *os.file
        writtenbytes       int
    )

    objecttype = strings.tolower(objecttype)

    if objecttype != "rsa" && objecttype != "ec" {
        logger.fatalf("%s: unrecognized type, it can only be equal to rsa or ec", objecttype)
    }

    switch objecttype {
    case "rsa":
        keytype = pkcs11.ckk_rsa
    case "ec":
        keytype = pkcs11.ckk_ec
    }

    // creation of the template to find the private key based on the given id (pkcs #11 attribute cka_id)
    privatekeytemplate = []*pkcs11.attribute{
        pkcs11.newattribute(pkcs11.cka_key_type, keytype),
        pkcs11.newattribute(pkcs11.cka_class, pkcs11.cko_private_key),
        pkcs11.newattribute(pkcs11.cka_id, id),
    }

    startfindobject := time.now()
    privatekeyobject, err = t.session.findobject(privatekeytemplate)
    timings = append(timings, time.since(startfindobject))
    if err != nil {
        return nil, err
    }

    // creation of the x.509 certificate template
    certtemplate := &x509.certificate{
        serialnumber: big.newint(2023),
        subject: pkix.name{
            commonname: "test",
        },
        signaturealgorithm: x509.sha512withrsa,
        notbefore:          time.now(),
        notafter:           time.now().adddate(1, 0, 0),
    }

    // instantiate the rsasigner with the found private key object
    signer, err = newrsasigner(p11.privatekey(privatekeyobject))
    if err != nil {
        return nil, err
    }

    startcreatecert := time.now()
    cert, err = x509.createcertificate(rand.reader, certtemplate, certtemplate, signer.publickey, signer)
    timings = append(timings, time.since(startcreatecert))
    if err != nil {
        return nil, err
    }

    file, err = os.create(output)
    if err != nil {
        return nil, err
    }

    writtenbytes, err = file.write(cert)
    if err != nil {
        return nil, err
    }

    logger.printf("wrote %d bytes in %s", writtenbytes, output)

    return append(timings, time.since(startfunction)), nil
}

無論金鑰類型(rsa 或 ec)為何,此函數都會傳回下列錯誤。

FATA[2022-12-22 10:48:50] x509: signature over certificate returned by signer is invalid: crypto/rsa: verification error

如果 crypto.signer 實作未正確完成,則會傳回此錯誤。

我實作了 crypto.signer 來嘗試使用橢圓曲線上的金鑰對執行相同的操作,但錯誤是相同的。

我還在 sign 函數中嘗試了不同的雜湊演算法,但它沒有改變任何東西。

該錯誤似乎來自 crypto.signer 的實現,儘管它可以用於生成 csr。

解決方法

儘管我幾個月前就已經找到了這個問題的解決方案,但我從未花時間分享答案,但是,現在是時候了。

當我們直接透過pkcs #11 進行簽名時,我們需要透過使用此處引用的digestinfo 值手動為雜湊添加前綴來管理雜湊前綴:https://www .rfc-editor.org/rfc/rfc3447#page-43

更精確地說,對於 rsassa-pkcs1-v1_5 簽名,實際簽名函數的輸入是 asn.1 der 編碼的結構。 pkcs #11 具有特定於哈希的機制(例如ckm_sha256_rsa_pkcs),它們知道如何產生該結構,但它們都假設資料未經過哈希處理,而加密貨幣的情況並非如此。 signer 接口,因此我們必須使用通用的 cka_rsa_pkcs 機制,該機制僅執行原始簽名操作。這意味著我們必須自己產生 asn.1 結構,只需為我們可能想要使用的所有雜湊值提供正確的前綴即可做到這一點。

借助crypto.signeropts類型的opts參數,我們可以在以下情況下檢索crypto.hash類型的雜湊函數的識別碼:調用sign() 函數,並套用正確的前綴。

type signer struct {
    prikey p11.privatekey
    pubkey *rsa.publickey
}

var hashprefixes = map[crypto.hash][]byte{
    crypto.sha256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
    crypto.sha384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
    crypto.sha512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
}

func (s signer) public() crypto.publickey {
    return s.pubkey
}

func (s signer) sign(_ io.reader, digest []byte, opts crypto.signeropts) ([]byte, error) {
    return s.prikey.sign(*pkcs11.newmechanism(pkcs11.ckm_rsa_pkcs, nil), append(hashprefixes[opts.hashfunc()], digest...))
}

func newsigner(key p11.privatekey) (*signer, error) {
    // retrieve modulus n from the private key
    // reminder: n = p * q
    modulus, err := p11.object(key).attribute(pkcs11.cka_modulus)
    if err != nil {
        return nil, err
    }

    var pubexp []byte
    // retrieve public exponent (e: "always" 65537) from the private key
    // reminder: φ(n) = (p - 1) * (q - 1), e such that 1 < e < φ(n) and e and φ(n) are co prime
    pubexp, err = p11.object(key).attribute(pkcs11.cka_public_exponent)
    if err != nil {
        return nil, err
    }

    // public key is (e, n)
    pubkey := &rsa.publickey{
        n: new(big.int).setbytes(modulus),
        e: int(new(big.int).setbytes(pubexp).uint64()),
    }

    return &signer{prikey: key, pubkey: pubkey}, nil
}

它就像一個魅力。不過,還有更好的事要做。

ckm_rsa_pkcs機制提供rsassa-pkcs1-v1_5類型的簽章。我留給有興趣的讀者自己研究這個舊的簽名方案,該方案不應再在新產品/軟體中使用。

確實,建議使用ckm_rsa_pkcs_pss機制,它提供rsassa-pss類型的簽章。

從這個原則出發,這是我現在使用的實作。

type Signer struct {
    priKey p11.PrivateKey
    pubKey *rsa.PublicKey
}

var sigAlg = map[crypto.Hash]uint{
    crypto.SHA256: pkcs11.CKM_SHA256_RSA_PKCS_PSS,
    crypto.SHA384: pkcs11.CKM_SHA384_RSA_PKCS_PSS,
    crypto.SHA512: pkcs11.CKM_SHA512_RSA_PKCS_PSS,
}

var mgf = map[crypto.Hash]uint{
    crypto.SHA256: pkcs11.CKG_MGF1_SHA256,
    crypto.SHA384: pkcs11.CKG_MGF1_SHA384,
    crypto.SHA512: pkcs11.CKG_MGF1_SHA512,
}

func (s Signer) Public() crypto.PublicKey {
    return s.pubKey
}

func (s Signer) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
    return s.priKey.Sign(*pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS_PSS, pkcs11.NewPSSParams(sigAlg[opts.HashFunc()], mgf[opts.HashFunc()], uint(opts.HashFunc().Size()))), digest)
}

func NewSigner(key p11.PrivateKey) (*Signer, error) {
    // Retrieve modulus n from the private key
    // Reminder: n = p * q
    modulus, err := p11.Object(key).Attribute(pkcs11.CKA_MODULUS)
    if err != nil {
        return nil, err
    }

    var pubExp []byte
    // Retrieve public exponent (e: "always" 65537) from the private key
    // Reminder: φ(n) = (p - 1) * (q - 1), e such that 1 < e < φ(n) and e and φ(n) are co prime
    pubExp, err = p11.Object(key).Attribute(pkcs11.CKA_PUBLIC_EXPONENT)
    if err != nil {
        return nil, err
    }

    // Public key is (e, n)
    pubKey := &rsa.PublicKey{
        N: new(big.Int).SetBytes(modulus),
        E: int(new(big.Int).SetBytes(pubExp).Uint64()),
    }

    return &Signer{priKey: key, pubKey: pubKey}, nil
}

因此不再需要前綴,但是需要雜湊演算法識別碼和要使用的簽章演算法以及要使用的mgf之間的對應關係。

最後,在go中,使用的簽名演算法不再是x509.sha256withrsa、x509.sha384withrsax509.sha512withrsa,而是sha256withrsapsssha384withrsapsssha512withrsapss

簽約愉快。

以上是無法使用自訂 crypto.Signer 實作產生 X.509 證書的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:stackoverflow。如有侵權,請聯絡admin@php.cn刪除
HOO交易所可以提现USDT吗?提现流程步骤是怎样的?HOO交易所可以提现USDT吗?提现流程步骤是怎样的?Jan 30, 2024 pm 08:42 PM

HOO交易所备受关注,尤其是其USDT提现功能。以下将从多个角度分析HOO交易所提现流程步骤。什么是HOO交易所?HOO交易所是一个创新的加密货币交易平台,提供多样化的数字资产交易服务。作为一个知名的交易所,HOO以其高效的交易执行和丰富的交易品种而备受用户青睐。HOO交易所是否支持USDT提现?HOO交易所允许用户将持有的USDT提现至其他钱包地址或平台,从而实现USDT资金的转移。这一功能使得用户可以将USDT转换为其他货币或进行其他交易操作。HOO交易所USDT提现流程步骤第一步:登录账户

Ripple正在寻找加密货币ETF开发经理!福克斯记者:优先推出XRP现货ETF,接着是期货Ripple正在寻找加密货币ETF开发经理!福克斯记者:优先推出XRP现货ETF,接着是期货Jan 28, 2024 am 08:15 AM

在经过长达10年的反复拒绝后,美国证券交易委员会(SEC)终于批准了美国比特币现货ETF。这个决定引发了市场对推出其他加密货币ETF的期待,包括以太坊和XRP等。本站(120BTc.coM)将继续关注这一动态,为投资者提供及时的市场分析和信息。今日X账号@3TGMCrypto发现,Ripple正在纽约招聘一位资深经理人,主要负责推动与加密货币相关的ETF计划,这似乎意味着该公司有可能申请XRPETF。FoxBusiness记者:期货ETF是推出现货ETF的前置步骤社群对XRP期货ETF和现货ET

世界知名usdt交易所排名前十 盘点十大usdt交易所世界知名usdt交易所排名前十 盘点十大usdt交易所Jan 31, 2024 am 08:03 AM

世界知名USDT交易所排名前十USDT(Tether)是一种基于比特币区块链技术的数字货币,与美元挂钩,被广泛应用于加密货币交易。USDT交易所是提供USDT交易服务的平台,随着加密货币市场的不断发展,各国涌现了许多知名的USDT交易所。本文将盘点并深度分析全球排名前十的USDT交易所。1.币安(Binance)币安是全球最大的USDT交易所,也是市值最高的加密货币交易所之一。成立于2017年的币安,凭借强大的技术支持、丰富的交易品种和良好的用户体验,迅速成为行业领军者。币安拥有全球用户基础,提

USDT属于什么币种深度解析USDT属于什么币种深度解析Jan 30, 2024 pm 02:13 PM

全称为Tether(泰达币)。是一种基于区块链技术的数字加密货币,也是一种稳定币。其特点是与法定货币美元一比一挂钩,即每枚USDT币的价值与1美元等值。

如何购买SUI币?SUI币购买和交易所教程如何购买SUI币?SUI币购买和交易所教程Jan 30, 2024 pm 01:54 PM

SUI币相对较为陌生,它具备并行处理简单交易的能力。SUI币采用对象为中心的数据模型,使得数字资产及其属性能够存在于链上和智能合约以外。此外,SUI币还能在需求增加的情况下,以稳定且低廉的费用进行水平扩展。SUI币怎么买?购买SUI币的流程简单。以币安交易所为例,下面是买入和交易SUI币的教程:1.注册币安账户并完成身份验证。2.充值您的币安账户,选择合适的充值方式(如银行转账、加密货币转账等)。3.登录币安交易所,搜索SUI币并选择交易对。4.在交易页面选择买入选项,并输入您想要购买的SUI1

币安下架的币如何操作提现?币安下架的币如何处理?币安下架的币如何操作提现?币安下架的币如何处理?Jan 30, 2024 pm 01:27 PM

我们知道,每天都会有新的币种上线,交易所也会对一些没有发展前景或者有重大问题的币种进行下架处理。币种的上架和下架在交易所中是很正常的操作。币安下架的币怎么提现?为了向全球用户提供优质的投资选择,币安交易所会定期追踪审查已上线的币种,并下架不符合标准的项目和交易对。同时,如果您还没有账号,请点击注册一个账号。币安通常会在下架某个币种之前发布公告和发送邮件通知持有该币种的用户。提醒用户在下架前及时完成提现或资产置换,以避免财产损失。币安将停止支持下架币种的充值、提现和交易服务。如果您需要提现下架币,

欧盟加大力度打击加密货币洗钱行为:对1000欧元以上的交易进行尽职调查欧盟加大力度打击加密货币洗钱行为:对1000欧元以上的交易进行尽职调查Jan 24, 2024 pm 12:30 PM

欧盟理事会今日宣布,与欧洲议会达成临时协议,就“打击洗钱的综合监管方案”部分内容达成一致。按照协议,所有加密货币公司将被要求对其客户进行尽职调查,以更有效地保护欧盟公民和金融体系免受洗钱和恐怖主义融资的威胁。这一举措旨在加强监管措施,确保洗钱和恐怖主义融资等非法活动得到更有效的打击。比利时财政部长VincentVanPeteghem表示,这项协议是欧盟新反洗钱体系的重要组成部分,旨在提高各国反洗钱和反恐融资体系的组织和协作能力。通过该协议,欧盟成员国将能够更好地合作,防止欺诈者、有组织犯罪分子和

易优usdt交易所易优usdt交易所Jan 30, 2024 pm 08:12 PM

易优USDT交易所是一家专注于数字货币交易的知名平台。作为一家全球领先的加密货币交易平台,易优USDT交易所以其安全、便捷和稳定的数字货币交易服务而闻名。用户可以在该平台上进行多种数字货币的交易,并享受到高效的交易执行速度和可靠的资金安全保障。易优USDT交易所致力于为全球用户提供优质的数字资产交易环境,为他们的投资和交易活动提供良好的易优USDT交易所以其卓越的安全性备受赞誉。该交易所采取了多重防护措施来保障用户账户的安全。其中之一是采用冷钱包来存储大部分用户的数字资产,这样可以将用户的资产隔

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。