無法使用自訂 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,template
和parent
參數是相同的。
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.sha384withrsa 或x509.sha512withrsa,而是sha256withrsapss、sha384withrsapss 和sha512withrsapss。
簽約愉快。
以上是無法使用自訂 crypto.Signer 實作產生 X.509 證書的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

1、okx歐易交易所網頁版進入☜☜☜☜☜點擊保存2、okx歐易交易所app鏈接點擊☜☜☜☜☜點擊保存3、 進入官網後,清晰的界面提供登錄和註冊入口,用戶可根據自身情況選擇登錄已有賬戶或註冊新賬戶。 無論是查看實時行情、進行交易,還是管理資產,OKX網頁版都提供簡潔流暢的操作體驗,適合新手和老手使用。 立即訪問OKX官網,體驗便

本文提供了一份詳細的Gate.io新手註冊教程,涵蓋了從訪問官網到完成註冊的每一個步驟,包括填寫註冊信息、進行驗證、閱讀用戶協議等。文章還強調了註冊成功後的安全措施,如設置二次驗證和完成實名認證,並給出了新手提示,幫助用戶安全地開啟數字資產交易之旅。

歐易(OKX)是一個全球性的數字資產交易平台,主要功能包括:1. 買賣數字資產(現貨交易),2. 進行數字資產之間的交易,3. 提供市場行情和數據,4. 提供多樣化的交易產品(如衍生品),5. 提供資產增值相關服務,6. 方便資產管理。

本文詳細介紹瞭如何使用OK交易所官方網頁版進行登錄。用戶只需在瀏覽器搜索“OK交易所官方網頁版”,進入官網後點擊右上角的登錄按鈕,輸入用戶名和密碼即可登錄。 註冊用戶可輕鬆管理資產、進行交易及資金存取等操作。官網界面簡潔易用,並提供完善的客服支持,確保用戶獲得流暢的數字資產交易體驗。 還在等什麼?立即訪問OK交易所官方網站,開啟您的數字資產之旅!

本文提供Binance幣安電腦版登錄與註冊的完整指南。首先,詳細講解了幣安電腦版登錄步驟:在瀏覽器搜索“幣安官網”,點擊登錄按鈕,輸入郵箱和密碼(啟用2FA需輸入驗證碼)即可登錄。其次,文章闡述了註冊流程:點擊“註冊”按鈕,填寫郵箱地址,設置強密碼,驗證郵箱即可完成註冊。最後,文章還特別強調了賬戶安全,提醒用戶注意官方域名、網絡環境以及定期更新密碼,確保賬戶安全,更好地使用幣安電腦版提供的各項功能,例如查看行情、進行交易和管理資產。

本文推薦十個知名的虛擬幣相關APP推薦網站,涵蓋幣安學院(Binance Academy)、OKX Learn、CoinGecko、CryptoSlate、CoinDesk、Investopedia、CoinMarketCap、火幣大學(Huobi University)、Coinbase Learn和CryptoCompare。這些網站不僅提供虛擬貨幣市場數據、價格走勢分析等信息,還提供豐富的學習資源,包括區塊鏈基礎知識、交易策略、以及各個交易平台APP的使用教程和評測,幫助用戶更好地了解和使

本文推荐十家主流加密货币交易所,包括币安、OKX、芝麻开门(gate.io)、Coinbase、Kraken、Bitstamp、Gemini、Bittrex、KuCoin和Bitfinex。 这些交易所各有优势,例如币安以其全球最大交易量和丰富的币种选择著称;OKX则提供创新工具如网格交易和多种衍生品;Coinbase主打美国合规性;Kraken以其高安全性与质押收益吸引用户;其他交易所则在不同方面如法币交易、山寨币交易、高频交易工具等方面各有特色。 选择适合自己的交易所,需根据自身投资经验

全球用户量排名前列,支持现货、合约、Web3钱包等全品类交易,安全性高且手续费低。历史悠久的综合交易平台,以合规性和高流动性著称,支持多语言服务。行业龙头,覆盖币币交易、杠杆、期权等,流动性强且支持BNB抵扣费用。
