# Copyright (C) Jean-Paul Calderone # See LICENSE for details. import sys from OpenSSL.crypto import ( FILETYPE_PEM, TYPE_DSA, Error, PKey, X509, load_privatekey, CRL, Revoked, get_elliptic_curves, _X509_REVOKED_dup, ) from OpenSSL._util import lib as _lib class BaseChecker(object): def __init__(self, iterations): self.iterations = iterations class Checker_X509_get_pubkey(BaseChecker): """ Leak checks for L{X509.get_pubkey}. """ def check_exception(self): """ Call the method repeatedly such that it will raise an exception. """ for i in xrange(self.iterations): cert = X509() try: cert.get_pubkey() except Error: pass def check_success(self): """ Call the method repeatedly such that it will return a PKey object. """ small = xrange(3) for i in xrange(self.iterations): key = PKey() key.generate_key(TYPE_DSA, 256) for i in small: cert = X509() cert.set_pubkey(key) for i in small: cert.get_pubkey() class Checker_load_privatekey(BaseChecker): """ Leak checks for :py:obj:`load_privatekey`. """ ENCRYPTED_PEM = """\ -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: BF-CBC,3763C340F9B5A1D0 a/DO10mLjHLCAOG8/Hc5Lbuh3pfjvcTZiCexShP+tupkp0VxW2YbZjML8uoXrpA6 fSPUo7cEC+r96GjV03ZIVhjmsxxesdWMpfkzXRpG8rUbWEW2KcCJWdSX8bEkuNW3 uvAXdXZwiOrm56ANDo/48gj27GcLwnlA8ld39+ylAzkUJ1tcMVzzTjfcyd6BMFpR Yjg23ikseug6iWEsZQormdl0ITdYzmFpM+YYsG7kmmmi4UjCEYfb9zFaqJn+WZT2 qXxmo2ZPFzmEVkuB46mf5GCqMwLRN2QTbIZX2+Dljj1Hfo5erf5jROewE/yzcTwO FCB5K3c2kkTv2KjcCAimjxkE+SBKfHg35W0wB0AWkXpVFO5W/TbHg4tqtkpt/KMn /MPnSxvYr/vEqYMfW4Y83c45iqK0Cyr2pwY60lcn8Kk= -----END RSA PRIVATE KEY----- """ def check_load_privatekey_callback(self): """ Call the function with an encrypted PEM and a passphrase callback. """ for i in xrange(self.iterations * 10): load_privatekey( FILETYPE_PEM, self.ENCRYPTED_PEM, lambda *args: "hello, secret" ) def check_load_privatekey_callback_incorrect(self): """ Call the function with an encrypted PEM and a passphrase callback which returns the wrong passphrase. """ for i in xrange(self.iterations * 10): try: load_privatekey( FILETYPE_PEM, self.ENCRYPTED_PEM, lambda *args: "hello, public", ) except Error: pass def check_load_privatekey_callback_wrong_type(self): """ Call the function with an encrypted PEM and a passphrase callback which returns a non-string. """ for i in xrange(self.iterations * 10): try: load_privatekey( FILETYPE_PEM, self.ENCRYPTED_PEM, lambda *args: {} ) except ValueError: pass class Checker_CRL(BaseChecker): """ Leak checks for L{CRL.add_revoked} and L{CRL.get_revoked}. """ def check_add_revoked(self): """ Call the add_revoked method repeatedly on an empty CRL. """ for i in xrange(self.iterations * 200): CRL().add_revoked(Revoked()) def check_get_revoked(self): """ Create a CRL object with 100 Revoked objects, then call the get_revoked method repeatedly. """ crl = CRL() for i in xrange(100): crl.add_revoked(Revoked()) for i in xrange(self.iterations): crl.get_revoked() class Checker_X509_REVOKED_dup(BaseChecker): """ Leak checks for :py:obj:`_X509_REVOKED_dup`. """ def check_X509_REVOKED_dup(self): """ Copy an empty Revoked object repeatedly. The copy is not garbage collected, therefore it needs to be manually freed. """ for i in xrange(self.iterations * 100): revoked_copy = _X509_REVOKED_dup(Revoked()._revoked) _lib.X509_REVOKED_free(revoked_copy) class Checker_EllipticCurve(BaseChecker): """ Leak checks for :py:obj:`_EllipticCurve`. """ def check_to_EC_KEY(self): """ Repeatedly create an EC_KEY* from an :py:obj:`_EllipticCurve`. The structure should be automatically garbage collected. """ curves = get_elliptic_curves() if curves: curve = next(iter(curves)) for i in xrange(self.iterations * 1000): curve._to_EC_KEY() def vmsize(): return [x for x in file("/proc/self/status").readlines() if "VmSize" in x] def main(iterations="1000"): iterations = int(iterations) for klass in globals(): if klass.startswith("Checker_"): klass = globals()[klass] print klass checker = klass(iterations) for meth in dir(checker): if meth.startswith("check_"): print "\t", meth, vmsize(), "...", getattr(checker, meth)() print vmsize() if __name__ == "__main__": main(*sys.argv[1:])