好的,我正在尝试使用Python验证来自PKCS7信封的数据.
我有Java中的工作代码:http://nyal.developpez.com/tutoriel/java/bouncycastle/#L4.2
我想要的是先从信封中获取证书.
我能用这个命令打开它:
openssl pkcs7 -in pkcs7 -print_certs -text
然后我想验证数据是否正常.
我试过这个:
import base64
from M2Crypto import SMIME, X509, BIO
raw_sig = """base64 PKCS7 envelop"""
msg = "challenge message to verify"
sm_obj = SMIME.SMIME()
x509 = X509.load_cert('/etc/ssl/certs/ca-certificates.crt') # public key cert used by the remote
# client when signing the message
sk = X509.X509_Stack()
sk.push(x509)
sm_obj.set_x509_stack(sk)
st = X509.X509_Store()
st.load_info('/etc/ssl/certs/ca-certificates.crt') # Public cert for the CA which signed
# the above certificate
sm_obj.set_x509_store(st)
# re-wrap signature so that it fits base64 standards
cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in xrange(0, len(raw_sig), 76))
# now, wrap the signature in a PKCS7 block
sig = """
-----BEGIN PKCS7-----
%s
-----END PKCS7-----
""" % cooked_sig
# print sig
# and load it into an SMIME p7 object through the BIO I/O buffer:
buf = BIO.MemoryBuffer(sig)
p7 = SMIME.load_pkcs7_bio(buf)
# do the same for the message text
data_bio = BIO.MemoryBuffer(msg)
cert = sm_obj.verify(p7, data_bio)
我认为其中一个/etc/ssl/certs/ca-certificates.crt应该是userCertificate.
获得证书后,我想检查它是否仍然有效(使用验证日期)并根据CRL和CPS进行验证以进行撤销.
我希望你能帮助我.
解决方法:
所以我几乎在那里:
import base64
from M2Crypto import SMIME, X509, BIO
raw_sig = """base64 PKCS7 envelop"""
msg = "challenge message to verify"
sm_obj = SMIME.SMIME()
x509 = X509.load_cert('ISSUER.crt') # public key cert used by the remote
# client when signing the message
sk = X509.X509_Stack()
sk.push(x509)
sm_obj.set_x509_stack(sk)
st = X509.X509_Store()
st.load_info('ROOT.crt') # Public cert for the CA which signed
# the above certificate
sm_obj.set_x509_store(st)
# re-wrap signature so that it fits base64 standards
cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in xrange(0, len(raw_sig), 76))
# now, wrap the signature in a PKCS7 block
sig = """
-----BEGIN PKCS7-----
%s
-----END PKCS7-----
""" % cooked_sig
# print sig
# and load it into an SMIME p7 object through the BIO I/O buffer:
buf = BIO.MemoryBuffer(sig)
p7 = SMIME.load_pkcs7_bio(buf)
signers = p7.get0_signers(sk)
certificat = signers[0]
那么您可能也对CRL和OCSP验证感兴趣:
from os.path import basename
import re
from tempfile import NamedTemporaryFile
try:
from subprocess import check_output, CalledProcessError, STDOUT
except ImportError: # check_output new in 2.7, so use a backport for <=2.6
from subprocess32 import check_output, CalledProcessError, STDOUT
class OpenSSLError(Exception):
pass
def info_extension_cert(cert):
"""
This function take a certificate and return the extensions in dict.
@type cert : M2Crypto.X509
@param cert : Certificate
"""
certificateExtensions = {}
for index in range(cert.get_ext_count()):
ext = cert.get_ext_at(index)
certificateExtensions[ext.get_name()] = ext.get_value()
return certificateExtensions
def get_cert_url_ocsp(cert):
"""
Get the OCSP url of a certificate
@type cert : M2Crypto.X509
@parm cert : Certificat
@rtype : string
@return : The OSCP url
"""
infos = [x.strip() for x in info_extension_cert(cert)["authorityInfoAccess"].split('\n')]
ocsp_url = None
for info in infos:
if re.match(r"^OCSP - URI:", info):
ocsp_url = info.replace("OCSP - URI:","")
break
return ocsp_url.strip()
def is_revoked(cert, cert_parent):
"""
Check if the certificate has been revoked.
@type cert : M2Crypto.X509
@param cert : The certificate
@type cert_parent : string
@param cert_parent : Issuer certificate file path
@rtype : boolean
@return : True if revoked or False
"""
ocsp_url = get_cert_url_ocsp(cert)
if re.match(r"^http", ocsp_url) is None:
return False
data = {'cert_parent': cert_parent,
'ocsp_url': ocsp_url,
'serial': cert.get_serial_number()}
cmd = "openssl ocsp -issuer %(cert_parent)s -CAfile %(cert_parent)s -url %(ocsp_url)s -serial %(serial)s" % data
print cmd
try:
output = check_output(cmd, shell=True, stderr=STDOUT).lower()
except CalledProcessError, e:
msg = u"[OpenSSL] Error while checking ocsp %s: %s. Output: %r" % (
cmd, e, e.output)
raise OpenSSLError(msg)
return not ('response verify ok' in output and '%s: good' % data['serial'] in output)
def is_revoked_crl(cert, cert_parent_with_crl):
"""
Check if the certificate as been revoked with the crl.
@type cert : M2Crypto.X509
@param cert : The certificate
@type cert_parent : string
@param cert_parent : Issuer certificate file path
@rtype : boolean
@return : True if revoked or False
"""
tmp_file = NamedTemporaryFile(prefix='cert')
cert.save(tmp_file.name)
data = {'cert': tmp_file.name,
'cert_parent_with_crl': cert_parent_with_crl}
cmd = "openssl verify -crl_check -CAfile %(cert_parent_with_crl)s %(cert)s" % data
print cmd
try:
output = check_output(cmd, shell=True, stderr=STDOUT).lower()
except CalledProcessError, e:
msg = u"[OpenSSL] Error while checking ocsp %s: %s. Output: %r" % (
cmd, e, e.output)
raise OpenSSLError(msg)
print output
return '%s: ok' % data['cert'] not in output
def get_cert_url_crl(cert):
"""
Return the crl url from the certificate
@type cert : M2Crypto.X509
@parm cert : Certificate
@rtype : string
@return : CRL url
"""
infos = [x.strip() for x in info_extension_cert(cert)["crlDistributionPoints"].split('\n')]
crl_url = None
for info in infos:
print info
if re.match(r"^URI:", info):
crl_url = info.replace("URI:","")
break
return crl_url.strip()
cert_parent是ROOT.crt和ISSUER.crt连接在一起的文件.
cert_parent_crl是ROOT.crt,ISSUER.crt和CRL连接在一起的文件.
要使用我使用的其他证书来连接CRL:
rm FILE.crl
wget http://URL/FILE.crl
cat ROOT_ISSUER.crt > ROOT_ISSUER_CRL.crt
echo "-----BEGIN X509 CRL-----" >> ROOT_ISSUER_CRL.crt
openssl enc -base64 -in FILE.crl >> ROOT_ISSUER_CRL.crt
echo "-----END X509 CRL-----" >> ROOT_ISSUER_CRL.crt