Python - extract certificate from p7s file











up vote
1
down vote

favorite












Decoding an incoming email in Python, I have an attachment "smime.p7s".
If I write this to a file, then it can be extracted and viewed using



openssl pkcs7 -inform der -print_certs <smime.p7s



I'd like to do that in Python. There's an example here of the inverse process, i.e. how to sign a mail.



Looking at the OpenSSL API documentation there is an entry point PKCS7_get0_signers which seems to do this.



Here's the code snippet I'm trying, based on a naive reworking of the signing code.



with open(fname, 'wb') as p7sfile:
p7sfile.write(sig)
pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)


It doesn't work - giving



pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)
TypeError: initializer for ctype 'PKCS7 *' must be a cdata pointer, not bytes


The function seems to require three parameters, although maybe flags is optional?



This line of code (from the older M2Crypto library) also suggests that entry point needs three parameters.



I don't understand why it would need a "certs.stack" as an input param when we are trying to extract the certs, and I don't understand what to put in "flags".



I'm pretty sure I need some specially typed buffer declarations to set up the call, and also retrieve the results (like the bio_in = crypto._new_mem_buf(data) preamble in 1). Can someone please suggest how to do it?



Also - the M2Crypto library is not compatible with Python 3.x, hence looking for an alternative.










share|improve this question
























  • Possible duplicate of Extract userCertificate from PKCS7 envelop in python
    – stovfl
    Nov 22 at 18:23










  • Yes, that is related. but uses the older M2Crypto library which isn't Python 3.x compatible. I found a code snippet using the PyOpenSSL library below which I'll propose as a self-answer.
    – steve
    Nov 23 at 12:25















up vote
1
down vote

favorite












Decoding an incoming email in Python, I have an attachment "smime.p7s".
If I write this to a file, then it can be extracted and viewed using



openssl pkcs7 -inform der -print_certs <smime.p7s



I'd like to do that in Python. There's an example here of the inverse process, i.e. how to sign a mail.



Looking at the OpenSSL API documentation there is an entry point PKCS7_get0_signers which seems to do this.



Here's the code snippet I'm trying, based on a naive reworking of the signing code.



with open(fname, 'wb') as p7sfile:
p7sfile.write(sig)
pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)


It doesn't work - giving



pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)
TypeError: initializer for ctype 'PKCS7 *' must be a cdata pointer, not bytes


The function seems to require three parameters, although maybe flags is optional?



This line of code (from the older M2Crypto library) also suggests that entry point needs three parameters.



I don't understand why it would need a "certs.stack" as an input param when we are trying to extract the certs, and I don't understand what to put in "flags".



I'm pretty sure I need some specially typed buffer declarations to set up the call, and also retrieve the results (like the bio_in = crypto._new_mem_buf(data) preamble in 1). Can someone please suggest how to do it?



Also - the M2Crypto library is not compatible with Python 3.x, hence looking for an alternative.










share|improve this question
























  • Possible duplicate of Extract userCertificate from PKCS7 envelop in python
    – stovfl
    Nov 22 at 18:23










  • Yes, that is related. but uses the older M2Crypto library which isn't Python 3.x compatible. I found a code snippet using the PyOpenSSL library below which I'll propose as a self-answer.
    – steve
    Nov 23 at 12:25













up vote
1
down vote

favorite









up vote
1
down vote

favorite











Decoding an incoming email in Python, I have an attachment "smime.p7s".
If I write this to a file, then it can be extracted and viewed using



openssl pkcs7 -inform der -print_certs <smime.p7s



I'd like to do that in Python. There's an example here of the inverse process, i.e. how to sign a mail.



Looking at the OpenSSL API documentation there is an entry point PKCS7_get0_signers which seems to do this.



Here's the code snippet I'm trying, based on a naive reworking of the signing code.



with open(fname, 'wb') as p7sfile:
p7sfile.write(sig)
pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)


It doesn't work - giving



pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)
TypeError: initializer for ctype 'PKCS7 *' must be a cdata pointer, not bytes


The function seems to require three parameters, although maybe flags is optional?



This line of code (from the older M2Crypto library) also suggests that entry point needs three parameters.



I don't understand why it would need a "certs.stack" as an input param when we are trying to extract the certs, and I don't understand what to put in "flags".



I'm pretty sure I need some specially typed buffer declarations to set up the call, and also retrieve the results (like the bio_in = crypto._new_mem_buf(data) preamble in 1). Can someone please suggest how to do it?



Also - the M2Crypto library is not compatible with Python 3.x, hence looking for an alternative.










share|improve this question















Decoding an incoming email in Python, I have an attachment "smime.p7s".
If I write this to a file, then it can be extracted and viewed using



openssl pkcs7 -inform der -print_certs <smime.p7s



I'd like to do that in Python. There's an example here of the inverse process, i.e. how to sign a mail.



Looking at the OpenSSL API documentation there is an entry point PKCS7_get0_signers which seems to do this.



Here's the code snippet I'm trying, based on a naive reworking of the signing code.



with open(fname, 'wb') as p7sfile:
p7sfile.write(sig)
pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)


It doesn't work - giving



pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)
TypeError: initializer for ctype 'PKCS7 *' must be a cdata pointer, not bytes


The function seems to require three parameters, although maybe flags is optional?



This line of code (from the older M2Crypto library) also suggests that entry point needs three parameters.



I don't understand why it would need a "certs.stack" as an input param when we are trying to extract the certs, and I don't understand what to put in "flags".



I'm pretty sure I need some specially typed buffer declarations to set up the call, and also retrieve the results (like the bio_in = crypto._new_mem_buf(data) preamble in 1). Can someone please suggest how to do it?



Also - the M2Crypto library is not compatible with Python 3.x, hence looking for an alternative.







python openssl cryptography pkcs#7 smime






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 at 14:23

























asked Nov 22 at 17:42









steve

356




356












  • Possible duplicate of Extract userCertificate from PKCS7 envelop in python
    – stovfl
    Nov 22 at 18:23










  • Yes, that is related. but uses the older M2Crypto library which isn't Python 3.x compatible. I found a code snippet using the PyOpenSSL library below which I'll propose as a self-answer.
    – steve
    Nov 23 at 12:25


















  • Possible duplicate of Extract userCertificate from PKCS7 envelop in python
    – stovfl
    Nov 22 at 18:23










  • Yes, that is related. but uses the older M2Crypto library which isn't Python 3.x compatible. I found a code snippet using the PyOpenSSL library below which I'll propose as a self-answer.
    – steve
    Nov 23 at 12:25
















Possible duplicate of Extract userCertificate from PKCS7 envelop in python
– stovfl
Nov 22 at 18:23




Possible duplicate of Extract userCertificate from PKCS7 envelop in python
– stovfl
Nov 22 at 18:23












Yes, that is related. but uses the older M2Crypto library which isn't Python 3.x compatible. I found a code snippet using the PyOpenSSL library below which I'll propose as a self-answer.
– steve
Nov 23 at 12:25




Yes, that is related. but uses the older M2Crypto library which isn't Python 3.x compatible. I found a code snippet using the PyOpenSSL library below which I'll propose as a self-answer.
– steve
Nov 23 at 12:25












1 Answer
1






active

oldest

votes

















up vote
0
down vote













I found a useful code snippet here. This extracts certs from a PKCS7 binary object into a list of OpenSSL.crypto.X509 objects.



The OpenSSL.crypto.X509 object is OK for dumping out the certificate contents (it has a dump_certificate method), but the attributes are hard to work with as they are still ASN.1 encoded and are C types.



Once you've got a list of certs, each can be converted into a cryptography Certificate object which is Python native and more amenable. For example:



class Cert(object):
"""
Convenient container object for human-readable and output-file friendly certificate contents
"""
pem = ''
email_signer = None
startT = None
endT = None
issuer = {}
algorithm = None


def extract_smime_signature(payload):
"""
Extract public certificates from the PKCS7 binary payload

:param payload: bytes
:return: list of Cert objects
"""
pkcs7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, payload)
certs = get_certificates(pkcs7)
certList =
# Collect the following info from the certificates
all_cert_times_valid = True
for c in certs:
# Convert to the modern & easier to use https://cryptography.io library objects
c2 = crypto.X509.to_cryptography(c)
c3 = Cert()

# check each certificate's time validity, ANDing cumulatively across each one
c3.startT = c2.not_valid_before
c3.endT = c2.not_valid_after
now = datetime.now()
all_cert_times_valid = all_cert_times_valid and (c3.startT <= now) and (now <= c3.endT)

# get Issuer, unpacking the ASN.1 structure into a dict
for i in c2.issuer.rdns:
for j in i:
c3.issuer[j.oid._name] = j.value

# get email address from the cert "subject" - consider more than one address in the bundle as an error
for i in c2.subject.rdns:
for j in i:
attrName = j.oid._name
if attrName == 'emailAddress':
c3.email_signer = j.value

# Get hash alg - just for interest
c3.algorithm = c2.signature_hash_algorithm.name
c3.pem = c2.public_bytes(serialization.Encoding.PEM).decode('utf8')
certList.append(c3)
return certList





share|improve this answer























  • The checks on the certs made in this code are overly simplistic. With access to a trusted cert bundle (such as the file "ca-bundle.crt" available in many Linuxes) it's possible to do much better than this. It's work in progress, but see github.com/tuck1s/sparkySecure/blob/master/readSMIMEsig.py
    – steve
    2 days ago











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53436023%2fpython-extract-certificate-from-p7s-file%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote













I found a useful code snippet here. This extracts certs from a PKCS7 binary object into a list of OpenSSL.crypto.X509 objects.



The OpenSSL.crypto.X509 object is OK for dumping out the certificate contents (it has a dump_certificate method), but the attributes are hard to work with as they are still ASN.1 encoded and are C types.



Once you've got a list of certs, each can be converted into a cryptography Certificate object which is Python native and more amenable. For example:



class Cert(object):
"""
Convenient container object for human-readable and output-file friendly certificate contents
"""
pem = ''
email_signer = None
startT = None
endT = None
issuer = {}
algorithm = None


def extract_smime_signature(payload):
"""
Extract public certificates from the PKCS7 binary payload

:param payload: bytes
:return: list of Cert objects
"""
pkcs7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, payload)
certs = get_certificates(pkcs7)
certList =
# Collect the following info from the certificates
all_cert_times_valid = True
for c in certs:
# Convert to the modern & easier to use https://cryptography.io library objects
c2 = crypto.X509.to_cryptography(c)
c3 = Cert()

# check each certificate's time validity, ANDing cumulatively across each one
c3.startT = c2.not_valid_before
c3.endT = c2.not_valid_after
now = datetime.now()
all_cert_times_valid = all_cert_times_valid and (c3.startT <= now) and (now <= c3.endT)

# get Issuer, unpacking the ASN.1 structure into a dict
for i in c2.issuer.rdns:
for j in i:
c3.issuer[j.oid._name] = j.value

# get email address from the cert "subject" - consider more than one address in the bundle as an error
for i in c2.subject.rdns:
for j in i:
attrName = j.oid._name
if attrName == 'emailAddress':
c3.email_signer = j.value

# Get hash alg - just for interest
c3.algorithm = c2.signature_hash_algorithm.name
c3.pem = c2.public_bytes(serialization.Encoding.PEM).decode('utf8')
certList.append(c3)
return certList





share|improve this answer























  • The checks on the certs made in this code are overly simplistic. With access to a trusted cert bundle (such as the file "ca-bundle.crt" available in many Linuxes) it's possible to do much better than this. It's work in progress, but see github.com/tuck1s/sparkySecure/blob/master/readSMIMEsig.py
    – steve
    2 days ago















up vote
0
down vote













I found a useful code snippet here. This extracts certs from a PKCS7 binary object into a list of OpenSSL.crypto.X509 objects.



The OpenSSL.crypto.X509 object is OK for dumping out the certificate contents (it has a dump_certificate method), but the attributes are hard to work with as they are still ASN.1 encoded and are C types.



Once you've got a list of certs, each can be converted into a cryptography Certificate object which is Python native and more amenable. For example:



class Cert(object):
"""
Convenient container object for human-readable and output-file friendly certificate contents
"""
pem = ''
email_signer = None
startT = None
endT = None
issuer = {}
algorithm = None


def extract_smime_signature(payload):
"""
Extract public certificates from the PKCS7 binary payload

:param payload: bytes
:return: list of Cert objects
"""
pkcs7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, payload)
certs = get_certificates(pkcs7)
certList =
# Collect the following info from the certificates
all_cert_times_valid = True
for c in certs:
# Convert to the modern & easier to use https://cryptography.io library objects
c2 = crypto.X509.to_cryptography(c)
c3 = Cert()

# check each certificate's time validity, ANDing cumulatively across each one
c3.startT = c2.not_valid_before
c3.endT = c2.not_valid_after
now = datetime.now()
all_cert_times_valid = all_cert_times_valid and (c3.startT <= now) and (now <= c3.endT)

# get Issuer, unpacking the ASN.1 structure into a dict
for i in c2.issuer.rdns:
for j in i:
c3.issuer[j.oid._name] = j.value

# get email address from the cert "subject" - consider more than one address in the bundle as an error
for i in c2.subject.rdns:
for j in i:
attrName = j.oid._name
if attrName == 'emailAddress':
c3.email_signer = j.value

# Get hash alg - just for interest
c3.algorithm = c2.signature_hash_algorithm.name
c3.pem = c2.public_bytes(serialization.Encoding.PEM).decode('utf8')
certList.append(c3)
return certList





share|improve this answer























  • The checks on the certs made in this code are overly simplistic. With access to a trusted cert bundle (such as the file "ca-bundle.crt" available in many Linuxes) it's possible to do much better than this. It's work in progress, but see github.com/tuck1s/sparkySecure/blob/master/readSMIMEsig.py
    – steve
    2 days ago













up vote
0
down vote










up vote
0
down vote









I found a useful code snippet here. This extracts certs from a PKCS7 binary object into a list of OpenSSL.crypto.X509 objects.



The OpenSSL.crypto.X509 object is OK for dumping out the certificate contents (it has a dump_certificate method), but the attributes are hard to work with as they are still ASN.1 encoded and are C types.



Once you've got a list of certs, each can be converted into a cryptography Certificate object which is Python native and more amenable. For example:



class Cert(object):
"""
Convenient container object for human-readable and output-file friendly certificate contents
"""
pem = ''
email_signer = None
startT = None
endT = None
issuer = {}
algorithm = None


def extract_smime_signature(payload):
"""
Extract public certificates from the PKCS7 binary payload

:param payload: bytes
:return: list of Cert objects
"""
pkcs7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, payload)
certs = get_certificates(pkcs7)
certList =
# Collect the following info from the certificates
all_cert_times_valid = True
for c in certs:
# Convert to the modern & easier to use https://cryptography.io library objects
c2 = crypto.X509.to_cryptography(c)
c3 = Cert()

# check each certificate's time validity, ANDing cumulatively across each one
c3.startT = c2.not_valid_before
c3.endT = c2.not_valid_after
now = datetime.now()
all_cert_times_valid = all_cert_times_valid and (c3.startT <= now) and (now <= c3.endT)

# get Issuer, unpacking the ASN.1 structure into a dict
for i in c2.issuer.rdns:
for j in i:
c3.issuer[j.oid._name] = j.value

# get email address from the cert "subject" - consider more than one address in the bundle as an error
for i in c2.subject.rdns:
for j in i:
attrName = j.oid._name
if attrName == 'emailAddress':
c3.email_signer = j.value

# Get hash alg - just for interest
c3.algorithm = c2.signature_hash_algorithm.name
c3.pem = c2.public_bytes(serialization.Encoding.PEM).decode('utf8')
certList.append(c3)
return certList





share|improve this answer














I found a useful code snippet here. This extracts certs from a PKCS7 binary object into a list of OpenSSL.crypto.X509 objects.



The OpenSSL.crypto.X509 object is OK for dumping out the certificate contents (it has a dump_certificate method), but the attributes are hard to work with as they are still ASN.1 encoded and are C types.



Once you've got a list of certs, each can be converted into a cryptography Certificate object which is Python native and more amenable. For example:



class Cert(object):
"""
Convenient container object for human-readable and output-file friendly certificate contents
"""
pem = ''
email_signer = None
startT = None
endT = None
issuer = {}
algorithm = None


def extract_smime_signature(payload):
"""
Extract public certificates from the PKCS7 binary payload

:param payload: bytes
:return: list of Cert objects
"""
pkcs7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, payload)
certs = get_certificates(pkcs7)
certList =
# Collect the following info from the certificates
all_cert_times_valid = True
for c in certs:
# Convert to the modern & easier to use https://cryptography.io library objects
c2 = crypto.X509.to_cryptography(c)
c3 = Cert()

# check each certificate's time validity, ANDing cumulatively across each one
c3.startT = c2.not_valid_before
c3.endT = c2.not_valid_after
now = datetime.now()
all_cert_times_valid = all_cert_times_valid and (c3.startT <= now) and (now <= c3.endT)

# get Issuer, unpacking the ASN.1 structure into a dict
for i in c2.issuer.rdns:
for j in i:
c3.issuer[j.oid._name] = j.value

# get email address from the cert "subject" - consider more than one address in the bundle as an error
for i in c2.subject.rdns:
for j in i:
attrName = j.oid._name
if attrName == 'emailAddress':
c3.email_signer = j.value

# Get hash alg - just for interest
c3.algorithm = c2.signature_hash_algorithm.name
c3.pem = c2.public_bytes(serialization.Encoding.PEM).decode('utf8')
certList.append(c3)
return certList






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 23 at 15:43

























answered Nov 23 at 12:32









steve

356




356












  • The checks on the certs made in this code are overly simplistic. With access to a trusted cert bundle (such as the file "ca-bundle.crt" available in many Linuxes) it's possible to do much better than this. It's work in progress, but see github.com/tuck1s/sparkySecure/blob/master/readSMIMEsig.py
    – steve
    2 days ago


















  • The checks on the certs made in this code are overly simplistic. With access to a trusted cert bundle (such as the file "ca-bundle.crt" available in many Linuxes) it's possible to do much better than this. It's work in progress, but see github.com/tuck1s/sparkySecure/blob/master/readSMIMEsig.py
    – steve
    2 days ago
















The checks on the certs made in this code are overly simplistic. With access to a trusted cert bundle (such as the file "ca-bundle.crt" available in many Linuxes) it's possible to do much better than this. It's work in progress, but see github.com/tuck1s/sparkySecure/blob/master/readSMIMEsig.py
– steve
2 days ago




The checks on the certs made in this code are overly simplistic. With access to a trusted cert bundle (such as the file "ca-bundle.crt" available in many Linuxes) it's possible to do much better than this. It's work in progress, but see github.com/tuck1s/sparkySecure/blob/master/readSMIMEsig.py
– steve
2 days ago


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53436023%2fpython-extract-certificate-from-p7s-file%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

What visual should I use to simply compare current year value vs last year in Power BI desktop

How to ignore python UserWarning in pytest?

Alexandru Averescu