如何将.p12转换为包含未加密的PKCS#1私钥块的.pem?

时间:2017-12-01 18:37:20

标签: ssl openssl pkcs#12 pkcs#1

我有一个Certificates.p12文件,我希望转换为包含PKCS#1格式的未加密私钥的certificates.pem。我以前能够通过运行:

来做到这一点
openssl pkcs12 -in Certificates.p12 -out certificates.pem -nodes -clcerts

生成的certificates.pem文件具有PRIVATE KEY PEM块,如预期的那样。但是,the library I'm using无法理解此PEM块,因为它期望它是PKCS#1私钥。 PKCS#1私钥的ASN.1结构由RFC 3447定义为:

RSAPrivateKey ::= SEQUENCE {
    version           Version,
    modulus           INTEGER,  -- n
    publicExponent    INTEGER,  -- e
    privateExponent   INTEGER,  -- d
    prime1            INTEGER,  -- p
    prime2            INTEGER,  -- q
    exponent1         INTEGER,  -- d mod (p-1)
    exponent2         INTEGER,  -- d mod (q-1)
    coefficient       INTEGER,  -- (inverse of q) mod p
    otherPrimeInfos   OtherPrimeInfos OPTIONAL
}

我的certificates.pem中的错误私钥块没有此PKCS#1结构!相反,它的ASN.1结构如下所示:

$ openssl asn1parse -i -in badprivatekey.pem
    0:d=0  hl=4 l=1212 cons: SEQUENCE
    4:d=1  hl=2 l=   1 prim:  INTEGER           :00
    7:d=1  hl=2 l=  13 cons:  SEQUENCE
    9:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
   20:d=2  hl=2 l=   0 prim:   NULL
   22:d=1  hl=4 l=1190 prim:  OCTET STRING      [HEX DUMP]:308204A...very long hex...

上述格式是什么? The documentation for openssl pkcs12只是模糊地说它的输出是“以PEM格式编写的”。我需要更强有力的保证私钥PEM块是PKCS#1格式。

奇怪的是openssl rsa理解“坏”私钥的奇怪格式,并且可以将其转换为正确的PKCS#1结构:

openssl rsa -in badprivatekey.pem -out goodprivatekey.pem

虽然openssl rsa了解输入文件,但该工具似乎无法告诉我为什么,即输入文件的格式是什么。

openssl pkcs12的输出格式是什么?具体来说,它的私钥块的格式是什么?如何让openssl pkcs12输出正确的PKCS#1私钥?

1 个答案:

答案 0 :(得分:2)

哇,那个库假设任何以PRIVATE KEY结尾的PEM必须是PKCS1 ??这是非常错误的。 有几种 xx PRIVATE KEY格式,其中只有一个是PKCS1,见下文。

Meta:我认为这是一个骗局,但我找不到它,所以无论如何回答。

OpenSSL支持RSA私钥的四种不同PEM格式:

  • '传统'或'传统'未加密,这是您想要的PKC1格式(https://tools.ietf.org/html/rfc8017#appendix-A.1.2),其中PEM类型为RSA PRIVATE KEY(不仅仅是PRIVATE KEY

    < / LI>
  • 使用OpenSSL(SSLeay)自定义方案在PEM级别加密的“传统”或“传统”,该方案使用相当差(且无法修复)的PBKDF;这具有相同的PEM类型RSA PRIVATE KEY,但添加了标题Proc-typeDEK-info

  • PKC8标准/通用未加密(https://tools.ietf.org/html/rfc5208#section-5),PEM类型为PRIVATE KEY;这是一个简单的ASN.1包装器,包含算法的标识符(即RSA的OID)加上包含算法相关部分的OCTET STRING,RSA是PKCS1

  • PKC8标准/通用加密(https://tools.ietf.org/html/rfc5208#section-6),PEM类型为ENCRYPTED PRIVATE KEY;这会加密ASN.1中的PKCS8数据,其算法通常至少默认为PBKDF2-SHA1-2048

因为PKCS8更灵活,并且是标准的(并且相当常用,例如Java),并且具有更好的加密,所以通常是优选的;请参阅the manpage for the PEM_read/write functions for keys and some but not all other things的注释部分。

读取PEM私钥的所有OpenSSL函数都可以读取其中任何一个(必要时给定正确的密码)但是它们编写的函数取决于函数和范围选项。正如您注意到pkcs12 (import)(当前)写入PKCS8,但rsa(始终)写入传统/ PKCS1。

您的选择是:

  • 使用rsa(正如您所做)或在1.1.0 pkey -traditional中转换为传统

  • 在1.0.0之前的版本中使用pkcs12,如0.9.8,当它编写传统格式时(对于多种算法而不仅仅是RSA)。当然,使用过时且不受支持的版本可能会使您遇到以后版本中修复的漏洞甚至漏洞。

  • 从(未加密或解密的)PKCS8中提取PKCS1部分。 OpenSSL使用DER作为密钥,这意味着依赖于算法的blob(最后一个组中最后一个字段的值)始终是数据的连续最后部分。举个例子:

    $ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes MAC verified OK Bag Attributes friendlyName: mykey localKeyID: 54 69 6D 65 20 31 35 31 32 31 37 30 38 39 39 33 33 37 Key Attributes: -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCnWIGH4p1FHOP2 wtVbxuyvSHpBGd2v+7AyVHG4EJ/9WRoWN4+aGYUOGxzdTyDxk9e7DCTjuY6ciNTh Ph74LADfQQ0B8yGkRtKer3vO1Dg7+6ErCcIGgsfrhZqpuUfod4nSU/LnHXoAAgN5 07LVvohrJMSRTA55jn356EDv31sz/dew1ThzHjYTShGbXh0/baqLxpmm4e8OixAL YV1glHnIdr4h6wrwkJ6TtNexc3xTLwtRf9k7pJPvg+viGh7RTqhbUcGSV+dLelNe 653LbElHtAByz4Ti9e4vUKFuzxqsaWaSYGpzxF/pdthQawV/fTa9CjLGJFFrnVqc KT3TSJ19AgMBAAECggEAOmmubRwxAVrgR9YiW3LIUzbdVbQNqcwU6LyJJVLIRcrA TFkAiy21QAM+xBFG0oxklSncBpFSslkg1a61aLMTatpuC+wuJgWCp1lhwgRZzLY8 v6UcUOF9nzx3jB7cdsyjEwOymfG0ECSjyfaXSfzD6YJgCsedldijKIRlhlVUpIS4 YvdPPGQMXxLr9K8dkQ9o5yTQCrpey1/dNEo7lS17/uMV++dxmka5J+/dRcm2AAIc 7dk6OX9MpGKPFODUyvFjdrWPR2qK25cmVW6hrhJuaPih+1eSd78UkR7OdoHBQEbJ 5MoXSO0eTV4rhid+dX+ynwXA2OvaZbxcr7rlZXjaAQKBgQDybaKW32RHVmjKQDXC xyTdQTMJV7JClBKeXjqJxbgKDhKFTiapn7kNVbJ594n7twuxmTxxoN35gamsbe7q HjEesZZvb2vgLTXnqSvSXcl32CEi554VjlNP6+jZ5JBu/Gw7qObKuWBt+/gkrtCx d09xQllZlD354RyfS3+9jzdEXQKBgQCwttL+Gw2WEm4dPQrfxbasXKQ5hNSE42j+ i0W26xv8o1lKQFip0A4YWidfI+Cvued944ZqCTvnPv6Z+JQzidHFjg6DXWgs1GK/ olsh5xO0hoxAj1azx+11ZHKSb7Kni+jSJsz40U35mWE805HFijxzzQz45unuPZGr d8oqXIcroQKBgQCKuU32w7JgWAPy6DdbVBW2Pl70E6jADHdzBDy/JdMgfdj/Sy84 lVuRU96jiJD+50nbwPIjm4gqBJaRQv8aHVjCVaDd94Zla7mS7O1UnbJxz812ac++ SglGjJpcRTyZJfzRTt9yVg3mIe9nHlnxk3J0PyFd70Rfvv9f8BYS5OcdSQKBgBnb xug0ITrSm5ZftlWkYuS58bYQ/+AqPtTwoFTx9nhzlr9MxyyiK03Y82XypBBSzdMY FjUyALgH+c2iGF2qTy3vaaRDaNkWgxSzt04wuCt0fNV9pBxOpyrEdheDjMsDqCAI WXoXdqeNkDMMaopTfiEb4kgR0i1wiP5kWwrz2zvBAoGBAPELu0IH3jtvo849KeXW O6U1QlxdmWS6h/La1iVRHoE2U3pxAj39IDx4P6GMrgc9VLqRKLTO1Cu9giimO2jH 8iryT5VTlrrINL3M4vXAFjSN/xwVsrLaw/mAQPOKBwNlDwxcCrlxnANnYXdrhk8n uNmZ2VH8flBFRpSbm9aisgMr -----END PRIVATE KEY----- $ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes \ | sed -e 1,/-BEGIN/d -e /-END/,\$d | openssl asn1parse MAC verified OK 0:d=0 hl=4 l=1214 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :00 7:d=1 hl=2 l= 13 cons: SEQUENCE 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 20:d=2 hl=2 l= 0 prim: NULL 22:d=1 hl=4 l=1192 prim: OCTET STRING [HEX DUMP]:308204A4[rest snipped] [that's PKCS8 with algo-dependent part in the OCTET STRING at offset 22] [with a tag-length header length of 4 (the hl=4)]

    您可以使用asn1parse -strparse提取PKCS1部分: $ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes \ | sed -e 1,/-BEGIN/d -e /-END/,\$d \ | openssl asn1parse -strparse 22 -out SO47599544.raw -noout MAC verified OK $ openssl asn1parse -in SO47599544.raw -inform der 0:d=0 hl=4 l=1188 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :00 7:d=1 hl=4 l= 257 prim: INTEGER :[snipped] 268:d=1 hl=2 l= 3 prim: INTEGER :010001 273:d=1 hl=4 l= 256 prim: INTEGER :[snipped] [rest snipped -- that's your PKCS1 format but in der so convert to pem] $ (echo -----BEGIN RSA PRIVATE KEY-----; openssl base64 -in SO47599544.raw; \ echo -----END RSA PRIVATE KEY-----) | tee SO47599544.pem -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAp1iBh+KdRRzj9sLVW8bsr0h6QRndr/uwMlRxuBCf/VkaFjeP mhmFDhsc3U8g8ZPXuwwk47mOnIjU4T4e+CwA30ENAfMhpEbSnq97ztQ4O/uhKwnC BoLH64WaqblH6HeJ0lPy5x16AAIDedOy1b6IayTEkUwOeY59+ehA799bM/3XsNU4 cx42E0oRm14dP22qi8aZpuHvDosQC2FdYJR5yHa+IesK8JCek7TXsXN8Uy8LUX/Z O6ST74Pr4hoe0U6oW1HBklfnS3pTXuudy2xJR7QAcs+E4vXuL1Chbs8arGlmkmBq c8Rf6XbYUGsFf302vQoyxiRRa51anCk900idfQIDAQABAoIBADpprm0cMQFa4EfW IltyyFM23VW0DanMFOi8iSVSyEXKwExZAIsttUADPsQRRtKMZJUp3AaRUrJZINWu tWizE2rabgvsLiYFgqdZYcIEWcy2PL+lHFDhfZ88d4we3HbMoxMDspnxtBAko8n2 l0n8w+mCYArHnZXYoyiEZYZVVKSEuGL3TzxkDF8S6/SvHZEPaOck0Aq6Xstf3TRK O5Ute/7jFfvncZpGuSfv3UXJtgACHO3ZOjl/TKRijxTg1MrxY3a1j0dqituXJlVu oa4Sbmj4oftXkne/FJEeznaBwUBGyeTKF0jtHk1eK4YnfnV/sp8FwNjr2mW8XK+6 5WV42gECgYEA8m2ilt9kR1ZoykA1wsck3UEzCVeyQpQSnl46icW4Cg4ShU4mqZ+5 DVWyefeJ+7cLsZk8caDd+YGprG3u6h4xHrGWb29r4C0156kr0l3Jd9ghIueeFY5T T+vo2eSQbvxsO6jmyrlgbfv4JK7QsXdPcUJZWZQ9+eEcn0t/vY83RF0CgYEAsLbS /hsNlhJuHT0K38W2rFykOYTUhONo/otFtusb/KNZSkBYqdAOGFonXyPgr7nnfeOG agk75z7+mfiUM4nRxY4Og11oLNRiv6JbIecTtIaMQI9Ws8ftdWRykm+yp4vo0ibM +NFN+ZlhPNORxYo8c80M+Obp7j2Rq3fKKlyHK6ECgYEAirlN9sOyYFgD8ug3W1QV tj5e9BOowAx3cwQ8vyXTIH3Y/0svOJVbkVPeo4iQ/udJ28DyI5uIKgSWkUL/Gh1Y wlWg3feGZWu5kuztVJ2ycc/NdmnPvkoJRoyaXEU8mSX80U7fclYN5iHvZx5Z8ZNy dD8hXe9EX77/X/AWEuTnHUkCgYAZ28boNCE60puWX7ZVpGLkufG2EP/gKj7U8KBU 8fZ4c5a/TMcsoitN2PNl8qQQUs3TGBY1MgC4B/nNohhdqk8t72mkQ2jZFoMUs7dO MLgrdHzVfaQcTqcqxHYXg4zLA6ggCFl6F3anjZAzDGqKU34hG+JIEdItcIj+ZFsK 89s7wQKBgQDxC7tCB947b6POPSnl1julNUJcXZlkuofy2tYlUR6BNlN6cQI9/SA8 eD+hjK4HPVS6kSi0ztQrvYIopjtox/Iq8k+VU5a6yDS9zOL1wBY0jf8cFbKy2sP5 gEDzigcDZQ8MXAq5cZwDZ2F3a4ZPJ7jZmdlR/H5QRUaUm5vWorIDKw== -----END RSA PRIVATE KEY-----

    或者您可以将PKCS8主体转换为二进制并且只丢弃前22 + 4 = 26个字节(因为上面第一个asn1parse中的头文件len hl = 4): $ openssl pkcs12 -in SO47599544.p12 -passin pass:sekrit -nocerts -nodes \ | sed -e 1,/-BEGIN/d -e /-END/,\$d \ | openssl base64 -d | dd bs=1 skip=26 >SO47599544.raw MAC verified OK 1192+0 records in 1192+0 records out 1192 bytes (1.2 kB) copied, 0.00892462 s, 134 kB/s [then convert to PEM with echo BEGIN;base64(encode);echo END as above]

PS:如果只读一次PKCS12很重要,例如为了避免重新输入密码,你可以使用awk之类的

openssl pkcs12 -in file.p12 | \
awk '/BEGIN PRIVATE/,/END PRIVATE/{t=t $0 RS;next}1; \
  END{process t as the whole PRIVATE KEY PEM}'

openssl pkcs12 -in file.p12 | \
awk '/BEGIN PRIVATE/{f=1;next}/END PRIVATE/{f=0;next}f{t=t $0 RS;next}1; \
    END{process t as just the base64 body}'