Skip to content

Commit a0c510a

Browse files
authored
Merge pull request #385 from sigmavirus24/move-to-cryptography
Swap pycrypto* for pyca/cryptography
2 parents 08815f9 + afdf5b4 commit a0c510a

File tree

4 files changed

+42
-86
lines changed

4 files changed

+42
-86
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
'paste',
1515
'zope.interface',
1616
'repoze.who',
17-
'pycryptodomex',
17+
'cryptography',
1818
'pytz',
1919
'pyOpenSSL',
2020
'python-dateutil',

src/saml2/cert.py

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
from OpenSSL import crypto
99
from os.path import join
1010
from os import remove
11-
from Cryptodome.Util import asn1
11+
12+
from cryptography.hazmat.backends import default_backend
13+
from cryptography.x509 import load_pem_x509_certificate
14+
15+
backend = default_backend()
1216

1317
class WrongInput(Exception):
1418
pass
@@ -194,9 +198,8 @@ def write_str_to_file(self, file, str_data):
194198
f.close()
195199

196200
def read_str_from_file(self, file, type="pem"):
197-
f = open(file, 'rt')
198-
str_data = f.read()
199-
f.close()
201+
with open(file, 'rb') as f:
202+
str_data = f.read()
200203

201204
if type == "pem":
202205
return str_data
@@ -336,31 +339,13 @@ def verify(self, signing_cert_str, cert_str):
336339
cert_algorithm = cert.get_signature_algorithm()
337340
if six.PY3:
338341
cert_algorithm = cert_algorithm.decode('ascii')
342+
cert_str = cert_str.encode('ascii')
339343

340-
cert_asn1 = crypto.dump_certificate(crypto.FILETYPE_ASN1, cert)
341-
342-
der_seq = asn1.DerSequence()
343-
der_seq.decode(cert_asn1)
344-
345-
cert_certificate = der_seq[0]
346-
#cert_signature_algorithm=der_seq[1]
347-
cert_signature = der_seq[2]
348-
349-
cert_signature_decoded = asn1.DerObject()
350-
cert_signature_decoded.decode(cert_signature)
351-
352-
signature_payload = cert_signature_decoded.payload
353-
354-
sig_pay0 = signature_payload[0]
355-
if ((isinstance(sig_pay0, int) and sig_pay0 != 0) or
356-
(isinstance(sig_pay0, str) and sig_pay0 != '\x00')):
357-
return (False,
358-
"The certificate should not contain any unused bits.")
359-
360-
signature = signature_payload[1:]
344+
cert_crypto = load_pem_x509_certificate(cert_str, backend)
361345

362346
try:
363-
crypto.verify(ca_cert, signature, cert_certificate,
347+
crypto.verify(ca_cert, cert_crypto.signature,
348+
cert_crypto.tbs_certificate_bytes,
364349
cert_algorithm)
365350
return True, "Signed certificate is valid and correctly signed by CA certificate."
366351
except crypto.Error as e:

src/saml2/entity.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
from binascii import hexlify
88
from hashlib import sha1
99

10-
# from Crypto.PublicKey import RSA
11-
from Cryptodome.PublicKey import RSA
12-
1310
from saml2.metadata import ENDPOINTS
1411
from saml2.profile import paos, ecp
1512
from saml2.soap import parse_soap_enveloped_saml_artifact_resolve

src/saml2/sigver.py

Lines changed: 30 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,13 @@
1919

2020
from future.backports.urllib.parse import urlencode
2121

22-
# from Crypto.PublicKey.RSA import importKey
23-
# from Crypto.Signature import PKCS1_v1_5
24-
# from Crypto.Util.asn1 import DerSequence
25-
# from Crypto.PublicKey import RSA
26-
# from Crypto.Hash import SHA
27-
# from Crypto.Hash import SHA224
28-
# from Crypto.Hash import SHA256
29-
# from Crypto.Hash import SHA384
30-
# from Crypto.Hash import SHA512
31-
32-
from Cryptodome.PublicKey.RSA import importKey
33-
from Cryptodome.Signature import PKCS1_v1_5
34-
from Cryptodome.Util.asn1 import DerSequence
35-
from Cryptodome.PublicKey import RSA
36-
from Cryptodome.Hash import SHA
37-
from Cryptodome.Hash import SHA224
38-
from Cryptodome.Hash import SHA256
39-
from Cryptodome.Hash import SHA384
40-
from Cryptodome.Hash import SHA512
22+
from cryptography.exceptions import InvalidSignature
23+
from cryptography.hazmat.backends import default_backend
24+
from cryptography.hazmat.primitives import hashes
25+
from cryptography.hazmat.primitives.asymmetric import rsa
26+
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
27+
from cryptography.hazmat.primitives.serialization import load_pem_private_key
28+
from cryptography.x509 import load_pem_x509_certificate
4129

4230
from tempfile import NamedTemporaryFile
4331
from subprocess import Popen
@@ -87,6 +75,8 @@
8775
PREFIX1 = "<?xml version='1.0' encoding='UTF-8'?>"
8876
PREFIX2 = '<?xml version="1.0" encoding="UTF-8"?>'
8977

78+
backend = default_backend()
79+
9080

9181
class SigverError(SAMLError):
9282
pass
@@ -406,18 +396,10 @@ def active_cert(key):
406396
"""
407397
try:
408398
cert_str = pem_format(key)
409-
try:
410-
certificate = importKey(cert_str)
411-
not_before = to_time(str(certificate.get_not_before()))
412-
not_after = to_time(str(certificate.get_not_after()))
413-
assert not_before < utc_now()
414-
assert not_after > utc_now()
415-
return True
416-
except:
417-
cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_str)
418-
assert cert.has_expired() == 0
419-
assert not OpenSSLWrapper().certificate_not_valid_yet(cert)
420-
return True
399+
cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_str)
400+
assert cert.has_expired() == 0
401+
assert not OpenSSLWrapper().certificate_not_valid_yet(cert)
402+
return True
421403
except AssertionError:
422404
return False
423405
except AttributeError:
@@ -555,19 +537,8 @@ def rsa_eq(key1, key2):
555537

556538

557539
def extract_rsa_key_from_x509_cert(pem):
558-
# Convert from PEM to DER
559-
der = ssl.PEM_cert_to_DER_cert(pem.decode('ascii'))
560-
561-
# Extract subjectPublicKeyInfo field from X.509 certificate (see RFC3280)
562-
cert = DerSequence()
563-
cert.decode(der)
564-
tbsCertificate = DerSequence()
565-
tbsCertificate.decode(cert[0])
566-
subjectPublicKeyInfo = tbsCertificate[6]
567-
568-
# Initialize RSA key
569-
rsa_key = RSA.importKey(subjectPublicKeyInfo)
570-
return rsa_key
540+
cert = load_pem_x509_certificate(pem, backend)
541+
return cert.public_key()
571542

572543

573544
def pem_format(key):
@@ -576,7 +547,7 @@ def pem_format(key):
576547

577548

578549
def import_rsa_key_from_file(filename):
579-
return RSA.importKey(read_file(filename, 'r'))
550+
return load_pem_private_key(read_file(filename, 'rb'), None, backend)
580551

581552

582553
def parse_xmlsec_output(output):
@@ -622,25 +593,28 @@ def sign(self, msg, key=None):
622593
if key is None:
623594
key = self.key
624595

625-
h = self.digest.new(msg)
626-
signer = PKCS1_v1_5.new(key)
627-
return signer.sign(h)
596+
return key.sign(msg, PKCS1v15(), self.digest)
628597

629598
def verify(self, msg, sig, key=None):
630599
if key is None:
631600
key = self.key
632601

633-
h = self.digest.new(msg)
634-
verifier = PKCS1_v1_5.new(key)
635-
return verifier.verify(h, sig)
602+
try:
603+
if isinstance(key, rsa.RSAPrivateKey):
604+
key = key.public_key()
605+
606+
key.verify(sig, msg, PKCS1v15(), self.digest)
607+
return True
608+
except InvalidSignature:
609+
return False
636610

637611

638612
SIGNER_ALGS = {
639-
SIG_RSA_SHA1: RSASigner(SHA),
640-
SIG_RSA_SHA224: RSASigner(SHA224),
641-
SIG_RSA_SHA256: RSASigner(SHA256),
642-
SIG_RSA_SHA384: RSASigner(SHA384),
643-
SIG_RSA_SHA512: RSASigner(SHA512),
613+
SIG_RSA_SHA1: RSASigner(hashes.SHA1()),
614+
SIG_RSA_SHA224: RSASigner(hashes.SHA224()),
615+
SIG_RSA_SHA256: RSASigner(hashes.SHA256()),
616+
SIG_RSA_SHA384: RSASigner(hashes.SHA384()),
617+
SIG_RSA_SHA512: RSASigner(hashes.SHA512()),
644618
}
645619

646620
REQ_ORDER = ["SAMLRequest", "RelayState", "SigAlg"]

0 commit comments

Comments
 (0)