如何在python中修改PEM格式证书的签名

时间:2019-09-21 02:53:04

标签: python certificate x509 signature pem

是否可以使用python修改PEM编码的x509证书的签名?

我尝试使用加密python模块,但似乎无法设置x509签名属性。我只能得到它的价值。是否有另一个python模块可能对此更好用?

加密python模块文档在这里: https://cryptography.io/en/latest/x509/reference/#x-509-certificate-object

from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import Encoding
import os

#change the signature of the cert
def change_cert_sig(pem_data):
    cert = x509.load_pem_x509_certificate(pem_data, default_backend())
    #the line below works
    print(cert.signature)
    #the line below causes an exception "AttributeError: can't set attribute"
    cert.set_signature(os.urandom(len(cert.signature))) #set signature to random bytes
    return cert.public_bytes(Encoding.PEM)

3 个答案:

答案 0 :(得分:1)

  

是否可以使用python修改PEM编码的x509证书的签名?

是的

我不是Python专家,所以我只能描述该怎么做...将证书读入内存。这是来自RFC 5280, Appendix A, p. 116 (and friends)的证书的ASN.1结构:

Certificate  ::=  SEQUENCE  {
     tbsCertificate       TBSCertificate,
     signatureAlgorithm   AlgorithmIdentifier,
     signature            BIT STRING  }

tbsCertificate是颁发者(或证书颁发机构)签名的内容。 “ TBS” 表示“要签名”。 signature是发行人在tbsCertificate上的签名。 signatureAlgorithm描述了所使用的签名算法,例如sha256WithRSAEncryption

跳到第三个属性,即signature BIT STRING。前4个八位位组是BIT_STRING的ASN.1编码的一部分。八位字节5-37是签名字节。拿一个签名字节并篡改它。像Byte b = data[6]b ^= 0x01然后是data[6] = b之类的东西。

由于signature是证书中的最后一项内容,因此您应该可以篡改文件中的最后32个字节。最后的32个字节是签名。 (32字节假定使用SHA-256进行签名)。

答案 1 :(得分:1)

这不是小事。

您正在呼叫cert.public_bytes(Encoding.PEM),它具有以下源代码:

def public_bytes(self, encoding):
    bio = self._backend._create_mem_bio_gc()
    if encoding is serialization.Encoding.PEM:
        res = self._backend._lib.PEM_write_bio_X509(bio, self._x509)
    elif encoding is serialization.Encoding.DER:
        res = self._backend._lib.i2d_X509_bio(bio, self._x509)
    else:
        raise TypeError("encoding must be an item from the Encoding enum")

    self._backend.openssl_assert(res == 1)
    return self._backend._read_mem_bio(bio)

这将转到PEM_write_bio_X509,它实际上是用C实现的,可以通过CFFI访问。

传递给它的参数._x509只是一个数据blob:

In [25]: c._x509
Out[25]: <cdata 'X509 *' 0x7f8608d08890>

这意味着要修改现有对象中的签名,您必须找到内存位置并覆盖该内存位置...

那将是非常错误的。

您会发现cryptography是底层库(如OpenSSL)的薄薄补片。默认情况下,它不会为您提供所有详细信息。正确的方法是将证书的X.509表示形式分解为一堆字段,然后添加,删除,修改这些字段,然后将其回滚到X.509。

但是,由于这太难了,请观看:

pd  # PEM data as a string
'-----BEGIN CERTIFICATE-----\nMIIC [snip] 1Q=\n-----END CERTIFICATE-----\n'

b64 = "".join([bit for bit in pd.split() if "---" not in bit])
pemdata = binascii.a2b_base64(b64)

cert.signature in pemdata
True

因此,恰好证书签名在cert blob中占据了一定范围的字节,因此,让我们尝试对其进行更改:

pemdata.find(cert.signature)
423
len(cert.signature)
128
fakesig = b"\x42" * len(cert.signature)
fakecertdata = pemdata[:423] + fakesig + pemdata[423 + 128:]
with open("fake.pem", "wb") as fout:
    fout.write(b"-----BEGIN CERTIFICATE-----\n")
    fout.write(base64.encodebytes(fakecertdata))
    fout.write(b"-----END CERTIFICATE-----\n")

瞧瞧!

> openssl x509 -in fake.pem -text -noout
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: [snip]
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: [snip]
        Validity [snip]
        Subject: [snip]
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (1024 bit)
                Modulus:
                    00: [snip] :55
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha1WithRSAEncryption
         42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:
         42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:
         42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:
         42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:
         42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:
         42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:
         42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:42:
         42:42

答案 2 :(得分:0)

根据签名算法,@Dima Tisnek 的答案可能并不总是有效。例如,椭圆曲线 P-256 签名包含 ASN.1 整数,这些整数可能会或可能不会根据其值进行修剪。

这是调整ASN.1结构的位串和序列长度的修改版本:

let char = 'm';

rightSide.score += rightSide[char];

Microchip/Atmel 的 Compressed Certificate Definition 的第 3.2 节详细解释了所需修改。