X509證書中RSA公鑰的提取與載入


 

原文鏈接: http://blog.chinaunix.net/uid-16515626-id-2741894.html

 
由於項目需要,我計划利用openssl開發一個基本的CA,實現證書的發放等功能。在項目模型中公私鑰對是用戶自己產生的,並且以16進制數的形似提交給CA。我們知道,通常利用openssl頒發證書時,公私鑰對往往也是由openssl產生的,比如利用以下三個函數
RSA_generate_key
EVP_PKEY_assign_RSA
X509_set_pubkey
  便可以輕松搞定從密鑰產生到載入證書的過程,而提取證書公鑰只需
X509_get_pubkey
  如何將16進制形式的rsa公鑰載證書的卻沒有相關介紹,經過幾天的研究終於搞定了,貼出來與大家分享,我們可以利用下面的函數
  RSA* d2i_RSAPublicKey(NULL,(const unsigned **) pp,int len)
  其中*pp指向存儲公鑰的內存單元,len指公鑰的長度,請注意這里的公鑰是指經過ASN.1編碼的公鑰,關於此編碼方法,要想全面闡述是相當復雜的,但如果僅限於編rsa公鑰,則會簡單很多,以下是1024位rsa公鑰的ASN.1編碼的十六進制描述,共占據140bytes:
30 81 89 02 81 81 00 e3 8d 99 06 9f bd 9a c0 e5 
6a 5d 03 b3 cf 09 ca 8e c1 4a 6c f9 90 c2 46 e0 
89 44 69 cd a5 62 91 42 8a 5f e5 8f d3 fb 93 3f 
bc d7 6e 5e f2 80 41 a6 79 78 8e 4d 1d 3d 65 ad 
d4 36 9c c5 83 55 9d f1 bb 20 4c b7 6c 95 37 b0 
37 06 e3 40 fb 8f 74 c3 59 91 a2 bf a2 e1 db 99 
54 29 5f 9b a5 57 f5 40 7a 54 82 9c 84 d4 35 86 
14 38 69 14 60 f3 c6 c7 11 75 f2 43 2c 34 ed 89 
4a ae e1 9d 57 3e a1 02 03 01 00 01
  ASN.1采用Tag,Lenth,Value,編碼方式,在此將整個編為一個sequence,可以理解為結構體,以30作為開始標志,第二位81代表后面有1字節代表長度,即89代表長度(若為82則代表后面有兩字節代表長度,依次類推),轉化成十進制為137,正好與后面的字節數吻合,從第四位02開始便是此sequence的內涵,相當於結構體的元素,一般來說sequence往往需要嵌套,相當於結構體嵌結構體,但對公鑰的sequence來說,此處僅有一層。
  第四位02代表一下的內容為bit流,同樣緊隨其后的81代表有一字節代表長度,第六位的81代表長度為129,即從00開始直到最后一行a1此為129字節,去掉前面的00,余下128位便是rsa公鑰的N值,最后5個字節同樣是bit流,以02開始,03表示長度為3,最后的01 00 01 便是rsa公鑰的E值。
  關於為什么要在N值前補00,這可能是ASN.1的規定,若bit流的前四bit十六進制值小於8就要在在最前補零,看下面的例子
30 81 88 02 81 80 32 8d 99 06 9f bd 9a c0 e5 6a 
5d 03 b3 cf 09 ca 8e c1 4a 6c f9 90 c2 46 e0 89 
44 69 cd a5 62 91 42 8a 5f e5 8f d3 fb 93 3f bc 
d7 6e 5e f2 80 41 a6 79 78 8e 4d 1d 3d 65 ad d4 
36 9c c5 83 55 9d f1 bb 20 4c b7 6c 95 37 b0 37 
06 e3 40 fb 8f 74 c3 59 91 a2 bf a2 e1 db 99 54 
29 5f 9b a5 57 f5 40 7a 54 82 9c 84 d4 35 86 14 
38 69 14 60 f3 c6 c7 11 75 f2 43 2c 34 ed 89 4a 
ae e1 9d 57 3e a1 02 03 01 00 01
N的前四bit為0x3小於8,因此無需補零。
  關於什么情況下要在tag值之后用8X標明有幾位代表length,我的理解是,如果length的前四bit大於8或超過一字節,則必需用8X標明,否則不用。
  言規正傳,了解了rsa公鑰的編碼規則,我們便可以方便的將用其他工具產生的rsa公鑰編為openssl可接受的碼型,從而完成公鑰的導入,對於公鑰的提取,同樣有函數
  int i2d_RSAPublicKey(RSA *,(const char **))
  返回值為公鑰的長度,當然是經ASN.1編碼后的。
  完成了bit流與RSA的轉化,剩下的工作便有很輕松了,在此在介紹幾種簡便方法,可以直接在bit與EVP_PKEY之間轉化
  導出:
  len=i2d_RSAPublicKey(pkey->pkey.rsa,(const char**)pp);
  導入要多幾步:
  pkey->save_type=6;
  pkey->type=EVP_PKEY_type(6);
  pkey->pkey.rsa=d2i_RSAPublicKey(NULL,(const char**)pp,len);
  其中pkey的定義為EVP_PKEY *pkey;
  導入過程中前兩行的作用是設定采用的密碼算法為rsa,若采用bit-〉rsa-〉pkey模式,這個工作由EVP_PKEY_assign_RSA替我們做了。
  我接觸openssl4個月了,以上我的經驗總結,歡迎大家批評指正。
 
 
 
 
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM