Python 3 - 从X509证书中提取公钥并使用它加密
因为M2Crypto这个库在Python 3中不可用,所以我想找个办法来读取一个X509证书,从中提取公钥,然后用它进行RSA加密。
我现在有以下两个函数:
from ssl import PEM_cert_to_DER_cert # standard library
from Crypto.Util import asn1 # http://pycrypto.org
from OpenSSL.crypto import * # https://pythonhosted.org/pyOpenSSL/
def extract_publickey_1(certstr):
""" from http://stackoverflow.com/questions/12911373 """
der = PEM_cert_to_DER_cert(certstr)
cert = asn1.DerSequence()
cert.decode(der)
tbs = asn1.DerSequence()
tbs.decode(cert[0])
return tbs[6]
def extract_publickey_2(certstr):
return dump_privatekey(FILETYPE_ASN1,
load_certificate(FILETYPE_PEM, certstr).get_pubkey())
第一个函数在处理某些证书时会出现IndexError
错误,特别是那些不是通过命令行的OpenSSL生成的证书,而是通过一些加密库生成的(我测试过Python和C#的库)。对于通过命令行OpenSSL生成的证书,这个函数是可以正常工作的。
我检查了第二个函数的输出,发现它和第一个函数的输出不完全相同,但最后的266个字节是相等的:
extract_publickey_1(certstr)[-266:] == extract_publickey_2(certstr)[-266:]
返回True
。
我的问题是,这到底是怎么回事?有没有解决办法?
1 个回答
4
首先,你得明白,X.509证书是用ASN.1格式编码的,这意味着它里面包含了很多层次和各种不同的值。这种层次结构和数据类型可能是随意的,即使在DER模式下也是如此。所以,期待某个字段在固定的位置和固定的形式出现是很天真的,特别是当涉及到文本字符串时;更不用说使用“魔法常量”总是个坏主意。因此,你应该尽量使用专门的函数,比如get_pubkey()
,而不是像你用asn1
类那样自己去解析复杂的文档。
其次,你要理解,由于X.509规范与算法无关,所以并没有“RSA模数”、“RSA公钥指数”等特定字段。相反,只有一个通用的“公钥”字段,里面有一组嵌套的子字段——这些子字段指定了算法的OID和它的数值属性。例如,RSA公钥有两个属性:模数n
和加密指数e
;另外,你的extract_publickey_2()
函数前面还加了一个总是为零的属性,我也不知道它代表什么。很有可能你的RSA实现需要的是数字参数,而不是字节数组或复杂的ASN.1值,所以你可能需要用asn1.DerSequence.decode()
或者更专门的RSA函数来提取它们。