def test_readwithlen(self): s="A quick brown fox jumps over a lazy dog" bio=Membio(s) data=bio.read(len(s)) self.assertEqual(data,s) data2=bio.read(5) self.assertEqual(data2,"")
def test_readwithlen(self): s = b"A quick brown fox jumps over a lazy dog" bio = Membio(s) data = bio.read(len(s)) self.assertEqual(data, s) data2 = bio.read(5) self.assertEqual(data2, b"")
def __unicode__(self): """ Produces unicode representation of the name. """ bio = Membio() libcrypto.X509_NAME_print_ex(bio.bio, self.ptr, 0, self.PRINT_FLAG) return bio.__unicode__()
def __init__(self, ptr=None, privkey=None, pubkey=None, format="PEM", cansign=False, password=None, callback=_cb): if not ptr is None: self.key = ptr self.cansign = cansign if not privkey is None or not pubkey is None: raise TypeError("Just one of ptr, pubkey or privkey can " + "be specified") elif not privkey is None: if not pubkey is None: raise TypeError("Just one of ptr, pubkey or privkey can " + "be specified") bio = Membio(privkey) self.cansign = True if format == "PEM": self.key = libcrypto.PEM_read_bio_PrivateKey(bio.bio, None, callback, c_char_p(password)) else: self.key = libcrypto.d2i_PrivateKey_bio(bio.bio, None) if self.key is None: raise PKeyError("error parsing private key") elif not pubkey is None: bio = Membio(pubkey) self.cansign = False if format == "PEM": self.key = libcrypto.PEM_read_bio_PUBKEY(bio.bio, None, callback, c_char_p(password)) else: self.key = libcrypto.d2i_PUBKEY_bio(bio.bio, None) if self.key is None: raise PKeyError("error parsing public key") else: raise TypeError("Neither public, nor private key is specified")
def test_unicode(self): b = Membio() s = b'\xd0\xba\xd0\xb0\xd0\xba \xd1\x8d\xd1\x82\xd0\xbe \xd0\xbf\xd0\xbe-\xd1\x80\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8' b.write(s) self.assertEqual( unicode(b), u'\u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e-\u0440\u0443\u0441\u0441\u043a\u0438' )
def test_readshortstr(self): s = b"A quick brown fox jumps over a lazy dog" bio = Membio(s) data = bio.read() self.assertEqual(data, s) data2 = bio.read() self.assertEqual(data2, b"") del bio
def test_readshortstr(self): s="A quick brown fox jumps over a lazy dog" bio=Membio(s) data=bio.read() self.assertEqual(data,s) data2=bio.read() self.assertEqual(data2,"") del bio
def _keybio(blob, format): # But DER string should be binary if format == "PEM" and isinstance(blob, chartype): return Membio(blob.encode("ascii"), clone=True) elif isinstance(blob, bintype): return Membio(blob) else: raise TypeError("Key should be either blob or PEM string")
def test_reset(self): s="A quick brown fox jumps over a lazy dog" bio=Membio(s) data=bio.read() bio.reset() data2=bio.read() del bio self.assertEqual(data,data2) self.assertEqual(data,s)
def __bytes__(self): """ Produces an ascii representation of the name, escaping all symbols > 0x80. Probably it is not what you want, unless your native language is English """ bio = Membio() libcrypto.X509_NAME_print_ex(bio.bio, self.ptr, 0, self.PRINT_FLAG | self.ESC_MSB) return bio.__bytes__()
def test_readlongstr(self): poem = b'''Eyes of grey--a sodden quay, Driving rain and falling tears, As the steamer wears to sea In a parting storm of cheers. Sing, for Faith and Hope are high-- None so true as you and I-- Sing the Lovers' Litany: "Love like ours can never die!" Eyes of black--a throbbing keel, Milky foam to left and right; Whispered converse near the wheel In the brilliant tropic night. Cross that rules the Southern Sky! Stars that sweep and wheel and fly, Hear the Lovers' Litany: Love like ours can never die!" Eyes of brown--a dusty plain Split and parched with heat of June, Flying hoof and tightened rein, Hearts that beat the old, old tune. Side by side the horses fly, Frame we now the old reply Of the Lovers' Litany: "Love like ours can never die!" Eyes of blue--the Simla Hills Silvered with the moonlight hoar; Pleading of the waltz that thrills, Dies and echoes round Benmore. "Mabel," "Officers," "Goodbye," Glamour, wine, and witchery-- On my soul's sincerity, "Love like ours can never die!" Maidens of your charity, Pity my most luckless state. Four times Cupid's debtor I-- Bankrupt in quadruplicate. Yet, despite this evil case, And a maiden showed me grace, Four-and-forty times would I Sing the Lovers' Litany: "Love like ours can never die!"''' bio = Membio(poem) data = bio.read() self.assertEqual(data, poem) del bio
def test_readlongstr(self): poem='''Eyes of grey--a sodden quay, Driving rain and falling tears, As the steamer wears to sea In a parting storm of cheers. Sing, for Faith and Hope are high-- None so true as you and I-- Sing the Lovers' Litany: "Love like ours can never die!" Eyes of black--a throbbing keel, Milky foam to left and right; Whispered converse near the wheel In the brilliant tropic night. Cross that rules the Southern Sky! Stars that sweep and wheel and fly, Hear the Lovers' Litany: Love like ours can never die!" Eyes of brown--a dusty plain Split and parched with heat of June, Flying hoof and tightened rein, Hearts that beat the old, old tune. Side by side the horses fly, Frame we now the old reply Of the Lovers' Litany: "Love like ours can never die!" Eyes of blue--the Simla Hills Silvered with the moonlight hoar; Pleading of the waltz that thrills, Dies and echoes round Benmore. "Mabel," "Officers," "Goodbye," Glamour, wine, and witchery-- On my soul's sincerity, "Love like ours can never die!" Maidens of your charity, Pity my most luckless state. Four times Cupid's debtor I-- Bankrupt in quadruplicate. Yet, despite this evil case, And a maiden showed me grace, Four-and-forty times would I Sing the Lovers' Litany: "Love like ours can never die!"''' bio=Membio(poem) data=bio.read() self.assertEqual(data,poem) del bio
def test_readparts(self): s="A quick brown fox jumps over the lazy dog" bio=Membio(s) a=bio.read(10) self.assertEqual(a,s[0:10]) b=bio.read(9) self.assertEqual(b,s[10:19]) c=bio.read() self.assertEqual(c,s[19:]) d=bio.read() self.assertEqual(d,"")
def exportpriv(self, format="PEM", password=None, cipher=None, callback=_cb): """ Returns private key as PEM or DER Structure. If password and cipher are specified, encrypts key on given password, using given algorithm. Cipher must be an ctypescrypto.cipher.CipherType object """ bio = Membio() if cipher is None: evp_cipher = None else: evp_cipher = cipher.cipher if format == "PEM": ret = libcrypto.PEM_write_bio_PrivateKey(bio.bio, self.key, evp_cipher, None, 0, callback, c_char_p(password)) else: ret = libcrypto.i2d_PKCS8PrivateKey_bio(bio.bio, self.key, evp_cipher, None, 0, callback, c_char_p(password)) if ret == 0: raise PKeyError("error serializing private key") return str(bio)
def CMS(data, format="PEM"): """ Factory function to create CMS objects from received messages. Parses CMS data and returns either SignedData or EnvelopedData object. format argument can be either "PEM" or "DER". It determines object type from the contents of received CMS structure. """ bio = Membio(data) if format == "PEM": ptr = libcrypto.PEM_read_bio_CMS(bio.bio, None, None, None) else: ptr = libcrypto.d2i_CMS_bio(bio.bio, None) if ptr is None: raise CMSError("Error parsing CMS data") typeoid = Oid(libcrypto.OBJ_obj2nid(libcrypto.CMS_get0_type(ptr))) if typeoid.shortname() == "pkcs7-signedData": return SignedData(ptr) elif typeoid.shortname() == "pkcs7-envelopedData": return EnvelopedData(ptr) elif typeoid.shortname() == "pkcs7-encryptedData": return EncryptedData(ptr) else: raise NotImplementedError("cannot handle " + typeoid.shortname())
def create(data, cert, pkey, flags=Flags.BINARY, certs=None): """ Creates SignedData message by signing data with pkey and certificate. @param data - data to sign @param cert - signer's certificate @param pkey - pkey object with private key to sign @param flags - OReed combination of Flags constants @param certs - list of X509 objects to include into CMS """ if not pkey.cansign: raise ValueError("Specified keypair has no private part") if cert.pubkey != pkey: raise ValueError("Certificate doesn't match public key") bio = Membio(data) if certs is not None and len(certs) > 0: certstack = StackOfX509(certs).ptr else: certstack = None ptr = libcrypto.CMS_sign(cert.cert, pkey.key, certstack, bio.bio, flags) if ptr is None: raise CMSError("signing message") return SignedData(ptr)
def sign(self, cert, pkey, digest_type=None, data=None, flags=Flags.BINARY): """ Adds another signer to already signed message @param cert - signer's certificate @param pkey - signer's private key @param digest_type - message digest to use as DigestType object (if None - default for key would be used) @param data - data to sign (if detached and Flags.REUSE_DIGEST is not specified) @param flags - ORed combination of Flags consants """ if not pkey.cansign: raise ValueError("Specified keypair has no private part") if cert.pubkey != pkey: raise ValueError("Certificate doesn't match public key") if libcrypto.CMS_add1_signer(self.ptr, cert.cert, pkey.key, digest_type.digest, flags) is None: raise CMSError("adding signer") if flags & Flags.REUSE_DIGEST == 0: if data is not None: bio = Membio(data) biodata = bio.bio else: biodata = None res = libcrypto.CMS_final(self.ptr, biodata, None, flags) if res <= 0: raise CMSError("Cannot finalize CMS")
def verify(self, store, flags, data=None, certs=None): """ Verifies signature under CMS message using trusted cert store @param store - X509Store object with trusted certs @param flags - OR-ed combination of flag consants @param data - message data, if messge has detached signature param certs - list of certificates to use during verification If Flags.NOINTERN is specified, these are only sertificates to search for signing certificates @returns True if signature valid, False otherwise """ bio = None if data != None: bio_obj = Membio(data) bio = bio_obj.bio if certs is not None and len(certs) > 0: certstack_obj = StackOfX509( certs) # keep reference to prevent immediate __del__ call certstack = certstack_obj.ptr else: certstack = None res = libcrypto.CMS_verify(self.ptr, certstack, store.store, bio, None, flags) return res > 0
def exportpriv(self, format="PEM", password=None, cipher=None): """ Returns private key as PEM or DER Structure. If password and cipher are specified, encrypts key on given password, using given algorithm. Cipher must be an ctypescrypto.cipher.CipherType object Password can be either string or function with one argument, which returns password. It is called with argument True, which means, that we are encrypting key, and password should be verified (requested twice from user, for example). """ bio = Membio() if cipher is None: evp_cipher = None else: evp_cipher = cipher.cipher if format == "PEM": ret = libcrypto.PEM_write_bio_PrivateKey( bio.bio, self.key, evp_cipher, None, 0, _password_callback(password), None) if ret == 0: raise PKeyError("error serializing private key") return str(bio) else: ret = libcrypto.i2d_PKCS8PrivateKey_bio( bio.bio, self.key, evp_cipher, None, 0, _password_callback(password), None) if ret == 0: raise PKeyError("error serializing private key") return bintype(bio)
def pem(self): """ Serialize in PEM format """ bio = Membio() if not libcrypto.PEM_write_bio_CMS(bio.bio, self.ptr): raise CMSError("writing CMS to PEM") return str(bio)
def __str__(self): """ Serialize in DER format """ bio = Membio() if not libcrypto.i2d_CMS_bio(bio.bio, self.ptr): raise CMSError("writing CMS to DER") return str(bio)
def _X509__asn1date_to_datetime(asn1date): """ Converts openssl ASN1_TIME object to python datetime.datetime """ bio = Membio() libcrypto.ASN1_TIME_print(bio.bio, asn1date) pydate = datetime.strptime(str(bio), "%b %d %H:%M:%S %Y %Z") return pydate.replace(tzinfo=utc)
def data(self): """ Returns signed data if present in the message """ bio = Membio() if not libcrypto.CMS_verify(self.ptr, None, None, None, bio.bio, Flags.NO_VERIFY): raise CMSError("extract data") return str(bio)
def decrypt(self, key, flags=0): """ Decrypts encrypted data message @param key - symmetic key to decrypt @param flags - OR-ed combination of Flags constant """ bio = Membio() if libcrypto.CMS_EncryptedData_decrypt(self.ptr, key, len(key), None, bio.bio, flags) <= 0: raise CMSError("decrypt data") return str(bio)
def exportpub(self, format="PEM"): """ Returns public key as PEM or DER structure. """ bio = Membio() if format == "PEM": retcode = libcrypto.PEM_write_bio_PUBKEY(bio.bio, self.key) else: retcode = libcrypto.i2d_PUBKEY_bio(bio.bio, self.key) if retcode == 0: raise PKeyError("error serializing public key") return str(bio)
def __getitem__(self, key): if isinstance(key, Oid): # Return first matching field idx = libcrypto.X509_NAME_get_index_by_NID(self.ptr, key.nid, -1) if idx < 0: raise KeyError("Key not found " + str(Oid)) entry = libcrypto.X509_NAME_get_entry(self.ptr, idx) value = libcrypto.X509_NAME_ENTRY_get_data(entry) bio = Membio() libcrypto.ASN1_STRING_print_ex(bio.bio, value, self.PRINT_FLAG) return chartype(bio) elif isinstance(key, inttype): # Return OID, string tuple entry = libcrypto.X509_NAME_get_entry(self.ptr, key) if entry is None: raise IndexError("name entry index out of range") oid = Oid.fromobj(libcrypto.X509_NAME_ENTRY_get_object(entry)) value = libcrypto.X509_NAME_ENTRY_get_data(entry) bio = Membio() libcrypto.ASN1_STRING_print_ex(bio.bio, value, self.PRINT_FLAG) return (oid, chartype(bio)) else: raise TypeError("X509 NAME can be indexed by Oids or integers only")
def test_reset(self): s = b"A quick brown fox jumps over a lazy dog" bio = Membio(s) data = bio.read() bio.reset() data2 = bio.read() del bio self.assertEqual(data, data2) self.assertEqual(data, s)
def create(data, cipher, key, flags=0): """ Creates an EncryptedData message. @param data data to encrypt @param cipher cipher.CipherType object represening required cipher type @param key - byte array used as simmetic key @param flags - OR-ed combination of Flags constant """ bio = Membio(data) ptr = libcrypto.CMS_EncryptedData_encrypt(bio.bio, cipher.cipher, key, len(key), flags) if ptr is None: raise CMSError("encrypt data") return EncryptedData(ptr)
def create(recipients, data, cipher, flags=0): """ Creates and encrypts message @param recipients - list of X509 objects @param data - contents of the message @param cipher - CipherType object @param flags - flag """ recp = StackOfX509(recipients) bio = Membio(data) cms_ptr = libcrypto.CMS_encrypt(recp.ptr, bio.bio, cipher.cipher, flags) if cms_ptr is None: raise CMSError("encrypt EnvelopedData") return EnvelopedData(cms_ptr)
def test_readparts(self): s = b"A quick brown fox jumps over the lazy dog" bio = Membio(s) a = bio.read(10) self.assertEqual(a, s[0:10]) b = bio.read(9) self.assertEqual(b, s[10:19]) c = bio.read() self.assertEqual(c, s[19:]) d = bio.read() self.assertEqual(d, b"")
def decrypt(self, pkey, cert, flags=0): """ Decrypts message @param pkey - private key to decrypt @param cert - certificate of this private key (to find neccessary RecipientInfo @param flags - flags @returns - decrypted data """ if not pkey.cansign: raise ValueError("Specified keypair has no private part") if pkey != cert.pubkey: raise ValueError("Certificate doesn't match private key") bio = Membio() res = libcrypto.CMS_decrypt(self.ptr, pkey.key, cert.cert, None, bio.bio, flags) if res <= 0: raise CMSError("decrypting CMS") return str(bio)
def CMS(data, format="PEM"): """ Parses CMS data and returns either SignedData or EnvelopedData object """ bio = Membio(data) if format == "PEM": ptr = libcrypto.PEM_read_bio_CMS(bio.bio, None, None, None) else: ptr = libcrypto.d2i_CMS_bio(bio.bio, None) if ptr is None: raise CMSError("Error parsing CMS data") typeoid = Oid(libcrypto.OBJ_obj2nid(libcrypto.CMS_get0_type(ptr))) if typeoid.shortname() == "pkcs7-signedData": return SignedData(ptr) elif typeoid.shortname() == "pkcs7-envelopedData": return EnvelopedData(ptr) elif typeoid.shortname() == "pkcs7-encryptedData": return EncryptedData(ptr) else: raise NotImplementedError("cannot handle " + typeoid.shortname())
def __init__(self, data=None, ptr=None, format="PEM"): """ Initializes certificate @param data - serialized certificate in PEM or DER format. @param ptr - pointer to X509, returned by some openssl function. mutually exclusive with data @param format - specifies data format. "PEM" or "DER", default PEM """ if ptr is not None: if data is not None: raise TypeError("Cannot use data and ptr simultaneously") self.cert = ptr elif data is None: raise TypeError("data argument is required") else: bio = Membio(data) if format == "PEM": self.cert = libcrypto.PEM_read_bio_X509(bio.bio, None, None, None) else: self.cert = libcrypto.d2i_X509_bio(bio.bio, None) if self.cert is None: raise X509Error("error reading certificate") self.extensions = _X509extlist(self)
def serial(self): """ Serial number of certificate as integer """ asnint = libcrypto.X509_get_serialNumber(self.cert) bio = Membio() libcrypto.i2a_ASN1_INTEGER(bio.bio, asnint) return int(str(bio), 16)
def pem(self): """ Returns PEM represntation of the certificate """ bio = Membio() if libcrypto.PEM_write_bio_X509(bio.bio, self.cert) == 0: raise X509Error("error serializing certificate") return str(bio)
def test_write(self): b=Membio() b.write("A quick brown ") b.write("fox jumps over ") b.write("the lazy dog.") self.assertEqual(str(b),"A quick brown fox jumps over the lazy dog.")
def test_readwrongtype(self): s="A quick brown fox jumps over a lazy dog" bio=Membio(s) with self.assertRaises(TypeError): data=bio.read("5")
def test_unicode(self): b=Membio() s='\xd0\xba\xd0\xb0\xd0\xba \xd1\x8d\xd1\x82\xd0\xbe \xd0\xbf\xd0\xbe-\xd1\x80\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8' b.write(s) self.assertEqual(unicode(b),u'\u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e-\u0440\u0443\u0441\u0441\u043a\u0438')
def test_unicode2(self): b=Membio() u=u'\u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e-\u0440\u0443\u0441\u0441\u043a\u0438' b.write(u) self.assertEqual(unicode(b),u)