Skip to content

Instantly share code, notes, and snippets.

@jessepeterson
Created February 23, 2016 22:08
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jessepeterson/52f66951608ff8471b12 to your computer and use it in GitHub Desktop.
Save jessepeterson/52f66951608ff8471b12 to your computer and use it in GitHub Desktop.
Python PKCS#7 degenerate certificates (like `openssl crl2pkcs7`) using ctypes
#!/usr/bin/python
from M2Crypto import X509, BIO, m2
import os
from ctypes import CDLL
from ctypes import *
from ctypes.util import find_library
class PKCS7_SIGNED(Structure):
# no fields here to support a recursive structure
pass
class PKCS7_d(Union):
_fields_ = [
('ptr', c_char_p),
('data', c_void_p),
('sign', POINTER(PKCS7_SIGNED)),
('enveloped', c_void_p),
('signed_and_enveloped', c_void_p),
('digest', c_void_p),
('encrypted', c_void_p),
('other', c_void_p),
]
class PKCS7(Structure):
_fields_ = [
('asn1', c_char_p),
('length', c_long),
('state', c_int),
('detached', c_int),
('type', c_char_p), #
('d', PKCS7_d),
]
class X509_CRL(Structure):
_fields_ = [
('crl', c_void_p),
('sig_alg', c_void_p),
('signature', c_void_p),
('references', c_int),
]
# assign fields after class definition due to recursive references
PKCS7_SIGNED._fields_ = [
('version', c_void_p),
('md_algs', c_void_p),
('cert', c_void_p),
('crl', POINTER(X509_CRL)),
('signer_info', c_void_p),
('contents', POINTER(PKCS7)),
]
ossl = CDLL(find_library('crypto'))
PKCS7_new = ossl.PKCS7_new
PKCS7_new.argtypes = []
PKCS7_new.restype = POINTER(PKCS7)
PKCS7_set_type = ossl.PKCS7_set_type
PKCS7_set_type.argtypes = [POINTER(PKCS7), c_int]
PKCS7_set_type.restype = c_int
i2d_PKCS7_bio = ossl.i2d_PKCS7_bio
i2d_PKCS7_bio.argtypes = [c_void_p, POINTER(PKCS7)]
i2d_PKCS7_bio.restype = c_int
X509_CRL_new = ossl.X509_CRL_new
X509_CRL_new.argtypes = []
X509_CRL_new.restype = POINTER(X509_CRL)
def degenerate_pkcs7_der(stack):
# TODO: memory management! need to free some stuff here. (i.e. this code
# will leak as is)
p7 = PKCS7_new()
# memset(p7, 0, sizeof(PKCS7())) # didn't seem to be needed here
# set object type, ASN.1 defaults, and make included PKCS7_SIGNED struct
PKCS7_set_type(p7, m2.PKCS7_SIGNED)
crl = X509_CRL_new()
# seemed to be needed to prevent segfault (i.e. OpenSSL source has
# *_new_null() macros/functions that presuambly do this for us)
memset(crl, 0, sizeof(X509_CRL()))
# get pointer to M2Crypto X509_Stack
ct_ptr_x509stack = cast(stack.stack.__long__(), c_void_p)
# assign the inner PKCS7_SIGNED object our crl and cert. stack
p7.contents.d.sign.contents.crl = crl
p7.contents.d.sign.contents.cert = ct_ptr_x509stack
# new M2Crypto BIO MemoryBuffer
p7buf = BIO.MemoryBuffer()
ct_ptr_p7buf = cast(p7buf._ptr().__long__(), c_void_p)
i2d_PKCS7_bio(ct_ptr_p7buf, p7)
return p7buf.read()
if __name__ == '__main__':
stack = X509.X509_Stack()
if os.path.exists('s.crt'):
stack.push(X509.load_cert('s.crt'))
if os.path.exists('s2.crt'):
stack.push(X509.load_cert('s2.crt'))
dp7d = degenerate_pkcs7_der(stack)
# dump our base64 encoded DER-encoded PKCS#7 "degenerate" certificate
print '-----BEGIN PKCS7-----'
print dp7d.encode('base64').rstrip()
print '-----END PKCS7-----'
# should be able to do something like:
# ./crl2pkcs7.py | openssl pkcs7 -text -print_certs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment