Python - extract certificate from p7s file





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







1















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 '18 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 '18 at 12:25


















1















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 '18 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 '18 at 12:25














1












1








1








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 '18 at 14:23







steve

















asked Nov 22 '18 at 17:42









stevesteve

476




476













  • Possible duplicate of Extract userCertificate from PKCS7 envelop in python

    – stovfl
    Nov 22 '18 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 '18 at 12:25



















  • Possible duplicate of Extract userCertificate from PKCS7 envelop in python

    – stovfl
    Nov 22 '18 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 '18 at 12:25

















Possible duplicate of Extract userCertificate from PKCS7 envelop in python

– stovfl
Nov 22 '18 at 18:23





Possible duplicate of Extract userCertificate from PKCS7 envelop in python

– stovfl
Nov 22 '18 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 '18 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 '18 at 12:25












1 Answer
1






active

oldest

votes


















0














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
    Dec 11 '18 at 22:59












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',
autoActivateHeartbeat: false,
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









0














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
    Dec 11 '18 at 22:59
















0














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
    Dec 11 '18 at 22:59














0












0








0







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 '18 at 15:43

























answered Nov 23 '18 at 12:32









stevesteve

476




476













  • 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
    Dec 11 '18 at 22:59



















  • 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
    Dec 11 '18 at 22:59

















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
Dec 11 '18 at 22:59





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
Dec 11 '18 at 22:59




















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.




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

How to send String Array data to Server using php in android

Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

Is anime1.com a legal site for watching anime?