From 13ec6f74c73b377d6233de42cc942846e976541b Mon Sep 17 00:00:00 2001 From: "yan11.meng" Date: Wed, 26 Feb 2020 12:47:07 +0900 Subject: [PATCH] Imported Upstream version 0.35.1 Change-Id: Id4a444b8c1d11fee1026b433a47ca5aabcf11622 --- CHANGES | 256 +- CONTRIBUTORS.rst | 43 + INSTALL | 226 - INSTALL.rst | 166 + M2Crypto.egg-info/PKG-INFO | 23 - M2Crypto.egg-info/SOURCES.txt | 354 - M2Crypto.egg-info/dependency_links.txt | 1 - M2Crypto.egg-info/top_level.txt | 1 - M2Crypto/ASN1.py | 187 +- M2Crypto/AuthCookie.py | 107 +- M2Crypto/BIO.py | 274 +- M2Crypto/BN.py | 37 +- M2Crypto/DH.py | 59 +- M2Crypto/DSA.py | 371 +- M2Crypto/EC.py | 422 +- M2Crypto/EVP.py | 329 +- M2Crypto/Engine.py | 73 +- M2Crypto/Err.py | 60 +- M2Crypto/PGP/PublicKey.py | 58 - M2Crypto/PGP/PublicKeyRing.py | 81 - M2Crypto/PGP/RSA.py | 36 - M2Crypto/PGP/__init__.py | 14 - M2Crypto/PGP/constants.py | 19 - M2Crypto/PGP/packet.py | 379 - M2Crypto/RC4.py | 19 +- M2Crypto/RSA.py | 360 +- M2Crypto/Rand.py | 148 +- M2Crypto/SMIME.py | 202 +- M2Crypto/SSL/Checker.py | 163 +- M2Crypto/SSL/Cipher.py | 32 +- M2Crypto/SSL/Connection.py | 525 +- M2Crypto/SSL/Context.py | 360 +- M2Crypto/SSL/SSLServer.py | 53 +- M2Crypto/SSL/Session.py | 30 +- M2Crypto/SSL/TwistedProtocolWrapper.py | 293 +- M2Crypto/SSL/__init__.py | 53 +- M2Crypto/SSL/cb.py | 59 +- M2Crypto/SSL/ssl_dispatcher.py | 27 +- M2Crypto/SSL/timeout.py | 34 +- M2Crypto/X509.py | 995 +- M2Crypto/__init__.py | 59 +- M2Crypto/callback.py | 4 +- M2Crypto/ftpslib.py | 21 +- M2Crypto/httpslib.py | 211 +- M2Crypto/m2.py | 6 +- M2Crypto/m2crypto.py | 87 + M2Crypto/m2urllib.py | 111 +- M2Crypto/m2urllib2.py | 100 +- M2Crypto/m2xmlrpclib.py | 40 +- M2Crypto/six.py | 950 + M2Crypto/threading.py | 11 +- M2Crypto/util.py | 82 +- MANIFEST.in | 13 + PKG-INFO | 23 - README => README.rst | 32 +- SWIG/Makefile | 6 +- SWIG/Makefile.mw | 34 - SWIG/Makefile.osx | 32 - SWIG/_aes.i | 41 +- SWIG/_asn1.i | 86 +- SWIG/_bio.i | 366 +- SWIG/_bn.i | 84 +- SWIG/_dh.i | 120 +- SWIG/_dsa.i | 293 +- SWIG/_ec.i | 196 +- SWIG/_engine.i | 1 + SWIG/_evp.i | 304 +- SWIG/_lib.h | 16 +- SWIG/_lib.i | 360 +- SWIG/_lib11_compat.i | 458 + SWIG/_m2crypto.def | 2 +- SWIG/_m2crypto.i | 48 +- SWIG/_m2crypto_wrap.c | 32491 ++++++++++++++++ SWIG/_objects.i | 8 +- SWIG/_pkcs7.i | 113 +- SWIG/_py3k_compat.i | 43 + SWIG/_rand.i | 74 +- SWIG/_rc4.i | 25 +- SWIG/_rsa.i | 280 +- SWIG/_ssl.i | 498 +- SWIG/_threads.i | 21 +- SWIG/_util.i | 13 +- SWIG/_x509.i | 335 +- SWIG/libcrypto-compat.h | 62 + SWIG/py3k_compat.h | 32 + appveyor.yml | 151 + contrib/SimpleX509create.py | 201 +- contrib/dave.patch | 180 - contrib/dispatcher.py | 368 +- contrib/isaac.httpslib.py | 185 +- contrib/m2crypto.spec | 46 - contrib/smimeplus.py | 45 +- demo/CipherSaber/CipherSaber.py | 62 - demo/CipherSaber/cstest1.cs1 | 1 - demo/Zope/ZServer/HTTPS_Server.py | 187 - demo/Zope/ZServer/__init__.py | 95 - demo/Zope/ZServer/medusa/ftps_server.py | 438 - demo/Zope/ZServer/medusa/https_server.py | 83 - demo/Zope/ca.pem | 20 - demo/Zope/dh1024.pem | 5 - .../Products/GuardedFile/GuardedFile.py | 53 - .../python/Products/GuardedFile/README.txt | 16 - .../lib/python/Products/GuardedFile/TODO.txt | 1 - .../python/Products/GuardedFile/__init__.py | 25 - .../lib/python/Products/GuardedFile/add.dtml | 78 - .../python/Products/GuardedFile/refresh.txt | 0 .../python/Products/GuardedFile/version.txt | 1 - .../lib/python/Products/ZSmime/README.txt | 18 - .../lib/python/Products/ZSmime/SmimeTag.py | 104 - .../lib/python/Products/ZSmime/__init__.py | 9 - .../lib/python/Products/ZSmime/version.txt | 1 - demo/Zope/server.pem | 36 - demo/Zope/starts | 17 - demo/Zope/starts.bat | 1 - demo/Zope/utilities/x509_user.py | 79 - demo/Zope/z2s.py | 1078 - demo/Zope/z2s.py.diff | 266 - demo/Zope27/INSTALL.txt | 200 - .../lib/python/ZServer/HTTPS_Server.py | 187 - .../lib/python/ZServer/__init__.py.patch | 10 - .../lib/python/ZServer/component.xml.patch | 28 - .../lib/python/ZServer/datatypes.py.patch | 59 - .../lib/python/ZServer/medusa/https_server.py | 83 - demo/Zope27/instance_home/README.txt.patch | 7 - demo/Zope27/instance_home/etc/zope.conf.patch | 16 - demo/Zope27/instance_home/ssl/ca.pem | 20 - demo/Zope27/instance_home/ssl/dh1024.pem | 5 - demo/Zope27/instance_home/ssl/server.pem | 36 - demo/ZopeX3/INSTALL.txt | 73 - .../zope/app/server/configure.zcml.patch | 28 - .../lib/python/zope/app/server/https.py | 28 - .../python/zope/server/http/https_server.py | 104 - .../zope/server/http/https_serverchannel.py | 55 - .../zope/server/http/publisherhttps_server.py | 83 - demo/ZopeX3/instance_home/etc/zope.conf.patch | 26 - demo/ZopeX3/instance_home/ssl/ca.pem | 20 - demo/ZopeX3/instance_home/ssl/dh1024.pem | 5 - demo/ZopeX3/instance_home/ssl/server.pem | 36 - demo/bio_mem_rw.py | 44 - demo/dhtest.py | 27 - demo/dsa1024pvtkey.pem | 12 - demo/dsa_bench.py | 176 - demo/dsatest.pem | 8 - demo/dsatest.py | 57 - demo/ec/ecdhtest.py | 31 - demo/ec/ecdsa_bench.py | 368 - demo/ec/ecdsatest.pem | 5 - demo/ec/ecdsatest.py | 68 - demo/ec/secp160r1pvtkey.pem | 4 - demo/https.howto/ca.pem | 59 - demo/https.howto/dh1024.pem | 5 - demo/https.howto/get_https.py | 32 - demo/https.howto/https_cli.py | 49 - demo/https.howto/orig_https_srv.py | 153 - demo/https.howto/server.pem | 74 - demo/medusa/00_README | 32 - demo/medusa/START.py | 71 - demo/medusa/START_xmlrpc.py | 72 - demo/medusa/asynchat.py | 292 - demo/medusa/asyncore.py | 552 - demo/medusa/auth_handler.py | 135 - demo/medusa/ca.pem | 20 - demo/medusa/counter.py | 48 - demo/medusa/default_handler.py | 215 - demo/medusa/dh1024.pem | 5 - demo/medusa/filesys.py | 466 - demo/medusa/ftp_server.py | 1127 - demo/medusa/ftps_server.py | 438 - demo/medusa/http_date.py | 126 - demo/medusa/http_server.py | 784 - demo/medusa/https_server.py | 83 - demo/medusa/index.html | 6 - demo/medusa/logger.py | 262 - demo/medusa/m_syslog.py | 177 - demo/medusa/medusa_gif.py | 8 - demo/medusa/mime_type_table.py | 113 - demo/medusa/poison_handler.py | 69 - demo/medusa/producers.py | 329 - demo/medusa/put_handler.py | 113 - demo/medusa/redirecting_handler.py | 44 - demo/medusa/server.pem | 36 - demo/medusa/status_handler.py | 282 - demo/medusa/virtual_handler.py | 60 - demo/medusa/xmlrpc_handler.py | 104 - demo/medusa054/00_README | 30 - demo/medusa054/START.py | 71 - demo/medusa054/START_xmlrpc.py | 72 - demo/medusa054/ca.pem | 20 - demo/medusa054/counter.py | 51 - demo/medusa054/default_handler.py | 213 - demo/medusa054/dh1024.pem | 5 - demo/medusa054/filesys.py | 394 - demo/medusa054/ftp_server.py | 1111 - demo/medusa054/ftps_server.py | 438 - demo/medusa054/http_date.py | 126 - demo/medusa054/http_server.py | 749 - demo/medusa054/https_server.py | 85 - demo/medusa054/index.html | 6 - demo/medusa054/logger.py | 261 - demo/medusa054/m_syslog.py | 182 - demo/medusa054/medusa_gif.py | 8 - demo/medusa054/poison_handler.py | 69 - demo/medusa054/producers.py | 323 - demo/medusa054/server.pem | 36 - demo/medusa054/status_handler.py | 272 - demo/medusa054/xmlrpc_handler.py | 103 - demo/perf/memio.py | 49 - demo/perf/sha1.py | 46 - demo/pgp/pgpstep.py | 113 - demo/pgp/pubring.pgp | Bin 1088 -> 0 bytes demo/pgp/secring.pgp | Bin 1969 -> 0 bytes demo/pkcs7/pkcs7-thawte.pem | 45 - demo/pkcs7/test.py | 6 - demo/rsa.priv.pem | 9 - demo/rsa.priv0.pem | 15 - demo/rsa.pub.pem | 4 - demo/rsa1024pvtkey.pem | 15 - demo/rsa_bench.py | 183 - demo/rsatest.py | 45 - demo/smime.howto/README | 5 - demo/smime.howto/decrypt.py | 22 - demo/smime.howto/dv.py | 41 - demo/smime.howto/encrypt.p7 | 17 - demo/smime.howto/encrypt.py | 44 - demo/smime.howto/recipient.pem | 18 - demo/smime.howto/recipient_key.pem | 15 - demo/smime.howto/se.p7 | 56 - demo/smime.howto/se.py | 54 - demo/smime.howto/sendsmime.py | 82 - demo/smime.howto/sign.p7 | 46 - demo/smime.howto/sign.py | 37 - demo/smime.howto/signer.pem | 18 - demo/smime.howto/signer_key.pem | 15 - demo/smime.howto/verify.py | 30 - demo/smime/README | 54 - demo/smime/ca.pem | 20 - demo/smime/clear.p7 | 67 - demo/smime/client.p12 | Bin 1604 -> 0 bytes demo/smime/client.pem | 36 - demo/smime/client2.pem | 36 - demo/smime/m2.se.p7 | 84 - demo/smime/ns.p7 | 53 - demo/smime/ns.se.p7 | 75 - demo/smime/opaque.p7 | 47 - demo/smime/sendsmime.py | 82 - demo/smime/test.py | 192 - demo/smime/unsmime.py | 50 - demo/ssl/README | 25 - demo/ssl/c.py | 70 - demo/ssl/c_bio.py | 70 - demo/ssl/ca.der | Bin 841 -> 0 bytes demo/ssl/ca.pem | 20 - demo/ssl/client.p12 | Bin 1604 -> 0 bytes demo/ssl/client.pem | 35 - demo/ssl/dh1024.pem | 5 - demo/ssl/echo-eg.py | 51 - demo/ssl/echo.py | 59 - demo/ssl/echod-async.py | 112 - demo/ssl/echod-eg1.py | 49 - demo/ssl/echod-forking.py | 22 - demo/ssl/echod-iterative.py | 23 - demo/ssl/echod-thread.py | 55 - demo/ssl/echod-threading.py | 32 - demo/ssl/echod_lib.py | 45 - demo/ssl/ftp_tls.py | 41 - demo/ssl/http_cli_20.py | 22 - demo/ssl/https_cli.py | 45 - demo/ssl/https_cli_async.py | 106 - demo/ssl/https_srv.py | 150 - demo/ssl/myapp.py | 30 - demo/ssl/s_client.py | 108 - demo/ssl/s_server.py | 203 - demo/ssl/server.pem | 36 - demo/ssl/server3.py | 121 - demo/ssl/sess.py | 89 - demo/ssl/sess2.py | 78 - demo/ssl/sess2.ssldump.out | 112 - demo/ssl/socklib.py | 46 - demo/ssl/somelib.py | 21 - demo/ssl/ss.py | 25 - demo/ssl/twistedsslclient.py | 43 - demo/ssl/twistedsslserver.py | 37 - demo/ssl/xmlrpc_cli.py | 26 - demo/ssl/xmlrpc_srv.py | 26 - demo/tinderbox/build_lib.py | 162 - demo/tinderbox/killableprocess.py | 212 - demo/tinderbox/slave.py | 172 - demo/tinderbox/winprocess.py | 262 - demo/x509/ca.py | 104 - demo/x509/certdata2pem.py | 64 - demo/x509/client2.pem | 36 - demo/x509/demo1.py | 54 - demo/x509/proxy_destroy.py | 43 - demo/x509/proxy_info.py | 61 - demo/x509/proxy_init.py | 49 - demo/x509/proxylib.py | 327 - demo/x509/server-expired.pem | 36 - demo/x509/server.pem | 36 - demo/x509/x509auth.py | 675 - dev-requirements.txt | 2 + doc/M2Crypto.SSL.rst | 91 + doc/M2Crypto.rst | 218 + doc/Makefile | 153 + doc/ZServerSSL-HOWTO.html | 271 - doc/ZServerSSL-HOWTO.rst | 239 + doc/conf.py | 285 + doc/doctrees/M2Crypto.SSL.doctree | Bin 0 -> 349315 bytes doc/doctrees/M2Crypto.doctree | Bin 0 -> 963869 bytes doc/doctrees/ZServerSSL-HOWTO.doctree | Bin 0 -> 43570 bytes doc/doctrees/environment.pickle | Bin 0 -> 535122 bytes doc/doctrees/howto.ca.doctree | Bin 0 -> 49113 bytes doc/doctrees/howto.smime.doctree | Bin 0 -> 88860 bytes doc/doctrees/howto.ssl.doctree | Bin 0 -> 20890 bytes doc/doctrees/index.doctree | Bin 0 -> 6360 bytes doc/howto.ca.html | 891 - doc/howto.ca.rst | 370 + doc/howto.smime.html | 1570 - doc/howto.smime.rst | 778 + doc/howto.ssl.html | 206 - doc/howto.ssl.rst | 131 + doc/html/.buildinfo | 4 + doc/html/M2Crypto.SSL.html | 1706 + doc/html/M2Crypto.html | 4874 +++ doc/html/ZServerSSL-HOWTO.html | 355 + doc/html/_modules/M2Crypto/ASN1.html | 357 + doc/html/_modules/M2Crypto/AuthCookie.html | 273 + doc/html/_modules/M2Crypto/BIO.html | 494 + doc/html/_modules/M2Crypto/BN.html | 162 + doc/html/_modules/M2Crypto/DH.html | 217 + doc/html/_modules/M2Crypto/DSA.html | 552 + doc/html/_modules/M2Crypto/EC.html | 563 + doc/html/_modules/M2Crypto/EVP.html | 571 + doc/html/_modules/M2Crypto/Engine.html | 254 + doc/html/_modules/M2Crypto/Err.html | 177 + doc/html/_modules/M2Crypto/RC4.html | 140 + doc/html/_modules/M2Crypto/RSA.html | 570 + doc/html/_modules/M2Crypto/Rand.html | 251 + doc/html/_modules/M2Crypto/SMIME.html | 395 + doc/html/_modules/M2Crypto/SSL.html | 145 + doc/html/_modules/M2Crypto/SSL/Checker.html | 403 + doc/html/_modules/M2Crypto/SSL/Cipher.html | 166 + .../_modules/M2Crypto/SSL/Connection.html | 796 + doc/html/_modules/M2Crypto/SSL/Context.html | 552 + doc/html/_modules/M2Crypto/SSL/SSLServer.html | 172 + doc/html/_modules/M2Crypto/SSL/Session.html | 176 + .../M2Crypto/SSL/TwistedProtocolWrapper.html | 597 + doc/html/_modules/M2Crypto/SSL/cb.html | 202 + .../_modules/M2Crypto/SSL/ssl_dispatcher.html | 149 + doc/html/_modules/M2Crypto/SSL/timeout.html | 156 + doc/html/_modules/M2Crypto/X509.html | 1495 + doc/html/_modules/M2Crypto/ftpslib.html | 195 + doc/html/_modules/M2Crypto/httpslib.html | 373 + doc/html/_modules/M2Crypto/m2urllib.html | 225 + doc/html/_modules/M2Crypto/m2urllib2.html | 290 + doc/html/_modules/M2Crypto/m2xmlrpclib.html | 183 + doc/html/_modules/M2Crypto/threading.html | 129 + doc/html/_modules/M2Crypto/util.html | 193 + doc/html/_modules/index.html | 137 + doc/html/_modules/urllib/request.html | 2841 ++ doc/html/_sources/M2Crypto.SSL.rst.txt | 91 + doc/html/_sources/M2Crypto.rst.txt | 218 + doc/html/_sources/ZServerSSL-HOWTO.rst.txt | 239 + doc/html/_sources/howto.ca.rst.txt | 370 + doc/html/_sources/howto.smime.rst.txt | 778 + doc/html/_sources/howto.ssl.rst.txt | 131 + doc/html/_sources/index.rst.txt | 30 + doc/html/_static/ajax-loader.gif | Bin 0 -> 673 bytes doc/html/_static/alabaster.css | 701 + doc/html/_static/basic.css | 676 + doc/html/_static/comment-bright.png | Bin 0 -> 756 bytes doc/html/_static/comment-close.png | Bin 0 -> 829 bytes doc/html/_static/comment.png | Bin 0 -> 641 bytes doc/html/_static/custom.css | 1 + doc/html/_static/doctools.js | 315 + doc/html/_static/documentation_options.js | 10 + doc/html/_static/down-pressed.png | Bin 0 -> 222 bytes doc/html/_static/down.png | Bin 0 -> 202 bytes doc/html/_static/file.png | Bin 0 -> 286 bytes doc/html/_static/jquery-3.2.1.js | 10253 +++++ doc/html/_static/jquery.js | 4 + doc/html/_static/language_data.js | 297 + doc/html/_static/minus.png | Bin 0 -> 90 bytes doc/html/_static/plus.png | Bin 0 -> 90 bytes doc/html/_static/pygments.css | 69 + doc/html/_static/searchtools.js | 481 + doc/html/_static/underscore-1.3.1.js | 999 + doc/html/_static/underscore.js | 31 + doc/html/_static/up-pressed.png | Bin 0 -> 214 bytes doc/html/_static/up.png | Bin 0 -> 203 bytes doc/html/_static/websupport.js | 808 + doc/html/genindex.html | 1731 + doc/html/howto.ca.html | 478 + doc/html/howto.smime.html | 849 + doc/html/howto.ssl.html | 219 + doc/html/index.html | 177 + doc/html/objects.inv | Bin 0 -> 4395 bytes doc/html/py-modindex.html | 307 + doc/html/search.html | 120 + doc/html/searchindex.js | 1 + doc/index.rst | 30 + doc/make.bat | 190 + epydoc.conf | 3 - fedora_setup.sh | 15 - pack.py | 37 - packaging/python-M2Crypto.spec | 2 +- pylintrc | 272 + setup.cfg | 9 +- setup.py | 464 +- tests/__init__.py | 16 + tests/alltests.py | 54 +- tests/bad_date_cert.crt | 19 + tests/ca.pem | 135 +- tests/ca_key.pem | 27 + tests/easy_rsa.pem | 74 + tests/ec.priv.pem | 7 +- tests/ec.pub.pem | 5 +- tests/fips.py | 7 +- tests/makecerts.py | 213 + tests/recipient.pem | 133 +- tests/recipient_key.pem | 38 +- tests/sample-p7.pem | 102 + tests/server.pem | 142 +- tests/server_key.pem | 27 + tests/signer.pem | 106 +- tests/signer_key.pem | 38 +- tests/te_chunked_response.txt | 11 + tests/test_aes.py | 80 + tests/test_asn1.py | 93 +- tests/test_authcookie.py | 148 +- tests/test_bio.py | 84 +- tests/test_bio_file.py | 140 +- tests/test_bio_iobuf.py | 39 +- tests/test_bio_membuf.py | 79 +- tests/test_bio_ssl.py | 127 +- tests/test_bn.py | 27 +- tests/test_dh.py | 35 +- tests/test_dsa.py | 73 +- tests/test_ec_curves.py | 258 +- tests/test_ecdh.py | 28 +- tests/test_ecdsa.py | 57 +- tests/test_engine.py | 30 +- tests/test_err.py | 28 + tests/test_evp.py | 578 +- tests/test_obj.py | 132 +- tests/test_pgp.py | 40 - tests/test_rand.py | 87 +- tests/test_rc4.py | 41 +- tests/test_rsa.py | 307 +- tests/test_smime.py | 342 +- tests/test_ssl.py | 1179 +- tests/test_ssl_offline.py | 56 +- tests/test_ssl_win.py | 57 +- tests/test_threading.py | 3 +- tests/test_timeout.py | 135 + tests/test_util.py | 48 + tests/test_x509.py | 751 +- tests/vendor/unittest2/__init__.py | 68 + tests/vendor/unittest2/__main__.py | 10 + tests/vendor/unittest2/case.py | 1084 + tests/vendor/unittest2/collector.py | 9 + tests/vendor/unittest2/compatibility.py | 64 + tests/vendor/unittest2/loader.py | 322 + tests/vendor/unittest2/main.py | 241 + tests/vendor/unittest2/result.py | 183 + tests/vendor/unittest2/runner.py | 206 + tests/vendor/unittest2/signals.py | 57 + tests/vendor/unittest2/suite.py | 287 + tests/vendor/unittest2/util.py | 99 + tests/x509.der | Bin 656 -> 830 bytes tests/x509.pem | 142 +- tests/x509_key.pem | 27 + 471 files changed, 93189 insertions(+), 32050 deletions(-) create mode 100644 CONTRIBUTORS.rst delete mode 100644 INSTALL create mode 100644 INSTALL.rst delete mode 100644 M2Crypto.egg-info/PKG-INFO delete mode 100644 M2Crypto.egg-info/SOURCES.txt delete mode 100644 M2Crypto.egg-info/dependency_links.txt delete mode 100644 M2Crypto.egg-info/top_level.txt mode change 100755 => 100644 M2Crypto/BN.py delete mode 100644 M2Crypto/PGP/PublicKey.py delete mode 100644 M2Crypto/PGP/PublicKeyRing.py delete mode 100644 M2Crypto/PGP/RSA.py delete mode 100644 M2Crypto/PGP/__init__.py delete mode 100644 M2Crypto/PGP/constants.py delete mode 100644 M2Crypto/PGP/packet.py create mode 100644 M2Crypto/m2crypto.py create mode 100644 M2Crypto/six.py create mode 100644 MANIFEST.in delete mode 100644 PKG-INFO rename README => README.rst (65%) delete mode 100644 SWIG/Makefile.mw delete mode 100644 SWIG/Makefile.osx mode change 100755 => 100644 SWIG/_bn.i create mode 100644 SWIG/_lib11_compat.i create mode 100644 SWIG/_m2crypto_wrap.c create mode 100644 SWIG/_py3k_compat.i create mode 100644 SWIG/libcrypto-compat.h create mode 100644 SWIG/py3k_compat.h create mode 100644 appveyor.yml delete mode 100644 contrib/dave.patch delete mode 100644 contrib/m2crypto.spec delete mode 100644 demo/CipherSaber/CipherSaber.py delete mode 100644 demo/CipherSaber/cstest1.cs1 delete mode 100644 demo/Zope/ZServer/HTTPS_Server.py delete mode 100644 demo/Zope/ZServer/__init__.py delete mode 100644 demo/Zope/ZServer/medusa/ftps_server.py delete mode 100644 demo/Zope/ZServer/medusa/https_server.py delete mode 100644 demo/Zope/ca.pem delete mode 100644 demo/Zope/dh1024.pem delete mode 100644 demo/Zope/lib/python/Products/GuardedFile/GuardedFile.py delete mode 100644 demo/Zope/lib/python/Products/GuardedFile/README.txt delete mode 100644 demo/Zope/lib/python/Products/GuardedFile/TODO.txt delete mode 100644 demo/Zope/lib/python/Products/GuardedFile/__init__.py delete mode 100644 demo/Zope/lib/python/Products/GuardedFile/add.dtml delete mode 100644 demo/Zope/lib/python/Products/GuardedFile/refresh.txt delete mode 100644 demo/Zope/lib/python/Products/GuardedFile/version.txt delete mode 100644 demo/Zope/lib/python/Products/ZSmime/README.txt delete mode 100644 demo/Zope/lib/python/Products/ZSmime/SmimeTag.py delete mode 100644 demo/Zope/lib/python/Products/ZSmime/__init__.py delete mode 100644 demo/Zope/lib/python/Products/ZSmime/version.txt delete mode 100644 demo/Zope/server.pem delete mode 100644 demo/Zope/starts delete mode 100755 demo/Zope/starts.bat delete mode 100644 demo/Zope/utilities/x509_user.py delete mode 100644 demo/Zope/z2s.py delete mode 100644 demo/Zope/z2s.py.diff delete mode 100644 demo/Zope27/INSTALL.txt delete mode 100644 demo/Zope27/install_dir/lib/python/ZServer/HTTPS_Server.py delete mode 100644 demo/Zope27/install_dir/lib/python/ZServer/__init__.py.patch delete mode 100644 demo/Zope27/install_dir/lib/python/ZServer/component.xml.patch delete mode 100644 demo/Zope27/install_dir/lib/python/ZServer/datatypes.py.patch delete mode 100644 demo/Zope27/install_dir/lib/python/ZServer/medusa/https_server.py delete mode 100644 demo/Zope27/instance_home/README.txt.patch delete mode 100644 demo/Zope27/instance_home/etc/zope.conf.patch delete mode 100644 demo/Zope27/instance_home/ssl/ca.pem delete mode 100644 demo/Zope27/instance_home/ssl/dh1024.pem delete mode 100644 demo/Zope27/instance_home/ssl/server.pem delete mode 100644 demo/ZopeX3/INSTALL.txt delete mode 100644 demo/ZopeX3/install_dir/lib/python/zope/app/server/configure.zcml.patch delete mode 100644 demo/ZopeX3/install_dir/lib/python/zope/app/server/https.py delete mode 100644 demo/ZopeX3/install_dir/lib/python/zope/server/http/https_server.py delete mode 100644 demo/ZopeX3/install_dir/lib/python/zope/server/http/https_serverchannel.py delete mode 100644 demo/ZopeX3/install_dir/lib/python/zope/server/http/publisherhttps_server.py delete mode 100644 demo/ZopeX3/instance_home/etc/zope.conf.patch delete mode 100644 demo/ZopeX3/instance_home/ssl/ca.pem delete mode 100644 demo/ZopeX3/instance_home/ssl/dh1024.pem delete mode 100644 demo/ZopeX3/instance_home/ssl/server.pem delete mode 100644 demo/bio_mem_rw.py delete mode 100644 demo/dhtest.py delete mode 100644 demo/dsa1024pvtkey.pem delete mode 100644 demo/dsa_bench.py delete mode 100644 demo/dsatest.pem delete mode 100644 demo/dsatest.py delete mode 100644 demo/ec/ecdhtest.py delete mode 100644 demo/ec/ecdsa_bench.py delete mode 100644 demo/ec/ecdsatest.pem delete mode 100644 demo/ec/ecdsatest.py delete mode 100644 demo/ec/secp160r1pvtkey.pem delete mode 100644 demo/https.howto/ca.pem delete mode 100644 demo/https.howto/dh1024.pem delete mode 100755 demo/https.howto/get_https.py delete mode 100644 demo/https.howto/https_cli.py delete mode 100644 demo/https.howto/orig_https_srv.py delete mode 100644 demo/https.howto/server.pem delete mode 100644 demo/medusa/00_README delete mode 100644 demo/medusa/START.py delete mode 100644 demo/medusa/START_xmlrpc.py delete mode 100644 demo/medusa/asynchat.py delete mode 100644 demo/medusa/asyncore.py delete mode 100644 demo/medusa/auth_handler.py delete mode 100644 demo/medusa/ca.pem delete mode 100644 demo/medusa/counter.py delete mode 100644 demo/medusa/default_handler.py delete mode 100644 demo/medusa/dh1024.pem delete mode 100644 demo/medusa/filesys.py delete mode 100644 demo/medusa/ftp_server.py delete mode 100644 demo/medusa/ftps_server.py delete mode 100644 demo/medusa/http_date.py delete mode 100644 demo/medusa/http_server.py delete mode 100644 demo/medusa/https_server.py delete mode 100644 demo/medusa/index.html delete mode 100644 demo/medusa/logger.py delete mode 100644 demo/medusa/m_syslog.py delete mode 100644 demo/medusa/medusa_gif.py delete mode 100644 demo/medusa/mime_type_table.py delete mode 100644 demo/medusa/poison_handler.py delete mode 100644 demo/medusa/producers.py delete mode 100644 demo/medusa/put_handler.py delete mode 100644 demo/medusa/redirecting_handler.py delete mode 100644 demo/medusa/server.pem delete mode 100644 demo/medusa/status_handler.py delete mode 100644 demo/medusa/virtual_handler.py delete mode 100644 demo/medusa/xmlrpc_handler.py delete mode 100644 demo/medusa054/00_README delete mode 100644 demo/medusa054/START.py delete mode 100644 demo/medusa054/START_xmlrpc.py delete mode 100644 demo/medusa054/ca.pem delete mode 100644 demo/medusa054/counter.py delete mode 100644 demo/medusa054/default_handler.py delete mode 100644 demo/medusa054/dh1024.pem delete mode 100644 demo/medusa054/filesys.py delete mode 100644 demo/medusa054/ftp_server.py delete mode 100644 demo/medusa054/ftps_server.py delete mode 100644 demo/medusa054/http_date.py delete mode 100644 demo/medusa054/http_server.py delete mode 100644 demo/medusa054/https_server.py delete mode 100644 demo/medusa054/index.html delete mode 100644 demo/medusa054/logger.py delete mode 100644 demo/medusa054/m_syslog.py delete mode 100644 demo/medusa054/medusa_gif.py delete mode 100644 demo/medusa054/poison_handler.py delete mode 100644 demo/medusa054/producers.py delete mode 100644 demo/medusa054/server.pem delete mode 100644 demo/medusa054/status_handler.py delete mode 100644 demo/medusa054/xmlrpc_handler.py delete mode 100644 demo/perf/memio.py delete mode 100644 demo/perf/sha1.py delete mode 100644 demo/pgp/pgpstep.py delete mode 100644 demo/pgp/pubring.pgp delete mode 100644 demo/pgp/secring.pgp delete mode 100644 demo/pkcs7/pkcs7-thawte.pem delete mode 100644 demo/pkcs7/test.py delete mode 100644 demo/rsa.priv.pem delete mode 100644 demo/rsa.priv0.pem delete mode 100644 demo/rsa.pub.pem delete mode 100644 demo/rsa1024pvtkey.pem delete mode 100644 demo/rsa_bench.py delete mode 100644 demo/rsatest.py delete mode 100644 demo/smime.howto/README delete mode 100644 demo/smime.howto/decrypt.py delete mode 100644 demo/smime.howto/dv.py delete mode 100644 demo/smime.howto/encrypt.p7 delete mode 100644 demo/smime.howto/encrypt.py delete mode 100644 demo/smime.howto/recipient.pem delete mode 100644 demo/smime.howto/recipient_key.pem delete mode 100644 demo/smime.howto/se.p7 delete mode 100644 demo/smime.howto/se.py delete mode 100644 demo/smime.howto/sendsmime.py delete mode 100644 demo/smime.howto/sign.p7 delete mode 100644 demo/smime.howto/sign.py delete mode 100644 demo/smime.howto/signer.pem delete mode 100644 demo/smime.howto/signer_key.pem delete mode 100644 demo/smime.howto/verify.py delete mode 100644 demo/smime/README delete mode 100644 demo/smime/ca.pem delete mode 100644 demo/smime/clear.p7 delete mode 100644 demo/smime/client.p12 delete mode 100644 demo/smime/client.pem delete mode 100644 demo/smime/client2.pem delete mode 100644 demo/smime/m2.se.p7 delete mode 100644 demo/smime/ns.p7 delete mode 100644 demo/smime/ns.se.p7 delete mode 100644 demo/smime/opaque.p7 delete mode 100644 demo/smime/sendsmime.py delete mode 100644 demo/smime/test.py delete mode 100644 demo/smime/unsmime.py delete mode 100644 demo/ssl/README delete mode 100644 demo/ssl/c.py delete mode 100644 demo/ssl/c_bio.py delete mode 100644 demo/ssl/ca.der delete mode 100644 demo/ssl/ca.pem delete mode 100644 demo/ssl/client.p12 delete mode 100644 demo/ssl/client.pem delete mode 100644 demo/ssl/dh1024.pem delete mode 100644 demo/ssl/echo-eg.py delete mode 100644 demo/ssl/echo.py delete mode 100644 demo/ssl/echod-async.py delete mode 100644 demo/ssl/echod-eg1.py delete mode 100644 demo/ssl/echod-forking.py delete mode 100644 demo/ssl/echod-iterative.py delete mode 100644 demo/ssl/echod-thread.py delete mode 100644 demo/ssl/echod-threading.py delete mode 100644 demo/ssl/echod_lib.py delete mode 100644 demo/ssl/ftp_tls.py delete mode 100644 demo/ssl/http_cli_20.py delete mode 100644 demo/ssl/https_cli.py delete mode 100644 demo/ssl/https_cli_async.py delete mode 100644 demo/ssl/https_srv.py delete mode 100644 demo/ssl/myapp.py delete mode 100644 demo/ssl/s_client.py delete mode 100644 demo/ssl/s_server.py delete mode 100644 demo/ssl/server.pem delete mode 100644 demo/ssl/server3.py delete mode 100644 demo/ssl/sess.py delete mode 100644 demo/ssl/sess2.py delete mode 100644 demo/ssl/sess2.ssldump.out delete mode 100644 demo/ssl/socklib.py delete mode 100644 demo/ssl/somelib.py delete mode 100644 demo/ssl/ss.py delete mode 100755 demo/ssl/twistedsslclient.py delete mode 100755 demo/ssl/twistedsslserver.py delete mode 100644 demo/ssl/xmlrpc_cli.py delete mode 100644 demo/ssl/xmlrpc_srv.py delete mode 100644 demo/tinderbox/build_lib.py delete mode 100644 demo/tinderbox/killableprocess.py delete mode 100755 demo/tinderbox/slave.py delete mode 100644 demo/tinderbox/winprocess.py delete mode 100644 demo/x509/ca.py delete mode 100755 demo/x509/certdata2pem.py delete mode 100644 demo/x509/client2.pem delete mode 100644 demo/x509/demo1.py delete mode 100644 demo/x509/proxy_destroy.py delete mode 100644 demo/x509/proxy_info.py delete mode 100644 demo/x509/proxy_init.py delete mode 100644 demo/x509/proxylib.py delete mode 100644 demo/x509/server-expired.pem delete mode 100644 demo/x509/server.pem delete mode 100644 demo/x509/x509auth.py create mode 100644 dev-requirements.txt create mode 100644 doc/M2Crypto.SSL.rst create mode 100644 doc/M2Crypto.rst create mode 100644 doc/Makefile delete mode 100644 doc/ZServerSSL-HOWTO.html create mode 100644 doc/ZServerSSL-HOWTO.rst create mode 100644 doc/conf.py create mode 100644 doc/doctrees/M2Crypto.SSL.doctree create mode 100644 doc/doctrees/M2Crypto.doctree create mode 100644 doc/doctrees/ZServerSSL-HOWTO.doctree create mode 100644 doc/doctrees/environment.pickle create mode 100644 doc/doctrees/howto.ca.doctree create mode 100644 doc/doctrees/howto.smime.doctree create mode 100644 doc/doctrees/howto.ssl.doctree create mode 100644 doc/doctrees/index.doctree delete mode 100644 doc/howto.ca.html create mode 100644 doc/howto.ca.rst delete mode 100644 doc/howto.smime.html create mode 100644 doc/howto.smime.rst delete mode 100644 doc/howto.ssl.html create mode 100644 doc/howto.ssl.rst create mode 100644 doc/html/.buildinfo create mode 100644 doc/html/M2Crypto.SSL.html create mode 100644 doc/html/M2Crypto.html create mode 100644 doc/html/ZServerSSL-HOWTO.html create mode 100644 doc/html/_modules/M2Crypto/ASN1.html create mode 100644 doc/html/_modules/M2Crypto/AuthCookie.html create mode 100644 doc/html/_modules/M2Crypto/BIO.html create mode 100644 doc/html/_modules/M2Crypto/BN.html create mode 100644 doc/html/_modules/M2Crypto/DH.html create mode 100644 doc/html/_modules/M2Crypto/DSA.html create mode 100644 doc/html/_modules/M2Crypto/EC.html create mode 100644 doc/html/_modules/M2Crypto/EVP.html create mode 100644 doc/html/_modules/M2Crypto/Engine.html create mode 100644 doc/html/_modules/M2Crypto/Err.html create mode 100644 doc/html/_modules/M2Crypto/RC4.html create mode 100644 doc/html/_modules/M2Crypto/RSA.html create mode 100644 doc/html/_modules/M2Crypto/Rand.html create mode 100644 doc/html/_modules/M2Crypto/SMIME.html create mode 100644 doc/html/_modules/M2Crypto/SSL.html create mode 100644 doc/html/_modules/M2Crypto/SSL/Checker.html create mode 100644 doc/html/_modules/M2Crypto/SSL/Cipher.html create mode 100644 doc/html/_modules/M2Crypto/SSL/Connection.html create mode 100644 doc/html/_modules/M2Crypto/SSL/Context.html create mode 100644 doc/html/_modules/M2Crypto/SSL/SSLServer.html create mode 100644 doc/html/_modules/M2Crypto/SSL/Session.html create mode 100644 doc/html/_modules/M2Crypto/SSL/TwistedProtocolWrapper.html create mode 100644 doc/html/_modules/M2Crypto/SSL/cb.html create mode 100644 doc/html/_modules/M2Crypto/SSL/ssl_dispatcher.html create mode 100644 doc/html/_modules/M2Crypto/SSL/timeout.html create mode 100644 doc/html/_modules/M2Crypto/X509.html create mode 100644 doc/html/_modules/M2Crypto/ftpslib.html create mode 100644 doc/html/_modules/M2Crypto/httpslib.html create mode 100644 doc/html/_modules/M2Crypto/m2urllib.html create mode 100644 doc/html/_modules/M2Crypto/m2urllib2.html create mode 100644 doc/html/_modules/M2Crypto/m2xmlrpclib.html create mode 100644 doc/html/_modules/M2Crypto/threading.html create mode 100644 doc/html/_modules/M2Crypto/util.html create mode 100644 doc/html/_modules/index.html create mode 100644 doc/html/_modules/urllib/request.html create mode 100644 doc/html/_sources/M2Crypto.SSL.rst.txt create mode 100644 doc/html/_sources/M2Crypto.rst.txt create mode 100644 doc/html/_sources/ZServerSSL-HOWTO.rst.txt create mode 100644 doc/html/_sources/howto.ca.rst.txt create mode 100644 doc/html/_sources/howto.smime.rst.txt create mode 100644 doc/html/_sources/howto.ssl.rst.txt create mode 100644 doc/html/_sources/index.rst.txt create mode 100644 doc/html/_static/ajax-loader.gif create mode 100644 doc/html/_static/alabaster.css create mode 100644 doc/html/_static/basic.css create mode 100644 doc/html/_static/comment-bright.png create mode 100644 doc/html/_static/comment-close.png create mode 100644 doc/html/_static/comment.png create mode 100644 doc/html/_static/custom.css create mode 100644 doc/html/_static/doctools.js create mode 100644 doc/html/_static/documentation_options.js create mode 100644 doc/html/_static/down-pressed.png create mode 100644 doc/html/_static/down.png create mode 100644 doc/html/_static/file.png create mode 100644 doc/html/_static/jquery-3.2.1.js create mode 100644 doc/html/_static/jquery.js create mode 100644 doc/html/_static/language_data.js create mode 100644 doc/html/_static/minus.png create mode 100644 doc/html/_static/plus.png create mode 100644 doc/html/_static/pygments.css create mode 100644 doc/html/_static/searchtools.js create mode 100644 doc/html/_static/underscore-1.3.1.js create mode 100644 doc/html/_static/underscore.js create mode 100644 doc/html/_static/up-pressed.png create mode 100644 doc/html/_static/up.png create mode 100644 doc/html/_static/websupport.js create mode 100644 doc/html/genindex.html create mode 100644 doc/html/howto.ca.html create mode 100644 doc/html/howto.smime.html create mode 100644 doc/html/howto.ssl.html create mode 100644 doc/html/index.html create mode 100644 doc/html/objects.inv create mode 100644 doc/html/py-modindex.html create mode 100644 doc/html/search.html create mode 100644 doc/html/searchindex.js create mode 100644 doc/index.rst create mode 100644 doc/make.bat delete mode 100755 fedora_setup.sh delete mode 100644 pack.py create mode 100644 pylintrc create mode 100644 tests/bad_date_cert.crt create mode 100644 tests/ca_key.pem create mode 100644 tests/easy_rsa.pem create mode 100755 tests/makecerts.py create mode 100644 tests/sample-p7.pem create mode 100644 tests/server_key.pem create mode 100644 tests/te_chunked_response.txt create mode 100644 tests/test_aes.py mode change 100644 => 100755 tests/test_authcookie.py mode change 100755 => 100644 tests/test_bn.py create mode 100644 tests/test_err.py delete mode 100644 tests/test_pgp.py create mode 100644 tests/test_timeout.py create mode 100644 tests/test_util.py create mode 100644 tests/vendor/unittest2/__init__.py create mode 100644 tests/vendor/unittest2/__main__.py create mode 100644 tests/vendor/unittest2/case.py create mode 100644 tests/vendor/unittest2/collector.py create mode 100644 tests/vendor/unittest2/compatibility.py create mode 100644 tests/vendor/unittest2/loader.py create mode 100644 tests/vendor/unittest2/main.py create mode 100644 tests/vendor/unittest2/result.py create mode 100644 tests/vendor/unittest2/runner.py create mode 100644 tests/vendor/unittest2/signals.py create mode 100644 tests/vendor/unittest2/suite.py create mode 100644 tests/vendor/unittest2/util.py create mode 100644 tests/x509_key.pem diff --git a/CHANGES b/CHANGES index 8355a94..882a835 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,191 @@ +0.35.1 - 2019-06-08 +------------------- + +- Actually, really fix compatibility with OpenSSL 1.1.1c. Thank you, + Sebastian Andrzej Siewior from the Debian team for resolving it. + +0.34.0 - 2019-05-30 +------------------- + +- Use more recent version of OpenSSL on Windows +- Be resilient against the situation when no erorr happened. +- Correct URL of https://www.schneier.com/academic/smime/ +- Use shlex.split() for CPP + +0.33.0 - 2019-04-26 +------------------- + +- eb4525c - Stop pretending to support Python 3.4. +- 6a89548 - Fix use of urlunsplit (25 hours ago) +- 0a5a356 - tests/test_ssl: use -ciphercuites for TLS1.3 cipher in + openssl1.1 +- 8a0a3e3 - There are apparently multiword CPP variables. Taking that + into account. + +0.32.0 - 2019-03-04 +------------------- + +- 471582f - setup.py: use ${CPP} as path to cpp +- efb1580 - Bump pipeline OpenSSL from 1.1.0i to 1.1.0j +- 35bb71b - Stub wchar_t helpers and ignore unused WCHAR defs +- effc7be - Add type comment to setup.py + +0.31.0 - 2018-11-08 +------------------- + +- Compatibility with OpenSSL 1.1.1 (partly workaround, maybe requires + further investigation) +- Fixes for Windows builds +- Fixes of installs on AWS Lambda +- Fixes of Mac OS X related failures +- Fix Python 2.6 compatibility issues + +0.30.1 - 2018-04-29 +------------------- +- Fix packaging (missed packaging testing file) + +0.30.0 - 2018-04-25 +------------------- +- Various small typos (Windows builds, Fix SSL.Connection.__del__) +- The project is now Linux-distribution agnostic +- Replace all old-style classes with the new ones (it shouldn't cause + any problems, but feel free to file an issue, if it does) +- Do not by-pass a potential transfer decoding in m2urllib2 +- Update M2Crypto.six with 1.11.0 and replace our local workarounds with + new functions. +- SSLv3 just removed. +- Don't support Python 2.6 on Windows anymore. Windows users don't have + python as a system package, so they are usually more likely to upgrade + anyway. + +0.29.0 - 2018-02-23 +------------------- +- Fix building on Windows (all tests fix on Win32 and Win64 on all + supported combinations of versions of OpenSSL and Python) +- Fixes of some small bugs + +0.28.0 - 2018-02-08 +------------------- +- Mainly port to Python 3 (supporting 2.6, 2.7, 3.3, 3.4, 3.5, 3.6) +- Some lame efforts to make setup.py build --openssl work better (needs + more real testing on Mac OS X) +- Fix licence: it is MIT, not BSD +- Fix and add tests for SWIG/_aes.i module +- Improve somehow situation on Mac OS X (some testing, improve setup.py, + testsuite should fully pass) +- Bundle-in unittest2 for Python 2.6 (dealing with the need for + specific version of unittest2 package was too complicated) +- Remove all PGP modules + +0.27.0 - 2017-10-05 +------------------- +- Fix licence: it is MIT, not BSD +- At least minimal support of SNI in httpslib. +- Small bugfixes and cleanups. +- More effort to make build system more robust (now should work even on + Debian LTS). +- Restore m2.rsa_set_e() and m2.rsa_set_n(). +- Make sure that every exceptional return throws and exception and vice + versa. + +0.26.4 - 2017-09-26 +------------------- +- Proper fix of deprecation warning for OpenSSL 1.1.0 +- Small mostly stylistic bugfixes +- Emergency release to fix FTBFS. + +0.26.3 - 2017-09-22 +------------------- +- Fix a syntax typo. + +0.26.2 - 2017-09-20 +------------------- +- port to support OpenSSL 1.1.0 API +- add generated Sphinx documentation +- another set of cleanups + +0.26.0 - 2017-03-21 +------------------- +- Fix packaging on RHEL-6 +- Replace ASN1_UTCTIME with ASN1_TIME which supports both UTCTime and + GeneralizedTime +- Add possibility to sign PKCS7 with a non-default digest. +- Add possibility to set custom callback for X509 verification. +- Clean up imports and PEP8ization +- A lot of cleanups on the way towards Python 3 +- Other small bugfixes + +0.25.1 - 2016-07-25 +------------------- +- Actually do check, whether we have SSLv2 compiled in, and don't run + test for it. + +0.25.0 - 2016-03-21 +------------------- +- More cleanups, removal of obsolete stuff, and moves towards py3k + compatibility. +- Add support for EC.get_builtin_curves() and use it for testing. +- Enable AES CTR mode +- Bundle-in six module v. 1.10.0 +- add rand_file_name and rand_status +- remove all LHASH fiddling +- Extend Travis and GitLab CI configuration to test also py3k (with + allowed_failures) and CentOS6 (on GitLab CI). +- Add CONTRIBUTORS.rst. Thank you! +- Add PEP-484 type hints in comments to all Python files (except for + tests) +- Use context managers for file handling wherever possible instead of + leaking open file descriptors. +- Improve defaults handling for SSL_CTX_new(). +- Fix PGP tests to actually run + +0.24.0 - 2016-03-21 +------------------- +- More cleanups, removal of obsolete stuff, and moves towards py3k + compatibility. +- Add DSA.pub_key_from_params() factory function (and m2.dsa_set_pub()). +- Allow import/export of EC public key with binary values +- Add EVP.load_key_string_pubkey() function, as well as helper functions +- Add EVP.get_digestbyname() functionality. +- Convert documentation to rST (and add instructions for building on Mac + OS X) +- Another round of fixing multiarch building. +- Disable tests with weak ciphers on some platforms (Debain) + +0.23.0 - 2016-01-29 +------------------- +- Add Travis and GitLab CI configurations +- Allow building without SSLv2 +- More cleanups and removing obsolete code +- Fix README +- Fix buffer overflow in pkcs5_pbkdf2_hmac_sha1 +- First moves towards Python 3 compatibility +- Removed rather large and completely unmaintained demo/ subdirectory + (now in a separate repo https://gitlab.com/m2crypto/m2crypto_demo) +- Automatically generated test data files +- Finally fix building on multiarch systems +- All objects derived from BIO.BIO now could work as context managers +- Switch setup.py to setuptools + +0.22.5 - 2015-10-13 +------------------- +- Add forgoteen SWIG/*.h among distributed files. + +0.22.4 - 2015-10-13 +------------------- +- Matěj Cepl takes over leadership of the upstream maintenance +- Fedora/RHEL distribution patches merged to the main development + (mainly, but not only, upgrading to the more recent versions of + OpenSSL, swig which is now at 3.0.5, but anything above 2.0.4 is + supported as well, and python which now has to be at least 2.6). +- Tons of cleaning up the code for obsolete constructs, PEP8ization, + etc. + +0.22.3 - 2014-01-22 +------------------- +(released by Martin Paljak, later development started on top of 0.21.1 +with his improvements cherry picked to the new development branch) + 0.21.1 - 2011-01-15 ------------------- - Distribution fix @@ -43,7 +231,7 @@ was held by another thread, by Miloslav Trmac - Allow more blocking OpenSSL functions to run without GIL, by Miloslav Trmac - Fixed httpslib to send only the path+query+fragment part of the URL when - using CONNECT proxy, by James Bowes + using CONNECT proxy, by James Bowes - SSLServer.__init__ now takes optional bind_and_activate parameter and initializes by calling SocketServer.BaseServer.__init__, which are Python 2.6 compatibility fixes, by Christian @@ -54,7 +242,7 @@ - Added support for disabling padding when using RSA encryption, by Chris Collis - ASN1_INTEGERs can now be larger than fits in an int, for example to support - X509 certificates with large serial numbers, + X509 certificates with large serial numbers, patch by Mikhail Vorozhtsov and testcase by Barry G. - Reverted a change done in 0.17 to m2urllib2 which changed urls to include host when it should stay as it was @@ -180,7 +368,7 @@ are both None - Fixed X509.check_purpose() (was always raising exceptions) - smime_read_pkcs7 was changed to automatically call BIO_set_mem_eof_return - on memory BIOs because otherwise the read would fail with + on memory BIOs because otherwise the read would fail with "SMIME_Error: not enough data" - X509.new_extension('subjectKeyIdentifier', 'hash') raises ValueError instead of crashing Python @@ -262,7 +450,7 @@ M2Crypto.Rand. - Updated ZServerSSL files to match Zope 2.7.0 versions. - Integrated (overlapping) patches by Peter Teniz and Heikki Toivonen - covering operations on X.509-related structures that gives M2Crypto + covering operations on X.509-related structures that gives M2Crypto PKI functionality. Thanks Peter and Heikki. - Peter Teniz contributed demo2004/pki/x509auth.py. - Created demo2004/ directory that will contain new or updated demos. @@ -274,15 +462,15 @@ ------------------------- - Patches from Artur Frysiak . Thanks Artur. = Allow using a passphrase callback in class SMIME. - = Added method get0_signers to class PKCS7, which retrieves signers' + = Added method get0_signers to class PKCS7, which retrieves signers' certificates from a PKCS7 blob. = Added methods as_pem and save_pem to class X509. = Added file version.py. - = Allow SSL.Context.load_verify_locations to accept both 'cafile' and + = Allow SSL.Context.load_verify_locations to accept both 'cafile' and 'capath'. -- Fixed BIO.read() not reading until EOF. Thanks to Egil Muller +- Fixed BIO.read() not reading until EOF. Thanks to Egil Muller for suggestion. -- Honour 'mode' parameter in SSL.Connection.makefile. Thanks again to Egil +- Honour 'mode' parameter in SSL.Connection.makefile. Thanks again to Egil Muller. - Roger Binns contributed epydoc-generated docs for M2Crypto. Thanks Roger. - Peter Teniz contributed patches to create X.509 requests and certificates. @@ -295,24 +483,24 @@ -------------------- - ZServerSSL with client certificate-based authentication rides again. - Created Makefile for Python 2.3. -- Modified LICENCE: changed my name to the generic "the author" in the +- Modified LICENCE: changed my name to the generic "the author" in the all-caps disclaimer paragraph. - Allow to save RSA key pair in the clear. - ZServerSSL for Zope 2.7. -- Excluded RC5. IDEA was taken out several releases ago. This should +- Excluded RC5. IDEA was taken out several releases ago. This should allow M2Crypto to build with stock OpenSSL on various Linuxen. - Added ssl_set_tmp_dh_callback. - Added ssl_set_tmp_rsa and ssl_set_tmp_rsa_callback to support weak-cipher browsers. -- ZServerSSL exports SSL_CIPHER request header (a la mod_ssl) to Zope +- ZServerSSL exports SSL_CIPHER request header (a la mod_ssl) to Zope applications. - Perform distutils's SWIG .i search path tweaking within setup.py. setup.py should now work "out of the box". -- Added contrib/smimeplus.py, a high-level S/MIME interface, contributed by +- Added contrib/smimeplus.py, a high-level S/MIME interface, contributed by Bernard Yue . Thanks Bernard. -- Added in long forms of nid's in X509_Name. Thanks to William K Volkman +- Added in long forms of nid's in X509_Name. Thanks to William K Volkman for patch. -- Updated Mac OS X build instructions. Thanks to Larry Bugbee +- Updated Mac OS X build instructions. Thanks to Larry Bugbee Changes since 0.10 @@ -335,19 +523,19 @@ Changes since 0.09 -------------------- - Updated to OpenSSL 0.9.7. Thanks to Toby Allsopp for - patches. -- Added functionality to create a basic certificate request. Also - contributed by Toby Allsopp. + patches. +- Added functionality to create a basic certificate request. Also + contributed by Toby Allsopp. - Finally, AES! Changes since 0.08 -------------------- -- Replaced demo/Zope/ZServer/__init__.py with the correct version +- Replaced demo/Zope/ZServer/__init__.py with the correct version for Zope 2.6.0. - Added a sample starts.bat for ZServerSSL. - Incoporated a patch by prashanth@jibe.biz that handled the - new-in-Python-2.2.2 "strict" parameter for the various HTTP[S] connection + new-in-Python-2.2.2 "strict" parameter for the various HTTP[S] connection classes in httplib.py. Thanks prashanth. This fixes M2Crypto's XMLRPC support for Python 2.2.2. (Apparently it was working for Python 2.2.1.) - Incorporated some cosmetic patches from Adam Karpierz . @@ -365,7 +553,7 @@ - Included in contrib/ Isaac Salzberg's application of Mihai Ibanescu's patch that allows IIS interoperability thru an authenticating proxy. Thanks Isaac. -- Included in contrib/ patch by Dave Brueck +- Included in contrib/ patch by Dave Brueck that has smarter non-blocking behaviour. Thanks Dave. @@ -387,7 +575,7 @@ Changes since 0.05 ----------------------- - Handled the cases where Python callbacks raised exceptions. -- Fixed a NULL-deref bug in _ssl.i which crashes Medusa https when IE +- Fixed a NULL-deref bug in _ssl.i which crashes Medusa https when IE or Opera comes a-calling. - ZServerSSL rides again - a more robust ZServerSSL for Zope 2.3.0. - Added the MIME type 'application/x-x509-ca-cert' to @@ -411,17 +599,17 @@ - Fixed yet more memory leaks. Thanks to Ray Suorsa . - Build instructions for Borland BC++ 5.5 free compiler suite. - Bundles the June 2000 unencumbered release of Medusa. -- SSL callback thread-safety. Thanks again to Ray Suorsa for insights and +- SSL callback thread-safety. Thanks again to Ray Suorsa for insights and patches. -- Renamed M2Crypto.M2Crypto to M2Crypto.m2 to prevent package/module loading +- Renamed M2Crypto.M2Crypto to M2Crypto.m2 to prevent package/module loading confusion. - SSL.Session and a demo in demo/ssl/sess.py. - https_srv.py, an enhanced, https version of SimpleHTTPServer.py. -- Interface change: SMIME.load_pkcs7_bio() is renamed - SMIME.smime_load_pkcs7_bio(), similarly SMIME.load_pkcs7() to +- Interface change: SMIME.load_pkcs7_bio() is renamed + SMIME.smime_load_pkcs7_bio(), similarly SMIME.load_pkcs7() to SMIME.smime_load_pkcs7(); these load PKCS7 objects generated by S/MIME. -- Interface change: SMIME.load_pkcs7_bio() now loads a PKCS7 PEM file, i.e., a - file of the format "-----BEGIN PKCS7-----". +- Interface change: SMIME.load_pkcs7_bio() now loads a PKCS7 PEM file, i.e., a + file of the format "-----BEGIN PKCS7-----". - Works with both Python 2.0 and Python 1.5.2. - OpenSSL 0.9.6. (Possibly incompatible with earlier OpenSSL releases.) - Unit tests with PyUnit. @@ -430,7 +618,7 @@ = Diligent error checking. = Fixed memory leaks. - Renamed M2Crypto.urllib2 to M2Crypto.m2urllib. -- HTTPS clients of Python 1.5.2's and Python 2.0's httplib and urllib. +- HTTPS clients of Python 1.5.2's and Python 2.0's httplib and urllib. Changes since 0.03 @@ -444,7 +632,7 @@ - Unified SSL read() and write() for synchronous and asynchronous operation. - S/MIME and PKCS #7. - Integrated with OpenSSL 0.9.5. -- Enhanced the PRNG interface. +- Enhanced the PRNG interface. Changes since 0.02 @@ -457,7 +645,7 @@ 6. Beginnings of PGP2 support. 7. Replaced eval() calls with other (hopefully) safe ones. 8. Miscellaneous enhancements and bug fixes. - + Changes since 0.01 ----------------------- @@ -467,12 +655,12 @@ - An SSLServer modeled after SocketServer. - A ForkingSSLServer that seems to work well. - A ThreadingSSLServer that runs one thread at a time. (!) ;-) - + For building servers, nonblocking i/o: - An ssl_dispatcher modeled after asyncore.dispatcher. A HTTPS server based on Medusa. - + For client-side web programming: - httpslib - urllib2 @@ -482,7 +670,7 @@ 3. Reduced per-module name space pollution. 4. Have Swig check for NULL pointers: reduced .i cut-&-paste. 5. Standardise on MPINT for passing big integers between Python and OpenSSL. -6. Removed MD5, SHA1, RIPEMD160. Just use EVP.MessageDigest. -7. Removed HMAC. Just use EVP.HMAC. +6. Removed MD5, SHA1, RIPEMD160. Just use EVP.MessageDigest. +7. Removed HMAC. Just use EVP.HMAC. diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst new file mode 100644 index 0000000..d46dff0 --- /dev/null +++ b/CONTRIBUTORS.rst @@ -0,0 +1,43 @@ +* The original project was created inside of the huge `Chandler project`_ + where it was mostly work of Ng Pheng Siong [#]_ . + +* Then for a log time it was maintained and extended to the large part + by Heikki Toivonen. + +With 247 and 415 commits, respectively, these two first maintainers +provided by far the biggest amount of work on the project. Thank you. + +* An attempt to restart the project was made by Martin Paljak. Although + his effort was most mostly discarded in the end, all his suggested + changes were reviewed and some of them incorporated in some other + form. Just two commits of his remaining in the tree hugely + underestimate an effort he made to keep this project alive. Thank you + very much for your work. + +* Plenty of work on keeping this project alive was made by the + maintainer of the package inside of RHEL, Martin Trmač. He also helped + a lot by advice with this last effort to revive the project, and his + pestering me to do proper small commits rather than freaking dumps of + my current thoughts helped to make changes to be made a little bit + better (and revieweable). + +* This last hyena-like effort to revive a dead carcas has been started + by Matěj Cepl. + +* I got a lot of help especially with reviewing patches from Hubert + Kario. + +* Craig Rodrigues didn't loose the hope that M2Crypto could be ported to + be py3k-compatible, which lead to the renewed effort to do so. He also + helped with plenty of patches in this effort. + +* Casey Deccio helped a lot with fixing EC module. + +* Remaining contributors could be find in the output of ``git shortlog + -s`` command. Thank you to all. + +.. _`Chandler project`: + https://en.wikipedia.org/wiki/Chandler_%28software%29 + +.. [#] His and everybody else emails can be found in the git log, + I won't make spammers even more happy to collect them here. diff --git a/INSTALL b/INSTALL deleted file mode 100644 index f67fed4..0000000 --- a/INSTALL +++ /dev/null @@ -1,226 +0,0 @@ -==================== - Installing M2Crypto -==================== - -:Maintainer: Heikki Toivonen -:Web-Site: http://chandlerproject.org/Projects/MeTooCrypto - -.. contents:: - - -Pre-requisites ----------------- - -The following software packages are pre-requisites: - -- **Python 2.3 or newer** -- **OpenSSL 0.9.7 or newer** -- **SWIG 1.3.28 or newer** - -Note about OpenSSL versions early in the 0.9.7 series ------------------------------------------------------ - -Early OpenSSL 0.9.7 versions require the __i386__ symbol to be defined. -Uncomment this line in setup.py: - - #'-D__i386__', # Uncomment for early OpenSSL 0.9.7 versions - -if you get this compile-time error: - - This openssl-devel package does not work your architecture? - -Note about Fedora Core -based Distributions ------------------------------------------------------ - -Fedora Core (and RedHat, CentOS etc.) have made changes to OpenSSL -configuration compared to many other Linux distributions. If you can not -build M2Crypto normally, try the fedora_setup.sh script included with -M2Crypto sources. - -Installing on Unix-like systems, including Cygwin -------------------------------------------------- - -:: - - $ tar zxf m2crypto-.tar.gz - $ cd m2crypto- - $ python setup.py build - $ python setup.py install - -If you have installed setuptools you can also optionally run tests like this: - - $ python setup.py test - -This assumes OpenSSL is installed in /usr. You can provide an alternate -OpenSSL prefix location with --openssl option to build_ext command. Other -commands accept standard options if you need them. - -Some distributions, like Fedora Core, package OpenSSL headers in a different -location from OpenSSL itself. In that case you need to tell build_ext the -additional include location with -I option. - -Differences when installing on Windows --------------------------------------- - -Before building from source, you need to install OpenSSL's include files, -import libraries and DLLs. By default setup.py assumes that OpenSSL include -files are in ``c:\pkg\openssl\include``, and the import libraries -in ``c:\pkg\openssl\lib``. As with other platforms, you can specify a different -OpenSSL location with --openssl option to build_ext command. - -Using OpenSSL 0.9.8 on Windows requires Python be built with applink.c -(add an include statement in python.c). This is not a requirement for -Linux or MacOSX. (applink.c is provided by OpenSSL.) - - -MSVC++ -~~~~~~~~ - -setup.py is already configured to work with MSVC++ by default. - -With MSVC++, the OpenSSL DLLs, as built, are named ``libeay32.dll`` -and ``ssleay32.dll``. Install these somewhere on your PATH; for example -in ``c:\bin``, together with ``openssl.exe``. - -For MSVC++, the import libraries, as built by OpenSSL, are named -``libeay32.lib`` and ``ssleay32.lib``. - - -MINGW -~~~~~~~ - -.. NOTE:: - The following instructions for building M2Crypto with MINGW are from - M2Crypto 0.12. These instructions should continue to work for this release, - although I have not tested them. - -Read Sebastien Sauvage's webpage: - - http://sebsauvage.net/python/mingw.html - -For mingw32, the OpenSSL import libraries are named ``libeay32.a`` and -``libssl32.a``. You may need to edit setup.py file for these. - -You'll also need to create ``libpython2[123].a``, depending on your version -of Python. - -OpenSSL DLLs for mingw32 are named ``libeay32.dll`` and ``libssl32.dll``. -Install these somewhere on your PATH; for example in -``c:\bin``, together with ``openssl.exe``. - -Build M2Crypto: - - python setup.py build -cmingw32 - python setup.py install - - -BC++ -~~~~~~ - -.. NOTE:: - The following instructions for building M2Crypto with MSVC++ 6.0 and - BC++ 5.5 free compiler suite are from M2Crypto 0.10. These instructions - should continue to work for this release, although I have not tested - them. - -For BC++ these files are created from the MSVC++-built ones using the -tool ``coff2omf.exe``. I call them ``libeay32_bc.lib`` and -``ssleay32_bc.lib``, respectively. You will need to edit setup.py file -for these. - -You'll also need Python's import library, e.g., ``python22.lib``, to -be the BC++-compatible version; i.e., create ``python22_bc.lib`` from -``python22.lib``, save a copy of ``python22.lib`` (as ``python22_vc.lib``, -say), then rename ``python22_bc.lib`` to ``python22.lib``. - - -Now you are ready to build M2Crypto. Do one of the following:: - - python setup.py build - python setup.py build -cbcpp - -Then, - -:: - - python setup.py install - - -MacOSX ------- - -Follow the standard instructions to build and install M2Crypto. -However, should you encounter difficulties, you may want to consider -the following possibilities. - - - Distutils for Python 2.5 now provides support for universal - builds (ppc and i386) and Distutils requires a recent version - of Xcode. See http://developer.apple.com/tools/download/ - - - OpenSSL 0.9.7l gets installed in /usr with Apple's Security - Update 2006-007. If you need features in OpenSSL 0.9.8, you - should consider installing 0.9.8 in /usr/local. The commands - are: - - OpenSSL: - ./config shared --prefix=/usr/local - make - make test - sudo make install [or... install_sw] - - M2Crypto: - python setup.py build build_ext --openssl=/usr/local - sudo python setup.py install build_ext --openssl=/usr/local - -To make Universal builds, you will need to uncomment a line in setup.py: - - extra_link_args = ['-Wl,-search_paths_first'], - -If that does not work, here is what Marc Hedlund was able to get working: - - First, download OpenSSL 0.9.8d and unpack it. Edit the OpenSSL Makefiles - per PROBLEMS. Then: - - ./config no-shared no-asm --prefix=/usr/local - make - make test - sudo make install - make clean - ./Configure no-shared no-asm --prefix=/usr/local darwin-ppc-cc - make build_libs "CC=cc -arch ppc" - lipo -info lib* - mkdir -p build/ppc - mv lib* build/ppc - make clean - ./Configure no-shared no-asm --prefix=/usr/local darwin-i386-cc - make build_libs "CC=cc -arch i386" - lipo -info lib* - mkdir -p build/i386 - mv lib* build/i386/ - /bin/ls -1 build/i386/ > libnames.tmp - mkdir universal - - Create a script in the OpenSSL directory called 'make_universal', with these - contents: - - #!/bin/sh - for lib in `cat libnames.tmp`; do - lipo -create build/*/$lib -output universal/$lib - done - exit 0 - - Then: - - sh make_universal - lipo -info universal/lib* - sudo cp universal/lib* /usr/local/lib - lipo -info /usr/local/lib/lib{crypto,ssl}* - cd ../m2crypto-0.17 - - Then edit the m2crypto setup.py and uncomment the extra_link_args line at - the end. - - python setup.py build build_ext --openssl=/usr/local - sudo python setup.py install build_ext --openssl=/usr/local - - diff --git a/INSTALL.rst b/INSTALL.rst new file mode 100644 index 0000000..f0ab79e --- /dev/null +++ b/INSTALL.rst @@ -0,0 +1,166 @@ +Installing M2Crypto +=================== + +.. contents:: + +Pre-requisites +-------------- + +The following is required to *use* M2Crypto (once installed): + +- ``Python 2.6``, ``2.7``, ``3.5``, or newer +- ``OpenSSL 1.0.1e`` or newer + +To *install* M2Crypto, you must be able to compile and link C sources +against Python and OpenSSL headers/libraries. For example on a Debian-based +system the following packages are needed: + +- ``build-essential`` +- ``python3-dev`` and/or ``python-dev`` +- ``libssl-dev`` +- ``swig 2.0.4`` or newer (installation is also possible on some +particular old systems with swig v1.*) + +Installing on Unix-like systems, including Cygwin +------------------------------------------------- + +(not tested and most likely obsolete, updated information for building +with Cygwin are welcome).:: + + $ tar zxf m2crypto-.tar.gz + $ cd m2crypto- + $ python setup.py build + $ python setup.py install + +If you have installed setuptools you can also optionally run tests like +this::: + + $ python setup.py test + +This assumes OpenSSL is installed in ``/usr``. You can provide an +alternate OpenSSL prefix location with --openssl option to +``build\_ext`` (or ``build``) command. So, for example, if you +build your local version of OpenSSL and install it with +``/usr/local`` prefix (your includes are in +``/usr/local/include/openssl`` and libs in ``/usr/local/lib``), +then you would add ``--openssl=/usr/local`` to your ``build`` +command. + + +Differences when installing on Windows +-------------------------------------- + +(Python 2.6 is not supported on Windows anymore, please, just +update to 2.7 if you want to stay on Python 2) + +(needs updating) + +Before building from source, you need to install OpenSSL's include +files, import libraries and DLLs. OpenSSL 1.1.0 and on are installed +by default in ``%ProgramFiles(86)%\OpenSSL`` (32-bit), or +in ``%ProgramW6432%\OpenSSL`` (64-bit), or as a last resort, in +``%ProgramFiles%\OpenSSL``. setup.py will look in those locations. +OpenSSL before 1.1.0 doesn't have a default install location, so +you have to specify its install location explicitely. + +As with other platforms, you can specify a OpenSSL location with +--openssl option to ``build\_ext`` (or ``build``) command. For +example, ``--openssl=c:\pkg\openssl`` would specify that the OpenSSL +include files can be found in ``c:\pkg\openssl\include`` and the +librariesin ``c:\pkg\openssl\lib``. + +The '--openssl' option will configure swig and the compiler to look in the +default locations for headers and libraries. If your OpenSSL is installed in a +or you want to modify the default options run the build_ext step with normal +distutils options: `--swig-opts`, `--include-dirs`, `--library-dirs`, and +`--libraries`. + +MSVC++ ~\ :sub:`:sub:`:sub:`~``` + +setup.py is already configured to work with MSVC++ by default. + +With MSVC++, the OpenSSL pre 1.1.0 DLLs, as built, are named +``libeay32.dll`` and ``ssleay32.dll``. The OpenSSL 1.1.x DLLs are +named ``libcrypto-1_1.dll`` and ``libssl-1_1.dll``. Install these +somewhere on your PATH; for example in ``c:\bin``, together with +``openssl.exe``. + +For MSVC++, the import libraries, as built by OpenSSL pre 1.1.0, are +named ``libeay32.lib`` and ``ssleay32.lib``. The OpenSSL 1.1.x import +libraries are named ``libcrypto.lib`` and ``libssl.lib``. + +MINGW :sub:`:sub:`:sub:`~``` + +.. NOTE:: The following instructions for building M2Crypto with MINGW + are from M2Crypto 0.12. These instructions should continue to work + for this release, although I have not tested them. + +Read Sebastien Sauvage's webpage:: + + http://sebsauvage.net/python/mingw.html + +For mingw32, the OpenSSL pre 1.1.0 import libraries are named +``libeay32.dll.a`` and ``libssl32.dll.a``. You may need to edit +setup.py file for these. + +You'll also need to create ``libpython2[123].a``, depending on your +version of Python. + +OpenSSL pre 1.1.0 DLLs for mingw32 are named ``libeay32.dll`` and +``libssl32.dll``. OpenSSL 1.1.x DLLs are named ``libcrypto-1_1.dll`` +and ``libssl-1_1.dll``. Install these somewhere on your PATH; for +example in ``c:\bin``, together with ``openssl.exe``. + +Build M2Crypto:: + + python setup.py build -cmingw32 + python setup.py install + +BC++ :sub:`:sub:`~``\ ~ + +.. NOTE:: The following instructions for building M2Crypto with MSVC++ + 6.0 and BC++ 5.5 free compiler suite are from M2Crypto 0.10. These + instructions should continue to work for this release, although + I have not tested them. + +.. NOTE:: OpenSSL 1.1.x doesn't support BC++. + +For BC++ these files are created from the MSVC++-built ones using the +tool ``coff2omf.exe``. I call them ``libeay32_bc.lib`` and +``ssleay32_bc.lib``, respectively. You will need to edit setup.py file +for these. + +You'll also need Python's import library, e.g., ``python22.lib``, to be +the BC++-compatible version; i.e., create ``python22_bc.lib`` from +``python22.lib``, save a copy of ``python22.lib`` (as +``python22_vc.lib``, say), then rename ``python22_bc.lib`` to +``python22.lib``. + +Now you are ready to build M2Crypto. Do one of the following:: + + python setup.py build + python setup.py build -cbcpp + +Then,:: + + python setup.py install + +MacOSX +------ + +Apple does not provide on more recent versions of Mac OS X (at least +certainly `since 10.11`_) any version of OpenSSL, so it is necessary to +use ``brew`` or similar packaging systems to install third party +packages. A Mac OS X users suggested, that this series of commands gave +him a working copy of M2Crypto on his system:: + + $ brew install openssl && brew install swig + $ brew --prefix openssl + /usr/local/opt/openssl + $ LDFLAGS="-L$(brew --prefix openssl)/lib" \ + CFLAGS="-I$(brew --prefix openssl)/include" \ + SWIG_FEATURES="-I$(brew --prefix openssl)/include" \ + pip install m2crypto + +.. _`since 10.11`: + https://gitlab.com/m2crypto/m2crypto/merge_requests/7#note_2581821 diff --git a/M2Crypto.egg-info/PKG-INFO b/M2Crypto.egg-info/PKG-INFO deleted file mode 100644 index 3972df5..0000000 --- a/M2Crypto.egg-info/PKG-INFO +++ /dev/null @@ -1,23 +0,0 @@ -Metadata-Version: 1.0 -Name: M2Crypto -Version: 0.21.1 -Summary: M2Crypto: A Python crypto and SSL toolkit -Home-page: http://chandlerproject.org/Projects/MeTooCrypto -Author: Heikki Toivonen -Author-email: heikki@osafoundation.org -License: BSD-style license -Description: M2Crypto is the most complete Python wrapper for OpenSSL featuring RSA, DSA, - DH, EC, HMACs, message digests, symmetric ciphers (including AES); SSL - functionality to implement clients and servers; HTTPS extensions to Python's - httplib, urllib, and xmlrpclib; unforgeable HMAC'ing AuthCookies for web - session management; FTP/TLS client and server; S/MIME; ZServerSSL: A HTTPS - server for Zope and ZSmime: An S/MIME messenger for Zope. M2Crypto can also be - used to provide SSL for Twisted. -Platform: any -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: C -Classifier: Programming Language :: Python -Classifier: Topic :: Security :: Cryptography -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/M2Crypto.egg-info/SOURCES.txt b/M2Crypto.egg-info/SOURCES.txt deleted file mode 100644 index dffdb58..0000000 --- a/M2Crypto.egg-info/SOURCES.txt +++ /dev/null @@ -1,354 +0,0 @@ -CHANGES -INSTALL -LICENCE -README -epydoc.conf -fedora_setup.sh -pack.py -setup.cfg -setup.py -M2Crypto/ASN1.py -M2Crypto/AuthCookie.py -M2Crypto/BIO.py -M2Crypto/BN.py -M2Crypto/DH.py -M2Crypto/DSA.py -M2Crypto/EC.py -M2Crypto/EVP.py -M2Crypto/Engine.py -M2Crypto/Err.py -M2Crypto/RC4.py -M2Crypto/RSA.py -M2Crypto/Rand.py -M2Crypto/SMIME.py -M2Crypto/X509.py -M2Crypto/__init__.py -M2Crypto/callback.py -M2Crypto/ftpslib.py -M2Crypto/httpslib.py -M2Crypto/m2.py -M2Crypto/m2urllib.py -M2Crypto/m2urllib2.py -M2Crypto/m2xmlrpclib.py -M2Crypto/threading.py -M2Crypto/util.py -M2Crypto.egg-info/PKG-INFO -M2Crypto.egg-info/SOURCES.txt -M2Crypto.egg-info/dependency_links.txt -M2Crypto.egg-info/top_level.txt -M2Crypto/PGP/PublicKey.py -M2Crypto/PGP/PublicKeyRing.py -M2Crypto/PGP/RSA.py -M2Crypto/PGP/__init__.py -M2Crypto/PGP/constants.py -M2Crypto/PGP/packet.py -M2Crypto/SSL/Checker.py -M2Crypto/SSL/Cipher.py -M2Crypto/SSL/Connection.py -M2Crypto/SSL/Context.py -M2Crypto/SSL/SSLServer.py -M2Crypto/SSL/Session.py -M2Crypto/SSL/TwistedProtocolWrapper.py -M2Crypto/SSL/__init__.py -M2Crypto/SSL/cb.py -M2Crypto/SSL/ssl_dispatcher.py -M2Crypto/SSL/timeout.py -SWIG/Makefile -SWIG/Makefile.mw -SWIG/Makefile.osx -SWIG/_aes.i -SWIG/_asn1.i -SWIG/_bio.i -SWIG/_bn.i -SWIG/_dh.i -SWIG/_dsa.i -SWIG/_ec.i -SWIG/_engine.i -SWIG/_evp.i -SWIG/_lib.h -SWIG/_lib.i -SWIG/_m2crypto.def -SWIG/_m2crypto.i -SWIG/_objects.i -SWIG/_pkcs7.i -SWIG/_rand.i -SWIG/_rc4.i -SWIG/_rsa.i -SWIG/_ssl.i -SWIG/_threads.i -SWIG/_util.i -SWIG/_x509.i -contrib/README -contrib/SimpleX509create.README -contrib/SimpleX509create.py -contrib/dave.README -contrib/dave.patch -contrib/dispatcher.README -contrib/dispatcher.py -contrib/isaac.README -contrib/isaac.httpslib.py -contrib/m2crypto.spec -contrib/smimeplus.README -contrib/smimeplus.py -demo/bio_mem_rw.py -demo/dhtest.py -demo/dsa1024pvtkey.pem -demo/dsa_bench.py -demo/dsatest.pem -demo/dsatest.py -demo/rsa.priv.pem -demo/rsa.priv0.pem -demo/rsa.pub.pem -demo/rsa1024pvtkey.pem -demo/rsa_bench.py -demo/rsatest.py -demo/CipherSaber/CipherSaber.py -demo/CipherSaber/cstest1.cs1 -demo/Zope/ca.pem -demo/Zope/dh1024.pem -demo/Zope/server.pem -demo/Zope/starts -demo/Zope/starts.bat -demo/Zope/z2s.py -demo/Zope/z2s.py.diff -demo/Zope/ZServer/HTTPS_Server.py -demo/Zope/ZServer/__init__.py -demo/Zope/ZServer/medusa/ftps_server.py -demo/Zope/ZServer/medusa/https_server.py -demo/Zope/lib/python/Products/GuardedFile/GuardedFile.py -demo/Zope/lib/python/Products/GuardedFile/README.txt -demo/Zope/lib/python/Products/GuardedFile/TODO.txt -demo/Zope/lib/python/Products/GuardedFile/__init__.py -demo/Zope/lib/python/Products/GuardedFile/add.dtml -demo/Zope/lib/python/Products/GuardedFile/refresh.txt -demo/Zope/lib/python/Products/GuardedFile/version.txt -demo/Zope/lib/python/Products/ZSmime/README.txt -demo/Zope/lib/python/Products/ZSmime/SmimeTag.py -demo/Zope/lib/python/Products/ZSmime/__init__.py -demo/Zope/lib/python/Products/ZSmime/version.txt -demo/Zope/utilities/x509_user.py -demo/Zope27/INSTALL.txt -demo/Zope27/install_dir/lib/python/ZServer/HTTPS_Server.py -demo/Zope27/install_dir/lib/python/ZServer/__init__.py.patch -demo/Zope27/install_dir/lib/python/ZServer/component.xml.patch -demo/Zope27/install_dir/lib/python/ZServer/datatypes.py.patch -demo/Zope27/install_dir/lib/python/ZServer/medusa/https_server.py -demo/Zope27/instance_home/README.txt.patch -demo/Zope27/instance_home/etc/zope.conf.patch -demo/Zope27/instance_home/ssl/ca.pem -demo/Zope27/instance_home/ssl/dh1024.pem -demo/Zope27/instance_home/ssl/server.pem -demo/ZopeX3/INSTALL.txt -demo/ZopeX3/install_dir/lib/python/zope/app/server/configure.zcml.patch -demo/ZopeX3/install_dir/lib/python/zope/app/server/https.py -demo/ZopeX3/install_dir/lib/python/zope/server/http/https_server.py -demo/ZopeX3/install_dir/lib/python/zope/server/http/https_serverchannel.py -demo/ZopeX3/install_dir/lib/python/zope/server/http/publisherhttps_server.py -demo/ZopeX3/instance_home/etc/zope.conf.patch -demo/ZopeX3/instance_home/ssl/ca.pem -demo/ZopeX3/instance_home/ssl/dh1024.pem -demo/ZopeX3/instance_home/ssl/server.pem -demo/ec/ecdhtest.py -demo/ec/ecdsa_bench.py -demo/ec/ecdsatest.pem -demo/ec/ecdsatest.py -demo/ec/secp160r1pvtkey.pem -demo/https.howto/ca.pem -demo/https.howto/dh1024.pem -demo/https.howto/get_https.py -demo/https.howto/https_cli.py -demo/https.howto/orig_https_srv.py -demo/https.howto/server.pem -demo/medusa/00_README -demo/medusa/START.py -demo/medusa/START_xmlrpc.py -demo/medusa/asynchat.py -demo/medusa/asyncore.py -demo/medusa/auth_handler.py -demo/medusa/ca.pem -demo/medusa/counter.py -demo/medusa/default_handler.py -demo/medusa/dh1024.pem -demo/medusa/filesys.py -demo/medusa/ftp_server.py -demo/medusa/ftps_server.py -demo/medusa/http_date.py -demo/medusa/http_server.py -demo/medusa/https_server.py -demo/medusa/index.html -demo/medusa/logger.py -demo/medusa/m_syslog.py -demo/medusa/medusa_gif.py -demo/medusa/mime_type_table.py -demo/medusa/poison_handler.py -demo/medusa/producers.py -demo/medusa/put_handler.py -demo/medusa/redirecting_handler.py -demo/medusa/server.pem -demo/medusa/status_handler.py -demo/medusa/virtual_handler.py -demo/medusa/xmlrpc_handler.py -demo/medusa054/00_README -demo/medusa054/START.py -demo/medusa054/START_xmlrpc.py -demo/medusa054/ca.pem -demo/medusa054/counter.py -demo/medusa054/default_handler.py -demo/medusa054/dh1024.pem -demo/medusa054/filesys.py -demo/medusa054/ftp_server.py -demo/medusa054/ftps_server.py -demo/medusa054/http_date.py -demo/medusa054/http_server.py -demo/medusa054/https_server.py -demo/medusa054/index.html -demo/medusa054/logger.py -demo/medusa054/m_syslog.py -demo/medusa054/medusa_gif.py -demo/medusa054/poison_handler.py -demo/medusa054/producers.py -demo/medusa054/server.pem -demo/medusa054/status_handler.py -demo/medusa054/xmlrpc_handler.py -demo/perf/memio.py -demo/perf/sha1.py -demo/pgp/pgpstep.py -demo/pgp/pubring.pgp -demo/pgp/secring.pgp -demo/pkcs7/pkcs7-thawte.pem -demo/pkcs7/test.py -demo/smime/README -demo/smime/ca.pem -demo/smime/clear.p7 -demo/smime/client.p12 -demo/smime/client.pem -demo/smime/client2.pem -demo/smime/m2.se.p7 -demo/smime/ns.p7 -demo/smime/ns.se.p7 -demo/smime/opaque.p7 -demo/smime/sendsmime.py -demo/smime/test.py -demo/smime/unsmime.py -demo/smime.howto/README -demo/smime.howto/decrypt.py -demo/smime.howto/dv.py -demo/smime.howto/encrypt.p7 -demo/smime.howto/encrypt.py -demo/smime.howto/recipient.pem -demo/smime.howto/recipient_key.pem -demo/smime.howto/se.p7 -demo/smime.howto/se.py -demo/smime.howto/sendsmime.py -demo/smime.howto/sign.p7 -demo/smime.howto/sign.py -demo/smime.howto/signer.pem -demo/smime.howto/signer_key.pem -demo/smime.howto/verify.py -demo/ssl/README -demo/ssl/c.py -demo/ssl/c_bio.py -demo/ssl/ca.der -demo/ssl/ca.pem -demo/ssl/client.p12 -demo/ssl/client.pem -demo/ssl/dh1024.pem -demo/ssl/echo-eg.py -demo/ssl/echo.py -demo/ssl/echod-async.py -demo/ssl/echod-eg1.py -demo/ssl/echod-forking.py -demo/ssl/echod-iterative.py -demo/ssl/echod-thread.py -demo/ssl/echod-threading.py -demo/ssl/echod_lib.py -demo/ssl/ftp_tls.py -demo/ssl/http_cli_20.py -demo/ssl/https_cli.py -demo/ssl/https_cli_async.py -demo/ssl/https_srv.py -demo/ssl/myapp.py -demo/ssl/s_client.py -demo/ssl/s_server.py -demo/ssl/server.pem -demo/ssl/server3.py -demo/ssl/sess.py -demo/ssl/sess2.py -demo/ssl/sess2.ssldump.out -demo/ssl/socklib.py -demo/ssl/somelib.py -demo/ssl/ss.py -demo/ssl/twistedsslclient.py -demo/ssl/twistedsslserver.py -demo/ssl/xmlrpc_cli.py -demo/ssl/xmlrpc_srv.py -demo/tinderbox/build_lib.py -demo/tinderbox/killableprocess.py -demo/tinderbox/slave.py -demo/tinderbox/winprocess.py -demo/x509/ca.py -demo/x509/certdata2pem.py -demo/x509/client2.pem -demo/x509/demo1.py -demo/x509/proxy_destroy.py -demo/x509/proxy_info.py -demo/x509/proxy_init.py -demo/x509/proxylib.py -demo/x509/server-expired.pem -demo/x509/server.pem -demo/x509/x509auth.py -doc/ZServerSSL-HOWTO.html -doc/howto.ca.html -doc/howto.smime.html -doc/howto.ssl.html -tests/README -tests/__init__.py -tests/alltests.py -tests/ca.pem -tests/der_encoded_seq.b64 -tests/dhparams.pem -tests/dsa.param.pem -tests/dsa.priv.pem -tests/dsa.pub.pem -tests/ec.priv.pem -tests/ec.pub.pem -tests/fips.py -tests/long_serial_cert.pem -tests/pubring.pgp -tests/recipient.pem -tests/recipient_key.pem -tests/rsa.priv.pem -tests/rsa.priv2.pem -tests/rsa.pub.pem -tests/server.pem -tests/signer.pem -tests/signer_key.pem -tests/test_asn1.py -tests/test_authcookie.py -tests/test_bio.py -tests/test_bio_file.py -tests/test_bio_iobuf.py -tests/test_bio_membuf.py -tests/test_bio_ssl.py -tests/test_bn.py -tests/test_dh.py -tests/test_dsa.py -tests/test_ec_curves.py -tests/test_ecdh.py -tests/test_ecdsa.py -tests/test_engine.py -tests/test_evp.py -tests/test_obj.py -tests/test_pgp.py -tests/test_rand.py -tests/test_rc4.py -tests/test_rsa.py -tests/test_smime.py -tests/test_ssl.py -tests/test_ssl_offline.py -tests/test_ssl_win.py -tests/test_threading.py -tests/test_x509.py -tests/thawte.pem -tests/x509.der -tests/x509.pem \ No newline at end of file diff --git a/M2Crypto.egg-info/dependency_links.txt b/M2Crypto.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/M2Crypto.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/M2Crypto.egg-info/top_level.txt b/M2Crypto.egg-info/top_level.txt deleted file mode 100644 index fa4a704..0000000 --- a/M2Crypto.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -M2Crypto diff --git a/M2Crypto/ASN1.py b/M2Crypto/ASN1.py index 09d9e9f..bcdb034 100644 --- a/M2Crypto/ASN1.py +++ b/M2Crypto/ASN1.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """ M2Crypto wrapper for OpenSSL ASN1 API. @@ -7,115 +9,156 @@ Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2005 OSAF. All Rights Reserved. """ -import time, datetime +import datetime +import time -import BIO -import m2 +from M2Crypto import BIO, m2, py27plus, six +if py27plus: + from typing import Any, Callable, Optional, Tuple # noqa MBSTRING_FLAG = 0x1000 -MBSTRING_ASC = MBSTRING_FLAG | 1 -MBSTRING_BMP = MBSTRING_FLAG | 2 +MBSTRING_ASC = MBSTRING_FLAG | 1 +MBSTRING_BMP = MBSTRING_FLAG | 2 -class ASN1_Integer: +class ASN1_Integer(object): m2_asn1_integer_free = m2.asn1_integer_free def __init__(self, asn1int, _pyfree=0): + # type: (ASN1_Integer, int) -> None self.asn1int = asn1int self._pyfree = _pyfree - + def __cmp__(self, other): + # type: (ASN1_Integer) -> int + if not isinstance(other, ASN1_Integer): + raise TypeError( + "Comparisons supported only between ANS1_Integer objects") + return m2.asn1_integer_cmp(self.asn1int, other.asn1int) def __del__(self): + # type: () -> None if self._pyfree: self.m2_asn1_integer_free(self.asn1int) + def __int__(self): + # type: () -> int + return m2.asn1_integer_get(self.asn1int) + + +class ASN1_String(object): -class ASN1_String: - m2_asn1_string_free = m2.asn1_string_free - + def __init__(self, asn1str, _pyfree=0): + # type: (ASN1_String, int) -> None self.asn1str = asn1str self._pyfree = _pyfree - def __str__(self): + def __bytes__(self): + # type: () -> bytes buf = BIO.MemoryBuffer() - m2.asn1_string_print( buf.bio_ptr(), self.asn1str ) + m2.asn1_string_print(buf.bio_ptr(), self.asn1str) return buf.read_all() + def __str__(self): + # type: () -> str + return six.ensure_text(self.__bytes__()) + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_asn1_string_free(self.asn1str) - + def _ptr(self): return self.asn1str - + def as_text(self, flags=0): + # type: (int) -> str + """Output an ASN1_STRING structure according to the set flags. + + :param flags: determine the format of the output by using + predetermined constants, see ASN1_STRING_print_ex(3) + manpage for their meaning. + :return: output an ASN1_STRING structure. + """ buf = BIO.MemoryBuffer() - m2.asn1_string_print_ex( buf.bio_ptr(), self.asn1str, flags) - return buf.read_all() + m2.asn1_string_print_ex(buf.bio_ptr(), self.asn1str, flags) + return six.ensure_text(buf.read_all()) -class ASN1_Object: - +class ASN1_Object(object): + m2_asn1_object_free = m2.asn1_object_free def __init__(self, asn1obj, _pyfree=0): + # type: (ASN1_Object, int) -> None self.asn1obj = asn1obj self._pyfree = _pyfree - + def __del__(self): + # type: () -> None if self._pyfree: self.m2_asn1_object_free(self.asn1obj) def _ptr(self): return self.asn1obj + class _UTC(datetime.tzinfo): def tzname(self, dt): + # type: (Optional[datetime.datetime]) -> str return "UTC" - + def dst(self, dt): + # type: (Optional[datetime.datetime]) -> datetime.timedelta return datetime.timedelta(0) - + def utcoffset(self, dt): + # type: (Optional[datetime.datetime]) -> datetime.timedelta return datetime.timedelta(0) def __repr__(self): return "" % self.tzname(None) -UTC = _UTC() + + +UTC = _UTC() # type: _UTC class LocalTimezone(datetime.tzinfo): - """ Localtimezone from datetime manual """ + """Localtimezone from datetime manual.""" + def __init__(self): - self._stdoffset = datetime.timedelta(seconds = -time.timezone) + # type: () -> None + self._stdoffset = datetime.timedelta(seconds=-time.timezone) if time.daylight: - self._dstoffset = datetime.timedelta(seconds = -time.altzone) + self._dstoffset = datetime.timedelta(seconds=-time.altzone) else: self._dstoffset = self._stdoffset self._dstdiff = self._dstoffset - self._stdoffset - def utcoffset(self, dt): + # type: (datetime.datetime) -> datetime.timedelta if self._isdst(dt): return self._dstoffset else: return self._stdoffset def dst(self, dt): + # type: (datetime.datetime) -> datetime.timedelta if self._isdst(dt): return self._dstdiff else: return datetime.timedelta(0) def tzname(self, dt): - return time.tzname[self._isdst(dt)] + # type: (datetime.datetime) -> str + return time.tzname[self._isdst(dt).real] def _isdst(self, dt): + # type: (datetime.datetime) -> bool tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1) @@ -124,49 +167,59 @@ class LocalTimezone(datetime.tzinfo): return tt.tm_isdst > 0 -class ASN1_UTCTIME: +class ASN1_TIME(object): _ssl_months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] - m2_asn1_utctime_free = m2.asn1_utctime_free - - def __init__(self, asn1_utctime=None, _pyfree=0): - if asn1_utctime is not None: - assert m2.asn1_utctime_type_check(asn1_utctime), "'asn1_utctime' type error'" - self.asn1_utctime = asn1_utctime + m2_asn1_time_free = m2.asn1_time_free + + def __init__(self, asn1_time=None, _pyfree=0, asn1_utctime=None): + # type: (Optional[ASN1_TIME], Optional[int], Optional[ASN1_TIME]) -> None + # handle old keyword parameter + if asn1_time is None: + asn1_time = asn1_utctime + if asn1_time is not None: + assert m2.asn1_time_type_check(asn1_time), \ + "'asn1_time' type error'" + self.asn1_time = asn1_time self._pyfree = _pyfree else: - self.asn1_utctime = m2.asn1_utctime_new () + self.asn1_time = m2.asn1_time_new() self._pyfree = 1 - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): - self.m2_asn1_utctime_free(self.asn1_utctime) - + self.m2_asn1_time_free(self.asn1_time) + def __str__(self): - assert m2.asn1_utctime_type_check(self.asn1_utctime), "'asn1_utctime' type error'" + # type: () -> str + assert m2.asn1_time_type_check(self.asn1_time), \ + "'asn1_time' type error'" buf = BIO.MemoryBuffer() - m2.asn1_utctime_print( buf.bio_ptr(), self.asn1_utctime ) - return buf.read_all() + m2.asn1_time_print(buf.bio_ptr(), self.asn1_time) + return six.ensure_text(buf.read_all()) def _ptr(self): - assert m2.asn1_utctime_type_check(self.asn1_utctime), "'asn1_utctime' type error'" - return self.asn1_utctime - - def set_string (self, string): - """ - Set time from UTC string. - """ - assert m2.asn1_utctime_type_check(self.asn1_utctime), "'asn1_utctime' type error'" - return m2.asn1_utctime_set_string( self.asn1_utctime, string ) - - def set_time (self, time): - """ - Set time from seconds since epoch (long). - """ - assert m2.asn1_utctime_type_check(self.asn1_utctime), "'asn1_utctime' type error'" - return m2.asn1_utctime_set( self.asn1_utctime, time ) + assert m2.asn1_time_type_check(self.asn1_time), \ + "'asn1_time' type error'" + return self.asn1_time + + def set_string(self, string): + # type: (bytes) -> int + """Set time from UTC string.""" + assert m2.asn1_time_type_check(self.asn1_time), \ + "'asn1_time' type error'" + return m2.asn1_time_set_string(self.asn1_time, string) + + def set_time(self, time): + # type: (int) -> ASN1_TIME + """Set time from seconds since epoch (int).""" + assert m2.asn1_time_type_check(self.asn1_time), \ + "'asn1_time' type error'" + return m2.asn1_time_set(self.asn1_time, time) def get_datetime(self): + # type: () -> ASN1_TIME date = str(self) timezone = None @@ -174,19 +227,27 @@ class ASN1_UTCTIME: raise ValueError("Invalid date: %s" % date) month, rest = date.split(' ', 1) if month not in self._ssl_months: - raise ValueError("Invalid date %s: Invalid month: %s" % (date, m)) + raise ValueError("Invalid date %s: Invalid month: %s" % + (date, month)) if rest.endswith(' GMT'): timezone = UTC rest = rest[:-4] - tm = list(time.strptime(rest, "%d %H:%M:%S %Y"))[:6] - tm[1] = self._ssl_months.index(month) + 1 - tm.append(0) - tm.append(timezone) - return datetime.datetime(*tm) + if '.' in rest: + dt = datetime.datetime.strptime(rest, "%d %H:%M:%S.%f %Y") + else: + dt = datetime.datetime.strptime(rest, "%d %H:%M:%S %Y") + dt = dt.replace(month=self._ssl_months.index(month) + 1) + if timezone: + dt = dt.replace(tzinfo=UTC) + return dt def set_datetime(self, date): + # type: (datetime.datetime) -> ASN1_TIME local = LocalTimezone() if date.tzinfo is None: date = date.replace(tzinfo=local) date = date.astimezone(local) return self.set_time(int(time.mktime(date.timetuple()))) + + +ASN1_UTCTIME = ASN1_TIME diff --git a/M2Crypto/AuthCookie.py b/M2Crypto/AuthCookie.py index d401708..c843797 100644 --- a/M2Crypto/AuthCookie.py +++ b/M2Crypto/AuthCookie.py @@ -1,28 +1,41 @@ +from __future__ import absolute_import + """Secure Authenticator Cookies Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" -# M2Crypto -import Rand, m2 +import logging +import re +import time + +from M2Crypto import Rand, m2, py27plus, six, util +from M2Crypto.six.moves.http_cookies import SimpleCookie # pylint: disable=no-name-in-module,import-error -# Python. Cookie is bundled with Python 2.x. -import Cookie, binascii, re, time +if py27plus: + from typing import re as type_re, AnyStr, Dict, Optional, Union # noqa +_MIX_FORMAT = 'exp=%f&data=%s&digest=' +_MIX_RE = re.compile(r'exp=(\d+\.\d+)&data=(.+)&digest=(\S*)') + +log = logging.getLogger(__name__) -_MIX_FORMAT = 'exp=%s&data=%s&digest=' -_MIX_RE = re.compile('exp=(\d+\.\d+)&data=(.+)&digest=(\S*)') def mix(expiry, data, format=_MIX_FORMAT): - return format % (repr(expiry), data) + # type: (float, AnyStr, str) -> AnyStr + return format % (expiry, data) + def unmix(dough, regex=_MIX_RE): + # type: (AnyStr, type_re) -> object mo = regex.match(dough) if mo: return float(mo.group(1)), mo.group(2) else: return None + def unmix3(dough, regex=_MIX_RE): + # type: (AnyStr, type_re) -> Optional[tuple[float, AnyStr, AnyStr]] mo = regex.match(dough) if mo: return float(mo.group(1)), mo.group(2), mo.group(3) @@ -30,23 +43,37 @@ def unmix3(dough, regex=_MIX_RE): return None -_TOKEN = '_M2AUTH_' +_TOKEN = '_M2AUTH_' # type: str + -class AuthCookieJar: +class AuthCookieJar(object): - _keylen = 20 + _keylen = 20 # type: int def __init__(self): + # type: () -> None self._key = Rand.rand_bytes(self._keylen) - + def _hmac(self, key, data): - return binascii.b2a_base64(m2.hmac(key, data, m2.sha1()))[:-1] - + # type: (bytes, str) -> str + return util.bin_to_hex(m2.hmac(key, six.ensure_binary(data), m2.sha1())) + def makeCookie(self, expiry, data): + # type: (float, str) -> AuthCookie + """ + Make a cookie + + :param expiry: expiration time (float in seconds) + :param data: cookie content + :return: AuthCookie object + """ + if not isinstance(expiry, (six.integer_types, float)): + raise ValueError('Expiration time must be number, not "%s' % expiry) dough = mix(expiry, data) return AuthCookie(expiry, data, dough, self._hmac(self._key, dough)) def isGoodCookie(self, cookie): + # type: (AuthCookie) -> Union[bool, int] assert isinstance(cookie, AuthCookie) if cookie.isExpired(): return 0 @@ -56,59 +83,87 @@ class AuthCookieJar: and (c._mac == cookie._mac) \ and (c.output() == cookie.output()) - def isGoodCookieString(self, cookie_str): - c = Cookie.SmartCookie() + def isGoodCookieString(self, cookie_str, _debug=False): + # type: (Union[dict, bytes], bool) -> Union[bool, int] + c = SimpleCookie() c.load(cookie_str) - if not c.has_key(_TOKEN): + if _TOKEN not in c: + log.debug('_TOKEN not in c (keys = %s)', dir(c)) return 0 undough = unmix3(c[_TOKEN].value) if undough is None: + log.debug('undough is None') return 0 exp, data, mac = undough c2 = self.makeCookie(exp, data) + if _debug and (c2._mac == mac): + log.error('cookie_str = %s', cookie_str) + log.error('c2.isExpired = %s', c2.isExpired()) + log.error('mac = %s', mac) + log.error('c2._mac = %s', c2._mac) + log.error('c2._mac == mac: %s', str(c2._mac == mac)) return (not c2.isExpired()) and (c2._mac == mac) -class AuthCookie: - +class AuthCookie(object): + def __init__(self, expiry, data, dough, mac): + # type: (float, str, str, str) -> None + """ + Create new authentication cookie + + :param expiry: expiration time (in seconds) + :param data: cookie payload (as a string) + :param dough: expiry & data concatenated to URL compliant + string + :param mac: SHA1-based HMAC of dough and random key + """ self._expiry = expiry self._data = data self._mac = mac - self._cookie = Cookie.SmartCookie() + self._cookie = SimpleCookie() self._cookie[_TOKEN] = '%s%s' % (dough, mac) - self._name = '%s%s' % (dough, mac) # XXX WebKit only. + self._name = '%s%s' % (dough, mac) # WebKit only. def expiry(self): + # type: () -> float """Return the cookie's expiry time.""" return self._expiry def data(self): + # type: () -> str """Return the data portion of the cookie.""" return self._data def mac(self): + # type: () -> str """Return the cookie's MAC.""" return self._mac - def output(self): + def output(self, header="Set-Cookie:"): + # type: (Optional[str]) -> str """Return the cookie's output in "Set-Cookie" format.""" - return self._cookie.output() + return self._cookie.output(header=header) def value(self): + # type: () -> str """Return the cookie's output minus the "Set-Cookie: " portion. """ return self._cookie[_TOKEN].value def isExpired(self): + # type: () -> bool """Return 1 if the cookie has expired, 0 otherwise.""" - return (time.time() > self._expiry) + return isinstance(self._expiry, (float, six.integer_types)) and \ + (time.time() > self._expiry) - # XXX Following methods are for WebKit only. These should be pushed - # to WKAuthCookie. + # Following two methods are for WebKit only. + # I may wish to push them to WKAuthCookie, but they are part + # of the API now. Oh well. def name(self): + # type: () -> str return self._name def headerValue(self): + # type: () -> str return self.value() - diff --git a/M2Crypto/BIO.py b/M2Crypto/BIO.py index 11dbce4..71a486a 100644 --- a/M2Crypto/BIO.py +++ b/M2Crypto/BIO.py @@ -1,31 +1,38 @@ +from __future__ import absolute_import + """M2Crypto wrapper for OpenSSL BIO API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" -import m2 +import logging + +from M2Crypto import m2, py27plus, six +if py27plus: + from typing import AnyStr, Callable, Iterable, Optional, Union # noqa -# Deprecated -from m2 import bio_do_handshake as bio_do_ssl_handshake +log = logging.getLogger('BIO') -from cStringIO import StringIO -class BIOError(Exception): pass +class BIOError(ValueError): + pass + m2.bio_init(BIOError) -class BIO: +class BIO(object): """Abstract object interface to the BIO API.""" m2_bio_free = m2.bio_free def __init__(self, bio=None, _pyfree=0, _close_cb=None): + # type: (Optional[BIO], int, Optional[Callable]) -> None self.bio = bio self._pyfree = _pyfree self._close_cb = _close_cb self.closed = 0 self.write_closed = 0 - + def __del__(self): if self._pyfree: self.m2_bio_free(self.bio) @@ -37,160 +44,248 @@ class BIO: bio_ptr = _ptr def fileno(self): + # type: () -> int return m2.bio_get_fd(self.bio) def readable(self): + # type: () -> bool return not self.closed def read(self, size=None): + # type: (int) -> Union[bytes, bytearray] if not self.readable(): - raise IOError, 'cannot read' + raise IOError('cannot read') if size is None: - buf = StringIO() + buf = bytearray() while 1: data = m2.bio_read(self.bio, 4096) - if not data: break - buf.write(data) - return buf.getvalue() + if not data: + break + buf += data + return buf elif size == 0: - return '' + return b'' elif size < 0: - raise ValueError, 'read count is negative' + raise ValueError('read count is negative') else: - return m2.bio_read(self.bio, size) + return bytes(m2.bio_read(self.bio, size)) def readline(self, size=4096): + # type: (int) -> bytes if not self.readable(): - raise IOError, 'cannot read' + raise IOError('cannot read') buf = m2.bio_gets(self.bio, size) - return buf + buf = '' if buf is None else buf + return six.ensure_binary(buf) def readlines(self, sizehint='ignored'): + # type: (Union[AnyStr, int]) -> Iterable[bytes] if not self.readable(): - raise IOError, 'cannot read' - lines=[] + raise IOError('cannot read') + lines = [] while 1: - buf=m2.bio_gets(self.bio, 4096) + buf = m2.bio_gets(self.bio, 4096) if buf is None: break - lines.append(buf) + lines.append(six.ensure_binary(buf)) return lines def writeable(self): + # type: () -> bool return (not self.closed) and (not self.write_closed) - + def write(self, data): + # type: (AnyStr) -> int + """Write data to BIO. + + :return: either data written, or [0, -1] for nothing written, + -2 not implemented + """ if not self.writeable(): - raise IOError, 'cannot write' + raise IOError('cannot write') + if isinstance(data, six.text_type): + data = data.encode('utf8') return m2.bio_write(self.bio, data) def write_close(self): + # type: () -> None self.write_closed = 1 def flush(self): + # type: () -> None + """Flush the buffers. + + :return: 1 for success, and 0 or -1 for failure + """ m2.bio_flush(self.bio) def reset(self): - """ - Sets the bio to its initial state + # type: () -> int + """Set the bio to its initial state. + + :return: 1 for success, and 0 or -1 for failure """ return m2.bio_reset(self.bio) def close(self): + # type: () -> None self.closed = 1 if self._close_cb: self._close_cb() def should_retry(self): + # type: () -> int """ Can the call be attempted again, or was there an error - ie do_handshake - + ie do_handshake + """ - return m2.bio_should_retry(self.bio) + return m2.bio_should_retry(self.bio) def should_read(self): - """ - Returns whether the cause of the condition is the bio - should read more data - """ + # type: () -> int + """Should we read more data?""" + return m2.bio_should_read(self.bio) - + def should_write(self): - """ - Returns whether the cause of the condition is the bio - should write more data - """ + # type: () -> int + """Should we write more data?""" return m2.bio_should_write(self.bio) - + + def tell(self): + """Return the current offset.""" + return m2.bio_tell(self.bio) + + def seek(self, off): + """Seek to the specified absolute offset.""" + return m2.bio_seek(self.bio, off) + + def __enter__(self): + return self + + def __exit__(self, *args): + # type: (*Any) -> int + self.close() + + class MemoryBuffer(BIO): + """Object interface to BIO_s_mem. - """ - Object interface to BIO_s_mem. - - Empirical testing suggests that this class performs less well than cStringIO, - because cStringIO is implemented in C, whereas this class is implemented in - Python. Thus, the recommended practice is to use cStringIO for regular work and - convert said cStringIO object to a MemoryBuffer object only when necessary. + Empirical testing suggests that this class performs less well than + cStringIO, because cStringIO is implemented in C, whereas this class + is implemented in Python. Thus, the recommended practice is to use + cStringIO for regular work and convert said cStringIO object to + a MemoryBuffer object only when necessary. """ def __init__(self, data=None): - BIO.__init__(self) + # type: (Optional[bytes]) -> None + super(MemoryBuffer, self).__init__(self) + if data is not None and not isinstance(data, bytes): + raise TypeError( + "data must be bytes or None, not %s" % (type(data).__name__, )) self.bio = m2.bio_new(m2.bio_s_mem()) self._pyfree = 1 if data is not None: m2.bio_write(self.bio, data) def __len__(self): + # type: () -> int return m2.bio_ctrl_pending(self.bio) def read(self, size=0): + # type: (int) -> bytes if not self.readable(): - raise IOError, 'cannot read' + raise IOError('cannot read') if size: return m2.bio_read(self.bio, size) else: return m2.bio_read(self.bio, m2.bio_ctrl_pending(self.bio)) - + # Backwards-compatibility. getvalue = read_all = read def write_close(self): - self.write_closed = 1 + # type: () -> None + super(MemoryBuffer, self).write_close() m2.bio_set_mem_eof_return(self.bio, 0) close = write_close class File(BIO): + """Object interface to BIO_s_pyfd. - """ - Object interface to BIO_s_fp. - - This class interfaces Python to OpenSSL functions that expect BIO *. For + This class interfaces Python to OpenSSL functions that expect BIO. For general file manipulation in Python, use Python's builtin file object. """ - def __init__(self, pyfile, close_pyfile=1): - BIO.__init__(self, _pyfree=1) + def __init__(self, pyfile, close_pyfile=1, mode='rb'): + # type: (Union[io.BytesIO, AnyStr], int, AnyStr) -> None + super(File, self).__init__(self, _pyfree=1) + + if isinstance(pyfile, six.string_types): + pyfile = open(pyfile, mode) + + # This is for downward compatibility, but I don't think, that it is + # good practice to have two handles for the same file. Whats about + # concurrent write access? Last write, last wins? Especially since Py3 + # has its own buffer management. See: + # + # https://docs.python.org/3.3/c-api/file.html + # + pyfile.flush() + self.fname = pyfile.name self.pyfile = pyfile + # Be wary of https://github.com/openssl/openssl/pull/1925 + # BIO_new_fd is NEVER to be used before OpenSSL 1.1.1 + if hasattr(m2, "bio_new_pyfd"): + self.bio = m2.bio_new_pyfd(pyfile.fileno(), m2.bio_noclose) + else: + self.bio = m2.bio_new_pyfile(pyfile, m2.bio_noclose) + self.close_pyfile = close_pyfile - self.bio = m2.bio_new_fp(pyfile, 0) + self.closed = False + + def flush(self): + # type: () -> None + super(File, self).flush() + self.pyfile.flush() def close(self): - self.closed = 1 + # type: () -> None + self.flush() + super(File, self).close() if self.close_pyfile: self.pyfile.close() + def reset(self): + # type: () -> int + """Set the bio to its initial state. + + :return: 0 for success, and -1 for failure + """ + return super(File, self).reset() + + def __del__(self): + if not self.closed: + m2.bio_free(self.bio) + + def openfile(filename, mode='rb'): - return File(open(filename, mode)) + # type: (AnyStr, AnyStr) -> File + try: + f = open(filename, mode) + except IOError as ex: + raise BIOError(ex.args) + + return File(f) class IOBuffer(BIO): + """Object interface to BIO_f_buffer. - """ - Object interface to BIO_f_buffer. - Its principal function is to be BIO_push()'ed on top of a BIO_f_ssl, so that makefile() of said underlying SSL socket works. """ @@ -199,30 +294,30 @@ class IOBuffer(BIO): m2_bio_free = m2.bio_free def __init__(self, under_bio, mode='rwb', _pyfree=1): - BIO.__init__(self, _pyfree=_pyfree) + # type: (BIO, str, int) -> None + super(IOBuffer, self).__init__(self, _pyfree=_pyfree) self.io = m2.bio_new(m2.bio_f_buffer()) self.bio = m2.bio_push(self.io, under_bio._ptr()) # This reference keeps the underlying BIO alive while we're not closed. - self._under_bio = under_bio + self._under_bio = under_bio if 'w' in mode: self.write_closed = 0 else: self.write_closed = 1 - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_bio_pop(self.bio) self.m2_bio_free(self.io) def close(self): + # type: () -> None BIO.close(self) class CipherStream(BIO): - - """ - Object interface to BIO_f_cipher. - """ + """Object interface to BIO_f_cipher.""" SALT_LEN = m2.PKCS5_SALT_LEN @@ -230,57 +325,66 @@ class CipherStream(BIO): m2_bio_free = m2.bio_free def __init__(self, obio): - BIO.__init__(self, _pyfree=1) + # type: (BIO) -> None + super(CipherStream, self).__init__(self, _pyfree=1) self.obio = obio self.bio = m2.bio_new(m2.bio_f_cipher()) self.closed = 0 - + def __del__(self): + # type: () -> None if not getattr(self, 'closed', 1): self.close() def close(self): + # type: () -> None self.m2_bio_pop(self.bio) self.m2_bio_free(self.bio) self.closed = 1 - + def write_close(self): + # type: () -> None self.obio.write_close() def set_cipher(self, algo, key, iv, op): + # type: (str, AnyStr, AnyStr, int) -> None cipher = getattr(m2, algo, None) if cipher is None: - raise ValueError, ('unknown cipher', algo) - m2.bio_set_cipher(self.bio, cipher(), key, iv, op) + raise ValueError('unknown cipher', algo) + else: + if not isinstance(key, bytes): + key = key.encode('utf8') + if not isinstance(iv, bytes): + iv = iv.encode('utf8') + m2.bio_set_cipher(self.bio, cipher(), key, iv, int(op)) m2.bio_push(self.bio, self.obio._ptr()) class SSLBio(BIO): - """ - Object interface to BIO_f_ssl - """ + """Object interface to BIO_f_ssl.""" + def __init__(self, _pyfree=1): - BIO.__init__(self, _pyfree) + # type: (int) -> None + super(SSLBio, self).__init__(self, _pyfree=_pyfree) self.bio = m2.bio_new(m2.bio_f_ssl()) self.closed = 0 - def set_ssl(self, conn, close_flag=m2.bio_noclose): + # type: (Connection, int) -> None """ Sets the bio to the SSL pointer which is - contained in the connection object. + contained in the connection object. """ - self._pyfree = 0 + self._pyfree = 0 m2.bio_set_ssl(self.bio, conn.ssl, close_flag) if close_flag == m2.bio_noclose: conn.set_ssl_close_flag(m2.bio_close) - + def do_handshake(self): - """ - Do the handshake. - + # type: () -> int + """Do the handshake. + Return 1 if the handshake completes Return 0 or a negative number if there is a problem """ return m2.bio_do_handshake(self.bio) - diff --git a/M2Crypto/BN.py b/M2Crypto/BN.py old mode 100755 new mode 100644 index ec741c0..57a13a6 --- a/M2Crypto/BN.py +++ b/M2Crypto/BN.py @@ -1,47 +1,58 @@ +from __future__ import absolute_import + """ M2Crypto wrapper for OpenSSL BN (BIGNUM) API. Copyright (c) 2005 Open Source Applications Foundation. All rights reserved. """ -import m2 +from M2Crypto import m2, util +if util.py27plus: + from typing import Optional # noqa + def rand(bits, top=-1, bottom=0): + # type: (int, int, int) -> Optional[int] """ Generate cryptographically strong random number. - - @param bits: Length of random number in bits. - @param top: If -1, the most significant bit can be 0. If 0, the most + + :param bits: Length of random number in bits. + :param top: If -1, the most significant bit can be 0. If 0, the most significant bit is 1, and if 1, the two most significant bits will be 1. - @param bottom: If bottom is true, the number will be odd. + :param bottom: If bottom is true, the number will be odd. """ return m2.bn_rand(bits, top, bottom) def rand_range(range): + # type: (int) -> int """ Generate a random number in a range. - - @param range: Upper limit for range. - @return: A random number in the range [0, range) + + :param range: Upper limit for range. + :return: A random number in the range [0, range) """ return m2.bn_rand_range(range) def randfname(length): + # type: (int) -> str """ Return a random filename, which is simply a string where all the characters are from the set [a-zA-Z0-9]. - @param length: Length of filename to return. - @type length: int - @return: random filename string + :param length: Length of filename to return. + :return: random filename string """ + import warnings + warnings.warn( + "Don't use BN.randfname(), use tempfile methods instead.", + DeprecationWarning, stacklevel=2) letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890' lettersLen = len(letters) - fname = [] + fname = [] # type: list for x in range(length): fname += [letters[m2.bn_rand_range(lettersLen)]] - + return ''.join(fname) diff --git a/M2Crypto/DH.py b/M2Crypto/DH.py index 4d454ef..b46a305 100644 --- a/M2Crypto/DH.py +++ b/M2Crypto/DH.py @@ -1,37 +1,45 @@ +from __future__ import absolute_import + """M2Crypto wrapper for OpenSSL DH API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" -from util import genparam_callback -import BIO, Err, m2 +from M2Crypto import BIO, m2, util +from M2Crypto.util import genparam_callback +if util.py27plus: + from typing import AnyStr, Callable # noqa + -class DHError(Exception): pass +class DHError(Exception): + pass m2.dh_init(DHError) -class DH: - """ - Object interface to the Diffie-Hellman key exchange - protocol. +class DH(object): + """Object interface to the Diffie-Hellman key exchange protocol. """ m2_dh_free = m2.dh_free def __init__(self, dh, _pyfree=0): + # type: (bytes, int) -> None assert m2.dh_type_check(dh) self.dh = dh self._pyfree = _pyfree - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_dh_free(self.dh) def __len__(self): + # type: () -> int assert m2.dh_type_check(self.dh), "'dh' type error" - return m2.dh_size(self.dh) + return int(m2.dh_size(self.dh)) def __getattr__(self, name): + # type: (str) -> bytes if name in ('p', 'g', 'pub', 'priv'): method = getattr(m2, 'dh_get_%s' % (name,)) assert m2.dh_type_check(self.dh), "'dh' type error" @@ -40,10 +48,11 @@ class DH: raise AttributeError def __setattr__(self, name, value): + # type: (str, bytes) -> bytes if name in ('p', 'g'): - raise DHError, 'set (p, g) via set_params()' - elif name in ('pub','priv'): - raise DHError, 'generate (pub, priv) via gen_key()' + raise DHError('set (p, g) via set_params()') + elif name in ('pub', 'priv'): + raise DHError('generate (pub, priv) via gen_key()') else: self.__dict__[name] = value @@ -51,46 +60,54 @@ class DH: return self.dh def check_params(self): + # type: () -> int assert m2.dh_type_check(self.dh), "'dh' type error" return m2.dh_check(self.dh) - + def gen_key(self): + # type: () -> None assert m2.dh_type_check(self.dh), "'dh' type error" - m2.dh_generate_key(self.dh) + m2.dh_generate_key(self.dh) def compute_key(self, pubkey): + # type: (bytes) -> bytes assert m2.dh_type_check(self.dh), "'dh' type error" return m2.dh_compute_key(self.dh, pubkey) def print_params(self, bio): + # type: (BIO.BIO) -> int assert m2.dh_type_check(self.dh), "'dh' type error" return m2.dhparams_print(bio._ptr(), self.dh) def gen_params(plen, g, callback=genparam_callback): - return DH(m2.dh_generate_parameters(plen, g, callback), 1) + # type: (int, int, Optional[Callable]) -> DH + dh_parms = m2.dh_generate_parameters(plen, g, callback) + dh_obj = DH(dh_parms, 1) + return dh_obj def load_params(file): - bio = BIO.openfile(file) - return load_params_bio(bio) + # type: (AnyStr) -> DH + with BIO.openfile(file) as bio: + return load_params_bio(bio) def load_params_bio(bio): + # type: (BIO.BIO) -> DH return DH(m2.dh_read_parameters(bio._ptr()), 1) def set_params(p, g): + # type: (bytes, bytes) -> DH dh = m2.dh_new() - m2.dh_set_p(dh, p) - m2.dh_set_g(dh, g) + m2.dh_set_pg(dh, p, g) return DH(dh, 1) -#def free_params(cptr): +# def free_params(cptr): # m2.dh_free(cptr) DH_GENERATOR_2 = m2.DH_GENERATOR_2 DH_GENERATOR_5 = m2.DH_GENERATOR_5 - diff --git a/M2Crypto/DSA.py b/M2Crypto/DSA.py index db1f2ff..224848d 100644 --- a/M2Crypto/DSA.py +++ b/M2Crypto/DSA.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import, print_function + """ M2Crypto wrapper for OpenSSL DSA API. @@ -7,71 +9,77 @@ Copyright (C) 2004 OSAF. All Rights Reserved. """ -import sys -import util, BIO, m2 +from M2Crypto import BIO, m2, util +if util.py27plus: + from typing import AnyStr, Callable, Tuple # noqa + -class DSAError(Exception): pass +class DSAError(Exception): + pass m2.dsa_init(DSAError) -class DSA: + +class DSA(object): """ This class is a context supporting DSA key and parameter values, signing and verifying. - + Simple example:: - + from M2Crypto import EVP, DSA, util - + message = 'Kilroy was here!' md = EVP.MessageDigest('sha1') - md.update(message) + md.update(message) digest = md.final() - + dsa = DSA.gen_params(1024) dsa.gen_key() r, s = dsa.sign(digest) good = dsa.verify(digest, r, s) if good: - print ' ** success **' + print(' ** success **') else: - print ' ** verification failed **' + print(' ** verification failed **') """ m2_dsa_free = m2.dsa_free def __init__(self, dsa, _pyfree=0): + # type: (bytes, int) -> None """ Use one of the factory functions to create an instance. + :param dsa: binary representation of OpenSSL DSA type """ assert m2.dsa_type_check(dsa), "'dsa' type error" self.dsa = dsa self._pyfree = _pyfree - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_dsa_free(self.dsa) def __len__(self): + # type: () -> int """ Return the key length. - - @rtype: int - @return: the DSA key length in bits + + :return: the DSA key length in bits """ assert m2.dsa_type_check(self.dsa), "'dsa' type error" return m2.dsa_keylen(self.dsa) def __getattr__(self, name): + # type: (str) -> bytes """ Return specified DSA parameters and key values. - - @type name: str - @param name: name of variable to be returned. Must be + + :param name: name of variable to be returned. Must be one of 'p', 'q', 'g', 'pub', 'priv'. - @rtype: str - @return: value of specified variable (a "byte string") + :return: value of specified variable (a "byte string") """ if name in ['p', 'q', 'g', 'pub', 'priv']: method = getattr(m2, 'dsa_get_%s' % (name,)) @@ -81,87 +89,95 @@ class DSA: raise AttributeError def __setattr__(self, name, value): + # type: (str, bytes) -> None if name in ['p', 'q', 'g']: raise DSAError('set (p, q, g) via set_params()') - elif name in ['pub','priv']: + elif name in ['pub', 'priv']: raise DSAError('generate (pub, priv) via gen_key()') else: self.__dict__[name] = value def set_params(self, p, q, g): + # type: (bytes, bytes, bytes) -> None """ Set new parameters. - + + :param p: MPI binary representation ... format that consists of + the number's length in bytes represented as a 4-byte + big-endian number, and the number itself in big-endian + format, where the most significant bit signals + a negative number (the representation of numbers with + the MSB set is prefixed with null byte). + :param q: ditto + :param g: ditto + @warning: This does not change the private key, so it may be unsafe to use this method. It is better to use gen_params function to create a new DSA object. """ - m2.dsa_set_p(self.dsa, p) - m2.dsa_set_q(self.dsa, q) - m2.dsa_set_g(self.dsa, g) + m2.dsa_set_pqg(self.dsa, p, q, g) def gen_key(self): + # type: () -> None """ Generate a key pair. """ assert m2.dsa_type_check(self.dsa), "'dsa' type error" - m2.dsa_gen_key(self.dsa) + m2.dsa_gen_key(self.dsa) def save_params(self, filename): + # type: (AnyStr) -> int """ Save the DSA parameters to a file. - - @type filename: str - @param filename: Save the DSA parameters to this file. - @return: 1 (true) if successful + + :param filename: Save the DSA parameters to this file. + :return: 1 (true) if successful """ - bio = BIO.openfile(filename, 'wb') - ret = m2.dsa_write_params_bio(self.dsa, bio._ptr()) - bio.close() + with BIO.openfile(filename, 'wb') as bio: + ret = m2.dsa_write_params_bio(self.dsa, bio._ptr()) + return ret def save_params_bio(self, bio): + # type: (BIO.BIO) -> int """ Save DSA parameters to a BIO object. - - @type bio: M2Crypto.BIO object - @param bio: Save DSA parameters to this object. - @return: 1 (true) if successful + + :param bio: Save DSA parameters to this object. + :return: 1 (true) if successful """ return m2.dsa_write_params_bio(self.dsa, bio._ptr()) - def save_key(self, filename, cipher='aes_128_cbc', + def save_key(self, filename, cipher='aes_128_cbc', callback=util.passphrase_callback): + # type: (AnyStr, str, Callable) -> int """ Save the DSA key pair to a file. - - @type filename: str - @param filename: Save the DSA key pair to this file. - @type cipher: str - @param cipher: name of symmetric key algorithm and mode + + :param filename: Save the DSA key pair to this file. + :param cipher: name of symmetric key algorithm and mode to encrypt the private key. - @return: 1 (true) if successful + :return: 1 (true) if successful """ - bio = BIO.openfile(filename, 'wb') - ret = self.save_key_bio(bio, cipher, callback) - bio.close() + with BIO.openfile(filename, 'wb') as bio: + ret = self.save_key_bio(bio, cipher, callback) + return ret - def save_key_bio(self, bio, cipher='aes_128_cbc', + def save_key_bio(self, bio, cipher='aes_128_cbc', callback=util.passphrase_callback): + # type: (BIO.BIO, str, Callable) -> int """ Save DSA key pair to a BIO object. - - @type bio: M2Crypto.BIO object - @param bio: Save DSA parameters to this object. - @type cipher: str - @param cipher: name of symmetric key algorithm and mode + + :param bio: Save DSA parameters to this object. + :param cipher: name of symmetric key algorithm and mode to encrypt the private key. - @return: 1 (true) if successful + :return: 1 (true) if successful """ if cipher is None: - return m2.dsa_write_key_bio_no_cipher(self.dsa, - bio._ptr(), callback) + return m2.dsa_write_key_bio_no_cipher(self.dsa, + bio._ptr(), callback) else: ciph = getattr(m2, cipher, None) if ciph is None: @@ -171,58 +187,54 @@ class DSA: return m2.dsa_write_key_bio(self.dsa, bio._ptr(), ciph, callback) def save_pub_key(self, filename): + # type: (AnyStr) -> int """ Save the DSA public key (with parameters) to a file. - - @type filename: str - @param filename: Save DSA public key (with parameters) + + :param filename: Save DSA public key (with parameters) to this file. - @return: 1 (true) if successful + :return: 1 (true) if successful """ - bio = BIO.openfile(filename, 'wb') - ret = self.save_pub_key_bio(bio) - bio.close() + with BIO.openfile(filename, 'wb') as bio: + ret = self.save_pub_key_bio(bio) + return ret def save_pub_key_bio(self, bio): + # type: (BIO.BIO) -> int """ Save DSA public key (with parameters) to a BIO object. - - @type bio: M2Crypto.BIO object - @param bio: Save DSA public key (with parameters) + + :param bio: Save DSA public key (with parameters) to this object. - @return: 1 (true) if successful + :return: 1 (true) if successful """ return m2.dsa_write_pub_key_bio(self.dsa, bio._ptr()) def sign(self, digest): + # type: (bytes) -> Tuple[bytes, bytes] """ Sign the digest. - - @type digest: str - @param digest: SHA-1 hash of message (same as output + + :param digest: SHA-1 hash of message (same as output from MessageDigest, a "byte string") - @rtype: tuple - @return: DSA signature, a tuple of two values, r and s, + :return: DSA signature, a tuple of two values, r and s, both "byte strings". """ assert self.check_key(), 'key is not initialised' return m2.dsa_sign(self.dsa, digest) - + def verify(self, digest, r, s): + # type: (bytes, bytes, bytes) -> int """ - Verify a newly calculated digest against the signature + Verify a newly calculated digest against the signature values r and s. - - @type digest: str - @param digest: SHA-1 hash of message (same as output + + :param digest: SHA-1 hash of message (same as output from MessageDigest, a "byte string") - @type r: str - @param r: r value of the signature, a "byte string" - @type s: str - @param s: s value of the signature, a "byte string" - @rtype: int - @return: 1 (true) if verify succeeded, 0 if failed + :param r: r value of the signature, a "byte string" + :param s: s value of the signature, a "byte string" + :return: 1 (true) if verify succeeded, 0 if failed """ assert self.check_key(), 'key is not initialised' return m2.dsa_verify(self.dsa, digest, r, s) @@ -230,7 +242,7 @@ class DSA: def sign_asn1(self, digest): assert self.check_key(), 'key is not initialised' return m2.dsa_sign_asn1(self.dsa, digest) - + def verify_asn1(self, digest, blob): assert self.check_key(), 'key is not initialised' return m2.dsa_verify_asn1(self.dsa, digest, blob) @@ -238,202 +250,199 @@ class DSA: def check_key(self): """ Check to be sure the DSA object has a valid private key. - - @rtype: int - @return: 1 (true) if a valid private key + + :return: 1 (true) if a valid private key """ assert m2.dsa_type_check(self.dsa), "'dsa' type error" return m2.dsa_check_key(self.dsa) - class DSA_pub(DSA): """ - This class is a DSA context that only supports a public key - and verification. It does NOT support a private key or + This class is a DSA context that only supports a public key + and verification. It does NOT support a private key or signing. - + """ def sign(self, *argv): + # type: (*Any) -> None raise DSAError('DSA_pub object has no private key') sign_asn1 = sign def check_key(self): + # type: () -> int + """ + :return: does DSA_pub contain a pub key? + """ return m2.dsa_check_pub_key(self.dsa) - + save_key = DSA.save_pub_key save_key_bio = DSA.save_pub_key_bio -#--------------------------------------------------------------- -# factories and other functions +# -------------------------------------------------------------- +# factories and other functions + def gen_params(bits, callback=util.genparam_callback): + # type: (int, Callable) -> DSA """ - Factory function that generates DSA parameters and + Factory function that generates DSA parameters and instantiates a DSA object from the output. - @type bits: int - @param bits: The length of the prime to be generated. If + :param bits: The length of the prime to be generated. If 'bits' < 512, it is set to 512. - @type callback: function - @param callback: A Python callback object that will be - invoked during parameter generation; it usual + :param callback: A Python callback object that will be + invoked during parameter generation; it usual purpose is to provide visual feedback. - @rtype: DSA - @return: instance of DSA. + :return: instance of DSA. """ dsa = m2.dsa_generate_parameters(bits, callback) - if dsa is None: - raise DSAError('problem generating DSA parameters') return DSA(dsa, 1) + def set_params(p, q, g): + # type: (bytes, bytes, bytes) -> DSA """ Factory function that instantiates a DSA object with DSA parameters. - @type p: str - @param p: value of p, a "byte string" - @type q: str - @param q: value of q, a "byte string" - @type g: str - @param g: value of g, a "byte string" - @rtype: DSA - @return: instance of DSA. + :param p: value of p, a "byte string" + :param q: value of q, a "byte string" + :param g: value of g, a "byte string" + :return: instance of DSA. """ dsa = m2.dsa_new() - m2.dsa_set_p(dsa, p) - m2.dsa_set_q(dsa, q) - m2.dsa_set_g(dsa, g) + m2.dsa_set_pqg(dsa, p, q, g) return DSA(dsa, 1) + def load_params(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> DSA """ - Factory function that instantiates a DSA object with DSA + Factory function that instantiates a DSA object with DSA parameters from a file. - @type file: str - @param file: Names the file (a path) that contains the PEM - representation of the DSA parameters. - @type callback: A Python callable - @param callback: A Python callback object that will be - invoked if the DSA parameters file is + :param file: Names the file (a path) that contains the PEM + representation of the DSA parameters. + :param callback: A Python callback object that will be + invoked if the DSA parameters file is passphrase-protected. - @rtype: DSA - @return: instance of DSA. + :return: instance of DSA. """ - bio = BIO.openfile(file) - ret = load_params_bio(bio, callback) - bio.close() + with BIO.openfile(file) as bio: + ret = load_params_bio(bio, callback) + return ret def load_params_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> DSA """ Factory function that instantiates a DSA object with DSA parameters from a M2Crypto.BIO object. - @type bio: M2Crypto.BIO object - @param bio: Contains the PEM representation of the DSA - parameters. - @type callback: A Python callable - @param callback: A Python callback object that will be - invoked if the DSA parameters file is + :param bio: Contains the PEM representation of the DSA + parameters. + :param callback: A Python callback object that will be + invoked if the DSA parameters file is passphrase-protected. - @rtype: DSA - @return: instance of DSA. + :return: instance of DSA. """ dsa = m2.dsa_read_params(bio._ptr(), callback) - if dsa is None: - raise DSAError('problem loading DSA parameters') return DSA(dsa, 1) def load_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> DSA """ Factory function that instantiates a DSA object from a PEM encoded DSA key pair. - @type file: str - @param file: Names the file (a path) that contains the PEM - representation of the DSA key pair. - @type callback: A Python callable - @param callback: A Python callback object that will be - invoked if the DSA key pair is + :param file: Names the file (a path) that contains the PEM + representation of the DSA key pair. + :param callback: A Python callback object that will be + invoked if the DSA key pair is passphrase-protected. - @rtype: DSA - @return: instance of DSA. + :return: instance of DSA. """ - bio = BIO.openfile(file) - ret = load_key_bio(bio, callback) - bio.close() + with BIO.openfile(file) as bio: + ret = load_key_bio(bio, callback) + return ret def load_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> DSA """ Factory function that instantiates a DSA object from a PEM encoded DSA key pair. - @type bio: M2Crypto.BIO object - @param bio: Contains the PEM representation of the DSA - key pair. - @type callback: A Python callable - @param callback: A Python callback object that will be - invoked if the DSA key pair is + :param bio: Contains the PEM representation of the DSA + key pair. + :param callback: A Python callback object that will be + invoked if the DSA key pair is passphrase-protected. - @rtype: DSA - @return: instance of DSA. + :return: instance of DSA. """ dsa = m2.dsa_read_key(bio._ptr(), callback) - if not dsa: - raise DSAError('problem loading DSA key pair') return DSA(dsa, 1) +def pub_key_from_params(p, q, g, pub): + # type: (bytes, bytes, bytes, bytes) -> DSA_pub + """ + Factory function that instantiates a DSA_pub object using + the parameters and public key specified. + + :param p: value of p + :param q: value of q + :param g: value of g + :param pub: value of the public key + :return: instance of DSA_pub. + """ + dsa = m2.dsa_new() + m2.dsa_set_pqg(dsa, p, q, g) + m2.dsa_set_pub(dsa, pub) + return DSA_pub(dsa, 1) + + def load_pub_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> DSA_pub """ Factory function that instantiates a DSA_pub object using - a DSA public key contained in PEM file. The PEM file + a DSA public key contained in PEM file. The PEM file must contain the parameters in addition to the public key. - @type file: str - @param file: Names the file (a path) that contains the PEM - representation of the DSA public key. - @type callback: A Python callable - @param callback: A Python callback object that will be - invoked should the DSA public key be + :param file: Names the file (a path) that contains the PEM + representation of the DSA public key. + :param callback: A Python callback object that will be + invoked should the DSA public key be passphrase-protected. - @rtype: DSA_pub - @return: instance of DSA_pub. + :return: instance of DSA_pub. """ - bio = BIO.openfile(file) - ret = load_pub_key_bio(bio, callback) - bio.close() + with BIO.openfile(file) as bio: + ret = load_pub_key_bio(bio, callback) + return ret def load_pub_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> DSA_pub """ Factory function that instantiates a DSA_pub object using - a DSA public key contained in PEM format. The PEM + a DSA public key contained in PEM format. The PEM must contain the parameters in addition to the public key. - @type bio: M2Crypto.BIO object - @param bio: Contains the PEM representation of the DSA - public key (with params). - @type callback: A Python callable - @param callback: A Python callback object that will be - invoked should the DSA public key be + :param bio: Contains the PEM representation of the DSA + public key (with params). + :param callback: A Python callback object that will be + invoked should the DSA public key be passphrase-protected. - @rtype: DSA_pub - @return: instance of DSA_pub. + :return: instance of DSA_pub. """ dsapub = m2.dsa_read_pub_key(bio._ptr(), callback) - if not dsapub: - raise DSAError('problem loading DSA public key') return DSA_pub(dsapub, 1) diff --git a/M2Crypto/EC.py b/M2Crypto/EC.py index b1ed43e..b730334 100644 --- a/M2Crypto/EC.py +++ b/M2Crypto/EC.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """ M2Crypto wrapper for OpenSSL ECDH/ECDSA API. @@ -5,139 +7,180 @@ M2Crypto wrapper for OpenSSL ECDH/ECDSA API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. -Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. +Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved.""" -import util, BIO, m2 +from M2Crypto import BIO, Err, EVP, m2, util +if util.py27plus: + from typing import AnyStr, Callable, Dict, Optional, Tuple, Union # noqa + +EC_Key = bytes + -class ECError(Exception): pass +class ECError(Exception): + pass m2.ec_init(ECError) # Curve identifier constants -NID_secp112r1 = m2.NID_secp112r1 -NID_secp112r2 = m2.NID_secp112r2 -NID_secp128r1 = m2.NID_secp128r1 -NID_secp128r2 = m2.NID_secp128r2 -NID_secp160k1 = m2.NID_secp160k1 -NID_secp160r1 = m2.NID_secp160r1 -NID_secp160r2 = m2.NID_secp160r2 -NID_secp192k1 = m2.NID_secp192k1 -NID_secp224k1 = m2.NID_secp224k1 -NID_secp224r1 = m2.NID_secp224r1 -NID_secp256k1 = m2.NID_secp256k1 -NID_secp384r1 = m2.NID_secp384r1 -NID_secp521r1 = m2.NID_secp521r1 -NID_sect113r1 = m2.NID_sect113r1 -NID_sect113r2 = m2.NID_sect113r2 -NID_sect131r1 = m2.NID_sect131r1 -NID_sect131r2 = m2.NID_sect131r2 -NID_sect163k1 = m2.NID_sect163k1 -NID_sect163r1 = m2.NID_sect163r1 -NID_sect163r2 = m2.NID_sect163r2 -NID_sect193r1 = m2.NID_sect193r1 -NID_sect193r2 = m2.NID_sect193r2 -NID_sect233k1 = m2.NID_sect233k1 # default for secg.org TLS test server -NID_sect233r1 = m2.NID_sect233r1 -NID_sect239k1 = m2.NID_sect239k1 -NID_sect283k1 = m2.NID_sect283k1 -NID_sect283r1 = m2.NID_sect283r1 -NID_sect409k1 = m2.NID_sect409k1 -NID_sect409r1 = m2.NID_sect409r1 -NID_sect571k1 = m2.NID_sect571k1 -NID_sect571r1 = m2.NID_sect571r1 - -NID_X9_62_prime192v1 = m2.NID_X9_62_prime192v1 -NID_X9_62_prime192v2 = m2.NID_X9_62_prime192v2 -NID_X9_62_prime192v3 = m2.NID_X9_62_prime192v3 -NID_X9_62_prime239v1 = m2.NID_X9_62_prime239v1 -NID_X9_62_prime239v2 = m2.NID_X9_62_prime239v2 -NID_X9_62_prime239v3 = m2.NID_X9_62_prime239v3 -NID_X9_62_prime256v1 = m2.NID_X9_62_prime256v1 -NID_X9_62_c2pnb163v1 = m2.NID_X9_62_c2pnb163v1 -NID_X9_62_c2pnb163v2 = m2.NID_X9_62_c2pnb163v2 -NID_X9_62_c2pnb163v3 = m2.NID_X9_62_c2pnb163v3 -NID_X9_62_c2pnb176v1 = m2.NID_X9_62_c2pnb176v1 -NID_X9_62_c2tnb191v1 = m2.NID_X9_62_c2tnb191v1 -NID_X9_62_c2tnb191v2 = m2.NID_X9_62_c2tnb191v2 -NID_X9_62_c2tnb191v3 = m2.NID_X9_62_c2tnb191v3 -NID_X9_62_c2pnb208w1 = m2.NID_X9_62_c2pnb208w1 -NID_X9_62_c2tnb239v1 = m2.NID_X9_62_c2tnb239v1 -NID_X9_62_c2tnb239v2 = m2.NID_X9_62_c2tnb239v2 -NID_X9_62_c2tnb239v3 = m2.NID_X9_62_c2tnb239v3 -NID_X9_62_c2pnb272w1 = m2.NID_X9_62_c2pnb272w1 -NID_X9_62_c2pnb304w1 = m2.NID_X9_62_c2pnb304w1 -NID_X9_62_c2tnb359v1 = m2.NID_X9_62_c2tnb359v1 -NID_X9_62_c2pnb368w1 = m2.NID_X9_62_c2pnb368w1 -NID_X9_62_c2tnb431r1 = m2.NID_X9_62_c2tnb431r1 - -NID_wap_wsg_idm_ecid_wtls1 = m2.NID_wap_wsg_idm_ecid_wtls1 -NID_wap_wsg_idm_ecid_wtls3 = m2.NID_wap_wsg_idm_ecid_wtls3 -NID_wap_wsg_idm_ecid_wtls4 = m2.NID_wap_wsg_idm_ecid_wtls4 -NID_wap_wsg_idm_ecid_wtls5 = m2.NID_wap_wsg_idm_ecid_wtls5 -NID_wap_wsg_idm_ecid_wtls6 = m2.NID_wap_wsg_idm_ecid_wtls6 -NID_wap_wsg_idm_ecid_wtls7 = m2.NID_wap_wsg_idm_ecid_wtls7 -NID_wap_wsg_idm_ecid_wtls8 = m2.NID_wap_wsg_idm_ecid_wtls8 -NID_wap_wsg_idm_ecid_wtls9 = m2.NID_wap_wsg_idm_ecid_wtls9 -NID_wap_wsg_idm_ecid_wtls10 = m2.NID_wap_wsg_idm_ecid_wtls10 -NID_wap_wsg_idm_ecid_wtls11 = m2.NID_wap_wsg_idm_ecid_wtls11 -NID_wap_wsg_idm_ecid_wtls12 = m2.NID_wap_wsg_idm_ecid_wtls12 - -# The following two curves, according to OpenSSL, have a -# "Questionable extension field!" and are not supported by +NID_secp112r1 = m2.NID_secp112r1 # type: int +NID_secp112r2 = m2.NID_secp112r2 # type: int +NID_secp128r1 = m2.NID_secp128r1 # type: int +NID_secp128r2 = m2.NID_secp128r2 # type: int +NID_secp160k1 = m2.NID_secp160k1 # type: int +NID_secp160r1 = m2.NID_secp160r1 # type: int +NID_secp160r2 = m2.NID_secp160r2 # type: int +NID_secp192k1 = m2.NID_secp192k1 # type: int +NID_secp224k1 = m2.NID_secp224k1 # type: int +NID_secp224r1 = m2.NID_secp224r1 # type: int +NID_secp256k1 = m2.NID_secp256k1 # type: int +NID_secp384r1 = m2.NID_secp384r1 # type: int +NID_secp521r1 = m2.NID_secp521r1 # type: int +NID_sect113r1 = m2.NID_sect113r1 # type: int +NID_sect113r2 = m2.NID_sect113r2 # type: int +NID_sect131r1 = m2.NID_sect131r1 # type: int +NID_sect131r2 = m2.NID_sect131r2 # type: int +NID_sect163k1 = m2.NID_sect163k1 # type: int +NID_sect163r1 = m2.NID_sect163r1 # type: int +NID_sect163r2 = m2.NID_sect163r2 # type: int +NID_sect193r1 = m2.NID_sect193r1 # type: int +NID_sect193r2 = m2.NID_sect193r2 # type: int +# default for secg.org TLS test server +NID_sect233k1 = m2.NID_sect233k1 # type: int +NID_sect233r1 = m2.NID_sect233r1 # type: int +NID_sect239k1 = m2.NID_sect239k1 # type: int +NID_sect283k1 = m2.NID_sect283k1 # type: int +NID_sect283r1 = m2.NID_sect283r1 # type: int +NID_sect409k1 = m2.NID_sect409k1 # type: int +NID_sect409r1 = m2.NID_sect409r1 # type: int +NID_sect571k1 = m2.NID_sect571k1 # type: int +NID_sect571r1 = m2.NID_sect571r1 # type: int + +NID_prime192v1 = m2.NID_X9_62_prime192v1 # type: int +NID_prime192v2 = m2.NID_X9_62_prime192v2 # type: int +NID_prime192v3 = m2.NID_X9_62_prime192v3 # type: int +NID_prime239v1 = m2.NID_X9_62_prime239v1 # type: int +NID_prime239v2 = m2.NID_X9_62_prime239v2 # type: int +NID_prime239v3 = m2.NID_X9_62_prime239v3 # type: int +NID_prime256v1 = m2.NID_X9_62_prime256v1 # type: int +NID_c2pnb163v1 = m2.NID_X9_62_c2pnb163v1 # type: int +NID_c2pnb163v2 = m2.NID_X9_62_c2pnb163v2 # type: int +NID_c2pnb163v3 = m2.NID_X9_62_c2pnb163v3 # type: int +NID_c2pnb176v1 = m2.NID_X9_62_c2pnb176v1 # type: int +NID_c2tnb191v1 = m2.NID_X9_62_c2tnb191v1 # type: int +NID_c2tnb191v2 = m2.NID_X9_62_c2tnb191v2 # type: int +NID_c2tnb191v3 = m2.NID_X9_62_c2tnb191v3 # type: int +NID_c2pnb208w1 = m2.NID_X9_62_c2pnb208w1 # type: int +NID_c2tnb239v1 = m2.NID_X9_62_c2tnb239v1 # type: int +NID_c2tnb239v2 = m2.NID_X9_62_c2tnb239v2 # type: int +NID_c2tnb239v3 = m2.NID_X9_62_c2tnb239v3 # type: int +NID_c2pnb272w1 = m2.NID_X9_62_c2pnb272w1 # type: int +NID_c2pnb304w1 = m2.NID_X9_62_c2pnb304w1 # type: int +NID_c2tnb359v1 = m2.NID_X9_62_c2tnb359v1 # type: int +NID_c2pnb368w1 = m2.NID_X9_62_c2pnb368w1 # type: int +NID_c2tnb431r1 = m2.NID_X9_62_c2tnb431r1 # type: int + +# To preserve compatibility with older names +NID_X9_62_prime192v1 = NID_prime192v1 # type: int +NID_X9_62_prime192v2 = NID_prime192v2 # type: int +NID_X9_62_prime192v3 = NID_prime192v3 # type: int +NID_X9_62_prime239v1 = NID_prime239v1 # type: int +NID_X9_62_prime239v2 = NID_prime239v2 # type: int +NID_X9_62_prime239v3 = NID_prime239v3 # type: int +NID_X9_62_prime256v1 = NID_prime256v1 # type: int +NID_X9_62_c2pnb163v1 = NID_c2pnb163v1 # type: int +NID_X9_62_c2pnb163v2 = NID_c2pnb163v2 # type: int +NID_X9_62_c2pnb163v3 = NID_c2pnb163v3 # type: int +NID_X9_62_c2pnb176v1 = NID_c2pnb176v1 # type: int +NID_X9_62_c2tnb191v1 = NID_c2tnb191v1 # type: int +NID_X9_62_c2tnb191v2 = NID_c2tnb191v2 # type: int +NID_X9_62_c2tnb191v3 = NID_c2tnb191v3 # type: int +NID_X9_62_c2pnb208w1 = NID_c2pnb208w1 # type: int +NID_X9_62_c2tnb239v1 = NID_c2tnb239v1 # type: int +NID_X9_62_c2tnb239v2 = NID_c2tnb239v2 # type: int +NID_X9_62_c2tnb239v3 = NID_c2tnb239v3 # type: int +NID_X9_62_c2pnb272w1 = NID_c2pnb272w1 # type: int +NID_X9_62_c2pnb304w1 = NID_c2pnb304w1 # type: int +NID_X9_62_c2tnb359v1 = NID_c2tnb359v1 # type: int +NID_X9_62_c2pnb368w1 = NID_c2pnb368w1 # type: int +NID_X9_62_c2tnb431r1 = NID_c2tnb431r1 # type: int + +NID_wap_wsg_idm_ecid_wtls1 = m2.NID_wap_wsg_idm_ecid_wtls1 # type: int +NID_wap_wsg_idm_ecid_wtls3 = m2.NID_wap_wsg_idm_ecid_wtls3 # type: int +NID_wap_wsg_idm_ecid_wtls4 = m2.NID_wap_wsg_idm_ecid_wtls4 # type: int +NID_wap_wsg_idm_ecid_wtls5 = m2.NID_wap_wsg_idm_ecid_wtls5 # type: int +NID_wap_wsg_idm_ecid_wtls6 = m2.NID_wap_wsg_idm_ecid_wtls6 # type: int +NID_wap_wsg_idm_ecid_wtls7 = m2.NID_wap_wsg_idm_ecid_wtls7 # type: int +NID_wap_wsg_idm_ecid_wtls8 = m2.NID_wap_wsg_idm_ecid_wtls8 # type: int +NID_wap_wsg_idm_ecid_wtls9 = m2.NID_wap_wsg_idm_ecid_wtls9 # type: int +NID_wap_wsg_idm_ecid_wtls10 = m2.NID_wap_wsg_idm_ecid_wtls10 # type: int +NID_wap_wsg_idm_ecid_wtls11 = m2.NID_wap_wsg_idm_ecid_wtls11 # type: int +NID_wap_wsg_idm_ecid_wtls12 = m2.NID_wap_wsg_idm_ecid_wtls12 # type: int + +# The following two curves, according to OpenSSL, have a +# "Questionable extension field!" and are not supported by # the OpenSSL inverse function. ECError: no inverse. -# As such they cannot be used for signing. They might, -# however, be usable for encryption but that has not +# As such they cannot be used for signing. They might, +# however, be usable for encryption but that has not # been tested. Until thir usefulness can be established, # they are not supported at this time. # NID_ipsec3 = m2.NID_ipsec3 # NID_ipsec4 = m2.NID_ipsec4 -class EC: +class EC(object): """ Object interface to a EC key pair. """ m2_ec_key_free = m2.ec_key_free - + def __init__(self, ec, _pyfree=0): + # type: (EC, int) -> None assert m2.ec_key_type_check(ec), "'ec' type error" self.ec = ec self._pyfree = _pyfree def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_ec_key_free(self.ec) def __len__(self): + # type: () -> int assert m2.ec_key_type_check(self.ec), "'ec' type error" return m2.ec_key_keylen(self.ec) def gen_key(self): + # type: () -> int """ Generates the key pair from its parameters. Use:: + keypair = EC.gen_params(curve) keypair.gen_key() + to create an EC key pair. """ assert m2.ec_key_type_check(self.ec), "'ec' type error" - m2.ec_key_gen_key(self.ec) + m2.ec_key_gen_key(self.ec) def pub(self): + # type: () -> EC_pub # Don't let python free return EC_pub(self.ec, 0) def sign_dsa(self, digest): + # type: (bytes) -> Tuple[bytes, bytes] """ Sign the given digest using ECDSA. Returns a tuple (r,s), the two ECDSA signature parameters. """ assert self._check_key_type(), "'ec' type error" return m2.ecdsa_sign(self.ec, digest) - + def verify_dsa(self, digest, r, s): + # type: (bytes, bytes, bytes) -> int """ Verify the given digest using ECDSA. r and s are the ECDSA signature parameters. @@ -146,39 +189,41 @@ class EC: return m2.ecdsa_verify(self.ec, digest, r, s) def sign_dsa_asn1(self, digest): + # type: (bytes) -> bytes assert self._check_key_type(), "'ec' type error" return m2.ecdsa_sign_asn1(self.ec, digest) - + def verify_dsa_asn1(self, digest, blob): assert self._check_key_type(), "'ec' type error" return m2.ecdsa_verify_asn1(self.ec, digest, blob) - def compute_dh_key(self,pub_key): + def compute_dh_key(self, pub_key): + # type: (EC) -> Optional[bytes] """ - Compute the ECDH shared key of this key pair and the given public - key object. They must both use the same curve. Returns the - shared key in binary as a buffer object. No Key Derivation Function is + Compute the ECDH shared key of this key pair and the given public + key object. They must both use the same curve. Returns the + shared key in binary as a buffer object. No Key Derivation Function is applied. """ assert self.check_key(), 'key is not initialised' return m2.ecdh_compute_key(self.ec, pub_key.ec) - def save_key_bio(self, bio, cipher='aes_128_cbc', callback=util.passphrase_callback): + def save_key_bio(self, bio, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (BIO.BIO, Optional[str], Callable) -> int """ Save the key pair to an M2Crypto.BIO.BIO object in PEM format. - @type bio: M2Crypto.BIO.BIO - @param bio: M2Crypto.BIO.BIO object to save key to. + :param bio: M2Crypto.BIO.BIO object to save key to. - @type cipher: string - @param cipher: Symmetric cipher to protect the key. The default - cipher is 'aes_128_cbc'. If cipher is None, then the key is saved - in the clear. + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. """ if cipher is None: return m2.ec_key_write_bio_no_cipher(self.ec, bio._ptr(), callback) @@ -188,64 +233,78 @@ class EC: raise ValueError('not such cipher %s' % cipher) return m2.ec_key_write_bio(self.ec, bio._ptr(), ciph(), callback) - def save_key(self, file, cipher='aes_128_cbc', callback=util.passphrase_callback): + def save_key(self, file, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (AnyStr, Optional[str], Callable) -> int """ Save the key pair to a file in PEM format. - @type file: string - @param file: Name of file to save key to. + :param file: Name of filename to save key to. - @type cipher: string - @param cipher: Symmetric cipher to protect the key. The default - cipher is 'aes_128_cbc'. If cipher is None, then the key is saved - in the clear. + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. """ - bio = BIO.openfile(file, 'wb') - return self.save_key_bio(bio, cipher, callback) - + with BIO.openfile(file, 'wb') as bio: + return self.save_key_bio(bio, cipher, callback) + def save_pub_key_bio(self, bio): + # type: (BIO.BIO) -> int """ Save the public key to an M2Crypto.BIO.BIO object in PEM format. - @type bio: M2Crypto.BIO.BIO - @param bio: M2Crypto.BIO.BIO object to save key to. - """ + :param bio: M2Crypto.BIO.BIO object to save key to. + """ return m2.ec_key_write_pubkey(self.ec, bio._ptr()) def save_pub_key(self, file): + # type: (AnyStr) -> int """ - Save the public key to a file in PEM format. + Save the public key to a filename in PEM format. - @type file: string - @param file: Name of file to save key to. + :param file: Name of filename to save key to. """ - bio = BIO.openfile(file, 'wb') - return m2.ec_key_write_pubkey(self.ec, bio._ptr()) - + with BIO.openfile(file, 'wb') as bio: + return m2.ec_key_write_pubkey(self.ec, bio._ptr()) + + def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback): + """ + Returns the key(pair) as a string in PEM format. + If no password is passed and the cipher is set + it exits with error + """ + with BIO.MemoryBuffer() as bio: + self.save_key_bio(bio, cipher, callback) + return bio.read() + def _check_key_type(self): + # type: () -> int return m2.ec_key_type_check(self.ec) def check_key(self): + # type: () -> int assert m2.ec_key_type_check(self.ec), "'ec' type error" return m2.ec_key_check_key(self.ec) - + class EC_pub(EC): """ - Object interface to an EC public key. + Object interface to an EC public key. ((don't like this implementation inheritance)) """ - def __init__(self,ec,_pyfree=0): - EC.__init__(self,ec,_pyfree) - self.der = None + def __init__(self, ec, _pyfree=0): + # type: (EC, int) -> None + EC.__init__(self, ec, _pyfree) + self.der = None # type: Optional[bytes] def get_der(self): + # type: () -> bytes """ Returns the public key in DER format as a buffer object. """ @@ -254,82 +313,147 @@ class EC_pub(EC): self.der = m2.ec_key_get_public_der(self.ec) return self.der + def get_key(self): + # type: () -> bytes + """ + Returns the public key as a byte string. + """ + assert self.check_key(), 'key is not initialised' + return m2.ec_key_get_public_key(self.ec) + save_key = EC.save_pub_key save_key_bio = EC.save_pub_key_bio def gen_params(curve): + # type: (int) -> EC """ - Factory function that generates EC parameters and + Factory function that generates EC parameters and instantiates a EC object from the output. - @param curve: This is the OpenSSL nid of the curve to use. + :param curve: This is the OpenSSL nid of the curve to use. """ + assert curve in [x['NID'] for x in m2.ec_get_builtin_curves()], \ + 'Elliptic curve %s is not available on this system.' % \ + m2.obj_nid2sn(curve) return EC(m2.ec_key_new_by_curve_name(curve), 1) def load_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> EC """ Factory function that instantiates a EC object. - @param file: Names the file that contains the PEM representation - of the EC key pair. + :param file: Names the filename that contains the PEM representation + of the EC key pair. - @param callback: Python callback object that will be invoked - if the EC key pair is passphrase-protected. + :param callback: Python callback object that will be invoked + if the EC key pair is passphrase-protected. """ - bio = BIO.openfile(file) - return load_key_bio(bio, callback) + with BIO.openfile(file) as bio: + return load_key_bio(bio, callback) + + +def load_key_string(string, callback=util.passphrase_callback): + # type: (str, Callable) -> EC + """ + Load an EC key pair from a string. + + :param string: String containing EC key pair in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to unlock the + key. The default is util.passphrase_callback. + + :return: M2Crypto.EC.EC object. + """ + with BIO.MemoryBuffer(string) as bio: + return load_key_bio(bio, callback) def load_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> EC """ Factory function that instantiates a EC object. - @param bio: M2Crypto.BIO object that contains the PEM - representation of the EC key pair. + :param bio: M2Crypto.BIO object that contains the PEM + representation of the EC key pair. - @param callback: Python callback object that will be invoked - if the EC key pair is passphrase-protected. + :param callback: Python callback object that will be invoked + if the EC key pair is passphrase-protected. """ return EC(m2.ec_key_read_bio(bio._ptr(), callback), 1) + def load_pub_key(file): + # type: (AnyStr) -> EC_pub + """ + Load an EC public key from filename. + + :param file: Name of filename containing EC public key in PEM + format. + + :return: M2Crypto.EC.EC_pub object. + """ + with BIO.openfile(file) as bio: + return load_pub_key_bio(bio) + + +def load_key_string_pubkey(string, callback=util.passphrase_callback): + # type: (str, Callable) -> PKey """ - Load an EC public key from file. + Load an M2Crypto.EC.PKey from a public key as a string. + + :param string: String containing the key in PEM format. - @type file: string - @param file: Name of file containing EC public key in PEM format. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. - @rtype: M2Crypto.EC.EC_pub - @return: M2Crypto.EC.EC_pub object. + :return: M2Crypto.EC.PKey object. """ - bio = BIO.openfile(file) - return load_pub_key_bio(bio) + with BIO.MemoryBuffer(string) as bio: + return EVP.load_key_bio_pubkey(bio, callback) def load_pub_key_bio(bio): + # type: (BIO.BIO) -> EC_pub """ Load an EC public key from an M2Crypto.BIO.BIO object. - @type bio: M2Crypto.BIO.BIO - @param bio: M2Crypto.BIO.BIO object containing EC public key in PEM - format. + :param bio: M2Crypto.BIO.BIO object containing EC public key in PEM + format. - @rtype: M2Crypto.EC.EC_pub - @return: M2Crypto.EC.EC_pub object. - """ + :return: M2Crypto.EC.EC_pub object. + """ ec = m2.ec_key_read_pubkey(bio._ptr()) if ec is None: ec_error() return EC_pub(ec, 1) + def ec_error(): - raise ECError, m2.err_reason_error_string(m2.err_get_error()) + # type: () -> ECError + raise ECError(Err.get_error_message()) + def pub_key_from_der(der): + # type: (bytes) -> EC_pub """ Create EC_pub from DER. """ return EC_pub(m2.ec_key_from_pubkey_der(der), 1) + + +def pub_key_from_params(curve, bytes): + # type: (bytes, bytes) -> EC_pub + """ + Create EC_pub from curve name and octet string. + """ + return EC_pub(m2.ec_key_from_pubkey_params(curve, bytes), 1) + + +def get_builtin_curves(): + # type: () -> Tuple[Dict[str, Union[int, str]]] + return m2.ec_get_builtin_curves() diff --git a/M2Crypto/EVP.py b/M2Crypto/EVP.py index cb92380..b21dec6 100644 --- a/M2Crypto/EVP.py +++ b/M2Crypto/EVP.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """M2Crypto wrapper for OpenSSL EVP API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. @@ -6,54 +8,62 @@ Portions Copyright (c) 2004-2007 Open Source Applications Foundation. Author: Heikki Toivonen """ -from M2Crypto import Err, util, BIO, RSA -import m2 +import logging +from M2Crypto import BIO, Err, RSA, m2, util +if util.py27plus: + from typing import AnyStr, Optional, Callable # noqa + +log = logging.getLogger('EVP') -class EVPError(Exception): pass +class EVPError(ValueError): + pass m2.evp_init(EVPError) def pbkdf2(password, salt, iter, keylen): + # type: (bytes, bytes, int, int) -> bytes """ Derive a key from password using PBKDF2 algorithm specified in RFC 2898. - - @param password: Derive the key from this password. - @type password: str - @param salt: Salt. - @type salt: str - @param iter: Number of iterations to perform. - @type iter: int - @param keylen: Length of key to produce. - @type keylen: int - @return: Key. - @rtype: str + + :param password: Derive the key from this password. + :param salt: Salt. + :param iter: Number of iterations to perform. + :param keylen: Length of key to produce. + :return: Key. """ return m2.pkcs5_pbkdf2_hmac_sha1(password, salt, iter, keylen) -class MessageDigest: + +class MessageDigest(object): """ Message Digest """ m2_md_ctx_free = m2.md_ctx_free def __init__(self, algo): - md = getattr(m2, algo, None) + # type: (str) -> None + md = getattr(m2, algo, None) # type: Optional[Callable] if md is None: - raise ValueError, ('unknown algorithm', algo) - self.md=md() - self.ctx=m2.md_ctx_new() + # if the digest algorithm isn't found as an attribute of the m2 + # module, try to look up the digest using get_digestbyname() + self.md = m2.get_digestbyname(algo) + else: + self.md = md() + self.ctx = m2.md_ctx_new() m2.digest_init(self.ctx, self.md) - + def __del__(self): + # type: () -> None if getattr(self, 'ctx', None): self.m2_md_ctx_free(self.ctx) def update(self, data): + # type: (bytes) -> int """ Add data to be digested. - - @return: -1 for Python error, 1 for success, 0 for OpenSSL failure. + + :return: -1 for Python error, 1 for success, 0 for OpenSSL failure. """ return m2.digest_update(self.ctx, data) @@ -61,94 +71,112 @@ class MessageDigest: return m2.digest_final(self.ctx) # Deprecated. - digest = final + digest = final -class HMAC: - +class HMAC(object): + m2_hmac_ctx_free = m2.hmac_ctx_free def __init__(self, key, algo='sha1'): + # type: (bytes, str) -> None md = getattr(m2, algo, None) if md is None: - raise ValueError, ('unknown algorithm', algo) - self.md=md() - self.ctx=m2.hmac_ctx_new() + raise ValueError('unknown algorithm', algo) + self.md = md() + self.ctx = m2.hmac_ctx_new() m2.hmac_init(self.ctx, key, self.md) - + def __del__(self): + # type: () -> None if getattr(self, 'ctx', None): self.m2_hmac_ctx_free(self.ctx) def reset(self, key): + # type: (bytes) -> None m2.hmac_init(self.ctx, key, self.md) def update(self, data): + # type: (bytes) -> None m2.hmac_update(self.ctx, data) def final(self): + # type: () -> bytes return m2.hmac_final(self.ctx) - - digest=final + + digest = final + def hmac(key, data, algo='sha1'): + # type: (bytes, bytes, str) -> bytes md = getattr(m2, algo, None) if md is None: - raise ValueError, ('unknown algorithm', algo) + raise ValueError('unknown algorithm', algo) return m2.hmac(key, data, md()) -class Cipher: +class Cipher(object): m2_cipher_ctx_free = m2.cipher_ctx_free - def __init__(self, alg, key, iv, op, key_as_bytes=0, d='md5', salt='12345678', i=1, padding=1): + def __init__(self, alg, key, iv, op, key_as_bytes=0, d='md5', + salt=b'12345678', i=1, padding=1): + # type: (str, bytes, bytes, object, int, str, bytes, int, int) -> None cipher = getattr(m2, alg, None) if cipher is None: - raise ValueError, ('unknown cipher', alg) - self.cipher=cipher() + raise ValueError('unknown cipher', alg) + self.cipher = cipher() if key_as_bytes: kmd = getattr(m2, d, None) if kmd is None: - raise ValueError, ('unknown message digest', d) + raise ValueError('unknown message digest', d) key = m2.bytes_to_key(self.cipher, kmd(), key, salt, iv, i) - self.ctx=m2.cipher_ctx_new() + self.ctx = m2.cipher_ctx_new() m2.cipher_init(self.ctx, self.cipher, key, iv, op) self.set_padding(padding) del key - + def __del__(self): - if getattr(self, 'ctx', None): + # type: () -> None + if getattr(self, 'ctx', None): self.m2_cipher_ctx_free(self.ctx) def update(self, data): + # type: (bytes) -> bytes return m2.cipher_update(self.ctx, data) def final(self): + # type: () -> bytes return m2.cipher_final(self.ctx) def set_padding(self, padding=1): - return m2.cipher_set_padding(self.ctx, padding) + # type: (int) -> int + """ + Actually always return 1 + """ + return m2.cipher_set_padding(self.ctx, padding) -class PKey: +class PKey(object): """ Public Key """ - + m2_pkey_free = m2.pkey_free m2_md_ctx_free = m2.md_ctx_free def __init__(self, pkey=None, _pyfree=0, md='sha1'): + # type: (Optional[bytes], int, str) -> None if pkey is not None: - self.pkey = pkey + self.pkey = pkey # type: bytes self._pyfree = _pyfree else: self.pkey = m2.pkey_new() self._pyfree = 1 self._set_context(md) - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_pkey_free(self.pkey) if getattr(self, 'ctx', None): @@ -158,42 +186,44 @@ class PKey: return self.pkey def _set_context(self, md): - mda = getattr(m2, md, None) + # type: (str) -> None + mda = getattr(m2, md, None) # type: Optional[Callable] if mda is None: - raise ValueError, ('unknown message digest', md) + raise ValueError('unknown message digest', md) self.md = mda() - self.ctx = m2.md_ctx_new() + self.ctx = m2.md_ctx_new() # type: Context def reset_context(self, md='sha1'): + # type: (str) -> None """ Reset internal message digest context. - @type md: string - @param md: The message digest algorithm. + :param md: The message digest algorithm. """ self._set_context(md) def sign_init(self): + # type: () -> None """ Initialise signing operation with self. """ m2.sign_init(self.ctx, self.md) def sign_update(self, data): + # type: (bytes) -> None """ Feed data to signing operation. - @type data: string - @param data: Data to be signed. + :param data: Data to be signed. """ m2.sign_update(self.ctx, data) def sign_final(self): + # type: () -> bytes """ Return signature. - @rtype: string - @return: The signature. + :return: The signature. """ return m2.sign_final(self.ctx, self.pkey) @@ -202,46 +232,45 @@ class PKey: final = sign_final def verify_init(self): + # type: () -> None """ Initialise signature verification operation with self. """ m2.verify_init(self.ctx, self.md) def verify_update(self, data): + # type: (bytes) -> int """ Feed data to verification operation. - @type data: string - @param data: Data to be verified. - @return: -1 on Python error, 1 for success, 0 for OpenSSL error + :param data: Data to be verified. + :return: -1 on Python error, 1 for success, 0 for OpenSSL error """ return m2.verify_update(self.ctx, data) def verify_final(self, sign): + # type: (bytes) -> int """ Return result of verification. - @param sign: Signature to use for verification - @rtype: int - @return: Result of verification: 1 for success, 0 for failure, -1 on + :param sign: Signature to use for verification + :return: Result of verification: 1 for success, 0 for failure, -1 on other error. """ return m2.verify_final(self.ctx, sign, self.pkey) def assign_rsa(self, rsa, capture=1): + # type: (RSA.RSA, int) -> int """ Assign the RSA key pair to self. - @type rsa: M2Crypto.RSA.RSA - @param rsa: M2Crypto.RSA.RSA object to be assigned to self. + :param rsa: M2Crypto.RSA.RSA object to be assigned to self. - @type capture: boolean - @param capture: If true (default), this PKey object will own the RSA + :param capture: If true (default), this PKey object will own the RSA object, meaning that once the PKey object gets deleted it is no longer safe to use the RSA object. - - @rtype: int - @return: Return 1 for success and 0 for failure. + + :return: Return 1 for success and 0 for failure. """ if capture: ret = m2.pkey_assign_rsa(self.pkey, rsa.rsa) @@ -252,157 +281,187 @@ class PKey: return ret def get_rsa(self): + # type: () -> RSA.RSA_pub """ Return the underlying RSA key if that is what the EVP instance is holding. """ rsa_ptr = m2.pkey_get1_rsa(self.pkey) - if rsa_ptr is None: - raise ValueError("PKey instance is not holding a RSA key") - + rsa = RSA.RSA_pub(rsa_ptr, 1) return rsa - def save_key(self, file, cipher='aes_128_cbc', callback=util.passphrase_callback): + def save_key(self, file, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (AnyStr, Optional[str], Callable) -> int """ Save the key pair to a file in PEM format. - @type file: string - @param file: Name of file to save key to. + :param file: Name of file to save key to. - @type cipher: string - @param cipher: Symmetric cipher to protect the key. The default - cipher is 'aes_128_cbc'. If cipher is None, then the key is saved - in the clear. + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. """ - bio = BIO.openfile(file, 'wb') - return self.save_key_bio(bio, cipher, callback) + with BIO.openfile(file, 'wb') as bio: + return self.save_key_bio(bio, cipher, callback) - def save_key_bio(self, bio, cipher='aes_128_cbc', callback=util.passphrase_callback): + def save_key_bio(self, bio, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (BIO.BIO, Optional[str], Callable) -> int """ Save the key pair to the M2Crypto.BIO object 'bio' in PEM format. - @type bio: M2Crypto.BIO - @param bio: M2Crypto.BIO object to save key to. + :param bio: M2Crypto.BIO object to save key to. - @type cipher: string - @param cipher: Symmetric cipher to protect the key. The default - cipher is 'aes_128_cbc'. If cipher is None, then the key is saved - in the clear. + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. """ if cipher is None: return m2.pkey_write_pem_no_cipher(self.pkey, bio._ptr(), callback) else: proto = getattr(m2, cipher, None) if proto is None: - raise ValueError, 'no such cipher %s' % cipher + raise ValueError('no such cipher %s' % cipher) return m2.pkey_write_pem(self.pkey, bio._ptr(), proto(), callback) def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback): + # type: (Optional[str], Callable) -> bytes """ Return key in PEM format in a string. - @type cipher: string - @param cipher: Symmetric cipher to protect the key. The default - cipher is 'aes_128_cbc'. If cipher is None, then the key is saved - in the clear. + :param cipher: Symmetric cipher to protect the key. The default + cipher is ``'aes_128_cbc'``. If cipher is None, + then the key is saved in the clear. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. """ bio = BIO.MemoryBuffer() self.save_key_bio(bio, cipher, callback) return bio.read_all() def as_der(self): + # type: () -> bytes """ Return key in DER format in a string """ buf = m2.pkey_as_der(self.pkey) bio = BIO.MemoryBuffer(buf) return bio.read_all() - + def size(self): + # type: () -> int """ Return the size of the key in bytes. """ return m2.pkey_size(self.pkey) - + def get_modulus(self): + # type: () -> Optional[bytes] """ Return the modulus in hex format. """ return m2.pkey_get_modulus(self.pkey) - + def load_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> PKey """ Load an M2Crypto.EVP.PKey from file. - @type file: string - @param file: Name of file containing the key in PEM format. + :param file: Name of file containing the key in PEM format. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. - @rtype: M2Crypto.EVP.PKey - @return: M2Crypto.EVP.PKey object. + :return: M2Crypto.EVP.PKey object. """ - bio = m2.bio_new_file(file, 'r') - if bio is None: - raise BIO.BIOError(Err.get_error()) - cptr = m2.pkey_read_pem(bio, callback) - m2.bio_free(bio) - if cptr is None: - raise EVPError(Err.get_error()) + with BIO.openfile(file, 'r') as bio: + cptr = m2.pkey_read_pem(bio.bio, callback) + return PKey(cptr, 1) + def load_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> PKey """ Load an M2Crypto.EVP.PKey from an M2Crypto.BIO object. - @type bio: M2Crypto.BIO - @param bio: M2Crypto.BIO object containing the key in PEM format. + :param bio: M2Crypto.BIO object containing the key in PEM format. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. - @rtype: M2Crypto.EVP.PKey - @return: M2Crypto.EVP.PKey object. + :return: M2Crypto.EVP.PKey object. """ cptr = m2.pkey_read_pem(bio._ptr(), callback) + return PKey(cptr, 1) + + +def load_key_bio_pubkey(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> PKey + """ + Load an M2Crypto.EVP.PKey from a public key as a M2Crypto.BIO object. + + :param bio: M2Crypto.BIO object containing the key in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. + + :return: M2Crypto.EVP.PKey object. + """ + cptr = m2.pkey_read_pem_pubkey(bio._ptr(), callback) if cptr is None: raise EVPError(Err.get_error()) return PKey(cptr, 1) + def load_key_string(string, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> PKey """ Load an M2Crypto.EVP.PKey from a string. - @type string: string - @param string: String containing the key in PEM format. + :param string: String containing the key in PEM format. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. - @rtype: M2Crypto.EVP.PKey - @return: M2Crypto.EVP.PKey object. + :return: M2Crypto.EVP.PKey object. """ bio = BIO.MemoryBuffer(string) - return load_key_bio( bio, callback) + return load_key_bio(bio, callback) + +def load_key_string_pubkey(string, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> PKey + """ + Load an M2Crypto.EVP.PKey from a public key as a string. + + :param string: String containing the key in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. + + :return: M2Crypto.EVP.PKey object. + """ + bio = BIO.MemoryBuffer(string) + return load_key_bio_pubkey(bio, callback) diff --git a/M2Crypto/Engine.py b/M2Crypto/Engine.py index d6b879b..fa79e46 100644 --- a/M2Crypto/Engine.py +++ b/M2Crypto/Engine.py @@ -1,4 +1,6 @@ # vim: sts=4 sw=4 et +from __future__ import absolute_import + """ M2Crypto wrapper for OpenSSL ENGINE API. @@ -6,18 +8,24 @@ Pavel Shramov IMEC MSU """ -from M2Crypto import m2, EVP, X509, Err +from M2Crypto import EVP, Err, X509, m2, six, util +if util.py27plus: + from typing import AnyStr, Callable, Optional # noqa + -class EngineError(Exception): pass +class EngineError(Exception): + pass m2.engine_init_error(EngineError) -class Engine: + +class Engine(object): """Wrapper for ENGINE object.""" m2_engine_free = m2.engine_free - - def __init__(self, id = None, _ptr = None, _pyfree = 1): + + def __init__(self, id=None, _ptr=None, _pyfree=1): + # type: (Optional[bytes], Optional[bytes], int) -> None """Create new Engine from ENGINE pointer or obtain by id""" if not _ptr and not id: raise ValueError("No engine id specified") @@ -29,38 +37,52 @@ class Engine: self._pyfree = _pyfree def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_engine_free(self._ptr) def init(self): + # type: () -> int """Obtain a functional reference to the engine. - - @return: 0 on error, non-zero on success.""" + + :return: 0 on error, non-zero on success.""" return m2.engine_init(self._ptr) - + def finish(self): + # type: () -> int """Release a functional and structural reference to the engine.""" return m2.engine_finish(self._ptr) - def ctrl_cmd_string(self, cmd, arg, optional = 0): + def ctrl_cmd_string(self, cmd, arg, optional=0): + # type: (AnyStr, Optional[AnyStr], int) -> None """Call ENGINE_ctrl_cmd_string""" + cmd = six.ensure_str(cmd) + if arg is not None: + arg = six.ensure_str(arg) if not m2.engine_ctrl_cmd_string(self._ptr, cmd, arg, optional): raise EngineError(Err.get_error()) def get_name(self): + # type: () -> bytes """Return engine name""" return m2.engine_get_name(self._ptr) def get_id(self): + # type: () -> bytes """Return engine id""" return m2.engine_get_id(self._ptr) - def set_default(self, methods = m2.ENGINE_METHOD_ALL): - """Use this engine as default for methods specified in argument - Possible values are bitwise OR of m2.ENGINE_METHOD_*""" + def set_default(self, methods=m2.ENGINE_METHOD_ALL): + # type: (int) -> int + """ + Use this engine as default for methods specified in argument + + :param methods: Possible values are bitwise OR of m2.ENGINE_METHOD_* + """ return m2.engine_set_default(self._ptr, methods) - def _engine_load_key(self, func, name, pin = None): + def _engine_load_key(self, func, name, pin=None): + # type: (Callable, bytes, Optional[bytes]) -> EVP.PKey """Helper function for loading keys""" ui = m2.ui_openssl() cbd = m2.engine_pkcs11_data_new(pin) @@ -68,52 +90,61 @@ class Engine: kptr = func(self._ptr, name, ui, cbd) if not kptr: raise EngineError(Err.get_error()) - key = EVP.PKey(kptr, _pyfree = 1) + key = EVP.PKey(kptr, _pyfree=1) finally: m2.engine_pkcs11_data_free(cbd) return key - def load_private_key(self, name, pin = None): + def load_private_key(self, name, pin=None): + # type: (bytes, Optional[bytes]) -> X509.X509 """Load private key with engine methods (e.g from smartcard). If pin is not set it will be asked """ return self._engine_load_key(m2.engine_load_private_key, name, pin) - def load_public_key(self, name, pin = None): + def load_public_key(self, name, pin=None): + # type: (bytes, Optional[bytes]) -> EVP.PKey """Load public key with engine methods (e.g from smartcard).""" return self._engine_load_key(m2.engine_load_public_key, name, pin) def load_certificate(self, name): + # type: (bytes) -> X509.X509 """Load certificate from engine (e.g from smartcard). NOTE: This function may be not implemented by engine!""" cptr = m2.engine_load_certificate(self._ptr, name) if not cptr: raise EngineError("Certificate or card not found") - return X509.X509(cptr, _pyfree = 1) + return X509.X509(cptr, _pyfree=1) def load_dynamic_engine(id, sopath): + # type: (bytes, AnyStr) -> Engine """Load and return dymanic engine from sopath and assign id to it""" + if isinstance(sopath, six.text_type): + sopath = sopath.encode('utf8') m2.engine_load_dynamic() e = Engine('dynamic') - e.ctrl_cmd_string("SO_PATH", sopath) - e.ctrl_cmd_string("ID", id) - e.ctrl_cmd_string("LIST_ADD", "1") - e.ctrl_cmd_string("LOAD", None) + e.ctrl_cmd_string('SO_PATH', sopath) + e.ctrl_cmd_string('ID', id) + e.ctrl_cmd_string('LIST_ADD', '1') + e.ctrl_cmd_string('LOAD', None) return e def load_dynamic(): + # type: () -> None """Load dynamic engine""" m2.engine_load_dynamic() def load_openssl(): + # type: () -> None """Load openssl engine""" m2.engine_load_openssl() def cleanup(): + # type: () -> None """If you load any engines, you need to clean up after your application is finished with the engines.""" m2.engine_cleanup() diff --git a/M2Crypto/Err.py b/M2Crypto/Err.py index 3588f76..70974c9 100644 --- a/M2Crypto/Err.py +++ b/M2Crypto/Err.py @@ -1,49 +1,77 @@ +from __future__ import absolute_import + """M2Crypto wrapper for OpenSSL Error API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" -import BIO -import m2 +from M2Crypto import BIO, m2, py27plus, util, six # noqa +if py27plus: + from typing import Optional # noqa + def get_error(): - err=BIO.MemoryBuffer() + # type: () -> Optional[str] + err = BIO.MemoryBuffer() m2.err_print_errors(err.bio_ptr()) - return err.getvalue() + err_msg = err.read() + if err_msg: + return six.ensure_text(err_msg) + def get_error_code(): + # type: () -> int return m2.err_get_error() + def peek_error_code(): + # type: () -> int return m2.err_peek_error() + def get_error_lib(err): - return m2.err_lib_error_string(err) + # type: (Optional[int]) -> str + err_str = m2.err_lib_error_string(err) + return six.ensure_text(err_str) if err_str else '' + def get_error_func(err): - return m2.err_func_error_string(err) + # type: (Optional[int]) -> str + err_str = m2.err_func_error_string(err) + return six.ensure_text(err_str) if err_str else '' + def get_error_reason(err): - return m2.err_reason_error_string(err) + # type: (Optional[int]) -> str + err_str = m2.err_reason_error_string(err) + return six.ensure_text(err_str) if err_str else '' + + +def get_error_message(): + # type: () -> str + return six.ensure_text(get_error_reason(get_error_code())) + def get_x509_verify_error(err): - return m2.x509_get_verify_error(err) + # type: (Optional[int]) -> str + err_str = m2.x509_get_verify_error(err) + return six.ensure_text(err_str) if err_str else '' + class SSLError(Exception): def __init__(self, err, client_addr): + # type: (int, util.AddrType) -> None self.err = err self.client_addr = client_addr def __str__(self): - if (isinstance(self.client_addr, unicode)): - s = self.client_addr.encode('utf8') + # type: () -> str + if not isinstance(self.client_addr, six.text_type): + s = self.client_addr.decode('utf8') else: s = self.client_addr - return "%s: %s: %s" % \ - (m2.err_func_error_string(self.err), \ - s, \ - m2.err_reason_error_string(self.err)) + return "%s: %s: %s" % (get_error_func(self.err), s, + get_error_reason(self.err)) + class M2CryptoError(Exception): pass - - diff --git a/M2Crypto/PGP/PublicKey.py b/M2Crypto/PGP/PublicKey.py deleted file mode 100644 index f892ade..0000000 --- a/M2Crypto/PGP/PublicKey.py +++ /dev/null @@ -1,58 +0,0 @@ -"""M2Crypto PGP2. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from constants import * -from packet import * -import RSA - -class PublicKey: - def __init__(self, pubkey_pkt): - import warnings - warnings.warn('Deprecated. No maintainer for PGP. If you use this, please inform M2Crypto maintainer.', DeprecationWarning) - - self._pubkey_pkt = pubkey_pkt - self._pubkey = RSA.new_pub_key((pubkey_pkt._e, pubkey_pkt._n)) - self._userid = {} - self._signature = {} - - def keyid(self): - return self._pubkey.n[-8:] - - def add_userid(self, u_pkt): - assert isinstance(u_pkt, userid_packet) - self._userid[u_pkt.userid()] = u_pkt - - def remove_userid(self, userid): - del self._userid[userid] - - def add_signature(self, userid, s_pkt): - assert isinstance(s_pkt, signature_packet) - assert self._userid.has_key(userid) - if self._signature.has_key(userid): - self._signature.append(s_pkt) - else: - self._signature = [s_pkt] - - def __getitem__(self, id): - return self._userid[id] - - def __setitem__(self, *args): - raise NotImplementedError - - def __delitem__(self, id): - del self._userid[id] - if self._signature[id]: - del self._signature[id] - - def write(self, stream): - pass - - def encrypt(self, ptxt): - # XXX Munge ptxt into pgp format. - return self._pubkey.public_encrypt(ptxt, RSA.pkcs1_padding) - - def decrypt(self, ctxt): - # XXX Munge ctxt into pgp format. - return self._pubkey.public_encrypt(ctxt, RSA.pkcs1_padding) - diff --git a/M2Crypto/PGP/PublicKeyRing.py b/M2Crypto/PGP/PublicKeyRing.py deleted file mode 100644 index a8447b3..0000000 --- a/M2Crypto/PGP/PublicKeyRing.py +++ /dev/null @@ -1,81 +0,0 @@ -"""M2Crypto PGP2. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from constants import * -from packet import * -from PublicKey import * - -class PublicKeyRing: - def __init__(self, keyring): - import warnings - warnings.warn('Deprecated. No maintainer for PGP. If you use this, please inform M2Crypto maintainer.', DeprecationWarning) - - self._keyring = keyring - self._userid = {} - self._keyid = {} - self._spurious = [] - self._pubkey = [] - - def load(self): - curr_pub = None - curr_index = -1 - - ps = packet_stream(self._keyring) - while 1: - pkt = ps.read() - - if pkt is None: - break - - elif isinstance(pkt, public_key_packet): - curr_index = curr_index + 1 - curr_pub = PublicKey(pkt) - self._pubkey.append(curr_pub) - #self._keyid[curr_pub.keyid()] = (curr_pub, curr_index) - - elif isinstance(pkt, userid_packet): - if curr_pub is None: - self._spurious.append(pkt) - else: - curr_pub.add_userid(pkt) - self._userid[pkt.userid()] = (curr_pub, curr_index) - - elif isinstance(pkt, signature_packet): - if curr_pub is None: - self._spurious.append(pkt) - else: - curr_pub.add_signature(pkt) - - else: - self._spurious.append(pkt) - - ps.close() - - def __getitem__(self, id): - return self._userid[id][0] - - def __setitem__(self, *args): - raise NotImplementedError - - def __delitem__(self, id): - pkt, idx = self._userid[id] - del self._pubkey[idx] - del self._userid[idx] - pkt, idx = self._keyid[id] - del self._keyid[idx] - - def spurious(self): - return tuple(self._spurious) - - def save(self, keyring): - for p in self._pubkey: - pp = p.pack() - keyring.write(pp) - - -def load_pubring(filename='pubring.pgp'): - pkr = PublicKeyRing(open(filename, 'rb')) - pkr.load() - return pkr - diff --git a/M2Crypto/PGP/RSA.py b/M2Crypto/PGP/RSA.py deleted file mode 100644 index 153193d..0000000 --- a/M2Crypto/PGP/RSA.py +++ /dev/null @@ -1,36 +0,0 @@ -"""M2Crypto PGP2 RSA. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -import sys -from M2Crypto import m2, RSA -_RSA = RSA -del RSA - - -class RSA(_RSA.RSA): - pass - - -class RSA_pub(_RSA.RSA_pub): - pass - - -def new_pub_key((e, n)): - """ - Factory function that instantiates an RSA_pub object from a (e, n) tuple. - - 'e' is the RSA public exponent; it is a string in OpenSSL's binary format, - i.e., a number of bytes in big-endian. - - 'n' is the RSA composite of primes; it is a string in OpenSSL's binary format, - i.e., a number of bytes in big-endian. - """ - import warnings - warnings.warn('Deprecated. No maintainer for PGP. If you use this, please inform M2Crypto maintainer.', DeprecationWarning) - - rsa = m2.rsa_new() - m2.rsa_set_e_bin(rsa, e) - m2.rsa_set_n_bin(rsa, n) - return RSA_pub(rsa, 1) - diff --git a/M2Crypto/PGP/__init__.py b/M2Crypto/PGP/__init__.py deleted file mode 100644 index 27fd669..0000000 --- a/M2Crypto/PGP/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -"""M2Crypto PGP2. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from constants import * - -from packet import public_key_packet, trust_packet, userid_packet,\ - comment_packet, signature_packet, private_key_packet, cke_packet,\ - pke_packet, literal_packet, packet_stream - -from PublicKey import * -from PublicKeyRing import * - - diff --git a/M2Crypto/PGP/constants.py b/M2Crypto/PGP/constants.py deleted file mode 100644 index 9a7810f..0000000 --- a/M2Crypto/PGP/constants.py +++ /dev/null @@ -1,19 +0,0 @@ -"""M2Crypto PGP2. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -CTB_TAG = 128 - -CTB_PKE = 1 -CTB_SIGNATURE = 2 -CTB_MESSAGE_DIGETS = 3 -CTB_PRIVATE_KEY = 5 -CTB_PUBLIC_KEY = 6 -CTB_COMPRESSED_DATA = 8 -CTB_CKE = 9 -CTB_LITERAL_DATA = 11 -CTB_TRUST = 12 -CTB_USERID = 13 -CTB_COMMENT = 14 - - diff --git a/M2Crypto/PGP/packet.py b/M2Crypto/PGP/packet.py deleted file mode 100644 index d662c84..0000000 --- a/M2Crypto/PGP/packet.py +++ /dev/null @@ -1,379 +0,0 @@ -"""M2Crypto PGP2. - -This module implements PGP packets per RFC1991 and various source distributions. - -Each packet type is represented by a class; packet classes derive from -the abstract 'packet' class. - -The 'message digest' packet type, mentioned but not documented in RFC1991, -is not implemented. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -# XXX Work-in-progress. - -# Be liberal in what you accept. -# Be conservative in what you send. -# Be lazy in what you eval. - -import struct, time - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -from M2Crypto import EVP, RSA -from M2Crypto.util import octx_to_num - -from constants import * - -_OK_VERSION = ('\002', '\003') -_OK_VALIDITY = ('\000',) -_OK_PKC = ('\001',) - - -class packet: - def __init__(self, ctb, body=None): - import warnings - warnings.warn('Deprecated. No maintainer for PGP. If you use this, please inform M2Crypto maintainer.', DeprecationWarning) - - self.ctb = ctb - if body is not None: - self.body = StringIO(body) - else: - self.body = None - - def validate(self): - return 1 - - def pack(self): - raise NotImplementedError, '%s.pack(): abstract method' % (self.__class__,) - - def version(self): - if hasattr(self, '_version'): - return ord(self._version) - else: - return None - - def timestamp(self): - if hasattr(self, '_timestamp'): - return struct.unpack('>L', self._timestamp)[0] - else: - return None - - def validity(self): - if hasattr(self, '_validity'): - return struct.unpack('>H', self._validity)[0] - else: - return None - - def pkc(self): - if hasattr(self, '_pkc'): - return self._pkc - else: - return None - - def _llf(self, lenf): - if lenf < 256: - return (0, chr(lenf)) - elif lenf < 65536: - return (1, struct.pack('>H', lenf)) - else: - assert lenf < 2L**32 - return (2, struct.pack('>L', lenf)) - - def _ctb(self, llf): - ctbv = _FACTORY[self.__class__] - return chr((1 << 7) | (ctbv << 2) | llf) - - -class public_key_packet(packet): - def __init__(self, ctb, body=None): - packet.__init__(self, ctb, body) - if self.body is not None: - self._version = self.body.read(1) - self._timestamp = self.body.read(4) - self._validity = self.body.read(2) - self._pkc = self.body.read(1) - - self._nlen = self.body.read(2) - nlen = (struct.unpack('>H', self._nlen)[0] + 7) / 8 - self._n = self.body.read(nlen) - - self._elen = self.body.read(2) - elen = (struct.unpack('>H', self._elen)[0] + 7) / 8 - self._e = self.body.read(elen) - - def pack(self): - if self.body is None: - self.body = StringIO() - self.body.write(self._version) - self.body.write(self._timestamp) - self.body.write(self._validity) - self.body.write(self._pkc) - self.body.write(self._nlen) - self.body.write(self._n) - self.body.write(self._elen) - self.body.write(self._e) - self.body = self.body.getvalue() - llf, lenf = self._llf(len(self.body)) - ctb = self._ctb(llf) - return '%s%s%s' % (ctb, lenf, self.body) - - def pubkey(self): - return self._pubkey.pub() - - -class trust_packet(packet): - # This implementation neither interprets nor emits trust packets. - def __init__(self, ctb, body=None): - packet.__init__(self, ctb, body) - if body is not None: - self.trust = self.body.read(1) - - -class userid_packet(packet): - def __init__(self, ctb, body=None): - packet.__init__(self, ctb, body) - if body is not None: - self._userid = body - - def pack(self): - if self.body is None: - self.body = StringIO() - self.body.write(chr(len(self._userid))) - self.body.write(self._userid) - self.body = self.body.getvalue() - return self.ctb + self.body - - def userid(self): - return self._userid - - -class comment_packet(packet): - def __init__(self, ctb, body=None): - packet.__init__(self, ctb, body) - if body is not None: - self.comment = self.body.getvalue() - - def pack(self): - if self.body is None: - self.body = StringIO() - self.body.write(chr(len(self.comment))) - self.body.write(self.comment) - self.body = self.body.getvalue() - return self.ctb + self.body - - -class signature_packet(packet): - def __init__(self, ctb, body=None): - packet.__init__(self, ctb, body) - if body is not None: - self._version = self.body.read(1) - self._len_md_stuff = self.body.read(1) - self._classification = self.body.read(1) - self._timestamp = self.body.read(4) - self._keyid = self.body.read(8) - self._pkc = self.body.read(1) - self._md_algo = self.body.read(1) - self._md_chksum = self.body.read(2) - self._sig = self.body.read() - - def pack(self): - if self.body is None: - self.body = StringIO() - self.body.write(self._version) - self.body.write(self._len_md_stuff) - self.body.write(self._classification) - self.body.write(self._timestamp) - self.body.write(self._keyid) - self.body.write(self._pkc) - self.body.write(self._md_algo) - self.body.write(self._md_chksum) - self.body.write(self._sig) - self.body = self.body.getvalue() - llf, lenf = self._llf(len(body)) - self.ctb = self.ctb | llf - return '%s%s%s' % (self.ctb, lenf, self.body) - - - def validate(self): - if self._version not in _OK_VERSION: - return None - if self._len_md_stuff != '\005': - return None - - -class private_key_packet(packet): - def __init__(self, ctb, body=None): - packet.__init__(self, ctb, body) - if body is not None: - self._version = self.body.read(1) - self._timestamp = self.body.read(4) - self._validity = self.body.read(2) - self._pkc = self.body.read(1) - - self._nlen = self.body.read(2) - nlen = (struct.unpack('>H', self._nlen)[0] + 7) / 8 - self._n = self.body.read(nlen) - - self._elen = self.body.read(2) - elen = (struct.unpack('>H', self._elen)[0] + 7) / 8 - self._e = self.body.read(elen) - - self._cipher = self.body.read(1) - if self._cipher == '\001': - self._iv = self.body.read(8) - else: - self._iv = None - - for param in ['d', 'p', 'q', 'u']: - _plen = self.body.read(2) - setattr(self, '_'+param+'len', _plen) - plen = (struct.unpack('>H', _plen)[0] + 7) / 8 - setattr(self, '_'+param, self.body.read(plen)) - - self._cksum = self.body.read(2) - - def is_encrypted(self): - return ord(self._cipher) - - -class cke_packet(packet): - def __init__(self, ctb, body=None): - packet.__init__(self, ctb, body) - if body is not None: - self._iv = self.body.read(8) - self._cksum = self.body.read(2) - self._ctxt = self.body.read() - - -class pke_packet(packet): - def __init__(self, ctb, body=None): - packet.__init__(self, ctb, body) - if body is not None: - self._version = self.body.read(1) - self._keyid = self.body.read(8) - self._pkc = ord(self.body.read(1)) - - deklen = (struct.unpack('>H', self.body.read(2))[0] + 7 ) / 8 - self._dek = octx_to_num(self.body.read(deklen)) - - -class literal_packet(packet): - def __init__(self, ctb, body=None): - packet.__init__(self, ctb, body) - if body is not None: - self.fmode = self.body.read(1) - fnlen = self.body.read(1) - self.fname = self.body.read(fnlen) - self.ftime = self.body.read(4) - #self.data = self.body.read() - - -class compressed_packet(packet): - def __init__(self, ctb, stream): - packet.__init__(self, ctb, '') - if body is not None: - self.algo = stream.read(1) - # This reads the entire stream into memory. - self.data = stream.read() - - def validate(self): - return (self.algo == '\001') - - def uncompress(self): - import zlib - decomp = zlib.decompressobj(-13) # RFC 2440, pg 61. - # This doubles the memory usage. - stream = StringIO(decomp.decompress(self.data)) - return stream - - -_FACTORY = { - 1 : pke_packet, - 2 : signature_packet, - #3 : message_digest_packet, # XXX not implemented - 5 : private_key_packet, - 6 : public_key_packet, - #8 : compressed_packet, # special case - 9 : cke_packet, - 11 : literal_packet, - 12 : trust_packet, - 13 : userid_packet, - 14 : comment_packet, - pke_packet : 1, - signature_packet : 2, - #3 : message_digest_packet, - private_key_packet : 5, - public_key_packet : 6, - #8 : compressed_packet, - cke_packet : 9, - literal_packet : 11, - trust_packet : 12, - userid_packet : 13, - comment_packet : 14 -} - - -class packet_stream: - def __init__(self, input): - self.stream = input - self.under_current = None - self._count = 0 - - def close(self): - self.stream.close() - if self.under_current is not None: - self.under_current.close() - - def read(self, keep_trying=0): - while 1: - ctb0 = self.stream.read(1) - if not ctb0: - return None - ctb = ord(ctb0) - if is_ctb(ctb): - break - elif keep_trying: - continue - else: - raise XXXError - ctbt = (ctb & 0x3c) >> 2 - - if ctbt == CTB_COMPRESSED_DATA: - self.under_current = self.stream - cp = compressed_packet(ctb0, self.stream) - self.stream = cp.uncompress() - return self.read() - - # Decode the length of following data. See RFC for details. - llf = ctb & 3 - if llf == 0: - lenf = ord(self.stream.read(1)) - elif llf == 1: - lenf = struct.unpack('>H', self.stream.read(2))[0] - elif llf == 2: - lenf = struct.unpack('>L', self.stream.read(4))[0] - else: # llf == 3 - raise XXXError, 'impossible case' - - body = self.stream.read(lenf) - if not body or (len(body) != lenf): - raise XXXError, 'corrupted packet' - - self._count = self.stream.tell() - try: - return _FACTORY[ctbt](ctb0, body) - except KeyError: - return packet(ctb0, body) - - def count(self): - return self._count - -def is_ctb(ctb): - return ctb & 0xc0 - -def make_ctb(value, llf): - return chr((1 << 7) | (value << 2) | llf) diff --git a/M2Crypto/RC4.py b/M2Crypto/RC4.py index 1b5d408..26e1079 100644 --- a/M2Crypto/RC4.py +++ b/M2Crypto/RC4.py @@ -1,31 +1,36 @@ +from __future__ import absolute_import + """M2Crypto wrapper for OpenSSL RC4 API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" -from m2 import rc4_new, rc4_free, rc4_set_key, rc4_update +from M2Crypto.m2 import rc4_free, rc4_new, rc4_set_key, rc4_update -class RC4: +class RC4(object): """Object interface to the stream cipher RC4.""" rc4_free = rc4_free def __init__(self, key=None): + # type: (bytes) -> None self.cipher = rc4_new() if key: rc4_set_key(self.cipher, key) - + def __del__(self): - if getattr(self, 'cipher', None): + # type: () -> None + if getattr(self, 'cipher', None): self.rc4_free(self.cipher) def set_key(self, key): - rc4_set_key(self.cipher, key) + # type: (bytes) -> None + rc4_set_key(self.cipher, key) def update(self, data): + # type: (bytes) -> bytes return rc4_update(self.cipher, data) def final(self): + # type: () -> str return '' - - diff --git a/M2Crypto/RSA.py b/M2Crypto/RSA.py index 2dff160..1292e1d 100644 --- a/M2Crypto/RSA.py +++ b/M2Crypto/RSA.py @@ -1,11 +1,18 @@ +from __future__ import absolute_import + """M2Crypto wrapper for OpenSSL RSA API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import sys -import util, BIO, Err, m2 -class RSAError(Exception): pass +from M2Crypto import BIO, Err, m2, util +if util.py27plus: + from typing import Any, AnyStr, Callable, Dict, List, IO, Optional, Tuple # noqa + + +class RSAError(Exception): + pass m2.rsa_init(RSAError) @@ -15,7 +22,7 @@ sslv23_padding = m2.sslv23_padding pkcs1_oaep_padding = m2.pkcs1_oaep_padding -class RSA: +class RSA(object): """ RSA Key Pair. """ @@ -23,18 +30,25 @@ class RSA: m2_rsa_free = m2.rsa_free def __init__(self, rsa, _pyfree=0): + # type: (bytes, int) -> None + """ + :param rsa: binary representation of OpenSSL RSA type + """ assert m2.rsa_type_check(rsa), "'rsa' type error" self.rsa = rsa self._pyfree = _pyfree - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_rsa_free(self.rsa) def __len__(self): - return m2.rsa_size(self.rsa) << 3 + # type: () -> int + return int(m2.rsa_size(self.rsa) << 3) def __getattr__(self, name): + # type: (str) -> bytes if name == 'e': return m2.rsa_get_e(self.rsa) elif name == 'n': @@ -43,75 +57,81 @@ class RSA: raise AttributeError def pub(self): + # type: () -> Tuple[bytes, bytes] assert self.check_key(), 'key is not initialised' return m2.rsa_get_e(self.rsa), m2.rsa_get_n(self.rsa) def public_encrypt(self, data, padding): + # type: (bytes, int) -> bytes assert self.check_key(), 'key is not initialised' return m2.rsa_public_encrypt(self.rsa, data, padding) def public_decrypt(self, data, padding): + # type: (bytes, int) -> bytes assert self.check_key(), 'key is not initialised' return m2.rsa_public_decrypt(self.rsa, data, padding) def private_encrypt(self, data, padding): + # type: (bytes, int) -> bytes assert self.check_key(), 'key is not initialised' return m2.rsa_private_encrypt(self.rsa, data, padding) def private_decrypt(self, data, padding): + # type: (bytes, int) -> bytes assert self.check_key(), 'key is not initialised' return m2.rsa_private_decrypt(self.rsa, data, padding) - def save_key_bio(self, bio, cipher='aes_128_cbc', callback=util.passphrase_callback): + def save_key_bio(self, bio, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (BIO.BIO, Optional[str], Callable) -> int """ Save the key pair to an M2Crypto.BIO.BIO object in PEM format. - @type bio: M2Crypto.BIO.BIO - @param bio: M2Crypto.BIO.BIO object to save key to. + :param bio: M2Crypto.BIO.BIO object to save key to. - @type cipher: string - @param cipher: Symmetric cipher to protect the key. The default - cipher is 'aes_128_cbc'. If cipher is None, then the key is saved - in the clear. + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. """ if cipher is None: return m2.rsa_write_key_no_cipher(self.rsa, bio._ptr(), callback) else: ciph = getattr(m2, cipher, None) if ciph is None: - raise RSAError, 'not such cipher %s' % cipher + raise RSAError('not such cipher %s' % cipher) else: ciph = ciph() return m2.rsa_write_key(self.rsa, bio._ptr(), ciph, callback) - def save_key(self, file, cipher='aes_128_cbc', callback=util.passphrase_callback): + def save_key(self, file, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (AnyStr, Optional[str], Callable) -> int """ Save the key pair to a file in PEM format. - @type file: string - @param file: Name of file to save key to. + :param file: Name of file to save key to. - @type cipher: string - @param cipher: Symmetric cipher to protect the key. The default - cipher is 'aes_128_cbc'. If cipher is None, then the key is saved - in the clear. + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to protect the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. """ - bio = BIO.openfile(file, 'wb') - return self.save_key_bio(bio, cipher, callback) + with BIO.openfile(file, 'wb') as bio: + return self.save_key_bio(bio, cipher, callback) save_pem = save_key def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback): + # type: (Optional[str], Callable) -> bytes """ Returns the key(pair) as a string in PEM format. """ @@ -120,143 +140,148 @@ class RSA: return bio.read() def save_key_der_bio(self, bio): + # type: (BIO.BIO) -> int """ Save the key pair to an M2Crypto.BIO.BIO object in DER format. - @type bio: M2Crypto.BIO.BIO - @param bio: M2Crypto.BIO.BIO object to save key to. + :param bio: M2Crypto.BIO.BIO object to save key to. """ return m2.rsa_write_key_der(self.rsa, bio._ptr()) def save_key_der(self, file): + # type: (AnyStr) -> int """ Save the key pair to a file in DER format. - @type file: str - @param file: Filename to save key to + :param file: Filename to save key to """ - bio = BIO.openfile(file, 'wb') - return self.save_key_der_bio(bio) + with BIO.openfile(file, 'wb') as bio: + return self.save_key_der_bio(bio) def save_pub_key_bio(self, bio): + # type: (BIO.BIO) -> int """ Save the public key to an M2Crypto.BIO.BIO object in PEM format. - @type bio: M2Crypto.BIO.BIO - @param bio: M2Crypto.BIO.BIO object to save key to. - """ + :param bio: M2Crypto.BIO.BIO object to save key to. + """ return m2.rsa_write_pub_key(self.rsa, bio._ptr()) def save_pub_key(self, file): + # type: (AnyStr) -> int """ Save the public key to a file in PEM format. - @type file: string - @param file: Name of file to save key to. + :param file: Name of file to save key to. """ - bio = BIO.openfile(file, 'wb') - return m2.rsa_write_pub_key(self.rsa, bio._ptr()) + with BIO.openfile(file, 'wb') as bio: + return m2.rsa_write_pub_key(self.rsa, bio._ptr()) def check_key(self): + # type: () -> int + """ + Validate RSA keys. + + It checks that p and q are in fact prime, and that n = p*q. + + :return: returns 1 if rsa is a valid RSA key, and 0 otherwise. + -1 is returned if an error occurs while checking the key. + If the key is invalid or an error occurred, the reason + code can be obtained using ERR_get_error(3). + """ return m2.rsa_check_key(self.rsa) def sign_rsassa_pss(self, digest, algo='sha1', salt_length=20): + # type: (bytes, str, int) -> bytes """ Signs a digest with the private key using RSASSA-PSS - - @requires: OpenSSL 0.9.7h or later. - @type digest: str - @param digest: A digest created by using the digest method + :param digest: A digest created by using the digest method - @type salt_length: int - @param salt_length: The length of the salt to use - - @type algo: str - @param algo: The hash algorithm to use + :param salt_length: The length of the salt to use - @return: a string which is the signature + :param algo: The hash algorithm to use + Legal values like 'sha1','sha224', 'sha256', + 'ripemd160', and 'md5'. + + :return: a string which is the signature """ hash = getattr(m2, algo, None) + if hash is None: - raise ValueError('not such hash algorithm %s' % hash_algo) + raise RSAError('not such hash algorithm %s' % algo) signature = m2.rsa_padding_add_pkcs1_pss(self.rsa, digest, hash(), salt_length) - - return self.private_encrypt(signature, m2.no_padding) + + return self.private_encrypt(signature, m2.no_padding) def verify_rsassa_pss(self, data, signature, algo='sha1', salt_length=20): + # type: (bytes, bytes, str, int) -> int """ Verifies the signature RSASSA-PSS - @requires: OpenSSL 0.9.7h or later. + :param data: Data that has been signed - @type data: str - @param data: Data that has been signed + :param signature: The signature signed with RSASSA-PSS - @type signature: str - @param signature: The signature signed with RSASSA-PSS - - @type salt_length: int - @param salt_length: The length of the salt that was used + :param salt_length: The length of the salt that was used - @type algo: str - @param algo: The hash algorithm to use + :param algo: The hash algorithm to use + Legal values are for example 'sha1','sha224', + 'sha256', 'ripemd160', and 'md5'. - @return: 1 or 0, depending on whether the signature was - verified or not. + :return: 1 or 0, depending on whether the signature was + verified or not. """ hash = getattr(m2, algo, None) + if hash is None: - raise ValueError('not such hash algorithm %s' % hash_algo) + raise RSAError('not such hash algorithm %s' % algo) plain_signature = self.public_decrypt(signature, m2.no_padding) - + return m2.rsa_verify_pkcs1_pss(self.rsa, data, plain_signature, hash(), salt_length) def sign(self, digest, algo='sha1'): + # type: (bytes, str) -> bytes """ Signs a digest with the private key - @type digest: str - @param digest: A digest created by using the digest method + :param digest: A digest created by using the digest method - @type algo: str - @param algo: The method that created the digest. - Legal values are 'sha1','sha224', 'sha256', 'ripemd160', - and 'md5'. - - @return: a string which is the signature + :param algo: The method that created the digest. + Legal values like 'sha1','sha224', 'sha256', + 'ripemd160', and 'md5'. + + :return: a string which is the signature """ - digest_type = getattr(m2, 'NID_' + algo, None) + digest_type = getattr(m2, 'NID_' + algo, None) if digest_type is None: - raise ValueError, ('unknown algorithm', algo) - - return m2.rsa_sign(self.rsa, digest, digest_type) - + raise ValueError('unknown algorithm', algo) + + return m2.rsa_sign(self.rsa, digest, digest_type) + def verify(self, data, signature, algo='sha1'): + # type: (bytes, bytes, str) -> int """ Verifies the signature with the public key - @type data: str - @param data: Data that has been signed + :param data: Data that has been signed - @type signature: str - @param signature: The signature signed with the private key + :param signature: The signature signed with the private key - @type algo: str - @param algo: The method use to create digest from the data - before it was signed. Legal values are 'sha1','sha224', - 'sha256', 'ripemd160', and 'md5'. + :param algo: The method use to create digest from the data + before it was signed. Legal values like + 'sha1','sha224', 'sha256', 'ripemd160', and 'md5'. - @return: True or False, depending on whether the signature was - verified. + :return: 1 or 0, depending on whether the signature was + verified or not. """ digest_type = getattr(m2, 'NID_' + algo, None) if digest_type is None: - raise ValueError, ('unknown algorithm', algo) - - return m2.rsa_verify(self.rsa, data, signature, digest_type) + raise ValueError('unknown algorithm', algo) + + return m2.rsa_verify(self.rsa, data, signature, digest_type) class RSA_pub(RSA): @@ -266,106 +291,107 @@ class RSA_pub(RSA): """ def __setattr__(self, name, value): + # type: (str, bytes) -> None if name in ['e', 'n']: - raise RSAError, \ - 'use factory function new_pub_key() to set (e, n)' + raise RSAError('use factory function new_pub_key() to set (e, n)') else: self.__dict__[name] = value - + def private_encrypt(self, *argv): - raise RSAError, 'RSA_pub object has no private key' + # type: (*Any) -> None + raise RSAError('RSA_pub object has no private key') def private_decrypt(self, *argv): - raise RSAError, 'RSA_pub object has no private key' + # type: (*Any) -> None + raise RSAError('RSA_pub object has no private key') def save_key(self, file, *args, **kw): + # type: (AnyStr, *Any, **Any) -> int """ Save public key to file. """ return self.save_pub_key(file) def save_key_bio(self, bio, *args, **kw): + # type: (BIO.BIO, *Any, **Any) -> int """ Save public key to BIO. """ return self.save_pub_key_bio(bio) - #save_key_der + # save_key_der - #save_key_der_bio + # save_key_der_bio def check_key(self): + # type: () -> int return m2.rsa_check_pub_key(self.rsa) def rsa_error(): - raise RSAError, m2.err_reason_error_string(m2.err_get_error()) + # type: () -> None + raise RSAError(Err.get_error_message()) def keygen_callback(p, n, out=sys.stdout): + # type: (int, Any, IO[str]) -> None """ Default callback for gen_key(). """ - ch = ['.','+','*','\n'] + ch = ['.', '+', '*', '\n'] out.write(ch[p]) out.flush() def gen_key(bits, e, callback=keygen_callback): + # type: (int, int, Callable) -> RSA """ Generate an RSA key pair. - @type bits: int - @param bits: Key length, in bits. + :param bits: Key length, in bits. - @type e: int - @param e: The RSA public exponent. + :param e: The RSA public exponent. - @type callback: Python callable - @param callback: A Python callable object that is invoked - during key generation; its usual purpose is to provide visual - feedback. The default callback is keygen_callback. + :param callback: A Python callable object that is invoked + during key generation; its usual purpose is to + provide visual feedback. The default callback is + keygen_callback. - @rtype: M2Crypto.RSA.RSA - @return: M2Crypto.RSA.RSA object. - """ + :return: M2Crypto.RSA.RSA object. + """ return RSA(m2.rsa_generate_key(bits, e, callback), 1) def load_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> RSA """ Load an RSA key pair from file. - @type file: string - @param file: Name of file containing RSA public key in PEM format. + :param file: Name of file containing RSA public key in PEM format. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to unlock the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to unlock the + key. The default is util.passphrase_callback. - @rtype: M2Crypto.RSA.RSA - @return: M2Crypto.RSA.RSA object. + :return: M2Crypto.RSA.RSA object. """ - bio = BIO.openfile(file) - return load_key_bio(bio, callback) + with BIO.openfile(file) as bio: + return load_key_bio(bio, callback) def load_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> RSA """ Load an RSA key pair from an M2Crypto.BIO.BIO object. - @type bio: M2Crypto.BIO.BIO - @param bio: M2Crypto.BIO.BIO object containing RSA key pair in PEM - format. + :param bio: M2Crypto.BIO.BIO object containing RSA key pair in PEM + format. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to unlock the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to unlock the + key. The default is util.passphrase_callback. - @rtype: M2Crypto.RSA.RSA - @return: M2Crypto.RSA.RSA object. + :return: M2Crypto.RSA.RSA object. """ rsa = m2.rsa_read_key(bio._ptr(), callback) if rsa is None: @@ -374,75 +400,67 @@ def load_key_bio(bio, callback=util.passphrase_callback): def load_key_string(string, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> RSA """ Load an RSA key pair from a string. - @type string: string - @param string: String containing RSA key pair in PEM format. + :param string: String containing RSA key pair in PEM format. - @type callback: Python callable - @param callback: A Python callable object that is invoked - to acquire a passphrase with which to unlock the key. - The default is util.passphrase_callback. + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to unlock the + key. The default is util.passphrase_callback. - @rtype: M2Crypto.RSA.RSA - @return: M2Crypto.RSA.RSA object. + :return: M2Crypto.RSA.RSA object. """ bio = BIO.MemoryBuffer(string) return load_key_bio(bio, callback) def load_pub_key(file): + # type: (AnyStr) -> RSA_pub """ Load an RSA public key from file. - @type file: string - @param file: Name of file containing RSA public key in PEM format. + :param file: Name of file containing RSA public key in PEM format. - @rtype: M2Crypto.RSA.RSA_pub - @return: M2Crypto.RSA.RSA_pub object. + :return: M2Crypto.RSA.RSA_pub object. """ - bio = BIO.openfile(file) - return load_pub_key_bio(bio) + with BIO.openfile(file) as bio: + return load_pub_key_bio(bio) def load_pub_key_bio(bio): + # type: (BIO.BIO) -> RSA_pub """ Load an RSA public key from an M2Crypto.BIO.BIO object. - @type bio: M2Crypto.BIO.BIO - @param bio: M2Crypto.BIO.BIO object containing RSA public key in PEM - format. + :param bio: M2Crypto.BIO.BIO object containing RSA public key in PEM + format. - @rtype: M2Crypto.RSA.RSA_pub - @return: M2Crypto.RSA.RSA_pub object. - """ + :return: M2Crypto.RSA.RSA_pub object. + """ rsa = m2.rsa_read_pub_key(bio._ptr()) if rsa is None: rsa_error() return RSA_pub(rsa, 1) -def new_pub_key((e, n)): +def new_pub_key(e_n): + # type: (Tuple[bytes, bytes]) -> RSA_pub """ Instantiate an RSA_pub object from an (e, n) tuple. - @type e: string - @param e: The RSA public exponent; it is a string in OpenSSL's MPINT - format - 4-byte big-endian bit-count followed by the appropriate - number of bits. + :param e: The RSA public exponent; it is a string in OpenSSL's MPINT + format - 4-byte big-endian bit-count followed by the + appropriate number of bits. - @type n: string - @param n: The RSA composite of primes; it is a string in OpenSSL's MPINT - format - 4-byte big-endian bit-count followed by the appropriate - number of bits. + :param n: The RSA composite of primes; it is a string in OpenSSL's + MPINT format - 4-byte big-endian bit-count followed by the + appropriate number of bits. - @rtype: M2Crypto.RSA.RSA_pub - @return: M2Crypto.RSA.RSA_pub object. - """ + :return: M2Crypto.RSA.RSA_pub object. + """ + (e, n) = e_n rsa = m2.rsa_new() - m2.rsa_set_e(rsa, e) - m2.rsa_set_n(rsa, n) + m2.rsa_set_en(rsa, e, n) return RSA_pub(rsa, 1) - - diff --git a/M2Crypto/Rand.py b/M2Crypto/Rand.py index 1e6a918..86a6f16 100644 --- a/M2Crypto/Rand.py +++ b/M2Crypto/Rand.py @@ -1,17 +1,147 @@ """M2Crypto wrapper for OpenSSL PRNG. Requires OpenSSL 0.9.5 and above. -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. +Copyright (c) 2014-2017 Matej Cepl. All rights reserved. + +See LICENCE for the license information. +""" +from __future__ import absolute_import + +from M2Crypto import m2, py27plus, six +if py27plus: + from typing import AnyStr, Tuple # noqa + __all__ = ['rand_seed', 'rand_add', 'load_file', 'save_file', 'rand_bytes', - 'rand_pseudo_bytes'] + 'rand_pseudo_bytes', 'rand_file_name', 'rand_status'] + + +class RandError(ValueError): + pass + +m2.rand_init(RandError) + + +def rand_add(blob, entropy): + # type: (bytes, float) -> None + """ + Mixes blob into the PRNG state. + + :param blob: added data + :param entropy: (the lower bound of) an estimate of how much randomness + is contained in blob, measured in bytes. + + Thus, if the data at buf are unpredictable to an adversary, this + increases the uncertainty about the state and makes the PRNG output less + predictable. Suitable input comes from user interaction (random key + presses, mouse movements) and certain hardware events. + + Details about sources of randomness and how to estimate their entropy + can be found in the literature, e.g. RFC 1750. + """ + m2.rand_add(blob, entropy) # pylint: disable=no-member + + +def rand_seed(seed): + # type: (bytes) -> None + """ + Equivalent to rand_add() when len(seed) == entropy. + + :param seed: added data (see description at rand_add) + """ + m2.rand_seed(seed) # pylint: disable=no-member + + +def rand_status(): + # type: () -> int + """ + Check whether there is enough entropy in PRNG. + + :return: 1 if the PRNG has been seeded with enough + data, 0 otherwise. + """ + return m2.rand_status() # pylint: disable=no-member + + +def rand_file_name(): + # type: () -> str + """ + Generate a default path for the random seed file. + + :return: string with the filename. + The seed file is $RANDFILE if that environment variable + is set, $HOME/.rnd otherwise. If $HOME is not set either, + an error occurs. + """ + return six.ensure_text(m2.rand_file_name()) # pylint: disable=no-member + + +def load_file(filename, max_bytes): + # type: (AnyStr, int) -> int + """ + Read a number of bytes from file filename and adds them to the PRNG. + + If max_bytes is non-negative, up to to max_bytes are read; starting with + OpenSSL 0.9.5, if max_bytes is -1, the complete file is read. + + :param filename: + :param max_bytes: + :return: the number of bytes read. + """ + return m2.rand_load_file(six.ensure_str(filename), max_bytes) # pylint: disable=no-member + + +def save_file(filename): + # type: (AnyStr) -> int + """ + Write a number of random bytes (currently 1024) to file. + + The file then can be used to initialize the PRNG by calling load_file() in + a later session. + + :param filename: + :return: returns the number of bytes written, and -1 if the bytes + written were generated without appropriate seed. + """ + return m2.rand_save_file(filename) # pylint: disable=no-member + + +def rand_bytes(num): + # type: (int) -> bytes + """ + Return n cryptographically strong pseudo-random bytes. + + An error occurs if the PRNG has not been seeded with enough randomness + to ensure an unpredictable byte sequence. + + :param num: number of bytes to be returned + :return: random bytes + """ + return m2.rand_bytes(num) # pylint: disable=no-member + + +def rand_pseudo_bytes(num): + # type: (int) -> Tuple[bytes, int] + """ + Return num pseudo-random bytes into buf. -import m2 + Pseudo-random byte sequences generated by this method will be unique + if they are of sufficient length, but are not necessarily + unpredictable. They can be used for non-cryptographic purposes and for + certain purposes in cryptographic protocols, but usually not for key + generation etc. -rand_seed = m2.rand_seed -rand_add = m2.rand_add -load_file = m2.rand_load_file -save_file = m2.rand_save_file -rand_bytes = m2.rand_bytes -rand_pseudo_bytes = m2.rand_pseudo_bytes + Output of the function is mixed into the entropy pool before + retrieving the new pseudo-random bytes unless disabled at compile + time (see FAQ). + :param num: number of bytes to be returned + :return: random bytes + """ + import warnings + if m2.OPENSSL_VERSION_NUMBER >= 0x10100000: + warnings.warn('The underlying OpenSSL method has been ' + + 'deprecated. Use Rand.rand_bytes instead.', + DeprecationWarning) + return m2.rand_pseudo_bytes(num) # pylint: disable=no-member diff --git a/M2Crypto/SMIME.py b/M2Crypto/SMIME.py index 556cd8f..7c78d19 100644 --- a/M2Crypto/SMIME.py +++ b/M2Crypto/SMIME.py @@ -1,42 +1,55 @@ +from __future__ import absolute_import + """M2Crypto wrapper for OpenSSL S/MIME API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" -import BIO, EVP, X509, Err, util -import m2 +from M2Crypto import BIO, EVP, Err, X509, m2, util +if util.py27plus: + from typing import AnyStr, Callable, Optional # noqa + +PKCS7_TEXT = m2.PKCS7_TEXT # type: int +PKCS7_NOCERTS = m2.PKCS7_NOCERTS # type: int +PKCS7_NOSIGS = m2.PKCS7_NOSIGS # type: int +PKCS7_NOCHAIN = m2.PKCS7_NOCHAIN # type: int +PKCS7_NOINTERN = m2.PKCS7_NOINTERN # type: int +PKCS7_NOVERIFY = m2.PKCS7_NOVERIFY # type: int +PKCS7_DETACHED = m2.PKCS7_DETACHED # type: int +PKCS7_BINARY = m2.PKCS7_BINARY # type: int +PKCS7_NOATTR = m2.PKCS7_NOATTR # type: int -PKCS7_TEXT = m2.PKCS7_TEXT -PKCS7_NOCERTS = m2.PKCS7_NOCERTS -PKCS7_NOSIGS = m2.PKCS7_NOSIGS -PKCS7_NOCHAIN = m2.PKCS7_NOCHAIN -PKCS7_NOINTERN = m2.PKCS7_NOINTERN -PKCS7_NOVERIFY = m2.PKCS7_NOVERIFY -PKCS7_DETACHED = m2.PKCS7_DETACHED -PKCS7_BINARY = m2.PKCS7_BINARY -PKCS7_NOATTR = m2.PKCS7_NOATTR +PKCS7_SIGNED = m2.PKCS7_SIGNED # type: int +PKCS7_ENVELOPED = m2.PKCS7_ENVELOPED # type: int +PKCS7_SIGNED_ENVELOPED = m2.PKCS7_SIGNED_ENVELOPED # Deprecated +PKCS7_DATA = m2.PKCS7_DATA # type: int -PKCS7_SIGNED = m2.PKCS7_SIGNED -PKCS7_ENVELOPED = m2.PKCS7_ENVELOPED -PKCS7_SIGNED_ENVELOPED = m2.PKCS7_SIGNED_ENVELOPED # Deprecated -PKCS7_DATA = m2.PKCS7_DATA -class PKCS7_Error(Exception): pass +class PKCS7_Error(Exception): + pass m2.pkcs7_init(PKCS7_Error) -class PKCS7: + +class PKCS7(object): m2_pkcs7_free = m2.pkcs7_free def __init__(self, pkcs7=None, _pyfree=0): + # type: (Optional[bytes], int) -> None + """PKCS7 object. + + :param pkcs7: binary representation of + the OpenSSL type PKCS7 + """ if pkcs7 is not None: self.pkcs7 = pkcs7 self._pyfree = _pyfree else: self.pkcs7 = m2.pkcs7_new() self._pyfree = 1 - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_pkcs7_free(self.pkcs7) @@ -44,63 +57,71 @@ class PKCS7: return self.pkcs7 def type(self, text_name=0): + # type: (int) -> int if text_name: return m2.pkcs7_type_sn(self.pkcs7) else: return m2.pkcs7_type_nid(self.pkcs7) def write(self, bio): + # type: (BIO.BIO) -> int return m2.pkcs7_write_bio(self.pkcs7, bio._ptr()) def write_der(self, bio): + # type: (BIO.BIO) -> int return m2.pkcs7_write_bio_der(self.pkcs7, bio._ptr()) - def get0_signers(self, certs, flags = 0): + def get0_signers(self, certs, flags=0): + # type: (X509.X509_Stack, int) -> X509.X509_Stack return X509.X509_Stack(m2.pkcs7_get0_signers(self.pkcs7, certs.stack, flags), 1) def load_pkcs7(p7file): - bio = m2.bio_new_file(p7file, 'r') - if bio is None: - raise BIO.BIOError(Err.get_error()) + # type: (AnyStr) -> PKCS7 + with BIO.openfile(p7file, 'r') as bio: + p7_ptr = m2.pkcs7_read_bio(bio.bio) + + return PKCS7(p7_ptr, 1) + + +def load_pkcs7_der(p7file): + # type: (AnyStr) -> PKCS7 + with BIO.openfile(p7file, 'rb') as bio: + p7_ptr = m2.pkcs7_read_bio_der(bio.bio) - try: - p7_ptr = m2.pkcs7_read_bio(bio) - finally: - m2.bio_free(bio) - - if p7_ptr is None: - raise PKCS7_Error(Err.get_error()) return PKCS7(p7_ptr, 1) - + def load_pkcs7_bio(p7_bio): + # type: (BIO.BIO) -> PKCS7 p7_ptr = m2.pkcs7_read_bio(p7_bio._ptr()) - if p7_ptr is None: - raise PKCS7_Error(Err.get_error()) return PKCS7(p7_ptr, 1) - + + +def load_pkcs7_bio_der(p7_bio): + # type: (BIO.BIO) -> PKCS7 + p7_ptr = m2.pkcs7_read_bio_der(p7_bio._ptr()) + return PKCS7(p7_ptr, 1) + def smime_load_pkcs7(p7file): + # type: (AnyStr) -> PKCS7 bio = m2.bio_new_file(p7file, 'r') - if bio is None: - raise BIO.BIOError(Err.get_error()) - + try: p7_ptr, bio_ptr = m2.smime_read_pkcs7(bio) finally: m2.bio_free(bio) - - if p7_ptr is None: - raise SMIME_Error(Err.get_error()) + if bio_ptr is None: return PKCS7(p7_ptr, 1), None else: return PKCS7(p7_ptr, 1), BIO.BIO(bio_ptr, 1) - + def smime_load_pkcs7_bio(p7_bio): + # type: (BIO.BIO) -> PKCS7 p7_ptr, bio_ptr = m2.smime_read_pkcs7(p7_bio._ptr()) if p7_ptr is None: raise SMIME_Error(Err.get_error()) @@ -108,126 +129,151 @@ def smime_load_pkcs7_bio(p7_bio): return PKCS7(p7_ptr, 1), None else: return PKCS7(p7_ptr, 1), BIO.BIO(bio_ptr, 1) - - -class Cipher: - """ - Object interface to EVP_CIPHER without all the frills of M2Crypto.EVP.Cipher. + +class Cipher(object): + """Object interface to EVP_CIPHER without all the frills of + M2Crypto.EVP.Cipher. """ def __init__(self, algo): + # type: (str) -> None cipher = getattr(m2, algo, None) if cipher is None: - raise ValueError, ('unknown cipher', algo) + raise ValueError('unknown cipher', algo) self.cipher = cipher() def _ptr(self): return self.cipher -class SMIME_Error(Exception): pass +class SMIME_Error(Exception): + pass m2.smime_init(SMIME_Error) -class SMIME: - def load_key(self, keyfile, certfile=None, callback=util.passphrase_callback): + +# FIXME class has no __init__ method +class SMIME(object): + def load_key(self, keyfile, certfile=None, + callback=util.passphrase_callback): + # type: (AnyStr, Optional[AnyStr], Callable) -> None if certfile is None: certfile = keyfile self.pkey = EVP.load_key(keyfile, callback) self.x509 = X509.load_cert(certfile) - def load_key_bio(self, keybio, certbio=None, callback=util.passphrase_callback): + def load_key_bio(self, keybio, certbio=None, + callback=util.passphrase_callback): + # type: (BIO.BIO, Optional[BIO.BIO], Callable) -> None if certbio is None: certbio = keybio self.pkey = EVP.load_key_bio(keybio, callback) self.x509 = X509.load_cert_bio(certbio) def set_x509_stack(self, stack): + # type: (X509.X509_Stack) -> None assert isinstance(stack, X509.X509_Stack) self.x509_stack = stack def set_x509_store(self, store): + # type: (X509.X509_Store) -> None assert isinstance(store, X509.X509_Store) self.x509_store = store def set_cipher(self, cipher): + # type: (Cipher) -> None assert isinstance(cipher, Cipher) self.cipher = cipher def unset_key(self): + # type: () -> None del self.pkey del self.x509 def unset_x509_stack(self): + # type: () -> None del self.x509_stack def unset_x509_store(self): + # type: () -> None del self.x509_store def unset_cipher(self): + # type: () -> None del self.cipher def encrypt(self, data_bio, flags=0): + # type: (BIO.BIO, int) -> PKCS7 if not hasattr(self, 'cipher'): - raise SMIME_Error, 'no cipher: use set_cipher()' + raise SMIME_Error('no cipher: use set_cipher()') if not hasattr(self, 'x509_stack'): - raise SMIME_Error, 'no recipient certs: use set_x509_stack()' - pkcs7 = m2.pkcs7_encrypt(self.x509_stack._ptr(), data_bio._ptr(), self.cipher._ptr(), flags) - if pkcs7 is None: - raise SMIME_Error(Err.get_error()) + raise SMIME_Error('no recipient certs: use set_x509_stack()') + + pkcs7 = m2.pkcs7_encrypt(self.x509_stack._ptr(), data_bio._ptr(), + self.cipher._ptr(), flags) + return PKCS7(pkcs7, 1) def decrypt(self, pkcs7, flags=0): + # type: (PKCS7, int) -> Optional[bytes] if not hasattr(self, 'pkey'): - raise SMIME_Error, 'no private key: use load_key()' + raise SMIME_Error('no private key: use load_key()') if not hasattr(self, 'x509'): - raise SMIME_Error, 'no certificate: load_key() used incorrectly?' - blob = m2.pkcs7_decrypt(pkcs7._ptr(), self.pkey._ptr(), self.x509._ptr(), flags) - if blob is None: - raise SMIME_Error(Err.get_error()) + raise SMIME_Error('no certificate: load_key() used incorrectly?') + blob = m2.pkcs7_decrypt(pkcs7._ptr(), self.pkey._ptr(), + self.x509._ptr(), flags) return blob - def sign(self, data_bio, flags=0): + def sign(self, data_bio, flags=0, algo='sha1'): + # type: (BIO.BIO, int, Optional[str]) -> PKCS7 if not hasattr(self, 'pkey'): - raise SMIME_Error, 'no private key: use load_key()' + raise SMIME_Error('no private key: use load_key()') + + hash = getattr(m2, algo, None) + + if hash is None: + raise SMIME_Error('no such hash algorithm %s' % algo) + if hasattr(self, 'x509_stack'): - pkcs7 = m2.pkcs7_sign1(self.x509._ptr(), self.pkey._ptr(), - self.x509_stack._ptr(), data_bio._ptr(), flags) - if pkcs7 is None: - raise SMIME_Error(Err.get_error()) + pkcs7 = m2.pkcs7_sign1(self.x509._ptr(), self.pkey._ptr(), + self.x509_stack._ptr(), + data_bio._ptr(), hash(), flags) return PKCS7(pkcs7, 1) else: - pkcs7 = m2.pkcs7_sign0(self.x509._ptr(), self.pkey._ptr(), - data_bio._ptr(), flags) - if pkcs7 is None: - raise SMIME_Error(Err.get_error()) + pkcs7 = m2.pkcs7_sign0(self.x509._ptr(), self.pkey._ptr(), + data_bio._ptr(), hash(), flags) return PKCS7(pkcs7, 1) def verify(self, pkcs7, data_bio=None, flags=0): + # type: (PKCS7, BIO.BIO, int) -> Optional[bytes] if not hasattr(self, 'x509_stack'): - raise SMIME_Error, 'no signer certs: use set_x509_stack()' + raise SMIME_Error('no signer certs: use set_x509_stack()') if not hasattr(self, 'x509_store'): - raise SMIME_Error, 'no x509 cert store: use set_x509_store()' + raise SMIME_Error('no x509 cert store: use set_x509_store()') assert isinstance(pkcs7, PKCS7), 'pkcs7 not an instance of PKCS7' p7 = pkcs7._ptr() if data_bio is None: - blob = m2.pkcs7_verify0(p7, self.x509_stack._ptr(), self.x509_store._ptr(), flags) + blob = m2.pkcs7_verify0(p7, self.x509_stack._ptr(), + self.x509_store._ptr(), flags) else: - blob = m2.pkcs7_verify1(p7, self.x509_stack._ptr(), self.x509_store._ptr(), data_bio._ptr(), flags) - if blob is None: - raise SMIME_Error(Err.get_error()) + blob = m2.pkcs7_verify1(p7, self.x509_stack._ptr(), + self.x509_store._ptr(), + data_bio._ptr(), flags) return blob def write(self, out_bio, pkcs7, data_bio=None, flags=0): + # type: (BIO.BIO, PKCS7, Optional[BIO.BIO], int) -> int assert isinstance(pkcs7, PKCS7) if data_bio is None: return m2.smime_write_pkcs7(out_bio._ptr(), pkcs7._ptr(), flags) else: - return m2.smime_write_pkcs7_multi(out_bio._ptr(), pkcs7._ptr(), data_bio._ptr(), flags) + return m2.smime_write_pkcs7_multi(out_bio._ptr(), pkcs7._ptr(), + data_bio._ptr(), flags) def text_crlf(text): + # type: (bytes) -> bytes bio_in = BIO.MemoryBuffer(text) bio_out = BIO.MemoryBuffer() if m2.smime_crlf_copy(bio_in._ptr(), bio_out._ptr()): @@ -237,9 +283,9 @@ def text_crlf(text): def text_crlf_bio(bio_in): + # type: (BIO.BIO) -> BIO.BIO bio_out = BIO.MemoryBuffer() if m2.smime_crlf_copy(bio_in._ptr(), bio_out._ptr()): return bio_out else: raise SMIME_Error(Err.get_error()) - diff --git a/M2Crypto/SSL/Checker.py b/M2Crypto/SSL/Checker.py index 5218663..86ed8ba 100644 --- a/M2Crypto/SSL/Checker.py +++ b/M2Crypto/SSL/Checker.py @@ -10,78 +10,105 @@ Copyright 2008 Heikki Toivonen. All rights reserved. __all__ = ['SSLVerificationError', 'NoCertificate', 'WrongCertificate', 'WrongHost', 'Checker'] -from M2Crypto import util, EVP, m2 import re +import socket + +from M2Crypto import X509, m2, six, util # noqa +if util.py27plus: + from typing import AnyStr, Optional # noqa + class SSLVerificationError(Exception): pass + class NoCertificate(SSLVerificationError): pass + class WrongCertificate(SSLVerificationError): pass + class WrongHost(SSLVerificationError): def __init__(self, expectedHost, actualHost, fieldName='commonName'): + # type: (str, AnyStr, str) -> None """ This exception will be raised if the certificate returned by the peer was issued for a different host than we tried to connect to. This could be due to a server misconfiguration or an active attack. - - @param expectedHost: The name of the host we expected to find in the + + :param expectedHost: The name of the host we expected to find in the certificate. - @param actualHost: The name of the host we actually found in the + :param actualHost: The name of the host we actually found in the certificate. - @param fieldName: The field name where we noticed the error. This + :param fieldName: The field name where we noticed the error. This should be either 'commonName' or 'subjectAltName'. """ if fieldName not in ('commonName', 'subjectAltName'): - raise ValueError('Unknown fieldName, should be either commonName or subjectAltName') - + raise ValueError( + 'Unknown fieldName, should be either commonName ' + + 'or subjectAltName') + SSLVerificationError.__init__(self) self.expectedHost = expectedHost self.actualHost = actualHost self.fieldName = fieldName - + def __str__(self): + # type: () -> str s = 'Peer certificate %s does not match host, expected %s, got %s' \ - % (self.fieldName, self.expectedHost, self.actualHost) - if isinstance(s, unicode): - s = s.encode('utf8') - return s + % (self.fieldName, self.expectedHost, self.actualHost) + return six.ensure_text(s) -class Checker: - +class Checker(object): + numericIpMatch = re.compile('^[0-9]+(\.[0-9]+)*$') - + def __init__(self, host=None, peerCertHash=None, peerCertDigest='sha1'): + # type: (Optional[str], Optional[bytes], str) -> None self.host = host + if peerCertHash is not None: + peerCertHash = six.ensure_binary(peerCertHash) self.fingerprint = peerCertHash - self.digest = peerCertDigest + self.digest = peerCertDigest # type: str def __call__(self, peerCert, host=None): + # type: (X509.X509, Optional[str]) -> bool if peerCert is None: raise NoCertificate('peer did not return certificate') if host is not None: - self.host = host - + self.host = host # type: str + if self.fingerprint: if self.digest not in ('sha1', 'md5'): - raise ValueError('unsupported digest "%s"' %(self.digest)) - - if (self.digest == 'sha1' and len(self.fingerprint) != 40) or \ - (self.digest == 'md5' and len(self.fingerprint) != 32): - raise WrongCertificate('peer certificate fingerprint length does not match') - - der = peerCert.as_der() - md = EVP.MessageDigest(self.digest) - md.update(der) - digest = md.final() - if util.octx_to_num(digest) != int(self.fingerprint, 16): - raise WrongCertificate('peer certificate fingerprint does not match') + raise ValueError('unsupported digest "%s"' % self.digest) + + if self.digest == 'sha1': + expected_len = 40 + elif self.digest == 'md5': + expected_len = 32 + else: + raise ValueError('Unexpected digest {0}'.format(self.digest)) + + if len(self.fingerprint) != expected_len: + raise WrongCertificate( + ('peer certificate fingerprint length does not match\n' + + 'fingerprint: {0}\nexpected = {1}\n' + + 'observed = {2}').format(self.fingerprint, + expected_len, + len(self.fingerprint))) + + expected_fingerprint = six.ensure_text(self.fingerprint) + observed_fingerprint = peerCert.get_fingerprint(md=self.digest) + if observed_fingerprint != expected_fingerprint: + raise WrongCertificate( + ('peer certificate fingerprint does not match\n' + + 'expected = {0},\n' + + 'observed = {1}').format(expected_fingerprint, + observed_fingerprint)) if self.host: hostValidationPassed = False @@ -93,7 +120,7 @@ class Checker: if self._splitSubjectAltName(self.host, subjectAltName): hostValidationPassed = True elif self.useSubjectAltNameOnly: - raise WrongHost(expectedHost=self.host, + raise WrongHost(expectedHost=self.host, actualHost=subjectAltName, fieldName='subjectAltName') except LookupError: @@ -103,7 +130,8 @@ class Checker: if not hostValidationPassed: hasCommonName = False commonNames = '' - for entry in peerCert.get_subject().get_entries_by_nid(m2.NID_commonName): + for entry in peerCert.get_subject().get_entries_by_nid( + m2.NID_commonName): hasCommonName = True commonName = entry.get_data().as_text() if not commonNames: @@ -125,31 +153,42 @@ class Checker: return True def _splitSubjectAltName(self, host, subjectAltName): + # type: (AnyStr, AnyStr) -> bool """ >>> check = Checker() - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:my.example.com') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:my.example.com') True - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:*.example.com') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:*.example.com') True - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*.example.com') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*.example.com') True - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*ample.com') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*ample.com') False >>> check.useSubjectAltNameOnly True - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*ample.com, othername:') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*ample.com, othername:') False - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*ample.com, DNS:my.example.org') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*ample.com, DNS:my.example.org') False - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:m*ample.com, DNS:my.example.com') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*ample.com, DNS:my.example.com') True - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='DNS:my.example.com, DNS:my.example.org') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:my.example.com, DNS:my.example.org') True >>> check.useSubjectAltNameOnly True - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='') False - >>> check._splitSubjectAltName(host='my.example.com', subjectAltName='othername:') + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='othername:') False >>> check.useSubjectAltNameOnly False @@ -161,10 +200,14 @@ class Checker: self.useSubjectAltNameOnly = True if self._match(host, certHost[4:]): return True + elif certHost[:11] == 'ip address:': + self.useSubjectAltNameOnly = True + if self._matchIPAddress(host, certHost[11:]): + return True return False - def _match(self, host, certHost): + # type: (str, str) -> bool """ >>> check = Checker() >>> check._match(host='my.example.com', certHost='my.example.com') @@ -200,7 +243,7 @@ class Checker: return False if self.numericIpMatch.match(host) or \ - self.numericIpMatch.match(certHost.replace('*', '')): + self.numericIpMatch.match(certHost.replace('*', '')): # Not sure if * allowed in numeric IP, but think not. return False @@ -213,11 +256,41 @@ class Checker: # Massage certHost so that it can be used in regex certHost = certHost.replace('.', '\.') certHost = certHost.replace('*', '[^\.]*') - if re.compile('^%s$' %(certHost)).match(host): + if re.compile('^%s$' % certHost).match(host): return True return False + def _matchIPAddress(self, host, certHost): + # type: (AnyStr, AnyStr) -> bool + """ + >>> check = Checker() + >>> check._matchIPAddress(host='my.example.com', + ... certHost='my.example.com') + False + >>> check._matchIPAddress(host='1.2.3.4', certHost='1.2.3.4') + True + >>> check._matchIPAddress(host='1.2.3.4', certHost='*.2.3.4') + False + >>> check._matchIPAddress(host='1.2.3.4', certHost='1.2.3.40') + False + >>> check._matchIPAddress(host='::1', certHost='::1') + True + >>> check._matchIPAddress(host='::1', certHost='0:0:0:0:0:0:0:1') + True + >>> check._matchIPAddress(host='::1', certHost='::2') + False + """ + try: + canonical = socket.getaddrinfo(host, 0, 0, socket.SOCK_STREAM, 0, + socket.AI_NUMERICHOST) + certCanonical = socket.getaddrinfo(certHost, 0, 0, + socket.SOCK_STREAM, 0, + socket.AI_NUMERICHOST) + except: + return False + return canonical == certCanonical + if __name__ == '__main__': import doctest diff --git a/M2Crypto/SSL/Cipher.py b/M2Crypto/SSL/Cipher.py index 2d2c088..4683377 100644 --- a/M2Crypto/SSL/Cipher.py +++ b/M2Crypto/SSL/Cipher.py @@ -4,41 +4,57 @@ Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" __all__ = ['Cipher', 'Cipher_Stack'] -from M2Crypto import m2 +from M2Crypto import m2, py27plus, six +if py27plus: + from typing import Iterable # noqa -class Cipher: + +class Cipher(object): def __init__(self, cipher): - self.cipher=cipher + # type: (str) -> None + self.cipher = cipher def __len__(self): + # type: () -> int return m2.ssl_cipher_get_bits(self.cipher) def __repr__(self): + # type: () -> str return "%s-%s" % (self.name(), len(self)) def __str__(self): + # type: () -> str return "%s-%s" % (self.name(), len(self)) def version(self): + # type: () -> int return m2.ssl_cipher_get_version(self.cipher) def name(self): - return m2.ssl_cipher_get_name(self.cipher) + # type: () -> str + return six.ensure_text(m2.ssl_cipher_get_name(self.cipher)) -class Cipher_Stack: +class Cipher_Stack(object): def __init__(self, stack): - self.stack=stack + # type: (bytes) -> None + """ + :param stack: binary of the C-type STACK_OF(SSL_CIPHER) + """ + self.stack = stack def __len__(self): + # type: () -> int return m2.sk_ssl_cipher_num(self.stack) def __getitem__(self, idx): + # type: (int) -> Cipher if not 0 <= idx < m2.sk_ssl_cipher_num(self.stack): raise IndexError('index out of range') - v=m2.sk_ssl_cipher_value(self.stack, idx) + v = m2.sk_ssl_cipher_value(self.stack, idx) return Cipher(v) def __iter__(self): - for i in xrange(m2.sk_ssl_cipher_num(self.stack)): + # type: () -> Iterable + for i in six.moves.range(m2.sk_ssl_cipher_num(self.stack)): yield self[i] diff --git a/M2Crypto/SSL/Connection.py b/M2Crypto/SSL/Connection.py index ef6a2c8..7053aa6 100644 --- a/M2Crypto/SSL/Connection.py +++ b/M2Crypto/SSL/Connection.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """SSL Connection aka socket Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. @@ -8,28 +10,30 @@ Copyright (C) 2004-2007 OSAF. All Rights Reserved. Copyright 2008 Heikki Toivonen. All rights reserved. """ +import logging +import socket + +from M2Crypto import BIO, Err, X509, m2, py27plus, six, util # noqa +from M2Crypto.SSL import Checker, Context, timeout # noqa +from M2Crypto.SSL import SSLError +from M2Crypto.SSL.Cipher import Cipher, Cipher_Stack +from M2Crypto.SSL.Session import Session +if py27plus: + from typing import Any, AnyStr, Callable, Dict, List, Optional, Tuple, Union # noqa + __all__ = ['Connection', - 'timeout', # XXX Not really, but for documentation purposes + 'timeout', # XXX Not really, but for documentation purposes ] -# Python -import socket +log = logging.getLogger(__name__) -# M2Crypto -from Cipher import Cipher, Cipher_Stack -from Session import Session -from M2Crypto import BIO, X509, m2 -import timeout -import Checker - -#SSLError = getattr(__import__('M2Crypto.SSL', globals(), locals(), 'SSLError'), 'SSLError') -from M2Crypto.SSL import SSLError def _serverPostConnectionCheck(*args, **kw): + # type: (*Any, **Any) -> int return 1 -class Connection: +class Connection(object): """An SSL connection.""" clientPostConnectionCheck = Checker.Checker() @@ -37,35 +41,57 @@ class Connection: m2_bio_free = m2.bio_free m2_ssl_free = m2.ssl_free - - def __init__(self, ctx, sock=None): + m2_bio_noclose = m2.bio_noclose + + def __init__(self, ctx, sock=None, family=socket.AF_INET): + # type: (Context, socket.socket, int) -> None + """ + + :param ctx: SSL.Context + :param sock: socket to be used + :param family: socket family + """ self.ctx = ctx - self.ssl = m2.ssl_new(self.ctx.ctx) - if sock is not None: + self.ssl = m2.ssl_new(self.ctx.ctx) # type: bytes + if sock is not None: self.socket = sock else: - self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket = socket.socket(family, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._fileno = self.socket.fileno() - - self.blocking = self.socket.gettimeout() - + + self._timeout = self.socket.gettimeout() + if self._timeout is None: + self._timeout = -1.0 + self.ssl_close_flag = m2.bio_noclose - + if self.ctx.post_connection_check is not None: + self.set_post_connection_check_callback( + self.ctx.post_connection_check) + + self.host = None + def __del__(self): + # type: () -> None + # Notice that M2Crypto doesn't automatically shuts down the + # connection here. You have to call self.close() in your + # program, M2Crypto won't do it automatically for you. if getattr(self, 'sslbio', None): self.m2_bio_free(self.sslbio) if getattr(self, 'sockbio', None): self.m2_bio_free(self.sockbio) - if self.ssl_close_flag == m2.bio_noclose and getattr(self, 'ssl', None): + if self.ssl_close_flag == self.m2_bio_noclose and \ + getattr(self, 'ssl', None): self.m2_ssl_free(self.ssl) self.socket.close() def close(self): + # type: () -> None m2.ssl_shutdown(self.ssl) def clear(self): + # type: () -> int """ If there were errors in this connection, call clear() rather than close() to end it, so that bad sessions will be cleared @@ -74,61 +100,116 @@ class Connection: return m2.ssl_clear(self.ssl) def set_shutdown(self, mode): + # type: (int) -> None + """Sets the shutdown state of the Connection to mode. + + The shutdown state of an ssl connection is a bitmask of (use + m2.SSL_* constants): + + 0 No shutdown setting, yet. + + SSL_SENT_SHUTDOWN + A "close notify" shutdown alert was sent to the peer, the + connection is being considered closed and the session is + closed and correct. + + SSL_RECEIVED_SHUTDOWN + A shutdown alert was received form the peer, either a normal + "close notify" or a fatal error. + + SSL_SENT_SHUTDOWN and SSL_RECEIVED_SHUTDOWN can be set at the + same time. + + :param mode: set the mode bitmask. + """ m2.ssl_set_shutdown1(self.ssl, mode) def get_shutdown(self): + # type: () -> None + """Get the current shutdown mode of the Connection.""" return m2.ssl_get_shutdown(self.ssl) def bind(self, addr): + # type: (util.AddrType) -> None self.socket.bind(addr) def listen(self, qlen=5): - self.socket.listen(qlen) + # type: (int) -> None + self.socket.listen(qlen) def ssl_get_error(self, ret): + # type: (int) -> int return m2.ssl_get_error(self.ssl, ret) def set_bio(self, readbio, writebio): - """ - Explicitly set read and write bios + # type: (BIO.BIO, BIO.BIO) -> None + """Explicitly set read and write bios + + Connects the BIOs for the read and write operations of the + TLS/SSL (encrypted) side of ssl. + + The SSL engine inherits the behaviour of both BIO objects, + respectively. If a BIO is non-blocking, the Connection will also + have non-blocking behaviour. + + If there was already a BIO connected to Connection, BIO_free() + will be called (for both the reading and writing side, if + different). + + :param readbio: BIO for reading + :param writebio: BIO for writing. """ m2.ssl_set_bio(self.ssl, readbio._ptr(), writebio._ptr()) - + def set_client_CA_list_from_file(self, cafile): - """ - Set the acceptable client CA list. If the client - returns a certificate, it must have been issued by + # type: (AnyStr) -> None + """Set the acceptable client CA list. + + If the client returns a certificate, it must have been issued by one of the CAs listed in cafile. - + Makes sense only for servers. - - @param cafile: Filename from which to load the CA list. + + :param cafile: Filename from which to load the CA list. + + :return: 0 A failure while manipulating the STACK_OF(X509_NAME) + object occurred or the X509_NAME could not be + extracted from cacert. Check the error stack to find + out the reason. + + 1 The operation succeeded. """ m2.ssl_set_client_CA_list_from_file(self.ssl, cafile) def set_client_CA_list_from_context(self): + # type: () -> None """ Set the acceptable client CA list. If the client returns a certificate, it must have been issued by one of the CAs listed in context. - + Makes sense only for servers. """ m2.ssl_set_client_CA_list_from_context(self.ssl, self.ctx.ctx) def setup_addr(self, addr): + # type: (util.AddrType) -> None self.addr = addr def set_ssl_close_flag(self, flag): + # type: (int) -> None """ By default, SSL struct will be freed in __del__. Call with m2.bio_close to override this default. + + :param flag: either m2.bio_close or m2.bio_noclose """ if flag not in (m2.bio_close, m2.bio_noclose): raise ValueError("flag must be m2.bio_close or m2.bio_noclose") self.ssl_close_flag = flag def setup_ssl(self): + # type: () -> None # Make a BIO_s_socket. self.sockbio = m2.bio_new_socket(self.socket.fileno(), 0) # Link SSL struct with the BIO_socket. @@ -139,223 +220,471 @@ class Connection: m2.bio_set_ssl(self.sslbio, self.ssl, m2.bio_noclose) def _setup_ssl(self, addr): + # type: (util.AddrType) -> None """Deprecated""" self.setup_addr(addr) self.setup_ssl() def set_accept_state(self): + # type: () -> None + """Sets Connection to work in the server mode.""" m2.ssl_set_accept_state(self.ssl) def accept_ssl(self): - return m2.ssl_accept(self.ssl) + # type: () -> Optional[int] + """Waits for a TLS/SSL client to initiate the TLS/SSL handshake. + + The communication channel must already have been set and + assigned to the ssl by setting an underlying BIO. + + :return: 0 The TLS/SSL handshake was not successful but was shut + down controlled and by the specifications of the + TLS/SSL protocol. Call get_error() with the return + value ret to find out the reason. + + 1 The TLS/SSL handshake was successfully completed, + a TLS/SSL connection has been established. + + <0 The TLS/SSL handshake was not successful because + a fatal error occurred either at the protocol level + or a connection failure occurred. The shutdown was + not clean. It can also occur of action is need to + continue the operation for non-blocking BIOs. Call + get_error() with the return value ret to find + out the reason. + """ + return m2.ssl_accept(self.ssl, self._timeout) def accept(self): - """Accept an SSL connection. The return value is a pair (ssl, addr) where - ssl is a new SSL connection object and addr is the address bound to - the other end of the SSL connection.""" + # type: () -> Tuple[Connection, util.AddrType] + """Accept an SSL connection. + + The return value is a pair (ssl, addr) where ssl is a new SSL + connection object and addr is the address bound to the other end + of the SSL connection. + + :return: tuple of Connection and addr. Address can take very + various forms (see socket documentation), for IPv4 it + is tuple(str, int), for IPv6 a tuple of four (host, + port, flowinfo, scopeid), where the last two are + optional ints. + """ sock, addr = self.socket.accept() ssl = Connection(self.ctx, sock) ssl.addr = addr ssl.setup_ssl() ssl.set_accept_state() ssl.accept_ssl() - check = getattr(self, 'postConnectionCheck', self.serverPostConnectionCheck) + check = getattr(self, 'postConnectionCheck', + self.serverPostConnectionCheck) if check is not None: if not check(ssl.get_peer_cert(), ssl.addr[0]): - raise Checker.SSLVerificationError, 'post connection check failed' + raise Checker.SSLVerificationError( + 'post connection check failed') return ssl, addr def set_connect_state(self): + # type: () -> None + """Sets Connection to work in the client mode.""" m2.ssl_set_connect_state(self.ssl) def connect_ssl(self): - return m2.ssl_connect(self.ssl) + # type: () -> Optional[int] + return m2.ssl_connect(self.ssl, self._timeout) def connect(self, addr): + # type: (util.AddrType) -> int + """Overloading socket.connect() + + :param addr: addresses have various depending on their type + + :return:status of ssl_connect() + """ self.socket.connect(addr) self.addr = addr self.setup_ssl() self.set_connect_state() ret = self.connect_ssl() - check = getattr(self, 'postConnectionCheck', self.clientPostConnectionCheck) + check = getattr(self, 'postConnectionCheck', + self.clientPostConnectionCheck) if check is not None: - if not check(self.get_peer_cert(), self.addr[0]): - raise Checker.SSLVerificationError, 'post connection check failed' + if not check(self.get_peer_cert(), + self.host if self.host else self.addr[0]): + raise Checker.SSLVerificationError( + 'post connection check failed') return ret def shutdown(self, how): + # type: (int) -> None m2.ssl_set_shutdown(self.ssl, how) def renegotiate(self): + # type: () -> int """Renegotiate this connection's SSL parameters.""" return m2.ssl_renegotiate(self.ssl) def pending(self): - """Return the numbers of octets that can be read from the - connection.""" + # type: () -> int + """Return the numbers of octets that can be read from the connection.""" return m2.ssl_pending(self.ssl) def _write_bio(self, data): - return m2.ssl_write(self.ssl, data) + # type: (bytes) -> int + return m2.ssl_write(self.ssl, data, self._timeout) def _write_nbio(self, data): + # type: (bytes) -> int return m2.ssl_write_nbio(self.ssl, data) def _read_bio(self, size=1024): + # type: (int) -> bytes if size <= 0: - raise ValueError, 'size <= 0' - return m2.ssl_read(self.ssl, size) + raise ValueError('size <= 0') + return m2.ssl_read(self.ssl, size, self._timeout) def _read_nbio(self, size=1024): + # type: (int) -> bytes if size <= 0: - raise ValueError, 'size <= 0' + raise ValueError('size <= 0') return m2.ssl_read_nbio(self.ssl, size) def write(self, data): - if self.blocking: + # type: (bytes) -> int + if self._timeout != 0.0: return self._write_bio(data) return self._write_nbio(data) sendall = send = write - + + def _decref_socketios(self): + pass + + def recv_into(self, buff, nbytes=0): + # type: (Union[bytearray, memoryview], int) -> int + """ + A version of recv() that stores its data into a buffer rather + than creating a new string. Receive up to buffersize bytes from + the socket. If buffersize is not specified (or 0), receive up + to the size available in the given buffer. + + If buff is bytearray, it will have after return length of the + actually returned number of bytes. If buff is memoryview, then + the size of buff won't change (it cannot), but all bytes after + the number of returned bytes will be NULL. + + :param buffer: a buffer for the received bytes + :param nbytes: maximum number of bytes to read + :return: number of bytes read + + See recv() for documentation about the flags. + """ + n = len(buff) if nbytes == 0 else nbytes + + if n <= 0: + raise ValueError('size <= 0') + + # buff_bytes are actual bytes returned + buff_bytes = m2.ssl_read(self.ssl, n, self._timeout) + buflen = len(buff_bytes) + + # memoryview type has been added in 2.7 + if py27plus and isinstance(buff, memoryview): + buff[:buflen] = buff_bytes + buff[buflen:] = b'\x00' * (len(buff) - buflen) + else: + buff[:] = buff_bytes + + return buflen + def read(self, size=1024): - if self.blocking: + # type: (int) -> bytes + if self._timeout != 0.0: return self._read_bio(size) return self._read_nbio(size) recv = read def setblocking(self, mode): - """Set this connection's underlying socket to _mode_.""" + # type: (int) -> None + """Set this connection's underlying socket to _mode_. + + Set blocking or non-blocking mode of the socket: if flag is 0, + the socket is set to non-blocking, else to blocking mode. + Initially all sockets are in blocking mode. In non-blocking mode, + if a recv() call doesn't find any data, or if a send() call can't + immediately dispose of the data, a error exception is raised; + in blocking mode, the calls block until they can proceed. + s.setblocking(0) is equivalent to s.settimeout(0.0); + s.setblocking(1) is equivalent to s.settimeout(None). + + :param mode: new mode to be set + """ self.socket.setblocking(mode) - self.blocking = mode + if mode: + self._timeout = -1.0 + else: + self._timeout = 0.0 + + def settimeout(self, timeout): + # type: (float) -> None + """Set this connection's underlying socket's timeout to _timeout_.""" + self.socket.settimeout(timeout) + self._timeout = timeout + if self._timeout is None: + self._timeout = -1.0 def fileno(self): + # type: () -> int return self.socket.fileno() - def getsockopt(self, *args): - return apply(self.socket.getsockopt, args) + def getsockopt(self, level, optname, buflen=None): + # type: (int, int, Optional[int]) -> Union[int, bytes] + """Get the value of the given socket option. + + :param level: level at which the option resides. + To manipulate options at the sockets API level, level is + specified as socket.SOL_SOCKET. To manipulate options at + any other level the protocol number of the appropriate + protocol controlling the option is supplied. For example, + to indicate that an option is to be interpreted by the + TCP protocol, level should be set to the protocol number + of socket.SOL_TCP; see getprotoent(3). + + :param optname: The value of the given socket option is + described in the Unix man page getsockopt(2)). The needed + symbolic constants (SO_* etc.) are defined in the socket + module. + + :param buflen: If it is absent, an integer option is assumed + and its integer value is returned by the function. If + buflen is present, it specifies the maximum length of the + buffer used to receive the option in, and this buffer is + returned as a bytes object. + + :return: Either integer or bytes value of the option. It is up + to the caller to decode the contents of the buffer (see + the optional built-in module struct for a way to decode + C structures encoded as byte strings). + """ + return self.socket.getsockopt(level, optname, buflen) - def setsockopt(self, *args): - return apply(self.socket.setsockopt, args) + def setsockopt(self, level, optname, value=None): + # type: (int, int, Union[int, bytes, None]) -> Optional[bytes] + """Set the value of the given socket option. + + :param level: same as with getsockopt() above + + :param optname: same as with getsockopt() above + + :param value: an integer or a string representing a buffer. In + the latter case it is up to the caller to ensure + that the string contains the proper bits (see the + optional built-in module struct for a way to + encode C structures as strings). + + :return: None for success or the error handler for failure. + """ + return self.socket.setsockopt(level, optname, value) def get_context(self): - """Return the SSL.Context object associated with this - connection.""" + # type: () -> Context + """Return the Context object associated with this connection.""" return m2.ssl_get_ssl_ctx(self.ssl) def get_state(self): - """Return the SSL state of this connection.""" + # type: () -> bytes + """Return the SSL state of this connection. + + During its use, an SSL objects passes several states. The state + is internally maintained. Querying the state information is not + very informative before or when a connection has been + established. It however can be of significant interest during + the handshake. + + :return: 6 letter string indicating the current state of the SSL + object ssl. + """ return m2.ssl_get_state(self.ssl) def verify_ok(self): + # type: () -> bool return (m2.ssl_get_verify_result(self.ssl) == m2.X509_V_OK) def get_verify_mode(self): + # type: () -> int """Return the peer certificate verification mode.""" return m2.ssl_get_verify_mode(self.ssl) def get_verify_depth(self): + # type: () -> int """Return the peer certificate verification depth.""" return m2.ssl_get_verify_depth(self.ssl) def get_verify_result(self): + # type: () -> int """Return the peer certificate verification result.""" return m2.ssl_get_verify_result(self.ssl) def get_peer_cert(self): - """Return the peer certificate; if the peer did not provide - a certificate, return None.""" - c=m2.ssl_get_peer_cert(self.ssl) + # type: () -> X509.X509 + """Return the peer certificate. + + If the peer did not provide a certificate, return None. + """ + c = m2.ssl_get_peer_cert(self.ssl) if c is None: return None # Need to free the pointer coz OpenSSL doesn't. return X509.X509(c, 1) - + def get_peer_cert_chain(self): - """Return the peer certificate chain; if the peer did not provide + # type: () -> Optional[X509.X509_Stack] + """Return the peer certificate chain; if the peer did not provide a certificate chain, return None. - - @warning: The returned chain will be valid only for as long as the - connection object is alive. Once the connection object gets freed, - the chain will be freed as well. + + :warning: The returned chain will be valid only for as long as the + connection object is alive. Once the connection object + gets freed, the chain will be freed as well. """ - c=m2.ssl_get_peer_cert_chain(self.ssl) + c = m2.ssl_get_peer_cert_chain(self.ssl) if c is None: return None # No need to free the pointer coz OpenSSL does. return X509.X509_Stack(c) - + def get_cipher(self): - """Return an M2Crypto.SSL.Cipher object for this connection; if the - connection has not been initialised with a cipher suite, return None.""" - c=m2.ssl_get_current_cipher(self.ssl) + # type: () -> Optional[Cipher] + """Return an M2Crypto.SSL.Cipher object for this connection; if the + connection has not been initialised with a cipher suite, return None. + """ + c = m2.ssl_get_current_cipher(self.ssl) if c is None: return None return Cipher(c) - + def get_ciphers(self): - """Return an M2Crypto.SSL.Cipher_Stack object for this connection; if the - connection has not been initialised with cipher suites, return None.""" - c=m2.ssl_get_ciphers(self.ssl) + # type: () -> Optional[Cipher_Stack] + """Return an M2Crypto.SSL.Cipher_Stack object for this + connection; if the connection has not been initialised with + cipher suites, return None. + """ + c = m2.ssl_get_ciphers(self.ssl) if c is None: return None return Cipher_Stack(c) def get_cipher_list(self, idx=0): + # type: (int) -> str """Return the cipher suites for this connection as a string object.""" - return m2.ssl_get_cipher_list(self.ssl, idx) + return six.ensure_text(m2.ssl_get_cipher_list(self.ssl, idx)) def set_cipher_list(self, cipher_list): + # type: (str) -> int """Set the cipher suites for this connection.""" return m2.ssl_set_cipher_list(self.ssl, cipher_list) - def makefile(self, mode='rb', bufsize='ignored'): - r = 'r' in mode or '+' in mode - w = 'w' in mode or 'a' in mode or '+' in mode - b = 'b' in mode - m2mode = ['', 'r'][r] + ['', 'w'][w] + ['', 'b'][b] - # XXX Need to dup(). - bio = BIO.BIO(self.sslbio, _close_cb=self.close) - m2.bio_do_handshake(bio._ptr()) - return BIO.IOBuffer(bio, m2mode, _pyfree=0) + def makefile(self, mode='rb', bufsize=-1): + # type: (AnyStr, int) -> socket._fileobject + if six.PY3: + return socket.SocketIO(self, mode) + else: + return socket._fileobject(self, mode, bufsize) def getsockname(self): + # type: () -> util.AddrType + """Return the socket's own address. + + This is useful to find out the port number of an IPv4/v6 socket, + for instance. (The format of the address returned depends + on the address family -- see above.) + + :return:socket's address as addr type + """ return self.socket.getsockname() def getpeername(self): + # type: () -> util.AddrType + """Return the remote address to which the socket is connected. + + This is useful to find out the port number of a remote IPv4/v6 socket, + for instance. + On some systems this function is not supported. + + :return: + """ return self.socket.getpeername() def set_session_id_ctx(self, id): + # type: (bytes) -> int ret = m2.ssl_set_session_id_context(self.ssl, id) if not ret: - raise SSLError(m2.err_reason_error_string(m2.err_get_error())) + raise SSLError(Err.get_error_message()) def get_session(self): + # type: () -> Session sess = m2.ssl_get_session(self.ssl) return Session(sess) def set_session(self, session): + # type: (Session) -> None m2.ssl_set_session(self.ssl, session._ptr()) def get_default_session_timeout(self): + # type: () -> int return m2.ssl_get_default_session_timeout(self.ssl) def get_socket_read_timeout(self): - return timeout.struct_to_timeout(self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeout.struct_size())) + # type: () -> timeout + return timeout.struct_to_timeout( + self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, + timeout.struct_size())) + + @staticmethod + def _hexdump(s): + assert isinstance(s, six.binary_type) + return ":".join("{0:02x}".format(ord(c) if six.PY2 else c) for c in s) def get_socket_write_timeout(self): - return timeout.struct_to_timeout(self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_SNDTIMEO, timeout.struct_size())) + # type: () -> timeout + binstr = self.socket.getsockopt( + socket.SOL_SOCKET, socket.SO_SNDTIMEO, timeout.struct_size()) + timeo = timeout.struct_to_timeout(binstr) + #print("Debug: get_socket_write_timeout: " + # "get sockopt value: %s -> returned timeout(sec=%r, microsec=%r)" % + # (self._hexdump(binstr), timeo.sec, timeo.microsec)) + return timeo def set_socket_read_timeout(self, timeo): + # type: (timeout) -> None assert isinstance(timeo, timeout.timeout) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeo.pack()) + self.socket.setsockopt( + socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeo.pack()) def set_socket_write_timeout(self, timeo): + # type: (timeout) -> None assert isinstance(timeo, timeout.timeout) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_SNDTIMEO, timeo.pack()) + binstr = timeo.pack() + #print("Debug: set_socket_write_timeout: " + # "input timeout(sec=%r, microsec=%r) -> set sockopt value: %s" % + # (timeo.sec, timeo.microsec, self._hexdump(binstr))) + self.socket.setsockopt( + socket.SOL_SOCKET, socket.SO_SNDTIMEO, binstr) def get_version(self): - "Return the TLS/SSL protocol version for this connection." - return m2.ssl_get_version(self.ssl) + # type: () -> str + """Return the TLS/SSL protocol version for this connection.""" + return six.ensure_text(m2.ssl_get_version(self.ssl)) - def set_post_connection_check_callback(self, postConnectionCheck): + def set_post_connection_check_callback(self, postConnectionCheck): # noqa + # type: (Callable) -> None self.postConnectionCheck = postConnectionCheck + + def set_tlsext_host_name(self, name): + # type: (bytes) -> None + """Set the requested hostname for the SNI (Server Name Indication) + extension. + """ + m2.ssl_set_tlsext_host_name(self.ssl, name) + + def set1_host(self, name): + # type: (bytes) -> None + """Set the requested hostname to check in the server certificate.""" + self.host = name diff --git a/M2Crypto/SSL/Context.py b/M2Crypto/SSL/Context.py index b8d159f..7faccf0 100644 --- a/M2Crypto/SSL/Context.py +++ b/M2Crypto/SSL/Context.py @@ -1,114 +1,135 @@ +from __future__ import absolute_import + """SSL Context Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" -__all__ = ['map', 'Context'] - +from M2Crypto import BIO, Err, RSA, X509, m2, util # noqa +from M2Crypto.SSL import cb # noqa +from M2Crypto.SSL.Session import Session # noqa from weakref import WeakValueDictionary +if util.py27plus: + from typing import Any, AnyStr, Callable, Optional, Union # noqa + +__all__ = ['ctxmap', 'Context', 'map'] -# M2Crypto -import cb -from M2Crypto import util, BIO, Err, RSA, m2, X509 -class _ctxmap: - singleton = None +class _ctxmap(object): + singleton = None # type: Optional[_ctxmap] + def __init__(self): - self.map = WeakValueDictionary() + # type: () -> None + """Simple WeakReffed list. + """ + self._ctxmap = WeakValueDictionary() def __getitem__(self, key): - return self.map[key] + # type: (int) -> Any + return self._ctxmap[key] def __setitem__(self, key, value): - self.map[key] = value + # type: (int, Any) -> None + self._ctxmap[key] = value def __delitem__(self, key): - del self.map[key] + # type: (int) -> None + del self._ctxmap[key] -def map(): + +def ctxmap(): + # type: () -> _ctxmap if _ctxmap.singleton is None: _ctxmap.singleton = _ctxmap() return _ctxmap.singleton +# deprecated!!! +map = ctxmap -class Context: +class Context(object): """'Context' for SSL connections.""" m2_ssl_ctx_free = m2.ssl_ctx_free - def __init__(self, protocol='sslv23', weak_crypto=None): + def __init__(self, protocol='tls', weak_crypto=None, + post_connection_check=None): + # type: (str, Optional[int], Optional[Callable]) -> None proto = getattr(m2, protocol + '_method', None) if proto is None: - raise ValueError, "no such protocol '%s'" % protocol + # default is 'sslv23' for older versions of OpenSSL + if protocol == 'tls': + proto = getattr(m2, 'sslv23_method') + else: + raise ValueError("no such protocol '%s'" % protocol) self.ctx = m2.ssl_ctx_new(proto()) - self.allow_unknown_ca = 0 - map()[long(self.ctx)] = self - m2.ssl_ctx_set_cache_size(self.ctx, 128L) - if weak_crypto is None: - if protocol == 'sslv23': - self.set_options(m2.SSL_OP_ALL | m2.SSL_OP_NO_SSLv2) - self.set_cipher_list('ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH') - + self.allow_unknown_ca = 0 # type: Union[int, bool] + self.post_connection_check = post_connection_check + ctxmap()[int(self.ctx)] = self + m2.ssl_ctx_set_cache_size(self.ctx, 128) + if weak_crypto is None and protocol in ('sslv23', 'tls'): + self.set_options(m2.SSL_OP_ALL | m2.SSL_OP_NO_SSLv2 | + m2.SSL_OP_NO_SSLv3) + def __del__(self): + # type: () -> None if getattr(self, 'ctx', None): self.m2_ssl_ctx_free(self.ctx) def close(self): - del map()[long(self.ctx)] - - def load_cert(self, certfile, keyfile=None, callback=util.passphrase_callback): + # type: () -> None + del ctxmap()[int(self.ctx)] + + def load_cert(self, certfile, keyfile=None, + callback=util.passphrase_callback): + # type: (AnyStr, Optional[AnyStr], Callable) -> None """Load certificate and private key into the context. - - @param certfile: File that contains the PEM-encoded certificate. - @type certfile: str - @param keyfile: File that contains the PEM-encoded private key. + + :param certfile: File that contains the PEM-encoded certificate. + :param keyfile: File that contains the PEM-encoded private key. Default value of None indicates that the private key is to be found in 'certfile'. - @type keyfile: str - - @param callback: Callable object to be invoked if the private key is + :param callback: Callable object to be invoked if the private key is passphrase-protected. Default callback provides a simple terminal-style input for the passphrase. """ m2.ssl_ctx_passphrase_callback(self.ctx, callback) m2.ssl_ctx_use_cert(self.ctx, certfile) - if not keyfile: + if not keyfile: keyfile = certfile m2.ssl_ctx_use_privkey(self.ctx, keyfile) if not m2.ssl_ctx_check_privkey(self.ctx): - raise ValueError, 'public/private key mismatch' + raise ValueError('public/private key mismatch') - def load_cert_chain(self, certchainfile, keyfile=None, callback=util.passphrase_callback): + def load_cert_chain(self, certchainfile, keyfile=None, + callback=util.passphrase_callback): + # type: (AnyStr, Optional[AnyStr], Callable) -> None """Load certificate chain and private key into the context. - - @param certchainfile: File object containing the PEM-encoded + + :param certchainfile: File object containing the PEM-encoded certificate chain. - @type certchainfile: str - @param keyfile: File object containing the PEM-encoded private + :param keyfile: File object containing the PEM-encoded private key. Default value of None indicates that the private key is to be found in 'certchainfile'. - @type keyfile: str - - @param callback: Callable object to be invoked if the private key - is passphrase-protected. Default callback + :param callback: Callable object to be invoked if the private key + is passphrase-protected. Default callback provides a simple terminal-style input for the passphrase. """ m2.ssl_ctx_passphrase_callback(self.ctx, callback) m2.ssl_ctx_use_cert_chain(self.ctx, certchainfile) - if not keyfile: + if not keyfile: keyfile = certchainfile m2.ssl_ctx_use_privkey(self.ctx, keyfile) if not m2.ssl_ctx_check_privkey(self.ctx): - raise ValueError, 'public/private key mismatch' + raise ValueError('public/private key mismatch') def set_client_CA_list_from_file(self, cafile): + # type: (AnyStr) -> None """Load CA certs into the context. These CA certs are sent to the peer during *SSLv3 certificate request*. - - @param cafile: File object containing one or more PEM-encoded CA + + :param cafile: File object containing one or more PEM-encoded CA certificates concatenated together. - @type cafile: str """ m2.ssl_ctx_set_client_CA_list_from_file(self.ctx, cafile) @@ -116,15 +137,23 @@ class Context: load_client_CA = load_client_ca = set_client_CA_list_from_file def load_verify_locations(self, cafile=None, capath=None): - """Load CA certs into the context. These CA certs are used during - verification of the peer's certificate. + # type: (Optional[AnyStr], Optional[AnyStr]) -> int + """Load CA certs into the context. + + These CA certs are used during verification of the peer's + certificate. - @param cafile: File containing one or more PEM-encoded CA certificates - concatenated together. - @type cafile: str - @param capath: Directory containing PEM-encoded CA certificates + :param cafile: File containing one or more PEM-encoded CA + certificates concatenated together. + + :param capath: Directory containing PEM-encoded CA certificates (one certificate per file). - @type capath: str + + :return: 0 if the operation failed because CAfile and CApath are NULL + or the processing at one of the locations specified failed. + Check the error stack to find out the reason. + + 1 The operation succeeded. """ if cafile is None and capath is None: raise ValueError("cafile and capath can not both be None.") @@ -134,38 +163,79 @@ class Context: load_verify_info = load_verify_locations def set_session_id_ctx(self, id): + # type: (bytes) -> None + """Sets the session id for the SSL.Context w/in a session can be reused. + + :param id: Sessions are generated within a certain context. When + exporting/importing sessions with + i2d_SSL_SESSION/d2i_SSL_SESSION it would be possible, + to re-import a session generated from another context + (e.g. another application), which might lead to + malfunctions. Therefore each application must set its + own session id context sid_ctx which is used to + distinguish the contexts and is stored in exported + sessions. The sid_ctx can be any kind of binary data + with a given length, it is therefore possible to use + e.g. the name of the application and/or the hostname + and/or service name. + """ ret = m2.ssl_ctx_set_session_id_context(self.ctx, id) if not ret: raise Err.SSLError(Err.get_error_code(), '') - def set_allow_unknown_ca(self, ok): - """Set the context to accept/reject a peer certificate if the + def set_default_verify_paths(self): + # type: () -> int + """ + Specifies that the default locations from which CA certs are + loaded should be used. + + There is one default directory and one default file. The default + CA certificates directory is called "certs" in the default + OpenSSL directory. Alternatively the SSL_CERT_DIR environment + variable can be defined to override this location. The default + CA certificates file is called "cert.pem" in the default OpenSSL + directory. Alternatively the SSL_CERT_FILE environment variable + can be defined to override this location. + + @return 0 if the operation failed. A missing default location is + still treated as a success. No error code is set. + + 1 The operation succeeded. + """ + ret = m2.ssl_ctx_set_default_verify_paths(self.ctx) + if not ret: + raise ValueError('Cannot use default SSL certificate store!') + + def set_allow_unknown_ca(self, ok): + # type: (Union[int, bool]) -> None + """Set the context to accept/reject a peer certificate if the certificate's CA is unknown. - @param ok: True to accept, False to reject. - @type ok: boolean + :param ok: True to accept, False to reject. """ self.allow_unknown_ca = ok def get_allow_unknown_ca(self): + # type: () -> Union[int, bool] """Get the context's setting that accepts/rejects a peer certificate if the certificate's CA is unknown. + + FIXME 2Bconverted to bool """ return self.allow_unknown_ca def set_verify(self, mode, depth, callback=None): + # type: (int, int, Optional[Callable]) -> None """ Set verify options. Most applications will need to call this method with the right options to make a secure SSL connection. - - @param mode: The verification mode to use. Typically at least + + :param mode: The verification mode to use. Typically at least SSL.verify_peer is used. Clients would also typically add SSL.verify_fail_if_no_peer_cert. - @type mode: int - @param depth: The maximum allowed depth of the certificate chain + :param depth: The maximum allowed depth of the certificate chain returned by the peer. - @type depth: int - @param callback: Callable that can be used to specify custom + :param callback: Callable that can be used to specify custom verification checks. """ if callback is None: @@ -175,80 +245,202 @@ class Context: m2.ssl_ctx_set_verify_depth(self.ctx, depth) def get_verify_mode(self): + # type: () -> int return m2.ssl_ctx_get_verify_mode(self.ctx) def get_verify_depth(self): + # type: () -> int + """Returns the verification mode currently set in the SSL Context.""" return m2.ssl_ctx_get_verify_depth(self.ctx) def set_tmp_dh(self, dhpfile): + # type: (AnyStr) -> int """Load ephemeral DH parameters into the context. - @param dhpfile: File object containing the PEM-encoded DH - parameters. - @type dhpfile: str + :param dhpfile: Filename of the file containing the PEM-encoded + DH parameters. """ f = BIO.openfile(dhpfile) dhp = m2.dh_read_parameters(f.bio_ptr()) return m2.ssl_ctx_set_tmp_dh(self.ctx, dhp) def set_tmp_dh_callback(self, callback=None): + # type: (Optional[Callable]) -> None + """Sets the callback function for SSL.Context. + + :param callback: Callable to be used when a DH parameters are required. + """ if callback is not None: - m2.ssl_ctx_set_tmp_dh_callback(self.ctx, callback) + m2.ssl_ctx_set_tmp_dh_callback(self.ctx, callback) def set_tmp_rsa(self, rsa): + # type: (RSA.RSA) -> int """Load ephemeral RSA key into the context. - @param rsa: M2Crypto.RSA.RSA instance. + :param rsa: RSA.RSA instance. """ if isinstance(rsa, RSA.RSA): return m2.ssl_ctx_set_tmp_rsa(self.ctx, rsa.rsa) else: - raise TypeError, "Expected an instance of RSA.RSA, got %s." % (rsa,) + raise TypeError("Expected an instance of RSA.RSA, got %s." % rsa) def set_tmp_rsa_callback(self, callback=None): + # type: (Optional[Callable]) -> None + """Sets the callback function to be used when + a temporary/ephemeral RSA key is required. + """ if callback is not None: - m2.ssl_ctx_set_tmp_rsa_callback(self.ctx, callback) + m2.ssl_ctx_set_tmp_rsa_callback(self.ctx, callback) def set_info_callback(self, callback=cb.ssl_info_callback): + # type: (Callable) -> None + """Set a callback function to get state information. + + It can be used to get state information about the SSL + connections that are created from this context. + + :param callback: Callback function. The default prints + information to stderr. """ - Set a callback function that can be used to get state information - about the SSL connections that are created from this context. - - @param callback: Callback function. The default prints information to - stderr. - """ - m2.ssl_ctx_set_info_callback(self.ctx, callback) + m2.ssl_ctx_set_info_callback(self.ctx, callback) def set_cipher_list(self, cipher_list): + # type: (str) -> int + """Sets the list of available ciphers. + + :param cipher_list: The format of the string is described in + ciphers(1). + :return: 1 if any cipher could be selected and 0 on complete + failure. + """ return m2.ssl_ctx_set_cipher_list(self.ctx, cipher_list) def add_session(self, session): + # type: (Session) -> int + """Add the session to the context. + + :param session: the session to be added. + + :return: 0 The operation failed. It was tried to add the same + (identical) session twice. + + 1 The operation succeeded. + """ return m2.ssl_ctx_add_session(self.ctx, session._ptr()) def remove_session(self, session): + # type: (Session) -> int + """Remove the session from the context. + + :param session: the session to be removed. + + :return: 0 The operation failed. The session was not found in + the cache. + + 1 The operation succeeded. + """ return m2.ssl_ctx_remove_session(self.ctx, session._ptr()) def get_session_timeout(self): + # type: () -> int + """Get current session timeout. + + Whenever a new session is created, it is assigned a maximum + lifetime. This lifetime is specified by storing the creation + time of the session and the timeout value valid at this time. If + the actual time is later than creation time plus timeout, the + session is not reused. + + Due to this realization, all sessions behave according to the + timeout value valid at the time of the session negotiation. + Changes of the timeout value do not affect already established + sessions. + + Expired sessions are removed from the internal session cache, + whenever SSL_CTX_flush_sessions(3) is called, either directly by + the application or automatically (see + SSL_CTX_set_session_cache_mode(3)) + + The default value for session timeout is decided on a per + protocol basis, see SSL_get_default_timeout(3). All currently + supported protocols have the same default timeout value of 300 + seconds. + + SSL_CTX_set_timeout() returns the previously set timeout value. + + :return: the currently set timeout value. + """ return m2.ssl_ctx_get_session_timeout(self.ctx) def set_session_timeout(self, timeout): + # type: (int) -> int + """Set new session timeout. + + See self.get_session_timeout() for explanation of the session + timeouts. + + :param timeout: new timeout value. + + :return: the previously set timeout value. + """ return m2.ssl_ctx_set_session_timeout(self.ctx, timeout) def set_session_cache_mode(self, mode): + # type: (int) -> int + """Enables/disables session caching. + + The mode is set by using m2.SSL_SESS_CACHE_* constants. + + :param mode: new mode value. + + :return: the previously set cache mode value. + """ return m2.ssl_ctx_set_session_cache_mode(self.ctx, mode) def get_session_cache_mode(self): + # type: () -> int + """Gets the current session caching. + + The mode is set to m2.SSL_SESS_CACHE_* constants. + + :return: the previously set cache mode value. + """ return m2.ssl_ctx_get_session_cache_mode(self.ctx) def set_options(self, op): + # type: (int) -> int + """Adds the options set via bitmask in options to the Context. + + !!! Options already set before are not cleared! + + The behaviour of the SSL library can be changed by setting + several options. The options are coded as bitmasks and can be + combined by a logical or operation (|). + + SSL.Context.set_options() and SSL.set_options() affect the + (external) protocol behaviour of the SSL library. The (internal) + behaviour of the API can be changed by using the similar + SSL.Context.set_mode() and SSL.set_mode() functions. + + During a handshake, the option settings of the SSL object are + used. When a new SSL object is created from a context using + SSL(), the current option setting is copied. Changes to ctx + do not affect already created SSL objects. SSL.clear() does not + affect the settings. + + :param op: bitmask of additional options specified in + SSL_CTX_set_options(3) manpage. + + :return: the new options bitmask after adding options. + """ return m2.ssl_ctx_set_options(self.ctx, op) def get_cert_store(self): + # type: () -> X509.X509 """ Get the certificate store associated with this context. - - @warning: The store is NOT refcounted, and as such can not be relied - to be valid once the context goes away or is changed. + + :warning: The store is NOT refcounted, and as such can not be relied + to be valid once the context goes away or is changed. """ return X509.X509_Store(m2.ssl_ctx_get_cert_store(self.ctx)) - diff --git a/M2Crypto/SSL/SSLServer.py b/M2Crypto/SSL/SSLServer.py index d894d3b..886019e 100644 --- a/M2Crypto/SSL/SSLServer.py +++ b/M2Crypto/SSL/SSLServer.py @@ -1,32 +1,45 @@ +from __future__ import absolute_import, print_function + """SSLServer Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" -__all__ = ['SSLServer', 'ForkingSSLServer', 'ThreadingSSLServer'] - -# Python -import socket, SocketServer # M2Crypto -from Connection import Connection from M2Crypto.SSL import SSLError -from M2Crypto import m2 +from M2Crypto.SSL.Connection import Connection +from M2Crypto.SSL.Context import Context # noqa +from M2Crypto import six # noqa +from M2Crypto import util # noqa +from M2Crypto.six.moves.socketserver import (BaseServer, TCPServer, + ThreadingMixIn) +import os +if os.name != 'nt': + from M2Crypto.six.moves.socketserver import ForkingMixIn +from socket import socket # noqa +if util.py27plus: + from typing import Union # noqa + +__all__ = ['SSLServer', 'ForkingSSLServer', 'ThreadingSSLServer'] -class SSLServer(SocketServer.TCPServer): - def __init__(self, server_address, RequestHandlerClass, ssl_context, bind_and_activate=True): - """ +class SSLServer(TCPServer): + def __init__(self, server_address, RequestHandlerClass, ssl_context, # noqa + bind_and_activate=True): + # type: (util.AddrType, socketserver.BaseRequestHandler, Context, bool) -> None + """ Superclass says: Constructor. May be extended, do not override. This class says: Ho-hum. """ - SocketServer.BaseServer.__init__(self, server_address, RequestHandlerClass) - self.ssl_ctx=ssl_context - self.socket=Connection(self.ssl_ctx) + BaseServer.__init__(self, server_address, RequestHandlerClass) + self.ssl_ctx = ssl_context + self.socket = Connection(self.ssl_ctx) if bind_and_activate: self.server_bind() - self.server_activate() + self.server_activate() def handle_request(self): + # type: () -> None request = None client_address = None try: @@ -37,17 +50,17 @@ class SSLServer(SocketServer.TCPServer): self.handle_error(request, client_address) def handle_error(self, request, client_address): - print '-'*40 + # type: (Union[socket, Connection], util.AddrType) -> None + print('-' * 40) import traceback traceback.print_exc() - print '-'*40 - - -class ForkingSSLServer(SocketServer.ForkingMixIn, SSLServer): - pass + print('-' * 40) -class ThreadingSSLServer(SocketServer.ThreadingMixIn, SSLServer): +class ThreadingSSLServer(ThreadingMixIn, SSLServer): pass +if os.name != 'nt': + class ForkingSSLServer(ForkingMixIn, SSLServer): + pass diff --git a/M2Crypto/SSL/Session.py b/M2Crypto/SSL/Session.py index 1edf5b0..8c4e8f4 100644 --- a/M2Crypto/SSL/Session.py +++ b/M2Crypto/SSL/Session.py @@ -4,55 +4,67 @@ Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" __all__ = ['Session', 'load_session'] -from M2Crypto import BIO, Err, m2 +from M2Crypto import BIO, Err, m2, util +from M2Crypto.SSL import SSLError +if util.py27plus: + from typing import AnyStr # noqa -class Session: + +class Session(object): m2_ssl_session_free = m2.ssl_session_free def __init__(self, session, _pyfree=0): + # type: (bytes, int) -> None assert session is not None self.session = session self._pyfree = _pyfree - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_ssl_session_free(self.session) def _ptr(self): + # type: () -> bytes return self.session def as_text(self): + # type: () -> bytes buf = BIO.MemoryBuffer() m2.ssl_session_print(buf.bio_ptr(), self.session) return buf.read_all() def as_der(self): + # type: () -> bytes buf = BIO.MemoryBuffer() m2.i2d_ssl_session(buf.bio_ptr(), self.session) return buf.read_all() def write_bio(self, bio): + # type: (BIO.BIO) -> int return m2.ssl_session_write_bio(bio.bio_ptr(), self.session) def get_time(self): + # type: () -> int return m2.ssl_session_get_time(self.session) def set_time(self, t): + # type: (int) -> int return m2.ssl_session_set_time(self.session, t) def get_timeout(self): + # type: () -> int return m2.ssl_session_get_timeout(self.session) def set_timeout(self, t): + # type: (int) -> int return m2.ssl_session_set_timeout(self.session, t) def load_session(pemfile): - f = BIO.openfile(pemfile) - cptr = m2.ssl_session_read_pem(f.bio_ptr()) - f.close() - if cptr is None: - from M2Crypto.SSL import SSLError - raise SSLError(Err.get_error()) + # type: (AnyStr) -> Session + with BIO.openfile(pemfile) as f: + cptr = m2.ssl_session_read_pem(f.bio_ptr()) + return Session(cptr, 1) diff --git a/M2Crypto/SSL/TwistedProtocolWrapper.py b/M2Crypto/SSL/TwistedProtocolWrapper.py index 930dd32..f9f7ccd 100644 --- a/M2Crypto/SSL/TwistedProtocolWrapper.py +++ b/M2Crypto/SSL/TwistedProtocolWrapper.py @@ -3,20 +3,32 @@ Make Twisted use M2Crypto for SSL Copyright (c) 2004-2007 Open Source Applications Foundation. All rights reserved. + +FIXME THIS HAS NOT BEEN FINISHED. NEITHER PEP484 NOR PORT PYTHON3 HAS +BEEN FINISHED. THE FURTHER WORK WILL BE DONE WHEN THE STATUS OF TWISTED +IN THE PYTHON 3 (AND ASYNCIO) WORLD WILL BE CLEAR. """ __all__ = ['connectSSL', 'connectTCP', 'listenSSL', 'listenTCP', 'TLSProtocolWrapper'] -import twisted.protocols.policies as policies +import logging + +from functools import partial + import twisted.internet.reactor -from twisted.protocols.policies import ProtocolWrapper +import twisted.protocols.policies as policies + +from M2Crypto import BIO, X509, m2, util +from M2Crypto.SSL.Checker import Checker, SSLVerificationError + from twisted.internet.interfaces import ITLSTransport -from zope.interface import implements +from twisted.protocols.policies import ProtocolWrapper +if util.py27plus: + from typing import AnyStr, Callable, Iterable, Optional # noqa + from zope.interface import implementer -import M2Crypto # for M2Crypto.BIO.BIOError -from M2Crypto import m2, X509 -from M2Crypto.SSL import Checker +log = logging.getLogger(__name__) def _alwaysSucceedsPostConnectionCheck(peerX509, expectedHost): @@ -26,11 +38,12 @@ def _alwaysSucceedsPostConnectionCheck(peerX509, expectedHost): def connectSSL(host, port, factory, contextFactory, timeout=30, bindAddress=None, reactor=twisted.internet.reactor, - postConnectionCheck=Checker.Checker()): + postConnectionCheck=Checker()): + # type: (str, int, object, object, int, Optional[str], twisted.internet.reactor, Checker) -> reactor.connectTCP """ A convenience function to start an SSL/TLS connection using Twisted. - - See IReactorSSL interface in Twisted. + + See IReactorSSL interface in Twisted. """ wrappingFactory = policies.WrappingFactory(factory) wrappingFactory.protocol = lambda factory, wrappedProtocol: \ @@ -41,17 +54,18 @@ def connectSSL(host, port, factory, contextFactory, timeout=30, contextFactory=contextFactory, postConnectionCheck=postConnectionCheck) return reactor.connectTCP(host, port, wrappingFactory, timeout, bindAddress) - + def connectTCP(host, port, factory, timeout=30, bindAddress=None, reactor=twisted.internet.reactor, - postConnectionCheck=Checker.Checker()): + postConnectionCheck=Checker()): + # type: (str, int, object, int, Optional[util.AddrType], object, Callable) -> object """ - A convenience function to start a TCP connection using Twisted. + A convenience function to start a TCP connection using Twisted. NOTE: You must call startTLS(ctx) to go into SSL/TLS mode. - See IReactorTCP interface in Twisted. + See IReactorTCP interface in Twisted. """ wrappingFactory = policies.WrappingFactory(factory) wrappingFactory.protocol = lambda factory, wrappedProtocol: \ @@ -65,12 +79,12 @@ def connectTCP(host, port, factory, timeout=30, bindAddress=None, def listenSSL(port, factory, contextFactory, backlog=5, interface='', - reactor=twisted.internet.reactor, + reactor=twisted.internet.reactor, postConnectionCheck=_alwaysSucceedsPostConnectionCheck): """ - A convenience function to listen for SSL/TLS connections using Twisted. + A convenience function to listen for SSL/TLS connections using Twisted. - See IReactorSSL interface in Twisted. + See IReactorSSL interface in Twisted. """ wrappingFactory = policies.WrappingFactory(factory) wrappingFactory.protocol = lambda factory, wrappedProtocol: \ @@ -84,14 +98,14 @@ def listenSSL(port, factory, contextFactory, backlog=5, interface='', def listenTCP(port, factory, backlog=5, interface='', - reactor=twisted.internet.reactor, + reactor=twisted.internet.reactor, postConnectionCheck=None): """ - A convenience function to listen for TCP connections using Twisted. - + A convenience function to listen for TCP connections using Twisted. + NOTE: You must call startTLS(ctx) to go into SSL/TLS mode. - See IReactorTCP interface in Twisted. + See IReactorTCP interface in Twisted. """ wrappingFactory = policies.WrappingFactory(factory) wrappingFactory.protocol = lambda factory, wrappedProtocol: \ @@ -104,90 +118,90 @@ def listenTCP(port, factory, backlog=5, interface='', return reactor.listenTCP(port, wrappingFactory, backlog, interface) -class _BioProxy: +class _BioProxy(object): """ The purpose of this class is to eliminate the __del__ method from TLSProtocolWrapper, and thus letting it be garbage collected. """ - + m2_bio_free_all = m2.bio_free_all def __init__(self, bio): self.bio = bio - + def _ptr(self): return self.bio - + def __del__(self): if self.bio is not None: self.m2_bio_free_all(self.bio) -class _SSLProxy: +class _SSLProxy(object): """ The purpose of this class is to eliminate the __del__ method from TLSProtocolWrapper, and thus letting it be garbage collected. """ - + m2_ssl_free = m2.ssl_free def __init__(self, ssl): self.ssl = ssl - + def _ptr(self): return self.ssl - + def __del__(self): if self.ssl is not None: self.m2_ssl_free(self.ssl) +@implementer(ITLSTransport) class TLSProtocolWrapper(ProtocolWrapper): """ A SSL/TLS protocol wrapper to be used with Twisted. Typically - you would not use this class directly. Use connectTCP, + you would not use this class directly. Use connectTCP, connectSSL, listenTCP, listenSSL functions defined above, which will hook in this class. """ - implements(ITLSTransport) - def __init__(self, factory, wrappedProtocol, startPassThrough, client, contextFactory, postConnectionCheck): + # type: (policies.WrappingFactory, object, int, int, object, Checker) -> None """ - @param factory: - @param wrappedProtocol: - @param startPassThrough: If true we won't encrypt at all. Need to + :param factory: + :param wrappedProtocol: + :param startPassThrough: If true we won't encrypt at all. Need to call startTLS() later to switch to SSL/TLS. - @param client: True if this should be a client protocol. - @param contextFactory: Factory that creates SSL.Context objects. + :param client: True if this should be a client protocol. + :param contextFactory: Factory that creates SSL.Context objects. The called function is getContext(). - @param postConnectionCheck: The post connection check callback that + :param postConnectionCheck: The post connection check callback that will be called just after connection has been established but before any real data has been exchanged. The first argument to this function is an X509 object, the second is the expected host name string. """ - #ProtocolWrapper.__init__(self, factory, wrappedProtocol) - #XXX: Twisted 2.0 has a new addition where the wrappingFactory is - # set as the factory of the wrappedProtocol. This is an issue - # as the wrap should be transparent. What we want is - # the factory of the wrappedProtocol to be the wrappedFactory and - # not the outer wrappingFactory. This is how it was implemented in - # Twisted 1.3 + # ProtocolWrapper.__init__(self, factory, wrappedProtocol) + # XXX: Twisted 2.0 has a new addition where the wrappingFactory is + # set as the factory of the wrappedProtocol. This is an issue + # as the wrap should be transparent. What we want is + # the factory of the wrappedProtocol to be the wrappedFactory and + # not the outer wrappingFactory. This is how it was implemented in + # Twisted 1.3 self.factory = factory self.wrappedProtocol = wrappedProtocol - + # wrappedProtocol == client/server instance # factory.wrappedFactory == client/server factory - self.data = '' # Clear text to encrypt and send - self.encrypted = '' # Encrypted data we need to decrypt and pass on - self.tlsStarted = 0 # SSL/TLS mode or pass through - self.checked = 0 # Post connection check done or not + self.data = b'' # Clear text to encrypt and send + self.encrypted = b'' # Encrypted data we need to decrypt and pass on + self.tlsStarted = 0 # SSL/TLS mode or pass through + self.checked = 0 # Post connection check done or not self.isClient = client - self.helloDone = 0 # True when hello has been sent + self.helloDone = 0 # True when hello has been sent if postConnectionCheck is None: self.postConnectionCheck = _alwaysSucceedsPostConnectionCheck else: @@ -195,7 +209,7 @@ class TLSProtocolWrapper(ProtocolWrapper): if not startPassThrough: self.startTLS(contextFactory.getContext()) - + def clear(self): """ Clear this instance, after which it is ready for reuse. @@ -205,15 +219,15 @@ class TLSProtocolWrapper(ProtocolWrapper): self.ssl = None self.internalBio = None self.networkBio = None - self.data = '' - self.encrypted = '' + self.data = b'' + self.encrypted = b'' self.tlsStarted = 0 self.checked = 0 self.isClient = 1 self.helloDone = 0 # We can reuse self.ctx and it will be deleted automatically # when this instance dies - + def startTLS(self, ctx): """ Start SSL/TLS. If this is not called, this instance just passes data @@ -223,7 +237,7 @@ class TLSProtocolWrapper(ProtocolWrapper): # expects transports to have. This will be called automatically # by Twisted in STARTTLS situations, for example with SMTP. if self.tlsStarted: - raise Exception, 'TLS already started' + raise Exception('TLS already started') self.ctx = ctx @@ -241,7 +255,7 @@ class TLSProtocolWrapper(ProtocolWrapper): m2.ssl_set_connect_state(self.ssl._ptr()) else: m2.ssl_set_accept_state(self.ssl._ptr()) - + m2.ssl_set_bio(self.ssl._ptr(), self.internalBio, self.internalBio) m2.bio_set_ssl(self.sslBio._ptr(), self.ssl._ptr(), m2.bio_noclose) @@ -255,6 +269,7 @@ class TLSProtocolWrapper(ProtocolWrapper): self.tlsStarted = 1 def write(self, data): + # type: (bytes) -> None if not self.tlsStarted: ProtocolWrapper.write(self, data) return @@ -263,18 +278,19 @@ class TLSProtocolWrapper(ProtocolWrapper): encryptedData = self._encrypt(data) ProtocolWrapper.write(self, encryptedData) self.helloDone = 1 - except M2Crypto.BIO.BIOError, e: + except BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e def writeSequence(self, data): + # type: (Iterable[bytes]) -> None if not self.tlsStarted: - ProtocolWrapper.writeSequence(self, ''.join(data)) + ProtocolWrapper.writeSequence(self, b''.join(data)) return - self.write(''.join(data)) + self.write(b''.join(data)) def loseConnection(self): # XXX Do we need to do m2.ssl_shutdown(self.ssl._ptr())? @@ -286,6 +302,7 @@ class TLSProtocolWrapper(ProtocolWrapper): self._clientHello() def dataReceived(self, data): + # type: (bytes) -> None if not self.tlsStarted: ProtocolWrapper.dataReceived(self, data) return @@ -303,15 +320,16 @@ class TLSProtocolWrapper(ProtocolWrapper): ProtocolWrapper.dataReceived(self, decryptedData) - if decryptedData == '' and encryptedData == '': + if decryptedData == b'' and encryptedData == b'': break - except M2Crypto.BIO.BIOError, e: + except BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e def connectionLost(self, reason): + # type: (AnyStr) -> None self.clear() ProtocolWrapper.connectionLost(self, reason) @@ -325,7 +343,7 @@ class TLSProtocolWrapper(ProtocolWrapper): else: host = self.transport.getPeer().host if not self.postConnectionCheck(x509, host): - raise Checker.SSLVerificationError, 'post connection check' + raise SSLVerificationError('post connection check') self.checked = 1 def _clientHello(self): @@ -335,75 +353,138 @@ class TLSProtocolWrapper(ProtocolWrapper): encryptedData = self._encrypt(clientHello=1) ProtocolWrapper.write(self, encryptedData) self.helloDone = 1 - except M2Crypto.BIO.BIOError, e: + except BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e - def _encrypt(self, data='', clientHello=0): - # XXX near mirror image of _decrypt - refactor - encryptedData = '' + # Optimizations to reduce attribute accesses + + @property + def _get_wr_guar_ssl(self): + # type: () -> Callable[[], int] + """Return max. length of data can be written to the BIO. + + Writes larger than this value will return a value from + BIO_write() less than the amount requested or if the buffer is + full request a retry. + """ + return partial(m2.bio_ctrl_get_write_guarantee, + self.sslBio._ptr()) + + @property + def _get_wr_guar_net(self): + # type: () -> Callable[[], int] + return partial(m2.bio_ctrl_get_write_guarantee, + self.networkBio._ptr()) + + @property + def _shoud_retry_ssl(self): + # type: () -> Callable[[], int] + # BIO_should_retry() is true if the call that produced this + # condition should then be retried at a later time. + return partial(m2.bio_should_retry, self.sslBio._ptr()) + + @property + def _shoud_retry_net(self): + # type: () -> Callable[[], int] + return partial(m2.bio_should_retry, self.networkBio._ptr()) + + @property + def _ctrl_pend_ssl(self): + # type: () -> Callable[[], int] + # size_t BIO_ctrl_pending(BIO *b); + # BIO_ctrl_pending() return the number of pending characters in + # the BIOs read and write buffers. + return partial(m2.bio_ctrl_pending, self.sslBio._ptr()) + + @property + def _ctrl_pend_net(self): + # type: () -> Callable[[], int] + return partial(m2.bio_ctrl_pending, self.networkBio._ptr()) + + @property + def _write_ssl(self): + # type: () -> Callable[[bytes], int] + # All these functions return either the amount of data + # successfully read or written (if the return value is + # positive) or that no data was successfully read or written + # if the result is 0 or -1. If the return value is -2 then + # the operation is not implemented in the specific BIO type. + return partial(m2.bio_write, self.sslBio._ptr()) + + @property + def _write_net(self): + # type: () -> Callable[[bytes], int] + return partial(m2.bio_write, self.networkBio._ptr()) + + @property + def _read_ssl(self): + # type: () -> Callable[[int], Optional[bytes]] + return partial(m2.bio_read, self.sslBio._ptr()) + + @property + def _read_net(self): + # type: () -> Callable[[int], Optional[bytes]] + return partial(m2.bio_read, self.networkBio._ptr()) + + def _encrypt(self, data=b'', clientHello=0): + # type: (bytes, int) -> bytes + """ + :param data: + :param clientHello: + :return: + """ + encryptedData = b'' self.data += data - # Optimizations to reduce attribute accesses - sslBioPtr = self.sslBio._ptr() - networkBio = self.networkBio._ptr() - m2bio_ctrl_get_write_guarantee = m2.bio_ctrl_get_write_guarantee - m2bio_write = m2.bio_write - m2bio_should_retry = m2.bio_should_retry - m2bio_ctrl_pending = m2.bio_ctrl_pending - m2bio_read = m2.bio_read - + while 1: - g = m2bio_ctrl_get_write_guarantee(sslBioPtr) - if g > 0 and self.data != '' or clientHello: - r = m2bio_write(sslBioPtr, self.data) + if (self._get_wr_guar_ssl() > 0 and self.data != b'') or clientHello: + r = self._write_ssl(self.data) if r <= 0: - assert(m2bio_should_retry(sslBioPtr)) + if not self._shoud_retry_ssl(): + raise IOError( + ('Data left to be written to {}, ' + + 'but cannot retry SSL connection!').format(self.sslBio)) else: - assert(self.checked) + assert self.checked self.data = self.data[r:] - - pending = m2bio_ctrl_pending(networkBio) + + pending = self._ctrl_pend_net() if pending: - d = m2bio_read(networkBio, pending) - if d is not None: # This is strange, but d can be None + d = self._read_net(pending) + if d is not None: # This is strange, but d can be None encryptedData += d else: - assert(m2bio_should_retry(networkBio)) + assert(self._shoud_retry_net()) else: break return encryptedData - def _decrypt(self, data=''): - # XXX near mirror image of _encrypt - refactor + def _decrypt(self, data=b''): + # type: (bytes) -> bytes self.encrypted += data - decryptedData = '' - # Optimizations to reduce attribute accesses - sslBioPtr = self.sslBio._ptr() - networkBio = self.networkBio._ptr() - m2bio_ctrl_get_write_guarantee = m2.bio_ctrl_get_write_guarantee - m2bio_write = m2.bio_write - m2bio_should_retry = m2.bio_should_retry - m2bio_ctrl_pending = m2.bio_ctrl_pending - m2bio_read = m2.bio_read - + decryptedData = b'' + while 1: - g = m2bio_ctrl_get_write_guarantee(networkBio) - if g > 0 and self.encrypted != '': - r = m2bio_write(networkBio, self.encrypted) + if self._get_wr_guar_ssl() > 0 and self.encrypted != b'': + r = self._write_net(self.encrypted) if r <= 0: - assert(m2bio_should_retry(networkBio)) + if not self._shoud_retry_net(): + raise IOError( + ('Data left to be written to {}, ' + + 'but cannot retry SSL connection!').format(self.networkBio)) else: self.encrypted = self.encrypted[r:] - - pending = m2bio_ctrl_pending(sslBioPtr) + + pending = self._ctrl_pend_ssl() if pending: - d = m2bio_read(sslBioPtr, pending) - if d is not None: # This is strange, but d can be None + d = self._read_ssl(pending) + if d is not None: # This is strange, but d can be None decryptedData += d else: - assert(m2bio_should_retry(sslBioPtr)) + assert(self._shoud_retry_ssl()) else: break diff --git a/M2Crypto/SSL/__init__.py b/M2Crypto/SSL/__init__.py index a013569..b62e81c 100644 --- a/M2Crypto/SSL/__init__.py +++ b/M2Crypto/SSL/__init__.py @@ -1,28 +1,41 @@ +from __future__ import absolute_import + """M2Crypto SSL services. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" +import socket, os + # M2Crypto -from M2Crypto import m2 +from M2Crypto import _m2crypto as m2 + + +class SSLError(Exception): + pass + -class SSLError(Exception): pass -m2.ssl_init(SSLError) +class SSLTimeoutError(SSLError, socket.timeout): + pass + +m2.ssl_init(SSLError, SSLTimeoutError) # M2Crypto.SSL -from Cipher import Cipher, Cipher_Stack -from Context import Context -from Connection import Connection -from SSLServer import SSLServer, ForkingSSLServer, ThreadingSSLServer -from ssl_dispatcher import ssl_dispatcher -from timeout import timeout - -verify_none = m2.SSL_VERIFY_NONE -verify_peer = m2.SSL_VERIFY_PEER -verify_fail_if_no_peer_cert = m2.SSL_VERIFY_FAIL_IF_NO_PEER_CERT -verify_client_once = m2.SSL_VERIFY_CLIENT_ONCE - -SSL_SENT_SHUTDOWN = m2.SSL_SENT_SHUTDOWN -SSL_RECEIVED_SHUTDOWN = m2.SSL_RECEIVED_SHUTDOWN - -op_all = m2.SSL_OP_ALL -op_no_sslv2 = m2.SSL_OP_NO_SSLv2 +from M2Crypto.SSL.Cipher import Cipher, Cipher_Stack +from M2Crypto.SSL.Connection import Connection +from M2Crypto.SSL.Context import Context +from M2Crypto.SSL.SSLServer import SSLServer, ThreadingSSLServer +if os.name != 'nt': + from M2Crypto.SSL.SSLServer import ForkingSSLServer +from M2Crypto.SSL.ssl_dispatcher import ssl_dispatcher +from M2Crypto.SSL.timeout import timeout, struct_to_timeout, struct_size + +verify_none = m2.SSL_VERIFY_NONE # type: int +verify_peer = m2.SSL_VERIFY_PEER # type: int +verify_fail_if_no_peer_cert = m2.SSL_VERIFY_FAIL_IF_NO_PEER_CERT # type: int +verify_client_once = m2.SSL_VERIFY_CLIENT_ONCE # type: int + +SSL_SENT_SHUTDOWN = m2.SSL_SENT_SHUTDOWN # type: int +SSL_RECEIVED_SHUTDOWN = m2.SSL_RECEIVED_SHUTDOWN # type: int + +op_all = m2.SSL_OP_ALL # type: int +op_no_sslv2 = m2.SSL_OP_NO_SSLv2 # type: int diff --git a/M2Crypto/SSL/cb.py b/M2Crypto/SSL/cb.py index c1710cc..d10735d 100644 --- a/M2Crypto/SSL/cb.py +++ b/M2Crypto/SSL/cb.py @@ -1,16 +1,18 @@ +from __future__ import absolute_import + """SSL callbacks Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" +import sys + +from M2Crypto import m2, util +if util.py27plus: + from typing import Any, List # noqa + __all__ = ['unknown_issuer', 'ssl_verify_callback_stub', 'ssl_verify_callback', 'ssl_verify_callback_allow_unknown_ca', 'ssl_info_callback'] -# Python -import sys - -# M2Crypto -import Context -from M2Crypto import m2 def ssl_verify_callback_stub(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok): # Deprecated @@ -21,14 +23,19 @@ unknown_issuer = [ m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, m2.X509_V_ERR_CERT_UNTRUSTED, - ] +] + def ssl_verify_callback(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok): + # type: (bytes, bytes, int, int, int) -> int # Deprecated - ssl_ctx = Context.map()[long(ssl_ctx_ptr)] - if errnum in unknown_issuer: + + from M2Crypto.SSL.Context import Context + ssl_ctx = Context.ctxmap()[int(ssl_ctx_ptr)] + if errnum in unknown_issuer: if ssl_ctx.get_allow_unknown_ca(): - sys.stderr.write("policy: %s: permitted...\n" % (m2.x509_get_verify_error(errnum))) + sys.stderr.write("policy: %s: permitted...\n" % + (m2.x509_get_verify_error(errnum))) sys.stderr.flush() ok = 1 # CRL checking goes here... @@ -39,45 +46,51 @@ def ssl_verify_callback(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok): ok = 0 return ok + def ssl_verify_callback_allow_unknown_ca(ok, store): + # type: (int, Any) -> int errnum = store.get_error() if errnum in unknown_issuer: ok = 1 return ok + # Cribbed from OpenSSL's apps/s_cb.c. def ssl_info_callback(where, ret, ssl_ptr): + # type: (int, int, bytes) -> None w = where & ~m2.SSL_ST_MASK - if (w & m2.SSL_ST_CONNECT): + if w & m2.SSL_ST_CONNECT: state = "SSL connect" - elif (w & m2.SSL_ST_ACCEPT): + elif w & m2.SSL_ST_ACCEPT: state = "SSL accept" else: state = "SSL state unknown" - if (where & m2.SSL_CB_LOOP): - sys.stderr.write("LOOP: %s: %s\n" % (state, m2.ssl_get_state_v(ssl_ptr))) + if where & m2.SSL_CB_LOOP: + sys.stderr.write("LOOP: %s: %s\n" % + (state, m2.ssl_get_state_v(ssl_ptr))) sys.stderr.flush() return - if (where & m2.SSL_CB_EXIT): + if where & m2.SSL_CB_EXIT: if not ret: - sys.stderr.write("FAILED: %s: %s\n" % (state, m2.ssl_get_state_v(ssl_ptr))) + sys.stderr.write("FAILED: %s: %s\n" % + (state, m2.ssl_get_state_v(ssl_ptr))) sys.stderr.flush() else: - sys.stderr.write("INFO: %s: %s\n" % (state, m2.ssl_get_state_v(ssl_ptr))) + sys.stderr.write("INFO: %s: %s\n" % + (state, m2.ssl_get_state_v(ssl_ptr))) sys.stderr.flush() return - if (where & m2.SSL_CB_ALERT): - if (where & m2.SSL_CB_READ): + if where & m2.SSL_CB_ALERT: + if where & m2.SSL_CB_READ: w = 'read' else: w = 'write' - sys.stderr.write("ALERT: %s: %s: %s\n" % \ - (w, m2.ssl_get_alert_type_v(ret), m2.ssl_get_alert_desc_v(ret))) + sys.stderr.write("ALERT: %s: %s: %s\n" % + (w, m2.ssl_get_alert_type_v(ret), + m2.ssl_get_alert_desc_v(ret))) sys.stderr.flush() return - - diff --git a/M2Crypto/SSL/ssl_dispatcher.py b/M2Crypto/SSL/ssl_dispatcher.py index 1e8c875..73a4b82 100644 --- a/M2Crypto/SSL/ssl_dispatcher.py +++ b/M2Crypto/SSL/ssl_dispatcher.py @@ -1,36 +1,43 @@ +from __future__ import absolute_import + """SSL dispatcher Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" -__all__ = ['ssl_dispatcher'] - # Python -import asyncore, socket +import asyncore +import socket # M2Crypto -from Connection import Connection -from M2Crypto import Err, m2 +from M2Crypto import util # noqa +from M2Crypto.SSL.Connection import Connection +from M2Crypto.SSL.Context import Context # noqa + +__all__ = ['ssl_dispatcher'] class ssl_dispatcher(asyncore.dispatcher): def create_socket(self, ssl_context): - self.family_and_type=socket.AF_INET, socket.SOCK_STREAM - self.ssl_ctx=ssl_context - self.socket=Connection(self.ssl_ctx) - #self.socket.setblocking(0) + # type: (Context) -> None + self.family_and_type = socket.AF_INET, socket.SOCK_STREAM + self.ssl_ctx = ssl_context + self.socket = Connection(self.ssl_ctx) + # self.socket.setblocking(0) self.add_channel() def connect(self, addr): + # type: (util.AddrType) -> None self.socket.setblocking(1) self.socket.connect(addr) self.socket.setblocking(0) def recv(self, buffer_size=4096): + # type: (int) -> bytes """Receive data over SSL.""" return self.socket.recv(buffer_size) def send(self, buffer): + # type: (bytes) -> int """Send data over SSL.""" return self.socket.send(buffer) - diff --git a/M2Crypto/SSL/timeout.py b/M2Crypto/SSL/timeout.py index d76556d..42b0291 100644 --- a/M2Crypto/SSL/timeout.py +++ b/M2Crypto/SSL/timeout.py @@ -7,24 +7,44 @@ Copyright 2008 Heikki Toivonen. All rights reserved. __all__ = ['DEFAULT_TIMEOUT', 'timeout', 'struct_to_timeout', 'struct_size'] +import sys import struct -from M2Crypto import m2 -DEFAULT_TIMEOUT = 600 +DEFAULT_TIMEOUT = 600 # type: int -class timeout: + +class timeout(object): def __init__(self, sec=DEFAULT_TIMEOUT, microsec=0): + # type: (int, int) -> None self.sec = sec self.microsec = microsec def pack(self): - return struct.pack('ll', self.sec, self.microsec) + if sys.platform == 'win32': + millisec = int(self.sec * 1000 + round(float(self.microsec) / 1000)) + binstr = struct.pack('l', millisec) + else: + binstr = struct.pack('ll', self.sec, self.microsec) + return binstr def struct_to_timeout(binstr): - (s, ms) = struct.unpack('ll', binstr) - return timeout(s, ms) + # type: (bytes) -> timeout + if sys.platform == 'win32': + millisec = struct.unpack('l', binstr)[0] + # On py3, int/int performs exact division and returns float. We want + # the whole number portion of the exact division result: + sec = int(millisec / 1000) + microsec = (millisec % 1000) * 1000 + else: + (sec, microsec) = struct.unpack('ll', binstr) + return timeout(sec, microsec) + def struct_size(): - return struct.calcsize('ll') + # type: () -> int + if sys.platform == 'win32': + return struct.calcsize('l') + else: + return struct.calcsize('ll') diff --git a/M2Crypto/X509.py b/M2Crypto/X509.py index eef83fe..fc00ada 100644 --- a/M2Crypto/X509.py +++ b/M2Crypto/X509.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """M2Crypto wrapper for OpenSSL X509 API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. @@ -7,141 +9,172 @@ Copyright (C) 2004-2007 OSAF. All Rights Reserved. Author: Heikki Toivonen """ -# M2Crypto -from M2Crypto import ASN1, BIO, Err, EVP, util -import m2 +import binascii +import logging + +from M2Crypto import ASN1, BIO, EVP, m2, py27plus, six # noqa +if py27plus: + from typing import AnyStr, Optional # noqa FORMAT_DER = 0 FORMAT_PEM = 1 -class X509Error(Exception): pass +log = logging.getLogger(__name__) + + +class X509Error(ValueError): + pass m2.x509_init(X509Error) -V_OK = m2.X509_V_OK +V_OK = m2.X509_V_OK # type: int + + +def x509_store_default_cb(ok, ctx): + # type: (int, X509_Store_Context) -> int + return ok + def new_extension(name, value, critical=0, _pyfree=1): + # type: (str, bytes, int, int) -> X509_Extension """ Create new X509_Extension instance. """ if name == 'subjectKeyIdentifier' and \ - value.strip('0123456789abcdefABCDEF:') is not '': + value.strip('0123456789abcdefABCDEF:') is not '': raise ValueError('value must be precomputed hash') - lhash = m2.x509v3_lhash() - ctx = m2.x509v3_set_conf_lhash(lhash) - x509_ext_ptr = m2.x509v3_ext_conf(lhash, ctx, name, value) + ctx = m2.x509v3_set_nconf() + x509_ext_ptr = m2.x509v3_ext_conf(None, ctx, name, value) + if x509_ext_ptr is None: + raise X509Error( + "Cannot create X509_Extension with name '%s' and value '%s'" % + (name, value)) x509_ext = X509_Extension(x509_ext_ptr, _pyfree) x509_ext.set_critical(critical) - return x509_ext + return x509_ext -class X509_Extension: +class X509_Extension(object): """ X509 Extension """ - + m2_x509_extension_free = m2.x509_extension_free - + def __init__(self, x509_ext_ptr=None, _pyfree=1): + # type: (Optional[bytes], int) -> None self.x509_ext = x509_ext_ptr self._pyfree = _pyfree def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0) and self.x509_ext: self.m2_x509_extension_free(self.x509_ext) def _ptr(self): + # type: () -> bytes return self.x509_ext def set_critical(self, critical=1): + # type: (int) -> int """ Mark this extension critical or noncritical. By default an extension is not critical. - @type critical: int - @param critical: Nonzero sets this extension as critical. + :param critical: Nonzero sets this extension as critical. Calling this method without arguments will set this extension to critical. + :return: 1 for success, 0 for failure """ return m2.x509_extension_set_critical(self.x509_ext, critical) - + def get_critical(self): + # type: () -> int """ Return whether or not this is a critical extension. - @rtype: int - @return: Nonzero if this is a critical extension. + :return: Nonzero if this is a critical extension. """ return m2.x509_extension_get_critical(self.x509_ext) - + def get_name(self): + # type: () -> str """ Get the extension name, for example 'subjectAltName'. """ - return m2.x509_extension_get_name(self.x509_ext) + return six.ensure_text(m2.x509_extension_get_name(self.x509_ext)) def get_value(self, flag=0, indent=0): + # type: (int, int) -> str """ Get the extension value, for example 'DNS:www.example.com'. - - @param flag: Flag to control what and how to print. - @param indent: How many spaces to print before actual value. + + :param flag: Flag to control what and how to print. + :param indent: How many spaces to print before actual value. """ - buf=BIO.MemoryBuffer() + buf = BIO.MemoryBuffer() m2.x509_ext_print(buf.bio_ptr(), self.x509_ext, flag, indent) - return buf.read_all() + return six.ensure_text(buf.read_all()) -class X509_Extension_Stack: +class X509_Extension_Stack(object): """ X509 Extension Stack - - @warning: Do not modify the underlying OpenSSL stack - except through this interface, or use any OpenSSL functions that do so - indirectly. Doing so will get the OpenSSL stack and the internal pystack - of this class out of sync, leading to python memory leaks, exceptions - or even python crashes! + + :warning: Do not modify the underlying OpenSSL stack + except through this interface, or use any OpenSSL + functions that do so indirectly. Doing so will get the + OpenSSL stack and the internal pystack of this class out + of sync, leading to python memory leaks, exceptions or + even python crashes! """ m2_sk_x509_extension_free = m2.sk_x509_extension_free def __init__(self, stack=None, _pyfree=0): + # type: (Optional[bytes], int) -> None if stack is not None: self.stack = stack self._pyfree = _pyfree num = m2.sk_x509_extension_num(self.stack) for i in range(num): - self.pystack.append(X509_Extension(m2.sk_x509_extension_value(self.stack, i), - _pyfree=_pyfree)) + self.pystack.append(X509_Extension( + m2.sk_x509_extension_value(self.stack, i), + _pyfree=_pyfree)) else: self.stack = m2.sk_x509_extension_new_null() self._pyfree = 1 - self.pystack = [] # This must be kept in sync with self.stack - + self.pystack = [] # This must be kept in sync with self.stack + def __del__(self): + # type: () -> None + # see BIO.py - unbalanced __init__ / __del__ if getattr(self, '_pyfree', 0): self.m2_sk_x509_extension_free(self.stack) def __len__(self): + # type: () -> int assert m2.sk_x509_extension_num(self.stack) == len(self.pystack) return len(self.pystack) def __getitem__(self, idx): + # type: (int) -> X509_Extension return self.pystack[idx] - + def __iter__(self): return iter(self.pystack) - + def _ptr(self): + # type: () -> bytes return self.stack def push(self, x509_ext): + # type: (X509_Extension) -> int """ Push X509_Extension object onto the stack. - @type x509_ext: M2Crypto.X509.X509_Extension - @param x509_ext: X509_Extension object to be pushed onto the stack. - @return: The number of extensions on the stack. + :param x509_ext: X509_Extension object to be pushed onto the stack. + :return: The number of extensions on the stack. """ self.pystack.append(x509_ext) ret = m2.sk_x509_extension_push(self.stack, x509_ext._ptr()) @@ -149,10 +182,11 @@ class X509_Extension_Stack: return ret def pop(self): + # type: () -> X509_Extension """ Pop X509_Extension object from the stack. - - @return: X509_Extension popped + + :return: X509_Extension popped """ x509_ext_ptr = m2.sk_x509_extension_pop(self.stack) if x509_ext_ptr is None: @@ -161,7 +195,7 @@ class X509_Extension_Stack: return self.pystack.pop() -class X509_Name_Entry: +class X509_Name_Entry(object): """ X509 Name Entry """ @@ -169,121 +203,202 @@ class X509_Name_Entry: m2_x509_name_entry_free = m2.x509_name_entry_free def __init__(self, x509_name_entry, _pyfree=0): + # type: (bytes, int) -> None + """ + :param x509_name_entry: this should be OpenSSL X509_NAME_ENTRY binary + :param _pyfree: + """ self.x509_name_entry = x509_name_entry self._pyfree = _pyfree - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_name_entry_free(self.x509_name_entry) def _ptr(self): + # type: () -> bytes return self.x509_name_entry def set_object(self, asn1obj): + # type: (ASN1.ASN1_Object) -> int + """ + Sets the field name to asn1obj + + :param asn1obj: + :return: 0 on failure, 1 on success + """ return m2.x509_name_entry_set_object(self.x509_name_entry, asn1obj._ptr()) def set_data(self, data, type=ASN1.MBSTRING_ASC): - return m2.x509_name_entry_set_data(self.x509_name_entry, - type, data) + # type: (bytes, int) -> int + """ + Sets the field name to asn1obj + + :param data: data in a binary form to be set + :return: 0 on failure, 1 on success + """ + return m2.x509_name_entry_set_data(self.x509_name_entry, type, data) def get_object(self): - return ASN1.ASN1_Object(m2.x509_name_entry_get_object(self.x509_name_entry)) - + # type: () -> ASN1.ASN1_Object + return ASN1.ASN1_Object( + m2.x509_name_entry_get_object(self.x509_name_entry)) + def get_data(self): - return ASN1.ASN1_String(m2.x509_name_entry_get_data(self.x509_name_entry)) + # type: () -> ASN1.ASN1_String + return ASN1.ASN1_String( + m2.x509_name_entry_get_data(self.x509_name_entry)) - def create_by_txt( self, field, type, entry, len): + def create_by_txt(self, field, type, entry, len): return m2.x509_name_entry_create_by_txt(self.x509_name_entry._ptr(), field, type, entry, len) - -class X509_Name: + +class X509_Name(object): """ X509 Name """ - nid = {'C' : m2.NID_countryName, - 'SP' : m2.NID_stateOrProvinceName, - 'ST' : m2.NID_stateOrProvinceName, - 'stateOrProvinceName' : m2.NID_stateOrProvinceName, - 'L' : m2.NID_localityName, - 'localityName' : m2.NID_localityName, - 'O' : m2.NID_organizationName, - 'organizationName' : m2.NID_organizationName, - 'OU' : m2.NID_organizationalUnitName, - 'organizationUnitName' : m2.NID_organizationalUnitName, - 'CN' : m2.NID_commonName, - 'commonName' : m2.NID_commonName, - 'Email' : m2.NID_pkcs9_emailAddress, - 'emailAddress' : m2.NID_pkcs9_emailAddress, - 'serialNumber' : m2.NID_serialNumber, - 'SN' : m2.NID_surname, - 'surname' : m2.NID_surname, - 'GN' : m2.NID_givenName, - 'givenName' : m2.NID_givenName + nid = {'C': m2.NID_countryName, + 'SP': m2.NID_stateOrProvinceName, + 'ST': m2.NID_stateOrProvinceName, + 'stateOrProvinceName': m2.NID_stateOrProvinceName, + 'L': m2.NID_localityName, + 'localityName': m2.NID_localityName, + 'O': m2.NID_organizationName, + 'organizationName': m2.NID_organizationName, + 'OU': m2.NID_organizationalUnitName, + 'organizationUnitName': m2.NID_organizationalUnitName, + 'CN': m2.NID_commonName, + 'commonName': m2.NID_commonName, + 'Email': m2.NID_pkcs9_emailAddress, + 'emailAddress': m2.NID_pkcs9_emailAddress, + 'serialNumber': m2.NID_serialNumber, + 'SN': m2.NID_surname, + 'surname': m2.NID_surname, + 'GN': m2.NID_givenName, + 'givenName': m2.NID_givenName } m2_x509_name_free = m2.x509_name_free def __init__(self, x509_name=None, _pyfree=0): + # type: (bytes, int) -> None + """ + :param x509_name: this should be OpenSSL X509_NAME binary + :param _pyfree: + """ if x509_name is not None: assert m2.x509_name_type_check(x509_name), "'x509_name' type error" self.x509_name = x509_name self._pyfree = _pyfree else: - self.x509_name = m2.x509_name_new () + self.x509_name = m2.x509_name_new() self._pyfree = 1 - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_name_free(self.x509_name) def __str__(self): - assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error" + # type: () -> bytes + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" return m2.x509_name_oneline(self.x509_name) def __getattr__(self, attr): + # type: (str) -> str if attr in self.nid: - assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error" - return m2.x509_name_by_nid(self.x509_name, self.nid[attr]) + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + return six.ensure_text(m2.x509_name_by_nid(self.x509_name, self.nid[attr])) if attr in self.__dict__: return self.__dict__[attr] - raise AttributeError, (self, attr) + raise AttributeError(self, attr) def __setattr__(self, attr, value): + # type: (str, AnyStr) -> int + """ + :return: 1 for success of 0 if an error occurred. + """ if attr in self.nid: - assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error" - return m2.x509_name_set_by_nid(self.x509_name, self.nid[attr], value) + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + return m2.x509_name_set_by_nid(self.x509_name, self.nid[attr], + six.ensure_binary(value)) self.__dict__[attr] = value def __len__(self): + # type: () -> int return m2.x509_name_entry_count(self.x509_name) - + def __getitem__(self, idx): + # type: (int) -> X509_Name_Entry if not 0 <= idx < self.entry_count(): raise IndexError("index out of range") return X509_Name_Entry(m2.x509_name_get_entry(self.x509_name, idx)) def __iter__(self): - for i in xrange(self.entry_count()): + for i in range(self.entry_count()): yield self[i] def _ptr(self): - #assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error" + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" return self.x509_name def add_entry_by_txt(self, field, type, entry, len, loc, set): - return m2.x509_name_add_entry_by_txt(self.x509_name, field, type, - entry, len, loc, set ) + # entry_type: (str, int, bytes, int, int, int) -> int + """ + Add X509_Name field whose name is identified by its name. + + :param field: name of the entry + :param type: use MBSTRING_ASC or MBSTRING_UTF8 + (or standard ASN1 type like V_ASN1_IA5STRING) + :param entry: value + :param len: buf_len of the entry + (-1 and the length is computed automagically) + + The ``loc`` and ``set`` parameters determine where a new entry + should be added. + For almost all applications loc can be set to -1 and set to 0. + This adds a new entry to the end of name as a single valued + RelativeDistinguishedName (RDN). + + :param loc: determines the index where the new entry is + inserted: if it is -1 it is appended. + :param set: determines how the new type is added. If it is zero + a new RDN is created. + If set is -1 or 1 it is added to the previous or next RDN + structure respectively. This will then be a multivalued + RDN: since multivalues RDNs are very seldom used set is + almost always set to zero. + + :return: 1 for success of 0 if an error occurred. + """ + return m2.x509_name_add_entry_by_txt(self.x509_name, + six.ensure_str(field), type, + six.ensure_str(entry), len, loc, set) + + def entry_count(self): + # type: () -> int + return m2.x509_name_entry_count(self.x509_name) - def entry_count( self ): - return m2.x509_name_entry_count( self.x509_name ) - def get_entries_by_nid(self, nid): + # type: (int) -> List[X509_Name_Entry] + """ + Retrieve the next index matching nid. + + :param nid: name of the entry (as m2.NID* constants) + + :return: list of X509_Name_Entry items + """ ret = [] lastpos = -1 @@ -292,33 +407,40 @@ class X509_Name: lastpos) if lastpos == -1: break - + ret.append(self[lastpos]) - + return ret - + def as_text(self, indent=0, flags=m2.XN_FLAG_COMPAT): + # type: (int, int) -> str """ as_text returns the name as a string. - - @param indent: Each line in multiline format is indented + + :param indent: Each line in multiline format is indented by this many spaces. - @param flags: Flags that control how the output should be formatted. + :param flags: Flags that control how the output should be formatted. """ - assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error" - buf=BIO.MemoryBuffer() + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + buf = BIO.MemoryBuffer() m2.x509_name_print_ex(buf.bio_ptr(), self.x509_name, indent, flags) - return buf.read_all() + return six.ensure_text(buf.read_all()) def as_der(self): - assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error" + # type: () -> bytes + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" return m2.x509_name_get_der(self.x509_name) def as_hash(self): - assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error" + # type: () -> int + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" return m2.x509_name_hash(self.x509_name) -class X509: + +class X509(object): """ X.509 Certificate """ @@ -326,107 +448,143 @@ class X509: m2_x509_free = m2.x509_free def __init__(self, x509=None, _pyfree=0): + # type: (Optional[bytes], int) -> None + """ + :param x509: binary representation of + the underlying OpenSSL X509 object. + :param _pyfree: + """ if x509 is not None: assert m2.x509_type_check(x509), "'x509' type error" self.x509 = x509 self._pyfree = _pyfree else: - self.x509 = m2.x509_new () + self.x509 = m2.x509_new() self._pyfree = 1 - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_free(self.x509) def _ptr(self): + # type: () -> bytes assert m2.x509_type_check(self.x509), "'x509' type error" return self.x509 def as_text(self): + # type: () -> str assert m2.x509_type_check(self.x509), "'x509' type error" - buf=BIO.MemoryBuffer() + buf = BIO.MemoryBuffer() m2.x509_print(buf.bio_ptr(), self.x509) - return buf.read_all() + return six.ensure_text(buf.read_all()) def as_der(self): + # type: () -> bytes assert m2.x509_type_check(self.x509), "'x509' type error" return m2.i2d_x509(self.x509) def as_pem(self): - buf=BIO.MemoryBuffer() + # type: () -> bytes + buf = BIO.MemoryBuffer() m2.x509_write_pem(buf.bio_ptr(), self.x509) return buf.read_all() def save_pem(self, filename): + # type: (AnyStr) -> int """ - save_pem + :param filename: name of the file to be loaded + :return: 1 for success or 0 for failure """ - bio=BIO.openfile(filename, 'wb') - return m2.x509_write_pem(bio.bio_ptr(), self.x509) + with BIO.openfile(filename, 'wb') as bio: + return m2.x509_write_pem(bio.bio_ptr(), self.x509) def save(self, filename, format=FORMAT_PEM): + # type: (AnyStr, int) -> int """ Saves X.509 certificate to a file. Default output format is PEM. - @type filename: string - @param filename: Name of the file the cert will be saved to. - @type format: int - @param format: Controls what output format is used to save the cert. - Either FORMAT_PEM or FORMAT_DER to save in PEM or DER format. - Raises a ValueError if an unknow format is used. + :param filename: Name of the file the cert will be saved to. + + :param format: Controls what output format is used to save the cert. + Either FORMAT_PEM or FORMAT_DER to save in PEM or + DER format. Raises a ValueError if an unknow + format is used. + + :return: 1 for success or 0 for failure """ - bio = BIO.openfile(filename, 'wb') - if format == FORMAT_PEM: - return m2.x509_write_pem(bio.bio_ptr(), self.x509) - elif format == FORMAT_DER: - return m2.i2d_x509_bio(bio.bio_ptr(), self.x509) - else: - raise ValueError("Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER") + with BIO.openfile(filename, 'wb') as bio: + if format == FORMAT_PEM: + return m2.x509_write_pem(bio.bio_ptr(), self.x509) + elif format == FORMAT_DER: + return m2.i2d_x509_bio(bio.bio_ptr(), self.x509) + else: + raise ValueError( + "Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER") def set_version(self, version): + # type: (int) -> int """ - Set version. + Set version of the certificate. - @type version: int - @param version: Version number. - @rtype: int - @return: Returns 0 on failure. + :param version: Version number. + :return: Returns 0 on failure. """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_version(self.x509, version) - def set_not_before(self, asn1_utctime): + def set_not_before(self, asn1_time): + # type: (ASN1.ASN1_TIME) -> int + """ + :return: 1 on success, 0 on failure + """ assert m2.x509_type_check(self.x509), "'x509' type error" - return m2.x509_set_not_before(self.x509, asn1_utctime._ptr()) + return m2.x509_set_not_before(self.x509, asn1_time._ptr()) - def set_not_after(self, asn1_utctime): + def set_not_after(self, asn1_time): + # type: (ASN1.ASN1_TIME) -> int + """ + :return: 1 on success, 0 on failure + """ assert m2.x509_type_check(self.x509), "'x509' type error" - return m2.x509_set_not_after(self.x509, asn1_utctime._ptr()) + return m2.x509_set_not_after(self.x509, asn1_time._ptr()) def set_subject_name(self, name): + # type: (X509_Name) -> int + """ + :return: 1 on success, 0 on failure + """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_subject_name(self.x509, name.x509_name) def set_issuer_name(self, name): + # type: (X509_Name) -> int + """ + :return: 1 on success, 0 on failure + """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_issuer_name(self.x509, name.x509_name) def get_version(self): + # type: () -> int assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_get_version(self.x509) def get_serial_number(self): + # type: () -> ASN1.ASN1_Integer assert m2.x509_type_check(self.x509), "'x509' type error" asn1_integer = m2.x509_get_serial_number(self.x509) return m2.asn1_integer_get(asn1_integer) def set_serial_number(self, serial): + # type: (ASN1.ASN1_Integer) -> int """ Set serial number. - @type serial: int - @param serial: Serial number. + :param serial: Serial number. + + :return 1 for success and 0 for failure. """ assert m2.x509_type_check(self.x509), "'x509' type error" # This "magically" changes serial since asn1_integer @@ -434,243 +592,281 @@ class X509: asn1_integer = m2.x509_get_serial_number(self.x509) return m2.asn1_integer_set(asn1_integer, serial) # XXX Or should I do this? - #asn1_integer = m2.asn1_integer_new() - #m2.asn1_integer_set(asn1_integer, serial) - #return m2.x509_set_serial_number(self.x509, asn1_integer) + # asn1_integer = m2.asn1_integer_new() + # m2.asn1_integer_set(asn1_integer, serial) + # return m2.x509_set_serial_number(self.x509, asn1_integer) def get_not_before(self): + # type: () -> ASN1.ASN1_TIME assert m2.x509_type_check(self.x509), "'x509' type error" - return ASN1.ASN1_UTCTIME(m2.x509_get_not_before(self.x509)) + return ASN1.ASN1_TIME(m2.x509_get_not_before(self.x509)) def get_not_after(self): + # type: () -> ASN1.ASN1_TIME assert m2.x509_type_check(self.x509), "'x509' type error" - return ASN1.ASN1_UTCTIME(m2.x509_get_not_after(self.x509)) + out = ASN1.ASN1_TIME(m2.x509_get_not_after(self.x509)) + if 'Bad time value' in str(out): + raise X509Error( + '''M2Crypto cannot handle dates after year 2050. + See RFC 5280 4.1.2.5 for more information. + ''') + return out def get_pubkey(self): + # type: () -> EVP.PKey assert m2.x509_type_check(self.x509), "'x509' type error" return EVP.PKey(m2.x509_get_pubkey(self.x509), _pyfree=1) def set_pubkey(self, pkey): + # type: (EVP.PKey) -> int """ Set the public key for the certificate - @type pkey: EVP_PKEY - @param pkey: Public key + :param pkey: Public key + + :return 1 for success and 0 for failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_pubkey(self.x509, pkey.pkey) def get_issuer(self): + # type: () -> X509_Name assert m2.x509_type_check(self.x509), "'x509' type error" return X509_Name(m2.x509_get_issuer_name(self.x509)) def set_issuer(self, name): + # type: (X509_Name) -> int """ Set issuer name. - @type name: X509_Name - @param name: subjectName field. + :param name: subjectName field. + + :return 1 for success and 0 for failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_issuer_name(self.x509, name.x509_name) def get_subject(self): + # type: () -> X509_Name assert m2.x509_type_check(self.x509), "'x509' type error" return X509_Name(m2.x509_get_subject_name(self.x509)) def set_subject(self, name): + # type: (X509_Name) -> int """ Set subject name. - @type name: X509_Name - @param name: subjectName field. + :param name: subjectName field. + + :return 1 for success and 0 for failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_subject_name(self.x509, name.x509_name) def add_ext(self, ext): + # type: (X509_Extension) -> int """ Add X509 extension to this certificate. - @type ext: X509_Extension - @param ext: Extension + :param ext: Extension + + :return 1 for success and 0 for failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_add_ext(self.x509, ext.x509_ext, -1) def get_ext(self, name): + # type: (str) -> X509_Extension """ Get X509 extension by name. - @type name: Name of the extension - @param name: str - @return: X509_Extension + :param name: Name of the extension + + :return: X509_Extension """ # Optimizations to reduce attribute accesses m2x509_get_ext = m2.x509_get_ext m2x509_extension_get_name = m2.x509_extension_get_name x509 = self.x509 - + + name = six.ensure_binary(name) for i in range(m2.x509_get_ext_count(x509)): - extPtr = m2x509_get_ext(x509, i) - if m2x509_extension_get_name(extPtr) == name: - return X509_Extension(extPtr, _pyfree=0) + ext_ptr = m2x509_get_ext(x509, i) + if m2x509_extension_get_name(ext_ptr) == name: + return X509_Extension(ext_ptr, _pyfree=0) raise LookupError def get_ext_at(self, index): + # type: (int) -> X509_Extension """ Get X509 extension by index. - @type index: Name of the extension - @param index: int - @return: X509_Extension + :param index: Name of the extension + + :return: X509_Extension """ if index < 0 or index >= self.get_ext_count(): raise IndexError - + return X509_Extension(m2.x509_get_ext(self.x509, index), _pyfree=0) def get_ext_count(self): + # type: () -> int """ Get X509 extension count. """ - return m2.x509_get_ext_count(self.x509) + return m2.x509_get_ext_count(self.x509) def sign(self, pkey, md): + # type: (EVP.PKey, str) -> int """ Sign the certificate. - @type pkey: EVP_PKEY - @param pkey: Public key - @type md: str - @param md: Message digest algorithm to use for signing, + :param pkey: Public key + + :param md: Message digest algorithm to use for signing, for example 'sha1'. + + :return int """ assert m2.x509_type_check(self.x509), "'x509' type error" mda = getattr(m2, md, None) if mda is None: - raise ValueError, ('unknown message digest', md) + raise ValueError('unknown message digest', md) return m2.x509_sign(self.x509, pkey.pkey, mda()) def verify(self, pkey=None): + # type: (Optional[EVP.PKey]) -> int assert m2.x509_type_check(self.x509), "'x509' type error" if pkey: return m2.x509_verify(self.x509, pkey.pkey) else: return m2.x509_verify(self.x509, self.get_pubkey().pkey) - + def check_ca(self): + # type: () -> int """ Check if the certificate is a Certificate Authority (CA) certificate. - - @return: 0 if the certificate is not CA, nonzero otherwise. - - @requires: OpenSSL 0.9.8 or newer + + :return: 0 if the certificate is not CA, nonzero otherwise. + + :requires: OpenSSL 0.9.8 or newer """ return m2.x509_check_ca(self.x509) - + def check_purpose(self, id, ca): + # type: (int, int) -> int """ Check if the certificate's purpose matches the asked purpose. - - @param id: Purpose id. See X509_PURPOSE_* constants. - @param ca: 1 if the certificate should be CA, 0 otherwise. - @return: 0 if the certificate purpose does not match, nonzero otherwise. + + :param id: Purpose id. See X509_PURPOSE_* constants. + + :param ca: 1 if the certificate should be CA, 0 otherwise. + + :return: 0 if the certificate purpose does not match, nonzero + otherwise. """ return m2.x509_check_purpose(self.x509, id, ca) def get_fingerprint(self, md='md5'): + # type: (str) -> str """ Get the fingerprint of the certificate. - - @param md: Message digest algorithm to use. - @return: String containing the fingerprint in hex format. + + :param md: Message digest algorithm to use. + + :return: String containing the fingerprint in hex format. """ der = self.as_der() md = EVP.MessageDigest(md) md.update(der) digest = md.final() - return hex(util.octx_to_num(digest))[2:-1].upper() + return six.ensure_text(binascii.hexlify(digest).upper()) + def load_cert(file, format=FORMAT_PEM): + # type: (AnyStr, int) -> X509 """ Load certificate from file. - @type file: string - @param file: Name of file containing certificate in either DER or PEM format. - @type format: int, either FORMAT_PEM or FORMAT_DER - @param format: Describes the format of the file to be loaded, either PEM or DER. + :param file: Name of file containing certificate in either DER or + PEM format. - @rtype: M2Crypto.X509.X509 - @return: M2Crypto.X509.X509 object. + :param format: Describes the format of the file to be loaded, + either PEM or DER. + + :return: M2Crypto.X509.X509 object. """ - bio = BIO.openfile(file) - if format == FORMAT_PEM: - return load_cert_bio(bio) - elif format == FORMAT_DER: - cptr = m2.d2i_x509(bio._ptr()) - if cptr is None: - raise X509Error(Err.get_error()) - return X509(cptr, _pyfree=1) - else: - raise ValueError("Unknown format. Must be either FORMAT_DER or FORMAT_PEM") + with BIO.openfile(file) as bio: + if format == FORMAT_PEM: + return load_cert_bio(bio) + elif format == FORMAT_DER: + cptr = m2.d2i_x509(bio._ptr()) + return X509(cptr, _pyfree=1) + else: + raise ValueError( + "Unknown format. Must be either FORMAT_DER or FORMAT_PEM") + def load_cert_bio(bio, format=FORMAT_PEM): + # type: (BIO.BIO, int) -> X509 """ Load certificate from a bio. - @type bio: M2Crypto.BIO.BIO - @param bio: BIO pointing at a certificate in either DER or PEM format. - @type format: int, either FORMAT_PEM or FORMAT_DER - @param format: Describes the format of the cert to be loaded, either PEM or DER. + :param bio: BIO pointing at a certificate in either DER or PEM format. - @rtype: M2Crypto.X509.X509 - @return: M2Crypto.X509.X509 object. + :param format: Describes the format of the cert to be loaded, + either PEM or DER (via constants FORMAT_PEM + and FORMAT_FORMAT_DER) + + :return: M2Crypto.X509.X509 object. """ if format == FORMAT_PEM: cptr = m2.x509_read_pem(bio._ptr()) elif format == FORMAT_DER: cptr = m2.d2i_x509(bio._ptr()) else: - raise ValueError("Unknown format. Must be either FORMAT_DER or FORMAT_PEM") - if cptr is None: - raise X509Error(Err.get_error()) + raise ValueError( + "Unknown format. Must be either FORMAT_DER or FORMAT_PEM") return X509(cptr, _pyfree=1) + def load_cert_string(string, format=FORMAT_PEM): + # type: (AnyStr, int) -> X509 """ Load certificate from a string. - @type string: string - @param string: String containing a certificate in either DER or PEM format. - @type format: int, either FORMAT_PEM or FORMAT_DER - @param format: Describes the format of the cert to be loaded, either PEM or DER. + :param string: String containing a certificate in either DER or PEM format. + + :param format: Describes the format of the cert to be loaded, + either PEM or DER (via constants FORMAT_PEM + and FORMAT_FORMAT_DER) - @rtype: M2Crypto.X509.X509 - @return: M2Crypto.X509.X509 object. + :return: M2Crypto.X509.X509 object. """ + string = six.ensure_binary(string) bio = BIO.MemoryBuffer(string) return load_cert_bio(bio, format) + def load_cert_der_string(string): + # type: (AnyStr) -> X509 """ Load certificate from a string. - @type string: string - @param string: String containing a certificate in DER format. + :param string: String containing a certificate in DER format. - @rtype: M2Crypto.X509.X509 - @return: M2Crypto.X509.X509 object. + :return: M2Crypto.X509.X509 object. """ + string = six.ensure_binary(string) bio = BIO.MemoryBuffer(string) cptr = m2.d2i_x509(bio._ptr()) - if cptr is None: - raise X509Error(Err.get_error()) return X509(cptr, _pyfree=1) -class X509_Store_Context: + +class X509_Store_Context(object): """ X509 Store Context """ @@ -678,49 +874,63 @@ class X509_Store_Context: m2_x509_store_ctx_free = m2.x509_store_ctx_free def __init__(self, x509_store_ctx, _pyfree=0): + # type: (bytes, int) -> None + """ + + :param x509_store_ctx: binary data for + OpenSSL X509_STORE_CTX type + """ self.ctx = x509_store_ctx self._pyfree = _pyfree - + def __del__(self): - if self._pyfree: + # type: () -> None + # see BIO.py - unbalanced __init__ / __del__ + if not hasattr(self, '_pyfree'): + pass # print("OOPS") + elif self._pyfree: self.m2_x509_store_ctx_free(self.ctx) - + def _ptr(self): return self.ctx - + def get_current_cert(self): + # type: () -> X509 """ Get current X.509 certificate. - - @warning: The returned certificate is NOT refcounted, so you can not - rely on it being valid once the store context goes away or is modified. + + :warning: The returned certificate is NOT refcounted, so you can not + rely on it being valid once the store context goes + away or is modified. """ return X509(m2.x509_store_ctx_get_current_cert(self.ctx), _pyfree=0) def get_error(self): + # type: () -> int """ Get error code. """ return m2.x509_store_ctx_get_error(self.ctx) - + def get_error_depth(self): + # type: () -> int """ Get error depth. """ return m2.x509_store_ctx_get_error_depth(self.ctx) - + def get1_chain(self): + # type: () -> X509_Stack """ Get certificate chain. - - @return: Reference counted (i.e. safe to use even after the store + + :return: Reference counted (i.e. safe to use even after the store context goes away) stack of certificates in the chain. - @rtype: X509_Stack """ return X509_Stack(m2.x509_store_ctx_get1_chain(self.ctx), 1, 1) - -class X509_Store: + +class X509_Store(object): """ X509 Store """ @@ -728,14 +938,19 @@ class X509_Store: m2_x509_store_free = m2.x509_store_free def __init__(self, store=None, _pyfree=0): + # type: (Optional[bytes], int) -> None + """ + :param store: binary data for OpenSSL X509_STORE_CTX type. + """ if store is not None: self.store = store self._pyfree = _pyfree else: self.store = m2.x509_store_new() self._pyfree = 1 - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_store_free(self.store) @@ -743,38 +958,72 @@ class X509_Store: return self.store def load_info(self, file): - ret = m2.x509_store_load_locations(self.store, file) - if ret < 1: - raise X509Error(Err.get_error()) + # type: (AnyStr) -> int + """ + :param file: filename + + :return: 1 on success, 0 on failure + """ + ret = m2.x509_store_load_locations(self.store, file) return ret load_locations = load_info - + def add_x509(self, x509): + # type: (X509) -> int assert isinstance(x509, X509) return m2.x509_store_add_cert(self.store, x509._ptr()) - + + def set_verify_cb(self, callback=None): + # type: (Optional[callable]) -> None + """ + Set callback which will be called when the store is verified. + Wrapper over OpenSSL X509_STORE_set_verify_cb(). + + :param callback: Callable to specify verification options. + Type of the callable must be: + (int, X509_Store_Context) -> int. + If None: set the standard options. + + :note: compile-time or run-time errors in the callback would result + in mysterious errors during verification, which could be hard + to trace. + + :note: Python exceptions raised in callbacks do not propagate to + verify() call. + + :return: None + """ + if callback is None: + return self.set_verify_cb(x509_store_default_cb) + + if not callable(callback): + raise X509Error("set_verify(): callback is not callable") + return m2.x509_store_set_verify_cb(self.store, callback) + add_cert = add_x509 -class X509_Stack: +class X509_Stack(object): """ X509 Stack - @warning: Do not modify the underlying OpenSSL stack - except through this interface, or use any OpenSSL functions that do so - indirectly. Doing so will get the OpenSSL stack and the internal pystack - of this class out of sync, leading to python memory leaks, exceptions - or even python crashes! + :warning: Do not modify the underlying OpenSSL stack + except through this interface, or use any OpenSSL + functions that do so indirectly. Doing so will get the + OpenSSL stack and the internal pystack of this class out + of sync, leading to python memory leaks, exceptions or + even python crashes! """ m2_sk_x509_free = m2.sk_x509_free def __init__(self, stack=None, _pyfree=0, _pyfree_x509=0): + # type: (bytes, int, int) -> None if stack is not None: self.stack = stack self._pyfree = _pyfree - self.pystack = [] # This must be kept in sync with self.stack + self.pystack = [] # This must be kept in sync with self.stack num = m2.sk_x509_num(self.stack) for i in range(num): self.pystack.append(X509(m2.sk_x509_value(self.stack, i), @@ -782,19 +1031,22 @@ class X509_Stack: else: self.stack = m2.sk_x509_new_null() self._pyfree = 1 - self.pystack = [] # This must be kept in sync with self.stack - + self.pystack = [] # This must be kept in sync with self.stack + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_sk_x509_free(self.stack) - + def __len__(self): + # type: () -> int assert m2.sk_x509_num(self.stack) == len(self.pystack) return len(self.pystack) def __getitem__(self, idx): + # type: (int) -> X509 return self.pystack[idx] - + def __iter__(self): return iter(self.pystack) @@ -802,11 +1054,13 @@ class X509_Stack: return self.stack def push(self, x509): + # type: (X509) -> int """ push an X509 certificate onto the stack. - - @param x509: X509 object. - @return: The number of X509 objects currently on the stack. + + :param x509: X509 object. + + :return: The number of X509 objects currently on the stack. """ assert isinstance(x509, X509) self.pystack.append(x509) @@ -815,11 +1069,12 @@ class X509_Stack: return ret def pop(self): + # type: () -> X509 """ pop a certificate from the stack. - - @return: X509 object that was popped, or None if there is nothing - to pop. + + :return: X509 object that was popped, or None if there is + nothing to pop. """ x509_ptr = m2.sk_x509_pop(self.stack) if x509_ptr is None: @@ -828,25 +1083,26 @@ class X509_Stack: return self.pystack.pop() def as_der(self): + # type: () -> bytes """ Return the stack as a DER encoded string """ - return m2.get_der_encoding_stack(self.stack) + return m2.get_der_encoding_stack(self.stack) def new_stack_from_der(der_string): + # type: (bytes) -> X509_Stack """ Create a new X509_Stack from DER string. - - @return: X509_Stack + + :return: X509_Stack """ + der_string = six.ensure_binary(der_string) stack_ptr = m2.make_stack_from_der_sequence(der_string) - if stack_ptr is None: - raise X509Error(Err.get_error()) return X509_Stack(stack_ptr, 1, 1) -class Request: +class Request(object): """ X509 Certificate Request. """ @@ -854,206 +1110,235 @@ class Request: m2_x509_req_free = m2.x509_req_free def __init__(self, req=None, _pyfree=0): + # type: (Optional[int], int) -> None if req is not None: self.req = req self._pyfree = _pyfree else: self.req = m2.x509_req_new() + m2.x509_req_set_version(self.req, 0) self._pyfree = 1 - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_req_free(self.req) - + def as_text(self): - buf=BIO.MemoryBuffer() + # type: () -> str + buf = BIO.MemoryBuffer() m2.x509_req_print(buf.bio_ptr(), self.req) - return buf.read_all() + return six.ensure_text(buf.read_all()) def as_pem(self): - buf=BIO.MemoryBuffer() + # type: () -> bytes + buf = BIO.MemoryBuffer() m2.x509_req_write_pem(buf.bio_ptr(), self.req) return buf.read_all() def as_der(self): + # type: () -> bytes buf = BIO.MemoryBuffer() m2.i2d_x509_req_bio(buf.bio_ptr(), self.req) return buf.read_all() def save_pem(self, filename): - bio=BIO.openfile(filename, 'wb') - return m2.x509_req_write_pem(bio.bio_ptr(), self.req) - + # type: (AnyStr) -> int + with BIO.openfile(filename, 'wb') as bio: + return m2.x509_req_write_pem(bio.bio_ptr(), self.req) + def save(self, filename, format=FORMAT_PEM): + # type: (AnyStr, int) -> int """ Saves X.509 certificate request to a file. Default output format is PEM. - @type filename: string - @param filename: Name of the file the request will be saved to. - @type format: int - @param format: Controls what output format is used to save the request. - Either FORMAT_PEM or FORMAT_DER to save in PEM or DER format. - Raises ValueError if an unknown format is used. + :param filename: Name of the file the request will be saved to. + + :param format: Controls what output format is used to save the + request. Either FORMAT_PEM or FORMAT_DER to save + in PEM or DER format. Raises ValueError if an + unknown format is used. + + :return: 1 for success, 0 for failure. + The error code can be obtained by ERR_get_error. """ - bio = BIO.openfile(filename, 'wb') - if format == FORMAT_PEM: - return m2.x509_req_write_pem(bio.bio_ptr(), self.req) - elif format == FORMAT_DER: - return m2.i2d_x509_req_bio(bio.bio_ptr(), self.req) - else: - raise ValueError("Unknown filetype. Must be either FORMAT_DER or FORMAT_PEM") + with BIO.openfile(filename, 'wb') as bio: + if format == FORMAT_PEM: + return m2.x509_req_write_pem(bio.bio_ptr(), self.req) + elif format == FORMAT_DER: + return m2.i2d_x509_req_bio(bio.bio_ptr(), self.req) + else: + raise ValueError( + "Unknown filetype. Must be either FORMAT_DER or FORMAT_PEM") def get_pubkey(self): + # type: () -> EVP.PKey """ Get the public key for the request. - @rtype: EVP_PKEY - @return: Public key from the request. + :return: Public key from the request. """ return EVP.PKey(m2.x509_req_get_pubkey(self.req), _pyfree=1) def set_pubkey(self, pkey): + # type: (EVP.PKey) -> int """ Set the public key for the request. - @type pkey: EVP_PKEY - @param pkey: Public key + :param pkey: Public key - @rtype: int - @return: Return 1 for success and 0 for failure. + :return: Return 1 for success and 0 for failure. """ - return m2.x509_req_set_pubkey( self.req, pkey.pkey ) + return m2.x509_req_set_pubkey(self.req, pkey.pkey) def get_version(self): + # type: () -> int """ Get version. - @rtype: int - @return: Returns version. + :return: Returns version. """ return m2.x509_req_get_version(self.req) def set_version(self, version): + # type: (int) -> int """ Set version. - @type version: int - @param version: Version number. - @rtype: int - @return: Returns 0 on failure. + :param version: Version number. + :return: Returns 0 on failure. """ - return m2.x509_req_set_version( self.req, version ) + return m2.x509_req_set_version(self.req, version) def get_subject(self): - return X509_Name(m2.x509_req_get_subject_name( self.req )) + # type: () -> X509_Name + return X509_Name(m2.x509_req_get_subject_name(self.req)) def set_subject_name(self, name): + # type: (X509_Name) -> int """ Set subject name. - @type name: X509_Name - @param name: subjectName field. + :param name: subjectName field. + :return: 1 for success and 0 for failure """ - return m2.x509_req_set_subject_name( self.req, name.x509_name ) + return m2.x509_req_set_subject_name(self.req, name.x509_name) set_subject = set_subject_name def add_extensions(self, ext_stack): + # type: (X509_Extension_Stack) -> int """ Add X509 extensions to this request. - @type ext_stack: X509_Extension_Stack - @param ext_stack: Stack of extensions to add. + :param ext_stack: Stack of extensions to add. + :return: 1 for success and 0 for failure """ return m2.x509_req_add_extensions(self.req, ext_stack._ptr()) def verify(self, pkey): + # type: (EVP.PKey) -> int + """ + + :param pkey: PKey to be verified + :return: 1 for success and 0 for failure + """ return m2.x509_req_verify(self.req, pkey.pkey) def sign(self, pkey, md): + # type: (EVP.PKey, str) -> int + """ + + :param pkey: PKey to be signed + :param md: used algorigthm + :return: 1 for success and 0 for failure + """ mda = getattr(m2, md, None) if mda is None: - raise ValueError, ('unknown message digest', md) + raise ValueError('unknown message digest', md) return m2.x509_req_sign(self.req, pkey.pkey, mda()) def load_request(file, format=FORMAT_PEM): + # type: (AnyStr, int) -> Request """ Load certificate request from file. - @type file: string - @param file: Name of file containing certificate request in either PEM or DER format. - @type format: int, either FORMAT_PEM or FORMAT_DER - @param format: Describes the format of the file to be loaded, either PEM or DER. - - @rtype: M2Crypto.X509.Request - @return: M2Crypto.X509.Request object. + :param file: Name of file containing certificate request in + either PEM or DER format. + :param format: Describes the format of the file to be loaded, + either PEM or DER. (using constants FORMAT_PEM + and FORMAT_DER) + :return: Request object. """ - f=BIO.openfile(file) - if format == FORMAT_PEM: - cptr=m2.x509_req_read_pem(f.bio_ptr()) - elif format == FORMAT_DER: - cptr = m2.d2i_x509_req(f.bio_ptr()) - else: - raise ValueError("Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER") - f.close() - if cptr is None: - raise X509Error(Err.get_error()) + with BIO.openfile(file) as f: + if format == FORMAT_PEM: + cptr = m2.x509_req_read_pem(f.bio_ptr()) + elif format == FORMAT_DER: + cptr = m2.d2i_x509_req(f.bio_ptr()) + else: + raise ValueError( + "Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER") + return Request(cptr, 1) + def load_request_bio(bio, format=FORMAT_PEM): + # type: (BIO.BIO, int) -> Request """ Load certificate request from a bio. - @type bio: M2Crypto.BIO.BIO - @param bio: BIO pointing at a certificate request in either DER or PEM format. - @type format: int, either FORMAT_PEM or FORMAT_DER - @param format: Describes the format of the request to be loaded, either PEM or DER. - - @rtype: M2Crypto.X509.Request - @return: M2Crypto.X509.Request object. + :param bio: BIO pointing at a certificate request in + either DER or PEM format. + :param format: Describes the format of the request to be loaded, + either PEM or DER. (using constants FORMAT_PEM + and FORMAT_DER) + :return: M2Crypto.X509.Request object. """ if format == FORMAT_PEM: cptr = m2.x509_req_read_pem(bio._ptr()) elif format == FORMAT_DER: cptr = m2.d2i_x509_req(bio._ptr()) else: - raise ValueError("Unknown format. Must be either FORMAT_DER or FORMAT_PEM") - if cptr is None: - raise X509Error(Err.get_error()) + raise ValueError( + "Unknown format. Must be either FORMAT_DER or FORMAT_PEM") + return Request(cptr, _pyfree=1) + def load_request_string(string, format=FORMAT_PEM): + # type: (AnyStr, int) -> Request """ Load certificate request from a string. - @type string: string - @param string: String containing a certificate request in either DER or PEM format. - @type format: int, either FORMAT_PEM or FORMAT_DER - @param format: Describes the format of the request to be loaded, either PEM or DER. + :param string: String containing a certificate request in + either DER or PEM format. + :param format: Describes the format of the request to be loaded, + either PEM or DER. (using constants FORMAT_PEM + and FORMAT_DER) - @rtype: M2Crypto.X509.Request - @return: M2Crypto.X509.Request object. + :return: M2Crypto.X509.Request object. """ + string = six.ensure_binary(string) bio = BIO.MemoryBuffer(string) return load_request_bio(bio, format) + def load_request_der_string(string): + # type: (AnyStr) -> Request """ Load certificate request from a string. - @type string: string - @param string: String containing a certificate request in DER format. - - @rtype: M2Crypto.X509.Request - @return: M2Crypto.X509.Request object. + :param string: String containing a certificate request in DER format. + :return: M2Crypto.X509.Request object. """ + string = six.ensure_binary(string) bio = BIO.MemoryBuffer(string) return load_request_bio(bio, FORMAT_DER) -class CRL: +class CRL(object): """ X509 Certificate Revocation List """ @@ -1061,44 +1346,46 @@ class CRL: m2_x509_crl_free = m2.x509_crl_free def __init__(self, crl=None, _pyfree=0): + # type: (Optional[bytes], int) -> None + """ + + :param crl: binary representation of + the underlying OpenSSL X509_CRL object. + """ if crl is not None: self.crl = crl self._pyfree = _pyfree else: self.crl = m2.x509_crl_new() self._pyfree = 1 - + def __del__(self): + # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_crl_free(self.crl) def as_text(self): + # type: () -> str """ Return CRL in PEM format in a string. - @rtype: string - @return: String containing the CRL in PEM format. + :return: String containing the CRL in PEM format. """ - buf=BIO.MemoryBuffer() + buf = BIO.MemoryBuffer() m2.x509_crl_print(buf.bio_ptr(), self.crl) - return buf.read_all() + return six.ensure_text(buf.read_all()) def load_crl(file): + # type: (AnyStr) -> CRL """ Load CRL from file. - @type file: string - @param file: Name of file containing CRL in PEM format. + :param file: Name of file containing CRL in PEM format. - @rtype: M2Crypto.X509.CRL - @return: M2Crypto.X509.CRL object. + :return: M2Crypto.X509.CRL object. """ - f=BIO.openfile(file) - cptr=m2.x509_crl_read_pem(f.bio_ptr()) - f.close() - if cptr is None: - raise X509Error(Err.get_error()) - return CRL(cptr, 1) - + with BIO.openfile(file) as f: + cptr = m2.x509_crl_read_pem(f.bio_ptr()) + return CRL(cptr, 1) diff --git a/M2Crypto/__init__.py b/M2Crypto/__init__.py index e7acfe7..f515883 100644 --- a/M2Crypto/__init__.py +++ b/M2Crypto/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """ M2Crypto is the most complete Python wrapper for OpenSSL featuring RSA, DSA, DH, EC, HMACs, message digests, symmetric ciphers (including AES); SSL @@ -15,46 +17,29 @@ Copyright (C) 2004-2007 OSAF. All Rights Reserved. Copyright 2008-2011 Heikki Toivonen. All rights reserved. """ +# noqa +import sys +from distutils.version import StrictVersion +__version__ = '0.35.1' +version = __version__ # type: str +version_info = StrictVersion(__version__).version + +# This means "Python 2.7 or higher" so it is True for py3k as well +py27plus = sys.version_info[:2] > (2, 6) # type: bool + +from M2Crypto import (ASN1, AuthCookie, BIO, BN, DH, DSA, EVP, Engine, Err, + RSA, Rand, SMIME, SSL, X509, m2crypto, ftpslib, + httpslib, m2, m2urllib, m2xmlrpclib, threading, + util) -version_info = (0, 21, 1) -version = '.'.join([str(_v) for _v in version_info]) - -import __m2crypto -import m2 -import ASN1 -import AuthCookie -import BIO -import BN -import Rand -import DH -import DSA if m2.OPENSSL_VERSION_NUMBER >= 0x90800F and m2.OPENSSL_NO_EC == 0: - import EC -import Err -import Engine -import EVP -import RSA -import RC4 -import SMIME -import SSL -import X509 -import PGP -import m2urllib + from M2Crypto import EC +if m2.OPENSSL_NO_RC4 == 0: + from M2Crypto import RC4 # Backwards compatibility. urllib2 = m2urllib -import sys -if sys.version_info >= (2,4): - import m2urllib2 -del sys - -import ftpslib -import httpslib -import m2xmlrpclib -import threading -import util - -encrypt=1 -decrypt=0 +encrypt = 1 +decrypt = 0 -__m2crypto.lib_init() +m2crypto.lib_init() diff --git a/M2Crypto/callback.py b/M2Crypto/callback.py index 46613ca..c6f54d8 100644 --- a/M2Crypto/callback.py +++ b/M2Crypto/callback.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """Deprecated, use the util module instead. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" @@ -6,4 +8,4 @@ import warnings warnings.warn('Use the util module instead', DeprecationWarning) -from util import genparam_callback, passphrase_callback +from M2Crypto.util import genparam_callback, passphrase_callback diff --git a/M2Crypto/ftpslib.py b/M2Crypto/ftpslib.py index b7d82fd..e996981 100644 --- a/M2Crypto/ftpslib.py +++ b/M2Crypto/ftpslib.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """M2Crypto client-side FTP/TLS. This implementation complies with draft-murray-auth-ftp-ssl-07.txt. @@ -31,16 +33,13 @@ drwxr-xr-x 12 0 0 512 May 31 17:08 python2.1 Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" -# Python -from ftplib import * -from ftplib import parse150, parse227 -from ftplib import error_reply, error_temp, error_perm, error_proto -import socket, time +# We want to import whole stdlib ftplib objects, because our users want +# to use them. +from ftplib import * # noqa # M2Crypto -import SSL +from M2Crypto import SSL -DEFAULT_PROTOCOL='sslv23' class FTP_TLS(FTP): @@ -51,7 +50,7 @@ class FTP_TLS(FTP): if ssl_ctx is not None: self.ssl_ctx = ssl_ctx else: - self.ssl_ctx = SSL.Context(DEFAULT_PROTOCOL) + self.ssl_ctx = SSL.Context() FTP.__init__(self, host) self.prot = 0 @@ -74,12 +73,12 @@ class FTP_TLS(FTP): self.voidcmd('PBSZ 0') self.voidcmd('PROT P') self.prot = 1 - + def prot_c(self): """Set up data connection in the clear.""" self.voidcmd('PROT C') self.prot = 0 - + def ntransfercmd(self, cmd, rest=None): """Initiate a data transfer.""" conn, size = FTP.ntransfercmd(self, cmd, rest) @@ -90,5 +89,3 @@ class FTP_TLS(FTP): conn.set_session(self.sock.get_session()) conn.connect_ssl() return conn, size - - diff --git a/M2Crypto/httpslib.py b/M2Crypto/httpslib.py index c1bfd78..f624865 100644 --- a/M2Crypto/httpslib.py +++ b/M2Crypto/httpslib.py @@ -1,15 +1,22 @@ -"""M2Crypto support for Python's httplib. +from __future__ import absolute_import + +import warnings + +"""M2Crypto support for Python's httplib. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" -import string, sys -import socket -from urlparse import urlsplit, urlunsplit import base64 +import socket + +from M2Crypto import SSL, py27plus, six +from M2Crypto.six.moves.urllib_parse import urlsplit, urlunsplit +from M2Crypto.six.moves.http_client import * # noqa +# This is not imported with just '*' +from M2Crypto.six.moves.http_client import HTTPS_PORT +if py27plus: + from typing import Any, AnyStr, Callable, Dict, List, Optional # noqa -from httplib import * -from httplib import HTTPS_PORT # This is not imported with just '*' -import SSL class HTTPSConnection(HTTPConnection): @@ -20,43 +27,77 @@ class HTTPSConnection(HTTPConnection): default_port = HTTPS_PORT def __init__(self, host, port=None, strict=None, **ssl): - self.session = None - keys = ssl.keys() - try: - keys.remove('key_file') - except ValueError: - pass - try: - keys.remove('cert_file') - except ValueError: - pass - try: - keys.remove('ssl_context') - except ValueError: - pass + # type: (str, Optional[int], Optional[bool], **Any) -> None + """ + Represents one transaction with an HTTP server over the SSL + connection. + + :param host: host name + :param port: port number + :param strict: if switched on, it raises BadStatusLine to be + raised if the status line can't be parsed as + a valid HTTP/1.0 or 1.1 status line. + :param ssl: dict with all remaining named real parameters of the + function. Specifically, ``ssl_context`` is expected + to be included with SSL.Context; if it is not + default ``'sslv23'`` is substituted). + """ + self.session = None # type: bytes + self.host = host + self.port = port + keys = set(ssl.keys()) - set(('key_file', 'cert_file', 'ssl_context')) if keys: - raise ValueError('unknown keyword argument') + raise ValueError('unknown keyword argument: %s', keys) try: self.ssl_ctx = ssl['ssl_context'] assert isinstance(self.ssl_ctx, SSL.Context), self.ssl_ctx except KeyError: - self.ssl_ctx = SSL.Context('sslv23') + self.ssl_ctx = SSL.Context() HTTPConnection.__init__(self, host, port, strict) def connect(self): - self.sock = SSL.Connection(self.ssl_ctx) - if self.session: - self.sock.set_session(self.session) - self.sock.connect((self.host, self.port)) + # type: () -> None + error = None + # We ignore the returned sockaddr because SSL.Connection.connect needs + # a host name. + for (family, _, _, _, _) in \ + socket.getaddrinfo(self.host, self.port, 0, + socket.SOCK_STREAM): + sock = None + try: + sock = SSL.Connection(self.ssl_ctx, family=family) + + # set SNI server name since we know it at this point + sock.set_tlsext_host_name(self.host) + + if self.session is not None: + sock.set_session(self.session) + sock.connect((self.host, self.port)) + + self.sock = sock + sock = None + return + except socket.error as e: + # Other exception are probably SSL-related, in that case we + # abort and the exception is forwarded to the caller. + error = e + finally: + if sock is not None: + sock.close() + + if error is None: + raise AssertionError("Empty list returned by getaddrinfo") + raise error def close(self): + # type: () -> None # This kludges around line 545 of httplib.py, # which closes the connection in this object; # the connection remains open in the response # object. # # M2Crypto doesn't close-here-keep-open-there, - # so, in effect, we don't close until the whole + # so, in effect, we don't close until the whole # business is over and gc kicks in. # # XXX Long-running callers beware leakage. @@ -65,30 +106,17 @@ class HTTPSConnection(HTTPConnection): # XXX but I've not investigated if the above conditions # XXX remain. pass - + def get_session(self): + # type: () -> SSL.Session.Session return self.sock.get_session() def set_session(self, session): + # type: (SSL.Session.Session) -> None self.session = session - - -class HTTPS(HTTP): - - _connection_class = HTTPSConnection - - def __init__(self, host='', port=None, strict=None, **ssl): - HTTP.__init__(self, host, port, strict) - try: - self.ssl_ctx = ssl['ssl_context'] - except KeyError: - self.ssl_ctx = SSL.Context('sslv23') - assert isinstance(self._conn, HTTPSConnection) - self._conn.ssl_ctx = self.ssl_ctx class ProxyHTTPSConnection(HTTPSConnection): - """ An HTTPS Connection that uses a proxy and the CONNECT request. @@ -101,56 +129,78 @@ class ProxyHTTPSConnection(HTTPSConnection): through the proxy. """ - _ports = {'http' : 80, 'https' : 443} + _ports = {'http': 80, 'https': 443} _AUTH_HEADER = "Proxy-Authorization" _UA_HEADER = "User-Agent" def __init__(self, host, port=None, strict=None, username=None, - password=None, **ssl): + password=None, **ssl): + # type: (str, Optional[int], Optional[bool], Optional[AnyStr], Optional[AnyStr], **Any) -> None """ Create the ProxyHTTPSConnection object. - host and port are the hostname and port number of the proxy server. + :param host: host name of the proxy server + :param port: port number of the proxy server + :param strict: if switched on, it raises BadStatusLine to be + raised if the status line can't be parsed as + a valid HTTP/1.0 or 1.1 status line. + :param username: username on the proxy server, when required + Username can be ``str``, but preferred type + is ``bytes``. M2Crypto does some conversion to + ``bytes`` when necessary, but it's better when + the user of the library does it on its own. + :param password: password on the proxy server, when required + The same as with ``username``, ``str`` is accepted, + but ``bytes`` are preferred. + :param ssl: dict with all remaining named real parameters of the + function. Specifically, ``ssl_context`` is expected + to be included with SSL.Context; if it is not + default ``'sslv23'`` is substituted). """ HTTPSConnection.__init__(self, host, port, strict, **ssl) - self._username = username - self._password = password - self._proxy_auth = None - self._proxy_UA = None + self._username = username.encode('utf8') \ + if isinstance(username, six.string_types) else username + self._password = password.encode('utf8') \ + if isinstance(password, six.string_types) else password + self._proxy_auth = None # type: str + self._proxy_UA = None # type: str def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0): - #putrequest is called before connect, so can interpret url and get - #real host/port to be used to make CONNECT request to proxy + # type: (AnyStr, AnyStr, int, int) -> None + """ + putrequest is called before connect, so can interpret url and get + real host/port to be used to make CONNECT request to proxy + """ proto, netloc, path, query, fragment = urlsplit(url) if not proto: - raise ValueError, "unknown URL type: %s" % url - - #get host & port + raise ValueError("unknown URL type: %s" % url) + + # get host & port try: username_password, host_port = netloc.split('@') except ValueError: host_port = netloc try: - host, port = host_port.split(':') + host, port_s = host_port.split(':') + port = int(port_s) except ValueError: host = host_port - #try to get port from proto + # try to get port from proto try: port = self._ports[proto] except KeyError: - raise ValueError, "unknown protocol for: %s" % url + raise ValueError("unknown protocol for: %s" % url) - self._real_host = host - self._real_port = int(port) - rest = urlunsplit((None, None, path, query, fragment)) - if sys.version_info < (2,4): - HTTPSConnection.putrequest(self, method, rest, skip_host) - else: - HTTPSConnection.putrequest(self, method, rest, skip_host, skip_accept_encoding) + self._real_host = host # type: str + self._real_port = port # type: int + rest = urlunsplit(('', '', path, query, fragment)) + HTTPSConnection.putrequest(self, method, rest, skip_host, + skip_accept_encoding) def putheader(self, header, value): + # type: (AnyStr, AnyStr) -> None # Store the auth header if passed in. if header.lower() == self._UA_HEADER.lower(): self._proxy_UA = value @@ -159,43 +209,47 @@ class ProxyHTTPSConnection(HTTPSConnection): else: HTTPSConnection.putheader(self, header, value) - def endheaders(self): + def endheaders(self, *args, **kwargs): + # type: (*Any, **Any) -> None # We've recieved all of hte headers. Use the supplied username # and password for authorization, possibly overriding the authstring # supplied in the headers. if not self._proxy_auth: self._proxy_auth = self._encode_auth() - HTTPSConnection.endheaders(self) + HTTPSConnection.endheaders(self, *args, **kwargs) def connect(self): + # type: () -> None HTTPConnection.connect(self) - #send proxy CONNECT request + # send proxy CONNECT request self.sock.sendall(self._get_connect_msg()) response = HTTPResponse(self.sock) response.begin() - + code = response.status if code != 200: - #proxy returned and error, abort connection, and raise exception + # proxy returned and error, abort connection, and raise exception self.close() - raise socket.error, "Proxy connection failed: %d" % code - + raise socket.error("Proxy connection failed: %d" % code) + self._start_ssl() def _get_connect_msg(self): + # type: () -> bytes """ Return an HTTP CONNECT request to send to the proxy. """ msg = "CONNECT %s:%d HTTP/1.1\r\n" % (self._real_host, self._real_port) msg = msg + "Host: %s:%d\r\n" % (self._real_host, self._real_port) if self._proxy_UA: msg = msg + "%s: %s\r\n" % (self._UA_HEADER, self._proxy_UA) if self._proxy_auth: - msg = msg + "%s: %s\r\n" % (self._AUTH_HEADER, self._proxy_auth) + msg = msg + "%s: %s\r\n" % (self._AUTH_HEADER, self._proxy_auth) msg = msg + "\r\n" - return msg + return six.ensure_binary(msg) def _start_ssl(self): + # type: () -> None """ Make this connection's socket SSL-aware. """ self.sock = SSL.Connection(self.ssl_ctx, self.sock) self.sock.setup_ssl() @@ -203,10 +257,13 @@ class ProxyHTTPSConnection(HTTPSConnection): self.sock.connect_ssl() def _encode_auth(self): + # type: () -> Optional[bytes] """ Encode the username and password for use in the auth header. """ if not (self._username and self._password): return None # Authenticated proxy userpass = "%s:%s" % (self._username, self._password) - enc_userpass = base64.encodestring(userpass).replace("\n", "") - return "Basic %s" % enc_userpass + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + enc_userpass = base64.encodestring(userpass).replace("\n", "") + return six.ensure_binary("Basic %s" % enc_userpass) diff --git a/M2Crypto/m2.py b/M2Crypto/m2.py index e4bb695..81e4315 100644 --- a/M2Crypto/m2.py +++ b/M2Crypto/m2.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """M2Crypto low level OpenSSL wrapper functions. m2 is the low level wrapper for OpenSSL functions. Typically you would not @@ -25,7 +27,5 @@ Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004 OSAF. All Rights Reserved. """ -from __m2crypto import * +from M2Crypto.m2crypto import * lib_init() - - diff --git a/M2Crypto/m2crypto.py b/M2Crypto/m2crypto.py new file mode 100644 index 0000000..9cad6f4 --- /dev/null +++ b/M2Crypto/m2crypto.py @@ -0,0 +1,87 @@ +# This file was automatically generated by SWIG (http://www.swig.org). +# Version 2.0.10 +# +# Do not make changes to this file unless you know what you are doing--modify +# the SWIG interface file instead. + + + +from sys import version_info +if version_info >= (2,6,0): + def swig_import_helper(): + from os.path import dirname + import imp + fp = None + try: + fp, pathname, description = imp.find_module('_m2crypto', [dirname(__file__)]) + except ImportError: + import _m2crypto + return _m2crypto + if fp is not None: + try: + _mod = imp.load_module('_m2crypto', fp, pathname, description) + finally: + fp.close() + return _mod + _m2crypto = swig_import_helper() + del swig_import_helper +else: + import _m2crypto +del version_info +from _m2crypto import * +try: + _swig_property = property +except NameError: + pass # Python < 2.2 doesn't have 'property'. +def _swig_setattr_nondynamic(self,class_type,name,value,static=1): + if (name == "thisown"): return self.this.own(value) + if (name == "this"): + if type(value).__name__ == 'SwigPyObject': + self.__dict__[name] = value + return + method = class_type.__swig_setmethods__.get(name,None) + if method: return method(self,value) + if (not static): + self.__dict__[name] = value + else: + raise AttributeError("You cannot add attributes to %s" % self) + +def _swig_setattr(self,class_type,name,value): + return _swig_setattr_nondynamic(self,class_type,name,value,0) + +def _swig_getattr(self,class_type,name): + if (name == "thisown"): return self.this.own() + method = class_type.__swig_getmethods__.get(name,None) + if method: return method(self) + raise AttributeError(name) + +def _swig_repr(self): + try: strthis = "proxy of " + self.this.__repr__() + except: strthis = "" + return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) + +try: + _object = object + _newclass = 1 +except AttributeError: + class _object : pass + _newclass = 0 + + +def _swig_setattr_nondynamic_method(set): + def set_attr(self,name,value): + if (name == "thisown"): return self.this.own(value) + if hasattr(self,name) or (name == "this"): + set(self,name,value) + else: + raise AttributeError("You cannot add attributes to %s" % self) + return set_attr + + + + + + + + + diff --git a/M2Crypto/m2urllib.py b/M2Crypto/m2urllib.py index d951eb2..79791d4 100644 --- a/M2Crypto/m2urllib.py +++ b/M2Crypto/m2urllib.py @@ -1,51 +1,102 @@ -"""M2Crypto enhancement to Python's urllib for handling +from __future__ import absolute_import, print_function + +"""M2Crypto enhancement to Python's urllib for handling 'https' url's. +FIXME: it is questionable whether we need this old-style module at all. urllib +(not urllib2) is in Python 3 support just as a legacy API. + Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" -import string, sys, urllib -from urllib import * +import base64 +import warnings + +from M2Crypto import SSL, httpslib, six, util + +from M2Crypto.six.moves.urllib_response import addinfourl +if util.py27plus: + from typing import AnyStr, Optional # noqa -import SSL -import httpslib +# six.moves doesn't support star imports +if six.PY3: + from urllib.request import * # noqa for other modules to import + from urllib.parse import * # noqa for other modules to import + from urllib.error import * # noqa for other modules to import +else: + from urllib import * # noqa -DEFAULT_PROTOCOL='sslv23' def open_https(self, url, data=None, ssl_context=None): + # type: (URLOpener, AnyStr, Optional[bytes], Optional[SSL.Context]) -> addinfourl + """ + Open URL over the SSL connection. + + :param url: URL to be opened + :param data: data for the POST request + :param ssl_context: SSL.Context to be used + :return: + """ + if six.PY3: + warnings.warn('URLOpener has been deprecated in Py3k', DeprecationWarning) + if ssl_context is not None and isinstance(ssl_context, SSL.Context): self.ctx = ssl_context else: - self.ctx = SSL.Context(DEFAULT_PROTOCOL) + self.ctx = SSL.Context() user_passwd = None - if type(url) is type(""): - host, selector = splithost(url) - if host: - user_passwd, host = splituser(host) - host = unquote(host) - realhost = host + if isinstance(url, six.string_types): + try: # python 2 + # http://pydoc.org/2.5.1/urllib.html + host, selector = splithost(url) + if host: + user_passwd, host = splituser(host) + host = unquote(host) + realhost = host + except NameError: # python 3 has no splithost + # https://docs.python.org/3/library/urllib.parse.html + parsed = urlparse(url) + host = parsed.hostname + if parsed.port: + host += ":{0}".format(parsed.port) + user_passwd = parsed.password + if parsed.password: + user_passwd += ":{0}".format(parsed.password) + selector = parsed.path else: host, selector = url urltype, rest = splittype(selector) url = rest user_passwd = None - if string.lower(urltype) != 'http': + if urltype.lower() != 'http': realhost = None else: - realhost, rest = splithost(rest) - if realhost: - user_passwd, realhost = splituser(realhost) - if user_passwd: - selector = "%s://%s%s" % (urltype, realhost, rest) - #print "proxy via http:", host, selector - if not host: raise IOError, ('http error', 'no host given') + try: # python 2 + realhost, rest = splithost(rest) + if realhost: + user_passwd, realhost = splituser(realhost) + if user_passwd: + selector = "%s://%s%s" % (urltype, realhost, rest) + except NameError: # python 3 has no splithost + parsed = urlparse(rest) + host = parsed.hostname + if parsed.port: + host += ":{0}".format(parsed.port) + user_passwd = parsed.username + if parsed.password: + user_passwd += ":{0}".format(parsed.password) + # print("proxy via http:", host, selector) + if not host: + raise IOError('http error', 'no host given') if user_passwd: - import base64 - auth = string.strip(base64.encodestring(user_passwd)) + if six.PY3: + auth = base64.encodebytes(user_passwd).strip() + else: + auth = base64.encodestring(user_passwd).strip() else: auth = None # Start here! h = httpslib.HTTPSConnection(host=host, ssl_context=self.ctx) - #h.set_debuglevel(1) + # h.set_debuglevel(1) # Stop here! if data is not None: h.putrequest('POST', selector) @@ -53,18 +104,18 @@ def open_https(self, url, data=None, ssl_context=None): h.putheader('Content-length', '%d' % len(data)) else: h.putrequest('GET', selector) - if auth: h.putheader('Authorization', 'Basic %s' % auth) - for args in self.addheaders: apply(h.putheader, args) + if auth: + h.putheader('Authorization', 'Basic %s' % auth) + for args in self.addheaders: + h.putheader(*args) # for python3 - used to use apply h.endheaders() if data is not None: h.send(data + '\r\n') # Here again! resp = h.getresponse() fp = resp.fp - return urllib.addinfourl(fp, resp.msg, "https:" + url) + return addinfourl(fp, resp.msg, "https:" + url) # Stop again. -# Minor brain surgery. +# Minor brain surgery. URLopener.open_https = open_https - - diff --git a/M2Crypto/m2urllib2.py b/M2Crypto/m2urllib2.py index e500410..acac92f 100644 --- a/M2Crypto/m2urllib2.py +++ b/M2Crypto/m2urllib2.py @@ -1,5 +1,7 @@ +from __future__ import absolute_import + """ -M2Crypto enhancement to Python's urllib2 for handling +M2Crypto enhancement to Python's urllib2 for handling 'https' url's. Code from urllib2 is Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 @@ -12,29 +14,46 @@ Summary of changes: """ import socket -from urllib2 import * -import urlparse -import SSL -import httpslib +from M2Crypto import SSL, httpslib, six, util + +from M2Crypto.six.moves.urllib_parse import urldefrag, urlparse as url_parse +from M2Crypto.six.moves.urllib_response import addinfourl +if util.py27plus: + from typing import List, Optional # noqa + +# six.moves doesn't support star imports +if six.PY3: + from urllib.request import * # noqa other modules want to import + from urllib.error import * # noqa other modules want to import +else: + from urllib2 import * # noqa + +try: + mother_class = socket._fileobject +except AttributeError: + mother_class = socket.SocketIO -class _closing_fileobject(socket._fileobject): - '''socket._fileobject that propagates self.close() to the socket. + +class _closing_fileobject(mother_class): # noqa + """socket._fileobject that propagates self.close() to the socket. Python 2.5 provides this as socket._fileobject(sock, close=True). - ''' + """ - def __init__(self, sock): - socket._fileobject.__init__(self, sock) +# for python 3 +try: + AbstractHTTPHandler +except NameError: + # somehow this won't get imported by the import * above + import urllib.request + AbstractHTTPHandler = urllib.request.AbstractHTTPHandler - def close(self): - sock = self._sock - socket._fileobject.close(self) - sock.close() class HTTPSHandler(AbstractHTTPHandler): - def __init__(self, ssl_context = None): + def __init__(self, ssl_context=None): + # type: (SSL.Context) -> None AbstractHTTPHandler.__init__(self) if ssl_context is not None: @@ -45,28 +64,41 @@ class HTTPSHandler(AbstractHTTPHandler): # Copied from urllib2, so we can set the ssl context. def https_open(self, req): + # type: (Request) -> addinfourl """Return an addinfourl object for the request, using http_class. http_class must implement the HTTPConnection API from httplib. The addinfourl return value is a file-like object. It also has methods and attributes including: + - info(): return a mimetools.Message object for the headers + - geturl(): return the original request URL + - code: HTTP status code """ - host = req.get_host() + # https://docs.python.org/3.3/library/urllib.request.html#urllib.request.Request.get_host + try: # up to python-3.2 + host = req.get_host() + except AttributeError: # from python-3.3 + host = req.host if not host: raise URLError('no host given') # Our change: Check to see if we're using a proxy. # Then create an appropriate ssl-aware connection. - full_url = req.get_full_url() - target_host = urlparse.urlparse(full_url)[1] + full_url = req.get_full_url() + target_host = url_parse(full_url)[1] - if (target_host != host): - h = httpslib.ProxyHTTPSConnection(host = host, ssl_context = self.ctx) + if target_host != host: + request_uri = urldefrag(full_url)[0] + h = httpslib.ProxyHTTPSConnection(host=host, ssl_context=self.ctx) else: - h = httpslib.HTTPSConnection(host = host, ssl_context = self.ctx) + try: # up to python-3.2 + request_uri = req.get_selector() + except AttributeError: # from python-3.3 + request_uri = req.selector + h = httpslib.HTTPSConnection(host=host, ssl_context=self.ctx) # End our change h.set_debuglevel(self._debuglevel) @@ -80,9 +112,9 @@ class HTTPSHandler(AbstractHTTPHandler): # request. headers["Connection"] = "close" try: - h.request(req.get_method(), req.get_selector(), req.data, headers) + h.request(req.get_method(), request_uri, req.data, headers) r = h.getresponse() - except socket.error, err: # XXX what error? + except socket.error as err: # XXX what error? raise URLError(err) # Pick apart the HTTPResponse object to get the addinfourl @@ -92,24 +124,27 @@ class HTTPSHandler(AbstractHTTPHandler): # for Windows. That adapter calls recv(), so delegate recv() # to read(). This weird wrapping allows the returned object to # have readline() and readlines() methods. - - # XXX It might be better to extract the read buffering code - # out of socket._fileobject() and into a base class. - r.recv = r.read - fp = _closing_fileobject(r) + if six.PY2: + fp = socket._fileobject(r, close=True) + else: + r._decref_socketios = lambda: None + r.ssl = h.sock.ssl + r._timeout = -1.0 + r.recv_into = r.readinto + fp = socket.SocketIO(r, 'rb') resp = addinfourl(fp, r.msg, req.get_full_url()) resp.code = r.status resp.msg = r.reason return resp - https_request = AbstractHTTPHandler.do_request_ # Copied from urllib2 with modifications for ssl -def build_opener(ssl_context = None, *handlers): +def build_opener(ssl_context=None, *handlers): + # type: (Optional[SSL.Context], *object) -> OpenerDirector """Create an opener object from a list of handlers. The opener will use several default handlers, including support @@ -118,9 +153,9 @@ def build_opener(ssl_context = None, *handlers): If any of the handlers passed as arguments are subclasses of the default handlers, the default handlers will not be used. """ - import types + def isclass(obj): - return isinstance(obj, types.ClassType) or hasattr(obj, "__bases__") + return isinstance(obj, type) or hasattr(obj, "__bases__") opener = OpenerDirector() default_classes = [ProxyHandler, UnknownHandler, HTTPHandler, @@ -144,7 +179,6 @@ def build_opener(ssl_context = None, *handlers): if HTTPSHandler not in skip: opener.add_handler(HTTPSHandler(ssl_context)) - for h in handlers: if isclass(h): h = h() diff --git a/M2Crypto/m2xmlrpclib.py b/M2Crypto/m2xmlrpclib.py index bb50a01..c7fe142 100644 --- a/M2Crypto/m2xmlrpclib.py +++ b/M2Crypto/m2xmlrpclib.py @@ -1,32 +1,47 @@ +from __future__ import absolute_import + """M2Crypto enhancement to xmlrpclib. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" -import base64, string, sys +import base64 -from xmlrpclib import * import M2Crypto -import SSL, httpslib, m2urllib -__version__ = M2Crypto.version +from M2Crypto import SSL, httpslib, m2urllib, six, util +if util.py27plus: + from typing import Any, AnyStr, Callable, Optional # noqa + +from M2Crypto.six.moves.xmlrpc_client import ProtocolError, Transport +# six.moves doesn't support star imports +if six.PY3: + from xmlrpc.client import * # noqa +else: + from xmlrpclib import * # noqa + +__version__ = M2Crypto.__version__ + class SSL_Transport(Transport): - user_agent = "M2Crypto_XMLRPC/%s - %s" % (__version__, Transport.user_agent) + user_agent = "M2Crypto_XMLRPC/%s - %s" % (__version__, + Transport.user_agent) def __init__(self, ssl_context=None, *args, **kw): - if getattr(Transport, '__init__', None) is not None: - Transport.__init__(self, *args, **kw) + # type: (Optional[SSL.Context], *Any, **Any) -> None + Transport.__init__(self, *args, **kw) if ssl_context is None: - self.ssl_ctx=SSL.Context('sslv23') + self.ssl_ctx = SSL.Context() else: - self.ssl_ctx=ssl_context + self.ssl_ctx = ssl_context def request(self, host, handler, request_body, verbose=0): + # type: (AnyStr, Callable, bytes, int) -> object # Handle username and password. user_passwd, host_port = m2urllib.splituser(host) _host, _port = m2urllib.splitport(host_port) - h = httpslib.HTTPS(_host, int(_port), ssl_context=self.ssl_ctx) + h = httpslib.HTTPSConnection(_host, int(_port), + ssl_context=self.ssl_ctx) if verbose: h.set_debuglevel(1) @@ -43,7 +58,7 @@ class SSL_Transport(Transport): # Authorisation. if user_passwd is not None: - auth=string.strip(base64.encodestring(user_passwd)) + auth = base64.encodestring(user_passwd).strip() h.putheader('Authorization', 'Basic %s' % auth) h.endheaders() @@ -58,8 +73,7 @@ class SSL_Transport(Transport): host + handler, errcode, errmsg, headers - ) + ) self.verbose = verbose return self.parse_response(h.getfile()) - diff --git a/M2Crypto/six.py b/M2Crypto/six.py new file mode 100644 index 0000000..8d9ac41 --- /dev/null +++ b/M2Crypto/six.py @@ -0,0 +1,950 @@ +# Copyright (c) 2010-2018 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Utilities for writing code that runs on Python 2 and 3""" + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.11.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("getoutput", "commands", "subprocess"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("splitvalue", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), + MovedAttribute("parse_http_list", "urllib2", "urllib.request"), + MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") + + +if PY3: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + unichr = chr + import struct + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +else: + def b(s): + return s + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + try: + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + finally: + value = None + tb = None + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + try: + raise tp, value, tb + finally: + tb = None +""") + + +if sys.version_info[:2] == (3, 2): + exec_("""def raise_from(value, from_value): + try: + if from_value is None: + raise value + raise value from from_value + finally: + value = None +""") +elif sys.version_info[:2] > (3, 2): + exec_("""def raise_from(value, from_value): + try: + raise value from from_value + finally: + value = None +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def ensure_binary(s, encoding='utf-8', errors='strict'): + """Coerce **s** to six.binary_type. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> encoded to `bytes` + - `bytes` -> `bytes` + """ + if isinstance(s, text_type): + return s.encode(encoding, errors) + elif isinstance(s, binary_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def ensure_str(s, encoding='utf-8', errors='strict'): + """Coerce *s* to `str`. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) + if PY2 and isinstance(s, text_type): + s = s.encode(encoding, errors) + elif PY3 and isinstance(s, binary_type): + s = s.decode(encoding, errors) + return s + + +def ensure_text(s, encoding='utf-8', errors='strict'): + """Coerce *s* to six.text_type. + + For Python 2: + - `unicode` -> `unicode` + - `str` -> `unicode` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if isinstance(s, binary_type): + return s.decode(encoding, errors) + elif isinstance(s, text_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + + +def python_2_unicode_compatible(klass): + """ + A decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/M2Crypto/threading.py b/M2Crypto/threading.py index 4cb8149..f9f2683 100644 --- a/M2Crypto/threading.py +++ b/M2Crypto/threading.py @@ -1,20 +1,25 @@ +from __future__ import absolute_import + """ -M2Crypto threading support, required for multithreaded applications. +M2Crypto threading support, required for multithreaded applications. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" # M2Crypto -import m2 +from M2Crypto import m2 + def init(): + # type: () -> None """ Initialize threading support. """ m2.threading_init() + def cleanup(): + # type: () -> None """ End and cleanup threading support. """ m2.threading_cleanup() - diff --git a/M2Crypto/util.py b/M2Crypto/util.py index 12103fc..9abf141 100644 --- a/M2Crypto/util.py +++ b/M2Crypto/util.py @@ -1,64 +1,81 @@ +from __future__ import absolute_import """ M2Crypto utility routines. - + + NOTHING IN THIS MODULE IS GUARANTEED TO BE STABLE, USED ONLY FOR + INTERNAL PURPOSES OF M2CRYPTO. + Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. - + Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004 OSAF. All Rights Reserved. """ +import binascii +import logging import sys -import m2 -class UtilError(Exception): pass +from M2Crypto import m2, py27plus, six +if py27plus: + from typing import Any, AnyStr, Optional, Tuple, Union # noqa + # see https://github.com/python/typeshed/issues/222 + AddrType = Union[Tuple[str, int], str] + +log = logging.getLogger('util') + + +class UtilError(Exception): + pass m2.util_init(UtilError) -def h2b(s): - import array, string - ar=array.array('c') - start=0 - if s[:2]=='0x': - start=2 - for i in range(start, len(s), 2): - num=string.atoi("%s"%(s[i:i+2],), 16) - ar.append(chr(num)) - return ar.tostring() def pkcs5_pad(data, blklen=8): - pad=(8-(len(data)%8)) - return data+chr(pad)*pad + # type: (str, int) -> str + pad = (8 - (len(data) % 8)) + return data + chr(pad) * pad + def pkcs7_pad(data, blklen): - if blklen>255: - raise ValueError, 'illegal block size' - pad=(blklen-(len(data)%blklen)) - return data+chr(pad)*pad + # type: (str, int) -> str + if blklen > 255: + raise ValueError('illegal block size') + pad = (blklen - (len(data) % blklen)) + return data + chr(pad) * pad + + +def bin_to_hex(b): + # type: (bytes) -> str + return six.ensure_text(binascii.b2a_base64(b)[:-1]) + def octx_to_num(x): - v = 0L - lx = len(x) - for i in range(lx): - v = v + ord(x[i]) * (256L ** (lx-i-1)) - return v + # type: (bytes) -> int + return int(binascii.hexlify(x), 16) + def genparam_callback(p, n, out=sys.stdout): - ch = ['.','+','*','\n'] + # type: (int, Any, file) -> None + ch = ['.', '+', '*', '\n'] out.write(ch[p]) out.flush() + def quiet_genparam_callback(p, n, out): + # type: (Any, Any, Any) -> None pass -def passphrase_callback(v, prompt1='Enter passphrase:', - prompt2='Verify passphrase:'): + +def passphrase_callback(v, prompt1='Enter passphrase:', + prompt2='Verify passphrase:'): + # type: (bool, str, str) -> Optional[str] from getpass import getpass while 1: try: - p1=getpass(prompt1) + p1 = getpass(prompt1) if v: - p2=getpass(prompt2) - if p1==p2: + p2 = getpass(prompt2) + if p1 == p2: break else: break @@ -66,6 +83,7 @@ def passphrase_callback(v, prompt1='Enter passphrase:', return None return p1 + def no_passphrase_callback(*args): + # type: (*Any) -> str return '' - diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..1eb138a --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,13 @@ +include SWIG/*.i +include SWIG/*.h +include SWIG/*.def +recursive-include tests *.py *.pem *.der *.b64 README *.pgp *.dat *.p7* *.crt *.txt +recursive-include doc * +recursive-include contrib * +include INSTALL.rst +include README.rst +include CHANGES +include epydoc.conf +include LICENCE +include SWIG/_m2crypto_wrap.c +include M2Crypto/m2crypto.py diff --git a/PKG-INFO b/PKG-INFO deleted file mode 100644 index 3972df5..0000000 --- a/PKG-INFO +++ /dev/null @@ -1,23 +0,0 @@ -Metadata-Version: 1.0 -Name: M2Crypto -Version: 0.21.1 -Summary: M2Crypto: A Python crypto and SSL toolkit -Home-page: http://chandlerproject.org/Projects/MeTooCrypto -Author: Heikki Toivonen -Author-email: heikki@osafoundation.org -License: BSD-style license -Description: M2Crypto is the most complete Python wrapper for OpenSSL featuring RSA, DSA, - DH, EC, HMACs, message digests, symmetric ciphers (including AES); SSL - functionality to implement clients and servers; HTTPS extensions to Python's - httplib, urllib, and xmlrpclib; unforgeable HMAC'ing AuthCookies for web - session management; FTP/TLS client and server; S/MIME; ZServerSSL: A HTTPS - server for Zope and ZSmime: An S/MIME messenger for Zope. M2Crypto can also be - used to provide SSL for Twisted. -Platform: any -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: C -Classifier: Programming Language :: Python -Classifier: Topic :: Security :: Cryptography -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/README b/README.rst similarity index 65% rename from README rename to README.rst index 99affa0..f0b3a27 100644 --- a/README +++ b/README.rst @@ -1,13 +1,15 @@ -========= - M2Crypto -========= - -:Maintainer: Heikki Toivonen -:Web-Site: http://chandlerproject.org/Projects/MeTooCrypto +======== +M2Crypto +======== +:Maintainer: Matěj Cepl +:Web-Site: https://gitlab.com/m2crypto/m2crypto +:Documentation: https://m2crypto.readthedocs.io/ +:Email list: m2crypto@lists.redcrew.org or http://redcrew.org/mailman/listinfo/m2crypto +:IRC channel: `#m2crypto`_ on Freenode M2Crypto = Python + OpenSSL + SWIG ------------------------------------- +---------------------------------- M2Crypto is a crypto and SSL toolkit for Python. @@ -18,7 +20,7 @@ M2Crypto comes with the following: - **RSA**, **DSA**, **DH**, **HMACs**, **message digests**, **symmetric ciphers** including **AES**, -- **SSL** functionality to implement **clients and servers**. +- **TLS** functionality to implement **clients and servers**. - **Example SSL client and server programs**, which are variously **threading**, **forking** or based on **non-blocking socket IO**. @@ -35,9 +37,15 @@ M2Crypto comes with the following: - **ZSmime**: An S/MIME messenger for **Zope**. +We care a lot about stable API and all Python methods should be +preserved, note however that ``m2.`` namespace is considered internal to +the library and it doesn't have to be preserved. If however some change +to it breaks your app, let us know and we will try to make things +working for you. + - And much more. -M2Crypto is released under a very liberal BSD-style licence. See +M2Crypto is released under a very liberal MIT licence. See LICENCE for details. To install, see the file INSTALL. @@ -52,10 +60,12 @@ Note these caveats: Python side and other objects on the C side, and these may change between OpenSSL versions. (Multiple free's lead to crashes very quickly, so these should be relatively rare.) - + - No memory locking/clearing for keys, passphrases, etc. because AFAIK Python does not provide the features needed. On the C (OpenSSL) side things are cleared when the Python objects are deleted. - Have fun! Your feedback is welcome. + +.. _`#m2crypto`: + irc://Freenode/#m2crypto diff --git a/SWIG/Makefile b/SWIG/Makefile index 7d73a3b..9a3bd56 100644 --- a/SWIG/Makefile +++ b/SWIG/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile 299 2005-06-09 17:32:28Z heikki $ +# $Id$ CFLAGS = -DTHREADING -g INCLUDE = -I/usr/local/include -I. @@ -17,8 +17,8 @@ all: _m2crypto _m2crypto: _m2crypto.i swig -python -shadow _m2crypto.i cc -c -fpic $(CFLAGS) $(INCLUDE) $(PYINCLUDE) _m2crypto_wrap.c - ld -Bshareable -o __m2crypto.so _m2crypto_wrap.o $(LIBS) - cp _m2crypto.py __m2crypto.so ../M2Crypto + ld -Bshareable -o _m2crypto.so _m2crypto_wrap.o $(LIBS) + cp m2crypto.py _m2crypto.so ../M2Crypto clean: rm -f *_wrap* *.o *.so _*.py *.pyc diff --git a/SWIG/Makefile.mw b/SWIG/Makefile.mw deleted file mode 100644 index 02f5ae5..0000000 --- a/SWIG/Makefile.mw +++ /dev/null @@ -1,34 +0,0 @@ -# $Id: Makefile.mw 299 2005-06-09 17:32:28Z heikki $ - -# Python -PYFLAGS=-D__WIN32__ -DHAVE_CONFIG_H -Ic:/pkg/py23/include -PYLIB=c:/pkg/py23/libs/libpython23.a -PYINCLUDE=-Ic:/pkg/py23/include - -# OpenSSL -SSLINCLUDE=-Ic:/pkg/openssl/include -SSLLIB=c:/pkg/openssl/lib/libssl32.a c:/pkg/openssl/lib/libeay32.a - -# Windoze -INCLUDE=$(PYINCLUDE) $(SSLINCLUDE) -I. -LIBS=$(PYLIB) $(SSLLIB) - -SWIG=c:/pkg/swig/swig.exe -SWIGFLAGS=-shadow -python #-verbose - -CP=cp - -all: swig - -swig: _m2crypto.i - $(SWIG) $(SWIGFLAGS) _m2crypto.i - gcc -c -DTHREADING -g $(INCLUDE) _m2crypto_wrap.c - dllwrap --dllname __m2crypto.pyd --driver-name gcc \ - --def _m2crypto.def -o __m2crypto.pyd _m2crypto_wrap.o \ - -s --entry _DllMain@12 --target=i386-mingw32 $(LIBS) - $(CP) _m2crypto.py ..\M2Crypto - $(CP) __m2crypto.pyd ..\M2Crypto - -clean: - del *wrap* *.o *.dll *.exp *.ilk *.pdb *.lib _*.py *.pyc - diff --git a/SWIG/Makefile.osx b/SWIG/Makefile.osx deleted file mode 100644 index a8508a6..0000000 --- a/SWIG/Makefile.osx +++ /dev/null @@ -1,32 +0,0 @@ -# $Id: Makefile.osx 299 2005-06-09 17:32:28Z heikki $ - -# 2003-10-26, ngps: Beware any mixup of tabs and spaces caused by me. - -WHICHOPENSSL = /usr/local - -CFLAGS = -DTHREADING -DHAVE_CONFIG -g -O2 -INCLUDE = -I. -I/Library/Frameworks/Python.framework/Headers -LIBS = $(WHICHOPENSSL)/lib/libssl.a \ - $(WHICHOPENSSL)/lib/libcrypto.a \ - /Library/Frameworks/Python.framework/python - -all: __m2crypto.so - -_m2crypto_wrap.c: _m2crypto.i - swig -shadow -python _m2crypto.i - -_m2crypto_wrap.o: _m2crypto_wrap.c - cc -c $(CFLAGS) $(INCLUDES) _m2crypto_wrap.c - -__m2crypto.so: _m2crypto_wrap.o - cc -bundle _m2crypto_wrap.o $(LIBS) -lcc_dynamic -o __m2crypto.so - cp __m2crypto.so ../M2Crypto - -clean: - rm -f *_wrap* *.o *.so _*.py *.pyc - -versions: - python -c "import sys, os; \ - print os.popen('gcc --version').readlines()[0],; \ - print 'Python '+sys.version.split()[0]; \ - print os.popen('$(WHICHOPENSSL)/bin/openssl version').readlines()[0]" diff --git a/SWIG/_aes.i b/SWIG/_aes.i index be0af87..ea36167 100644 --- a/SWIG/_aes.i +++ b/SWIG/_aes.i @@ -1,5 +1,5 @@ /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */ -/* $Id: _aes.i 721 2010-02-13 06:30:33Z heikki $ */ +/* $Id$ */ %{ #include @@ -28,8 +28,11 @@ extern EVP_CIPHER const *EVP_aes_256_ctr(void); AES_KEY *aes_new(void) { AES_KEY *key; - if (!(key = (AES_KEY *)PyMem_Malloc(sizeof(AES_KEY)))) - PyErr_SetString(PyExc_MemoryError, "aes_new"); + if (!(key = (AES_KEY *)PyMem_Malloc(sizeof(AES_KEY)))) { + PyErr_SetString(PyExc_MemoryError, + "Insufficient memory for AES key."); + return NULL; + } return key; } @@ -38,34 +41,34 @@ void AES_free(AES_KEY *key) { } /* -// op == 0: decrypt -// otherwise: encrypt (Python code will supply the value 1.) +// op == 0: encrypt +// otherwise: decrypt (Python code will supply the value 1.) */ PyObject *AES_set_key(AES_KEY *key, PyObject *value, int bits, int op) { - const void *vbuf; + char *vbuf; Py_ssize_t vlen; - if (PyObject_AsReadBuffer(value, &vbuf, &vlen) == -1) + if (PyBytes_AsStringAndSize(value, &vbuf, &vlen) == -1) return NULL; if (op == 0) - AES_set_encrypt_key(vbuf, bits, key); + AES_set_encrypt_key((const unsigned char *)vbuf, bits, key); else - AES_set_decrypt_key(vbuf, bits, key); - Py_INCREF(Py_None); - return Py_None; + AES_set_decrypt_key((const unsigned char *)vbuf, bits, key); + Py_RETURN_NONE; } /* -// op == 0: decrypt -// otherwise: encrypt (Python code will supply the value 1.) +// op == 0: encrypt +// otherwise: decrypt (Python code will supply the value 1.) */ PyObject *AES_crypt(const AES_KEY *key, PyObject *in, int outlen, int op) { - const void *buf; + char *buf; Py_ssize_t len; unsigned char *out; + PyObject *res; - if (PyObject_AsReadBuffer(in, &buf, &len) == -1) + if (PyBytes_AsStringAndSize(in, &buf, &len) == -1) return NULL; if (!(out=(unsigned char *)PyMem_Malloc(outlen))) { @@ -73,10 +76,12 @@ PyObject *AES_crypt(const AES_KEY *key, PyObject *in, int outlen, int op) { return NULL; } if (op == 0) - AES_encrypt((const unsigned char *)in, out, key); + AES_encrypt((const unsigned char *)buf, out, key); else - AES_decrypt((const unsigned char *)in, out, key); - return PyString_FromStringAndSize((char*)out, outlen); + AES_decrypt((const unsigned char *)buf, out, key); + res = PyBytes_FromStringAndSize((char*)out, outlen); + PyMem_Free(out); + return res; } int AES_type_check(AES_KEY *key) { diff --git a/SWIG/_asn1.i b/SWIG/_asn1.i index 6dab7ff..b51b33f 100644 --- a/SWIG/_asn1.i +++ b/SWIG/_asn1.i @@ -4,7 +4,7 @@ ** Portions created by Open Source Applications Foundation (OSAF) are ** Copyright (C) 2004 OSAF. All Rights Reserved. */ -/* $Id: _asn1.i 696 2009-07-28 03:43:19Z heikki $ */ +/* $Id$ */ %{ #include @@ -14,7 +14,7 @@ %apply Pointer NONNULL { ASN1_OBJECT * }; %apply Pointer NONNULL { ASN1_STRING * }; %apply Pointer NONNULL { ASN1_INTEGER * }; -%apply Pointer NONNULL { ASN1_UTCTIME * }; +%apply Pointer NONNULL { ASN1_TIME * }; %rename(asn1_object_new) ASN1_OBJECT_new; extern ASN1_OBJECT *ASN1_OBJECT_new( void ); @@ -24,10 +24,8 @@ extern ASN1_OBJECT *ASN1_OBJECT_create( int, unsigned char *, int, const char *, extern void ASN1_OBJECT_free( ASN1_OBJECT *); %rename(i2d_asn1_object) i2d_ASN1_OBJECT; extern int i2d_ASN1_OBJECT( ASN1_OBJECT *, unsigned char **); -%rename(c2i_asn1_object) c2i_ASN1_OBJECT; -extern ASN1_OBJECT *c2i_ASN1_OBJECT( ASN1_OBJECT **, CONST098 unsigned char **, long); %rename(d2i_asn1_object) d2i_ASN1_OBJECT; -extern ASN1_OBJECT *d2i_ASN1_OBJECT( ASN1_OBJECT **, CONST098 unsigned char **, long); +extern ASN1_OBJECT *d2i_ASN1_OBJECT( ASN1_OBJECT **, const unsigned char **, long); %rename(asn1_bit_string_new) ASN1_BIT_STRING_new; extern ASN1_BIT_STRING *ASN1_BIT_STRING_new( void ); @@ -37,18 +35,20 @@ extern ASN1_STRING *ASN1_STRING_new( void ); %rename(asn1_string_free) ASN1_STRING_free; extern void ASN1_STRING_free( ASN1_STRING *); -%typemap(in) (const void *, int) { - if (PyString_Check($input)) { +%typemap(in) (const void *, int) { + if (PyBytes_Check($input)) { Py_ssize_t len; - $1 = PyString_AsString($input); - len = PyString_Size($input); + $1 = PyBytes_AsString($input); + len = PyBytes_Size($input); + if (len > INT_MAX) { PyErr_SetString(PyExc_ValueError, "object too large"); return NULL; } $2 = len; - } else { + } + else { PyErr_SetString(PyExc_TypeError, "expected string"); return NULL; } @@ -66,19 +66,19 @@ extern int ASN1_STRING_print(BIO *, ASN1_STRING *); %rename(asn1_string_print_ex) ASN1_STRING_print_ex; extern int ASN1_STRING_print_ex(BIO *, ASN1_STRING *, unsigned long); -%rename(asn1_utctime_new) ASN1_UTCTIME_new; -extern ASN1_UTCTIME *ASN1_UTCTIME_new( void ); -%rename(asn1_utctime_free) ASN1_UTCTIME_free; -extern void ASN1_UTCTIME_free(ASN1_UTCTIME *); -%rename(asn1_utctime_check) ASN1_UTCTIME_check; -extern int ASN1_UTCTIME_check(ASN1_UTCTIME *); -%rename(asn1_utctime_set) ASN1_UTCTIME_set; -extern ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *, long); -%rename(asn1_utctime_set_string) ASN1_UTCTIME_set_string; -extern int ASN1_UTCTIME_set_string(ASN1_UTCTIME *, CONST098 char *); -%rename(asn1_utctime_print) ASN1_UTCTIME_print; -%threadallow ASN1_UTCTIME_print; -extern int ASN1_UTCTIME_print(BIO *, ASN1_UTCTIME *); +%rename(asn1_time_new) ASN1_TIME_new; +extern ASN1_TIME *ASN1_TIME_new( void ); +%rename(asn1_time_free) ASN1_TIME_free; +extern void ASN1_TIME_free(ASN1_TIME *); +%rename(asn1_time_check) ASN1_TIME_check; +extern int ASN1_TIME_check(ASN1_TIME *); +%rename(asn1_time_set) ASN1_TIME_set; +extern ASN1_TIME *ASN1_TIME_set(ASN1_TIME *, long); +%rename(asn1_time_set_string) ASN1_TIME_set_string; +extern int ASN1_TIME_set_string(ASN1_TIME *, const char *); +%rename(asn1_time_print) ASN1_TIME_print; +%threadallow ASN1_TIME_print; +extern int ASN1_TIME_print(BIO *, ASN1_TIME *); %rename(asn1_integer_new) ASN1_INTEGER_new; extern ASN1_INTEGER *ASN1_INTEGER_new( void ); @@ -92,8 +92,12 @@ extern int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *); %constant int ASN1_STRFLGS_ESC_MSB = 4; %constant int ASN1_STRFLGS_ESC_QUOTE = 8; %constant int ASN1_STRFLGS_UTF8_CONVERT = 0x10; +%constant int ASN1_STRFLGS_IGNORE_TYPE = 0x20; +%constant int ASN1_STRFLGS_SHOW_TYPE = 0x40; +%constant int ASN1_STRFLGS_DUMP_ALL = 0x80; %constant int ASN1_STRFLGS_DUMP_UNKNOWN = 0x100; %constant int ASN1_STRFLGS_DUMP_DER = 0x200; + %constant int ASN1_STRFLGS_RFC2253 = (ASN1_STRFLGS_ESC_2253 | \ ASN1_STRFLGS_ESC_CTRL | \ ASN1_STRFLGS_ESC_MSB | \ @@ -102,8 +106,8 @@ extern int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *); ASN1_STRFLGS_DUMP_DER); %inline %{ -/* ASN1_UTCTIME_set_string () is a macro */ -int asn1_utctime_type_check(ASN1_UTCTIME *ASN1_UTCTIME) { +/* ASN1_TIME_set_string () is a macro */ +int asn1_time_type_check(ASN1_TIME *ASN1_TIME) { return 1; } @@ -115,16 +119,14 @@ PyObject *asn1_integer_get(ASN1_INTEGER *asn1) { bn = ASN1_INTEGER_to_BN(asn1, NULL); if (!bn){ - PyErr_SetString( - PyExc_RuntimeError, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(PyExc_RuntimeError); return NULL; } hex = BN_bn2hex(bn); if (!hex){ - PyErr_SetString( - PyExc_RuntimeError, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(PyExc_RuntimeError); BN_free(bn); return NULL; } @@ -142,15 +144,23 @@ int asn1_integer_set(ASN1_INTEGER *asn1, PyObject *value) { BIGNUM *bn = NULL; PyObject *fmt, *args, *hex; - if (PyInt_Check(value)) - return ASN1_INTEGER_set(asn1, PyInt_AS_LONG(value)); +/* Despite all hopes to the contrary, we cannot survive here with + * PyLong_AsLong shims as provided in + * /usr/include/python2.7/longobject.h. + */ + long val = PyLong_AsLong(value); + if (val >= 0) { + return ASN1_INTEGER_set(asn1, val); + } else { + PyErr_Clear(); + } if (!PyLong_Check(value)){ PyErr_SetString(PyExc_TypeError, "expected int or long"); return 0; } - fmt = PyString_FromString("%x"); + fmt = PyUnicode_FromString("%x"); if (!fmt) return 0; @@ -165,7 +175,7 @@ int asn1_integer_set(ASN1_INTEGER *asn1, PyObject *value) { Py_INCREF(value); PyTuple_SET_ITEM(args, 0, value); - hex = PyString_Format(fmt, args); + hex = PyUnicode_Format(fmt, args); if (!hex){ PyErr_SetString(PyExc_RuntimeError, "PyString_Format() failed"); @@ -177,9 +187,8 @@ int asn1_integer_set(ASN1_INTEGER *asn1, PyObject *value) { Py_DECREF(fmt); Py_DECREF(args); - if (BN_hex2bn(&bn, PyString_AsString(hex)) <= 0){ - PyErr_SetString( - PyExc_RuntimeError, ERR_reason_error_string(ERR_get_error())); + if (BN_hex2bn(&bn, PyUnicode_AsUTF8(hex)) <= 0){ + m2_PyErr_Msg(PyExc_RuntimeError); Py_DECREF(hex); return 0; } @@ -187,9 +196,8 @@ int asn1_integer_set(ASN1_INTEGER *asn1, PyObject *value) { Py_DECREF(hex); if (!BN_to_ASN1_INTEGER(bn, asn1)){ - PyErr_SetString( - PyExc_RuntimeError, ERR_reason_error_string(ERR_get_error())); - BN_free(bn); + m2_PyErr_Msg(PyExc_RuntimeError); + BN_free(bn); return 0; } diff --git a/SWIG/_bio.i b/SWIG/_bio.i index 441ba06..e85a275 100644 --- a/SWIG/_bio.i +++ b/SWIG/_bio.i @@ -4,8 +4,9 @@ * Portions created by Open Source Applications Foundation (OSAF) are * Copyright (C) 2004-2005 OSAF. All Rights Reserved. * Author: Heikki Toivonen -*/ -/* $Id: _bio.i 695 2009-07-24 06:37:01Z heikki $ */ + * + * Copyright 2018 Daniel Wozniak. All Rights Reserved.*/ +/* $Id$ */ %{ #include @@ -31,15 +32,8 @@ extern BIO_METHOD *BIO_f_cipher(void); extern BIO *BIO_new(BIO_METHOD *); %rename(bio_new_socket) BIO_new_socket; extern BIO *BIO_new_socket(int, int); -%rename(bio_new_fd) BIO_new_fd; -extern BIO *BIO_new_fd(int, int); -%rename(bio_new_fp) BIO_new_fp; -extern BIO *BIO_new_fp(FILE *, int); -%rename(bio_new_file) BIO_new_file; -extern BIO *BIO_new_file(const char *, const char *); -%rename(bio_free) BIO_free; -%threadallow BIO_free; -extern int BIO_free(BIO *); +%rename(bio_new_fd) BIO_new_pyfd; +%rename(bio_new_pyfd) BIO_new_pyfd; %rename(bio_free_all) BIO_free_all; %threadallow BIO_free_all; extern void BIO_free_all(BIO *); @@ -51,6 +45,9 @@ extern BIO *BIO_push(BIO *, BIO *); %rename(bio_pop) BIO_pop; extern BIO *BIO_pop(BIO *); +%rename(bio_eof) BIO_eof; +extern int BIO_eof(BIO *); + %constant int bio_noclose = BIO_NOCLOSE; %constant int bio_close = BIO_CLOSE; %constant int BIO_FLAGS_READ = 0x01; @@ -60,12 +57,71 @@ extern BIO *BIO_pop(BIO *); %constant int BIO_FLAGS_SHOULD_RETRY = 0x08; %constant int BIO_FLAGS_MEM_RDONLY = 0x200; +%warnfilter(454) _bio_err; %inline %{ static PyObject *_bio_err; + +void pyfd_init(void); + void bio_init(PyObject *bio_err) { Py_INCREF(bio_err); _bio_err = bio_err; + pyfd_init(); +} + +int bio_free(BIO *bio) { + int ret; + + Py_BEGIN_ALLOW_THREADS + ret = BIO_free(bio); + Py_END_ALLOW_THREADS + if (ret == 0) { + m2_PyErr_Msg(_bio_err); + } + return ret; +} + +BIO * bio_new_file(const char *filename, const char *mode) { + BIO *ret; + + Py_BEGIN_ALLOW_THREADS + ret = BIO_new_file(filename, mode); + Py_END_ALLOW_THREADS + + if (ret == NULL) { + m2_PyErr_Msg(_bio_err); + } + + return ret; +} + +BIO *bio_new_pyfile(PyObject *pyfile, int bio_close) { + FILE *fp = NULL; + BIO *bio = NULL; + + fp = PyFile_AsFile(pyfile); + + bio = BIO_new_fp(fp, bio_close); + + /* returns NULL if error occurred */ + if (bio == NULL) { + /* Find out the name of the file so we can have good error + * message. */ + PyObject *pyname = m2_PyFile_Name(pyfile); + char *name = PyBytes_AsString(pyname); + + if (name == NULL) { + PyErr_Format(_bio_err, + "Opening of the new BIO on file failed!"); + } + else { + PyErr_Format(_bio_err, + "Opening of the new BIO on file %s failed!", name); + } + Py_DECREF(pyname); + } + return bio; } PyObject *bio_read(BIO *bio, int num) { @@ -83,13 +139,14 @@ PyObject *bio_read(BIO *bio, int num) { if (r < 0) { PyMem_Free(buf); if (ERR_peek_error()) { - PyErr_SetString(_bio_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_bio_err); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } - blob = PyString_FromStringAndSize(buf, r); + + blob = PyBytes_FromStringAndSize(buf, r); + PyMem_Free(buf); return blob; } @@ -106,23 +163,24 @@ PyObject *bio_gets(BIO *bio, int num) { Py_BEGIN_ALLOW_THREADS r = BIO_gets(bio, buf, num); Py_END_ALLOW_THREADS - if (r < 0) { + if (r < 1) { PyMem_Free(buf); if (ERR_peek_error()) { - PyErr_SetString(_bio_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_bio_err); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } - blob = PyString_FromStringAndSize(buf, r); + + blob = PyBytes_FromStringAndSize(buf, r); + PyMem_Free(buf); return blob; } int bio_write(BIO *bio, PyObject *from) { const void *fbuf; - int flen, ret; + int flen = 0, ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return -1; @@ -132,7 +190,8 @@ int bio_write(BIO *bio, PyObject *from) { Py_END_ALLOW_THREADS if (ret < 0) { if (ERR_peek_error()) { - PyErr_SetString(_bio_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_bio_err); + return -1; } } return ret; @@ -166,6 +225,10 @@ int bio_seek(BIO *bio, int offset) { return (int)BIO_seek(bio, offset); } +int bio_tell(BIO* bio) { + return BIO_tell(bio); +} + void bio_set_flags(BIO *bio, int flags) { BIO_set_flags(bio, flags); } @@ -174,6 +237,11 @@ int bio_get_flags(BIO *bio) { return BIO_get_flags(bio); } +/* + * sets the cipher of BIO @param b to c using key @param key and IV @iv. + * @param enc should be set to 1 for encryption and zero to decryption. + * + */ PyObject *bio_set_cipher(BIO *b, EVP_CIPHER *c, PyObject *key, PyObject *iv, int op) { const void *kbuf, *ibuf; Py_ssize_t klen, ilen; @@ -184,8 +252,7 @@ PyObject *bio_set_cipher(BIO *b, EVP_CIPHER *c, PyObject *key, PyObject *iv, int BIO_set_cipher(b, (const EVP_CIPHER *)c, (unsigned char *)kbuf, (unsigned char *)ibuf, op); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } int bio_set_mem_eof_return(BIO *b, int v) { @@ -197,6 +264,7 @@ int bio_get_fd(BIO *bio) { } %} +%warnfilter(454) methods_fdp; %threadallow bio_do_handshake; %inline %{ int bio_do_handshake(BIO *bio) { @@ -223,5 +291,255 @@ int bio_should_read(BIO* a) { int bio_should_write(BIO* a) { return BIO_should_write(a); } + +/* Macros for things not defined before 1.1.0 */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static BIO_METHOD * +BIO_meth_new( int type, const char *name ) +{ + BIO_METHOD *method = malloc( sizeof(BIO_METHOD) ); + memset( method, 0, sizeof(BIO_METHOD) ); + + method->type = type; + method->name = name; + + return method; +} + +static void +BIO_meth_free( BIO_METHOD *meth ) +{ + if ( meth == NULL ) { + return; + } + + free(meth); +} +#define BIO_meth_set_write(m, f) (m)->bwrite = (f) +#define BIO_meth_set_read(m, f) (m)->bread = (f) +#define BIO_meth_set_puts(m, f) (m)->bputs = (f) +#define BIO_meth_set_gets(m, f) (m)->bgets = (f) +#define BIO_meth_set_ctrl(m, f) (m)->ctrl = (f) +#define BIO_meth_set_create(m, f) (m)->create = (f) +#define BIO_meth_set_destroy(m, f) (m)->destroy = (f) +#define BIO_set_shutdown(b, x) (b)->shutdown = x +#define BIO_get_shutdown(b) (b)->shutdown +#define BIO_set_init(b, x) b->init = x +#define BIO_get_init(b) (b)->init +#define BIO_set_data(b, x) b->ptr = x +#define BIO_clear_flags(b, x) b->flags &= ~(x) +#define BIO_get_data(b) b->ptr +#endif + +/* implment custom BIO_s_pyfd */ + +#ifdef _WIN32 +# define clear_sys_error() SetLastError(0) +/* Linux doesn't use underscored calls yet */ +# define open(p, f, m) _open(p, f, m) +# define read(f, b, n) _read(f, b, n) +# define write(f, b, n) _write(f, b, n) +# define close(f) _close(f) +# define lseek(fd, o, w) _lseek(fd, o, w) +#else +# define clear_sys_error() errno=0 +#endif + +typedef struct pyfd_struct { + int fd; +} BIO_PYFD_CTX; + +/* Setting up methods_fdp */ +static BIO_METHOD *methods_fdp; + +static int pyfd_write(BIO *b, const char *in, int inl) { + int ret, fd; + + if (BIO_get_fd(b, &fd) == -1) { + PyErr_SetString(_bio_err, "BIO has not been initialized."); + return -1; + } + clear_sys_error(); + ret = write(fd, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_write(b); + } + return ret; +} + +static int pyfd_read(BIO *b, char *out, int outl) { + int ret = 0, fd; + + if (BIO_get_fd(b, &fd) == -1) { + PyErr_SetString(_bio_err, "BIO has not been initialized."); + return -1; + } + if (out != NULL) { + clear_sys_error(); + ret = read(fd, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_read(b); + } + } + return ret; +} + +static int pyfd_puts(BIO *bp, const char *str) { + int n, ret; + + n = strlen(str); + ret = pyfd_write(bp, str, n); + return ret; +} + +static int pyfd_gets(BIO *bp, char *buf, int size) { + int ret = 0; + char *ptr = buf; + char *end = buf + size - 1; + + /* See + https://github.com/openssl/openssl/pull/3442 + We were here just repeating a bug from OpenSSL + */ + while (ptr < end && pyfd_read(bp, ptr, 1) > 0) { + if (*ptr++ == '\n') + break; + } + + ptr[0] = '\0'; + + if (buf[0] != '\0') + ret = strlen(buf); + return ret; +} + +static int pyfd_new(BIO* b) { + BIO_PYFD_CTX* ctx; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return 0; + + ctx->fd = -1; + + BIO_set_data(b, ctx); + BIO_set_shutdown(b, 0); + BIO_set_init(b, 1); + + return 1; + } + +static int pyfd_free(BIO* b) { + BIO_PYFD_CTX* ctx; + + if (b == 0) + return 0; + + ctx = BIO_get_data(b); + if (ctx == NULL) + return 0; + + if (BIO_get_shutdown(b) && BIO_get_init(b)) + close(ctx->fd); + + BIO_set_data(b, NULL); + BIO_set_shutdown(b, 0); + BIO_set_init(b, 0); + + OPENSSL_free(ctx); + + return 1; +} + +static long pyfd_ctrl(BIO *b, int cmd, long num, void *ptr) { + BIO_PYFD_CTX* ctx; + int *ip; + long ret = 1; + + ctx = BIO_get_data(b); + if (ctx == NULL) + return 0; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + case BIO_C_FILE_SEEK: + ret = (long)lseek(ctx->fd, num, 0); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = (long)lseek(ctx->fd, 0, 1); + break; + case BIO_C_SET_FD: + pyfd_free(b); + if (*((int *)ptr) > -1) { + if (!pyfd_new(b) || !(ctx = BIO_get_data(b))) + return 0; + ctx->fd = *((int *)ptr); + BIO_set_shutdown(b, (int)num); + BIO_set_init(b, 1); + } + break; + case BIO_C_GET_FD: + if (BIO_get_init(b)) { + ip = (int *)ptr; + if (ip != NULL) + *ip = ctx->fd; + ret = ctx->fd; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = BIO_get_shutdown(b); + break; + case BIO_CTRL_SET_CLOSE: + BIO_set_shutdown(b, (int)num); + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +void pyfd_init(void) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + methods_fdp = BIO_meth_new( + BIO_get_new_index()|BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK, + "python file descriptor"); +#else + methods_fdp = BIO_meth_new( + 100 |BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK, + "python file descriptor"); +#endif + + BIO_meth_set_write(methods_fdp, pyfd_write); + BIO_meth_set_read(methods_fdp, pyfd_read); + BIO_meth_set_puts(methods_fdp, pyfd_puts); + BIO_meth_set_gets(methods_fdp, pyfd_gets); + BIO_meth_set_ctrl(methods_fdp, pyfd_ctrl); + BIO_meth_set_create(methods_fdp, pyfd_new); + BIO_meth_set_destroy(methods_fdp, pyfd_free); +} + +BIO* BIO_new_pyfd(int fd, int close_flag) { + BIO *ret; + + ret = BIO_new(methods_fdp); + BIO_set_fd(ret, fd, close_flag); + return ret; + } %} diff --git a/SWIG/_bn.i b/SWIG/_bn.i old mode 100755 new mode 100644 index a3b73c4..18dc154 --- a/SWIG/_bn.i +++ b/SWIG/_bn.i @@ -17,27 +17,32 @@ %inline %{ PyObject *bn_rand(int bits, int top, int bottom) { - BIGNUM rnd; + BIGNUM* rnd; PyObject *ret; char *randhex; - - BN_init(&rnd); - if (!BN_rand(&rnd, bits, top, bottom)) { + + rnd = BN_new(); + if (rnd == NULL) { + m2_PyErr_Msg(PyExc_Exception); + return NULL; + } + + if (!BN_rand(rnd, bits, top, bottom)) { /*Custom errors?*/ - PyErr_SetString(PyExc_Exception, ERR_reason_error_string(ERR_get_error())); - BN_free(&rnd); + m2_PyErr_Msg(PyExc_Exception); + BN_free(rnd); return NULL; } - - randhex = BN_bn2hex(&rnd); + + randhex = BN_bn2hex(rnd); if (!randhex) { /*Custom errors?*/ - PyErr_SetString(PyExc_Exception, ERR_reason_error_string(ERR_get_error())); - BN_free(&rnd); + m2_PyErr_Msg(PyExc_Exception); + BN_free(rnd); return NULL; } - BN_free(&rnd); - + BN_free(rnd); + ret = PyLong_FromString(randhex, NULL, 16); OPENSSL_free(randhex); return ret; @@ -46,15 +51,18 @@ PyObject *bn_rand(int bits, int top, int bottom) PyObject *bn_rand_range(PyObject *range) { - BIGNUM rnd; + BIGNUM* rnd; BIGNUM *rng = NULL; PyObject *ret, *tuple; PyObject *format, *rangePyString; - char *randhex, *rangehex; - + char *randhex; /* PyLong_FromString is unhappy with const */ + const char *rangehex; + /* Wow, it's a lot of work to convert into a hex string in C! */ - format = PyString_FromString("%x"); + format = PyUnicode_FromString("%x"); + if (!format) { + PyErr_SetString(PyExc_RuntimeError, "Cannot create Python string '%x'"); return NULL; } tuple = PyTuple_New(1); @@ -65,47 +73,53 @@ PyObject *bn_rand_range(PyObject *range) } Py_INCREF(range); PyTuple_SET_ITEM(tuple, 0, range); - rangePyString = PyString_Format(format, tuple); + + rangePyString = PyUnicode_Format(format, tuple); + if (!rangePyString) { - PyErr_SetString(PyExc_Exception, "PyString_Format failed"); + PyErr_SetString(PyExc_Exception, "String Format failed"); Py_DECREF(format); Py_DECREF(tuple); - return NULL; + return NULL; } Py_DECREF(format); Py_DECREF(tuple); - rangehex = PyString_AsString(rangePyString); - + + rangehex = (const char*)PyUnicode_AsUTF8(rangePyString); + if (!BN_hex2bn(&rng, rangehex)) { /*Custom errors?*/ - PyErr_SetString(PyExc_Exception, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(PyExc_Exception); Py_DECREF(rangePyString); - return NULL; + return NULL; } Py_DECREF(rangePyString); - - BN_init(&rnd); - if (!BN_rand_range(&rnd, rng)) { + if (!(rnd = BN_new())) { + PyErr_SetString(PyExc_MemoryError, "bn_rand_range"); + return NULL; + } + + if (!BN_rand_range(rnd, rng)) { /*Custom errors?*/ - PyErr_SetString(PyExc_Exception, ERR_reason_error_string(ERR_get_error())); - BN_free(&rnd); + m2_PyErr_Msg(PyExc_Exception); + BN_free(rnd); BN_free(rng); - return NULL; - } + return NULL; + } BN_free(rng); - randhex = BN_bn2hex(&rnd); + randhex = BN_bn2hex(rnd); if (!randhex) { /*Custom errors?*/ - PyErr_SetString(PyExc_Exception, ERR_reason_error_string(ERR_get_error())); - BN_free(&rnd); + m2_PyErr_Msg(PyExc_Exception); + BN_free(rnd); return NULL; } - BN_free(&rnd); - + BN_free(rnd); + ret = PyLong_FromString(randhex, NULL, 16); OPENSSL_free(randhex); return ret; diff --git a/SWIG/_dh.i b/SWIG/_dh.i index 675b39f..398f418 100644 --- a/SWIG/_dh.i +++ b/SWIG/_dh.i @@ -1,5 +1,5 @@ /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */ -/* $Id: _dh.i 695 2009-07-24 06:37:01Z heikki $ */ +/* $Id$ */ %{ #include @@ -32,6 +32,7 @@ extern int DHparams_print(BIO *, const DH *); %constant DH_GENERATOR_2 = 2; %constant DH_GENERATOR_5 = 5; +%warnfilter(454) _dh_err; %inline %{ static PyObject *_dh_err; @@ -53,26 +54,35 @@ DH *dh_read_parameters(BIO *bio) { return PEM_read_bio_DHparams(bio, NULL, NULL, NULL); } -void gendh_callback(int p, int n, void *arg) { - PyObject *argv, *ret, *cbfunc; - - cbfunc = (PyObject *)arg; - argv = Py_BuildValue("(ii)", p, n); - ret = PyEval_CallObject(cbfunc, argv); - PyErr_Clear(); - Py_DECREF(argv); - Py_XDECREF(ret); -} - DH *dh_generate_parameters(int plen, int g, PyObject *pyfunc) { DH *dh; + BN_GENCB *gencb; + int ret; + + if ((gencb=BN_GENCB_new()) == NULL) { + m2_PyErr_Msg(_dh_err); + return NULL; + } + + if ((dh=DH_new()) == NULL) { + m2_PyErr_Msg(_dh_err); + BN_GENCB_free(gencb); + return NULL; + } + + BN_GENCB_set(gencb, bn_gencb_callback, (void *)pyfunc); Py_INCREF(pyfunc); - dh = DH_generate_parameters(plen, g, gendh_callback, (void *)pyfunc); + ret = DH_generate_parameters_ex(dh, plen, g, gencb); Py_DECREF(pyfunc); - if (!dh) - PyErr_SetString(_dh_err, ERR_reason_error_string(ERR_get_error())); - return dh; + BN_GENCB_free(gencb); + + if (ret) + return dh; + + m2_PyErr_Msg(_dh_err); + DH_free(dh); + return NULL; } /* Note return value shenanigan. */ @@ -84,7 +94,7 @@ int dh_check(DH *dh) { PyObject *dh_compute_key(DH *dh, PyObject *pubkey) { const void *pkbuf; - int pklen, klen; + int pklen = 0, klen; void *key; BIGNUM *pk; PyObject *ret; @@ -93,7 +103,7 @@ PyObject *dh_compute_key(DH *dh, PyObject *pubkey) { return NULL; if (!(pk = BN_mpi2bn((unsigned char *)pkbuf, pklen, NULL))) { - PyErr_SetString(_dh_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_dh_err); return NULL; } if (!(key = PyMem_Malloc(DH_size(dh)))) { @@ -104,83 +114,73 @@ PyObject *dh_compute_key(DH *dh, PyObject *pubkey) { if ((klen = DH_compute_key((unsigned char *)key, pk, dh)) == -1) { BN_free(pk); PyMem_Free(key); - PyErr_SetString(_dh_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_dh_err); return NULL; } - ret = PyString_FromStringAndSize((const char *)key, klen); + + ret = PyBytes_FromStringAndSize((const char *)key, klen); + BN_free(pk); PyMem_Free(key); return ret; } - + PyObject *dh_get_p(DH *dh) { - if (!dh->p) { + const BIGNUM* p = NULL; + DH_get0_pqg(dh, &p, NULL, NULL); + if (!p) { PyErr_SetString(_dh_err, "'p' is unset"); return NULL; } - return bn_to_mpi(dh->p); + return bn_to_mpi(p); } PyObject *dh_get_g(DH *dh) { - if (!dh->g) { + const BIGNUM* g = NULL; + DH_get0_pqg(dh, NULL, NULL, &g); + if (!g) { PyErr_SetString(_dh_err, "'g' is unset"); return NULL; } - return bn_to_mpi(dh->g); + return bn_to_mpi(g); } PyObject *dh_get_pub(DH *dh) { - if (!dh->pub_key) { + const BIGNUM* pub_key = NULL; + DH_get0_key(dh, &pub_key, NULL); + if (!pub_key) { PyErr_SetString(_dh_err, "'pub' is unset"); return NULL; } - return bn_to_mpi(dh->pub_key); + return bn_to_mpi(pub_key); } PyObject *dh_get_priv(DH *dh) { - if (!dh->priv_key) { + const BIGNUM* priv_key = NULL; + DH_get0_key(dh, NULL, &priv_key); + if (!priv_key) { PyErr_SetString(_dh_err, "'priv' is unset"); return NULL; } - return bn_to_mpi(dh->priv_key); + return bn_to_mpi(priv_key); } -PyObject *dh_set_p(DH *dh, PyObject *value) { - BIGNUM *bn; - const void *vbuf; - int vlen; - - if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) - return NULL; +PyObject *dh_set_pg(DH *dh, PyObject *pval, PyObject* gval) { + BIGNUM* p, *g; - if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { - PyErr_SetString(_dh_err, ERR_reason_error_string(ERR_get_error())); + if (!(p = m2_PyObject_AsBIGNUM(pval, _dh_err)) + || !(g = m2_PyObject_AsBIGNUM(gval, _dh_err))) return NULL; - } - if (dh->p) - BN_free(dh->p); - dh->p = bn; - Py_INCREF(Py_None); - return Py_None; -} - -PyObject *dh_set_g(DH *dh, PyObject *value) { - BIGNUM *bn; - const void *vbuf; - int vlen; - if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + if (!DH_set0_pqg(dh, p, NULL, g)) { + PyErr_SetString(_dh_err, + "Cannot set prime number or generator of Z_p for DH."); + BN_free(p); + BN_free(g); return NULL; + } - if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { - PyErr_SetString(_dh_err, ERR_reason_error_string(ERR_get_error())); - return NULL; - } - if (dh->g) - BN_free(dh->g); - dh->g = bn; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } %} diff --git a/SWIG/_dsa.i b/SWIG/_dsa.i index addf33a..2c15c4f 100644 --- a/SWIG/_dsa.i +++ b/SWIG/_dsa.i @@ -1,5 +1,5 @@ /* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. */ -/* $Id: _dsa.i 723 2010-02-13 06:53:13Z heikki $ */ +/* $Id$ */ %{ #include @@ -8,11 +8,15 @@ #include PyObject *dsa_sig_get_r(DSA_SIG *dsa_sig) { - return bn_to_mpi(dsa_sig->r); + const BIGNUM* pr; + DSA_SIG_get0(dsa_sig, &pr, NULL); + return bn_to_mpi(pr); } PyObject *dsa_sig_get_s(DSA_SIG *dsa_sig) { - return bn_to_mpi(dsa_sig->s); + const BIGNUM* qs; + DSA_SIG_get0(dsa_sig, NULL, &qs); + return bn_to_mpi(qs); } %} @@ -27,6 +31,7 @@ extern int DSA_size(const DSA *); /* assert(dsa->q); */ %rename(dsa_gen_key) DSA_generate_key; extern int DSA_generate_key(DSA *); +%warnfilter(454) _dsa_err; %inline %{ static PyObject *_dsa_err; @@ -34,137 +39,189 @@ void dsa_init(PyObject *dsa_err) { Py_INCREF(dsa_err); _dsa_err = dsa_err; } +%} -void genparam_callback(int p, int n, void *arg) { - PyObject *argv, *ret, *cbfunc; +%typemap(out) DSA * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ - cbfunc = (PyObject *)arg; - argv = Py_BuildValue("(ii)", p, n); - ret = PyEval_CallObject(cbfunc, argv); - PyErr_Clear(); - Py_DECREF(argv); - Py_XDECREF(ret); + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + $result = NULL; + } } - +%inline %{ DSA *dsa_generate_parameters(int bits, PyObject *pyfunc) { DSA *dsa; + BN_GENCB *gencb; + int ret; + + if ((gencb=BN_GENCB_new()) == NULL) { + m2_PyErr_Msg(_dh_err); + return NULL; + } + + if ((dsa = DSA_new()) == NULL) { + m2_PyErr_Msg(_dsa_err); + BN_GENCB_free(gencb); + return NULL; + } + + BN_GENCB_set(gencb, bn_gencb_callback, (void *) pyfunc); + + Py_INCREF(pyfunc); + ret = DSA_generate_parameters_ex(dsa, bits, NULL, 0, NULL, NULL, + gencb); + Py_DECREF(pyfunc); + BN_GENCB_free(gencb); + + if (ret) + return dsa; + + m2_PyErr_Msg(_dsa_err); + DSA_free(dsa); + return NULL; +} + +DSA *dsa_read_params(BIO *f, PyObject *pyfunc) { + DSA *ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_read_bio_DSAparams(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + + if (ret == NULL) { + m2_PyErr_Msg(_dsa_err); + } + + return ret; +} + +DSA *dsa_read_key(BIO *f, PyObject *pyfunc) { + DSA *ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_read_bio_DSAPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + + if (ret == NULL) { + m2_PyErr_Msg(_dsa_err); + } + + return ret; +} + +DSA *dsa_read_pub_key(BIO *f, PyObject *pyfunc) { + DSA *ret; Py_INCREF(pyfunc); - dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, genparam_callback, (void *)pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_read_bio_DSA_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS Py_DECREF(pyfunc); - if (!dsa) - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); - return dsa; + + if (ret == NULL) { + m2_PyErr_Msg(_dsa_err); + } + + return ret; } +%} +%typemap(out) DSA * ; +%inline %{ PyObject *dsa_get_p(DSA *dsa) { - if (!dsa->p) { + const BIGNUM* p = NULL; + DSA_get0_pqg(dsa, &p, NULL, NULL); + if (!p) { PyErr_SetString(_dsa_err, "'p' is unset"); return NULL; } - return bn_to_mpi(dsa->p); + return bn_to_mpi(p); } PyObject *dsa_get_q(DSA *dsa) { - if (!dsa->q) { + const BIGNUM* q = NULL; + DSA_get0_pqg(dsa, NULL, &q, NULL); + if (!q) { PyErr_SetString(_dsa_err, "'q' is unset"); return NULL; } - return bn_to_mpi(dsa->q); + return bn_to_mpi(q); } PyObject *dsa_get_g(DSA *dsa) { - if (!dsa->g) { + const BIGNUM* g = NULL; + DSA_get0_pqg(dsa, NULL, NULL, &g); + if (!g) { PyErr_SetString(_dsa_err, "'g' is unset"); return NULL; } - return bn_to_mpi(dsa->g); + return bn_to_mpi(g); } PyObject *dsa_get_pub(DSA *dsa) { - if (!dsa->pub_key) { + const BIGNUM* pub_key = NULL; + DSA_get0_key(dsa, &pub_key, NULL); + if (!pub_key) { PyErr_SetString(_dsa_err, "'pub' is unset"); return NULL; } - return bn_to_mpi(dsa->pub_key); + return bn_to_mpi(pub_key); } PyObject *dsa_get_priv(DSA *dsa) { - if (!dsa->priv_key) { + const BIGNUM* priv_key = NULL; + DSA_get0_key(dsa, NULL, &priv_key); + if (!priv_key) { PyErr_SetString(_dsa_err, "'priv' is unset"); return NULL; } - return bn_to_mpi(dsa->priv_key); + return bn_to_mpi(priv_key); } -PyObject *dsa_set_p(DSA *dsa, PyObject *value) { - BIGNUM *bn; - const void *vbuf; - int vlen; +PyObject *dsa_set_pqg(DSA *dsa, PyObject *pval, PyObject* qval, PyObject* gval) { + BIGNUM* p, *q, *g; - if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + if (!(p = m2_PyObject_AsBIGNUM(pval, _dsa_err)) + || !(q = m2_PyObject_AsBIGNUM(qval, _dsa_err)) + || !(g = m2_PyObject_AsBIGNUM(gval, _dsa_err))) return NULL; - if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); + if (!DSA_set0_pqg(dsa, p, q, g)) { + PyErr_SetString( + _dsa_err, + "Cannot set prime number, subprime, or generator of subgroup for DSA."); + BN_free(p); + BN_free(q); + BN_free(g); return NULL; - } - if (dsa->p) - BN_free(dsa->p); - dsa->p = bn; - Py_INCREF(Py_None); - return Py_None; -} + } -PyObject *dsa_set_q(DSA *dsa, PyObject *value) { - BIGNUM *bn; - const void *vbuf; - int vlen; - - if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) - return NULL; - - if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); - return NULL; + Py_RETURN_NONE; } - if (dsa->q) - BN_free(dsa->q); - dsa->q = bn; - Py_INCREF(Py_None); - return Py_None; -} -PyObject *dsa_set_g(DSA *dsa, PyObject *value) { +PyObject *dsa_set_pub(DSA *dsa, PyObject *value) { BIGNUM *bn; const void *vbuf; - int vlen; + int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_dsa_err); return NULL; } - if (dsa->g) - BN_free(dsa->g); - dsa->g = bn; - Py_INCREF(Py_None); - return Py_None; -} -%} - -%inline %{ -DSA *dsa_read_params(BIO *f, PyObject *pyfunc) { - DSA *ret; - - Py_INCREF(pyfunc); - Py_BEGIN_ALLOW_THREADS - ret = PEM_read_bio_DSAparams(f, NULL, passphrase_callback, (void *)pyfunc); - Py_END_ALLOW_THREADS - Py_DECREF(pyfunc); - return ret; + if (!DSA_set0_key(dsa, bn, NULL)) { + BN_free(bn); + PyErr_SetString(_dsa_err, "Cannot set private and public key for DSA."); + } + Py_RETURN_NONE; } %} @@ -211,41 +268,17 @@ int dsa_write_pub_key_bio(DSA* dsa, BIO* f) { %} %inline %{ -DSA *dsa_read_key(BIO *f, PyObject *pyfunc) { - DSA *ret; - - Py_INCREF(pyfunc); - Py_BEGIN_ALLOW_THREADS - ret = PEM_read_bio_DSAPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); - Py_END_ALLOW_THREADS - Py_DECREF(pyfunc); - return ret; -} -%} - -%inline %{ -DSA *dsa_read_pub_key(BIO *f, PyObject *pyfunc) { - DSA *ret; - - Py_INCREF(pyfunc); - Py_BEGIN_ALLOW_THREADS - ret = PEM_read_bio_DSA_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); - Py_END_ALLOW_THREADS - Py_DECREF(pyfunc); - return ret; -} - PyObject *dsa_sign(DSA *dsa, PyObject *value) { const void *vbuf; - int vlen; + int vlen = 0; PyObject *tuple; - DSA_SIG *sig; + DSA_SIG *sig; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(sig = DSA_do_sign(vbuf, vlen, dsa))) { - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_dsa_err); return NULL; } if (!(tuple = PyTuple_New(2))) { @@ -261,8 +294,9 @@ PyObject *dsa_sign(DSA *dsa, PyObject *value) { int dsa_verify(DSA *dsa, PyObject *value, PyObject *r, PyObject *s) { const void *vbuf, *rbuf, *sbuf; - int vlen, rlen, slen; + int vlen = 0, rlen = 0, slen = 0; DSA_SIG *sig; + BIGNUM* pr, *ps; int ret; if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) @@ -271,29 +305,38 @@ int dsa_verify(DSA *dsa, PyObject *value, PyObject *r, PyObject *s) { return -1; if (!(sig = DSA_SIG_new())) { - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_dsa_err); return -1; } - if (!(sig->r = BN_mpi2bn((unsigned char *)rbuf, rlen, NULL))) { - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); + if (!(pr = BN_mpi2bn((unsigned char *)rbuf, rlen, NULL))) { + m2_PyErr_Msg(_dsa_err); DSA_SIG_free(sig); return -1; } - if (!(sig->s = BN_mpi2bn((unsigned char *)sbuf, slen, NULL))) { - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); + if (!(ps = BN_mpi2bn((unsigned char *)sbuf, slen, NULL))) { + m2_PyErr_Msg(_dsa_err); DSA_SIG_free(sig); + BN_free(pr); return -1; } + if (!DSA_SIG_set0(sig, pr, ps)) { + m2_PyErr_Msg(_dsa_err); + DSA_SIG_free(sig); + BN_free(pr); + BN_free(ps); + return -1; + } + ret = DSA_do_verify(vbuf, vlen, sig, dsa); DSA_SIG_free(sig); if (ret == -1) - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_dsa_err); return ret; } PyObject *dsa_sign_asn1(DSA *dsa, PyObject *value) { const void *vbuf; - int vlen; + int vlen = 0; void *sigbuf; unsigned int siglen; PyObject *ret; @@ -306,19 +349,21 @@ PyObject *dsa_sign_asn1(DSA *dsa, PyObject *value) { return NULL; } if (!DSA_sign(0, vbuf, vlen, (unsigned char *)sigbuf, &siglen, dsa)) { - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_dsa_err); PyMem_Free(sigbuf); return NULL; } - ret = PyString_FromStringAndSize(sigbuf, siglen); + + ret = PyBytes_FromStringAndSize(sigbuf, siglen); + PyMem_Free(sigbuf); return ret; } int dsa_verify_asn1(DSA *dsa, PyObject *value, PyObject *sig) { - const void *vbuf; + const void *vbuf; void *sbuf; - int vlen, slen, ret; + int vlen = 0, slen = 0, ret = 0; if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) || (m2_PyObject_AsReadBufferInt(sig, (const void **)&sbuf, &slen) @@ -326,20 +371,26 @@ int dsa_verify_asn1(DSA *dsa, PyObject *value, PyObject *sig) { return -1; if ((ret = DSA_verify(0, vbuf, vlen, sbuf, slen, dsa)) == -1) - PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_dsa_err); return ret; } int dsa_check_key(DSA *dsa) { - return (dsa->pub_key) && (dsa->priv_key); + const BIGNUM* pub_key, *priv_key; + DSA_get0_key(dsa, &pub_key, &priv_key); + return pub_key != NULL && priv_key != NULL; } int dsa_check_pub_key(DSA *dsa) { - return dsa->pub_key ? 1 : 0; + const BIGNUM* pub_key; + DSA_get0_key(dsa, &pub_key, NULL); + return pub_key ? 1 : 0; } int dsa_keylen(DSA *dsa) { - return BN_num_bits(dsa->p); + const BIGNUM* p; + DSA_get0_pqg(dsa, &p, NULL, NULL); + return BN_num_bits(p); } int dsa_type_check(DSA *dsa) { diff --git a/SWIG/_ec.i b/SWIG/_ec.i index f0e52bd..f47d593 100644 --- a/SWIG/_ec.i +++ b/SWIG/_ec.i @@ -1,4 +1,4 @@ -/* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. +/* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. Most code originally from _dsa.i, _rsa.i and _dh.i and adjusted for EC use. @@ -28,7 +28,7 @@ extern EC_KEY *EC_KEY_new(void); %rename(ec_key_free) EC_KEY_free; extern void EC_KEY_free(EC_KEY *); %rename(ec_key_size) ECDSA_size; -extern int ECDSA_size(const EC_KEY *); +extern int ECDSA_size(const EC_KEY *); %rename(ec_key_gen_key) EC_KEY_generate_key; extern int EC_KEY_generate_key(EC_KEY *); %rename(ec_key_check_key) EC_KEY_check_key; @@ -107,6 +107,7 @@ extern int EC_KEY_check_key(const EC_KEY *); %constant int NID_ipsec4 = NID_ipsec4; +%warnfilter(454) _ec_err; %inline %{ static PyObject *_ec_err; @@ -115,6 +116,57 @@ void ec_init(PyObject *ec_err) { _ec_err = ec_err; } +PyObject *ec_get_builtin_curves(void) { + /* size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t + * nitems); */ + EC_builtin_curve *curves; + Py_ssize_t ret_curves = 0; + size_t num_curves = EC_get_builtin_curves(NULL, 0); + PyObject *ret_tuple = NULL; + PyObject *ret_dict = NULL; + Py_ssize_t i; + const char *comment; + const char *sname; + + if (!(curves = PyMem_Malloc(num_curves * sizeof(EC_builtin_curve)))) { + PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves"); + return NULL; + } + + ret_curves = (Py_ssize_t)EC_get_builtin_curves(curves, num_curves); + + if (!(ret_tuple = PyTuple_New(ret_curves))) { + PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves"); + return NULL; + } + + for (i = 0; i < ret_curves; i++) { + if (!(ret_dict = PyDict_New())) { + PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves"); + return NULL; + } + + comment = curves[i].comment; + sname = OBJ_nid2sn(curves[i].nid); + if (sname == NULL) + sname = ""; + + PyDict_SetItemString(ret_dict, "NID", + PyLong_FromLong((long)curves[i].nid)); + PyDict_SetItemString(ret_dict, "sname", + PyString_FromString(sname)); + PyDict_SetItemString(ret_dict, "comment", + PyString_FromString(comment)); + + PyTuple_SET_ITEM(ret_tuple, i, ret_dict); + + } + + PyMem_Free(curves); + + return ret_tuple; +} + EC_KEY* ec_key_new_by_curve_name(int nid) { EC_KEY *key; @@ -136,8 +188,8 @@ EC_KEY* ec_key_new_by_curve_name(int nid) } group = EC_GROUP_new_by_curve_name(nid); if (!group) { + m2_PyErr_Msg(_ec_err); EC_KEY_free(key); - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); return NULL; } EC_GROUP_set_asn1_flag(group, asn1_flag); @@ -156,45 +208,53 @@ EC_KEY* ec_key_new_by_curve_name(int nid) } PyObject *ec_key_get_public_der(EC_KEY *key) { - - unsigned char *src=NULL; - void *dst=NULL; + char *src=NULL; int src_len=0; - Py_ssize_t dst_len=0; PyObject *pyo=NULL; - int ret=0; - + /* Convert to binary */ - src_len = i2d_EC_PUBKEY( key, &src ); + src_len = i2d_EC_PUBKEY( key, (unsigned char**)&src ); if (src_len < 0) { - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ec_err); return NULL; } /* Create a PyBuffer containing a copy of the binary, * to simplify memory deallocation */ - pyo = PyBuffer_New( src_len ); - ret = PyObject_AsWriteBuffer( pyo, &dst, &dst_len ); - assert( src_len == dst_len ); - if (ret < 0) + pyo = PyBytes_FromStringAndSize( src, src_len ); + + OPENSSL_free(src); + + return pyo; +} + +PyObject *ec_key_get_public_key(EC_KEY *key) { + char *src=NULL; + int src_len=0; + PyObject *pyo=NULL; + + /* Convert to binary */ + src_len = i2o_ECPublicKey(key, (unsigned char**)&src); + if (src_len < 0) { - Py_DECREF(pyo); - OPENSSL_free(src); - PyErr_SetString(_ec_err, "cannot get write buffer"); + m2_PyErr_Msg(_ec_err); return NULL; } - memcpy( dst, src, src_len ); + + pyo = PyBytes_FromStringAndSize( src, src_len ); + OPENSSL_free(src); return pyo; } + %} %threadallow ec_key_read_pubkey; %inline %{ EC_KEY *ec_key_read_pubkey(BIO *f) { - return PEM_read_bio_EC_PUBKEY(f, NULL, NULL, NULL); + return PEM_read_bio_EC_PUBKEY(f, NULL, NULL, NULL); } %} @@ -238,7 +298,7 @@ int ec_key_write_bio_no_cipher(EC_KEY *key, BIO *f, PyObject *pyfunc) { Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS - ret = PEM_write_bio_ECPrivateKey(f, key, NULL, NULL, 0, + ret = PEM_write_bio_ECPrivateKey(f, key, NULL, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); @@ -247,24 +307,28 @@ int ec_key_write_bio_no_cipher(EC_KEY *key, BIO *f, PyObject *pyfunc) { PyObject *ecdsa_sig_get_r(ECDSA_SIG *ecdsa_sig) { - return bn_to_mpi(ecdsa_sig->r); + const BIGNUM* pr; + ECDSA_SIG_get0(ecdsa_sig, &pr, NULL); + return bn_to_mpi(pr); } PyObject *ecdsa_sig_get_s(ECDSA_SIG *ecdsa_sig) { - return bn_to_mpi(ecdsa_sig->s); + const BIGNUM* ps; + ECDSA_SIG_get0(ecdsa_sig, NULL, &ps); + return bn_to_mpi(ps); } PyObject *ecdsa_sign(EC_KEY *key, PyObject *value) { const void *vbuf; - int vlen; + int vlen = 0; PyObject *tuple; - ECDSA_SIG *sig; + ECDSA_SIG *sig; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(sig = ECDSA_do_sign(vbuf, vlen, key))) { - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ec_err); return NULL; } if (!(tuple = PyTuple_New(2))) { @@ -280,40 +344,50 @@ PyObject *ecdsa_sign(EC_KEY *key, PyObject *value) { int ecdsa_verify(EC_KEY *key, PyObject *value, PyObject *r, PyObject *s) { const void *vbuf, *rbuf, *sbuf; - int vlen, rlen, slen; + int vlen = 0, rlen = 0, slen = 0; ECDSA_SIG *sig; int ret; + BIGNUM* pr, *ps; if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) || (m2_PyObject_AsReadBufferInt(r, &rbuf, &rlen) == -1) || (m2_PyObject_AsReadBufferInt(s, &sbuf, &slen) == -1)) return -1; - if (!(sig = ECDSA_SIG_new())) { - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); + if (!(pr = BN_mpi2bn((unsigned char *)rbuf, rlen, NULL))) { + m2_PyErr_Msg(_ec_err); return -1; } - if (!BN_mpi2bn((unsigned char *)rbuf, rlen, sig->r)) { - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); - ECDSA_SIG_free(sig); + if (!(ps = BN_mpi2bn((unsigned char *)sbuf, slen, NULL))) { + m2_PyErr_Msg(_ec_err); + BN_free(pr); return -1; } - if (!BN_mpi2bn((unsigned char *)sbuf, slen, sig->s)) { - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); + + if (!(sig = ECDSA_SIG_new())) { + m2_PyErr_Msg(_ec_err); + BN_free(pr); + BN_free(ps); + return -1; + } + if (!ECDSA_SIG_set0(sig, pr, ps)) { + PyErr_SetString(_ec_err, "Cannot set r and s fields of ECDSA_SIG."); ECDSA_SIG_free(sig); + BN_free(pr); + BN_free(ps); return -1; } ret = ECDSA_do_verify(vbuf, vlen, sig, key); ECDSA_SIG_free(sig); if (ret == -1) - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ec_err); return ret; } PyObject *ecdsa_sign_asn1(EC_KEY *key, PyObject *value) { const void *vbuf; - int vlen; + int vlen = 0; void *sigbuf; unsigned int siglen; PyObject *ret; @@ -326,20 +400,21 @@ PyObject *ecdsa_sign_asn1(EC_KEY *key, PyObject *value) { return NULL; } if (!ECDSA_sign(0, vbuf, vlen, (unsigned char *)sigbuf, &siglen, key)) { - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ec_err); PyMem_Free(sigbuf); return NULL; } - ret = PyString_FromStringAndSize(sigbuf, siglen); + ret = PyBytes_FromStringAndSize(sigbuf, siglen); + PyMem_Free(sigbuf); return ret; } int ecdsa_verify_asn1(EC_KEY *key, PyObject *value, PyObject *sig) { - const void *vbuf; + const void *vbuf; void *sbuf; - int vlen, slen, ret; + int vlen = 0, slen = 0, ret; if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) || (m2_PyObject_AsReadBufferInt(sig, (const void **)&sbuf, &slen) @@ -347,7 +422,7 @@ int ecdsa_verify_asn1(EC_KEY *key, PyObject *value, PyObject *sig) { return -1; if ((ret = ECDSA_verify(0, vbuf, vlen, sbuf, slen, key)) == -1) - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ec_err); return ret; } @@ -360,10 +435,10 @@ PyObject *ecdh_compute_key(EC_KEY *keypairA, EC_KEY *pubkeyB) { if ((pkpointB = EC_KEY_get0_public_key(pubkeyB)) == NULL) { - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); + PyErr_SetString(_ec_err, "Cannot get the public key of EC_KEY object."); return NULL; } - + groupA = EC_KEY_get0_group(keypairA); sharedkeylen = (EC_GROUP_get_degree(groupA) + 7)/8; @@ -372,14 +447,15 @@ PyObject *ecdh_compute_key(EC_KEY *keypairA, EC_KEY *pubkeyB) { return NULL; } if ((sharedkeylen = ECDH_compute_key((unsigned char *)sharedkey, sharedkeylen, pkpointB, keypairA, NULL)) == -1) { + m2_PyErr_Msg(_ec_err); PyMem_Free(sharedkey); - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); return NULL; } - ret = PyString_FromStringAndSize((const char *)sharedkey, sharedkeylen); + ret = PyBytes_FromStringAndSize((const char *)sharedkey, sharedkeylen); + PyMem_Free(sharedkey); - + return ret; } @@ -398,7 +474,33 @@ EC_KEY* ec_key_from_pubkey_der(PyObject *pubkey) { tempBuf = (const unsigned char *)keypairbuf; if ((keypair = d2i_EC_PUBKEY( NULL, &tempBuf, keypairbuflen)) == 0) { - PyErr_SetString(_ec_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ec_err); + return NULL; + } + return keypair; +} + +EC_KEY* ec_key_from_pubkey_params(int nid, PyObject *pubkey) { + const void *keypairbuf; + Py_ssize_t keypairbuflen; + const unsigned char *tempBuf; + EC_KEY *keypair; + + if (PyObject_AsReadBuffer(pubkey, &keypairbuf, &keypairbuflen) == -1) + { + return NULL; + } + + keypair = ec_key_new_by_curve_name(nid); + if (!keypair) { + m2_PyErr_Msg(_ec_err); + return NULL; + } + + tempBuf = (const unsigned char *)keypairbuf; + if ((o2i_ECPublicKey( &keypair, &tempBuf, keypairbuflen)) == 0) + { + m2_PyErr_Msg(_ec_err); return NULL; } return keypair; diff --git a/SWIG/_engine.i b/SWIG/_engine.i index b55720f..4ba93f3 100644 --- a/SWIG/_engine.i +++ b/SWIG/_engine.i @@ -164,6 +164,7 @@ extern EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id, * This function may be not implemented in engine. * pkcs11 engine has this control. */ +%warnfilter(454) _engine_err; %inline %{ static PyObject *_engine_err; diff --git a/SWIG/_evp.i b/SWIG/_evp.i index 0593eed..d04e806 100644 --- a/SWIG/_evp.i +++ b/SWIG/_evp.i @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* +/* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. Portions Copyright (c) 2004-2007 Open Source Applications Foundation. @@ -18,8 +18,32 @@ Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. #include #include #include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +HMAC_CTX *HMAC_CTX_new(void) { + HMAC_CTX *ret = PyMem_Malloc(sizeof(HMAC_CTX)); + HMAC_CTX_init(ret); + return ret; +} +#define HMAC_CTX_reset(ctx) HMAC_CTX_init(ctx) +#define HMAC_CTX_free(ctx) \ + do { \ + HMAC_CTX_cleanup(ctx); \ + PyMem_Free((void *)ctx); \ + } while(0) + +#define EVP_CIPHER_CTX_reset(ctx) EVP_CIPHER_CTX_init(ctx) +#endif %} +/* +from openssl/crypto/include/internal/evp_int.h struct evp_md_st +typedef struct evp_md_st EVP_MD; +from openssl/crypto/evp/evp_locl.h evp_md_ctx_st +typedef struct evp_md_ctx_st EVP_MD_CTX; +*/ + %apply Pointer NONNULL { EVP_MD_CTX * }; %apply Pointer NONNULL { EVP_MD * }; %apply Pointer NONNULL { EVP_PKEY * }; @@ -101,10 +125,14 @@ extern const EVP_CIPHER *EVP_cast5_ofb(void); %rename(rc5_cfb) extern const EVP_CIPHER *EVP_rc5_32_12_16_cfb(void); %rename(rc5_ofb) extern const EVP_CIPHER *EVP_rc5_32_12_16_ofb(void); */ +#if !defined(OPENSSL_NO_RC4) %rename(rc4) EVP_rc4; extern const EVP_CIPHER *EVP_rc4(void); +#endif +#if !defined(OPENSSL_NO_RC2) %rename(rc2_40_cbc) EVP_rc2_40_cbc; extern const EVP_CIPHER *EVP_rc2_40_cbc(void); +#endif %rename(aes_128_ecb) EVP_aes_128_ecb; extern const EVP_CIPHER *EVP_aes_128_ecb(void); %rename(aes_128_cbc) EVP_aes_128_cbc; @@ -113,6 +141,8 @@ extern const EVP_CIPHER *EVP_aes_128_cbc(void); extern const EVP_CIPHER *EVP_aes_128_cfb(void); %rename(aes_128_ofb) EVP_aes_128_ofb; extern const EVP_CIPHER *EVP_aes_128_ofb(void); +%rename(aes_128_ctr) EVP_aes_128_ctr; +extern const EVP_CIPHER *EVP_aes_128_ctr(void); %rename(aes_192_ecb) EVP_aes_192_ecb; extern const EVP_CIPHER *EVP_aes_192_ecb(void); %rename(aes_192_cbc) EVP_aes_192_cbc; @@ -121,6 +151,8 @@ extern const EVP_CIPHER *EVP_aes_192_cbc(void); extern const EVP_CIPHER *EVP_aes_192_cfb(void); %rename(aes_192_ofb) EVP_aes_192_ofb; extern const EVP_CIPHER *EVP_aes_192_ofb(void); +%rename(aes_192_ctr) EVP_aes_192_ctr; +extern const EVP_CIPHER *EVP_aes_192_ctr(void); %rename(aes_256_ecb) EVP_aes_256_ecb; extern const EVP_CIPHER *EVP_aes_256_ecb(void); %rename(aes_256_cbc) EVP_aes_256_cbc; @@ -129,12 +161,15 @@ extern const EVP_CIPHER *EVP_aes_256_cbc(void); extern const EVP_CIPHER *EVP_aes_256_cfb(void); %rename(aes_256_ofb) EVP_aes_256_ofb; extern const EVP_CIPHER *EVP_aes_256_ofb(void); +%rename(aes_256_ctr) EVP_aes_256_ctr; +extern EVP_CIPHER const *EVP_aes_256_ctr(void); %rename(cipher_set_padding) EVP_CIPHER_CTX_set_padding; extern int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int); -%rename(pkey_new) EVP_PKEY_new; -extern EVP_PKEY *EVP_PKEY_new(void); + +%rename(cipher_set_padding) EVP_CIPHER_CTX_set_padding; +extern int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *x, int padding); %rename(pkey_free) EVP_PKEY_free; extern void EVP_PKEY_free(EVP_PKEY *); %rename(pkey_assign) EVP_PKEY_assign; @@ -145,8 +180,6 @@ extern int EVP_PKEY_assign_EC_KEY(EVP_PKEY *, EC_KEY *); #endif %rename(pkey_set1_rsa) EVP_PKEY_set1_RSA; extern int EVP_PKEY_set1_RSA(EVP_PKEY *, RSA *); -%rename(pkey_get1_rsa) EVP_PKEY_get1_RSA; -extern RSA* EVP_PKEY_get1_RSA(EVP_PKEY *); %rename(sign_init) EVP_SignInit; extern int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *); %rename(verify_init) EVP_VerifyInit; @@ -154,6 +187,7 @@ extern int EVP_VerifyInit(EVP_MD_CTX *, const EVP_MD *); %rename(pkey_size) EVP_PKEY_size; extern int EVP_PKEY_size(EVP_PKEY *); +%warnfilter(454) _evp_err; %inline %{ #define PKCS5_SALT_LEN 8 @@ -163,16 +197,43 @@ void evp_init(PyObject *evp_err) { Py_INCREF(evp_err); _evp_err = evp_err; } +%} + +%typemap(out) RSA * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + $result = NULL; + } +} +%inline %{ +RSA *pkey_get1_rsa(EVP_PKEY *pkey) { + RSA *ret = NULL; + + if ((ret = EVP_PKEY_get1_RSA(pkey)) == NULL) { + /* _evp_err now inherits from PyExc_ValueError, so we should + * keep API intact. + */ + PyErr_Format(_evp_err, "Invalid key in function %s.", __FUNCTION__); + } + + return ret; +} +%} +%typemap(out) RSA * ; +%inline %{ PyObject *pkcs5_pbkdf2_hmac_sha1(PyObject *pass, PyObject *salt, int iter, int keylen) { - unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char *key; unsigned char *saltbuf; char *passbuf; PyObject *ret; - int passlen, saltlen; + int passlen = 0, saltlen = 0; if (m2_PyObject_AsReadBufferInt(pass, (const void **)&passbuf, &passlen) == -1) @@ -181,10 +242,14 @@ PyObject *pkcs5_pbkdf2_hmac_sha1(PyObject *pass, &saltlen) == -1) return NULL; + key = PyMem_Malloc(keylen); + if (key == NULL) + return PyErr_NoMemory(); PKCS5_PBKDF2_HMAC_SHA1(passbuf, passlen, saltbuf, saltlen, iter, keylen, key); - ret = PyString_FromStringAndSize((char*)key, keylen); + ret = PyBytes_FromStringAndSize((char*)key, keylen); OPENSSL_cleanse(key, keylen); + PyMem_Free(key); return ret; } @@ -193,6 +258,7 @@ EVP_MD_CTX *md_ctx_new(void) { if (!(ctx = EVP_MD_CTX_create())) { PyErr_SetString(PyExc_MemoryError, "md_ctx_new"); + return NULL; } return ctx; } @@ -216,16 +282,18 @@ PyObject *digest_final(EVP_MD_CTX *ctx) { int blen; PyObject *ret; - if (!(blob = PyMem_Malloc(ctx->digest->md_size))) { + if (!(blob = PyMem_Malloc(EVP_MD_CTX_size(ctx)))) { PyErr_SetString(PyExc_MemoryError, "digest_final"); return NULL; } if (!EVP_DigestFinal(ctx, blob, (unsigned int *)&blen)) { PyMem_Free(blob); - PyErr_SetString(_evp_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_evp_err); return NULL; } - ret = PyString_FromStringAndSize(blob, blen); + + ret = PyBytes_FromStringAndSize(blob, blen); + PyMem_Free(blob); return ret; } @@ -233,29 +301,29 @@ PyObject *digest_final(EVP_MD_CTX *ctx) { HMAC_CTX *hmac_ctx_new(void) { HMAC_CTX *ctx; - if (!(ctx = (HMAC_CTX *)PyMem_Malloc(sizeof(HMAC_CTX)))) { + if (!(ctx = HMAC_CTX_new())) { PyErr_SetString(PyExc_MemoryError, "hmac_ctx_new"); return NULL; } - HMAC_CTX_init(ctx); return ctx; } void hmac_ctx_free(HMAC_CTX *ctx) { - HMAC_CTX_cleanup(ctx); - PyMem_Free((void *)ctx); + HMAC_CTX_free(ctx); } PyObject *hmac_init(HMAC_CTX *ctx, PyObject *key, const EVP_MD *md) { const void *kbuf; - int klen; + int klen = 0; if (m2_PyObject_AsReadBufferInt(key, &kbuf, &klen) == -1) return NULL; - HMAC_Init(ctx, kbuf, klen, md); - Py_INCREF(Py_None); - return Py_None; + if (!HMAC_Init_ex(ctx, kbuf, klen, md, NULL)) { + PyErr_SetString(_evp_err, "HMAC_Init failed"); + return NULL; + } + Py_RETURN_NONE; } PyObject *hmac_update(HMAC_CTX *ctx, PyObject *blob) { @@ -265,9 +333,11 @@ PyObject *hmac_update(HMAC_CTX *ctx, PyObject *blob) { if (PyObject_AsReadBuffer(blob, &buf, &len) == -1) return NULL; - HMAC_Update(ctx, buf, len); - Py_INCREF(Py_None); - return Py_None; + if (!HMAC_Update(ctx, buf, len)) { + PyErr_SetString(_evp_err, "HMAC_Update failed"); + return NULL; + } + Py_RETURN_NONE; } PyObject *hmac_final(HMAC_CTX *ctx) { @@ -275,12 +345,18 @@ PyObject *hmac_final(HMAC_CTX *ctx) { int blen; PyObject *ret; - if (!(blob = PyMem_Malloc(ctx->md->md_size))) { + if (!(blob = PyMem_Malloc(HMAC_size(ctx)))) { PyErr_SetString(PyExc_MemoryError, "hmac_final"); return NULL; } - HMAC_Final(ctx, blob, (unsigned int *)&blen); - ret = PyString_FromStringAndSize(blob, blen); + + if (!HMAC_Final(ctx, blob, (unsigned int *)&blen)) { + PyErr_SetString(_evp_err, "HMAC_Final failed"); + return NULL; + } + + ret = PyBytes_FromStringAndSize(blob, blen); + PyMem_Free(blob); return ret; } @@ -288,7 +364,7 @@ PyObject *hmac_final(HMAC_CTX *ctx) { PyObject *hmac(PyObject *key, PyObject *data, const EVP_MD *md) { const void *kbuf, *dbuf; void *blob; - int klen; + int klen = 0; unsigned int blen; Py_ssize_t dlen; PyObject *ret; @@ -303,7 +379,9 @@ PyObject *hmac(PyObject *key, PyObject *data, const EVP_MD *md) { } HMAC(md, kbuf, klen, dbuf, dlen, blob, &blen); blob = PyMem_Realloc(blob, blen); - ret = PyString_FromStringAndSize(blob, blen); + + ret = PyBytes_FromStringAndSize(blob, blen); + PyMem_Free(blob); return ret; } @@ -311,26 +389,25 @@ PyObject *hmac(PyObject *key, PyObject *data, const EVP_MD *md) { EVP_CIPHER_CTX *cipher_ctx_new(void) { EVP_CIPHER_CTX *ctx; - if (!(ctx = (EVP_CIPHER_CTX *)PyMem_Malloc(sizeof(EVP_CIPHER_CTX)))) { + if (!(ctx = EVP_CIPHER_CTX_new())) { PyErr_SetString(PyExc_MemoryError, "cipher_ctx_new"); return NULL; } - EVP_CIPHER_CTX_init(ctx); + EVP_CIPHER_CTX_reset(ctx); return ctx; } void cipher_ctx_free(EVP_CIPHER_CTX *ctx) { - EVP_CIPHER_CTX_cleanup(ctx); - PyMem_Free((void *)ctx); + EVP_CIPHER_CTX_free(ctx); } -PyObject *bytes_to_key(const EVP_CIPHER *cipher, EVP_MD *md, +PyObject *bytes_to_key(const EVP_CIPHER *cipher, EVP_MD *md, PyObject *data, PyObject *salt, PyObject *iv, /* Not used */ int iter) { unsigned char key[EVP_MAX_KEY_LENGTH]; const void *dbuf, *sbuf; - int dlen, klen; + int dlen = 0, klen; Py_ssize_t slen; PyObject *ret; @@ -339,14 +416,16 @@ PyObject *bytes_to_key(const EVP_CIPHER *cipher, EVP_MD *md, return NULL; assert((slen == 8) || (slen == 0)); - klen = EVP_BytesToKey(cipher, md, (unsigned char *)sbuf, - (unsigned char *)dbuf, dlen, iter, + klen = EVP_BytesToKey(cipher, md, (unsigned char *)sbuf, + (unsigned char *)dbuf, dlen, iter, key, NULL); /* Since we are not returning IV no need to derive it */ - ret = PyString_FromStringAndSize((char*)key, klen); + + ret = PyBytes_FromStringAndSize((char*)key, klen); + return ret; } -PyObject *cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, +PyObject *cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, PyObject *key, PyObject *iv, int mode) { const void *kbuf, *ibuf; Py_ssize_t klen, ilen; @@ -357,16 +436,15 @@ PyObject *cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, if (!EVP_CipherInit(ctx, cipher, (unsigned char *)kbuf, (unsigned char *)ibuf, mode)) { - PyErr_SetString(_evp_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_evp_err); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject *cipher_update(EVP_CIPHER_CTX *ctx, PyObject *blob) { const void *buf; - int len, olen; + int len = 0, olen; void *obuf; PyObject *ret; @@ -379,10 +457,12 @@ PyObject *cipher_update(EVP_CIPHER_CTX *ctx, PyObject *blob) { } if (!EVP_CipherUpdate(ctx, obuf, &olen, (unsigned char *)buf, len)) { PyMem_Free(obuf); - PyErr_SetString(_evp_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_evp_err); return NULL; } - ret = PyString_FromStringAndSize(obuf, olen); + + ret = PyBytes_FromStringAndSize(obuf, olen); + PyMem_Free(obuf); return ret; } @@ -392,16 +472,18 @@ PyObject *cipher_final(EVP_CIPHER_CTX *ctx) { int olen; PyObject *ret; - if (!(obuf = PyMem_Malloc(ctx->cipher->block_size))) { + if (!(obuf = PyMem_Malloc(EVP_CIPHER_CTX_block_size(ctx)))) { PyErr_SetString(PyExc_MemoryError, "cipher_final"); return NULL; } if (!EVP_CipherFinal(ctx, (unsigned char *)obuf, &olen)) { PyMem_Free(obuf); - PyErr_SetString(_evp_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_evp_err); return NULL; } - ret = PyString_FromStringAndSize(obuf, olen); + + ret = PyBytes_FromStringAndSize(obuf, olen); + PyMem_Free(obuf); return ret; } @@ -414,11 +496,10 @@ PyObject *sign_update(EVP_MD_CTX *ctx, PyObject *blob) { return NULL; if (!EVP_SignUpdate(ctx, buf, len)) { - PyErr_SetString(_evp_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_evp_err); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject *sign_final(EVP_MD_CTX *ctx, EVP_PKEY *pkey) { @@ -433,12 +514,14 @@ PyObject *sign_final(EVP_MD_CTX *ctx, EVP_PKEY *pkey) { } if (!EVP_SignFinal(ctx, sigbuf, &siglen, pkey)) { + m2_PyErr_Msg(_evp_err); OPENSSL_cleanse(sigbuf, siglen); OPENSSL_free(sigbuf); - PyErr_SetString(_evp_err, ERR_reason_error_string(ERR_get_error())); return NULL; } - ret = PyString_FromStringAndSize((char*)sigbuf, siglen); + + ret = PyBytes_FromStringAndSize((char*)sigbuf, siglen); + OPENSSL_cleanse(sigbuf, siglen); OPENSSL_free(sigbuf); return ret; @@ -456,8 +539,8 @@ int verify_update(EVP_MD_CTX *ctx, PyObject *blob) { int verify_final(EVP_MD_CTX *ctx, PyObject *blob, EVP_PKEY *pkey) { - unsigned char *kbuf; - int len; + unsigned char *kbuf; + int len = 0; if (m2_PyObject_AsReadBufferInt(blob, (const void **)&kbuf, &len) == -1) return -1; @@ -466,6 +549,28 @@ int verify_final(EVP_MD_CTX *ctx, PyObject *blob, EVP_PKEY *pkey) { } %} +%typemap(out) EVP_MD * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + $result = NULL; + } +} +%inline %{ +const EVP_MD *get_digestbyname(const char* name) { + const EVP_MD *ret = NULL; + + if ((ret = EVP_get_digestbyname(name)) == NULL) { + m2_PyErr_Msg(_evp_err); + } + + return ret; +} +%} +%typemap(out) EVP_MD *; + %inline %{ int pkey_write_pem_no_cipher(EVP_PKEY *pkey, BIO *f, PyObject *pyfunc) { int ret; @@ -494,7 +599,27 @@ int pkey_write_pem(EVP_PKEY *pkey, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) } %} +%typemap(out) EVP_PKEY * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + $result = NULL; + } +} %inline %{ +EVP_PKEY *pkey_new(void) { + EVP_PKEY *ret; + + if ((ret = EVP_PKEY_new()) == NULL) { + PyErr_Format(PyExc_MemoryError, + "Insufficient memory for new key in function %s.", __FUNCTION__); + } + + return ret; +} + EVP_PKEY *pkey_read_pem(BIO *f, PyObject *pyfunc) { EVP_PKEY *pk; @@ -503,9 +628,35 @@ EVP_PKEY *pkey_read_pem(BIO *f, PyObject *pyfunc) { pk = PEM_read_bio_PrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); + + if (pk == NULL) { + PyErr_Format(_evp_err, + "Unable to read private key in function %s.", __FUNCTION__); + } + return pk; } +EVP_PKEY *pkey_read_pem_pubkey(BIO *f, PyObject *pyfunc) { + EVP_PKEY *pk; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + pk = PEM_read_bio_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + + if (pk == NULL) { + PyErr_Format(_evp_err, + "Unable to read public key in function %s.", __FUNCTION__); + } + + return pk; +} +%} +%typemap(out) EVP_PKEY * ; + +%inline %{ int pkey_assign_rsa(EVP_PKEY *pkey, RSA *rsa) { return EVP_PKEY_assign_RSA(pkey, rsa); } @@ -516,10 +667,12 @@ PyObject *pkey_as_der(EVP_PKEY *pkey) { PyObject * der; len = i2d_PUBKEY(pkey, &pp); if (len < 0){ - PyErr_SetString(PyExc_ValueError, "EVP_PKEY as DER failed"); - return NULL; + PyErr_SetString(_evp_err, "EVP_PKEY as DER failed"); + return NULL; } - der = PyString_FromStringAndSize((char*)pp, len); + + der = PyBytes_FromStringAndSize((char*)pp, len); + OPENSSL_free(pp); return der; } @@ -531,8 +684,9 @@ PyObject *pkey_get_modulus(EVP_PKEY *pkey) BIO *bio; BUF_MEM *bptr; PyObject *ret; + const BIGNUM* bn; - switch (pkey->type) { + switch (EVP_PKEY_base_id(pkey)) { case EVP_PKEY_RSA: rsa = EVP_PKEY_get1_RSA(pkey); @@ -542,20 +696,23 @@ PyObject *pkey_get_modulus(EVP_PKEY *pkey) PyErr_SetString(PyExc_MemoryError, "pkey_get_modulus"); return NULL; } - - if (!BN_print(bio, rsa->n)) { - PyErr_SetString(PyExc_RuntimeError, - ERR_error_string(ERR_get_error(), NULL)); + + RSA_get0_key(rsa, &bn, NULL, NULL); + if (!BN_print(bio, bn)) { + m2_PyErr_Msg(PyExc_RuntimeError); BIO_free(bio); RSA_free(rsa); return NULL; } BIO_get_mem_ptr(bio, &bptr); - ret = PyString_FromStringAndSize(bptr->data, bptr->length); - BIO_set_close(bio, BIO_CLOSE); + + ret = PyBytes_FromStringAndSize(bptr->data, bptr->length); + + (void)BIO_set_close(bio, BIO_CLOSE); BIO_free(bio); RSA_free(rsa); + return ret; break; case EVP_PKEY_DSA: @@ -568,29 +725,28 @@ PyObject *pkey_get_modulus(EVP_PKEY *pkey) return NULL; } - if (!BN_print(bio, dsa->pub_key)) { - PyErr_SetString(PyExc_RuntimeError, - ERR_error_string(ERR_get_error(), NULL)); + DSA_get0_key(dsa, &bn, NULL); + if (!BN_print(bio, bn)) { + m2_PyErr_Msg(PyExc_RuntimeError); BIO_free(bio); DSA_free(dsa); return NULL; } BIO_get_mem_ptr(bio, &bptr); - ret = PyString_FromStringAndSize(bptr->data, bptr->length); - BIO_set_close(bio, BIO_CLOSE); + + ret = PyBytes_FromStringAndSize(bptr->data, bptr->length); + + (void)BIO_set_close(bio, BIO_CLOSE); BIO_free(bio); DSA_free(dsa); + return ret; break; - + default: - PyErr_SetString(PyExc_ValueError, "unsupported key type"); + PyErr_SetString(_evp_err, "unsupported key type"); return NULL; } - - return ret; } - %} - diff --git a/SWIG/_lib.h b/SWIG/_lib.h index b53bc2a..e8a8645 100644 --- a/SWIG/_lib.h +++ b/SWIG/_lib.h @@ -1,11 +1,7 @@ /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */ -/* $Id: _lib.h 593 2007-10-12 21:46:34Z heikki $ */ +/* $Id$ */ -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -typedef int Py_ssize_t; -#define PY_SSIZE_T_MAX INT_MAX -#define PY_SSIZE_T_MIN INT_MIN -#endif +#include typedef struct _blob { unsigned char *data; @@ -20,7 +16,13 @@ static int m2_PyObject_AsReadBufferInt(PyObject *obj, const void **buffer, int *buffer_len); static int m2_PyString_AsStringAndSizeInt(PyObject *obj, char **s, int *len); -void gen_callback(int p, int n, void *arg); +static BIGNUM* m2_PyObject_AsBIGNUM(PyObject* value, PyObject* _py_exc) ; + +/* Always use these two together, to correctly handle non-memoryview objects. */ +static int m2_PyObject_GetBufferInt(PyObject *obj, Py_buffer *view, int flags); +static void m2_PyBuffer_Release(PyObject *obj, Py_buffer *view); + +int bn_gencb_callback(int p, int n, BN_GENCB *gencb); int passphrase_callback(char *buf, int num, int v, void *userdata); void lib_init(void); diff --git a/SWIG/_lib.i b/SWIG/_lib.i index 42dc180..c84b800 100644 --- a/SWIG/_lib.i +++ b/SWIG/_lib.i @@ -1,19 +1,85 @@ /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */ -/* $Id: _lib.i 695 2009-07-24 06:37:01Z heikki $ */ +/* $Id$ */ %{ +#include #include #include #include #include #include #include +#include #include +%} + +/* OpenSSL 1.1 compatibility shim */ +%include _lib11_compat.i + +/* Python 3 compatibility shim */ +%include _py3k_compat.i + +%{ +/* OpenSSL 1.0.2 copmatbility shim */ +#if OPENSSL_VERSION_NUMBER < 0x10002000L +typedef void (*OPENSSL_sk_freefunc)(void *); +typedef void *(*OPENSSL_sk_copyfunc)(const void *); +typedef struct stack_st OPENSSL_STACK; + +# define MIN_NODES 4 +# define sk_deep_copy OPENSSL_sk_deep_copy + +void OPENSSL_sk_free(OPENSSL_STACK *st) +{ + if (st == NULL) + return; + OPENSSL_free(st->data); + OPENSSL_free(st); +} + +OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk, + OPENSSL_sk_copyfunc copy_func, + OPENSSL_sk_freefunc free_func) +{ + OPENSSL_STACK *ret; + int i; + + if (sk->num < 0) + return NULL; + + if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) + return NULL; + + /* direct structure assignment */ + *ret = *sk; + + ret->num_alloc = sk->num > MIN_NODES ? (size_t)sk->num : MIN_NODES; + ret->data = OPENSSL_zalloc(sizeof(*ret->data) * ret->num_alloc); + if (ret->data == NULL) { + OPENSSL_free(ret); + return NULL; + } + + for (i = 0; i < ret->num; ++i) { + if (sk->data[i] == NULL) + continue; + if ((ret->data[i] = copy_func(sk->data[i])) == NULL) { + while (--i >= 0) + if (ret->data[i] != NULL) + free_func((void *)ret->data[i]); + OPENSSL_sk_free(ret); + return NULL; + } + } + return ret; +} +#endif /* OpenSSL 1.0.2 copmatbility shim */ + /* Blob interface. Deprecated. */ Blob *blob_new(int len, const char *errmsg) { - + Blob *blob; if (!(blob=(Blob *)PyMem_Malloc(sizeof(Blob)))){ PyErr_SetString(PyExc_MemoryError, errmsg); @@ -47,9 +113,15 @@ void blob_free(Blob *blob) { /* Python helpers. */ %} +%ignore PyObject_CheckBuffer; +%ignore PyObject_GetBuffer; +%ignore PyBuffer_Release; %ignore m2_PyObject_AsReadBufferInt; +%ignore m2_PyObject_GetBufferInt; +%ignore m2_PyBuffer_Release; %ignore m2_PyString_AsStringAndSizeInt; %{ + static int m2_PyObject_AsReadBufferInt(PyObject *obj, const void **buffer, int *buffer_len) @@ -68,13 +140,63 @@ m2_PyObject_AsReadBufferInt(PyObject *obj, const void **buffer, return 0; } +static int m2_PyObject_GetBufferInt(PyObject *obj, Py_buffer *view, int flags) +{ + int ret; + + if (PyObject_CheckBuffer(obj)) + ret = PyObject_GetBuffer(obj, view, flags); + else { + const void *buf; + + ret = PyObject_AsReadBuffer(obj, &buf, &view->len); + if (ret == 0) + view->buf = (void *)buf; + } + if (ret) + return ret; + if (view->len > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "object too large"); + m2_PyBuffer_Release(obj, view); + return -1; + } + + return 0; +} + +static BIGNUM* +m2_PyObject_AsBIGNUM(PyObject* value, PyObject* _py_exc) +{ + BIGNUM* bn; + const void* vbuf; + int vlen = 0; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { + PyErr_SetString(_py_exc, ERR_reason_error_string(ERR_get_error())); + return NULL; + } + + return bn; +} + +static void m2_PyBuffer_Release(PyObject *obj, Py_buffer *view) +{ + if (PyObject_CheckBuffer(obj)) + PyBuffer_Release(view); + /* else do nothing, view->buf comes from PyObject_AsReadBuffer */ +} + static int m2_PyString_AsStringAndSizeInt(PyObject *obj, char **s, int *len) { int ret; Py_ssize_t len2; - ret = PyString_AsStringAndSize(obj, s, &len2); + ret = PyBytes_AsStringAndSize(obj, s, &len2); + if (ret) return ret; if (len2 > INT_MAX) { @@ -85,8 +207,46 @@ m2_PyString_AsStringAndSizeInt(PyObject *obj, char **s, int *len) return 0; } +/* Works as PyFile_Name, but always returns a new object. */ +PyObject *m2_PyFile_Name(PyObject *pyfile) { + PyObject *out = NULL; +#if PY_MAJOR_VERSION >= 3 + out = PyObject_GetAttrString(pyfile, "name"); +#else + out = PyFile_Name(pyfile); + Py_XINCREF(out); +#endif + return out; +} + +/* Yes, __FUNCTION__ is a non-standard symbol, but it is supported by + * both gcc and MSVC. */ +#define m2_PyErr_Msg(type) m2_PyErr_Msg_Caller(type, (const char*) __FUNCTION__) + +static void m2_PyErr_Msg_Caller(PyObject *err_type, const char* caller) { + const char *err_reason; + const char *data; + int flags; + /* This max size of a (longer than ours) OpenSSL error string is hardcoded + * in OpenSSL's crypto/err/err_prn.c:ERR_print_errors_cb() */ + char err_msg[4096]; + unsigned long err_code = ERR_get_error_line_data(NULL, NULL, &data, &flags); + + if (err_code != 0) { + err_reason = ERR_reason_error_string(err_code); + if (data && (flags & ERR_TXT_STRING)) + snprintf(err_msg, sizeof(err_msg), "%s (%s)", err_reason, data); + else + snprintf(err_msg, sizeof(err_msg), "%s", err_reason); + + PyErr_SetString(err_type, err_msg); + } else { + PyErr_Format(err_type, "Unknown error in function %s.", caller); + } +} + -/* C callbacks invoked by OpenSSL; these in turn call back into +/* C callbacks invoked by OpenSSL; these in turn call back into Python. */ int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) { @@ -100,6 +260,7 @@ int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) { int cret; int new_style_callback = 0, warning_raised_exception=0; PyGILState_STATE gilstate; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx); @@ -117,7 +278,7 @@ int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) { PyCodeObject *code = (PyCodeObject *) PyFunction_GetCode(ssl_verify_cb_func); if (code && code->co_argcount == 2) { /* XXX Python internals */ new_style_callback = 1; - } + } } else { /* XXX There are lots of other callable types, but we will assume * XXX that any other type of callable uses the new style callback, @@ -125,30 +286,34 @@ int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) { */ new_style_callback = 1; } - + if (new_style_callback) { - PyObject *x509mod = PyDict_GetItemString(PyImport_GetModuleDict(), "M2Crypto.X509"); + PyObject *x509mod; + + x509mod = PyDict_GetItemString(PyImport_GetModuleDict(), "M2Crypto.X509"); _klass = PyObject_GetAttrString(x509mod, "X509_Store_Context"); - + _x509_store_ctx_swigptr = SWIG_NewPointerObj((void *)ctx, SWIGTYPE_p_X509_STORE_CTX, 0); _x509_store_ctx_obj = Py_BuildValue("(Oi)", _x509_store_ctx_swigptr, 0); - _x509_store_ctx_inst = PyInstance_New(_klass, _x509_store_ctx_obj, NULL); + + _x509_store_ctx_inst = PyObject_CallObject(_klass, _x509_store_ctx_obj); + argv = Py_BuildValue("(iO)", ok, _x509_store_ctx_inst); } else { if (PyErr_Warn(PyExc_DeprecationWarning, "Old style callback, use cb_func(ok, store) instead")) { warning_raised_exception = 1; } - + x509 = X509_STORE_CTX_get_current_cert(ctx); errnum = X509_STORE_CTX_get_error(ctx); errdepth = X509_STORE_CTX_get_error_depth(ctx); - - ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx); + + ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); ssl_ctx = SSL_get_SSL_CTX(ssl); - + _x509 = SWIG_NewPointerObj((void *)x509, SWIGTYPE_p_X509, 0); _ssl_ctx = SWIG_NewPointerObj((void *)ssl_ctx, SWIGTYPE_p_SSL_CTX, 0); - argv = Py_BuildValue("(OOiii)", _ssl_ctx, _x509, errnum, errdepth, ok); + argv = Py_BuildValue("(OOiii)", _ssl_ctx, _x509, errnum, errdepth, ok); } if (!warning_raised_exception) { @@ -161,9 +326,10 @@ int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) { /* Got an exception in PyEval_CallObject(), let's fail verification * to be safe. */ - cret = 0; + cret = 0; } else { - cret = (int)PyInt_AsLong(ret); + /* FIXME This is possibly problematic if ret > MAXINT */ + cret = (int)PyLong_AsLong(ret); } Py_XDECREF(ret); Py_XDECREF(argv); @@ -182,15 +348,59 @@ int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) { return cret; } +int x509_store_verify_callback(int ok, X509_STORE_CTX *ctx) { + PyGILState_STATE gilstate; + PyObject *argv, *ret; + PyObject *_x509_store_ctx_swigptr=0, *_x509_store_ctx_obj=0, *_x509_store_ctx_inst=0, *_klass=0; + int cret; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + PyObject *x509mod; + + + gilstate = PyGILState_Ensure(); + + /* Below, handle only what is called 'new style callback' in ssl_verify_callback(). + TODO: does 'old style callback' exist any more? */ + x509mod = PyDict_GetItemString(PyImport_GetModuleDict(), "M2Crypto.X509"); + _klass = PyObject_GetAttrString(x509mod, "X509_Store_Context"); + _x509_store_ctx_swigptr = SWIG_NewPointerObj((void *)ctx, SWIGTYPE_p_X509_STORE_CTX, 0); + _x509_store_ctx_obj = Py_BuildValue("(Oi)", _x509_store_ctx_swigptr, 0); + + _x509_store_ctx_inst = PyObject_CallObject(_klass, _x509_store_ctx_obj); + + argv = Py_BuildValue("(iO)", ok, _x509_store_ctx_inst); + + ret = PyEval_CallObject(x509_store_verify_cb_func, argv); + if (!ret) { + /* Got an exception in PyEval_CallObject(), let's fail verification + * to be safe. + */ + cret = 0; + } else { + cret = (int)PyInt_AsLong(ret); + } + + Py_XDECREF(ret); + Py_XDECREF(argv); + Py_XDECREF(_x509_store_ctx_inst); + Py_XDECREF(_x509_store_ctx_obj); + Py_XDECREF(_x509_store_ctx_swigptr); + Py_XDECREF(_klass); + + PyGILState_Release(gilstate); + return cret; +} + void ssl_info_callback(const SSL *s, int where, int ret) { PyObject *argv, *retval, *_SSL; PyGILState_STATE gilstate; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ gilstate = PyGILState_Ensure(); _SSL = SWIG_NewPointerObj((void *)s, SWIGTYPE_p_SSL, 0); argv = Py_BuildValue("(iiO)", where, ret, _SSL); - + retval = PyEval_CallObject(ssl_info_cb_func, argv); Py_XDECREF(retval); @@ -204,6 +414,7 @@ DH *ssl_set_tmp_dh_callback(SSL *ssl, int is_export, int keylength) { PyObject *argv, *ret, *_ssl; DH *dh; PyGILState_STATE gilstate; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ gilstate = PyGILState_Ensure(); @@ -227,6 +438,7 @@ RSA *ssl_set_tmp_rsa_callback(SSL *ssl, int is_export, int keylength) { PyObject *argv, *ret, *_ssl; RSA *rsa; PyGILState_STATE gilstate; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ gilstate = PyGILState_Ensure(); @@ -246,17 +458,18 @@ RSA *ssl_set_tmp_rsa_callback(SSL *ssl, int is_export, int keylength) { return rsa; } -void gen_callback(int p, int n, void *arg) { +/* Universal callback for dh_generate_parameters, + * dsa_generate_parametersm, and rsa_generate_key */ +int bn_gencb_callback(int p, int n, BN_GENCB *gencb) { PyObject *argv, *ret, *cbfunc; - - PyGILState_STATE gilstate; - gilstate = PyGILState_Ensure(); - cbfunc = (PyObject *)arg; + + cbfunc = (PyObject *)BN_GENCB_get_arg(gencb); argv = Py_BuildValue("(ii)", p, n); ret = PyEval_CallObject(cbfunc, argv); + PyErr_Clear(); Py_DECREF(argv); Py_XDECREF(ret); - PyGILState_Release(gilstate); + return 1; } int passphrase_callback(char *buf, int num, int v, void *arg) { @@ -269,20 +482,25 @@ int passphrase_callback(char *buf, int num, int v, void *arg) { gilstate = PyGILState_Ensure(); cbfunc = (PyObject *)arg; argv = Py_BuildValue("(i)", v); + /* PyEval_CallObject sets exception, if needed. */ ret = PyEval_CallObject(cbfunc, argv); Py_DECREF(argv); if (ret == NULL) { PyGILState_Release(gilstate); return -1; } - if (!PyString_Check(ret)) { + + if (!PyBytes_Check(ret)) { + PyErr_SetString(PyExc_RuntimeError, + "Result of callback is not bytes()."); Py_DECREF(ret); PyGILState_Release(gilstate); return -1; } - if ((len = PyString_Size(ret)) > num) + if ((len = PyBytes_Size(ret)) > num) len = num; - str = PyString_AsString(ret); + str = PyBytes_AsString(ret); + for (i = 0; i < len; i++) buf[i] = str[i]; Py_DECREF(ret); @@ -292,34 +510,38 @@ int passphrase_callback(char *buf, int num, int v, void *arg) { %} %inline %{ + void lib_init() { +#if OPENSSL_VERSION_NUMBER < 0x10100000L SSLeay_add_all_algorithms(); ERR_load_ERR_strings(); +#endif } -/* Bignum routines that aren't not numerous enough to +/* Bignum routines that aren't not numerous enough to warrant a separate file. */ -PyObject *bn_to_mpi(BIGNUM *bn) { - int len; +PyObject *bn_to_mpi(const BIGNUM *bn) { + int len = 0; unsigned char *mpi; - PyObject *pyo; + PyObject *pyo; len = BN_bn2mpi(bn, NULL); if (!(mpi=(unsigned char *)PyMem_Malloc(len))) { - PyErr_SetString(PyExc_RuntimeError, - ERR_error_string(ERR_get_error(), NULL)); + m2_PyErr_Msg(PyExc_MemoryError); return NULL; } len=BN_bn2mpi(bn, mpi); - pyo=PyString_FromStringAndSize((const char *)mpi, len); + + pyo=PyBytes_FromStringAndSize((const char *)mpi, len); + PyMem_Free(mpi); return pyo; } -BIGNUM *mpi_to_bn(PyObject *value) { +const BIGNUM *mpi_to_bn(PyObject *value) { const void *vbuf; - int vlen; + int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; @@ -328,9 +550,9 @@ BIGNUM *mpi_to_bn(PyObject *value) { } PyObject *bn_to_bin(BIGNUM *bn) { - int len; + int len = 0; unsigned char *bin; - PyObject *pyo; + PyObject *pyo; len = BN_num_bytes(bn); if (!(bin=(unsigned char *)PyMem_Malloc(len))) { @@ -338,14 +560,16 @@ PyObject *bn_to_bin(BIGNUM *bn) { return NULL; } BN_bn2bin(bn, bin); - pyo=PyString_FromStringAndSize((const char *)bin, len); + + pyo=PyBytes_FromStringAndSize((const char *)bin, len); + PyMem_Free(bin); return pyo; } -BIGNUM *bin_to_bn(PyObject *value) { +const BIGNUM *bin_to_bn(PyObject *value) { const void *vbuf; - int vlen; + int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; @@ -355,25 +579,26 @@ BIGNUM *bin_to_bn(PyObject *value) { PyObject *bn_to_hex(BIGNUM *bn) { char *hex; - PyObject *pyo; - Py_ssize_t len; + PyObject *pyo; + Py_ssize_t len = 0; hex = BN_bn2hex(bn); if (!hex) { - PyErr_SetString(PyExc_RuntimeError, - ERR_error_string(ERR_get_error(), NULL)); + m2_PyErr_Msg(PyExc_RuntimeError); OPENSSL_free(hex); - return NULL; + return NULL; } len = strlen(hex); - pyo=PyString_FromStringAndSize(hex, len); + + pyo=PyBytes_FromStringAndSize(hex, len); + OPENSSL_free(hex); return pyo; } BIGNUM *hex_to_bn(PyObject *value) { const void *vbuf; - Py_ssize_t vlen; + Py_ssize_t vlen = 0; BIGNUM *bn; if (PyObject_AsReadBuffer(value, &vbuf, &vlen) == -1) @@ -384,8 +609,7 @@ BIGNUM *hex_to_bn(PyObject *value) { return NULL; } if (BN_hex2bn(&bn, (const char *)vbuf) <= 0) { - PyErr_SetString(PyExc_RuntimeError, - ERR_error_string(ERR_get_error(), NULL)); + m2_PyErr_Msg(PyExc_RuntimeError); BN_free(bn); return NULL; } @@ -394,7 +618,7 @@ BIGNUM *hex_to_bn(PyObject *value) { BIGNUM *dec_to_bn(PyObject *value) { const void *vbuf; - Py_ssize_t vlen; + Py_ssize_t vlen = 0; BIGNUM *bn; if (PyObject_AsReadBuffer(value, &vbuf, &vlen) == -1) @@ -405,8 +629,7 @@ BIGNUM *dec_to_bn(PyObject *value) { return NULL; } if ((BN_dec2bn(&bn, (const char *)vbuf) <= 0)) { - PyErr_SetString(PyExc_RuntimeError, - ERR_error_string(ERR_get_error(), NULL)); + m2_PyErr_Msg(PyExc_RuntimeError); BN_free(bn); return NULL; } @@ -418,23 +641,26 @@ BIGNUM *dec_to_bn(PyObject *value) { /* Various useful typemaps. */ %typemap(in) Blob * { - Py_ssize_t len; + Py_ssize_t len = 0; - if (!PyString_Check($input)) { + if (!PyBytes_Check($input)) { PyErr_SetString(PyExc_TypeError, "expected PyString"); return NULL; } - len=PyString_Size($input); + len=PyBytes_Size($input); + if (len > INT_MAX) { PyErr_SetString(PyExc_ValueError, "object too large"); - return -1; + return NULL; } $1=(Blob *)PyMem_Malloc(sizeof(Blob)); if (!$1) { PyErr_SetString(PyExc_MemoryError, "malloc Blob"); return NULL; } - $1->data=(unsigned char *)PyString_AsString($input); + + $1->data=(unsigned char *)PyBytes_AsString($input); + $1->len=len; } @@ -443,20 +669,14 @@ BIGNUM *dec_to_bn(PyObject *value) { Py_INCREF(Py_None); $result=Py_None; } else { - $result=PyString_FromStringAndSize((const char *)$1->data, $1->len); + + $result=PyBytes_FromStringAndSize((const char *)$1->data, $1->len); + PyMem_Free($1->data); PyMem_Free($1); } } -%typemap(in) FILE * { - if (!PyFile_Check($input)) { - PyErr_SetString(PyExc_TypeError, "expected PyFile"); - return NULL; - } - $1=PyFile_AsFile($input); -} - %typemap(in) PyObject *pyfunc { if (!PyCallable_Check($input)) { PyErr_SetString(PyExc_TypeError, "expected PyCallable"); @@ -466,7 +686,8 @@ BIGNUM *dec_to_bn(PyObject *value) { } %typemap(in) PyObject *pyblob { - if (!PyString_Check($input)) { + if (!PyBytes_Check($input)) { + PyErr_SetString(PyExc_TypeError, "expected PyString"); return NULL; } @@ -482,7 +703,7 @@ BIGNUM *dec_to_bn(PyObject *value) { } %typemap(out) int { - $result=PyInt_FromLong($1); + $result=PyLong_FromLong($1); if (PyErr_Occurred()) SWIG_fail; } @@ -493,9 +714,6 @@ BIGNUM *dec_to_bn(PyObject *value) { /* A bunch of "straight-thru" functions. */ -%rename(err_print_errors_fp) ERR_print_errors_fp; -%threadallow ERR_print_errors_fp; -extern void ERR_print_errors_fp(FILE *); %rename(err_print_errors) ERR_print_errors; %threadallow ERR_print_errors; extern void ERR_print_errors(BIO *); diff --git a/SWIG/_lib11_compat.i b/SWIG/_lib11_compat.i new file mode 100644 index 0000000..1ec42dd --- /dev/null +++ b/SWIG/_lib11_compat.i @@ -0,0 +1,458 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +%{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +#include +#include + +# define OPENSSL_zalloc(num) \ + CRYPTO_zalloc(num, __FILE__, __LINE__) + +static void *CRYPTO_zalloc(size_t num, const char *file, int line) +{ + void *ret = CRYPTO_malloc(num, file, line); + if (ret != NULL) + memset(ret, 0, num); + return ret; +} + +#include + +#ifndef BN_F_BN_GENCB_NEW +# define BN_F_BN_GENCB_NEW 143 +#endif + +# define BN_GENCB_get_arg(gencb) ((gencb)->arg) + +BN_GENCB *BN_GENCB_new(void) +{ + BN_GENCB *ret; + + if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) { + BNerr(BN_F_BN_GENCB_NEW, ERR_R_MALLOC_FAILURE); + return (NULL); + } + + return ret; +} + +void BN_GENCB_free(BN_GENCB *cb) +{ + if (cb == NULL) + return; + OPENSSL_free(cb); +} + + +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) +{ + /* If the fields n and e in r are NULL, the corresponding input + * parameters MUST be non-NULL for n and e. d may be + * left NULL (in case only the public key is used). + */ + if ((r->n == NULL && n == NULL) + || (r->e == NULL && e == NULL)) + return 0; + + if (n != NULL) { + BN_free(r->n); + r->n = n; + } + if (e != NULL) { + BN_free(r->e); + r->e = e; + } + if (d != NULL) { + BN_free(r->d); + r->d = d; + } + + return 1; +} + +int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) +{ + /* If the fields p and q in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->p == NULL && p == NULL) + || (r->q == NULL && q == NULL)) + return 0; + + if (p != NULL) { + BN_free(r->p); + r->p = p; + } + if (q != NULL) { + BN_free(r->q); + r->q = q; + } + + return 1; +} + +int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) +{ + /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->dmp1 == NULL && dmp1 == NULL) + || (r->dmq1 == NULL && dmq1 == NULL) + || (r->iqmp == NULL && iqmp == NULL)) + return 0; + + if (dmp1 != NULL) { + BN_free(r->dmp1); + r->dmp1 = dmp1; + } + if (dmq1 != NULL) { + BN_free(r->dmq1); + r->dmq1 = dmq1; + } + if (iqmp != NULL) { + BN_free(r->iqmp); + r->iqmp = iqmp; + } + + return 1; +} + +void RSA_get0_key(const RSA *r, + const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) +{ + if (n != NULL) + *n = r->n; + if (e != NULL) + *e = r->e; + if (d != NULL) + *d = r->d; +} + +void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) +{ + if (p != NULL) + *p = r->p; + if (q != NULL) + *q = r->q; +} + +void RSA_get0_crt_params(const RSA *r, + const BIGNUM **dmp1, const BIGNUM **dmq1, + const BIGNUM **iqmp) +{ + if (dmp1 != NULL) + *dmp1 = r->dmp1; + if (dmq1 != NULL) + *dmq1 = r->dmq1; + if (iqmp != NULL) + *iqmp = r->iqmp; +} + +void DSA_get0_pqg(const DSA *d, + const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) +{ + if (p != NULL) + *p = d->p; + if (q != NULL) + *q = d->q; + if (g != NULL) + *g = d->g; +} + +int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + /* If the fields p, q and g in d are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((d->p == NULL && p == NULL) + || (d->q == NULL && q == NULL) + || (d->g == NULL && g == NULL)) + return 0; + + if (p != NULL) { + BN_free(d->p); + d->p = p; + } + if (q != NULL) { + BN_free(d->q); + d->q = q; + } + if (g != NULL) { + BN_free(d->g); + d->g = g; + } + + return 1; +} + +void DSA_get0_key(const DSA *d, + const BIGNUM **pub_key, const BIGNUM **priv_key) +{ + if (pub_key != NULL) + *pub_key = d->pub_key; + if (priv_key != NULL) + *priv_key = d->priv_key; +} + +int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) +{ + /* If the field pub_key in d is NULL, the corresponding input + * parameters MUST be non-NULL. The priv_key field may + * be left NULL. + */ + if (d->pub_key == NULL && pub_key == NULL) + return 0; + + if (pub_key != NULL) { + BN_free(d->pub_key); + d->pub_key = pub_key; + } + if (priv_key != NULL) { + BN_free(d->priv_key); + d->priv_key = priv_key; + } + + return 1; +} + +void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) +{ + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} + +void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) +{ + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} + +void DH_get0_pqg(const DH *dh, + const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) +{ + if (p != NULL) + *p = dh->p; + if (q != NULL) + *q = dh->q; + if (g != NULL) + *g = dh->g; +} + +int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + /* If the fields p and g in d are NULL, the corresponding input + * parameters MUST be non-NULL. q may remain NULL. + */ + if ((dh->p == NULL && p == NULL) + || (dh->g == NULL && g == NULL)) + return 0; + + if (p != NULL) { + BN_free(dh->p); + dh->p = p; + } + if (q != NULL) { + BN_free(dh->q); + dh->q = q; + } + if (g != NULL) { + BN_free(dh->g); + dh->g = g; + } + + if (q != NULL) { + dh->length = BN_num_bits(q); + } + + return 1; +} + +void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) +{ + if (pub_key != NULL) + *pub_key = dh->pub_key; + if (priv_key != NULL) + *priv_key = dh->priv_key; +} + +int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) +{ + /* If the field pub_key in dh is NULL, the corresponding input + * parameters MUST be non-NULL. The priv_key field may + * be left NULL. + */ + if (dh->pub_key == NULL && pub_key == NULL) + return 0; + + if (pub_key != NULL) { + BN_free(dh->pub_key); + dh->pub_key = pub_key; + } + if (priv_key != NULL) { + BN_free(dh->priv_key); + dh->priv_key = priv_key; + } + + return 1; +} + +int DH_set_length(DH *dh, long length) +{ + dh->length = length; + return 1; +} + +const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx) +{ + return ctx->iv; +} + +unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx) +{ + return ctx->iv; +} + +EVP_MD_CTX *EVP_MD_CTX_new(void) +{ + return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); +} + +void EVP_MD_CTX_free(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +int RSA_size(const RSA* rsa) { + /* BIGNUM* n = NULL; + RSA_get0_key(rsa, n, NULL, NULL); */ + return BN_num_bytes(rsa->n); +} + +RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth) +{ + RSA_METHOD *ret; + + ret = OPENSSL_malloc(sizeof(RSA_METHOD)); + + if (ret != NULL) { + memcpy(ret, meth, sizeof(*meth)); + ret->name = OPENSSL_strdup(meth->name); + if (ret->name == NULL) { + OPENSSL_free(ret); + return NULL; + } + } + + return ret; +} + +int RSA_meth_set1_name(RSA_METHOD *meth, const char *name) +{ + char *tmpname; + + tmpname = OPENSSL_strdup(name); + if (tmpname == NULL) { + return 0; + } + + OPENSSL_free((char *)meth->name); + meth->name = tmpname; + + return 1; +} + +int RSA_meth_set_priv_enc(RSA_METHOD *meth, + int (*priv_enc) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + meth->rsa_priv_enc = priv_enc; + return 1; +} + +int RSA_meth_set_priv_dec(RSA_METHOD *meth, + int (*priv_dec) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + meth->rsa_priv_dec = priv_dec; + return 1; +} + +int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)) +{ + meth->finish = finish; + return 1; +} + +void RSA_meth_free(RSA_METHOD *meth) +{ + if (meth != NULL) { + OPENSSL_free((char *)meth->name); + OPENSSL_free(meth); + } +} + +int RSA_bits(const RSA *r) +{ + return (BN_num_bits(r->n)); +} + +RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) +{ + if (pkey->type != EVP_PKEY_RSA) { + return NULL; + } + return pkey->pkey.rsa; +} + +int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, + size_t *pderlen) +{ + /* Make sure encoding is valid */ + if (i2d_X509_NAME(nm, NULL) <= 0) + return 0; + if (pder != NULL) + *pder = (unsigned char *)nm->bytes->data; + if (pderlen != NULL) + *pderlen = nm->bytes->length; + return 1; +} + +#endif /* OPENSSL_VERSION_NUMBER */ +%} diff --git a/SWIG/_m2crypto.def b/SWIG/_m2crypto.def index 753db2c..3e9d5bc 100644 --- a/SWIG/_m2crypto.def +++ b/SWIG/_m2crypto.def @@ -1,2 +1,2 @@ EXPORTS -init__m2crypto +init_m2crypto diff --git a/SWIG/_m2crypto.i b/SWIG/_m2crypto.i index 3d779a1..e300a10 100644 --- a/SWIG/_m2crypto.i +++ b/SWIG/_m2crypto.i @@ -8,17 +8,47 @@ * */ -%module(threads=1) _m2crypto +%module(threads=1) m2crypto /* We really don't need threadblock (PyGILState_Ensure() etc.) anywhere. Disable threadallow as well, only enable it for operations likely to block. */ %nothreadblock; %nothreadallow; +#if SWIG_VERSION >= 0x030000 +#define __WCHAR_MAX__ __WCHAR_MAX +#define __WCHAR_MIN__ __WCHAR_MIN +#endif +/* https://gitlab.com/m2crypto/m2crypto/issues/246 */ +%ignore WCHAR_MAX; +%ignore WCHAR_MIN; +/* http://swig.10945.n7.nabble.com/SWIG-AsVal-wchar-t-error-td2264.html */ +%{ +int SWIG_AsVal_wchar_t(PyObject *p, wchar_t *c) { return SWIG_OK; } +PyObject *SWIG_From_wchar_t(wchar_t c) { return SWIG_Py_Void(); } +%} + +%{ +#ifdef _WIN32 +#define _WINSOCKAPI_ +#include +#include +#pragma comment(lib, "Ws2_32") +typedef unsigned __int64 uint64_t; +#endif +%} + %{ +#if defined __GNUC__ && __GNUC__ < 5 +#pragma GCC diagnostic ignored "-Wunused-label" +#pragma GCC diagnostic warning "-Wstrict-prototypes" +#endif + #include #include #include <_lib.h> +#include +#include #include "compile.h" @@ -26,22 +56,15 @@ static PyObject *ssl_verify_cb_func; static PyObject *ssl_info_cb_func; static PyObject *ssl_set_tmp_dh_cb_func; static PyObject *ssl_set_tmp_rsa_cb_func; +static PyObject *x509_store_verify_cb_func; %} %include -#if OPENSSL_VERSION_NUMBER >= 0x0090707fL -#define CONST const -#else -#define CONST -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x0090800fL -#define CONST098 const -#else -#define CONST098 -#endif /* Bring in STACK_OF macro definition */ +#ifdef _WIN32 +%include +#endif %include /* Bring in LHASH_OF macro definition */ @@ -54,6 +77,7 @@ static PyObject *ssl_set_tmp_rsa_cb_func; #define LHASH_OF(type) struct lhash_st_##type #endif + %include constraints.i %include _threads.i %include _lib.i diff --git a/SWIG/_m2crypto_wrap.c b/SWIG/_m2crypto_wrap.c new file mode 100644 index 0000000..0f07702 --- /dev/null +++ b/SWIG/_m2crypto_wrap.c @@ -0,0 +1,32491 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.10 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +#define SWIGPYTHON +#define SWIG_PYTHON_THREADS +#define SWIG_PYTHON_DIRECTOR_NO_VTABLE +#define SWIGPYTHON_BUILTIN + +/* ----------------------------------------------------------------------------- + * This section contains generic SWIG labels for method/variable + * declarations/attributes, and other compiler dependent labels. + * ----------------------------------------------------------------------------- */ + +/* template workaround for compilers that cannot correctly implement the C++ standard */ +#ifndef SWIGTEMPLATEDISAMBIGUATOR +# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) +# define SWIGTEMPLATEDISAMBIGUATOR template +# elif defined(__HP_aCC) +/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ +/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ +# define SWIGTEMPLATEDISAMBIGUATOR template +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +#endif + +/* inline attribute */ +#ifndef SWIGINLINE +# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +# else +# define SWIGINLINE +# endif +#endif + +/* attribute recognised by some compilers to avoid 'unused' warnings */ +#ifndef SWIGUNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIG_MSC_UNSUPPRESS_4505 +# if defined(_MSC_VER) +# pragma warning(disable : 4505) /* unreferenced local function has been removed */ +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ +#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) +# define _SCL_SECURE_NO_DEPRECATE +#endif + + + +/* Python.h has to appear first */ +#include + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic C API SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "4" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the SWIG runtime code. + In 99.9% of the cases, SWIG just needs to declare them as 'static'. + + But only do this if strictly necessary, ie, if you have problems + with your compiler or suchlike. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 +#define SWIG_CAST_NEW_MEMORY 0x2 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The SWIG conversion methods, as ConvertPtr, return an integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old versions of SWIG, code such as the following was usually written: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + which is the same really, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + also requires SWIG_ConvertPtr to return new result values, such as + + int SWIG_ConvertPtr(obj, ptr,...) { + if () { + if () { + *ptr = ; + return SWIG_NEWOBJ; + } else { + *ptr = ; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + SWIG errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() +*/ + +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast(r) (r) +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *, int *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store information on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class" == "Class", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (int)((l1 - f1) - (l2 - f2)); +} + +/* + Check type equivalence in a name list like ||... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCmp(const char *nb, const char *tb) { + int equiv = 1; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (equiv != 0 && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = SWIG_TypeNameComp(nb, ne, tb, te); + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like ||... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + return SWIG_TypeCmp(nb, tb) == 0 ? 1 : 0; +} + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + if (ty) { + swig_cast_info *iter = ty->cast; + while (iter) { + if (strcmp(iter->type->name, c) == 0) { + if (iter == ty->cast) + return iter; + /* Move iter to the top of the linked list */ + iter->prev->next = iter->next; + if (iter->next) + iter->next->prev = iter->prev; + iter->next = ty->cast; + iter->prev = 0; + if (ty->cast) ty->cast->prev = iter; + ty->cast = iter; + return iter; + } + iter = iter->next; + } + } + return 0; +} + +/* + Identical to SWIG_TypeCheck, except strcmp is replaced with a pointer comparison +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *ty) { + if (ty) { + swig_cast_info *iter = ty->cast; + while (iter) { + if (iter->type == from) { + if (iter == ty->cast) + return iter; + /* Move iter to the top of the linked list */ + iter->prev->next = iter->next; + if (iter->next) + iter->next->prev = iter->prev; + iter->next = ty->cast; + iter->prev = 0; + if (ty->cast) ty->cast->prev = iter; + ty->cast = iter; + return iter; + } + iter = iter->next; + } + } + return 0; +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + register size_t l = 0; + register size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + register size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + register int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + register size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + register const unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + + +/* Compatibility macros for Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + +#define PyClass_Check(obj) PyObject_IsInstance(obj, (PyObject *)&PyType_Type) +#define PyInt_Check(x) PyLong_Check(x) +#define PyInt_AsLong(x) PyLong_AsLong(x) +#define PyInt_FromLong(x) PyLong_FromLong(x) +#define PyInt_FromSize_t(x) PyLong_FromSize_t(x) +#define PyString_Check(name) PyBytes_Check(name) +#define PyString_FromString(x) PyUnicode_FromString(x) +#define PyString_Format(fmt, args) PyUnicode_Format(fmt, args) +#define PyString_AsString(str) PyBytes_AsString(str) +#define PyString_Size(str) PyBytes_Size(str) +#define PyString_InternFromString(key) PyUnicode_InternFromString(key) +#define Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_BASETYPE +#define PyString_AS_STRING(x) PyUnicode_AS_STRING(x) +#define _PyLong_FromSsize_t(x) PyLong_FromSsize_t(x) + +#endif + +#ifndef Py_TYPE +# define Py_TYPE(op) ((op)->ob_type) +#endif + +/* SWIG APIs for compatibility of both Python 2 & 3 */ + +#if PY_VERSION_HEX >= 0x03000000 +# define SWIG_Python_str_FromFormat PyUnicode_FromFormat +#else +# define SWIG_Python_str_FromFormat PyString_FromFormat +#endif + + +/* Warning: This function will allocate a new string in Python 3, + * so please call SWIG_Python_str_DelForPy3(x) to free the space. + */ +SWIGINTERN char* +SWIG_Python_str_AsChar(PyObject *str) +{ +#if PY_VERSION_HEX >= 0x03000000 + char *cstr; + char *newstr; + Py_ssize_t len; + str = PyUnicode_AsUTF8String(str); + PyBytes_AsStringAndSize(str, &cstr, &len); + newstr = (char *) malloc(len+1); + memcpy(newstr, cstr, len+1); + Py_XDECREF(str); + return newstr; +#else + return PyString_AsString(str); +#endif +} + +#if PY_VERSION_HEX >= 0x03000000 +# define SWIG_Python_str_DelForPy3(x) free( (void*) (x) ) +#else +# define SWIG_Python_str_DelForPy3(x) +#endif + + +SWIGINTERN PyObject* +SWIG_Python_str_FromChar(const char *c) +{ +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromString(c); +#else + return PyString_FromString(c); +#endif +} + +/* Add PyOS_snprintf for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# define PyOS_snprintf _snprintf +# else +# define PyOS_snprintf snprintf +# endif +#endif + +/* A crude PyString_FromFormat implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 + +#ifndef SWIG_PYBUFFER_SIZE +# define SWIG_PYBUFFER_SIZE 1024 +#endif + +static PyObject * +PyString_FromFormat(const char *fmt, ...) { + va_list ap; + char buf[SWIG_PYBUFFER_SIZE * 2]; + int res; + va_start(ap, fmt); + res = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf); +} +#endif + +/* Add PyObject_Del for old Pythons */ +#if PY_VERSION_HEX < 0x01060000 +# define PyObject_Del(op) PyMem_DEL((op)) +#endif +#ifndef PyObject_DEL +# define PyObject_DEL PyObject_Del +#endif + +/* A crude PyExc_StopIteration exception for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# ifndef PyExc_StopIteration +# define PyExc_StopIteration PyExc_RuntimeError +# endif +# ifndef PyObject_GenericGetAttr +# define PyObject_GenericGetAttr 0 +# endif +#endif + +/* Py_NotImplemented is defined in 2.1 and up. */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef Py_NotImplemented +# define Py_NotImplemented PyExc_RuntimeError +# endif +#endif + +/* A crude PyString_AsStringAndSize implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef PyString_AsStringAndSize +# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;} +# endif +#endif + +/* PySequence_Size for old Pythons */ +#if PY_VERSION_HEX < 0x02000000 +# ifndef PySequence_Size +# define PySequence_Size PySequence_Length +# endif +#endif + +/* PyBool_FromLong for old Pythons */ +#if PY_VERSION_HEX < 0x02030000 +static +PyObject *PyBool_FromLong(long ok) +{ + PyObject *result = ok ? Py_True : Py_False; + Py_INCREF(result); + return result; +} +#endif + +/* Py_ssize_t for old Pythons */ +/* This code is as recommended by: */ +/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +# define PY_SSIZE_T_MAX INT_MAX +# define PY_SSIZE_T_MIN INT_MIN +typedef inquiry lenfunc; +typedef intargfunc ssizeargfunc; +typedef intintargfunc ssizessizeargfunc; +typedef intobjargproc ssizeobjargproc; +typedef intintobjargproc ssizessizeobjargproc; +typedef getreadbufferproc readbufferproc; +typedef getwritebufferproc writebufferproc; +typedef getsegcountproc segcountproc; +typedef getcharbufferproc charbufferproc; +static long PyNumber_AsSsize_t (PyObject *x, void *SWIGUNUSEDPARM(exc)) +{ + long result = 0; + PyObject *i = PyNumber_Int(x); + if (i) { + result = PyInt_AsLong(i); + Py_DECREF(i); + } + return result; +} +#endif + +#if PY_VERSION_HEX < 0x02050000 +#define PyInt_FromSize_t(x) PyInt_FromLong((long)x) +#endif + +#if PY_VERSION_HEX < 0x02040000 +#define Py_VISIT(op) \ + do { \ + if (op) { \ + int vret = visit((op), arg); \ + if (vret) \ + return vret; \ + } \ + } while (0) +#endif + +#if PY_VERSION_HEX < 0x02030000 +typedef struct { + PyTypeObject type; + PyNumberMethods as_number; + PyMappingMethods as_mapping; + PySequenceMethods as_sequence; + PyBufferProcs as_buffer; + PyObject *name, *slots; +} PyHeapTypeObject; +#endif + +#if PY_VERSION_HEX < 0x02030000 +typedef destructor freefunc; +#endif + +#if ((PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 6) || \ + (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 0) || \ + (PY_MAJOR_VERSION > 3)) +# define SWIGPY_USE_CAPSULE +# define SWIGPY_CAPSULE_NAME ((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION ".type_pointer_capsule" SWIG_TYPE_TABLE_NAME) +#endif + +#if PY_VERSION_HEX < 0x03020000 +#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type) +#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name) +#endif + +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIME PyObject* +SWIG_Python_ErrorType(int code) { + PyObject* type = 0; + switch(code) { + case SWIG_MemoryError: + type = PyExc_MemoryError; + break; + case SWIG_IOError: + type = PyExc_IOError; + break; + case SWIG_RuntimeError: + type = PyExc_RuntimeError; + break; + case SWIG_IndexError: + type = PyExc_IndexError; + break; + case SWIG_TypeError: + type = PyExc_TypeError; + break; + case SWIG_DivisionByZero: + type = PyExc_ZeroDivisionError; + break; + case SWIG_OverflowError: + type = PyExc_OverflowError; + break; + case SWIG_SyntaxError: + type = PyExc_SyntaxError; + break; + case SWIG_ValueError: + type = PyExc_ValueError; + break; + case SWIG_SystemError: + type = PyExc_SystemError; + break; + case SWIG_AttributeError: + type = PyExc_AttributeError; + break; + default: + type = PyExc_RuntimeError; + } + return type; +} + + +SWIGRUNTIME void +SWIG_Python_AddErrorMsg(const char* mesg) +{ + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + + if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); + if (value) { + char *tmp; + PyObject *old_str = PyObject_Str(value); + PyErr_Clear(); + Py_XINCREF(type); + + PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); + SWIG_Python_str_DelForPy3(tmp); + Py_DECREF(old_str); + Py_DECREF(value); + } else { + PyErr_SetString(PyExc_RuntimeError, mesg); + } +} + +#if defined(SWIG_PYTHON_NO_THREADS) +# if defined(SWIG_PYTHON_THREADS) +# undef SWIG_PYTHON_THREADS +# endif +#endif +#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ +# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) +# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */ +# define SWIG_PYTHON_USE_GIL +# endif +# endif +# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ +# ifndef SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() +# endif +# ifdef __cplusplus /* C++ code */ + class SWIG_Python_Thread_Block { + bool status; + PyGILState_STATE state; + public: + void end() { if (status) { PyGILState_Release(state); status = false;} } + SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} + ~SWIG_Python_Thread_Block() { end(); } + }; + class SWIG_Python_Thread_Allow { + bool status; + PyThreadState *save; + public: + void end() { if (status) { PyEval_RestoreThread(save); status = false; }} + SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} + ~SWIG_Python_Thread_Allow() { end(); } + }; +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block +# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow +# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() +# else /* C code */ +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() +# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() +# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) +# endif +# else /* Old thread way, not implemented, user must provide it */ +# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) +# define SWIG_PYTHON_INITIALIZE_THREADS +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) +# define SWIG_PYTHON_THREAD_END_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# endif +# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) +# define SWIG_PYTHON_THREAD_END_ALLOW +# endif +# endif +#else /* No thread support */ +# define SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# define SWIG_PYTHON_THREAD_END_BLOCK +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# define SWIG_PYTHON_THREAD_END_ALLOW +#endif + +/* ----------------------------------------------------------------------------- + * Python API portion that goes into the runtime + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------------------------------------------------------- + * Constant declarations + * ----------------------------------------------------------------------------- */ + +/* Constant Types */ +#define SWIG_PY_POINTER 4 +#define SWIG_PY_BINARY 5 + +/* Constant information structure */ +typedef struct swig_const_info { + int type; + char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_const_info; + + +/* ----------------------------------------------------------------------------- + * Wrapper of PyInstanceMethod_New() used in Python 3 + * It is exported to the generated module, used for -fastproxy + * ----------------------------------------------------------------------------- */ +#if PY_VERSION_HEX >= 0x03000000 +SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *func) +{ + return PyInstanceMethod_New(func); +} +#else +SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *SWIGUNUSEDPARM(func)) +{ + return NULL; +} +#endif + +#ifdef __cplusplus +} +#endif + + +/* ----------------------------------------------------------------------------- + * pyrun.swg + * + * This file contains the runtime support for Python modules + * and includes code for managing global variables and pointer + * type checking. + * + * ----------------------------------------------------------------------------- */ + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) +#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) +#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) + +#ifdef SWIGPYTHON_BUILTIN +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(self, ptr, type, flags) +#else +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) +#endif + +#define SWIG_InternalNewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) + +#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) +#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) +#define swig_owntype int + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) +#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(NULL, ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Python_GetModule(clientdata) +#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) +#define SWIG_NewClientData(obj) SwigPyClientData_New(obj) + +#define SWIG_SetErrorObj SWIG_Python_SetErrorObj +#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg +#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail + + +/* Runtime API implementation */ + +/* Error manipulation */ + +SWIGINTERN void +SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetObject(errtype, obj); + Py_DECREF(obj); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +SWIGINTERN void +SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetString(errtype, msg); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) + +/* Set a constant value */ + +#if defined(SWIGPYTHON_BUILTIN) + +SWIGINTERN void +SwigPyBuiltin_AddPublicSymbol(PyObject *seq, const char *key) { + PyObject *s = PyString_InternFromString(key); + PyList_Append(seq, s); + Py_DECREF(s); +} + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, PyObject *public_interface, const char *name, PyObject *obj) { +#if PY_VERSION_HEX < 0x02030000 + PyDict_SetItemString(d, (char *)name, obj); +#else + PyDict_SetItemString(d, name, obj); +#endif + Py_DECREF(obj); + if (public_interface) + SwigPyBuiltin_AddPublicSymbol(public_interface, name); +} + +#else + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { +#if PY_VERSION_HEX < 0x02030000 + PyDict_SetItemString(d, (char *)name, obj); +#else + PyDict_SetItemString(d, name, obj); +#endif + Py_DECREF(obj); +} + +#endif + +/* Append a value to the result obj */ + +SWIGINTERN PyObject* +SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { +#if !defined(SWIG_PYTHON_OUTPUT_TUPLE) + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyList_Check(result)) { + PyObject *o2 = result; + result = PyList_New(1); + PyList_SetItem(result, 0, o2); + } + PyList_Append(result,obj); + Py_DECREF(obj); + } + return result; +#else + PyObject* o2; + PyObject* o3; + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyTuple_Check(result)) { + o2 = result; + result = PyTuple_New(1); + PyTuple_SET_ITEM(result, 0, o2); + } + o3 = PyTuple_New(1); + PyTuple_SET_ITEM(o3, 0, obj); + o2 = result; + result = PySequence_Concat(o2, o3); + Py_DECREF(o2); + Py_DECREF(o3); + } + return result; +#endif +} + +/* Unpack the argument tuple */ + +SWIGINTERN int +SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) +{ + if (!args) { + if (!min && !max) { + return 1; + } else { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", + name, (min == max ? "" : "at least "), (int)min); + return 0; + } + } + if (!PyTuple_Check(args)) { + if (min <= 1 && max >= 1) { + register int i; + objs[0] = args; + for (i = 1; i < max; ++i) { + objs[i] = 0; + } + return 2; + } + PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); + return 0; + } else { + register Py_ssize_t l = PyTuple_GET_SIZE(args); + if (l < min) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at least "), (int)min, (int)l); + return 0; + } else if (l > max) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at most "), (int)max, (int)l); + return 0; + } else { + register int i; + for (i = 0; i < l; ++i) { + objs[i] = PyTuple_GET_ITEM(args, i); + } + for (; l < max; ++l) { + objs[l] = 0; + } + return i + 1; + } + } +} + +/* A functor is a function object with one single object argument */ +#if PY_VERSION_HEX >= 0x02020000 +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); +#else +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj); +#endif + +/* + Helper for static pointer initialization for both C and C++ code, for example + static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); +*/ +#ifdef __cplusplus +#define SWIG_STATIC_POINTER(var) var +#else +#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var +#endif + +/* ----------------------------------------------------------------------------- + * Pointer declarations + * ----------------------------------------------------------------------------- */ + +/* Flags for new pointer objects */ +#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) +#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) + +#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) + +#define SWIG_BUILTIN_TP_INIT (SWIG_POINTER_OWN << 2) +#define SWIG_BUILTIN_INIT (SWIG_BUILTIN_TP_INIT | SWIG_POINTER_OWN) + +#ifdef __cplusplus +extern "C" { +#endif + +/* How to access Py_None */ +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# ifndef SWIG_PYTHON_NO_BUILD_NONE +# ifndef SWIG_PYTHON_BUILD_NONE +# define SWIG_PYTHON_BUILD_NONE +# endif +# endif +#endif + +#ifdef SWIG_PYTHON_BUILD_NONE +# ifdef Py_None +# undef Py_None +# define Py_None SWIG_Py_None() +# endif +SWIGRUNTIMEINLINE PyObject * +_SWIG_Py_None(void) +{ + PyObject *none = Py_BuildValue((char*)""); + Py_DECREF(none); + return none; +} +SWIGRUNTIME PyObject * +SWIG_Py_None(void) +{ + static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None(); + return none; +} +#endif + +/* The python void return value */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Py_Void(void) +{ + PyObject *none = Py_None; + Py_INCREF(none); + return none; +} + +/* SwigPyClientData */ + +typedef struct { + PyObject *klass; + PyObject *newraw; + PyObject *newargs; + PyObject *destroy; + int delargs; + int implicitconv; + PyTypeObject *pytype; +} SwigPyClientData; + +SWIGRUNTIMEINLINE int +SWIG_Python_CheckImplicit(swig_type_info *ty) +{ + SwigPyClientData *data = (SwigPyClientData *)ty->clientdata; + return data ? data->implicitconv : 0; +} + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_ExceptionType(swig_type_info *desc) { + SwigPyClientData *data = desc ? (SwigPyClientData *) desc->clientdata : 0; + PyObject *klass = data ? data->klass : 0; + return (klass ? klass : PyExc_RuntimeError); +} + + +SWIGRUNTIME SwigPyClientData * +SwigPyClientData_New(PyObject* obj) +{ + if (!obj) { + return 0; + } else { + SwigPyClientData *data = (SwigPyClientData *)malloc(sizeof(SwigPyClientData)); + /* the klass element */ + data->klass = obj; + Py_INCREF(data->klass); + /* the newraw method and newargs arguments used to create a new raw instance */ + if (PyClass_Check(obj)) { + data->newraw = 0; + data->newargs = obj; + Py_INCREF(obj); + } else { +#if (PY_VERSION_HEX < 0x02020000) + data->newraw = 0; +#else + data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__"); +#endif + if (data->newraw) { + Py_INCREF(data->newraw); + data->newargs = PyTuple_New(1); + PyTuple_SetItem(data->newargs, 0, obj); + } else { + data->newargs = obj; + } + Py_INCREF(data->newargs); + } + /* the destroy method, aka as the C++ delete method */ + data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__"); + if (PyErr_Occurred()) { + PyErr_Clear(); + data->destroy = 0; + } + if (data->destroy) { + int flags; + Py_INCREF(data->destroy); + flags = PyCFunction_GET_FLAGS(data->destroy); +#ifdef METH_O + data->delargs = !(flags & (METH_O)); +#else + data->delargs = 0; +#endif + } else { + data->delargs = 0; + } + data->implicitconv = 0; + data->pytype = 0; + return data; + } +} + +SWIGRUNTIME void +SwigPyClientData_Del(SwigPyClientData *data) { + Py_XDECREF(data->newraw); + Py_XDECREF(data->newargs); + Py_XDECREF(data->destroy); +} + +/* =============== SwigPyObject =====================*/ + +typedef struct { + PyObject_HEAD + void *ptr; + swig_type_info *ty; + int own; + PyObject *next; +#ifdef SWIGPYTHON_BUILTIN + PyObject *dict; +#endif +} SwigPyObject; + +SWIGRUNTIME PyObject * +SwigPyObject_long(SwigPyObject *v) +{ + return PyLong_FromVoidPtr(v->ptr); +} + +SWIGRUNTIME PyObject * +SwigPyObject_format(const char* fmt, SwigPyObject *v) +{ + PyObject *res = NULL; + PyObject *args = PyTuple_New(1); + if (args) { + if (PyTuple_SetItem(args, 0, SwigPyObject_long(v)) == 0) { + PyObject *ofmt = SWIG_Python_str_FromChar(fmt); + if (ofmt) { +#if PY_VERSION_HEX >= 0x03000000 + res = PyUnicode_Format(ofmt,args); +#else + res = PyString_Format(ofmt,args); +#endif + Py_DECREF(ofmt); + } + Py_DECREF(args); + } + } + return res; +} + +SWIGRUNTIME PyObject * +SwigPyObject_oct(SwigPyObject *v) +{ + return SwigPyObject_format("%o",v); +} + +SWIGRUNTIME PyObject * +SwigPyObject_hex(SwigPyObject *v) +{ + return SwigPyObject_format("%x",v); +} + +SWIGRUNTIME PyObject * +#ifdef METH_NOARGS +SwigPyObject_repr(SwigPyObject *v) +#else +SwigPyObject_repr(SwigPyObject *v, PyObject *args) +#endif +{ + const char *name = SWIG_TypePrettyName(v->ty); + PyObject *repr = SWIG_Python_str_FromFormat("", (name ? name : "unknown"), (void *)v); + if (v->next) { +# ifdef METH_NOARGS + PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next); +# else + PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next, args); +# endif +# if PY_VERSION_HEX >= 0x03000000 + PyObject *joined = PyUnicode_Concat(repr, nrep); + Py_DecRef(repr); + Py_DecRef(nrep); + repr = joined; +# else + PyString_ConcatAndDel(&repr,nrep); +# endif + } + return repr; +} + +SWIGRUNTIME int +SwigPyObject_print(SwigPyObject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ + char *str; +#ifdef METH_NOARGS + PyObject *repr = SwigPyObject_repr(v); +#else + PyObject *repr = SwigPyObject_repr(v, NULL); +#endif + if (repr) { + str = SWIG_Python_str_AsChar(repr); + fputs(str, fp); + SWIG_Python_str_DelForPy3(str); + Py_DECREF(repr); + return 0; + } else { + return 1; + } +} + +SWIGRUNTIME PyObject * +SwigPyObject_str(SwigPyObject *v) +{ + char result[SWIG_BUFFER_SIZE]; + return SWIG_PackVoidPtr(result, v->ptr, v->ty->name, sizeof(result)) ? + SWIG_Python_str_FromChar(result) : 0; +} + +SWIGRUNTIME int +SwigPyObject_compare(SwigPyObject *v, SwigPyObject *w) +{ + void *i = v->ptr; + void *j = w->ptr; + return (i < j) ? -1 : ((i > j) ? 1 : 0); +} + +/* Added for Python 3.x, would it also be useful for Python 2.x? */ +SWIGRUNTIME PyObject* +SwigPyObject_richcompare(SwigPyObject *v, SwigPyObject *w, int op) +{ + PyObject* res; + if( op != Py_EQ && op != Py_NE ) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + res = PyBool_FromLong( (SwigPyObject_compare(v, w)==0) == (op == Py_EQ) ? 1 : 0); + return res; +} + + +SWIGRUNTIME PyTypeObject* SwigPyObject_TypeOnce(void); + +#ifdef SWIGPYTHON_BUILTIN +static swig_type_info *SwigPyObject_stype = 0; +SWIGRUNTIME PyTypeObject* +SwigPyObject_type(void) { + SwigPyClientData *cd; + assert(SwigPyObject_stype); + cd = (SwigPyClientData*) SwigPyObject_stype->clientdata; + assert(cd); + assert(cd->pytype); + return cd->pytype; +} +#else +SWIGRUNTIME PyTypeObject* +SwigPyObject_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyObject_TypeOnce(); + return type; +} +#endif + +SWIGRUNTIMEINLINE int +SwigPyObject_Check(PyObject *op) { +#ifdef SWIGPYTHON_BUILTIN + PyTypeObject *target_tp = SwigPyObject_type(); + if (PyType_IsSubtype(op->ob_type, target_tp)) + return 1; + return (strcmp(op->ob_type->tp_name, "SwigPyObject") == 0); +#else + return (Py_TYPE(op) == SwigPyObject_type()) + || (strcmp(Py_TYPE(op)->tp_name,"SwigPyObject") == 0); +#endif +} + +SWIGRUNTIME PyObject * +SwigPyObject_New(void *ptr, swig_type_info *ty, int own); + +SWIGRUNTIME void +SwigPyObject_dealloc(PyObject *v) +{ + SwigPyObject *sobj = (SwigPyObject *) v; + PyObject *next = sobj->next; + if (sobj->own == SWIG_POINTER_OWN) { + swig_type_info *ty = sobj->ty; + SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; + PyObject *destroy = data ? data->destroy : 0; + if (destroy) { + /* destroy is always a VARARGS method */ + PyObject *res; + if (data->delargs) { + /* we need to create a temporary object to carry the destroy operation */ + PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0); + res = SWIG_Python_CallFunctor(destroy, tmp); + Py_DECREF(tmp); + } else { + PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); + PyObject *mself = PyCFunction_GET_SELF(destroy); + res = ((*meth)(mself, v)); + } + Py_XDECREF(res); + } +#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) + else { + const char *name = SWIG_TypePrettyName(ty); + printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); + } +#endif + } + Py_XDECREF(next); + PyObject_DEL(v); +} + +SWIGRUNTIME PyObject* +SwigPyObject_append(PyObject* v, PyObject* next) +{ + SwigPyObject *sobj = (SwigPyObject *) v; +#ifndef METH_O + PyObject *tmp = 0; + if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL; + next = tmp; +#endif + if (!SwigPyObject_Check(next)) { + return NULL; + } + sobj->next = next; + Py_INCREF(next); + return SWIG_Py_Void(); +} + +SWIGRUNTIME PyObject* +#ifdef METH_NOARGS +SwigPyObject_next(PyObject* v) +#else +SwigPyObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + SwigPyObject *sobj = (SwigPyObject *) v; + if (sobj->next) { + Py_INCREF(sobj->next); + return sobj->next; + } else { + return SWIG_Py_Void(); + } +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +SwigPyObject_disown(PyObject *v) +#else +SwigPyObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + SwigPyObject *sobj = (SwigPyObject *)v; + sobj->own = 0; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +SwigPyObject_acquire(PyObject *v) +#else +SwigPyObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + SwigPyObject *sobj = (SwigPyObject *)v; + sobj->own = SWIG_POINTER_OWN; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +SwigPyObject_own(PyObject *v, PyObject *args) +{ + PyObject *val = 0; +#if (PY_VERSION_HEX < 0x02020000) + if (!PyArg_ParseTuple(args,(char *)"|O:own",&val)) +#elif (PY_VERSION_HEX < 0x02050000) + if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val)) +#else + if (!PyArg_UnpackTuple(args, "own", 0, 1, &val)) +#endif + { + return NULL; + } + else + { + SwigPyObject *sobj = (SwigPyObject *)v; + PyObject *obj = PyBool_FromLong(sobj->own); + if (val) { +#ifdef METH_NOARGS + if (PyObject_IsTrue(val)) { + SwigPyObject_acquire(v); + } else { + SwigPyObject_disown(v); + } +#else + if (PyObject_IsTrue(val)) { + SwigPyObject_acquire(v,args); + } else { + SwigPyObject_disown(v,args); + } +#endif + } + return obj; + } +} + +#ifdef METH_O +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)SwigPyObject_disown, METH_NOARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)SwigPyObject_acquire, METH_NOARGS, (char *)"acquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)SwigPyObject_append, METH_O, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)SwigPyObject_next, METH_NOARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)SwigPyObject_repr, METH_NOARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#else +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)SwigPyObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)SwigPyObject_acquire, METH_VARARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)SwigPyObject_append, METH_VARARGS, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)SwigPyObject_next, METH_VARARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)SwigPyObject_repr, METH_VARARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#endif + +#if PY_VERSION_HEX < 0x02020000 +SWIGINTERN PyObject * +SwigPyObject_getattr(SwigPyObject *sobj,char *name) +{ + return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name); +} +#endif + +SWIGRUNTIME PyTypeObject* +SwigPyObject_TypeOnce(void) { + static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; + + static PyNumberMethods SwigPyObject_as_number = { + (binaryfunc)0, /*nb_add*/ + (binaryfunc)0, /*nb_subtract*/ + (binaryfunc)0, /*nb_multiply*/ + /* nb_divide removed in Python 3 */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc)0, /*nb_divide*/ +#endif + (binaryfunc)0, /*nb_remainder*/ + (binaryfunc)0, /*nb_divmod*/ + (ternaryfunc)0,/*nb_power*/ + (unaryfunc)0, /*nb_negative*/ + (unaryfunc)0, /*nb_positive*/ + (unaryfunc)0, /*nb_absolute*/ + (inquiry)0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ +#if PY_VERSION_HEX < 0x03000000 + 0, /*nb_coerce*/ +#endif + (unaryfunc)SwigPyObject_long, /*nb_int*/ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc)SwigPyObject_long, /*nb_long*/ +#else + 0, /*nb_reserved*/ +#endif + (unaryfunc)0, /*nb_float*/ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc)SwigPyObject_oct, /*nb_oct*/ + (unaryfunc)SwigPyObject_hex, /*nb_hex*/ +#endif +#if PY_VERSION_HEX >= 0x03000000 /* 3.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index, nb_inplace_divide removed */ +#elif PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ +#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ +#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */ + 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */ +#endif + }; + + static PyTypeObject swigpyobject_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp = { + /* PyObject header changed in Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + (char *)"SwigPyObject", /* tp_name */ + sizeof(SwigPyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SwigPyObject_dealloc, /* tp_dealloc */ + (printfunc)SwigPyObject_print, /* tp_print */ +#if PY_VERSION_HEX < 0x02020000 + (getattrfunc)SwigPyObject_getattr, /* tp_getattr */ +#else + (getattrfunc)0, /* tp_getattr */ +#endif + (setattrfunc)0, /* tp_setattr */ +#if PY_VERSION_HEX >= 0x03000000 + 0, /* tp_reserved in 3.0.1, tp_compare in 3.0.0 but not used */ +#else + (cmpfunc)SwigPyObject_compare, /* tp_compare */ +#endif + (reprfunc)SwigPyObject_repr, /* tp_repr */ + &SwigPyObject_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)SwigPyObject_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigobject_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)SwigPyObject_richcompare,/* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + swigobject_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + swigpyobject_type = tmp; + type_init = 1; +#if PY_VERSION_HEX < 0x02020000 + swigpyobject_type.ob_type = &PyType_Type; +#else + if (PyType_Ready(&swigpyobject_type) < 0) + return NULL; +#endif + } + return &swigpyobject_type; +} + +SWIGRUNTIME PyObject * +SwigPyObject_New(void *ptr, swig_type_info *ty, int own) +{ + SwigPyObject *sobj = PyObject_NEW(SwigPyObject, SwigPyObject_type()); + if (sobj) { + sobj->ptr = ptr; + sobj->ty = ty; + sobj->own = own; + sobj->next = 0; + } + return (PyObject *)sobj; +} + +/* ----------------------------------------------------------------------------- + * Implements a simple Swig Packed type, and use it instead of string + * ----------------------------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + void *pack; + swig_type_info *ty; + size_t size; +} SwigPyPacked; + +SWIGRUNTIME int +SwigPyPacked_print(SwigPyPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ + char result[SWIG_BUFFER_SIZE]; + fputs("pack, v->size, 0, sizeof(result))) { + fputs("at ", fp); + fputs(result, fp); + } + fputs(v->ty->name,fp); + fputs(">", fp); + return 0; +} + +SWIGRUNTIME PyObject * +SwigPyPacked_repr(SwigPyPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + return SWIG_Python_str_FromFormat("", result, v->ty->name); + } else { + return SWIG_Python_str_FromFormat("", v->ty->name); + } +} + +SWIGRUNTIME PyObject * +SwigPyPacked_str(SwigPyPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ + return SWIG_Python_str_FromFormat("%s%s", result, v->ty->name); + } else { + return SWIG_Python_str_FromChar(v->ty->name); + } +} + +SWIGRUNTIME int +SwigPyPacked_compare(SwigPyPacked *v, SwigPyPacked *w) +{ + size_t i = v->size; + size_t j = w->size; + int s = (i < j) ? -1 : ((i > j) ? 1 : 0); + return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size); +} + +SWIGRUNTIME PyTypeObject* SwigPyPacked_TypeOnce(void); + +SWIGRUNTIME PyTypeObject* +SwigPyPacked_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyPacked_TypeOnce(); + return type; +} + +SWIGRUNTIMEINLINE int +SwigPyPacked_Check(PyObject *op) { + return ((op)->ob_type == SwigPyPacked_TypeOnce()) + || (strcmp((op)->ob_type->tp_name,"SwigPyPacked") == 0); +} + +SWIGRUNTIME void +SwigPyPacked_dealloc(PyObject *v) +{ + if (SwigPyPacked_Check(v)) { + SwigPyPacked *sobj = (SwigPyPacked *) v; + free(sobj->pack); + } + PyObject_DEL(v); +} + +SWIGRUNTIME PyTypeObject* +SwigPyPacked_TypeOnce(void) { + static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; + static PyTypeObject swigpypacked_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp = { + /* PyObject header changed in Python 3 */ +#if PY_VERSION_HEX>=0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + (char *)"SwigPyPacked", /* tp_name */ + sizeof(SwigPyPacked), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SwigPyPacked_dealloc, /* tp_dealloc */ + (printfunc)SwigPyPacked_print, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ +#if PY_VERSION_HEX>=0x03000000 + 0, /* tp_reserved in 3.0.1 */ +#else + (cmpfunc)SwigPyPacked_compare, /* tp_compare */ +#endif + (reprfunc)SwigPyPacked_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)SwigPyPacked_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigpacked_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + swigpypacked_type = tmp; + type_init = 1; +#if PY_VERSION_HEX < 0x02020000 + swigpypacked_type.ob_type = &PyType_Type; +#else + if (PyType_Ready(&swigpypacked_type) < 0) + return NULL; +#endif + } + return &swigpypacked_type; +} + +SWIGRUNTIME PyObject * +SwigPyPacked_New(void *ptr, size_t size, swig_type_info *ty) +{ + SwigPyPacked *sobj = PyObject_NEW(SwigPyPacked, SwigPyPacked_type()); + if (sobj) { + void *pack = malloc(size); + if (pack) { + memcpy(pack, ptr, size); + sobj->pack = pack; + sobj->ty = ty; + sobj->size = size; + } else { + PyObject_DEL((PyObject *) sobj); + sobj = 0; + } + } + return (PyObject *) sobj; +} + +SWIGRUNTIME swig_type_info * +SwigPyPacked_UnpackData(PyObject *obj, void *ptr, size_t size) +{ + if (SwigPyPacked_Check(obj)) { + SwigPyPacked *sobj = (SwigPyPacked *)obj; + if (sobj->size != size) return 0; + memcpy(ptr, sobj->pack, size); + return sobj->ty; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIMEINLINE PyObject * +_SWIG_This(void) +{ + return SWIG_Python_str_FromChar("this"); +} + +static PyObject *swig_this = NULL; + +SWIGRUNTIME PyObject * +SWIG_This(void) +{ + if (swig_this == NULL) + swig_this = _SWIG_This(); + return swig_this; +} + +/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ + +/* TODO: I don't know how to implement the fast getset in Python 3 right now */ +#if PY_VERSION_HEX>=0x03000000 +#define SWIG_PYTHON_SLOW_GETSET_THIS +#endif + +SWIGRUNTIME SwigPyObject * +SWIG_Python_GetSwigThis(PyObject *pyobj) +{ + PyObject *obj; + + if (SwigPyObject_Check(pyobj)) + return (SwigPyObject *) pyobj; + +#ifdef SWIGPYTHON_BUILTIN + (void)obj; +# ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + pyobj = PyWeakref_GET_OBJECT(pyobj); + if (pyobj && SwigPyObject_Check(pyobj)) + return (SwigPyObject*) pyobj; + } +# endif + return NULL; +#else + + obj = 0; + +#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000)) + if (PyInstance_Check(pyobj)) { + obj = _PyInstance_Lookup(pyobj, SWIG_This()); + } else { + PyObject **dictptr = _PyObject_GetDictPtr(pyobj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; + } else { +#ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); + return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; + } +#endif + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } + } + } +#else + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } +#endif + if (obj && !SwigPyObject_Check(obj)) { + /* a PyObject is called 'this', try to get the 'real this' + SwigPyObject from it */ + return SWIG_Python_GetSwigThis(obj); + } + return (SwigPyObject *)obj; +#endif +} + +/* Acquire a pointer value */ + +SWIGRUNTIME int +SWIG_Python_AcquirePtr(PyObject *obj, int own) { + if (own == SWIG_POINTER_OWN) { + SwigPyObject *sobj = SWIG_Python_GetSwigThis(obj); + if (sobj) { + int oldown = sobj->own; + sobj->own = own; + return oldown; + } + } + return 0; +} + +/* Convert a pointer value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { + int res; + SwigPyObject *sobj; + + if (!obj) + return SWIG_ERROR; + if (obj == Py_None) { + if (ptr) + *ptr = 0; + return SWIG_OK; + } + + res = SWIG_ERROR; + + sobj = SWIG_Python_GetSwigThis(obj); + if (own) + *own = 0; + while (sobj) { + void *vptr = sobj->ptr; + if (ty) { + swig_type_info *to = sobj->ty; + if (to == ty) { + /* no type cast needed */ + if (ptr) *ptr = vptr; + break; + } else { + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) { + sobj = (SwigPyObject *)sobj->next; + } else { + if (ptr) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + if (newmemory == SWIG_CAST_NEW_MEMORY) { + assert(own); /* badly formed typemap which will lead to a memory leak - it must set and use own to delete *ptr */ + if (own) + *own = *own | SWIG_CAST_NEW_MEMORY; + } + } + break; + } + } + } else { + if (ptr) *ptr = vptr; + break; + } + } + if (sobj) { + if (own) + *own = *own | sobj->own; + if (flags & SWIG_POINTER_DISOWN) { + sobj->own = 0; + } + res = SWIG_OK; + } else { + if (flags & SWIG_POINTER_IMPLICIT_CONV) { + SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; + if (data && !data->implicitconv) { + PyObject *klass = data->klass; + if (klass) { + PyObject *impconv; + data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ + impconv = SWIG_Python_CallFunctor(klass, obj); + data->implicitconv = 0; + if (PyErr_Occurred()) { + PyErr_Clear(); + impconv = 0; + } + if (impconv) { + SwigPyObject *iobj = SWIG_Python_GetSwigThis(impconv); + if (iobj) { + void *vptr; + res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); + if (SWIG_IsOK(res)) { + if (ptr) { + *ptr = vptr; + /* transfer the ownership to 'ptr' */ + iobj->own = 0; + res = SWIG_AddCast(res); + res = SWIG_AddNewMask(res); + } else { + res = SWIG_AddCast(res); + } + } + } + Py_DECREF(impconv); + } + } + } + } + } + return res; +} + +/* Convert a function ptr value */ + +SWIGRUNTIME int +SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { + if (!PyCFunction_Check(obj)) { + return SWIG_ConvertPtr(obj, ptr, ty, 0); + } else { + void *vptr = 0; + + /* here we get the method pointer for callbacks */ + const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); + const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; + if (desc) + desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; + if (!desc) + return SWIG_ERROR; + if (ty) { + swig_cast_info *tc = SWIG_TypeCheck(desc,ty); + if (tc) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + assert(!newmemory); /* newmemory handling not yet implemented */ + } else { + return SWIG_ERROR; + } + } else { + *ptr = vptr; + } + return SWIG_OK; + } +} + +/* Convert a packed value value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { + swig_type_info *to = SwigPyPacked_UnpackData(obj, ptr, sz); + if (!to) return SWIG_ERROR; + if (ty) { + if (to != ty) { + /* check type cast? */ + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) return SWIG_ERROR; + } + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Create a new pointer object + * ----------------------------------------------------------------------------- */ + +/* + Create a new instance object, without calling __init__, and set the + 'this' attribute. +*/ + +SWIGRUNTIME PyObject* +SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this) +{ +#if (PY_VERSION_HEX >= 0x02020000) + PyObject *inst = 0; + PyObject *newraw = data->newraw; + if (newraw) { + inst = PyObject_Call(newraw, data->newargs, NULL); + if (inst) { +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + PyDict_SetItem(dict, SWIG_This(), swig_this); + } + } +#else + PyObject *key = SWIG_This(); + PyObject_SetAttr(inst, key, swig_this); +#endif + } + } else { +#if PY_VERSION_HEX >= 0x03000000 + inst = PyBaseObject_Type.tp_new((PyTypeObject*) data->newargs, Py_None, Py_None); + if (inst) { + PyObject_SetAttr(inst, SWIG_This(), swig_this); + Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; + } +#else + PyObject *dict = PyDict_New(); + if (dict) { + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + } +#endif + } + return inst; +#else +#if (PY_VERSION_HEX >= 0x02010000) + PyObject *inst = 0; + PyObject *dict = PyDict_New(); + if (dict) { + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + } + return (PyObject *) inst; +#else + PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); + if (inst == NULL) { + return NULL; + } + inst->in_class = (PyClassObject *)data->newargs; + Py_INCREF(inst->in_class); + inst->in_dict = PyDict_New(); + if (inst->in_dict == NULL) { + Py_DECREF(inst); + return NULL; + } +#ifdef Py_TPFLAGS_HAVE_WEAKREFS + inst->in_weakreflist = NULL; +#endif +#ifdef Py_TPFLAGS_GC + PyObject_GC_Init(inst); +#endif + PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this); + return (PyObject *) inst; +#endif +#endif +} + +SWIGRUNTIME void +SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) +{ + PyObject *dict; +#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + } + PyDict_SetItem(dict, SWIG_This(), swig_this); + return; + } +#endif + dict = PyObject_GetAttrString(inst, (char*)"__dict__"); + PyDict_SetItem(dict, SWIG_This(), swig_this); + Py_DECREF(dict); +} + + +SWIGINTERN PyObject * +SWIG_Python_InitShadowInstance(PyObject *args) { + PyObject *obj[2]; + if (!SWIG_Python_UnpackTuple(args, "swiginit", 2, 2, obj)) { + return NULL; + } else { + SwigPyObject *sthis = SWIG_Python_GetSwigThis(obj[0]); + if (sthis) { + SwigPyObject_append((PyObject*) sthis, obj[1]); + } else { + SWIG_Python_SetSwigThis(obj[0], obj[1]); + } + return SWIG_Py_Void(); + } +} + +/* Create a new pointer object */ + +SWIGRUNTIME PyObject * +SWIG_Python_NewPointerObj(PyObject *self, void *ptr, swig_type_info *type, int flags) { + SwigPyClientData *clientdata; + PyObject * robj; + int own; + + if (!ptr) + return SWIG_Py_Void(); + + clientdata = type ? (SwigPyClientData *)(type->clientdata) : 0; + own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; + if (clientdata && clientdata->pytype) { + SwigPyObject *newobj; + if (flags & SWIG_BUILTIN_TP_INIT) { + newobj = (SwigPyObject*) self; + if (newobj->ptr) { + PyObject *next_self = clientdata->pytype->tp_alloc(clientdata->pytype, 0); + while (newobj->next) + newobj = (SwigPyObject *) newobj->next; + newobj->next = next_self; + newobj = (SwigPyObject *)next_self; + } + } else { + newobj = PyObject_New(SwigPyObject, clientdata->pytype); + } + if (newobj) { + newobj->ptr = ptr; + newobj->ty = type; + newobj->own = own; + newobj->next = 0; +#ifdef SWIGPYTHON_BUILTIN + newobj->dict = 0; +#endif + return (PyObject*) newobj; + } + return SWIG_Py_Void(); + } + + assert(!(flags & SWIG_BUILTIN_TP_INIT)); + + robj = SwigPyObject_New(ptr, type, own); + if (robj && clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { + PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); + Py_DECREF(robj); + robj = inst; + } + return robj; +} + +/* Create a new packed object */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { + return ptr ? SwigPyPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); +} + +/* -----------------------------------------------------------------------------* + * Get type list + * -----------------------------------------------------------------------------*/ + +#ifdef SWIG_LINK_RUNTIME +void *SWIG_ReturnGlobalTypeList(void *); +#endif + +SWIGRUNTIME swig_module_info * +SWIG_Python_GetModule(void *SWIGUNUSEDPARM(clientdata)) { + static void *type_pointer = (void *)0; + /* first check if module already created */ + if (!type_pointer) { +#ifdef SWIG_LINK_RUNTIME + type_pointer = SWIG_ReturnGlobalTypeList((void *)0); +#else +# ifdef SWIGPY_USE_CAPSULE + type_pointer = PyCapsule_Import(SWIGPY_CAPSULE_NAME, 0); +# else + type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + (char*)"type_pointer" SWIG_TYPE_TABLE_NAME); +# endif + if (PyErr_Occurred()) { + PyErr_Clear(); + type_pointer = (void *)0; + } +#endif + } + return (swig_module_info *) type_pointer; +} + +#if PY_MAJOR_VERSION < 2 +/* PyModule_AddObject function was introduced in Python 2.0. The following function + is copied out of Python/modsupport.c in python version 2.3.4 */ +SWIGINTERN int +PyModule_AddObject(PyObject *m, char *name, PyObject *o) +{ + PyObject *dict; + if (!PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs module as first arg"); + return SWIG_ERROR; + } + if (!o) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs non-NULL value"); + return SWIG_ERROR; + } + + dict = PyModule_GetDict(m); + if (dict == NULL) { + /* Internal error -- modules must have a dict! */ + PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", + PyModule_GetName(m)); + return SWIG_ERROR; + } + if (PyDict_SetItemString(dict, name, o)) + return SWIG_ERROR; + Py_DECREF(o); + return SWIG_OK; +} +#endif + +SWIGRUNTIME void +#ifdef SWIGPY_USE_CAPSULE +SWIG_Python_DestroyModule(PyObject *obj) +#else +SWIG_Python_DestroyModule(void *vptr) +#endif +{ +#ifdef SWIGPY_USE_CAPSULE + swig_module_info *swig_module = (swig_module_info *) PyCapsule_GetPointer(obj, SWIGPY_CAPSULE_NAME); +#else + swig_module_info *swig_module = (swig_module_info *) vptr; +#endif + swig_type_info **types = swig_module->types; + size_t i; + for (i =0; i < swig_module->size; ++i) { + swig_type_info *ty = types[i]; + if (ty->owndata) { + SwigPyClientData *data = (SwigPyClientData *) ty->clientdata; + if (data) SwigPyClientData_Del(data); + } + } + Py_DECREF(SWIG_This()); + swig_this = NULL; +} + +SWIGRUNTIME void +SWIG_Python_SetModule(swig_module_info *swig_module) { +#if PY_VERSION_HEX >= 0x03000000 + /* Add a dummy module object into sys.modules */ + PyObject *module = PyImport_AddModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION); +#else + static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} }; /* Sentinel */ + PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, swig_empty_runtime_method_table); +#endif +#ifdef SWIGPY_USE_CAPSULE + PyObject *pointer = PyCapsule_New((void *) swig_module, SWIGPY_CAPSULE_NAME, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, (char*)"type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +#else + PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +#endif +} + +/* The python cached type query */ +SWIGRUNTIME PyObject * +SWIG_Python_TypeCache(void) { + static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); + return cache; +} + +SWIGRUNTIME swig_type_info * +SWIG_Python_TypeQuery(const char *type) +{ + PyObject *cache = SWIG_Python_TypeCache(); + PyObject *key = SWIG_Python_str_FromChar(type); + PyObject *obj = PyDict_GetItem(cache, key); + swig_type_info *descriptor; + if (obj) { +#ifdef SWIGPY_USE_CAPSULE + descriptor = (swig_type_info *) PyCapsule_GetPointer(obj, NULL); +#else + descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj); +#endif + } else { + swig_module_info *swig_module = SWIG_GetModule(0); + descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); + if (descriptor) { +#ifdef SWIGPY_USE_CAPSULE + obj = PyCapsule_New((void*) descriptor, NULL, NULL); +#else + obj = PyCObject_FromVoidPtr(descriptor, NULL); +#endif + PyDict_SetItem(cache, key, obj); + Py_DECREF(obj); + } + } + Py_DECREF(key); + return descriptor; +} + +/* + For backward compatibility only +*/ +#define SWIG_POINTER_EXCEPTION 0 +#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) +#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) + +SWIGRUNTIME int +SWIG_Python_AddErrMesg(const char* mesg, int infront) +{ + if (PyErr_Occurred()) { + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + PyErr_Fetch(&type, &value, &traceback); + if (value) { + char *tmp; + PyObject *old_str = PyObject_Str(value); + Py_XINCREF(type); + PyErr_Clear(); + if (infront) { + PyErr_Format(type, "%s %s", mesg, tmp = SWIG_Python_str_AsChar(old_str)); + } else { + PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); + } + SWIG_Python_str_DelForPy3(tmp); + Py_DECREF(old_str); + } + return 1; + } else { + return 0; + } +} + +SWIGRUNTIME int +SWIG_Python_ArgFail(int argnum) +{ + if (PyErr_Occurred()) { + /* add information about failing argument */ + char mesg[256]; + PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); + return SWIG_Python_AddErrMesg(mesg, 1); + } else { + return 0; + } +} + +SWIGRUNTIMEINLINE const char * +SwigPyObject_GetDesc(PyObject *self) +{ + SwigPyObject *v = (SwigPyObject *)self; + swig_type_info *ty = v ? v->ty : 0; + return ty ? ty->str : ""; +} + +SWIGRUNTIME void +SWIG_Python_TypeError(const char *type, PyObject *obj) +{ + if (type) { +#if defined(SWIG_COBJECT_TYPES) + if (obj && SwigPyObject_Check(obj)) { + const char *otype = (const char *) SwigPyObject_GetDesc(obj); + if (otype) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'SwigPyObject(%s)' is received", + type, otype); + return; + } + } else +#endif + { + const char *otype = (obj ? obj->ob_type->tp_name : 0); + if (otype) { + PyObject *str = PyObject_Str(obj); + const char *cstr = str ? SWIG_Python_str_AsChar(str) : 0; + if (cstr) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", + type, otype, cstr); + SWIG_Python_str_DelForPy3(cstr); + } else { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", + type, otype); + } + Py_XDECREF(str); + return; + } + } + PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); + } else { + PyErr_Format(PyExc_TypeError, "unexpected type is received"); + } +} + + +/* Convert a pointer value, signal an exception on a type mismatch */ +SWIGRUNTIME void * +SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int SWIGUNUSEDPARM(argnum), int flags) { + void *result; + if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { + PyErr_Clear(); +#if SWIG_POINTER_EXCEPTION + if (flags) { + SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); + SWIG_Python_ArgFail(argnum); + } +#endif + } + return result; +} + +#ifdef SWIGPYTHON_BUILTIN +SWIGRUNTIME int +SWIG_Python_NonDynamicSetAttr(PyObject *obj, PyObject *name, PyObject *value) { + PyTypeObject *tp = obj->ob_type; + PyObject *descr; + PyObject *encoded_name; + descrsetfunc f; + int res; + +# ifdef Py_USING_UNICODE + if (PyString_Check(name)) { + name = PyUnicode_Decode(PyString_AsString(name), PyString_Size(name), NULL, NULL); + if (!name) + return -1; + } else if (!PyUnicode_Check(name)) +# else + if (!PyString_Check(name)) +# endif + { + PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", name->ob_type->tp_name); + return -1; + } else { + Py_INCREF(name); + } + + if (!tp->tp_dict) { + if (PyType_Ready(tp) < 0) + goto done; + } + + res = -1; + descr = _PyType_Lookup(tp, name); + f = NULL; + if (descr != NULL) + f = descr->ob_type->tp_descr_set; + if (!f) { + if (PyString_Check(name)) { + encoded_name = name; + Py_INCREF(name); + } else { + encoded_name = PyUnicode_AsUTF8String(name); + } + PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_name)); + Py_DECREF(encoded_name); + } else { + res = f(descr, obj, value); + } + + done: + Py_DECREF(name); + return res; +} +#endif + + +#ifdef __cplusplus +} +#endif + +#define SWIGPY_UNARYFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_closure(PyObject *a) { \ + return wrapper(a, NULL); \ +} + +#define SWIGPY_DESTRUCTOR_CLOSURE(wrapper) \ +SWIGINTERN void \ +wrapper##_closure(PyObject *a) { \ + SwigPyObject *sobj; \ + sobj = (SwigPyObject *)a; \ + if (sobj->own) { \ + PyObject *o = wrapper(a, NULL); \ + Py_XDECREF(o); \ + } \ + PyObject_Del(a); \ +} + +#define SWIGPY_INQUIRY_CLOSURE(wrapper) \ +SWIGINTERN int \ +wrapper##_closure(PyObject *a) { \ + PyObject *pyresult; \ + int result; \ + pyresult = wrapper(a, NULL); \ + result = pyresult && PyObject_IsTrue(pyresult) ? 1 : 0; \ + Py_XDECREF(pyresult); \ + return result; \ +} + +#define SWIGPY_BINARYFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_closure(PyObject *a, PyObject *b) { \ + PyObject *tuple, *result; \ + tuple = PyTuple_New(1); \ + assert(tuple); \ + PyTuple_SET_ITEM(tuple, 0, b); \ + Py_XINCREF(b); \ + result = wrapper(a, tuple); \ + Py_DECREF(tuple); \ + return result; \ +} + +typedef ternaryfunc ternarycallfunc; + +#define SWIGPY_TERNARYFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_closure(PyObject *a, PyObject *b, PyObject *c) { \ + PyObject *tuple, *result; \ + tuple = PyTuple_New(2); \ + assert(tuple); \ + PyTuple_SET_ITEM(tuple, 0, b); \ + PyTuple_SET_ITEM(tuple, 1, c); \ + Py_XINCREF(b); \ + Py_XINCREF(c); \ + result = wrapper(a, tuple); \ + Py_DECREF(tuple); \ + return result; \ +} + +#define SWIGPY_TERNARYCALLFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_closure(PyObject *callable_object, PyObject *args, PyObject *) { \ + return wrapper(callable_object, args); \ +} + +#define SWIGPY_LENFUNC_CLOSURE(wrapper) \ +SWIGINTERN Py_ssize_t \ +wrapper##_closure(PyObject *a) { \ + PyObject *resultobj; \ + Py_ssize_t result; \ + resultobj = wrapper(a, NULL); \ + result = PyNumber_AsSsize_t(resultobj, NULL); \ + Py_DECREF(resultobj); \ + return result; \ +} + +#define SWIGPY_SSIZESSIZEARGFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_closure(PyObject *a, Py_ssize_t b, Py_ssize_t c) { \ + PyObject *tuple, *result; \ + tuple = PyTuple_New(2); \ + assert(tuple); \ + PyTuple_SET_ITEM(tuple, 0, _PyLong_FromSsize_t(b)); \ + PyTuple_SET_ITEM(tuple, 1, _PyLong_FromSsize_t(c)); \ + result = wrapper(a, tuple); \ + Py_DECREF(tuple); \ + return result; \ +} + +#define SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE(wrapper) \ +SWIGINTERN int \ +wrapper##_closure(PyObject *a, Py_ssize_t b, Py_ssize_t c, PyObject *d) { \ + PyObject *tuple, *resultobj; \ + int result; \ + tuple = PyTuple_New(d ? 3 : 2); \ + assert(tuple); \ + PyTuple_SET_ITEM(tuple, 0, _PyLong_FromSsize_t(b)); \ + PyTuple_SET_ITEM(tuple, 1, _PyLong_FromSsize_t(c)); \ + if (d) { \ + PyTuple_SET_ITEM(tuple, 2, d); \ + Py_INCREF(d); \ + } \ + resultobj = wrapper(a, tuple); \ + result = resultobj ? 0 : -1; \ + Py_DECREF(tuple); \ + Py_XDECREF(resultobj); \ + return result; \ +} + +#define SWIGPY_SSIZEARGFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_closure(PyObject *a, Py_ssize_t b) { \ + PyObject *tuple, *result; \ + tuple = PyTuple_New(1); \ + assert(tuple); \ + PyTuple_SET_ITEM(tuple, 0, _PyLong_FromSsize_t(b)); \ + result = wrapper(a, tuple); \ + Py_DECREF(tuple); \ + return result; \ +} + +#define SWIGPY_FUNPACK_SSIZEARGFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_closure(PyObject *a, Py_ssize_t b) { \ + PyObject *arg, *result; \ + arg = _PyLong_FromSsize_t(b); \ + result = wrapper(a, arg); \ + Py_DECREF(arg); \ + return result; \ +} + +#define SWIGPY_SSIZEOBJARGPROC_CLOSURE(wrapper) \ +SWIGINTERN int \ +wrapper##_closure(PyObject *a, Py_ssize_t b, PyObject *c) { \ + PyObject *tuple, *resultobj; \ + int result; \ + tuple = PyTuple_New(2); \ + assert(tuple); \ + PyTuple_SET_ITEM(tuple, 0, _PyLong_FromSsize_t(b)); \ + PyTuple_SET_ITEM(tuple, 1, c); \ + Py_XINCREF(c); \ + resultobj = wrapper(a, tuple); \ + result = resultobj ? 0 : -1; \ + Py_XDECREF(resultobj); \ + Py_DECREF(tuple); \ + return result; \ +} + +#define SWIGPY_OBJOBJARGPROC_CLOSURE(wrapper) \ +SWIGINTERN int \ +wrapper##_closure(PyObject *a, PyObject *b, PyObject *c) { \ + PyObject *tuple, *resultobj; \ + int result; \ + tuple = PyTuple_New(c ? 2 : 1); \ + assert(tuple); \ + PyTuple_SET_ITEM(tuple, 0, b); \ + Py_XINCREF(b); \ + if (c) { \ + PyTuple_SET_ITEM(tuple, 1, c); \ + Py_XINCREF(c); \ + } \ + resultobj = wrapper(a, tuple); \ + result = resultobj ? 0 : -1; \ + Py_XDECREF(resultobj); \ + Py_DECREF(tuple); \ + return result; \ +} + +#define SWIGPY_REPRFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_closure(PyObject *a) { \ + return wrapper(a, NULL); \ +} + +#define SWIGPY_HASHFUNC_CLOSURE(wrapper) \ +SWIGINTERN long \ +wrapper##_closure(PyObject *a) { \ + PyObject *pyresult; \ + long result; \ + pyresult = wrapper(a, NULL); \ + if (!pyresult || !PyLong_Check(pyresult)) \ + return -1; \ + result = PyLong_AsLong(pyresult); \ + Py_DECREF(pyresult); \ + return result; \ +} + +#define SWIGPY_ITERNEXT_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_closure(PyObject *a) { \ + PyObject *result; \ + result = wrapper(a, NULL); \ + if (result && result == Py_None) { \ + Py_DECREF(result); \ + result = NULL; \ + } \ + return result; \ +} + +#ifdef __cplusplus +extern "C" { +#endif + +SWIGINTERN int +SwigPyBuiltin_BadInit(PyObject *self, PyObject *SWIGUNUSEDPARM(args), PyObject *SWIGUNUSEDPARM(kwds)) { + PyErr_Format(PyExc_TypeError, "Cannot create new instances of type '%.300s'", self->ob_type->tp_name); + return -1; +} + +SWIGINTERN void +SwigPyBuiltin_BadDealloc(PyObject *pyobj) { + SwigPyObject *sobj; + sobj = (SwigPyObject *)pyobj; + if (sobj->own) { + PyErr_Format(PyExc_TypeError, "Swig detected a memory leak in type '%.300s': no callable destructor found.", pyobj->ob_type->tp_name); + } +} + +typedef struct { + PyCFunction get; + PyCFunction set; +} SwigPyGetSet; + +SWIGINTERN PyObject * +SwigPyBuiltin_GetterClosure (PyObject *obj, void *closure) { + SwigPyGetSet *getset; + PyObject *tuple, *result; + if (!closure) + return SWIG_Py_Void(); + getset = (SwigPyGetSet *)closure; + if (!getset->get) + return SWIG_Py_Void(); + tuple = PyTuple_New(0); + assert(tuple); + result = (*getset->get)(obj, tuple); + Py_DECREF(tuple); + return result; +} + +SWIGINTERN PyObject * +SwigPyBuiltin_FunpackGetterClosure (PyObject *obj, void *closure) { + SwigPyGetSet *getset; + PyObject *result; + if (!closure) + return SWIG_Py_Void(); + getset = (SwigPyGetSet *)closure; + if (!getset->get) + return SWIG_Py_Void(); + result = (*getset->get)(obj, NULL); + return result; +} + +SWIGINTERN int +SwigPyBuiltin_SetterClosure (PyObject *obj, PyObject *val, void *closure) { + SwigPyGetSet *getset; + PyObject *tuple, *result; + if (!closure) { + PyErr_Format(PyExc_TypeError, "Missing getset closure"); + return -1; + } + getset = (SwigPyGetSet *)closure; + if (!getset->set) { + PyErr_Format(PyExc_TypeError, "Illegal member variable assignment in type '%.300s'", obj->ob_type->tp_name); + return -1; + } + tuple = PyTuple_New(1); + assert(tuple); + PyTuple_SET_ITEM(tuple, 0, val); + Py_XINCREF(val); + result = (*getset->set)(obj, tuple); + Py_DECREF(tuple); + Py_XDECREF(result); + return result ? 0 : -1; +} + +SWIGINTERN int +SwigPyBuiltin_FunpackSetterClosure (PyObject *obj, PyObject *val, void *closure) { + SwigPyGetSet *getset; + PyObject *result; + if (!closure) { + PyErr_Format(PyExc_TypeError, "Missing getset closure"); + return -1; + } + getset = (SwigPyGetSet *)closure; + if (!getset->set) { + PyErr_Format(PyExc_TypeError, "Illegal member variable assignment in type '%.300s'", obj->ob_type->tp_name); + return -1; + } + result = (*getset->set)(obj, val); + Py_XDECREF(result); + return result ? 0 : -1; +} + +SWIGINTERN void +SwigPyStaticVar_dealloc(PyDescrObject *descr) { + _PyObject_GC_UNTRACK(descr); + Py_XDECREF(PyDescr_TYPE(descr)); + Py_XDECREF(PyDescr_NAME(descr)); + PyObject_GC_Del(descr); +} + +SWIGINTERN PyObject * +SwigPyStaticVar_repr(PyGetSetDescrObject *descr) { +#if PY_VERSION_HEX >= 0x03000000 + + return PyUnicode_FromFormat("", PyDescr_NAME(descr), PyDescr_TYPE(descr)->tp_name); +#else + return PyString_FromFormat("", PyString_AsString(PyDescr_NAME(descr)), PyDescr_TYPE(descr)->tp_name); +#endif +} + +SWIGINTERN int +SwigPyStaticVar_traverse(PyObject *self, visitproc visit, void *arg) { + PyDescrObject *descr; + descr = (PyDescrObject *)self; + Py_VISIT((PyObject*) PyDescr_TYPE(descr)); + return 0; +} + +SWIGINTERN PyObject * +SwigPyStaticVar_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *SWIGUNUSEDPARM(type)) { + if (descr->d_getset->get != NULL) + return descr->d_getset->get(obj, descr->d_getset->closure); +#if PY_VERSION_HEX >= 0x03000000 + PyErr_Format(PyExc_AttributeError, "attribute '%.300S' of '%.100s' objects is not readable", PyDescr_NAME(descr), PyDescr_TYPE(descr)->tp_name); +#else + PyErr_Format(PyExc_AttributeError, "attribute '%.300s' of '%.100s' objects is not readable", PyString_AsString(PyDescr_NAME(descr)), PyDescr_TYPE(descr)->tp_name); +#endif + return NULL; +} + +SWIGINTERN int +SwigPyStaticVar_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) { + if (descr->d_getset->set != NULL) + return descr->d_getset->set(obj, value, descr->d_getset->closure); +#if PY_VERSION_HEX >= 0x03000000 + PyErr_Format(PyExc_AttributeError, "attribute '%.300S' of '%.100s' objects is not writable", PyDescr_NAME(descr), PyDescr_TYPE(descr)->tp_name); +#else + PyErr_Format(PyExc_AttributeError, "attribute '%.300s' of '%.100s' objects is not writable", PyString_AsString(PyDescr_NAME(descr)), PyDescr_TYPE(descr)->tp_name); +#endif + return -1; +} + +SWIGINTERN int +SwigPyObjectType_setattro(PyTypeObject *type, PyObject *name, PyObject *value) { + PyObject *attribute; + descrsetfunc local_set; + attribute = _PyType_Lookup(type, name); + if (attribute != NULL) { + /* Implement descriptor functionality, if any */ + local_set = attribute->ob_type->tp_descr_set; + if (local_set != NULL) + return local_set(attribute, (PyObject *)type, value); +#if PY_VERSION_HEX >= 0x03000000 + PyErr_Format(PyExc_AttributeError, "cannot modify read-only attribute '%.50s.%.400S'", type->tp_name, name); +#else + PyErr_Format(PyExc_AttributeError, "cannot modify read-only attribute '%.50s.%.400s'", type->tp_name, PyString_AS_STRING(name)); +#endif + } else { +#if PY_VERSION_HEX >= 0x03000000 + PyErr_Format(PyExc_AttributeError, "type '%.50s' has no attribute '%.400S'", type->tp_name, name); +#else + PyErr_Format(PyExc_AttributeError, "type '%.50s' has no attribute '%.400s'", type->tp_name, PyString_AS_STRING(name)); +#endif + } + + return -1; +} + +SWIGINTERN PyTypeObject* +SwigPyStaticVar_Type(void) { + static PyTypeObject staticvar_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp = { + /* PyObject header changed in Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(&PyType_Type, 0) +#else + PyObject_HEAD_INIT(&PyType_Type) + 0, +#endif + "swig_static_var_getset_descriptor", + sizeof(PyGetSetDescrObject), + 0, + (destructor)SwigPyStaticVar_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)SwigPyStaticVar_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_HAVE_CLASS, /* tp_flags */ + 0, /* tp_doc */ + SwigPyStaticVar_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)SwigPyStaticVar_get, /* tp_descr_get */ + (descrsetfunc)SwigPyStaticVar_set, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + staticvar_type = tmp; + type_init = 1; +#if PY_VERSION_HEX < 0x02020000 + staticvar_type.ob_type = &PyType_Type; +#else + if (PyType_Ready(&staticvar_type) < 0) + return NULL; +#endif + } + return &staticvar_type; +} + +SWIGINTERN PyGetSetDescrObject * +SwigPyStaticVar_new_getset(PyTypeObject *type, PyGetSetDef *getset) { + + PyGetSetDescrObject *descr; + descr = (PyGetSetDescrObject *)PyType_GenericAlloc(SwigPyStaticVar_Type(), 0); + assert(descr); + Py_XINCREF(type); + PyDescr_TYPE(descr) = type; + PyDescr_NAME(descr) = PyString_InternFromString(getset->name); + descr->d_getset = getset; + if (PyDescr_NAME(descr) == NULL) { + Py_DECREF(descr); + descr = NULL; + } + return descr; +} + +SWIGINTERN void +SwigPyBuiltin_InitBases (PyTypeObject *type, PyTypeObject **bases) { + int base_count = 0; + PyTypeObject **b; + PyObject *tuple; + int i; + + if (!bases[0]) { + bases[0] = SwigPyObject_type(); + bases[1] = NULL; + } + type->tp_base = bases[0]; + Py_INCREF((PyObject *)bases[0]); + for (b = bases; *b != NULL; ++b) + ++base_count; + tuple = PyTuple_New(base_count); + for (i = 0; i < base_count; ++i) { + PyTuple_SET_ITEM(tuple, i, (PyObject *)bases[i]); + Py_INCREF((PyObject *)bases[i]); + } + type->tp_bases = tuple; +} + +SWIGINTERN PyObject * +SwigPyBuiltin_ThisClosure (PyObject *self, void *SWIGUNUSEDPARM(closure)) { + PyObject *result; + result = (PyObject *)SWIG_Python_GetSwigThis(self); + Py_XINCREF(result); + return result; +} + +SWIGINTERN void +SwigPyBuiltin_SetMetaType (PyTypeObject *type, PyTypeObject *metatype) +{ +#if PY_VERSION_HEX >= 0x03000000 + type->ob_base.ob_base.ob_type = metatype; +#else + type->ob_type = metatype; +#endif +} + +#ifdef __cplusplus +} +#endif + + + + +#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) + +#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else + + + + #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +#define SWIGTYPE_p_AES_KEY swig_types[0] +#define SWIGTYPE_p_ASN1_BIT_STRING swig_types[1] +#define SWIGTYPE_p_ASN1_INTEGER swig_types[2] +#define SWIGTYPE_p_ASN1_OBJECT swig_types[3] +#define SWIGTYPE_p_ASN1_STRING swig_types[4] +#define SWIGTYPE_p_ASN1_TIME swig_types[5] +#define SWIGTYPE_p_BIGNUM swig_types[6] +#define SWIGTYPE_p_BIO swig_types[7] +#define SWIGTYPE_p_BIO_METHOD swig_types[8] +#define SWIGTYPE_p_DH swig_types[9] +#define SWIGTYPE_p_DSA swig_types[10] +#define SWIGTYPE_p_ECDSA_SIG swig_types[11] +#define SWIGTYPE_p_EC_KEY swig_types[12] +#define SWIGTYPE_p_ENGINE swig_types[13] +#define SWIGTYPE_p_EVP_CIPHER swig_types[14] +#define SWIGTYPE_p_EVP_CIPHER_CTX swig_types[15] +#define SWIGTYPE_p_EVP_MD swig_types[16] +#define SWIGTYPE_p_EVP_MD_CTX swig_types[17] +#define SWIGTYPE_p_EVP_PKEY swig_types[18] +#define SWIGTYPE_p_FILE swig_types[19] +#define SWIGTYPE_p_HMAC_CTX swig_types[20] +#define SWIGTYPE_p_PKCS7 swig_types[21] +#define SWIGTYPE_p_PyObject swig_types[22] +#define SWIGTYPE_p_RC4_KEY swig_types[23] +#define SWIGTYPE_p_RSA swig_types[24] +#define SWIGTYPE_p_SSL swig_types[25] +#define SWIGTYPE_p_SSL_CIPHER swig_types[26] +#define SWIGTYPE_p_SSL_CTX swig_types[27] +#define SWIGTYPE_p_SSL_METHOD swig_types[28] +#define SWIGTYPE_p_SSL_SESSION swig_types[29] +#define SWIGTYPE_p_SwigPyObject swig_types[30] +#define SWIGTYPE_p_UI_METHOD swig_types[31] +#define SWIGTYPE_p_X509 swig_types[32] +#define SWIGTYPE_p_X509V3_CTX swig_types[33] +#define SWIGTYPE_p_X509_CRL swig_types[34] +#define SWIGTYPE_p_X509_EXTENSION swig_types[35] +#define SWIGTYPE_p_X509_NAME swig_types[36] +#define SWIGTYPE_p_X509_NAME_ENTRY swig_types[37] +#define SWIGTYPE_p_X509_REQ swig_types[38] +#define SWIGTYPE_p_X509_STORE swig_types[39] +#define SWIGTYPE_p_X509_STORE_CTX swig_types[40] +#define SWIGTYPE_p__cbd_t swig_types[41] +#define SWIGTYPE_p_char swig_types[42] +#define SWIGTYPE_p_f_int_p_X509_STORE_CTX__int swig_types[43] +#define SWIGTYPE_p_f_p_q_const__void_p_q_const__void__int swig_types[44] +#define SWIGTYPE_p_f_p_void__p_void swig_types[45] +#define SWIGTYPE_p_f_p_void__void swig_types[46] +#define SWIGTYPE_p_p_ASN1_OBJECT swig_types[47] +#define SWIGTYPE_p_p_X509_NAME_ENTRY swig_types[48] +#define SWIGTYPE_p_p_char swig_types[49] +#define SWIGTYPE_p_p_unsigned_char swig_types[50] +#define SWIGTYPE_p_pyfd_struct swig_types[51] +#define SWIGTYPE_p_stack_st swig_types[52] +#define SWIGTYPE_p_stack_st_OPENSSL_BLOCK swig_types[53] +#define SWIGTYPE_p_stack_st_OPENSSL_STRING swig_types[54] +#define SWIGTYPE_p_stack_st_SSL_CIPHER swig_types[55] +#define SWIGTYPE_p_stack_st_X509 swig_types[56] +#define SWIGTYPE_p_stack_st_X509_EXTENSION swig_types[57] +#define SWIGTYPE_p_unsigned_char swig_types[58] +#define SWIGTYPE_p_void swig_types[59] +static swig_type_info *swig_types[61]; +static swig_module_info swig_module = {swig_types, 60, 0, 0, 0, 0}; +#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) +#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) + +/* -------- TYPES TABLE (END) -------- */ + +#if (PY_VERSION_HEX <= 0x02000000) +# if !defined(SWIG_PYTHON_CLASSIC) +# error "This python version requires swig to be run with the '-classic' option" +# endif +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodern' option" +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodernargs' option" +#endif + +/*----------------------------------------------- + @(target):= _m2crypto.so + ------------------------------------------------*/ +#if PY_VERSION_HEX >= 0x03000000 +# define SWIG_init PyInit__m2crypto + +#else +# define SWIG_init init_m2crypto + +#endif +#define SWIG_name "_m2crypto" + +#define SWIGVERSION 0x020010 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +#ifdef _WIN32 +#define _WINSOCKAPI_ +#include +#include +#pragma comment(lib, "Ws2_32") +typedef unsigned __int64 uint64_t; +#endif + + +#if defined __GNUC__ && __GNUC__ < 5 +#pragma GCC diagnostic ignored "-Wunused-label" +#pragma GCC diagnostic warning "-Wstrict-prototypes" +#endif + +#include +#include +#include <_lib.h> +#include +#include + +#include "compile.h" + +static PyObject *ssl_verify_cb_func; +static PyObject *ssl_info_cb_func; +static PyObject *ssl_set_tmp_dh_cb_func; +static PyObject *ssl_set_tmp_rsa_cb_func; +static PyObject *x509_store_verify_cb_func; + + + #define SWIG_From_long PyLong_FromLong + + +SWIGINTERN swig_type_info* +SWIG_pchar_descriptor(void) +{ + static int init = 0; + static swig_type_info* info = 0; + if (!init) { + info = SWIG_TypeQuery("_p_char"); + init = 1; + } + return info; +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtrAndSize(const char* carray, size_t size) +{ + if (carray) { + if (size > INT_MAX) { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + return pchar_descriptor ? + SWIG_InternalNewPointerObj((char *)(carray), pchar_descriptor, 0) : SWIG_Py_Void(); + } else { +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromStringAndSize(carray, (int)(size)); +#else + return PyString_FromStringAndSize(carray, (int)(size)); +#endif + } + } else { + return SWIG_Py_Void(); + } +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtr(const char *cptr) +{ + return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); +} + + +#include +#if !defined(SWIG_NO_LLONG_MAX) +# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) +# define LLONG_MAX __LONG_LONG_MAX__ +# define LLONG_MIN (-LLONG_MAX - 1LL) +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) +# endif +#endif + + +SWIGINTERN int +SWIG_AsVal_double (PyObject *obj, double *val) +{ + int res = SWIG_TypeError; + if (PyFloat_Check(obj)) { + if (val) *val = PyFloat_AsDouble(obj); + return SWIG_OK; + } else if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + double v = PyLong_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + double d = PyFloat_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = d; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); + } else { + PyErr_Clear(); + } + } + } +#endif + return res; +} + + +#include + + +#include + + +SWIGINTERNINLINE int +SWIG_CanCastAsInteger(double *d, double min, double max) { + double x = *d; + if ((min <= x && x <= max)) { + double fx = floor(x); + double cx = ceil(x); + double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ + if ((errno == EDOM) || (errno == ERANGE)) { + errno = 0; + } else { + double summ, reps, diff; + if (rd < x) { + diff = x - rd; + } else if (rd > x) { + diff = rd - x; + } else { + return 1; + } + summ = rd + x; + reps = diff/summ; + if (reps < 8*DBL_EPSILON) { + *d = rd; + return 1; + } + } + } + return 0; +} + + +SWIGINTERN int +SWIG_AsVal_long (PyObject *obj, long* val) +{ + if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + long v = PyInt_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { + if (val) *val = (long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_int (PyObject * obj, int *val) +{ + long v; + int res = SWIG_AsVal_long (obj, &v); + if (SWIG_IsOK(res)) { + if ((v < INT_MIN || v > INT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (int)(v); + } + } + return res; +} + + +SWIGINTERNINLINE PyObject* + SWIG_From_int (int value) +{ + return PyInt_FromLong((long) value); +} + + +#include +#include + +#if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L +#define CRYPTO_num_locks() (CRYPTO_NUM_LOCKS) +static PyThread_type_lock lock_cs[CRYPTO_num_locks()]; +static long lock_count[CRYPTO_num_locks()]; +static int thread_mode = 0; +#endif + +void threading_locking_callback(int mode, int type, const char *file, int line) { +#if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L + if (mode & CRYPTO_LOCK) { + PyThread_acquire_lock(lock_cs[type], WAIT_LOCK); + lock_count[type]++; + } else { + PyThread_release_lock(lock_cs[type]); + lock_count[type]--; + } +#endif +} + +unsigned long threading_id_callback(void) { +#if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L + return (unsigned long)PyThread_get_thread_ident(); +#else + return (unsigned long)0; +#endif +} + + +void threading_init(void) { +#if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L + int i; + if (!thread_mode) { + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include + + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +#include +#include + +# define OPENSSL_zalloc(num) \ + CRYPTO_zalloc(num, __FILE__, __LINE__) + +static void *CRYPTO_zalloc(size_t num, const char *file, int line) +{ + void *ret = CRYPTO_malloc(num, file, line); + if (ret != NULL) + memset(ret, 0, num); + return ret; +} + +#include + +#ifndef BN_F_BN_GENCB_NEW +# define BN_F_BN_GENCB_NEW 143 +#endif + +# define BN_GENCB_get_arg(gencb) ((gencb)->arg) + +BN_GENCB *BN_GENCB_new(void) +{ + BN_GENCB *ret; + + if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) { + BNerr(BN_F_BN_GENCB_NEW, ERR_R_MALLOC_FAILURE); + return (NULL); + } + + return ret; +} + +void BN_GENCB_free(BN_GENCB *cb) +{ + if (cb == NULL) + return; + OPENSSL_free(cb); +} + + +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) +{ + /* If the fields n and e in r are NULL, the corresponding input + * parameters MUST be non-NULL for n and e. d may be + * left NULL (in case only the public key is used). + */ + if ((r->n == NULL && n == NULL) + || (r->e == NULL && e == NULL)) + return 0; + + if (n != NULL) { + BN_free(r->n); + r->n = n; + } + if (e != NULL) { + BN_free(r->e); + r->e = e; + } + if (d != NULL) { + BN_free(r->d); + r->d = d; + } + + return 1; +} + +int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) +{ + /* If the fields p and q in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->p == NULL && p == NULL) + || (r->q == NULL && q == NULL)) + return 0; + + if (p != NULL) { + BN_free(r->p); + r->p = p; + } + if (q != NULL) { + BN_free(r->q); + r->q = q; + } + + return 1; +} + +int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) +{ + /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->dmp1 == NULL && dmp1 == NULL) + || (r->dmq1 == NULL && dmq1 == NULL) + || (r->iqmp == NULL && iqmp == NULL)) + return 0; + + if (dmp1 != NULL) { + BN_free(r->dmp1); + r->dmp1 = dmp1; + } + if (dmq1 != NULL) { + BN_free(r->dmq1); + r->dmq1 = dmq1; + } + if (iqmp != NULL) { + BN_free(r->iqmp); + r->iqmp = iqmp; + } + + return 1; +} + +void RSA_get0_key(const RSA *r, + const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) +{ + if (n != NULL) + *n = r->n; + if (e != NULL) + *e = r->e; + if (d != NULL) + *d = r->d; +} + +void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) +{ + if (p != NULL) + *p = r->p; + if (q != NULL) + *q = r->q; +} + +void RSA_get0_crt_params(const RSA *r, + const BIGNUM **dmp1, const BIGNUM **dmq1, + const BIGNUM **iqmp) +{ + if (dmp1 != NULL) + *dmp1 = r->dmp1; + if (dmq1 != NULL) + *dmq1 = r->dmq1; + if (iqmp != NULL) + *iqmp = r->iqmp; +} + +void DSA_get0_pqg(const DSA *d, + const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) +{ + if (p != NULL) + *p = d->p; + if (q != NULL) + *q = d->q; + if (g != NULL) + *g = d->g; +} + +int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + /* If the fields p, q and g in d are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((d->p == NULL && p == NULL) + || (d->q == NULL && q == NULL) + || (d->g == NULL && g == NULL)) + return 0; + + if (p != NULL) { + BN_free(d->p); + d->p = p; + } + if (q != NULL) { + BN_free(d->q); + d->q = q; + } + if (g != NULL) { + BN_free(d->g); + d->g = g; + } + + return 1; +} + +void DSA_get0_key(const DSA *d, + const BIGNUM **pub_key, const BIGNUM **priv_key) +{ + if (pub_key != NULL) + *pub_key = d->pub_key; + if (priv_key != NULL) + *priv_key = d->priv_key; +} + +int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) +{ + /* If the field pub_key in d is NULL, the corresponding input + * parameters MUST be non-NULL. The priv_key field may + * be left NULL. + */ + if (d->pub_key == NULL && pub_key == NULL) + return 0; + + if (pub_key != NULL) { + BN_free(d->pub_key); + d->pub_key = pub_key; + } + if (priv_key != NULL) { + BN_free(d->priv_key); + d->priv_key = priv_key; + } + + return 1; +} + +void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) +{ + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} + +void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) +{ + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} + +void DH_get0_pqg(const DH *dh, + const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) +{ + if (p != NULL) + *p = dh->p; + if (q != NULL) + *q = dh->q; + if (g != NULL) + *g = dh->g; +} + +int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + /* If the fields p and g in d are NULL, the corresponding input + * parameters MUST be non-NULL. q may remain NULL. + */ + if ((dh->p == NULL && p == NULL) + || (dh->g == NULL && g == NULL)) + return 0; + + if (p != NULL) { + BN_free(dh->p); + dh->p = p; + } + if (q != NULL) { + BN_free(dh->q); + dh->q = q; + } + if (g != NULL) { + BN_free(dh->g); + dh->g = g; + } + + if (q != NULL) { + dh->length = BN_num_bits(q); + } + + return 1; +} + +void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) +{ + if (pub_key != NULL) + *pub_key = dh->pub_key; + if (priv_key != NULL) + *priv_key = dh->priv_key; +} + +int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) +{ + /* If the field pub_key in dh is NULL, the corresponding input + * parameters MUST be non-NULL. The priv_key field may + * be left NULL. + */ + if (dh->pub_key == NULL && pub_key == NULL) + return 0; + + if (pub_key != NULL) { + BN_free(dh->pub_key); + dh->pub_key = pub_key; + } + if (priv_key != NULL) { + BN_free(dh->priv_key); + dh->priv_key = priv_key; + } + + return 1; +} + +int DH_set_length(DH *dh, long length) +{ + dh->length = length; + return 1; +} + +const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx) +{ + return ctx->iv; +} + +unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx) +{ + return ctx->iv; +} + +EVP_MD_CTX *EVP_MD_CTX_new(void) +{ + return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); +} + +void EVP_MD_CTX_free(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +int RSA_size(const RSA* rsa) { + /* BIGNUM* n = NULL; + RSA_get0_key(rsa, n, NULL, NULL); */ + return BN_num_bytes(rsa->n); +} + +RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth) +{ + RSA_METHOD *ret; + + ret = OPENSSL_malloc(sizeof(RSA_METHOD)); + + if (ret != NULL) { + memcpy(ret, meth, sizeof(*meth)); + ret->name = OPENSSL_strdup(meth->name); + if (ret->name == NULL) { + OPENSSL_free(ret); + return NULL; + } + } + + return ret; +} + +int RSA_meth_set1_name(RSA_METHOD *meth, const char *name) +{ + char *tmpname; + + tmpname = OPENSSL_strdup(name); + if (tmpname == NULL) { + return 0; + } + + OPENSSL_free((char *)meth->name); + meth->name = tmpname; + + return 1; +} + +int RSA_meth_set_priv_enc(RSA_METHOD *meth, + int (*priv_enc) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + meth->rsa_priv_enc = priv_enc; + return 1; +} + +int RSA_meth_set_priv_dec(RSA_METHOD *meth, + int (*priv_dec) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + meth->rsa_priv_dec = priv_dec; + return 1; +} + +int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)) +{ + meth->finish = finish; + return 1; +} + +void RSA_meth_free(RSA_METHOD *meth) +{ + if (meth != NULL) { + OPENSSL_free((char *)meth->name); + OPENSSL_free(meth); + } +} + +int RSA_bits(const RSA *r) +{ + return (BN_num_bits(r->n)); +} + +RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) +{ + if (pkey->type != EVP_PKEY_RSA) { + return NULL; + } + return pkey->pkey.rsa; +} + +int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, + size_t *pderlen) +{ + /* Make sure encoding is valid */ + if (i2d_X509_NAME(nm, NULL) <= 0) + return 0; + if (pder != NULL) + *pder = (unsigned char *)nm->bytes->data; + if (pderlen != NULL) + *pderlen = nm->bytes->length; + return 1; +} + +#endif /* OPENSSL_VERSION_NUMBER */ + + +#if PY_MAJOR_VERSION >= 3 + +FILE* PyFile_AsFile(PyObject *pyfile) { + FILE* fp; + int fd; + const char *mode_str = NULL; + PyObject *mode_obj; + + if ((fd = PyObject_AsFileDescriptor(pyfile)) == -1) { + PyErr_SetString(PyExc_BlockingIOError, + "Cannot find file handler for the Python file!"); + return NULL; + } + + if ((mode_obj = PyObject_GetAttrString(pyfile, "mode")) == NULL) { + mode_str = "rb"; + PyErr_Clear(); + } + else { + /* convert to plain string + * note that error checking is embedded in the function + */ + mode_str = PyUnicode_AsUTF8AndSize(mode_obj, NULL); + } + + if((fp = fdopen(fd, mode_str)) == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + } + + Py_XDECREF(mode_obj); + return fp; +} + +#else /* PY2K */ + +#define PyLong_FromLong(x) PyInt_FromLong(x) +#define PyUnicode_AsUTF8(x) PyString_AsString(x) + +#endif /* PY_MAJOR_VERSION */ + + +/* OpenSSL 1.0.2 copmatbility shim */ +#if OPENSSL_VERSION_NUMBER < 0x10002000L +typedef void (*OPENSSL_sk_freefunc)(void *); +typedef void *(*OPENSSL_sk_copyfunc)(const void *); +typedef struct stack_st OPENSSL_STACK; + +# define MIN_NODES 4 +# define sk_deep_copy OPENSSL_sk_deep_copy + +void OPENSSL_sk_free(OPENSSL_STACK *st) +{ + if (st == NULL) + return; + OPENSSL_free(st->data); + OPENSSL_free(st); +} + +OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk, + OPENSSL_sk_copyfunc copy_func, + OPENSSL_sk_freefunc free_func) +{ + OPENSSL_STACK *ret; + int i; + + if (sk->num < 0) + return NULL; + + if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) + return NULL; + + /* direct structure assignment */ + *ret = *sk; + + ret->num_alloc = sk->num > MIN_NODES ? (size_t)sk->num : MIN_NODES; + ret->data = OPENSSL_zalloc(sizeof(*ret->data) * ret->num_alloc); + if (ret->data == NULL) { + OPENSSL_free(ret); + return NULL; + } + + for (i = 0; i < ret->num; ++i) { + if (sk->data[i] == NULL) + continue; + if ((ret->data[i] = copy_func(sk->data[i])) == NULL) { + while (--i >= 0) + if (ret->data[i] != NULL) + free_func((void *)ret->data[i]); + OPENSSL_sk_free(ret); + return NULL; + } + } + return ret; +} +#endif /* OpenSSL 1.0.2 copmatbility shim */ + + +/* Blob interface. Deprecated. */ + +Blob *blob_new(int len, const char *errmsg) { + + Blob *blob; + if (!(blob=(Blob *)PyMem_Malloc(sizeof(Blob)))){ + PyErr_SetString(PyExc_MemoryError, errmsg); + return NULL; + } + if (!(blob->data=(unsigned char *)PyMem_Malloc(len))) { + PyMem_Free(blob); + PyErr_SetString(PyExc_MemoryError, errmsg); + return NULL; + } + blob->len=len; + return blob; +} + +Blob *blob_copy(Blob *from, const char *errmsg) { + Blob *blob=blob_new(from->len, errmsg); + if (!blob) { + PyErr_SetString(PyExc_MemoryError, errmsg); + return NULL; + } + memcpy(blob->data, from->data, from->len); + return blob; +} + +void blob_free(Blob *blob) { + PyMem_Free(blob->data); + PyMem_Free(blob); +} + + +/* Python helpers. */ + + + + +static int +m2_PyObject_AsReadBufferInt(PyObject *obj, const void **buffer, + int *buffer_len) +{ + int ret; + Py_ssize_t len; + + ret = PyObject_AsReadBuffer(obj, buffer, &len); + if (ret) + return ret; + if (len > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "object too large"); + return -1; + } + *buffer_len = len; + return 0; +} + +static int m2_PyObject_GetBufferInt(PyObject *obj, Py_buffer *view, int flags) +{ + int ret; + + if (PyObject_CheckBuffer(obj)) + ret = PyObject_GetBuffer(obj, view, flags); + else { + const void *buf; + + ret = PyObject_AsReadBuffer(obj, &buf, &view->len); + if (ret == 0) + view->buf = (void *)buf; + } + if (ret) + return ret; + if (view->len > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "object too large"); + m2_PyBuffer_Release(obj, view); + return -1; + } + + return 0; +} + +static BIGNUM* +m2_PyObject_AsBIGNUM(PyObject* value, PyObject* _py_exc) +{ + BIGNUM* bn; + const void* vbuf; + int vlen = 0; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { + PyErr_SetString(_py_exc, ERR_reason_error_string(ERR_get_error())); + return NULL; + } + + return bn; +} + +static void m2_PyBuffer_Release(PyObject *obj, Py_buffer *view) +{ + if (PyObject_CheckBuffer(obj)) + PyBuffer_Release(view); + /* else do nothing, view->buf comes from PyObject_AsReadBuffer */ +} + +static int +m2_PyString_AsStringAndSizeInt(PyObject *obj, char **s, int *len) +{ + int ret; + Py_ssize_t len2; + + ret = PyBytes_AsStringAndSize(obj, s, &len2); + + if (ret) + return ret; + if (len2 > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "string too large"); + return -1; + } + *len = len2; + return 0; +} + +/* Works as PyFile_Name, but always returns a new object. */ +PyObject *m2_PyFile_Name(PyObject *pyfile) { + PyObject *out = NULL; +#if PY_MAJOR_VERSION >= 3 + out = PyObject_GetAttrString(pyfile, "name"); +#else + out = PyFile_Name(pyfile); + Py_XINCREF(out); +#endif + return out; +} + +/* Yes, __FUNCTION__ is a non-standard symbol, but it is supported by + * both gcc and MSVC. */ +#define m2_PyErr_Msg(type) m2_PyErr_Msg_Caller(type, (const char*) __FUNCTION__) + +static void m2_PyErr_Msg_Caller(PyObject *err_type, const char* caller) { + const char *err_reason; + const char *data; + int flags; + /* This max size of a (longer than ours) OpenSSL error string is hardcoded + * in OpenSSL's crypto/err/err_prn.c:ERR_print_errors_cb() */ + char err_msg[4096]; + unsigned long err_code = ERR_get_error_line_data(NULL, NULL, &data, &flags); + + if (err_code != 0) { + err_reason = ERR_reason_error_string(err_code); + if (data && (flags & ERR_TXT_STRING)) + snprintf(err_msg, sizeof(err_msg), "%s (%s)", err_reason, data); + else + snprintf(err_msg, sizeof(err_msg), "%s", err_reason); + + PyErr_SetString(err_type, err_msg); + } else { + PyErr_Format(err_type, "Unknown error in function %s.", caller); + } +} + + +/* C callbacks invoked by OpenSSL; these in turn call back into +Python. */ + +int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) { + PyObject *argv, *ret; + PyObject *_x509_store_ctx_swigptr=0, *_x509_store_ctx_obj=0, *_x509_store_ctx_inst=0, *_klass=0; + PyObject *_x509=0, *_ssl_ctx=0; + SSL *ssl; + SSL_CTX *ssl_ctx; + X509 *x509; + int errnum, errdepth; + int cret; + int new_style_callback = 0, warning_raised_exception=0; + PyGILState_STATE gilstate; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx); + + gilstate = PyGILState_Ensure(); + + if (PyMethod_Check(ssl_verify_cb_func)) { + PyObject *func; + PyCodeObject *code; + func = PyMethod_Function(ssl_verify_cb_func); + code = (PyCodeObject *) PyFunction_GetCode(func); + if (code && code->co_argcount == 3) { /* XXX Python internals */ + new_style_callback = 1; + } + } else if (PyFunction_Check(ssl_verify_cb_func)) { + PyCodeObject *code = (PyCodeObject *) PyFunction_GetCode(ssl_verify_cb_func); + if (code && code->co_argcount == 2) { /* XXX Python internals */ + new_style_callback = 1; + } + } else { + /* XXX There are lots of other callable types, but we will assume + * XXX that any other type of callable uses the new style callback, + * XXX although this is not entirely safe assumption. + */ + new_style_callback = 1; + } + + if (new_style_callback) { + PyObject *x509mod; + + x509mod = PyDict_GetItemString(PyImport_GetModuleDict(), "M2Crypto.X509"); + _klass = PyObject_GetAttrString(x509mod, "X509_Store_Context"); + + _x509_store_ctx_swigptr = SWIG_NewPointerObj((void *)ctx, SWIGTYPE_p_X509_STORE_CTX, 0); + _x509_store_ctx_obj = Py_BuildValue("(Oi)", _x509_store_ctx_swigptr, 0); + + _x509_store_ctx_inst = PyObject_CallObject(_klass, _x509_store_ctx_obj); + + argv = Py_BuildValue("(iO)", ok, _x509_store_ctx_inst); + } else { + if (PyErr_Warn(PyExc_DeprecationWarning, "Old style callback, use cb_func(ok, store) instead")) { + warning_raised_exception = 1; + } + + x509 = X509_STORE_CTX_get_current_cert(ctx); + errnum = X509_STORE_CTX_get_error(ctx); + errdepth = X509_STORE_CTX_get_error_depth(ctx); + + ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + ssl_ctx = SSL_get_SSL_CTX(ssl); + + _x509 = SWIG_NewPointerObj((void *)x509, SWIGTYPE_p_X509, 0); + _ssl_ctx = SWIG_NewPointerObj((void *)ssl_ctx, SWIGTYPE_p_SSL_CTX, 0); + argv = Py_BuildValue("(OOiii)", _ssl_ctx, _x509, errnum, errdepth, ok); + } + + if (!warning_raised_exception) { + ret = PyEval_CallObject(ssl_verify_cb_func, argv); + } else { + ret = 0; + } + + if (!ret) { + /* Got an exception in PyEval_CallObject(), let's fail verification + * to be safe. + */ + cret = 0; + } else { + /* FIXME This is possibly problematic if ret > MAXINT */ + cret = (int)PyLong_AsLong(ret); + } + Py_XDECREF(ret); + Py_XDECREF(argv); + if (new_style_callback) { + Py_XDECREF(_x509_store_ctx_inst); + Py_XDECREF(_x509_store_ctx_obj); + Py_XDECREF(_x509_store_ctx_swigptr); + Py_XDECREF(_klass); + } else { + Py_XDECREF(_x509); + Py_XDECREF(_ssl_ctx); + } + + PyGILState_Release(gilstate); + + return cret; +} + +int x509_store_verify_callback(int ok, X509_STORE_CTX *ctx) { + PyGILState_STATE gilstate; + PyObject *argv, *ret; + PyObject *_x509_store_ctx_swigptr=0, *_x509_store_ctx_obj=0, *_x509_store_ctx_inst=0, *_klass=0; + int cret; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + PyObject *x509mod; + + + gilstate = PyGILState_Ensure(); + + /* Below, handle only what is called 'new style callback' in ssl_verify_callback(). + TODO: does 'old style callback' exist any more? */ + x509mod = PyDict_GetItemString(PyImport_GetModuleDict(), "M2Crypto.X509"); + _klass = PyObject_GetAttrString(x509mod, "X509_Store_Context"); + _x509_store_ctx_swigptr = SWIG_NewPointerObj((void *)ctx, SWIGTYPE_p_X509_STORE_CTX, 0); + _x509_store_ctx_obj = Py_BuildValue("(Oi)", _x509_store_ctx_swigptr, 0); + + _x509_store_ctx_inst = PyObject_CallObject(_klass, _x509_store_ctx_obj); + + argv = Py_BuildValue("(iO)", ok, _x509_store_ctx_inst); + + ret = PyEval_CallObject(x509_store_verify_cb_func, argv); + if (!ret) { + /* Got an exception in PyEval_CallObject(), let's fail verification + * to be safe. + */ + cret = 0; + } else { + cret = (int)PyInt_AsLong(ret); + } + + Py_XDECREF(ret); + Py_XDECREF(argv); + Py_XDECREF(_x509_store_ctx_inst); + Py_XDECREF(_x509_store_ctx_obj); + Py_XDECREF(_x509_store_ctx_swigptr); + Py_XDECREF(_klass); + + PyGILState_Release(gilstate); + return cret; +} + +void ssl_info_callback(const SSL *s, int where, int ret) { + PyObject *argv, *retval, *_SSL; + PyGILState_STATE gilstate; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + gilstate = PyGILState_Ensure(); + + _SSL = SWIG_NewPointerObj((void *)s, SWIGTYPE_p_SSL, 0); + argv = Py_BuildValue("(iiO)", where, ret, _SSL); + + retval = PyEval_CallObject(ssl_info_cb_func, argv); + + Py_XDECREF(retval); + Py_XDECREF(argv); + Py_XDECREF(_SSL); + + PyGILState_Release(gilstate); +} + +DH *ssl_set_tmp_dh_callback(SSL *ssl, int is_export, int keylength) { + PyObject *argv, *ret, *_ssl; + DH *dh; + PyGILState_STATE gilstate; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + gilstate = PyGILState_Ensure(); + + _ssl = SWIG_NewPointerObj((void *)ssl, SWIGTYPE_p_SSL, 0); + argv = Py_BuildValue("(Oii)", _ssl, is_export, keylength); + + ret = PyEval_CallObject(ssl_set_tmp_dh_cb_func, argv); + + if ((SWIG_ConvertPtr(ret, (void **)&dh, SWIGTYPE_p_DH, SWIG_POINTER_EXCEPTION | 0)) == -1) + dh = NULL; + Py_XDECREF(ret); + Py_XDECREF(argv); + Py_XDECREF(_ssl); + + PyGILState_Release(gilstate); + + return dh; +} + +RSA *ssl_set_tmp_rsa_callback(SSL *ssl, int is_export, int keylength) { + PyObject *argv, *ret, *_ssl; + RSA *rsa; + PyGILState_STATE gilstate; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + gilstate = PyGILState_Ensure(); + + _ssl = SWIG_NewPointerObj((void *)ssl, SWIGTYPE_p_SSL, 0); + argv = Py_BuildValue("(Oii)", _ssl, is_export, keylength); + + ret = PyEval_CallObject(ssl_set_tmp_rsa_cb_func, argv); + + if ((SWIG_ConvertPtr(ret, (void **)&rsa, SWIGTYPE_p_RSA, SWIG_POINTER_EXCEPTION | 0)) == -1) + rsa = NULL; + Py_XDECREF(ret); + Py_XDECREF(argv); + Py_XDECREF(_ssl); + + PyGILState_Release(gilstate); + + return rsa; +} + +/* Universal callback for dh_generate_parameters, + * dsa_generate_parametersm, and rsa_generate_key */ +int bn_gencb_callback(int p, int n, BN_GENCB *gencb) { + PyObject *argv, *ret, *cbfunc; + + cbfunc = (PyObject *)BN_GENCB_get_arg(gencb); + argv = Py_BuildValue("(ii)", p, n); + ret = PyEval_CallObject(cbfunc, argv); + PyErr_Clear(); + Py_DECREF(argv); + Py_XDECREF(ret); + return 1; +} + +int passphrase_callback(char *buf, int num, int v, void *arg) { + int i; + Py_ssize_t len; + char *str; + PyObject *argv, *ret, *cbfunc; + PyGILState_STATE gilstate; + + gilstate = PyGILState_Ensure(); + cbfunc = (PyObject *)arg; + argv = Py_BuildValue("(i)", v); + /* PyEval_CallObject sets exception, if needed. */ + ret = PyEval_CallObject(cbfunc, argv); + Py_DECREF(argv); + if (ret == NULL) { + PyGILState_Release(gilstate); + return -1; + } + + if (!PyBytes_Check(ret)) { + PyErr_SetString(PyExc_RuntimeError, + "Result of callback is not bytes()."); + Py_DECREF(ret); + PyGILState_Release(gilstate); + return -1; + } + if ((len = PyBytes_Size(ret)) > num) + len = num; + str = PyBytes_AsString(ret); + + for (i = 0; i < len; i++) + buf[i] = str[i]; + Py_DECREF(ret); + PyGILState_Release(gilstate); + return len; +} + + + +void lib_init() { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SSLeay_add_all_algorithms(); + ERR_load_ERR_strings(); +#endif +} + +/* Bignum routines that aren't not numerous enough to +warrant a separate file. */ + +PyObject *bn_to_mpi(const BIGNUM *bn) { + int len = 0; + unsigned char *mpi; + PyObject *pyo; + + len = BN_bn2mpi(bn, NULL); + if (!(mpi=(unsigned char *)PyMem_Malloc(len))) { + m2_PyErr_Msg(PyExc_MemoryError); + return NULL; + } + len=BN_bn2mpi(bn, mpi); + + pyo=PyBytes_FromStringAndSize((const char *)mpi, len); + + PyMem_Free(mpi); + return pyo; +} + +const BIGNUM *mpi_to_bn(PyObject *value) { + const void *vbuf; + int vlen = 0; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + return BN_mpi2bn(vbuf, vlen, NULL); +} + +PyObject *bn_to_bin(BIGNUM *bn) { + int len = 0; + unsigned char *bin; + PyObject *pyo; + + len = BN_num_bytes(bn); + if (!(bin=(unsigned char *)PyMem_Malloc(len))) { + PyErr_SetString(PyExc_MemoryError, "bn_to_bin"); + return NULL; + } + BN_bn2bin(bn, bin); + + pyo=PyBytes_FromStringAndSize((const char *)bin, len); + + PyMem_Free(bin); + return pyo; +} + +const BIGNUM *bin_to_bn(PyObject *value) { + const void *vbuf; + int vlen = 0; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + return BN_bin2bn(vbuf, vlen, NULL); +} + +PyObject *bn_to_hex(BIGNUM *bn) { + char *hex; + PyObject *pyo; + Py_ssize_t len = 0; + + hex = BN_bn2hex(bn); + if (!hex) { + m2_PyErr_Msg(PyExc_RuntimeError); + OPENSSL_free(hex); + return NULL; + } + len = strlen(hex); + + pyo=PyBytes_FromStringAndSize(hex, len); + + OPENSSL_free(hex); + return pyo; +} + +BIGNUM *hex_to_bn(PyObject *value) { + const void *vbuf; + Py_ssize_t vlen = 0; + BIGNUM *bn; + + if (PyObject_AsReadBuffer(value, &vbuf, &vlen) == -1) + return NULL; + + if ((bn=BN_new())==NULL) { + PyErr_SetString(PyExc_MemoryError, "hex_to_bn"); + return NULL; + } + if (BN_hex2bn(&bn, (const char *)vbuf) <= 0) { + m2_PyErr_Msg(PyExc_RuntimeError); + BN_free(bn); + return NULL; + } + return bn; +} + +BIGNUM *dec_to_bn(PyObject *value) { + const void *vbuf; + Py_ssize_t vlen = 0; + BIGNUM *bn; + + if (PyObject_AsReadBuffer(value, &vbuf, &vlen) == -1) + return NULL; + + if ((bn=BN_new())==NULL) { + PyErr_SetString(PyExc_MemoryError, "dec_to_bn"); + return NULL; + } + if ((BN_dec2bn(&bn, (const char *)vbuf) <= 0)) { + m2_PyErr_Msg(PyExc_RuntimeError); + BN_free(bn); + return NULL; + } + return bn; +} + + +SWIGINTERNINLINE PyObject* +SWIG_From_unsigned_SS_long (unsigned long value) +{ + return (value > LONG_MAX) ? + PyLong_FromUnsignedLong(value) : PyLong_FromLong((long)(value)); +} + + +SWIGINTERN int +SWIG_AsVal_unsigned_SS_long (PyObject *obj, unsigned long *val) +{ +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(obj)) { + long v = PyInt_AsLong(obj); + if (v >= 0) { + if (val) *val = v; + return SWIG_OK; + } else { + return SWIG_OverflowError; + } + } else +#endif + if (PyLong_Check(obj)) { + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); +#if PY_VERSION_HEX >= 0x03000000 + { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (v < 0) { + return SWIG_OverflowError; + } + } else { + PyErr_Clear(); + } + } +#endif + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { + if (val) *val = (unsigned long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +#include + + +static PyObject *_bio_err; + + +void pyfd_init(void); + +void bio_init(PyObject *bio_err) { + Py_INCREF(bio_err); + _bio_err = bio_err; + pyfd_init(); +} + +int bio_free(BIO *bio) { + int ret; + + Py_BEGIN_ALLOW_THREADS + ret = BIO_free(bio); + Py_END_ALLOW_THREADS + if (ret == 0) { + m2_PyErr_Msg(_bio_err); + } + return ret; +} + +BIO * bio_new_file(const char *filename, const char *mode) { + BIO *ret; + + Py_BEGIN_ALLOW_THREADS + ret = BIO_new_file(filename, mode); + Py_END_ALLOW_THREADS + + if (ret == NULL) { + m2_PyErr_Msg(_bio_err); + } + + return ret; +} + +BIO *bio_new_pyfile(PyObject *pyfile, int bio_close) { + FILE *fp = NULL; + BIO *bio = NULL; + + fp = PyFile_AsFile(pyfile); + + bio = BIO_new_fp(fp, bio_close); + + /* returns NULL if error occurred */ + if (bio == NULL) { + /* Find out the name of the file so we can have good error + * message. */ + PyObject *pyname = m2_PyFile_Name(pyfile); + char *name = PyBytes_AsString(pyname); + + if (name == NULL) { + PyErr_Format(_bio_err, + "Opening of the new BIO on file failed!"); + } + else { + PyErr_Format(_bio_err, + "Opening of the new BIO on file %s failed!", name); + } + Py_DECREF(pyname); + } + return bio; +} + +PyObject *bio_read(BIO *bio, int num) { + PyObject *blob; + void *buf; + int r; + + if (!(buf = PyMem_Malloc(num))) { + PyErr_SetString(PyExc_MemoryError, "bio_read"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + r = BIO_read(bio, buf, num); + Py_END_ALLOW_THREADS + if (r < 0) { + PyMem_Free(buf); + if (ERR_peek_error()) { + m2_PyErr_Msg(_bio_err); + return NULL; + } + Py_RETURN_NONE; + } + + blob = PyBytes_FromStringAndSize(buf, r); + + PyMem_Free(buf); + return blob; +} + +PyObject *bio_gets(BIO *bio, int num) { + PyObject *blob; + void *buf; + int r; + + if (!(buf = PyMem_Malloc(num))) { + PyErr_SetString(PyExc_MemoryError, "bio_gets"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + r = BIO_gets(bio, buf, num); + Py_END_ALLOW_THREADS + if (r < 1) { + PyMem_Free(buf); + if (ERR_peek_error()) { + m2_PyErr_Msg(_bio_err); + return NULL; + } + Py_RETURN_NONE; + } + + blob = PyBytes_FromStringAndSize(buf, r); + + PyMem_Free(buf); + return blob; +} + +int bio_write(BIO *bio, PyObject *from) { + const void *fbuf; + int flen = 0, ret; + + if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) + return -1; + + Py_BEGIN_ALLOW_THREADS + ret = BIO_write(bio, fbuf, flen); + Py_END_ALLOW_THREADS + if (ret < 0) { + if (ERR_peek_error()) { + m2_PyErr_Msg(_bio_err); + return -1; + } + } + return ret; +} + +/* XXX Casting size_t to int. */ +int bio_ctrl_pending(BIO *bio) { + return (int)BIO_ctrl_pending(bio); +} + +int bio_ctrl_wpending(BIO *bio) { + return (int)BIO_ctrl_wpending(bio); +} + +int bio_ctrl_get_write_guarantee(BIO *a) { + return BIO_ctrl_get_write_guarantee(a); +} + +int bio_reset(BIO *bio) { + return (int)BIO_reset(bio); +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) +{ +#if PY_VERSION_HEX>=0x03000000 + if (PyUnicode_Check(obj)) +#else + if (PyString_Check(obj)) +#endif + { + char *cstr; Py_ssize_t len; +#if PY_VERSION_HEX>=0x03000000 + if (!alloc && cptr) { + /* We can't allow converting without allocation, since the internal + representation of string in Python 3 is UCS-2/UCS-4 but we require + a UTF-8 representation. + TODO(bhy) More detailed explanation */ + return SWIG_RuntimeError; + } + obj = PyUnicode_AsUTF8String(obj); + PyBytes_AsStringAndSize(obj, &cstr, &len); + if(alloc) *alloc = SWIG_NEWOBJ; +#else + PyString_AsStringAndSize(obj, &cstr, &len); +#endif + if (cptr) { + if (alloc) { + /* + In python the user should not be able to modify the inner + string representation. To warranty that, if you define + SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string + buffer is always returned. + + The default behavior is just to return the pointer value, + so, be careful. + */ +#if defined(SWIG_PYTHON_SAFE_CSTRINGS) + if (*alloc != SWIG_OLDOBJ) +#else + if (*alloc == SWIG_NEWOBJ) +#endif + { + *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + *alloc = SWIG_NEWOBJ; + } + else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } else { + #if PY_VERSION_HEX>=0x03000000 + assert(0); /* Should never reach here in Python 3 */ + #endif + *cptr = SWIG_Python_str_AsChar(obj); + } + } + if (psize) *psize = len + 1; +#if PY_VERSION_HEX>=0x03000000 + Py_XDECREF(obj); +#endif + return SWIG_OK; + } else { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + if (pchar_descriptor) { + void* vptr = 0; + if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { + if (cptr) *cptr = (char *) vptr; + if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + } + } + return SWIG_TypeError; +} + + + + + +int bio_flush(BIO *bio) { + return (int)BIO_flush(bio); +} + +int bio_seek(BIO *bio, int offset) { + return (int)BIO_seek(bio, offset); +} + +int bio_tell(BIO* bio) { + return BIO_tell(bio); +} + +void bio_set_flags(BIO *bio, int flags) { + BIO_set_flags(bio, flags); +} + +int bio_get_flags(BIO *bio) { + return BIO_get_flags(bio); +} + +/* + * sets the cipher of BIO @param b to c using key @param key and IV @iv. + * @param enc should be set to 1 for encryption and zero to decryption. + * + */ +PyObject *bio_set_cipher(BIO *b, EVP_CIPHER *c, PyObject *key, PyObject *iv, int op) { + const void *kbuf, *ibuf; + Py_ssize_t klen, ilen; + + if ((PyObject_AsReadBuffer(key, &kbuf, &klen) == -1) + || (PyObject_AsReadBuffer(iv, &ibuf, &ilen) == -1)) + return NULL; + + BIO_set_cipher(b, (const EVP_CIPHER *)c, + (unsigned char *)kbuf, (unsigned char *)ibuf, op); + Py_RETURN_NONE; +} + +int bio_set_mem_eof_return(BIO *b, int v) { + return (int)BIO_set_mem_eof_return(b, v); +} + +int bio_get_fd(BIO *bio) { + return BIO_get_fd(bio, NULL); +} + + +int bio_do_handshake(BIO *bio) { + return BIO_do_handshake(bio); +} + +/* macro */ +int bio_make_bio_pair(BIO* b1, BIO* b2) { + return BIO_make_bio_pair(b1, b2); +} + +int bio_set_write_buf_size(BIO* b, size_t size) { + return BIO_set_write_buf_size(b, size); +} + +int bio_should_retry(BIO* a) { + return BIO_should_retry(a); +} + +int bio_should_read(BIO* a) { + return BIO_should_read(a); +} + +int bio_should_write(BIO* a) { + return BIO_should_write(a); +} + +/* Macros for things not defined before 1.1.0 */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static BIO_METHOD * +BIO_meth_new( int type, const char *name ) +{ + BIO_METHOD *method = malloc( sizeof(BIO_METHOD) ); + memset( method, 0, sizeof(BIO_METHOD) ); + + method->type = type; + method->name = name; + + return method; +} + +static void +BIO_meth_free( BIO_METHOD *meth ) +{ + if ( meth == NULL ) { + return; + } + + free(meth); +} +#define BIO_meth_set_write(m, f) (m)->bwrite = (f) +#define BIO_meth_set_read(m, f) (m)->bread = (f) +#define BIO_meth_set_puts(m, f) (m)->bputs = (f) +#define BIO_meth_set_gets(m, f) (m)->bgets = (f) +#define BIO_meth_set_ctrl(m, f) (m)->ctrl = (f) +#define BIO_meth_set_create(m, f) (m)->create = (f) +#define BIO_meth_set_destroy(m, f) (m)->destroy = (f) +#define BIO_set_shutdown(b, x) (b)->shutdown = x +#define BIO_get_shutdown(b) (b)->shutdown +#define BIO_set_init(b, x) b->init = x +#define BIO_get_init(b) (b)->init +#define BIO_set_data(b, x) b->ptr = x +#define BIO_clear_flags(b, x) b->flags &= ~(x) +#define BIO_get_data(b) b->ptr +#endif + +/* implment custom BIO_s_pyfd */ + +#ifdef _WIN32 +# define clear_sys_error() SetLastError(0) +/* Linux doesn't use underscored calls yet */ +# define open(p, f, m) _open(p, f, m) +# define read(f, b, n) _read(f, b, n) +# define write(f, b, n) _write(f, b, n) +# define close(f) _close(f) +# define lseek(fd, o, w) _lseek(fd, o, w) +#else +# define clear_sys_error() errno=0 +#endif + +typedef struct pyfd_struct { + int fd; +} BIO_PYFD_CTX; + +/* Setting up methods_fdp */ +static BIO_METHOD *methods_fdp; + +static int pyfd_write(BIO *b, const char *in, int inl) { + int ret, fd; + + if (BIO_get_fd(b, &fd) == -1) { + PyErr_SetString(_bio_err, "BIO has not been initialized."); + return -1; + } + clear_sys_error(); + ret = write(fd, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_write(b); + } + return ret; +} + +static int pyfd_read(BIO *b, char *out, int outl) { + int ret = 0, fd; + + if (BIO_get_fd(b, &fd) == -1) { + PyErr_SetString(_bio_err, "BIO has not been initialized."); + return -1; + } + if (out != NULL) { + clear_sys_error(); + ret = read(fd, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_read(b); + } + } + return ret; +} + +static int pyfd_puts(BIO *bp, const char *str) { + int n, ret; + + n = strlen(str); + ret = pyfd_write(bp, str, n); + return ret; +} + +static int pyfd_gets(BIO *bp, char *buf, int size) { + int ret = 0; + char *ptr = buf; + char *end = buf + size - 1; + + /* See + https://github.com/openssl/openssl/pull/3442 + We were here just repeating a bug from OpenSSL + */ + while (ptr < end && pyfd_read(bp, ptr, 1) > 0) { + if (*ptr++ == '\n') + break; + } + + ptr[0] = '\0'; + + if (buf[0] != '\0') + ret = strlen(buf); + return ret; +} + +static int pyfd_new(BIO* b) { + BIO_PYFD_CTX* ctx; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return 0; + + ctx->fd = -1; + + BIO_set_data(b, ctx); + BIO_set_shutdown(b, 0); + BIO_set_init(b, 1); + + return 1; + } + +static int pyfd_free(BIO* b) { + BIO_PYFD_CTX* ctx; + + if (b == 0) + return 0; + + ctx = BIO_get_data(b); + if (ctx == NULL) + return 0; + + if (BIO_get_shutdown(b) && BIO_get_init(b)) + close(ctx->fd); + + BIO_set_data(b, NULL); + BIO_set_shutdown(b, 0); + BIO_set_init(b, 0); + + OPENSSL_free(ctx); + + return 1; +} + +static long pyfd_ctrl(BIO *b, int cmd, long num, void *ptr) { + BIO_PYFD_CTX* ctx; + int *ip; + long ret = 1; + + ctx = BIO_get_data(b); + if (ctx == NULL) + return 0; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + case BIO_C_FILE_SEEK: + ret = (long)lseek(ctx->fd, num, 0); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = (long)lseek(ctx->fd, 0, 1); + break; + case BIO_C_SET_FD: + pyfd_free(b); + if (*((int *)ptr) > -1) { + if (!pyfd_new(b) || !(ctx = BIO_get_data(b))) + return 0; + ctx->fd = *((int *)ptr); + BIO_set_shutdown(b, (int)num); + BIO_set_init(b, 1); + } + break; + case BIO_C_GET_FD: + if (BIO_get_init(b)) { + ip = (int *)ptr; + if (ip != NULL) + *ip = ctx->fd; + ret = ctx->fd; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = BIO_get_shutdown(b); + break; + case BIO_CTRL_SET_CLOSE: + BIO_set_shutdown(b, (int)num); + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +void pyfd_init(void) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + methods_fdp = BIO_meth_new( + BIO_get_new_index()|BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK, + "python file descriptor"); +#else + methods_fdp = BIO_meth_new( + 100 |BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK, + "python file descriptor"); +#endif + + BIO_meth_set_write(methods_fdp, pyfd_write); + BIO_meth_set_read(methods_fdp, pyfd_read); + BIO_meth_set_puts(methods_fdp, pyfd_puts); + BIO_meth_set_gets(methods_fdp, pyfd_gets); + BIO_meth_set_ctrl(methods_fdp, pyfd_ctrl); + BIO_meth_set_create(methods_fdp, pyfd_new); + BIO_meth_set_destroy(methods_fdp, pyfd_free); +} + +BIO* BIO_new_pyfd(int fd, int close_flag) { + BIO *ret; + + ret = BIO_new(methods_fdp); + BIO_set_fd(ret, fd, close_flag); + return ret; + } + + +SWIGINTERNINLINE int +SWIG_AsVal_size_t (PyObject * obj, size_t *val) +{ + unsigned long v; + int res = SWIG_AsVal_unsigned_SS_long (obj, val ? &v : 0); + if (SWIG_IsOK(res) && val) *val = (size_t)(v); + return res; +} + + +#include + + +PyObject *bn_rand(int bits, int top, int bottom) +{ + BIGNUM* rnd; + PyObject *ret; + char *randhex; + + rnd = BN_new(); + if (rnd == NULL) { + m2_PyErr_Msg(PyExc_Exception); + return NULL; + } + + if (!BN_rand(rnd, bits, top, bottom)) { + /*Custom errors?*/ + m2_PyErr_Msg(PyExc_Exception); + BN_free(rnd); + return NULL; + } + + randhex = BN_bn2hex(rnd); + if (!randhex) { + /*Custom errors?*/ + m2_PyErr_Msg(PyExc_Exception); + BN_free(rnd); + return NULL; + } + BN_free(rnd); + + ret = PyLong_FromString(randhex, NULL, 16); + OPENSSL_free(randhex); + return ret; +} + + +PyObject *bn_rand_range(PyObject *range) +{ + BIGNUM* rnd; + BIGNUM *rng = NULL; + PyObject *ret, *tuple; + PyObject *format, *rangePyString; + char *randhex; /* PyLong_FromString is unhappy with const */ + const char *rangehex; + + /* Wow, it's a lot of work to convert into a hex string in C! */ + format = PyUnicode_FromString("%x"); + + if (!format) { + PyErr_SetString(PyExc_RuntimeError, "Cannot create Python string '%x'"); + return NULL; + } + tuple = PyTuple_New(1); + if (!tuple) { + Py_DECREF(format); + PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); + return NULL; + } + Py_INCREF(range); + PyTuple_SET_ITEM(tuple, 0, range); + + rangePyString = PyUnicode_Format(format, tuple); + + if (!rangePyString) { + PyErr_SetString(PyExc_Exception, "String Format failed"); + Py_DECREF(format); + Py_DECREF(tuple); + return NULL; + } + Py_DECREF(format); + Py_DECREF(tuple); + + rangehex = (const char*)PyUnicode_AsUTF8(rangePyString); + + if (!BN_hex2bn(&rng, rangehex)) { + /*Custom errors?*/ + m2_PyErr_Msg(PyExc_Exception); + Py_DECREF(rangePyString); + return NULL; + } + + Py_DECREF(rangePyString); + + if (!(rnd = BN_new())) { + PyErr_SetString(PyExc_MemoryError, "bn_rand_range"); + return NULL; + } + + if (!BN_rand_range(rnd, rng)) { + /*Custom errors?*/ + m2_PyErr_Msg(PyExc_Exception); + BN_free(rnd); + BN_free(rng); + return NULL; + } + + BN_free(rng); + + randhex = BN_bn2hex(rnd); + if (!randhex) { + /*Custom errors?*/ + m2_PyErr_Msg(PyExc_Exception); + BN_free(rnd); + return NULL; + } + BN_free(rnd); + + ret = PyLong_FromString(randhex, NULL, 16); + OPENSSL_free(randhex); + return ret; +} + + + +static PyObject *_rand_err; + +void rand_init(PyObject *rand_err) { + Py_INCREF(rand_err); + _rand_err = rand_err; +} + +PyObject *rand_seed(PyObject *seed) { + const void *buf; + int len = 0; + + m2_PyObject_AsReadBufferInt(seed, &buf, &len); + + RAND_seed(buf, len); + Py_RETURN_NONE; +} + +PyObject *rand_add(PyObject *blob, double entropy) { + const void *buf; + int len = 0; + + m2_PyObject_AsReadBufferInt(blob, &buf, &len); + + RAND_add(buf, len, entropy); + Py_RETURN_NONE; +} + +PyObject *rand_bytes(int n) { + void *blob; + int ret; + PyObject *obj; + + if (!(blob = PyMem_Malloc(n))) { + PyErr_SetString(PyExc_MemoryError, + "Insufficient memory for rand_bytes."); + return NULL; + } + if ((ret = RAND_bytes(blob, n)) == 1) { + obj = PyBytes_FromStringAndSize(blob, n); + PyMem_Free(blob); + return obj; + } else if (ret == 0) { + PyErr_SetString(_rand_err, "Not enough randomness."); + PyMem_Free(blob); + return NULL; + } else if (ret == -1) { + PyErr_SetString(_rand_err, + "Not supported by the current RAND method."); + PyMem_Free(blob); + return NULL; + } else { + PyMem_Free(blob); + m2_PyErr_Msg(_rand_err); + return NULL; + } +} + +PyObject *rand_pseudo_bytes(int n) { + int ret; + unsigned char *blob; + PyObject *tuple; + + if (!(blob=(unsigned char *)PyMem_Malloc(n))) { + PyErr_SetString(PyExc_MemoryError, "Insufficient memory for rand_pseudo_bytes."); + return NULL; + } + if (!(tuple=PyTuple_New(2))) { + PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); + PyMem_Free(blob); + return NULL; + } + ret = RAND_pseudo_bytes(blob, n); + if (ret == -1) { + PyMem_Free(blob); + Py_DECREF(tuple); + PyErr_SetString(_rand_err, + "Function RAND_pseudo_bytes not supported by the current RAND method."); + return NULL; + } else { + PyTuple_SET_ITEM(tuple, 0, PyBytes_FromStringAndSize((char*)blob, n)); + + PyMem_Free(blob); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong((long)ret)); + return tuple; + } +} + +PyObject *rand_file_name(void) { + PyObject *obj; + char *str; + if ((obj = PyBytes_FromStringAndSize(NULL, BUFSIZ))==NULL) { + PyErr_SetString(PyExc_MemoryError, "rand_file_name"); + return NULL; + } + str=PyBytes_AS_STRING(obj); + if (RAND_file_name(str, BUFSIZ)==NULL) { + PyErr_SetString(PyExc_RuntimeError, "rand_file_name"); + return NULL; + } + if (_PyBytes_Resize(&obj, (Py_ssize_t)strlen(str))!=0) + return NULL; /* mem exception set by _PyBytes_Resize */ + return obj; +} + +void rand_screen(void) { +#ifdef _WIN32 + RAND_screen(); +#endif +} + +int rand_win32_event(unsigned int imsg, int wparam, long lparam) { +#ifdef _WIN32 + return RAND_event(imsg, wparam, lparam); +#else + return 0; +#endif +} + + +SWIGINTERN int +SWIG_AsVal_unsigned_SS_int (PyObject * obj, unsigned int *val) +{ + unsigned long v; + int res = SWIG_AsVal_unsigned_SS_long (obj, &v); + if (SWIG_IsOK(res)) { + if ((v > UINT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (unsigned int)(v); + } + } + return res; +} + + +#include +#include +#include +#include +#include +#include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +HMAC_CTX *HMAC_CTX_new(void) { + HMAC_CTX *ret = PyMem_Malloc(sizeof(HMAC_CTX)); + HMAC_CTX_init(ret); + return ret; +} +#define HMAC_CTX_reset(ctx) HMAC_CTX_init(ctx) +#define HMAC_CTX_free(ctx) \ + do { \ + HMAC_CTX_cleanup(ctx); \ + PyMem_Free((void *)ctx); \ + } while(0) + +#define EVP_CIPHER_CTX_reset(ctx) EVP_CIPHER_CTX_init(ctx) +#endif + + +#define PKCS5_SALT_LEN 8 + +static PyObject *_evp_err; + +void evp_init(PyObject *evp_err) { + Py_INCREF(evp_err); + _evp_err = evp_err; +} + + +RSA *pkey_get1_rsa(EVP_PKEY *pkey) { + RSA *ret = NULL; + + if ((ret = EVP_PKEY_get1_RSA(pkey)) == NULL) { + /* _evp_err now inherits from PyExc_ValueError, so we should + * keep API intact. + */ + PyErr_Format(_evp_err, "Invalid key in function %s.", __FUNCTION__); + } + + return ret; +} + + +PyObject *pkcs5_pbkdf2_hmac_sha1(PyObject *pass, + PyObject *salt, + int iter, + int keylen) { + unsigned char *key; + unsigned char *saltbuf; + char *passbuf; + PyObject *ret; + int passlen = 0, saltlen = 0; + + if (m2_PyObject_AsReadBufferInt(pass, (const void **)&passbuf, + &passlen) == -1) + return NULL; + if (m2_PyObject_AsReadBufferInt(salt, (const void **)&saltbuf, + &saltlen) == -1) + return NULL; + + key = PyMem_Malloc(keylen); + if (key == NULL) + return PyErr_NoMemory(); + PKCS5_PBKDF2_HMAC_SHA1(passbuf, passlen, saltbuf, saltlen, iter, + keylen, key); + ret = PyBytes_FromStringAndSize((char*)key, keylen); + OPENSSL_cleanse(key, keylen); + PyMem_Free(key); + return ret; +} + +EVP_MD_CTX *md_ctx_new(void) { + EVP_MD_CTX *ctx; + + if (!(ctx = EVP_MD_CTX_create())) { + PyErr_SetString(PyExc_MemoryError, "md_ctx_new"); + return NULL; + } + return ctx; +} + +void md_ctx_free(EVP_MD_CTX *ctx) { + EVP_MD_CTX_destroy(ctx); +} + +int digest_update(EVP_MD_CTX *ctx, PyObject *blob) { + const void *buf; + Py_ssize_t len; + + if (PyObject_AsReadBuffer(blob, &buf, &len) == -1) + return -1; + + return EVP_DigestUpdate(ctx, buf, len); +} + +PyObject *digest_final(EVP_MD_CTX *ctx) { + void *blob; + int blen; + PyObject *ret; + + if (!(blob = PyMem_Malloc(EVP_MD_CTX_size(ctx)))) { + PyErr_SetString(PyExc_MemoryError, "digest_final"); + return NULL; + } + if (!EVP_DigestFinal(ctx, blob, (unsigned int *)&blen)) { + PyMem_Free(blob); + m2_PyErr_Msg(_evp_err); + return NULL; + } + + ret = PyBytes_FromStringAndSize(blob, blen); + + PyMem_Free(blob); + return ret; +} + +HMAC_CTX *hmac_ctx_new(void) { + HMAC_CTX *ctx; + + if (!(ctx = HMAC_CTX_new())) { + PyErr_SetString(PyExc_MemoryError, "hmac_ctx_new"); + return NULL; + } + return ctx; +} + +void hmac_ctx_free(HMAC_CTX *ctx) { + HMAC_CTX_free(ctx); +} + +PyObject *hmac_init(HMAC_CTX *ctx, PyObject *key, const EVP_MD *md) { + const void *kbuf; + int klen = 0; + + if (m2_PyObject_AsReadBufferInt(key, &kbuf, &klen) == -1) + return NULL; + + if (!HMAC_Init_ex(ctx, kbuf, klen, md, NULL)) { + PyErr_SetString(_evp_err, "HMAC_Init failed"); + return NULL; + } + Py_RETURN_NONE; +} + +PyObject *hmac_update(HMAC_CTX *ctx, PyObject *blob) { + const void *buf; + Py_ssize_t len; + + if (PyObject_AsReadBuffer(blob, &buf, &len) == -1) + return NULL; + + if (!HMAC_Update(ctx, buf, len)) { + PyErr_SetString(_evp_err, "HMAC_Update failed"); + return NULL; + } + Py_RETURN_NONE; +} + +PyObject *hmac_final(HMAC_CTX *ctx) { + void *blob; + int blen; + PyObject *ret; + + if (!(blob = PyMem_Malloc(HMAC_size(ctx)))) { + PyErr_SetString(PyExc_MemoryError, "hmac_final"); + return NULL; + } + + if (!HMAC_Final(ctx, blob, (unsigned int *)&blen)) { + PyErr_SetString(_evp_err, "HMAC_Final failed"); + return NULL; + } + + ret = PyBytes_FromStringAndSize(blob, blen); + + PyMem_Free(blob); + return ret; +} + +PyObject *hmac(PyObject *key, PyObject *data, const EVP_MD *md) { + const void *kbuf, *dbuf; + void *blob; + int klen = 0; + unsigned int blen; + Py_ssize_t dlen; + PyObject *ret; + + if ((m2_PyObject_AsReadBufferInt(key, &kbuf, &klen) == -1) + || (PyObject_AsReadBuffer(data, &dbuf, &dlen) == -1)) + return NULL; + + if (!(blob = PyMem_Malloc(EVP_MAX_MD_SIZE))) { + PyErr_SetString(PyExc_MemoryError, "hmac"); + return NULL; + } + HMAC(md, kbuf, klen, dbuf, dlen, blob, &blen); + blob = PyMem_Realloc(blob, blen); + + ret = PyBytes_FromStringAndSize(blob, blen); + + PyMem_Free(blob); + return ret; +} + +EVP_CIPHER_CTX *cipher_ctx_new(void) { + EVP_CIPHER_CTX *ctx; + + if (!(ctx = EVP_CIPHER_CTX_new())) { + PyErr_SetString(PyExc_MemoryError, "cipher_ctx_new"); + return NULL; + } + EVP_CIPHER_CTX_reset(ctx); + return ctx; +} + +void cipher_ctx_free(EVP_CIPHER_CTX *ctx) { + EVP_CIPHER_CTX_free(ctx); +} + +PyObject *bytes_to_key(const EVP_CIPHER *cipher, EVP_MD *md, + PyObject *data, PyObject *salt, + PyObject *iv, /* Not used */ + int iter) { + unsigned char key[EVP_MAX_KEY_LENGTH]; + const void *dbuf, *sbuf; + int dlen = 0, klen; + Py_ssize_t slen; + PyObject *ret; + + if ((m2_PyObject_AsReadBufferInt(data, &dbuf, &dlen) == -1) + || (PyObject_AsReadBuffer(salt, &sbuf, &slen) == -1)) + return NULL; + + assert((slen == 8) || (slen == 0)); + klen = EVP_BytesToKey(cipher, md, (unsigned char *)sbuf, + (unsigned char *)dbuf, dlen, iter, + key, NULL); /* Since we are not returning IV no need to derive it */ + + ret = PyBytes_FromStringAndSize((char*)key, klen); + + return ret; +} + +PyObject *cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + PyObject *key, PyObject *iv, int mode) { + const void *kbuf, *ibuf; + Py_ssize_t klen, ilen; + + if ((PyObject_AsReadBuffer(key, &kbuf, &klen) == -1) + || (PyObject_AsReadBuffer(iv, &ibuf, &ilen) == -1)) + return NULL; + + if (!EVP_CipherInit(ctx, cipher, (unsigned char *)kbuf, + (unsigned char *)ibuf, mode)) { + m2_PyErr_Msg(_evp_err); + return NULL; + } + Py_RETURN_NONE; +} + +PyObject *cipher_update(EVP_CIPHER_CTX *ctx, PyObject *blob) { + const void *buf; + int len = 0, olen; + void *obuf; + PyObject *ret; + + if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1) + return NULL; + + if (!(obuf = PyMem_Malloc(len + EVP_CIPHER_CTX_block_size(ctx) - 1))) { + PyErr_SetString(PyExc_MemoryError, "cipher_update"); + return NULL; + } + if (!EVP_CipherUpdate(ctx, obuf, &olen, (unsigned char *)buf, len)) { + PyMem_Free(obuf); + m2_PyErr_Msg(_evp_err); + return NULL; + } + + ret = PyBytes_FromStringAndSize(obuf, olen); + + PyMem_Free(obuf); + return ret; +} + +PyObject *cipher_final(EVP_CIPHER_CTX *ctx) { + void *obuf; + int olen; + PyObject *ret; + + if (!(obuf = PyMem_Malloc(EVP_CIPHER_CTX_block_size(ctx)))) { + PyErr_SetString(PyExc_MemoryError, "cipher_final"); + return NULL; + } + if (!EVP_CipherFinal(ctx, (unsigned char *)obuf, &olen)) { + PyMem_Free(obuf); + m2_PyErr_Msg(_evp_err); + return NULL; + } + + ret = PyBytes_FromStringAndSize(obuf, olen); + + PyMem_Free(obuf); + return ret; +} + +PyObject *sign_update(EVP_MD_CTX *ctx, PyObject *blob) { + const void *buf; + Py_ssize_t len; + + if (PyObject_AsReadBuffer(blob, &buf, &len) == -1) + return NULL; + + if (!EVP_SignUpdate(ctx, buf, len)) { + m2_PyErr_Msg(_evp_err); + return NULL; + } + Py_RETURN_NONE; +} + +PyObject *sign_final(EVP_MD_CTX *ctx, EVP_PKEY *pkey) { + PyObject *ret; + unsigned char *sigbuf; + unsigned int siglen = EVP_PKEY_size(pkey); + + sigbuf = (unsigned char*)OPENSSL_malloc(siglen); + if (!sigbuf) { + PyErr_SetString(PyExc_MemoryError, "sign_final"); + return NULL; + } + + if (!EVP_SignFinal(ctx, sigbuf, &siglen, pkey)) { + m2_PyErr_Msg(_evp_err); + OPENSSL_cleanse(sigbuf, siglen); + OPENSSL_free(sigbuf); + return NULL; + } + + ret = PyBytes_FromStringAndSize((char*)sigbuf, siglen); + + OPENSSL_cleanse(sigbuf, siglen); + OPENSSL_free(sigbuf); + return ret; +} + +int verify_update(EVP_MD_CTX *ctx, PyObject *blob) { + const void *buf; + Py_ssize_t len; + + if (PyObject_AsReadBuffer(blob, &buf, &len) == -1) + return -1; + + return EVP_VerifyUpdate(ctx, buf, len); +} + + +int verify_final(EVP_MD_CTX *ctx, PyObject *blob, EVP_PKEY *pkey) { + unsigned char *kbuf; + int len = 0; + + if (m2_PyObject_AsReadBufferInt(blob, (const void **)&kbuf, &len) == -1) + return -1; + + return EVP_VerifyFinal(ctx, kbuf, len, pkey); +} + + +const EVP_MD *get_digestbyname(const char* name) { + const EVP_MD *ret = NULL; + + if ((ret = EVP_get_digestbyname(name)) == NULL) { + m2_PyErr_Msg(_evp_err); + } + + return ret; +} + + +int pkey_write_pem_no_cipher(EVP_PKEY *pkey, BIO *f, PyObject *pyfunc) { + int ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_write_bio_PKCS8PrivateKey(f, pkey, NULL, NULL, 0, + passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return ret; +} + + +int pkey_write_pem(EVP_PKEY *pkey, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) { + int ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_write_bio_PKCS8PrivateKey(f, pkey, cipher, NULL, 0, + passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return ret; +} + + +EVP_PKEY *pkey_new(void) { + EVP_PKEY *ret; + + if ((ret = EVP_PKEY_new()) == NULL) { + PyErr_Format(PyExc_MemoryError, + "Insufficient memory for new key in function %s.", __FUNCTION__); + } + + return ret; +} + +EVP_PKEY *pkey_read_pem(BIO *f, PyObject *pyfunc) { + EVP_PKEY *pk; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + pk = PEM_read_bio_PrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + + if (pk == NULL) { + PyErr_Format(_evp_err, + "Unable to read private key in function %s.", __FUNCTION__); + } + + return pk; +} + +EVP_PKEY *pkey_read_pem_pubkey(BIO *f, PyObject *pyfunc) { + EVP_PKEY *pk; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + pk = PEM_read_bio_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + + if (pk == NULL) { + PyErr_Format(_evp_err, + "Unable to read public key in function %s.", __FUNCTION__); + } + + return pk; +} + + +int pkey_assign_rsa(EVP_PKEY *pkey, RSA *rsa) { + return EVP_PKEY_assign_RSA(pkey, rsa); +} + +PyObject *pkey_as_der(EVP_PKEY *pkey) { + unsigned char * pp = NULL; + int len; + PyObject * der; + len = i2d_PUBKEY(pkey, &pp); + if (len < 0){ + PyErr_SetString(_evp_err, "EVP_PKEY as DER failed"); + return NULL; + } + + der = PyBytes_FromStringAndSize((char*)pp, len); + + OPENSSL_free(pp); + return der; +} + +PyObject *pkey_get_modulus(EVP_PKEY *pkey) +{ + RSA *rsa; + DSA *dsa; + BIO *bio; + BUF_MEM *bptr; + PyObject *ret; + const BIGNUM* bn; + + switch (EVP_PKEY_base_id(pkey)) { + case EVP_PKEY_RSA: + rsa = EVP_PKEY_get1_RSA(pkey); + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + RSA_free(rsa); + PyErr_SetString(PyExc_MemoryError, "pkey_get_modulus"); + return NULL; + } + + RSA_get0_key(rsa, &bn, NULL, NULL); + if (!BN_print(bio, bn)) { + m2_PyErr_Msg(PyExc_RuntimeError); + BIO_free(bio); + RSA_free(rsa); + return NULL; + } + BIO_get_mem_ptr(bio, &bptr); + + ret = PyBytes_FromStringAndSize(bptr->data, bptr->length); + + (void)BIO_set_close(bio, BIO_CLOSE); + BIO_free(bio); + RSA_free(rsa); + + return ret; + break; + + case EVP_PKEY_DSA: + dsa = EVP_PKEY_get1_DSA(pkey); + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + DSA_free(dsa); + PyErr_SetString(PyExc_MemoryError, "pkey_get_modulus"); + return NULL; + } + + DSA_get0_key(dsa, &bn, NULL); + if (!BN_print(bio, bn)) { + m2_PyErr_Msg(PyExc_RuntimeError); + BIO_free(bio); + DSA_free(dsa); + return NULL; + } + BIO_get_mem_ptr(bio, &bptr); + + ret = PyBytes_FromStringAndSize(bptr->data, bptr->length); + + (void)BIO_set_close(bio, BIO_CLOSE); + BIO_free(bio); + DSA_free(dsa); + + return ret; + break; + + default: + PyErr_SetString(_evp_err, "unsupported key type"); + return NULL; + } +} + + + +#include + +#if OPENSSL_VERSION_NUMBER >= 0x0090800fL +#include +#endif + +/* +// 2004-10-10, ngps: +// CTR mode is not included in the default OpenSSL build. +// To use the AES CTR ciphers, link with your own copy of OpenSSL. +*/ +#ifdef HAVE_AES_CTR +extern EVP_CIPHER const *EVP_aes_128_ctr(void); +extern EVP_CIPHER const *EVP_aes_192_ctr(void); +extern EVP_CIPHER const *EVP_aes_256_ctr(void); +#endif + + +AES_KEY *aes_new(void) { + AES_KEY *key; + + if (!(key = (AES_KEY *)PyMem_Malloc(sizeof(AES_KEY)))) { + PyErr_SetString(PyExc_MemoryError, + "Insufficient memory for AES key."); + return NULL; + } + return key; +} + +void AES_free(AES_KEY *key) { + PyMem_Free((void *)key); +} + +/* +// op == 0: encrypt +// otherwise: decrypt (Python code will supply the value 1.) +*/ +PyObject *AES_set_key(AES_KEY *key, PyObject *value, int bits, int op) { + char *vbuf; + Py_ssize_t vlen; + + if (PyBytes_AsStringAndSize(value, &vbuf, &vlen) == -1) + return NULL; + + if (op == 0) + AES_set_encrypt_key((const unsigned char *)vbuf, bits, key); + else + AES_set_decrypt_key((const unsigned char *)vbuf, bits, key); + Py_RETURN_NONE; +} + +/* +// op == 0: encrypt +// otherwise: decrypt (Python code will supply the value 1.) +*/ +PyObject *AES_crypt(const AES_KEY *key, PyObject *in, int outlen, int op) { + char *buf; + Py_ssize_t len; + unsigned char *out; + PyObject *res; + + if (PyBytes_AsStringAndSize(in, &buf, &len) == -1) + return NULL; + + if (!(out=(unsigned char *)PyMem_Malloc(outlen))) { + PyErr_SetString(PyExc_MemoryError, "AES_crypt"); + return NULL; + } + if (op == 0) + AES_encrypt((const unsigned char *)buf, out, key); + else + AES_decrypt((const unsigned char *)buf, out, key); + res = PyBytes_FromStringAndSize((char*)out, outlen); + PyMem_Free(out); + return res; +} + +int AES_type_check(AES_KEY *key) { + return 1; +} + + +#include + + +RC4_KEY *rc4_new(void) { + RC4_KEY *key; + + if (!(key = (RC4_KEY *)PyMem_Malloc(sizeof(RC4_KEY)))) + PyErr_SetString(PyExc_MemoryError, "rc4_new"); + return key; +} + +void rc4_free(RC4_KEY *key) { + PyMem_Free((void *)key); +} + +PyObject *rc4_set_key(RC4_KEY *key, PyObject *value) { + const void *vbuf; + int vlen = 0; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + RC4_set_key(key, vlen, vbuf); + Py_RETURN_NONE; +} + +PyObject *rc4_update(RC4_KEY *key, PyObject *in) { + PyObject *ret; + const void *buf; + Py_ssize_t len; + void *out; + + if (PyObject_AsReadBuffer(in, &buf, &len) == -1) + return NULL; + + if (!(out = PyMem_Malloc(len))) { + PyErr_SetString(PyExc_MemoryError, "expected a string object"); + return NULL; + } + RC4(key, len, buf, out); + + ret = PyBytes_FromStringAndSize(out, len); + + PyMem_Free(out); + return ret; +} + +int rc4_type_check(RC4_KEY *key) { + return 1; +} + + +#include +#include +#include +#include +#include + + +static PyObject *_dh_err; + +void dh_init(PyObject *dh_err) { + Py_INCREF(dh_err); + _dh_err = dh_err; +} + +int dh_type_check(DH *dh) { + /* Our getting here means we passed Swig's type checking, + XXX Still need to check the pointer for sanity? */ + return 1; +} + + +DH *dh_read_parameters(BIO *bio) { + return PEM_read_bio_DHparams(bio, NULL, NULL, NULL); +} + +DH *dh_generate_parameters(int plen, int g, PyObject *pyfunc) { + DH *dh; + BN_GENCB *gencb; + int ret; + + if ((gencb=BN_GENCB_new()) == NULL) { + m2_PyErr_Msg(_dh_err); + return NULL; + } + + if ((dh=DH_new()) == NULL) { + m2_PyErr_Msg(_dh_err); + BN_GENCB_free(gencb); + return NULL; + } + + BN_GENCB_set(gencb, bn_gencb_callback, (void *)pyfunc); + + Py_INCREF(pyfunc); + ret = DH_generate_parameters_ex(dh, plen, g, gencb); + Py_DECREF(pyfunc); + BN_GENCB_free(gencb); + + if (ret) + return dh; + + m2_PyErr_Msg(_dh_err); + DH_free(dh); + return NULL; +} + +/* Note return value shenanigan. */ +int dh_check(DH *dh) { + int err; + + return (DH_check(dh, &err)) ? 0 : err; +} + +PyObject *dh_compute_key(DH *dh, PyObject *pubkey) { + const void *pkbuf; + int pklen = 0, klen; + void *key; + BIGNUM *pk; + PyObject *ret; + + if (m2_PyObject_AsReadBufferInt(pubkey, &pkbuf, &pklen) == -1) + return NULL; + + if (!(pk = BN_mpi2bn((unsigned char *)pkbuf, pklen, NULL))) { + m2_PyErr_Msg(_dh_err); + return NULL; + } + if (!(key = PyMem_Malloc(DH_size(dh)))) { + BN_free(pk); + PyErr_SetString(PyExc_MemoryError, "dh_compute_key"); + return NULL; + } + if ((klen = DH_compute_key((unsigned char *)key, pk, dh)) == -1) { + BN_free(pk); + PyMem_Free(key); + m2_PyErr_Msg(_dh_err); + return NULL; + } + + ret = PyBytes_FromStringAndSize((const char *)key, klen); + + BN_free(pk); + PyMem_Free(key); + return ret; +} + +PyObject *dh_get_p(DH *dh) { + const BIGNUM* p = NULL; + DH_get0_pqg(dh, &p, NULL, NULL); + if (!p) { + PyErr_SetString(_dh_err, "'p' is unset"); + return NULL; + } + return bn_to_mpi(p); +} + +PyObject *dh_get_g(DH *dh) { + const BIGNUM* g = NULL; + DH_get0_pqg(dh, NULL, NULL, &g); + if (!g) { + PyErr_SetString(_dh_err, "'g' is unset"); + return NULL; + } + return bn_to_mpi(g); +} + +PyObject *dh_get_pub(DH *dh) { + const BIGNUM* pub_key = NULL; + DH_get0_key(dh, &pub_key, NULL); + if (!pub_key) { + PyErr_SetString(_dh_err, "'pub' is unset"); + return NULL; + } + return bn_to_mpi(pub_key); +} + +PyObject *dh_get_priv(DH *dh) { + const BIGNUM* priv_key = NULL; + DH_get0_key(dh, NULL, &priv_key); + if (!priv_key) { + PyErr_SetString(_dh_err, "'priv' is unset"); + return NULL; + } + return bn_to_mpi(priv_key); +} + +PyObject *dh_set_pg(DH *dh, PyObject *pval, PyObject* gval) { + BIGNUM* p, *g; + + if (!(p = m2_PyObject_AsBIGNUM(pval, _dh_err)) + || !(g = m2_PyObject_AsBIGNUM(gval, _dh_err))) + return NULL; + + if (!DH_set0_pqg(dh, p, NULL, g)) { + PyErr_SetString(_dh_err, + "Cannot set prime number or generator of Z_p for DH."); + BN_free(p); + BN_free(g); + return NULL; + } + + Py_RETURN_NONE; +} + + +#include +#include +#include +#include +#include + + +static PyObject *_rsa_err; + +void rsa_init(PyObject *rsa_err) { + Py_INCREF(rsa_err); + _rsa_err = rsa_err; +} + + +RSA *rsa_read_key(BIO *f, PyObject *pyfunc) { + RSA *rsa; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + rsa = PEM_read_bio_RSAPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return rsa; +} + + +int rsa_write_key(RSA *rsa, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) { + int ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_write_bio_RSAPrivateKey(f, rsa, cipher, NULL, 0, + passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return ret; +} + + +int rsa_write_key_no_cipher(RSA *rsa, BIO *f, PyObject *pyfunc) { + int ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_write_bio_RSAPrivateKey(f, rsa, NULL, NULL, 0, + passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return ret; +} + + +RSA *rsa_read_pub_key(BIO *f) { + return PEM_read_bio_RSA_PUBKEY(f, NULL, NULL, NULL); +} + + +int rsa_write_pub_key(RSA *rsa, BIO *f) { + return PEM_write_bio_RSA_PUBKEY(f, rsa); +} + +PyObject *rsa_get_e(RSA *rsa) { + const BIGNUM* e = NULL; + RSA_get0_key(rsa, NULL, &e, NULL); + if (!e) { + PyErr_SetString(_rsa_err, "'e' is unset"); + return NULL; + } + return bn_to_mpi(e); +} + +PyObject *rsa_get_n(RSA *rsa) { + const BIGNUM* n = NULL; + RSA_get0_key(rsa, &n, NULL, NULL); + if (!n) { + PyErr_SetString(_rsa_err, "'n' is unset"); + return NULL; + } + return bn_to_mpi(n); +} + +PyObject *rsa_set_e(RSA *rsa, PyObject *eval) { + const BIGNUM* n_read = NULL; + BIGNUM* n = NULL; + BIGNUM* e; + + if (!(e = m2_PyObject_AsBIGNUM(eval, _rsa_err))) { + return NULL; + } + + /* n and e must be set at the same time so if e is unset, set it to zero */ + RSA_get0_key(rsa, &n_read, NULL, NULL); + if (!n_read) { + n = BN_new(); + } + + if (RSA_set0_key(rsa, n, e, NULL) != 1) { + PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); + BN_free(e); + BN_free(n); + return NULL; + } + Py_RETURN_NONE; +} + +PyObject *rsa_set_n(RSA *rsa, PyObject *nval) { + BIGNUM* n; + const BIGNUM* e_read = NULL; + BIGNUM* e = NULL; + + if (!(n = m2_PyObject_AsBIGNUM(nval, _rsa_err))) { + return NULL; + } + + /* n and e must be set at the same time so if e is unset, set it to zero */ + RSA_get0_key(rsa, NULL, &e_read, NULL); + if (!e_read) { + e = BN_new(); + } + + if (RSA_set0_key(rsa, n, e, NULL) != 1) { + PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); + BN_free(n); + BN_free(e); + return NULL; + } + Py_RETURN_NONE; +} + +PyObject *rsa_set_en(RSA *rsa, PyObject *eval, PyObject* nval) { + BIGNUM* e, *n; + + if (!(e = m2_PyObject_AsBIGNUM(eval, _rsa_err)) || + !(n = m2_PyObject_AsBIGNUM(nval, _rsa_err))) { + return NULL; + } + + if (!RSA_set0_key(rsa, n, e, NULL)) { + PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); + BN_free(e); + BN_free(n); + return NULL; + } + Py_RETURN_NONE; +} + +static BIGNUM* PyObject_Bin_AsBIGNUM(PyObject* value) { + BIGNUM* bn; + const void* vbuf; + int vlen = 0; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + if (!(bn = BN_bin2bn((unsigned char *)vbuf, vlen, NULL))) { + m2_PyErr_Msg(_rsa_err); + return NULL; + } + + return bn; +} + +PyObject *rsa_set_en_bin(RSA *rsa, PyObject *eval, PyObject* nval) { + BIGNUM* e, *n; + + if (!(e = PyObject_Bin_AsBIGNUM(eval)) || + !(n = PyObject_Bin_AsBIGNUM(nval))) { + return NULL; + } + + if (!RSA_set0_key(rsa, e, n, NULL)) { + PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); + BN_free(e); + BN_free(n); + return NULL; + } + Py_RETURN_NONE; +} + +PyObject *rsa_private_encrypt(RSA *rsa, PyObject *from, int padding) { + const void *fbuf; + void *tbuf; + int flen = 0, tlen; + PyObject *ret; + + if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) + return NULL; + + if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { + PyErr_SetString(PyExc_MemoryError, "rsa_private_encrypt"); + return NULL; + } + tlen = RSA_private_encrypt(flen, (unsigned char *)fbuf, + (unsigned char *)tbuf, rsa, padding); + if (tlen == -1) { + m2_PyErr_Msg(_rsa_err); + PyMem_Free(tbuf); + return NULL; + } + + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); + + PyMem_Free(tbuf); + return ret; +} + +PyObject *rsa_public_decrypt(RSA *rsa, PyObject *from, int padding) { + const void *fbuf; + void *tbuf; + int flen = 0, tlen = 0; + PyObject *ret; + + if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) + return NULL; + + /* OpenSSL docs are confused here: it says we only need buffer + * 'RSA_size()-11', but it is true only for RSA PKCS#1 type 1 + * padding. For other uses we need to use different sizes. */ + if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { + PyErr_SetString(PyExc_MemoryError, "rsa_public_decrypt"); + return NULL; + } + tlen = RSA_public_decrypt(flen, (unsigned char *)fbuf, + (unsigned char *)tbuf, rsa, padding); + if (tlen == -1) { + m2_PyErr_Msg(_rsa_err); + PyMem_Free(tbuf); + return NULL; + } + + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); + + PyMem_Free(tbuf); + return ret; +} + +PyObject *rsa_public_encrypt(RSA *rsa, PyObject *from, int padding) { + const void *fbuf; + void *tbuf; + int flen = 0, tlen; + PyObject *ret; + + if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) + return NULL; + + if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { + PyErr_SetString(PyExc_MemoryError, "rsa_public_encrypt"); + return NULL; + } + tlen = RSA_public_encrypt(flen, (unsigned char *)fbuf, + (unsigned char *)tbuf, rsa, padding); + if (tlen == -1) { + m2_PyErr_Msg(_rsa_err); + PyMem_Free(tbuf); + return NULL; + } + + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); + + PyMem_Free(tbuf); + return ret; +} + +PyObject *rsa_private_decrypt(RSA *rsa, PyObject *from, int padding) { + const void *fbuf; + void *tbuf; + int flen = 0, tlen; + PyObject *ret; + + if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) + return NULL; + + if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { + PyErr_SetString(PyExc_MemoryError, "rsa_private_decrypt"); + return NULL; + } + tlen = RSA_private_decrypt(flen, (unsigned char *)fbuf, + (unsigned char *)tbuf, rsa, padding); + if (tlen == -1) { + m2_PyErr_Msg(_rsa_err); + PyMem_Free(tbuf); + return NULL; + } + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); + + PyMem_Free(tbuf); + return ret; +} + +#if OPENSSL_VERSION_NUMBER >= 0x0090708fL +PyObject *rsa_padding_add_pkcs1_pss(RSA *rsa, PyObject *digest, EVP_MD *hash, int salt_length) { + const void *dbuf; + unsigned char *tbuf; + int dlen, result, tlen; + PyObject *ret; + + if (m2_PyObject_AsReadBufferInt(digest, &dbuf, &dlen) == -1) + return NULL; + + tlen = RSA_size(rsa); + + if (!(tbuf = OPENSSL_malloc(tlen))) { + PyErr_SetString(PyExc_MemoryError, "rsa_padding_add_pkcs1_pss"); + return NULL; + } + result = RSA_padding_add_PKCS1_PSS( + rsa, + tbuf, + (unsigned char *)dbuf, + hash, + salt_length); + + if (result == -1) { + m2_PyErr_Msg(_rsa_err); + OPENSSL_cleanse(tbuf, tlen); + OPENSSL_free(tbuf); + return NULL; + } + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); + OPENSSL_cleanse(tbuf, tlen); + OPENSSL_free(tbuf); + return ret; +} + +int rsa_verify_pkcs1_pss(RSA *rsa, PyObject *digest, PyObject *signature, EVP_MD *hash, int salt_length) { + const void *dbuf; + const void *sbuf; + int dlen, slen, ret; + + if (m2_PyObject_AsReadBufferInt(digest, &dbuf, &dlen) == -1) { + return 0; + } + + if (m2_PyObject_AsReadBufferInt(signature, &sbuf, &slen) == -1) { + return 0; + } + + ret = RSA_verify_PKCS1_PSS( + rsa, + (unsigned char *)dbuf, + hash, + (unsigned char *)sbuf, + salt_length); + + return ret; +} +#endif + +PyObject *rsa_sign(RSA *rsa, PyObject *py_digest_string, int method_type) { + int digest_len = 0; + int buf_len = 0; + int ret = 0; + unsigned int real_buf_len = 0; + char *digest_string = NULL; + unsigned char * sign_buf = NULL; + PyObject *signature; + + ret = m2_PyString_AsStringAndSizeInt(py_digest_string, &digest_string, + &digest_len); + if (ret == -1) { + /* PyString_AsStringAndSize raises the correct exceptions. */ + return NULL; + } + + buf_len = RSA_size(rsa); + sign_buf = (unsigned char *)PyMem_Malloc(buf_len); + ret = RSA_sign(method_type, (const unsigned char *)digest_string, digest_len, + sign_buf, &real_buf_len, rsa); + + if (!ret) { + m2_PyErr_Msg(_rsa_err); + PyMem_Free(sign_buf); + return NULL; + } + + signature = PyBytes_FromStringAndSize((const char*) sign_buf, buf_len); + + PyMem_Free(sign_buf); + return signature; +} + +int rsa_verify(RSA *rsa, PyObject *py_verify_string, PyObject* py_sign_string, int method_type){ + int ret = 0; + char * sign_string = NULL; + char * verify_string = NULL; + int verify_len = 0; + int sign_len = 0; + + ret = m2_PyString_AsStringAndSizeInt(py_verify_string, &verify_string, + &verify_len); + if (ret == -1) { + /* PyString_AsStringAndSize raises the correct exceptions. */ + return 0; + } + ret = m2_PyString_AsStringAndSizeInt(py_sign_string, &sign_string, + &sign_len); + if (ret == -1) { + return 0; + } + + ret = RSA_verify(method_type, (unsigned char *) verify_string, + verify_len, (unsigned char *) sign_string, + sign_len, rsa); + if (!ret) { + m2_PyErr_Msg(_rsa_err); + return 0; + } + return ret; +} + +PyObject *rsa_generate_key(int bits, unsigned long e, PyObject *pyfunc) { + RSA *rsa; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + BN_GENCB *gencb; + BIGNUM *e_big; + int ret; + + if ((e_big=BN_new()) == NULL) { + m2_PyErr_Msg(_rsa_err); + return NULL; + } + + if (BN_set_word(e_big, e) == 0) { + m2_PyErr_Msg(_rsa_err); + BN_free(e_big); + return NULL; + } + + if ((gencb=BN_GENCB_new()) == NULL) { + m2_PyErr_Msg(_rsa_err); + BN_free(e_big); + return NULL; + } + + if ((rsa = RSA_new()) == NULL) { + m2_PyErr_Msg(_rsa_err); + BN_free(e_big); + BN_GENCB_free(gencb); + return NULL; + } + + BN_GENCB_set(gencb, bn_gencb_callback, (void *) pyfunc); + + Py_INCREF(pyfunc); + ret = RSA_generate_key_ex(rsa, bits, e_big, gencb); + BN_free(e_big); + BN_GENCB_free(gencb); + Py_DECREF(pyfunc); + + if (ret) + return SWIG_NewPointerObj((void *)rsa, SWIGTYPE_p_RSA, 0); + + m2_PyErr_Msg(_rsa_err); + RSA_free(rsa); + return NULL; +} + +int rsa_type_check(RSA *rsa) { + return 1; +} + +int rsa_check_pub_key(RSA *rsa) { + const BIGNUM* n, *e; + RSA_get0_key(rsa, &n, &e, NULL); + return n && e; +} + + +int rsa_write_key_der(RSA *rsa, BIO *bio) { + return i2d_RSAPrivateKey_bio(bio, rsa); +} + + +#include +#include +#include +#include + +PyObject *dsa_sig_get_r(DSA_SIG *dsa_sig) { + const BIGNUM* pr; + DSA_SIG_get0(dsa_sig, &pr, NULL); + return bn_to_mpi(pr); +} + +PyObject *dsa_sig_get_s(DSA_SIG *dsa_sig) { + const BIGNUM* qs; + DSA_SIG_get0(dsa_sig, NULL, &qs); + return bn_to_mpi(qs); +} + + +static PyObject *_dsa_err; + +void dsa_init(PyObject *dsa_err) { + Py_INCREF(dsa_err); + _dsa_err = dsa_err; +} + + +DSA *dsa_generate_parameters(int bits, PyObject *pyfunc) { + DSA *dsa; + BN_GENCB *gencb; + int ret; + + if ((gencb=BN_GENCB_new()) == NULL) { + m2_PyErr_Msg(_dh_err); + return NULL; + } + + if ((dsa = DSA_new()) == NULL) { + m2_PyErr_Msg(_dsa_err); + BN_GENCB_free(gencb); + return NULL; + } + + BN_GENCB_set(gencb, bn_gencb_callback, (void *) pyfunc); + + Py_INCREF(pyfunc); + ret = DSA_generate_parameters_ex(dsa, bits, NULL, 0, NULL, NULL, + gencb); + Py_DECREF(pyfunc); + BN_GENCB_free(gencb); + + if (ret) + return dsa; + + m2_PyErr_Msg(_dsa_err); + DSA_free(dsa); + return NULL; +} + +DSA *dsa_read_params(BIO *f, PyObject *pyfunc) { + DSA *ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_read_bio_DSAparams(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + + if (ret == NULL) { + m2_PyErr_Msg(_dsa_err); + } + + return ret; +} + +DSA *dsa_read_key(BIO *f, PyObject *pyfunc) { + DSA *ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_read_bio_DSAPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + + if (ret == NULL) { + m2_PyErr_Msg(_dsa_err); + } + + return ret; +} + +DSA *dsa_read_pub_key(BIO *f, PyObject *pyfunc) { + DSA *ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_read_bio_DSA_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + + if (ret == NULL) { + m2_PyErr_Msg(_dsa_err); + } + + return ret; +} + + +PyObject *dsa_get_p(DSA *dsa) { + const BIGNUM* p = NULL; + DSA_get0_pqg(dsa, &p, NULL, NULL); + if (!p) { + PyErr_SetString(_dsa_err, "'p' is unset"); + return NULL; + } + return bn_to_mpi(p); +} + +PyObject *dsa_get_q(DSA *dsa) { + const BIGNUM* q = NULL; + DSA_get0_pqg(dsa, NULL, &q, NULL); + if (!q) { + PyErr_SetString(_dsa_err, "'q' is unset"); + return NULL; + } + return bn_to_mpi(q); +} + +PyObject *dsa_get_g(DSA *dsa) { + const BIGNUM* g = NULL; + DSA_get0_pqg(dsa, NULL, NULL, &g); + if (!g) { + PyErr_SetString(_dsa_err, "'g' is unset"); + return NULL; + } + return bn_to_mpi(g); +} + +PyObject *dsa_get_pub(DSA *dsa) { + const BIGNUM* pub_key = NULL; + DSA_get0_key(dsa, &pub_key, NULL); + if (!pub_key) { + PyErr_SetString(_dsa_err, "'pub' is unset"); + return NULL; + } + return bn_to_mpi(pub_key); +} + +PyObject *dsa_get_priv(DSA *dsa) { + const BIGNUM* priv_key = NULL; + DSA_get0_key(dsa, NULL, &priv_key); + if (!priv_key) { + PyErr_SetString(_dsa_err, "'priv' is unset"); + return NULL; + } + return bn_to_mpi(priv_key); +} + +PyObject *dsa_set_pqg(DSA *dsa, PyObject *pval, PyObject* qval, PyObject* gval) { + BIGNUM* p, *q, *g; + + if (!(p = m2_PyObject_AsBIGNUM(pval, _dsa_err)) + || !(q = m2_PyObject_AsBIGNUM(qval, _dsa_err)) + || !(g = m2_PyObject_AsBIGNUM(gval, _dsa_err))) + return NULL; + + if (!DSA_set0_pqg(dsa, p, q, g)) { + PyErr_SetString( + _dsa_err, + "Cannot set prime number, subprime, or generator of subgroup for DSA."); + BN_free(p); + BN_free(q); + BN_free(g); + return NULL; + } + + Py_RETURN_NONE; + } + +PyObject *dsa_set_pub(DSA *dsa, PyObject *value) { + BIGNUM *bn; + const void *vbuf; + int vlen = 0; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { + m2_PyErr_Msg(_dsa_err); + return NULL; + } + if (!DSA_set0_key(dsa, bn, NULL)) { + BN_free(bn); + PyErr_SetString(_dsa_err, "Cannot set private and public key for DSA."); + } + Py_RETURN_NONE; +} + + +int dsa_write_params_bio(DSA* dsa, BIO* f) { + return PEM_write_bio_DSAparams(f, dsa); +} + + +int dsa_write_key_bio(DSA* dsa, BIO* f, EVP_CIPHER *cipher, PyObject *pyfunc) { + int ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_write_bio_DSAPrivateKey(f, dsa, cipher, NULL, 0, + passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return ret; +} + + +int dsa_write_key_bio_no_cipher(DSA* dsa, BIO* f, PyObject *pyfunc) { + int ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_write_bio_DSAPrivateKey(f, dsa, NULL, NULL, 0, + passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return ret; +} + + +int dsa_write_pub_key_bio(DSA* dsa, BIO* f) { + return PEM_write_bio_DSA_PUBKEY(f, dsa); +} + + +PyObject *dsa_sign(DSA *dsa, PyObject *value) { + const void *vbuf; + int vlen = 0; + PyObject *tuple; + DSA_SIG *sig; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + if (!(sig = DSA_do_sign(vbuf, vlen, dsa))) { + m2_PyErr_Msg(_dsa_err); + return NULL; + } + if (!(tuple = PyTuple_New(2))) { + DSA_SIG_free(sig); + PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); + return NULL; + } + PyTuple_SET_ITEM(tuple, 0, dsa_sig_get_r(sig)); + PyTuple_SET_ITEM(tuple, 1, dsa_sig_get_s(sig)); + DSA_SIG_free(sig); + return tuple; +} + +int dsa_verify(DSA *dsa, PyObject *value, PyObject *r, PyObject *s) { + const void *vbuf, *rbuf, *sbuf; + int vlen = 0, rlen = 0, slen = 0; + DSA_SIG *sig; + BIGNUM* pr, *ps; + int ret; + + if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + || (m2_PyObject_AsReadBufferInt(r, &rbuf, &rlen) == -1) + || (m2_PyObject_AsReadBufferInt(s, &sbuf, &slen) == -1)) + return -1; + + if (!(sig = DSA_SIG_new())) { + m2_PyErr_Msg(_dsa_err); + return -1; + } + if (!(pr = BN_mpi2bn((unsigned char *)rbuf, rlen, NULL))) { + m2_PyErr_Msg(_dsa_err); + DSA_SIG_free(sig); + return -1; + } + if (!(ps = BN_mpi2bn((unsigned char *)sbuf, slen, NULL))) { + m2_PyErr_Msg(_dsa_err); + DSA_SIG_free(sig); + BN_free(pr); + return -1; + } + if (!DSA_SIG_set0(sig, pr, ps)) { + m2_PyErr_Msg(_dsa_err); + DSA_SIG_free(sig); + BN_free(pr); + BN_free(ps); + return -1; + } + + ret = DSA_do_verify(vbuf, vlen, sig, dsa); + DSA_SIG_free(sig); + if (ret == -1) + m2_PyErr_Msg(_dsa_err); + return ret; +} + +PyObject *dsa_sign_asn1(DSA *dsa, PyObject *value) { + const void *vbuf; + int vlen = 0; + void *sigbuf; + unsigned int siglen; + PyObject *ret; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + if (!(sigbuf = PyMem_Malloc(DSA_size(dsa)))) { + PyErr_SetString(PyExc_MemoryError, "dsa_sign_asn1"); + return NULL; + } + if (!DSA_sign(0, vbuf, vlen, (unsigned char *)sigbuf, &siglen, dsa)) { + m2_PyErr_Msg(_dsa_err); + PyMem_Free(sigbuf); + return NULL; + } + + ret = PyBytes_FromStringAndSize(sigbuf, siglen); + + PyMem_Free(sigbuf); + return ret; +} + +int dsa_verify_asn1(DSA *dsa, PyObject *value, PyObject *sig) { + const void *vbuf; + void *sbuf; + int vlen = 0, slen = 0, ret = 0; + + if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + || (m2_PyObject_AsReadBufferInt(sig, (const void **)&sbuf, &slen) + == -1)) + return -1; + + if ((ret = DSA_verify(0, vbuf, vlen, sbuf, slen, dsa)) == -1) + m2_PyErr_Msg(_dsa_err); + return ret; +} + +int dsa_check_key(DSA *dsa) { + const BIGNUM* pub_key, *priv_key; + DSA_get0_key(dsa, &pub_key, &priv_key); + return pub_key != NULL && priv_key != NULL; +} + +int dsa_check_pub_key(DSA *dsa) { + const BIGNUM* pub_key; + DSA_get0_key(dsa, &pub_key, NULL); + return pub_key ? 1 : 0; +} + +int dsa_keylen(DSA *dsa) { + const BIGNUM* p; + DSA_get0_pqg(dsa, &p, NULL, NULL); + return BN_num_bits(p); +} + +int dsa_type_check(DSA *dsa) { + return 1; +} + + +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#pragma comment(lib, "Ws2_32") +typedef unsigned __int64 uint64_t; +#else +#include +#include +#endif + + +static PyObject *_ssl_err; +static PyObject *_ssl_timeout_err; + +void ssl_init(PyObject *ssl_err, PyObject *ssl_timeout_err) { + SSL_library_init(); + SSL_load_error_strings(); + Py_INCREF(ssl_err); + Py_INCREF(ssl_timeout_err); + _ssl_err = ssl_err; + _ssl_timeout_err = ssl_timeout_err; +} + +const SSL_METHOD *tlsv1_method(void) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + PyErr_WarnEx(PyExc_DeprecationWarning, + "Function TLSv1_method has been deprecated.", 1); +#endif + return TLSv1_method(); +} + +void ssl_ctx_passphrase_callback(SSL_CTX *ctx, PyObject *pyfunc) { + SSL_CTX_set_default_passwd_cb(ctx, passphrase_callback); + SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)pyfunc); + Py_INCREF(pyfunc); +} + +int ssl_ctx_use_x509(SSL_CTX *ctx, X509 *x) { + int i; + + if (!(i = SSL_CTX_use_certificate(ctx, x))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + return i; + +} + +int ssl_ctx_use_cert(SSL_CTX *ctx, char *file) { + int i; + + if (!(i = SSL_CTX_use_certificate_file(ctx, file, SSL_FILETYPE_PEM))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + return i; +} + +int ssl_ctx_use_cert_chain(SSL_CTX *ctx, char *file) { + int i; + + if (!(i = SSL_CTX_use_certificate_chain_file(ctx, file))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + return i; +} + + +int ssl_ctx_use_privkey(SSL_CTX *ctx, char *file) { + int i; + + if (!(i = SSL_CTX_use_PrivateKey_file(ctx, file, SSL_FILETYPE_PEM))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + return i; +} + +int ssl_ctx_use_rsa_privkey(SSL_CTX *ctx, RSA *rsakey) { + int i; + + if (!(i = SSL_CTX_use_RSAPrivateKey(ctx, rsakey))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + return i; +} + +int ssl_ctx_use_pkey_privkey(SSL_CTX *ctx, EVP_PKEY *pkey) { + int i; + + if (!(i = SSL_CTX_use_PrivateKey(ctx, pkey))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + return i; +} + + +int ssl_ctx_check_privkey(SSL_CTX *ctx) { + int ret; + + if (!(ret = SSL_CTX_check_private_key(ctx))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + return ret; +} + +void ssl_ctx_set_client_CA_list_from_file(SSL_CTX *ctx, const char *ca_file) { + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(ca_file)); +} + +void ssl_ctx_set_verify_default(SSL_CTX *ctx, int mode) { + SSL_CTX_set_verify(ctx, mode, NULL); +} + +void ssl_ctx_set_verify(SSL_CTX *ctx, int mode, PyObject *pyfunc) { + Py_XDECREF(ssl_verify_cb_func); + Py_INCREF(pyfunc); + ssl_verify_cb_func = pyfunc; + SSL_CTX_set_verify(ctx, mode, ssl_verify_callback); +} + +int ssl_ctx_set_session_id_context(SSL_CTX *ctx, PyObject *sid_ctx) { + const void *buf; + int len = 0; + + if (m2_PyObject_AsReadBufferInt(sid_ctx, &buf, &len) == -1) + return -1; + + return SSL_CTX_set_session_id_context(ctx, buf, len); +} + +void ssl_ctx_set_info_callback(SSL_CTX *ctx, PyObject *pyfunc) { + Py_XDECREF(ssl_info_cb_func); + Py_INCREF(pyfunc); + ssl_info_cb_func = pyfunc; + SSL_CTX_set_info_callback(ctx, ssl_info_callback); +} + +long ssl_ctx_set_tmp_dh(SSL_CTX *ctx, DH* dh) { + return SSL_CTX_set_tmp_dh(ctx, dh); +} + +void ssl_ctx_set_tmp_dh_callback(SSL_CTX *ctx, PyObject *pyfunc) { + Py_XDECREF(ssl_set_tmp_dh_cb_func); + Py_INCREF(pyfunc); + ssl_set_tmp_dh_cb_func = pyfunc; + SSL_CTX_set_tmp_dh_callback(ctx, ssl_set_tmp_dh_callback); +} + +long ssl_ctx_set_tmp_rsa(SSL_CTX *ctx, RSA* rsa) { + return SSL_CTX_set_tmp_rsa(ctx, rsa); +} + +void ssl_ctx_set_tmp_rsa_callback(SSL_CTX *ctx, PyObject *pyfunc) { + Py_XDECREF(ssl_set_tmp_rsa_cb_func); + Py_INCREF(pyfunc); + ssl_set_tmp_rsa_cb_func = pyfunc; + SSL_CTX_set_tmp_rsa_callback(ctx, ssl_set_tmp_rsa_callback); +} + +int ssl_ctx_load_verify_locations(SSL_CTX *ctx, const char *cafile, const char *capath) { + return SSL_CTX_load_verify_locations(ctx, cafile, capath); +} + +/* SSL_CTX_set_options is a macro. */ +long ssl_ctx_set_options(SSL_CTX *ctx, long op) { + return SSL_CTX_set_options(ctx, op); +} + +int bio_set_ssl(BIO *bio, SSL *ssl, int flag) { + SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); + return BIO_ctrl(bio, BIO_C_SET_SSL, flag, (char *)ssl); +} + +long ssl_set_mode(SSL *ssl, long mode) { + return SSL_set_mode(ssl, mode); +} + +long ssl_get_mode(SSL *ssl) { + return SSL_get_mode(ssl); +} + +int ssl_set_tlsext_host_name(SSL *ssl, const char *name) { + long l; + + if (!(l = SSL_set_tlsext_host_name(ssl, name))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + /* Return an "int" to match the 'typemap(out) int' in _lib.i */ + return 1; +} + +void ssl_set_client_CA_list_from_file(SSL *ssl, const char *ca_file) { + SSL_set_client_CA_list(ssl, SSL_load_client_CA_file(ca_file)); +} + +void ssl_set_client_CA_list_from_context(SSL *ssl, SSL_CTX *ctx) { + SSL_set_client_CA_list(ssl, SSL_CTX_get_client_CA_list(ctx)); +} + +int ssl_set_session_id_context(SSL *ssl, PyObject *sid_ctx) { + const void *buf; + int len = 0; + + if (m2_PyObject_AsReadBufferInt(sid_ctx, &buf, &len) == -1) + return -1; + + return SSL_set_session_id_context(ssl, buf, len); +} + +int ssl_set_fd(SSL *ssl, int fd) { + int ret; + + if (!(ret = SSL_set_fd(ssl, fd))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + return ret; +} + +static void ssl_handle_error(int ssl_err, int ret) { + int err; + + switch (ssl_err) { + case SSL_ERROR_SSL: + PyErr_SetString(_ssl_err, + ERR_reason_error_string(ERR_get_error())); + break; + case SSL_ERROR_SYSCALL: + err = ERR_get_error(); + if (err) + PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); + else if (ret == 0) + PyErr_SetString(_ssl_err, "unexpected eof"); + else if (ret == -1) + PyErr_SetFromErrno(_ssl_err); + else + assert(0); + break; + default: + PyErr_SetString(_ssl_err, "unexpected SSL error"); + } +} + +#ifdef _WIN32 +/* http://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows */ +int gettimeofday(struct timeval *tp, void *tzp) +{ + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime( &system_time ); + SystemTimeToFileTime( &system_time, &file_time ); + time = ((uint64_t)file_time.dwLowDateTime ) ; + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long) ((time - EPOCH) / 10000000L); + tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + return 0; +} +#endif + +static int ssl_sleep_with_timeout(SSL *ssl, const struct timeval *start, + double timeout, int ssl_err) { +#ifdef _WIN32 +WSAPOLLFD fd; +#else +struct pollfd fd; +#endif + struct timeval tv; + int ms, tmp; + + assert(timeout > 0); + again: + gettimeofday(&tv, NULL); + /* tv >= start */ + if ((timeout + start->tv_sec - tv.tv_sec) > INT_MAX / 1000) + ms = -1; + else { + int fract; + + ms = ((start->tv_sec + (int)timeout) - tv.tv_sec) * 1000; + fract = (int)((start->tv_usec + (timeout - (int)timeout) * 1000000 + - tv.tv_usec + 999) / 1000); + if (ms > 0 && fract > INT_MAX - ms) + ms = -1; + else { + ms += fract; + if (ms <= 0) + goto timeout; + } + } + switch (ssl_err) { + case SSL_ERROR_WANT_READ: + fd.fd = SSL_get_rfd(ssl); + fd.events = POLLIN; + break; + + case SSL_ERROR_WANT_WRITE: + fd.fd = SSL_get_wfd(ssl); + fd.events = POLLOUT; + break; + + case SSL_ERROR_WANT_X509_LOOKUP: + return 0; /* FIXME: is this correct? */ + + default: + assert(0); + } + if (fd.fd == -1) { + PyErr_SetString(_ssl_err, "timeout on a non-FD SSL"); + return -1; + } + Py_BEGIN_ALLOW_THREADS +#ifdef _WIN32 + tmp = WSAPoll(&fd, 1, ms); +#else + tmp = poll(&fd, 1, ms); +#endif + Py_END_ALLOW_THREADS + switch (tmp) { + case 1: + return 0; + case 0: + goto timeout; + case -1: +#ifdef _WIN32 + if (WSAGetLastError() == EINTR) +#else + if (errno == EINTR) +#endif + goto again; + PyErr_SetFromErrno(_ssl_err); + return -1; + } + return 0; + + timeout: + PyErr_SetString(_ssl_timeout_err, "timed out"); + return -1; +} + +PyObject *ssl_accept(SSL *ssl, double timeout) { + PyObject *obj = NULL; + int r, ssl_err; + struct timeval tv; + + if (timeout > 0) + gettimeofday(&tv, NULL); + again: + Py_BEGIN_ALLOW_THREADS + r = SSL_accept(ssl); + ssl_err = SSL_get_error(ssl, r); + Py_END_ALLOW_THREADS + + + switch (ssl_err) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + obj = PyLong_FromLong((long)1); + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + if (timeout <= 0) { + obj = PyLong_FromLong((long)0); + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; + obj = NULL; + break; + case SSL_ERROR_SSL: + case SSL_ERROR_SYSCALL: + ssl_handle_error(ssl_err, r); + obj = NULL; + break; + } + + + return obj; +} + +PyObject *ssl_connect(SSL *ssl, double timeout) { + PyObject *obj = NULL; + int r, ssl_err; + struct timeval tv; + + if (timeout > 0) + gettimeofday(&tv, NULL); + again: + Py_BEGIN_ALLOW_THREADS + r = SSL_connect(ssl); + ssl_err = SSL_get_error(ssl, r); + Py_END_ALLOW_THREADS + + + switch (ssl_err) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + obj = PyLong_FromLong((long)1); + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + if (timeout <= 0) { + obj = PyLong_FromLong((long)0); + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; + obj = NULL; + break; + case SSL_ERROR_SSL: + case SSL_ERROR_SYSCALL: + ssl_handle_error(ssl_err, r); + obj = NULL; + break; + } + + + return obj; +} + +void ssl_set_shutdown1(SSL *ssl, int mode) { + SSL_set_shutdown(ssl, mode); +} + +PyObject *ssl_read(SSL *ssl, int num, double timeout) { + PyObject *obj = NULL; + void *buf; + int r; + struct timeval tv; + + if (!(buf = PyMem_Malloc(num))) { + PyErr_SetString(PyExc_MemoryError, "ssl_read"); + return NULL; + } + + + if (timeout > 0) + gettimeofday(&tv, NULL); + again: + Py_BEGIN_ALLOW_THREADS + r = SSL_read(ssl, buf, num); + Py_END_ALLOW_THREADS + + if (r >= 0) { + buf = PyMem_Realloc(buf, r); + obj = PyBytes_FromStringAndSize(buf, r); + } else { + int ssl_err; + + ssl_err = SSL_get_error(ssl, r); + switch (ssl_err) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + assert(0); + + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + if (timeout <= 0) { + Py_INCREF(Py_None); + obj = Py_None; + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; + obj = NULL; + break; + case SSL_ERROR_SSL: + case SSL_ERROR_SYSCALL: + ssl_handle_error(ssl_err, r); + obj = NULL; + break; + } + } + PyMem_Free(buf); + + + return obj; +} + +PyObject *ssl_read_nbio(SSL *ssl, int num) { + PyObject *obj = NULL; + void *buf; + int r, err; + + + if (!(buf = PyMem_Malloc(num))) { + PyErr_SetString(PyExc_MemoryError, "ssl_read"); + return NULL; + } + + + Py_BEGIN_ALLOW_THREADS + r = SSL_read(ssl, buf, num); + Py_END_ALLOW_THREADS + + + switch (SSL_get_error(ssl, r)) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + buf = PyMem_Realloc(buf, r); + + obj = PyBytes_FromStringAndSize(buf, r); + + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + Py_INCREF(Py_None); + obj = Py_None; + break; + case SSL_ERROR_SSL: + m2_PyErr_Msg(_ssl_err); + obj = NULL; + break; + case SSL_ERROR_SYSCALL: + err = ERR_get_error(); + if (err) + PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); + else if (r == 0) + PyErr_SetString(_ssl_err, "unexpected eof"); + else if (r == -1) + PyErr_SetFromErrno(_ssl_err); + obj = NULL; + break; + } + PyMem_Free(buf); + + + return obj; +} + +int ssl_write(SSL *ssl, PyObject *blob, double timeout) { + Py_buffer buf; + int r, ssl_err, ret; + struct timeval tv; + + + if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_CONTIG_RO) == -1) { + return -1; + } + + if (timeout > 0) + gettimeofday(&tv, NULL); + again: + Py_BEGIN_ALLOW_THREADS + r = SSL_write(ssl, buf.buf, buf.len); + ssl_err = SSL_get_error(ssl, r); + Py_END_ALLOW_THREADS + + + switch (ssl_err) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + ret = r; + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + if (timeout <= 0) { + ret = -1; + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; + ret = -1; + break; + case SSL_ERROR_SSL: + case SSL_ERROR_SYSCALL: + ssl_handle_error(ssl_err, r); + default: + ret = -1; + } + + m2_PyBuffer_Release(blob, &buf); + return ret; +} + +int ssl_write_nbio(SSL *ssl, PyObject *blob) { + Py_buffer buf; + int r, err, ret; + + + if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_CONTIG_RO) == -1) { + return -1; + } + + + Py_BEGIN_ALLOW_THREADS + r = SSL_write(ssl, buf.buf, buf.len); + Py_END_ALLOW_THREADS + + + switch (SSL_get_error(ssl, r)) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + ret = r; + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + ret = -1; + break; + case SSL_ERROR_SSL: + ret = -1; + break; + case SSL_ERROR_SYSCALL: + err = ERR_get_error(); + if (err) + PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); + else if (r == 0) + PyErr_SetString(_ssl_err, "unexpected eof"); + else if (r == -1) + PyErr_SetFromErrno(_ssl_err); + default: + ret = -1; + } + + m2_PyBuffer_Release(blob, &buf); + return ret; +} + +int ssl_cipher_get_bits(SSL_CIPHER *c) { + return SSL_CIPHER_get_bits(c, NULL); +} + +int sk_ssl_cipher_num(STACK_OF(SSL_CIPHER) *stack) { + return sk_SSL_CIPHER_num(stack); +} + +const SSL_CIPHER *sk_ssl_cipher_value(STACK_OF(SSL_CIPHER) *stack, int idx) { + return sk_SSL_CIPHER_value(stack, idx); +} + +STACK_OF(X509) *ssl_get_peer_cert_chain(SSL *ssl) { + return SSL_get_peer_cert_chain(ssl); +} + +int sk_x509_num(STACK_OF(X509) *stack) { + return sk_X509_num(stack); +} + +X509 *sk_x509_value(STACK_OF(X509) *stack, int idx) { + return sk_X509_value(stack, idx); +} + + +void i2d_ssl_session(BIO *bio, SSL_SESSION *sess) { + i2d_SSL_SESSION_bio(bio, sess); +} + + +SSL_SESSION *ssl_session_read_pem(BIO *bio) { + return PEM_read_bio_SSL_SESSION(bio, NULL, NULL, NULL); +} + + +int ssl_session_write_pem(SSL_SESSION *sess, BIO *bio) { + return PEM_write_bio_SSL_SESSION(bio, sess); +} + +int ssl_ctx_set_session_cache_mode(SSL_CTX *ctx, int mode) +{ + return SSL_CTX_set_session_cache_mode(ctx, mode); +} + +int ssl_ctx_get_session_cache_mode(SSL_CTX *ctx) +{ + return SSL_CTX_get_session_cache_mode(ctx); +} + +static long ssl_ctx_set_cache_size(SSL_CTX *ctx, long arg) +{ + return SSL_CTX_sess_set_cache_size(ctx, arg); +} + +int ssl_is_init_finished(SSL *ssl) +{ + return SSL_is_init_finished(ssl); +} + + +#include +#include +#include + +#include + +typedef STACK_OF(X509) SEQ_CERT; + +ASN1_ITEM_TEMPLATE(SEQ_CERT) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, SeqCert, X509) +ASN1_ITEM_TEMPLATE_END(SEQ_CERT) + +IMPLEMENT_ASN1_FUNCTIONS(SEQ_CERT) + + +X509 *x509_read_pem(BIO *bio) { + return PEM_read_bio_X509(bio, NULL, NULL, NULL); +} + + +X509 *d2i_x509(BIO *bio) { + return d2i_X509_bio(bio, NULL); +} + + +static PyObject *_x509_err; + +void x509_init(PyObject *x509_err) { + Py_INCREF(x509_err); + _x509_err = x509_err; +} + + +X509_REQ *d2i_x509_req(BIO *bio) { + return d2i_X509_REQ_bio(bio, NULL); +} + + +X509_REQ *x509_req_read_pem(BIO *bio) { + return PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL); +} + + +PyObject *i2d_x509(X509 *x) { + int len; + PyObject *ret = NULL; + unsigned char *buf = NULL; + len = i2d_X509(x, &buf); + if (len < 0) { + m2_PyErr_Msg(_x509_err); + } + else { + + ret = PyBytes_FromStringAndSize((char*)buf, len); + + OPENSSL_free(buf); + } + return ret; +} + + +int x509_req_write_pem(BIO *bio, X509_REQ *x) { + return PEM_write_bio_X509_REQ(bio, x); +} + + +X509_CRL *x509_crl_read_pem(BIO *bio) { + return PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL); +} + + +/* X509_set_version() is a macro. */ +int x509_set_version(X509 *x, long version) { + return X509_set_version(x, version); +} + +/* X509_get_version() is a macro. */ +long x509_get_version(X509 *x) { + return X509_get_version(x); +} + +/* X509_set_notBefore() is a macro. */ +int x509_set_not_before(X509 *x, ASN1_TIME *tm) { + return X509_set_notBefore(x, tm); +} + +/* X509_get_notBefore() is a macro. */ +ASN1_TIME *x509_get_not_before(X509 *x) { + return X509_get_notBefore(x); +} + +/* X509_set_notAfter() is a macro. */ +int x509_set_not_after(X509 *x, ASN1_TIME *tm) { + return X509_set_notAfter(x, tm); +} + +/* X509_get_notAfter() is a macro. */ +ASN1_TIME *x509_get_not_after(X509 *x) { + return X509_get_notAfter(x); +} + +int x509_sign(X509 *x, EVP_PKEY *pkey, EVP_MD *md) { + return X509_sign(x, pkey, md); +} + +/* x509_gmtime_adj() is a macro. */ +ASN1_TIME *x509_gmtime_adj(ASN1_TIME *s, long adj) { + return X509_gmtime_adj(s, adj); +} + +PyObject *x509_name_by_nid(X509_NAME *name, int nid) { + void *buf; + int len, xlen; + PyObject *ret; + + if ((len = X509_NAME_get_text_by_NID(name, nid, NULL, 0)) == -1) { + Py_RETURN_NONE; + } + len++; + if (!(buf = PyMem_Malloc(len))) { + PyErr_SetString(PyExc_MemoryError, "x509_name_by_nid"); + return NULL; + } + xlen = X509_NAME_get_text_by_NID(name, nid, buf, len); + + ret = PyBytes_FromStringAndSize(buf, xlen); + + PyMem_Free(buf); + return ret; +} + +int x509_name_set_by_nid(X509_NAME *name, int nid, PyObject *obj) { + return X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (unsigned char *)PyBytes_AsString(obj), -1, -1, 0); +} + +/* x509_name_add_entry_by_txt */ +int x509_name_add_entry_by_txt(X509_NAME *name, char *field, int type, char *bytes, int len, int loc, int set) { + return X509_NAME_add_entry_by_txt(name, field, type, (unsigned char *)bytes, len, loc, set); +} + +PyObject *x509_name_get_der(X509_NAME *name) { + const char* pder=""; + size_t pderlen; + i2d_X509_NAME(name, 0); + if (!X509_NAME_get0_der(name, (const unsigned char **)pder, &pderlen)) { + m2_PyErr_Msg(_x509_err); + return NULL; + } + return PyBytes_FromStringAndSize(pder, pderlen); +} + +/* sk_X509_free() is a macro. */ +void sk_x509_free(STACK_OF(X509) *stack) { + sk_X509_free(stack); +} + +/* sk_X509_push() is a macro. */ +int sk_x509_push(STACK_OF(X509) *stack, X509 *x509) { + return sk_X509_push(stack, x509); +} + +/* sk_X509_pop() is a macro. */ +X509 *sk_x509_pop(STACK_OF(X509) *stack) { + return sk_X509_pop(stack); +} + + +int x509_store_load_locations(X509_STORE *store, const char *file) { + int locations = 0; + + if ((locations = X509_STORE_load_locations(store, file, NULL)) < 1) { + m2_PyErr_Msg(_x509_err); + } + return locations; +} + +int x509_type_check(X509 *x509) { + return 1; +} + +int x509_name_type_check(X509_NAME *name) { + return 1; +} + +X509_NAME *x509_req_get_subject_name(X509_REQ *x) { + return X509_REQ_get_subject_name(x); +} + +long x509_req_get_version(X509_REQ *x) { + return X509_REQ_get_version(x); +} + +int x509_req_set_version(X509_REQ *x, long version) { + return X509_REQ_set_version(x, version); +} + +int x509_req_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts) { + return X509_REQ_add_extensions(req, exts); +} + +X509_NAME_ENTRY *x509_name_entry_create_by_txt(X509_NAME_ENTRY **ne, char *field, int type, char *bytes, int len) { + return X509_NAME_ENTRY_create_by_txt( ne, field, type, (unsigned char *)bytes, len); +} + + +X509V3_CTX * +x509v3_set_nconf(void) { + X509V3_CTX * ctx; + CONF *conf = NCONF_new(NULL); + + if (!(ctx=(X509V3_CTX *)PyMem_Malloc(sizeof(X509V3_CTX)))) { + PyErr_SetString(PyExc_MemoryError, "x509v3_set_nconf"); + return NULL; + } + /* X509V3_set_nconf does not generate any error signs at all. */ + X509V3_set_nconf(ctx, conf); + return ctx; +} + + +X509_EXTENSION * +x509v3_ext_conf(void *conf, X509V3_CTX *ctx, char *name, char *value) { + X509_EXTENSION * ext = NULL; + ext = X509V3_EXT_conf(conf, ctx, name, value); + PyMem_Free(ctx); + return ext; +} + + +/* X509_EXTENSION_free() might be a macro, didn't find definition. */ +void x509_extension_free(X509_EXTENSION *ext) { + X509_EXTENSION_free(ext); +} + +PyObject *x509_extension_get_name(X509_EXTENSION *ext) { + PyObject * ext_name; + const char * ext_name_str; + ext_name_str = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); + if (!ext_name_str) { + m2_PyErr_Msg(_x509_err); + return NULL; + } + ext_name = PyBytes_FromStringAndSize(ext_name_str, strlen(ext_name_str)); + return ext_name; +} + +/* sk_X509_EXTENSION_new_null is a macro. */ +STACK_OF(X509_EXTENSION) *sk_x509_extension_new_null(void) { + return sk_X509_EXTENSION_new_null(); +} + +/* sk_X509_EXTENSION_free() is a macro. */ +void sk_x509_extension_free(STACK_OF(X509_EXTENSION) *stack) { + sk_X509_EXTENSION_free(stack); +} + +/* sk_X509_EXTENSION_push() is a macro. */ +int sk_x509_extension_push(STACK_OF(X509_EXTENSION) *stack, X509_EXTENSION *x509_ext) { + return sk_X509_EXTENSION_push(stack, x509_ext); +} + +/* sk_X509_EXTENSION_pop() is a macro. */ +X509_EXTENSION *sk_x509_extension_pop(STACK_OF(X509_EXTENSION) *stack) { + return sk_X509_EXTENSION_pop(stack); +} + +/* sk_X509_EXTENSION_num() is a macro. */ +int sk_x509_extension_num(STACK_OF(X509_EXTENSION) *stack) { + return sk_X509_EXTENSION_num(stack); +} + +/* sk_X509_EXTENSION_value() is a macro. */ +X509_EXTENSION *sk_x509_extension_value(STACK_OF(X509_EXTENSION) *stack, int i) { + return sk_X509_EXTENSION_value(stack, i); +} + +/* X509_STORE_CTX_get_app_data is a macro. */ +void *x509_store_ctx_get_app_data(X509_STORE_CTX *ctx) { + return X509_STORE_CTX_get_app_data(ctx); +} + +/* X509_STORE_CTX_get_app_data is a macro. */ +void *x509_store_ctx_get_ex_data(X509_STORE_CTX *ctx, int idx) { + return X509_STORE_CTX_get_ex_data(ctx, idx); +} + +void x509_store_set_verify_cb(X509_STORE *store, PyObject *pyfunc) { + Py_XDECREF(x509_store_verify_cb_func); + Py_INCREF(pyfunc); + x509_store_verify_cb_func = pyfunc; + X509_STORE_set_verify_cb(store, x509_store_verify_callback); +} + + +STACK_OF(X509) * +make_stack_from_der_sequence(PyObject * pyEncodedString){ + STACK_OF(X509) *certs; + Py_ssize_t encoded_string_len; + char *encoded_string; + const unsigned char *tmp_str; + + encoded_string_len = PyBytes_Size(pyEncodedString); + + if (encoded_string_len > INT_MAX) { + PyErr_Format(_x509_err, "object too large"); + return NULL; + } + + encoded_string = PyBytes_AsString(pyEncodedString); + + if (!encoded_string) { + PyErr_SetString(_x509_err, + "Cannot convert Python Bytes to (char *)."); + return NULL; + } + + tmp_str = (unsigned char *)encoded_string; + certs = d2i_SEQ_CERT(NULL, &tmp_str, encoded_string_len); + if (certs == NULL) { + PyErr_SetString(_x509_err, "Generating STACK_OF(X509) failed."); + return NULL; + } + return certs; +} + +/* sk_X509_new_null() is a macro returning "STACK_OF(X509) *". */ +STACK_OF(X509) *sk_x509_new_null(void) { + return sk_X509_new_null(); +} + + +PyObject * +get_der_encoding_stack(STACK_OF(X509) *stack){ + PyObject * encodedString; + + unsigned char * encoding = NULL; + int len; + + len = i2d_SEQ_CERT(stack, &encoding); + if (!encoding) { + m2_PyErr_Msg(_x509_err); + return NULL; + } + + encodedString = PyBytes_FromStringAndSize((const char *)encoding, len); + + if (encoding) + OPENSSL_free(encoding); + + return encodedString; +} + + + +char *x509_name_oneline(X509_NAME *x) { + return X509_NAME_oneline(x, NULL, 0); +} + + +#include + + +/* ASN1_TIME_set_string () is a macro */ +int asn1_time_type_check(ASN1_TIME *ASN1_TIME) { + return 1; +} + +PyObject *asn1_integer_get(ASN1_INTEGER *asn1) { + BIGNUM *bn; + PyObject *ret; + char *hex; + + bn = ASN1_INTEGER_to_BN(asn1, NULL); + + if (!bn){ + m2_PyErr_Msg(PyExc_RuntimeError); + return NULL; + } + + hex = BN_bn2hex(bn); + + if (!hex){ + m2_PyErr_Msg(PyExc_RuntimeError); + BN_free(bn); + return NULL; + } + + BN_free(bn); + + ret = PyLong_FromString(hex, NULL, 16); + + OPENSSL_free(hex); + + return ret; +} + +int asn1_integer_set(ASN1_INTEGER *asn1, PyObject *value) { + BIGNUM *bn = NULL; + PyObject *fmt, *args, *hex; + +/* Despite all hopes to the contrary, we cannot survive here with + * PyLong_AsLong shims as provided in + * /usr/include/python2.7/longobject.h. + */ +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(value)) + return ASN1_INTEGER_set(asn1, PyLong_AsLong(value)); +#else + if (PyInt_Check(value)) + return ASN1_INTEGER_set(asn1, PyInt_AS_LONG(value)); +#endif // PY_MAJOR_VERSION >= 3 + + if (!PyLong_Check(value)){ + PyErr_SetString(PyExc_TypeError, "expected int or long"); + return 0; + } + + fmt = PyString_FromString("%x"); + + if (!fmt) + return 0; + + args = PyTuple_New(1); + + if (!args){ + Py_DECREF(fmt); + PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() failed"); + return 0; + } + + Py_INCREF(value); + PyTuple_SET_ITEM(args, 0, value); + hex = PyString_Format(fmt, args); + + if (!hex){ + PyErr_SetString(PyExc_RuntimeError, "PyString_Format() failed"); + Py_DECREF(fmt); + Py_DECREF(args); + return 0; + } + + Py_DECREF(fmt); + Py_DECREF(args); + + if (BN_hex2bn(&bn, PyString_AsString(hex)) <= 0){ + m2_PyErr_Msg(PyExc_RuntimeError); + Py_DECREF(hex); + return 0; + } + + Py_DECREF(hex); + + if (!BN_to_ASN1_INTEGER(bn, asn1)){ + m2_PyErr_Msg(PyExc_RuntimeError); + BN_free(bn); + return 0; + } + + BN_free(bn); + + return 1; +} + + + +#include +#include +#include +#include + + +static PyObject *_pkcs7_err, *_smime_err; + +void pkcs7_init(PyObject *pkcs7_err) { + Py_INCREF(pkcs7_err); + _pkcs7_err = pkcs7_err; +} + +void smime_init(PyObject *smime_err) { + Py_INCREF(smime_err); + _smime_err = smime_err; +} + + +PyObject *pkcs7_decrypt(PKCS7 *pkcs7, EVP_PKEY *pkey, X509 *cert, int flags) { + int outlen; + char *outbuf; + BIO *bio; + PyObject *ret; + + if (!(bio=BIO_new(BIO_s_mem()))) { + PyErr_SetString(PyExc_MemoryError, "pkcs7_decrypt"); + return NULL; + } + if (!PKCS7_decrypt(pkcs7, pkey, cert, bio, flags)) { + m2_PyErr_Msg(_pkcs7_err); + BIO_free(bio); + return NULL; + } + outlen = BIO_ctrl_pending(bio); + if (!(outbuf=(char *)PyMem_Malloc(outlen))) { + PyErr_SetString(PyExc_MemoryError, "pkcs7_decrypt"); + BIO_free(bio); + return NULL; + } + BIO_read(bio, outbuf, outlen); + + ret = PyBytes_FromStringAndSize(outbuf, outlen); + + BIO_free(bio); + PyMem_Free(outbuf); + return ret; +} + + +PKCS7 *pkcs7_encrypt(STACK_OF(X509) *stack, BIO *bio, EVP_CIPHER *cipher, int flags) { + return PKCS7_encrypt(stack, bio, cipher, flags); +} + + + +PKCS7 *pkcs7_sign1(X509 *x509, EVP_PKEY *pkey, STACK_OF(X509) *stack, BIO *bio, EVP_MD *hash, int flags) { + + PKCS7 *p7 = PKCS7_sign(NULL, NULL, stack, bio, flags | PKCS7_STREAM); + if (p7 == NULL) { + return NULL; + } + if (PKCS7_sign_add_signer(p7, x509, pkey, hash, flags) == NULL) { + return NULL; + } + if (PKCS7_final(p7, bio, flags) != 1) { + return NULL; + } + return p7; +} + + +PKCS7 *pkcs7_sign0(X509 *x509, EVP_PKEY *pkey, BIO *bio, EVP_MD *hash, int flags) { + return pkcs7_sign1(x509, pkey, NULL, bio, hash, flags); +} + + +PKCS7 *pkcs7_read_bio(BIO *bio) { + return PEM_read_bio_PKCS7(bio, NULL, NULL, NULL); +} + + +PKCS7 *pkcs7_read_bio_der(BIO *bio) { + return d2i_PKCS7_bio(bio, NULL); +} + + +PyObject *pkcs7_verify1(PKCS7 *pkcs7, STACK_OF(X509) *stack, X509_STORE *store, BIO *data, int flags) { + int res, outlen; + char *outbuf; + BIO *bio; + PyObject *ret; + + if (!(bio=BIO_new(BIO_s_mem()))) { + PyErr_SetString(PyExc_MemoryError, "pkcs7_verify1"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + res = PKCS7_verify(pkcs7, stack, store, data, bio, flags); + Py_END_ALLOW_THREADS + if (!res) { + m2_PyErr_Msg(_pkcs7_err); + BIO_free(bio); + return NULL; + } + outlen = BIO_ctrl_pending(bio); + if (!(outbuf=(char *)PyMem_Malloc(outlen))) { + PyErr_SetString(PyExc_MemoryError, "pkcs7_verify1"); + BIO_free(bio); + return NULL; + } + BIO_read(bio, outbuf, outlen); + + ret = PyBytes_FromStringAndSize(outbuf, outlen); + + BIO_free(bio); + PyMem_Free(outbuf); + return ret; +} + +PyObject *pkcs7_verify0(PKCS7 *pkcs7, STACK_OF(X509) *stack, X509_STORE *store, int flags) { + return pkcs7_verify1(pkcs7, stack, store, NULL, flags); +} + + +int smime_write_pkcs7_multi(BIO *bio, PKCS7 *pkcs7, BIO *data, int flags) { + return SMIME_write_PKCS7(bio, pkcs7, data, flags | PKCS7_DETACHED); +} + + +int smime_write_pkcs7(BIO *bio, PKCS7 *pkcs7, int flags) { + return SMIME_write_PKCS7(bio, pkcs7, NULL, flags); +} + +PyObject *smime_read_pkcs7(BIO *bio) { + BIO *bcont = NULL; + PKCS7 *p7; + PyObject *tuple, *_p7, *_BIO; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (BIO_method_type(bio) == BIO_TYPE_MEM) { + /* OpenSSL FAQ explains that this is needed for mem BIO to return EOF, + * like file BIO does. Might need to do this for more mem BIOs but + * not sure if that is safe, so starting with just this single place. + */ + BIO_set_mem_eof_return(bio, 0); + } + + Py_BEGIN_ALLOW_THREADS + p7=SMIME_read_PKCS7(bio, &bcont); + Py_END_ALLOW_THREADS + if (!p7) { + m2_PyErr_Msg(_smime_err); + return NULL; + } + if (!(tuple=PyTuple_New(2))) { + PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); + return NULL; + } + _p7 = SWIG_NewPointerObj((void *)p7, SWIGTYPE_p_PKCS7, 0); + PyTuple_SET_ITEM(tuple, 0, _p7); + if (!bcont) { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, 1, Py_None); + } else { + _BIO = SWIG_NewPointerObj((void *)bcont, SWIGTYPE_p_BIO, 0); + PyTuple_SET_ITEM(tuple, 1, _BIO); + } + return tuple; +} + + +int pkcs7_write_bio(PKCS7 *pkcs7, BIO* bio) { + return PEM_write_bio_PKCS7(bio, pkcs7); +} + + +int pkcs7_write_bio_der(PKCS7 *pkcs7, BIO *bio) { + return i2d_PKCS7_bio(bio, pkcs7); +} + +int pkcs7_type_nid(PKCS7 *pkcs7) { + return OBJ_obj2nid(pkcs7->type); +} + +const char *pkcs7_type_sn(PKCS7 *pkcs7) { + return OBJ_nid2sn(OBJ_obj2nid(pkcs7->type)); +} + + +int smime_crlf_copy(BIO *in, BIO *out) { + return SMIME_crlf_copy(in, out, PKCS7_TEXT); +} + +/* return STACK_OF(X509)* */ +STACK_OF(X509) *pkcs7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags) { + return PKCS7_get0_signers(p7, certs, flags); +} + + + +#include + + +static PyObject *_util_err; + +void util_init(PyObject *util_err) { + Py_INCREF(util_err); + _util_err = util_err; +} + +PyObject *util_hex_to_string(PyObject *blob) { + PyObject *obj; + const void *buf; + char *ret; + Py_ssize_t len; + + if (PyObject_AsReadBuffer(blob, &buf, &len) == -1) + return NULL; + + ret = hex_to_string((unsigned char *)buf, len); + if (!ret) { + m2_PyErr_Msg(_util_err); + return NULL; + } + + obj = PyBytes_FromString(ret); + + OPENSSL_free(ret); + return obj; +} + +PyObject *util_string_to_hex(PyObject *blob) { + PyObject *obj; + const void *buf; + unsigned char *ret; + Py_ssize_t len0; + long len; + + if (PyObject_AsReadBuffer(blob, &buf, &len0) == -1) + return NULL; + + len = len0; + ret = string_to_hex((char *)buf, &len); + if (ret == NULL) { + m2_PyErr_Msg(_util_err); + return NULL; + } + obj = PyBytes_FromStringAndSize((char*)ret, len); + OPENSSL_free(ret); + return obj; +} + + +#include +#include +#include +#include +#include +#include + + +static PyObject *_ec_err; + +void ec_init(PyObject *ec_err) { + Py_INCREF(ec_err); + _ec_err = ec_err; +} + +PyObject *ec_get_builtin_curves(void) { + /* size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t + * nitems); */ + EC_builtin_curve *curves; + Py_ssize_t ret_curves = 0; + size_t num_curves = EC_get_builtin_curves(NULL, 0); + PyObject *ret_tuple = NULL; + PyObject *ret_dict = NULL; + Py_ssize_t i; + const char *comment; + const char *sname; + + if (!(curves = PyMem_Malloc(num_curves * sizeof(EC_builtin_curve)))) { + PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves"); + return NULL; + } + + ret_curves = (Py_ssize_t)EC_get_builtin_curves(curves, num_curves); + + if (!(ret_tuple = PyTuple_New(ret_curves))) { + PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves"); + return NULL; + } + + for (i = 0; i < ret_curves; i++) { + if (!(ret_dict = PyDict_New())) { + PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves"); + return NULL; + } + + comment = curves[i].comment; + sname = OBJ_nid2sn(curves[i].nid); + if (sname == NULL) + sname = ""; + + PyDict_SetItemString(ret_dict, "NID", + PyLong_FromLong((long)curves[i].nid)); + PyDict_SetItemString(ret_dict, "sname", + PyString_FromString(sname)); + PyDict_SetItemString(ret_dict, "comment", + PyString_FromString(comment)); + + PyTuple_SET_ITEM(ret_tuple, i, ret_dict); + + } + + PyMem_Free(curves); + + return ret_tuple; +} + +EC_KEY* ec_key_new_by_curve_name(int nid) +{ + EC_KEY *key; + EC_GROUP *group; + int ret =0; + point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; + int asn1_flag = OPENSSL_EC_NAMED_CURVE; + + /* If I simply do "return EC_KEY_new_by_curve_name(nid);" + * I get large public keys (222 vs 84 bytes for sect233k1 curve). + * I don't know why that is, but 'openssl ecparam -genkey ...' sets + * the ASN.1 flag and the point conversion form, and gets the + * small pub keys. So let's do that too. + */ + key = EC_KEY_new(); + if (!key) { + PyErr_SetString(PyExc_MemoryError, "ec_key_new_by_curve_name"); + return NULL; + } + group = EC_GROUP_new_by_curve_name(nid); + if (!group) { + m2_PyErr_Msg(_ec_err); + EC_KEY_free(key); + return NULL; + } + EC_GROUP_set_asn1_flag(group, asn1_flag); + EC_GROUP_set_point_conversion_form(group, form); + ret = EC_KEY_set_group(key, group); + EC_GROUP_free(group); + if (ret == 0) + { + /* EC_KEY_set_group only returns 0 or 1, and does not set error. */ + PyErr_SetString(_ec_err, "cannot set key's group"); + EC_KEY_free(key); + return NULL; + } + + return key; +} + +PyObject *ec_key_get_public_der(EC_KEY *key) { + char *src=NULL; + int src_len=0; + PyObject *pyo=NULL; + + /* Convert to binary */ + src_len = i2d_EC_PUBKEY( key, (unsigned char**)&src ); + if (src_len < 0) + { + m2_PyErr_Msg(_ec_err); + return NULL; + } + /* Create a PyBuffer containing a copy of the binary, + * to simplify memory deallocation + */ + pyo = PyBytes_FromStringAndSize( src, src_len ); + + OPENSSL_free(src); + + return pyo; +} + +PyObject *ec_key_get_public_key(EC_KEY *key) { + char *src=NULL; + int src_len=0; + PyObject *pyo=NULL; + + /* Convert to binary */ + src_len = i2o_ECPublicKey(key, (unsigned char**)&src); + if (src_len < 0) + { + m2_PyErr_Msg(_ec_err); + return NULL; + } + + pyo = PyBytes_FromStringAndSize( src, src_len ); + + OPENSSL_free(src); + + return pyo; +} + + + +EC_KEY *ec_key_read_pubkey(BIO *f) { + return PEM_read_bio_EC_PUBKEY(f, NULL, NULL, NULL); +} + + +int ec_key_write_pubkey(EC_KEY *key, BIO *f) { + return PEM_write_bio_EC_PUBKEY(f, key ); +} + + +EC_KEY *ec_key_read_bio(BIO *f, PyObject *pyfunc) { + EC_KEY *ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_read_bio_ECPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return ret; +} + + +int ec_key_write_bio(EC_KEY *key, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) { + int ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_write_bio_ECPrivateKey(f, key, cipher, NULL, 0, + passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return ret; +} + + +int ec_key_write_bio_no_cipher(EC_KEY *key, BIO *f, PyObject *pyfunc) { + int ret; + + Py_INCREF(pyfunc); + Py_BEGIN_ALLOW_THREADS + ret = PEM_write_bio_ECPrivateKey(f, key, NULL, NULL, 0, + passphrase_callback, (void *)pyfunc); + Py_END_ALLOW_THREADS + Py_DECREF(pyfunc); + return ret; +} + + +PyObject *ecdsa_sig_get_r(ECDSA_SIG *ecdsa_sig) { + const BIGNUM* pr; + ECDSA_SIG_get0(ecdsa_sig, &pr, NULL); + return bn_to_mpi(pr); +} + +PyObject *ecdsa_sig_get_s(ECDSA_SIG *ecdsa_sig) { + const BIGNUM* ps; + ECDSA_SIG_get0(ecdsa_sig, NULL, &ps); + return bn_to_mpi(ps); +} + +PyObject *ecdsa_sign(EC_KEY *key, PyObject *value) { + const void *vbuf; + int vlen = 0; + PyObject *tuple; + ECDSA_SIG *sig; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + if (!(sig = ECDSA_do_sign(vbuf, vlen, key))) { + m2_PyErr_Msg(_ec_err); + return NULL; + } + if (!(tuple = PyTuple_New(2))) { + ECDSA_SIG_free(sig); + PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); + return NULL; + } + PyTuple_SET_ITEM(tuple, 0, ecdsa_sig_get_r(sig)); + PyTuple_SET_ITEM(tuple, 1, ecdsa_sig_get_s(sig)); + ECDSA_SIG_free(sig); + return tuple; +} + +int ecdsa_verify(EC_KEY *key, PyObject *value, PyObject *r, PyObject *s) { + const void *vbuf, *rbuf, *sbuf; + int vlen = 0, rlen = 0, slen = 0; + ECDSA_SIG *sig; + int ret; + BIGNUM* pr, *ps; + + if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + || (m2_PyObject_AsReadBufferInt(r, &rbuf, &rlen) == -1) + || (m2_PyObject_AsReadBufferInt(s, &sbuf, &slen) == -1)) + return -1; + + if (!(pr = BN_mpi2bn((unsigned char *)rbuf, rlen, NULL))) { + m2_PyErr_Msg(_ec_err); + return -1; + } + if (!(ps = BN_mpi2bn((unsigned char *)sbuf, slen, NULL))) { + m2_PyErr_Msg(_ec_err); + BN_free(pr); + return -1; + } + + if (!(sig = ECDSA_SIG_new())) { + m2_PyErr_Msg(_ec_err); + BN_free(pr); + BN_free(ps); + return -1; + } + if (!ECDSA_SIG_set0(sig, pr, ps)) { + PyErr_SetString(_ec_err, "Cannot set r and s fields of ECDSA_SIG."); + ECDSA_SIG_free(sig); + BN_free(pr); + BN_free(ps); + return -1; + } + ret = ECDSA_do_verify(vbuf, vlen, sig, key); + ECDSA_SIG_free(sig); + if (ret == -1) + m2_PyErr_Msg(_ec_err); + return ret; +} + + +PyObject *ecdsa_sign_asn1(EC_KEY *key, PyObject *value) { + const void *vbuf; + int vlen = 0; + void *sigbuf; + unsigned int siglen; + PyObject *ret; + + if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + return NULL; + + if (!(sigbuf = PyMem_Malloc(ECDSA_size(key)))) { + PyErr_SetString(PyExc_MemoryError, "ecdsa_sign_asn1"); + return NULL; + } + if (!ECDSA_sign(0, vbuf, vlen, (unsigned char *)sigbuf, &siglen, key)) { + m2_PyErr_Msg(_ec_err); + PyMem_Free(sigbuf); + return NULL; + } + ret = PyBytes_FromStringAndSize(sigbuf, siglen); + + PyMem_Free(sigbuf); + return ret; +} + + +int ecdsa_verify_asn1(EC_KEY *key, PyObject *value, PyObject *sig) { + const void *vbuf; + void *sbuf; + int vlen = 0, slen = 0, ret; + + if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + || (m2_PyObject_AsReadBufferInt(sig, (const void **)&sbuf, &slen) + == -1)) + return -1; + + if ((ret = ECDSA_verify(0, vbuf, vlen, sbuf, slen, key)) == -1) + m2_PyErr_Msg(_ec_err); + return ret; +} + +PyObject *ecdh_compute_key(EC_KEY *keypairA, EC_KEY *pubkeyB) { + int sharedkeylen; + void *sharedkey; + const EC_POINT *pkpointB; + PyObject *ret; + const EC_GROUP* groupA; + + if ((pkpointB = EC_KEY_get0_public_key(pubkeyB)) == NULL) + { + PyErr_SetString(_ec_err, "Cannot get the public key of EC_KEY object."); + return NULL; + } + + groupA = EC_KEY_get0_group(keypairA); + sharedkeylen = (EC_GROUP_get_degree(groupA) + 7)/8; + + if (!(sharedkey = PyMem_Malloc(sharedkeylen))) { + PyErr_SetString(PyExc_MemoryError, "ecdh_compute_key"); + return NULL; + } + if ((sharedkeylen = ECDH_compute_key((unsigned char *)sharedkey, sharedkeylen, pkpointB, keypairA, NULL)) == -1) { + m2_PyErr_Msg(_ec_err); + PyMem_Free(sharedkey); + return NULL; + } + + ret = PyBytes_FromStringAndSize((const char *)sharedkey, sharedkeylen); + + PyMem_Free(sharedkey); + + return ret; +} + + +EC_KEY* ec_key_from_pubkey_der(PyObject *pubkey) { + const void *keypairbuf; + Py_ssize_t keypairbuflen; + const unsigned char *tempBuf; + EC_KEY *keypair; + + if (PyObject_AsReadBuffer(pubkey, &keypairbuf, &keypairbuflen) == -1) + { + return NULL; + } + + tempBuf = (const unsigned char *)keypairbuf; + if ((keypair = d2i_EC_PUBKEY( NULL, &tempBuf, keypairbuflen)) == 0) + { + m2_PyErr_Msg(_ec_err); + return NULL; + } + return keypair; +} + +EC_KEY* ec_key_from_pubkey_params(int nid, PyObject *pubkey) { + const void *keypairbuf; + Py_ssize_t keypairbuflen; + const unsigned char *tempBuf; + EC_KEY *keypair; + + if (PyObject_AsReadBuffer(pubkey, &keypairbuf, &keypairbuflen) == -1) + { + return NULL; + } + + keypair = ec_key_new_by_curve_name(nid); + if (!keypair) { + m2_PyErr_Msg(_ec_err); + return NULL; + } + + tempBuf = (const unsigned char *)keypairbuf; + if ((o2i_ECPublicKey( &keypair, &tempBuf, keypairbuflen)) == 0) + { + m2_PyErr_Msg(_ec_err); + return NULL; + } + return keypair; +} + + +// According to [SEC2] the degree of the group is defined as EC key length +int ec_key_keylen(EC_KEY *key) { + const EC_GROUP *group = EC_KEY_get0_group(key); + return EC_GROUP_get_degree(group); +} + +int ec_key_type_check(EC_KEY *key) { + return 1; +} + + +#include +#include +#include + + + +/* + * Code from engine-pkcs11 1.4.0 in engine-pkcs11.c + * + +99 static char *get_pin(UI_METHOD * ui_method, void *callback_data, char *sc_pin, +100 int maxlen) +101 { +102 UI *ui; +103 struct { +104 const void *password; +105 const char *prompt_info; +106 } *mycb = callback_data; +107 +108 if (mycb->password) { +109 sc_pin = set_pin(mycb->password); +110 return sc_pin; +111 } + + * + * So callback_data need to be always provided and have fixed type. + * UI method still may be NULL. + * + * Following functions allocate and free callback data structure with + * optional password set. + */ + +typedef struct { + char * password; + char * prompt; +} _cbd_t; + +void * engine_pkcs11_data_new(const char *pin) { + _cbd_t * cb = (_cbd_t *) PyMem_Malloc(sizeof(_cbd_t)); + if (!cb) { + PyErr_SetString(PyExc_MemoryError, "engine_pkcs11_data_new"); + return NULL; + } + cb->password = NULL; + if (pin) { + size_t size = strlen(pin); + cb->password = (char *) PyMem_Malloc(size + 1); + if (!cb->password) { + PyErr_SetString(PyExc_MemoryError, "engine_pkcs11_data_new"); + PyMem_Free(cb); + return NULL; + } + memcpy(cb->password, pin, size + 1); + } + cb->prompt = NULL; + return cb; +} + +void engine_pkcs11_data_free(void * vcb) { + _cbd_t * cb = (_cbd_t *) vcb; + if (!cb) + return; + if (cb->password) + PyMem_Free(cb->password); + PyMem_Free(cb); +} + + + +static PyObject *_engine_err; + +void engine_init_error(PyObject *engine_err) { + Py_INCREF(engine_err); + _engine_err = engine_err; +} + +X509 * engine_load_certificate(ENGINE *e, const char * slot) { + struct { + const char * slot; + X509 * cert; + } cbd; + cbd.slot = slot; + cbd.cert = NULL; + if (!ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &cbd, NULL, 0)) { + PyErr_SetString(_engine_err, "cannot load certificate"); + return NULL; + } + return cbd.cert; +} + + +#include + + +/* + From the manpage for OBJ_obt2txt (): + BUGS + OBJ_obj2txt() is awkward and messy to use: it doesn’t follow the + convention of other OpenSSL functions where the buffer can be set + to NULL to determine the amount of data that should be written. + Instead buf must point to a valid buffer and buf_len should be set + to a positive value. A buffer length of 80 should be more than + enough to handle any OID encountered in practice. + + The first call to OBJ_obj2txt () therefore passes a non-NULL dummy + buffer. This wart is reportedly removed in OpenSSL 0.9.8b, although + the manpage has not been updated. + + OBJ_obj2txt always prints \0 at the end. But the return value + is the number of "good" bytes written. So memory is allocated for + len + 1 bytes but only len bytes are marshalled to python. +*/ +PyObject *obj_obj2txt(const ASN1_OBJECT *obj, int no_name) +{ + int len; + PyObject *ret; + char *buf; + char dummy[1]; + + len = OBJ_obj2txt(dummy, 1, obj, no_name); + if (len < 0) { + m2_PyErr_Msg(PyExc_RuntimeError); + return NULL; + } else if (len == 0) { + /* XXX: For OpenSSL prior to 0.9.8b. + + Changes between 0.9.8a and 0.9.8b [04 May 2006] + ... + *) Several fixes and enhancements to the OID generation code. The old code + sometimes allowed invalid OIDs (1.X for X >= 40 for example), couldn't + handle numbers larger than ULONG_MAX, truncated printing and had a + non standard OBJ_obj2txt() behaviour. + [Steve Henson] + */ + + len = 80; + } + + buf = PyMem_Malloc(len + 1); + len = OBJ_obj2txt(buf, len + 1, obj, no_name); + + ret = PyBytes_FromStringAndSize(buf, len); + + PyMem_Free(buf); + + return ret; +} + +#ifdef __cplusplus +extern "C" { +#endif +SWIGINTERN PyObject *_wrap__STACK_num_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"_STACK_num_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_num_set" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "_STACK_num_set" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (arg1) (arg1)->num = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__STACK_num_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int result; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_num_get" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + result = (int) ((arg1)->num); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__STACK_data_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + char **arg2 = (char **) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"_STACK_data_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_data_set" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_p_char, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "_STACK_data_set" "', argument " "2"" of type '" "char **""'"); + } + arg2 = (char **)(argp2); + if (arg1) (arg1)->data = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__STACK_data_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + char **result = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_data_get" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + result = (char **) ((arg1)->data); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_p_char, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__STACK_sorted_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"_STACK_sorted_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_sorted_set" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "_STACK_sorted_set" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (arg1) (arg1)->sorted = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__STACK_sorted_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int result; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_sorted_get" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + result = (int) ((arg1)->sorted); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__STACK_num_alloc_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"_STACK_num_alloc_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_num_alloc_set" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "_STACK_num_alloc_set" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (arg1) (arg1)->num_alloc = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__STACK_num_alloc_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int result; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_num_alloc_get" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + result = (int) ((arg1)->num_alloc); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__STACK_comp_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + int (*arg2)(void const *,void const *) = (int (*)(void const *,void const *)) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"_STACK_comp_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_comp_set" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + { + int res = SWIG_ConvertFunctionPtr(obj1, (void**)(&arg2), SWIGTYPE_p_f_p_q_const__void_p_q_const__void__int); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "_STACK_comp_set" "', argument " "2"" of type '" "int (*)(void const *,void const *)""'"); + } + } + if (arg1) (arg1)->comp = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__STACK_comp_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int (*result)(void const *,void const *) = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_STACK_comp_get" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + result = (int (*)(void const *,void const *)) ((arg1)->comp); + resultobj = SWIG_NewFunctionPtrObj((void *)(result), SWIGTYPE_p_f_p_q_const__void_p_q_const__void__int); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int _wrap_new__STACK(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *result = 0 ; + + result = (struct stack_st *)calloc(1, sizeof(struct stack_st)); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st, SWIG_BUILTIN_INIT | 0 ); + return resultobj == Py_None ? -1 : 0; +fail: + return -1; +} + + +SWIGINTERN PyObject *_wrap_delete__STACK(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st *arg1 = (struct stack_st *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete__STACK" "', argument " "1"" of type '" "struct stack_st *""'"); + } + arg1 = (struct stack_st *)(argp1); + free((char *) arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_num(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_num",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_num" "', argument " "1"" of type '" "_STACK const *""'"); + } + arg1 = (_STACK *)(argp1); + result = (int)sk_num((struct stack_st const *)arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_value(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + void *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_value",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_value" "', argument " "1"" of type '" "_STACK const *""'"); + } + arg1 = (_STACK *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "sk_value" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (void *)sk_value((struct stack_st const *)arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + int arg2 ; + void *arg3 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int res3 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + void *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_set",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_set" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "sk_set" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3), 0, 0); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "sk_set" "', argument " "3"" of type '" "void *""'"); + } + result = (void *)sk_set(arg1,arg2,arg3); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int (*arg1)(void const *,void const *) = (int (*)(void const *,void const *)) 0 ; + PyObject * obj0 = 0 ; + _STACK *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_new",1,1,&obj0)) SWIG_fail; + { + int res = SWIG_ConvertFunctionPtr(obj0, (void**)(&arg1), SWIGTYPE_p_f_p_q_const__void_p_q_const__void__int); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "sk_new" "', argument " "1"" of type '" "int (*)(void const *,void const *)""'"); + } + } + result = (_STACK *)sk_new(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_new_null(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *result = 0 ; + + result = (_STACK *)sk_new_null(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_free" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + sk_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_pop_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void (*arg2)(void *) = (void (*)(void *)) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_pop_free",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_pop_free" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + { + int res = SWIG_ConvertFunctionPtr(obj1, (void**)(&arg2), SWIGTYPE_p_f_p_void__void); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "sk_pop_free" "', argument " "2"" of type '" "void (*)(void *)""'"); + } + } + sk_pop_free(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_deep_copy(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *(*arg2)(void *) = (void *(*)(void *)) 0 ; + void (*arg3)(void *) = (void (*)(void *)) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + _STACK *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_deep_copy",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_deep_copy" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + { + int res = SWIG_ConvertFunctionPtr(obj1, (void**)(&arg2), SWIGTYPE_p_f_p_void__p_void); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "sk_deep_copy" "', argument " "2"" of type '" "void *(*)(void *)""'"); + } + } + { + int res = SWIG_ConvertFunctionPtr(obj2, (void**)(&arg3), SWIGTYPE_p_f_p_void__void); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "sk_deep_copy" "', argument " "3"" of type '" "void (*)(void *)""'"); + } + } + result = (_STACK *)sk_deep_copy(arg1,arg2,arg3); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_insert(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *arg2 = (void *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_insert",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_insert" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sk_insert" "', argument " "2"" of type '" "void *""'"); + } + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "sk_insert" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + result = (int)sk_insert(arg1,arg2,arg3); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_delete(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + void *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_delete",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_delete" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "sk_delete" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (void *)sk_delete(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_delete_ptr(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *arg2 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + void *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_delete_ptr",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_delete_ptr" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sk_delete_ptr" "', argument " "2"" of type '" "void *""'"); + } + result = (void *)sk_delete_ptr(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_find(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *arg2 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_find",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_find" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sk_find" "', argument " "2"" of type '" "void *""'"); + } + result = (int)sk_find(arg1,arg2); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_find_ex(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *arg2 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_find_ex",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_find_ex" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sk_find_ex" "', argument " "2"" of type '" "void *""'"); + } + result = (int)sk_find_ex(arg1,arg2); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_push(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *arg2 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_push",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_push" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sk_push" "', argument " "2"" of type '" "void *""'"); + } + result = (int)sk_push(arg1,arg2); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_unshift(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *arg2 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_unshift",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_unshift" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sk_unshift" "', argument " "2"" of type '" "void *""'"); + } + result = (int)sk_unshift(arg1,arg2); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_shift(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + void *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_shift",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_shift" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + result = (void *)sk_shift(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_pop(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + void *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_pop",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_pop" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + result = (void *)sk_pop(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_zero(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_zero",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_zero" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + sk_zero(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_set_cmp_func(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + int (*arg2)(void const *,void const *) = (int (*)(void const *,void const *)) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int (*result)(void const *,void const *) = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_set_cmp_func",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_set_cmp_func" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + { + int res = SWIG_ConvertFunctionPtr(obj1, (void**)(&arg2), SWIGTYPE_p_f_p_q_const__void_p_q_const__void__int); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "sk_set_cmp_func" "', argument " "2"" of type '" "int (*)(void const *,void const *)""'"); + } + } + result = (int (*)(void const *,void const *))sk_set_cmp_func(arg1,arg2); + resultobj = SWIG_NewFunctionPtrObj((void *)(result), SWIGTYPE_p_f_p_q_const__void_p_q_const__void__int); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_dup(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + _STACK *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_dup",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_dup" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + result = (_STACK *)sk_dup(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_sort(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_sort",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_sort" "', argument " "1"" of type '" "_STACK *""'"); + } + arg1 = (_STACK *)(argp1); + sk_sort(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_is_sorted(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _STACK *arg1 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_is_sorted",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_is_sorted" "', argument " "1"" of type '" "_STACK const *""'"); + } + arg1 = (_STACK *)(argp1); + result = (int)sk_is_sorted((struct stack_st const *)arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_stack_st_OPENSSL_STRING_stack_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_OPENSSL_STRING *arg1 = (struct stack_st_OPENSSL_STRING *) 0 ; + _STACK *arg2 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"stack_st_OPENSSL_STRING_stack_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st_OPENSSL_STRING, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "stack_st_OPENSSL_STRING_stack_set" "', argument " "1"" of type '" "struct stack_st_OPENSSL_STRING *""'"); + } + arg1 = (struct stack_st_OPENSSL_STRING *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "stack_st_OPENSSL_STRING_stack_set" "', argument " "2"" of type '" "_STACK *""'"); + } + arg2 = (_STACK *)(argp2); + if (arg1) (arg1)->stack = *arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_stack_st_OPENSSL_STRING_stack_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_OPENSSL_STRING *arg1 = (struct stack_st_OPENSSL_STRING *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + _STACK *result = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st_OPENSSL_STRING, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "stack_st_OPENSSL_STRING_stack_get" "', argument " "1"" of type '" "struct stack_st_OPENSSL_STRING *""'"); + } + arg1 = (struct stack_st_OPENSSL_STRING *)(argp1); + result = (_STACK *)& ((arg1)->stack); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int _wrap_new_stack_st_OPENSSL_STRING(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_OPENSSL_STRING *result = 0 ; + + result = (struct stack_st_OPENSSL_STRING *)calloc(1, sizeof(struct stack_st_OPENSSL_STRING)); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st_OPENSSL_STRING, SWIG_BUILTIN_INIT | 0 ); + return resultobj == Py_None ? -1 : 0; +fail: + return -1; +} + + +SWIGINTERN PyObject *_wrap_delete_stack_st_OPENSSL_STRING(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_OPENSSL_STRING *arg1 = (struct stack_st_OPENSSL_STRING *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st_OPENSSL_STRING, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_stack_st_OPENSSL_STRING" "', argument " "1"" of type '" "struct stack_st_OPENSSL_STRING *""'"); + } + arg1 = (struct stack_st_OPENSSL_STRING *)(argp1); + free((char *) arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_stack_st_OPENSSL_BLOCK_stack_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_OPENSSL_BLOCK *arg1 = (struct stack_st_OPENSSL_BLOCK *) 0 ; + _STACK *arg2 = (_STACK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"stack_st_OPENSSL_BLOCK_stack_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st_OPENSSL_BLOCK, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "stack_st_OPENSSL_BLOCK_stack_set" "', argument " "1"" of type '" "struct stack_st_OPENSSL_BLOCK *""'"); + } + arg1 = (struct stack_st_OPENSSL_BLOCK *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_stack_st, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "stack_st_OPENSSL_BLOCK_stack_set" "', argument " "2"" of type '" "_STACK *""'"); + } + arg2 = (_STACK *)(argp2); + if (arg1) (arg1)->stack = *arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_stack_st_OPENSSL_BLOCK_stack_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_OPENSSL_BLOCK *arg1 = (struct stack_st_OPENSSL_BLOCK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + _STACK *result = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st_OPENSSL_BLOCK, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "stack_st_OPENSSL_BLOCK_stack_get" "', argument " "1"" of type '" "struct stack_st_OPENSSL_BLOCK *""'"); + } + arg1 = (struct stack_st_OPENSSL_BLOCK *)(argp1); + result = (_STACK *)& ((arg1)->stack); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int _wrap_new_stack_st_OPENSSL_BLOCK(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_OPENSSL_BLOCK *result = 0 ; + + result = (struct stack_st_OPENSSL_BLOCK *)calloc(1, sizeof(struct stack_st_OPENSSL_BLOCK)); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st_OPENSSL_BLOCK, SWIG_BUILTIN_INIT | 0 ); + return resultobj == Py_None ? -1 : 0; +fail: + return -1; +} + + +SWIGINTERN PyObject *_wrap_delete_stack_st_OPENSSL_BLOCK(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_OPENSSL_BLOCK *arg1 = (struct stack_st_OPENSSL_BLOCK *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_stack_st_OPENSSL_BLOCK, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_stack_st_OPENSSL_BLOCK" "', argument " "1"" of type '" "struct stack_st_OPENSSL_BLOCK *""'"); + } + arg1 = (struct stack_st_OPENSSL_BLOCK *)(argp1); + free((char *) arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_threading_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + threading_init(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_threading_cleanup(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + threading_cleanup(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_lib_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + lib_init(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bn_to_mpi(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIGNUM *arg1 = (BIGNUM *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bn_to_mpi",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIGNUM, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bn_to_mpi" "', argument " "1"" of type '" "BIGNUM const *""'"); + } + arg1 = (BIGNUM *)(argp1); + result = (PyObject *)bn_to_mpi((BIGNUM const *)arg1); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_mpi_to_bn(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + BIGNUM *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"mpi_to_bn",1,1,&obj0)) SWIG_fail; + arg1 = obj0; + result = (BIGNUM *)mpi_to_bn(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIGNUM, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bn_to_bin(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIGNUM *arg1 = (BIGNUM *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bn_to_bin",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIGNUM, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bn_to_bin" "', argument " "1"" of type '" "BIGNUM *""'"); + } + arg1 = (BIGNUM *)(argp1); + result = (PyObject *)bn_to_bin(arg1); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bin_to_bn(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + BIGNUM *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bin_to_bn",1,1,&obj0)) SWIG_fail; + arg1 = obj0; + result = (BIGNUM *)bin_to_bn(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIGNUM, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bn_to_hex(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIGNUM *arg1 = (BIGNUM *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bn_to_hex",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIGNUM, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bn_to_hex" "', argument " "1"" of type '" "BIGNUM *""'"); + } + arg1 = (BIGNUM *)(argp1); + result = (PyObject *)bn_to_hex(arg1); + resultobj = result; + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_hex_to_bn(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + BIGNUM *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"hex_to_bn",1,1,&obj0)) SWIG_fail; + arg1 = obj0; + result = (BIGNUM *)hex_to_bn(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIGNUM, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dec_to_bn(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + BIGNUM *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dec_to_bn",1,1,&obj0)) SWIG_fail; + arg1 = obj0; + result = (BIGNUM *)dec_to_bn(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIGNUM, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_err_print_errors(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"err_print_errors",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "err_print_errors" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + ERR_print_errors(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_err_get_error(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + unsigned long result; + + result = (unsigned long)ERR_get_error(); + resultobj = SWIG_From_unsigned_SS_long((unsigned long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_err_peek_error(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + unsigned long result; + + result = (unsigned long)ERR_peek_error(); + resultobj = SWIG_From_unsigned_SS_long((unsigned long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_err_lib_error_string(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + unsigned long arg1 ; + unsigned long val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"err_lib_error_string",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_unsigned_SS_long(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "err_lib_error_string" "', argument " "1"" of type '" "unsigned long""'"); + } + arg1 = (unsigned long)(val1); + result = (char *)ERR_lib_error_string(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_err_func_error_string(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + unsigned long arg1 ; + unsigned long val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"err_func_error_string",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_unsigned_SS_long(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "err_func_error_string" "', argument " "1"" of type '" "unsigned long""'"); + } + arg1 = (unsigned long)(val1); + result = (char *)ERR_func_error_string(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_err_reason_error_string(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + unsigned long arg1 ; + unsigned long val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"err_reason_error_string",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_unsigned_SS_long(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "err_reason_error_string" "', argument " "1"" of type '" "unsigned long""'"); + } + arg1 = (unsigned long)(val1); + result = (char *)ERR_reason_error_string(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_s_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO_METHOD *result = 0 ; + + result = (BIO_METHOD *)BIO_s_bio(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO_METHOD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_s_mem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO_METHOD *result = 0 ; + + result = (BIO_METHOD *)BIO_s_mem(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO_METHOD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_s_socket(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO_METHOD *result = 0 ; + + result = (BIO_METHOD *)BIO_s_socket(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO_METHOD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_f_ssl(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO_METHOD *result = 0 ; + + result = (BIO_METHOD *)BIO_f_ssl(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO_METHOD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_f_buffer(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO_METHOD *result = 0 ; + + result = (BIO_METHOD *)BIO_f_buffer(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO_METHOD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_f_cipher(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO_METHOD *result = 0 ; + + result = (BIO_METHOD *)BIO_f_cipher(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO_METHOD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO_METHOD *arg1 = (BIO_METHOD *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + BIO *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_new",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO_METHOD, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_new" "', argument " "1"" of type '" "BIO_METHOD *""'"); + } + arg1 = (BIO_METHOD *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (BIO *)BIO_new(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_new_socket(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int arg2 ; + int val1 ; + int ecode1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + BIO *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_new_socket",2,2,&obj0,&obj1)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "bio_new_socket" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_new_socket" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (BIO *)BIO_new_socket(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_free_all(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_free_all",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_free_all" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + BIO_free_all(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_dup_chain(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + BIO *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_dup_chain",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_dup_chain" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (BIO *)BIO_dup_chain(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_push(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + BIO *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_push",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_push" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "bio_push" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (BIO *)BIO_push(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_pop(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + BIO *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_pop",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_pop" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (BIO *)BIO_pop(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_eof(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_eof",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_eof" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)BIO_eof(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__bio_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_bio_err""' of type '""PyObject *""'"); + } + _bio_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__bio_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_bio_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_pyfd_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + pyfd_init(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + bio_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_free" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_free(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_new_file(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + char *arg2 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + BIO *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_new_file",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_new_file" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "bio_new_file" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = (BIO *)bio_new_file((char const *)arg1,(char const *)arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO, 0 | 0 ); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_new_pyfile(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + int arg2 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + BIO *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_new_pyfile",2,2,&obj0,&obj1)) SWIG_fail; + { + arg1=obj0; + } + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_new_pyfile" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (BIO *)bio_new_pyfile(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_read(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_read",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_read" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_read" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)bio_read(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_gets(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_gets",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_gets" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_gets" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)bio_gets(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_write(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_write",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_write" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_write(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_ctrl_pending(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_ctrl_pending",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_ctrl_pending" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_ctrl_pending(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_ctrl_wpending(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_ctrl_wpending",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_ctrl_wpending" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_ctrl_wpending(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_ctrl_get_write_guarantee(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_ctrl_get_write_guarantee",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_ctrl_get_write_guarantee" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_ctrl_get_write_guarantee(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_reset(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_reset",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_reset" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_reset(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_flush(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_flush",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_flush" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)bio_flush(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_seek(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_seek",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_seek" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_seek" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_seek(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_tell(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_tell",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_tell" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_tell(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_set_flags(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_set_flags",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_set_flags" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_set_flags" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + bio_set_flags(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_get_flags(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_get_flags",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_get_flags" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_get_flags(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_set_cipher(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + EVP_CIPHER *arg2 = (EVP_CIPHER *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + int arg5 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val5 ; + int ecode5 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_set_cipher",5,5,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_set_cipher" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "bio_set_cipher" "', argument " "2"" of type '" "EVP_CIPHER *""'"); + } + arg2 = (EVP_CIPHER *)(argp2); + { + arg3=obj2; + } + { + arg4=obj3; + } + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "bio_set_cipher" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)bio_set_cipher(arg1,arg2,arg3,arg4,arg5); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_set_mem_eof_return(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_set_mem_eof_return",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_set_mem_eof_return" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_set_mem_eof_return" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_set_mem_eof_return(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_get_fd(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_get_fd",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_get_fd" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_get_fd(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_do_handshake(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_do_handshake",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_do_handshake" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)bio_do_handshake(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_make_bio_pair(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_make_bio_pair",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_make_bio_pair" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "bio_make_bio_pair" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_make_bio_pair(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_set_write_buf_size(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + size_t arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + size_t val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_set_write_buf_size",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_set_write_buf_size" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + ecode2 = SWIG_AsVal_size_t(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_set_write_buf_size" "', argument " "2"" of type '" "size_t""'"); + } + arg2 = (size_t)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_set_write_buf_size(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_should_retry(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_should_retry",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_should_retry" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_should_retry(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_should_read(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_should_read",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_should_read" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_should_read(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_should_write(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_should_write",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_should_write" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_should_write(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_BIO_meth_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + char *arg2 = (char *) 0 ; + int val1 ; + int ecode1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + BIO_METHOD *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"BIO_meth_new",2,2,&obj0,&obj1)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "BIO_meth_new" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "BIO_meth_new" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = (BIO_METHOD *)BIO_meth_new(arg1,(char const *)arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO_METHOD, 0 | 0 ); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_BIO_meth_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO_METHOD *arg1 = (BIO_METHOD *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"BIO_meth_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO_METHOD, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "BIO_meth_free" "', argument " "1"" of type '" "BIO_METHOD *""'"); + } + arg1 = (BIO_METHOD *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + BIO_meth_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_BIO_PYFD_CTX_fd_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct pyfd_struct *arg1 = (struct pyfd_struct *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"BIO_PYFD_CTX_fd_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_pyfd_struct, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "BIO_PYFD_CTX_fd_set" "', argument " "1"" of type '" "struct pyfd_struct *""'"); + } + arg1 = (struct pyfd_struct *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "BIO_PYFD_CTX_fd_set" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (arg1) (arg1)->fd = arg2; + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_BIO_PYFD_CTX_fd_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct pyfd_struct *arg1 = (struct pyfd_struct *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int result; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_pyfd_struct, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "BIO_PYFD_CTX_fd_get" "', argument " "1"" of type '" "struct pyfd_struct *""'"); + } + arg1 = (struct pyfd_struct *)(argp1); + result = (int) ((arg1)->fd); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int _wrap_new_BIO_PYFD_CTX(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct pyfd_struct *result = 0 ; + + result = (struct pyfd_struct *)calloc(1, sizeof(struct pyfd_struct)); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_pyfd_struct, SWIG_BUILTIN_INIT | 0 ); + return resultobj == Py_None ? -1 : 0; +fail: + return -1; +} + + +SWIGINTERN PyObject *_wrap_delete_BIO_PYFD_CTX(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct pyfd_struct *arg1 = (struct pyfd_struct *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_pyfd_struct, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_BIO_PYFD_CTX" "', argument " "1"" of type '" "struct pyfd_struct *""'"); + } + arg1 = (struct pyfd_struct *)(argp1); + free((char *) arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var_methods_fdp_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_BIO_METHOD, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""methods_fdp""' of type '""BIO_METHOD *""'"); + } + methods_fdp = (BIO_METHOD *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var_methods_fdp_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(methods_fdp), SWIGTYPE_p_BIO_METHOD, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_pyfd_write(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + char *arg2 = (char *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pyfd_write",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pyfd_write" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pyfd_write" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "pyfd_write" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pyfd_write(arg1,(char const *)arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pyfd_read(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + char *arg2 = (char *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pyfd_read",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pyfd_read" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pyfd_read" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "pyfd_read" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pyfd_read(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pyfd_puts(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pyfd_puts",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pyfd_puts" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pyfd_puts" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pyfd_puts(arg1,(char const *)arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pyfd_gets(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + char *arg2 = (char *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pyfd_gets",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pyfd_gets" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pyfd_gets" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "pyfd_gets" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pyfd_gets(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pyfd_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pyfd_new",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pyfd_new" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pyfd_new(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pyfd_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pyfd_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pyfd_free" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pyfd_free(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pyfd_ctrl(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + int arg2 ; + long arg3 ; + void *arg4 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + long val3 ; + int ecode3 = 0 ; + int res4 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"pyfd_ctrl",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pyfd_ctrl" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "pyfd_ctrl" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + ecode3 = SWIG_AsVal_long(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "pyfd_ctrl" "', argument " "3"" of type '" "long""'"); + } + arg3 = (long)(val3); + res4 = SWIG_ConvertPtr(obj3,SWIG_as_voidptrptr(&arg4), 0, 0); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "pyfd_ctrl" "', argument " "4"" of type '" "void *""'"); + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)pyfd_ctrl(arg1,arg2,arg3,arg4); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_new_pyfd(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int arg2 ; + int val1 ; + int ecode1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + BIO *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_new_pyfd",2,2,&obj0,&obj1)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "bio_new_pyfd" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_new_pyfd" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (BIO *)BIO_new_pyfd(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bn_rand(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int arg2 ; + int arg3 ; + int val1 ; + int ecode1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bn_rand",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "bn_rand" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bn_rand" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "bn_rand" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + result = (PyObject *)bn_rand(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bn_rand_range(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bn_rand_range",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + result = (PyObject *)bn_rand_range(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_file_name__SWIG_0(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + size_t arg2 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + size_t val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rand_file_name",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rand_file_name" "', argument " "1"" of type '" "char *""'"); + } + arg1 = (char *)(buf1); + ecode2 = SWIG_AsVal_size_t(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "rand_file_name" "', argument " "2"" of type '" "size_t""'"); + } + arg2 = (size_t)(val2); + result = (char *)RAND_file_name(arg1,arg2); + resultobj = SWIG_FromCharPtr((const char *)result); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_load_file(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + long arg2 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rand_load_file",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rand_load_file" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "rand_load_file" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + result = (int)RAND_load_file((char const *)arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_save_file(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rand_save_file",1,1,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rand_save_file" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + result = (int)RAND_write_file((char const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_poll(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int result; + + result = (int)RAND_poll(); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_status(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int result; + + result = (int)RAND_status(); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_cleanup(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + RAND_cleanup(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__rand_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_rand_err""' of type '""PyObject *""'"); + } + _rand_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__rand_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_rand_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_rand_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rand_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + rand_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_seed(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rand_seed",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + result = (PyObject *)rand_seed(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_add(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + double arg2 ; + double val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rand_add",2,2,&obj0,&obj1)) SWIG_fail; + { + arg1=obj0; + } + ecode2 = SWIG_AsVal_double(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "rand_add" "', argument " "2"" of type '" "double""'"); + } + arg2 = (double)(val2); + result = (PyObject *)rand_add(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_bytes(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rand_bytes",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "rand_bytes" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (PyObject *)rand_bytes(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_pseudo_bytes(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rand_pseudo_bytes",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "rand_pseudo_bytes" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (PyObject *)rand_pseudo_bytes(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_file_name__SWIG_1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *result = 0 ; + + result = (PyObject *)rand_file_name(); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_file_name(PyObject *self, PyObject *args) { + int argc; + PyObject *argv[3]; + int ii; + + if (!PyTuple_Check(args)) SWIG_fail; + argc = args ? (int)PyObject_Length(args) : 0; + for (ii = 0; (ii < 2) && (ii < argc); ii++) { + argv[ii] = PyTuple_GET_ITEM(args,ii); + } + if (argc == 0) { + return _wrap_rand_file_name__SWIG_1(self, args); + } + if (argc == 2) { + int _v; + int res = SWIG_AsCharPtrAndSize(argv[0], 0, NULL, 0); + _v = SWIG_CheckState(res); + if (_v) { + { + int res = SWIG_AsVal_size_t(argv[1], NULL); + _v = SWIG_CheckState(res); + } + if (_v) { + return _wrap_rand_file_name__SWIG_0(self, args); + } + } + } + +fail: + SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number or type of arguments for overloaded function 'rand_file_name'.\n" + " Possible C/C++ prototypes are:\n" + " RAND_file_name(char *,size_t)\n" + " rand_file_name()\n"); + return 0; +} + + +SWIGINTERN PyObject *_wrap_rand_screen(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + rand_screen(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rand_win32_event(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + unsigned int arg1 ; + int arg2 ; + long arg3 ; + unsigned int val1 ; + int ecode1 = 0 ; + int val2 ; + int ecode2 = 0 ; + long val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rand_win32_event",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + ecode1 = SWIG_AsVal_unsigned_SS_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "rand_win32_event" "', argument " "1"" of type '" "unsigned int""'"); + } + arg1 = (unsigned int)(val1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "rand_win32_event" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + ecode3 = SWIG_AsVal_long(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "rand_win32_event" "', argument " "3"" of type '" "long""'"); + } + arg3 = (long)(val3); + result = (int)rand_win32_event(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_md5(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD *result = 0 ; + + result = (EVP_MD *)EVP_md5(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_MD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sha1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD *result = 0 ; + + result = (EVP_MD *)EVP_sha1(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_MD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ripemd160(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD *result = 0 ; + + result = (EVP_MD *)EVP_ripemd160(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_MD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sha224(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD *result = 0 ; + + result = (EVP_MD *)EVP_sha224(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_MD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sha256(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD *result = 0 ; + + result = (EVP_MD *)EVP_sha256(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_MD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sha384(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD *result = 0 ; + + result = (EVP_MD *)EVP_sha384(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_MD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sha512(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD *result = 0 ; + + result = (EVP_MD *)EVP_sha512(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_MD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_digest_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + EVP_MD *arg2 = (EVP_MD *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"digest_init",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "digest_init" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "digest_init" "', argument " "2"" of type '" "EVP_MD const *""'"); + } + arg2 = (EVP_MD *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EVP_DigestInit(arg1,(EVP_MD const *)arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ecb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ecb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ede_ecb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ede(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ede3_ecb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ede3(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_cbc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_cbc(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ede_cbc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ede_cbc(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ede3_cbc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ede3_cbc(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_cfb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_cfb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ede_cfb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ede_cfb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ede3_cfb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ede3_cfb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ofb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ofb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ede_ofb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ede_ofb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_des_ede3_ofb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_des_ede3_ofb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bf_ecb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_bf_ecb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bf_cbc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_bf_cbc(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bf_cfb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_bf_cfb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bf_ofb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_bf_ofb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cast5_ecb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_cast5_ecb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cast5_cbc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_cast5_cbc(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cast5_cfb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_cast5_cfb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cast5_ofb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_cast5_ofb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rc4(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_rc4(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rc2_40_cbc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_rc2_40_cbc(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_128_ecb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_128_ecb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_128_cbc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_128_cbc(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_128_cfb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_128_cfb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_128_ofb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_128_ofb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_128_ctr(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_128_ctr(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_192_ecb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_192_ecb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_192_cbc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_192_cbc(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_192_cfb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_192_cfb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_192_ofb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_192_ofb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_192_ctr(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_192_ctr(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_256_ecb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_256_ecb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_256_cbc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_256_cbc(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_256_cfb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_256_cfb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_256_ofb(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_256_ofb(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_256_ctr(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *result = 0 ; + + result = (EVP_CIPHER *)EVP_aes_256_ctr(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cipher_set_padding(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER_CTX *arg1 = (EVP_CIPHER_CTX *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"cipher_set_padding",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_CIPHER_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "cipher_set_padding" "', argument " "1"" of type '" "EVP_CIPHER_CTX *""'"); + } + arg1 = (EVP_CIPHER_CTX *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "cipher_set_padding" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EVP_CIPHER_CTX_set_padding(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_free" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + EVP_PKEY_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_assign(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + int arg2 ; + char *arg3 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_assign",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_assign" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "pkey_assign" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "pkey_assign" "', argument " "3"" of type '" "char *""'"); + } + arg3 = (char *)(buf3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EVP_PKEY_assign(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_assign_ec(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + EC_KEY *arg2 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_assign_ec",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_assign_ec" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkey_assign_ec" "', argument " "2"" of type '" "EC_KEY *""'"); + } + arg2 = (EC_KEY *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EVP_PKEY_assign_EC_KEY(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_set1_rsa(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + RSA *arg2 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_set1_rsa",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_set1_rsa" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkey_set1_rsa" "', argument " "2"" of type '" "RSA *""'"); + } + arg2 = (RSA *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EVP_PKEY_set1_RSA(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sign_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + EVP_MD *arg2 = (EVP_MD *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sign_init",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sign_init" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sign_init" "', argument " "2"" of type '" "EVP_MD const *""'"); + } + arg2 = (EVP_MD *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EVP_SignInit(arg1,(EVP_MD const *)arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_verify_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + EVP_MD *arg2 = (EVP_MD *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"verify_init",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "verify_init" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "verify_init" "', argument " "2"" of type '" "EVP_MD const *""'"); + } + arg2 = (EVP_MD *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EVP_VerifyInit(arg1,(EVP_MD const *)arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_size(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_size",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_size" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EVP_PKEY_size(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__evp_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_evp_err""' of type '""PyObject *""'"); + } + _evp_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__evp_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_evp_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_evp_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"evp_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + evp_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_get1_rsa(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + RSA *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_get1_rsa",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_get1_rsa" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (RSA *)pkey_get1_rsa(arg1); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_RSA, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs5_pbkdf2_hmac_sha1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + int arg3 ; + int arg4 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs5_pbkdf2_hmac_sha1",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + { + arg1=obj0; + } + { + arg2=obj1; + } + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "pkcs5_pbkdf2_hmac_sha1" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "pkcs5_pbkdf2_hmac_sha1" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + result = (PyObject *)pkcs5_pbkdf2_hmac_sha1(arg1,arg2,arg3,arg4); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_md_ctx_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *result = 0 ; + + result = (EVP_MD_CTX *)md_ctx_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_md_ctx_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"md_ctx_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "md_ctx_free" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + md_ctx_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_digest_update(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"digest_update",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "digest_update" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)digest_update(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_digest_final(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"digest_final",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "digest_final" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)digest_final(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_hmac_ctx_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + HMAC_CTX *result = 0 ; + + result = (HMAC_CTX *)hmac_ctx_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_HMAC_CTX, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_hmac_ctx_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + HMAC_CTX *arg1 = (HMAC_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"hmac_ctx_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_HMAC_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "hmac_ctx_free" "', argument " "1"" of type '" "HMAC_CTX *""'"); + } + arg1 = (HMAC_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + hmac_ctx_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_hmac_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + HMAC_CTX *arg1 = (HMAC_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + EVP_MD *arg3 = (EVP_MD *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"hmac_init",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_HMAC_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "hmac_init" "', argument " "1"" of type '" "HMAC_CTX *""'"); + } + arg1 = (HMAC_CTX *)(argp1); + { + arg2=obj1; + } + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "hmac_init" "', argument " "3"" of type '" "EVP_MD const *""'"); + } + arg3 = (EVP_MD *)(argp3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)hmac_init(arg1,arg2,(EVP_MD const *)arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_hmac_update(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + HMAC_CTX *arg1 = (HMAC_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"hmac_update",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_HMAC_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "hmac_update" "', argument " "1"" of type '" "HMAC_CTX *""'"); + } + arg1 = (HMAC_CTX *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)hmac_update(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_hmac_final(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + HMAC_CTX *arg1 = (HMAC_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"hmac_final",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_HMAC_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "hmac_final" "', argument " "1"" of type '" "HMAC_CTX *""'"); + } + arg1 = (HMAC_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)hmac_final(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_hmac(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + EVP_MD *arg3 = (EVP_MD *) 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"hmac",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + { + arg1=obj0; + } + { + arg2=obj1; + } + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "hmac" "', argument " "3"" of type '" "EVP_MD const *""'"); + } + arg3 = (EVP_MD *)(argp3); + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)hmac(arg1,arg2,(EVP_MD const *)arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cipher_ctx_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER_CTX *result = 0 ; + + result = (EVP_CIPHER_CTX *)cipher_ctx_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_CIPHER_CTX, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cipher_ctx_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER_CTX *arg1 = (EVP_CIPHER_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"cipher_ctx_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_CIPHER_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "cipher_ctx_free" "', argument " "1"" of type '" "EVP_CIPHER_CTX *""'"); + } + arg1 = (EVP_CIPHER_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + cipher_ctx_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bytes_to_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER *arg1 = (EVP_CIPHER *) 0 ; + EVP_MD *arg2 = (EVP_MD *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + PyObject *arg5 = (PyObject *) 0 ; + int arg6 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val6 ; + int ecode6 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PyObject * obj5 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bytes_to_key",6,6,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bytes_to_key" "', argument " "1"" of type '" "EVP_CIPHER const *""'"); + } + arg1 = (EVP_CIPHER *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "bytes_to_key" "', argument " "2"" of type '" "EVP_MD *""'"); + } + arg2 = (EVP_MD *)(argp2); + { + arg3=obj2; + } + { + arg4=obj3; + } + { + arg5=obj4; + } + ecode6 = SWIG_AsVal_int(obj5, &val6); + if (!SWIG_IsOK(ecode6)) { + SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "bytes_to_key" "', argument " "6"" of type '" "int""'"); + } + arg6 = (int)(val6); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)bytes_to_key((EVP_CIPHER const *)arg1,arg2,arg3,arg4,arg5,arg6); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cipher_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER_CTX *arg1 = (EVP_CIPHER_CTX *) 0 ; + EVP_CIPHER *arg2 = (EVP_CIPHER *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + int arg5 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val5 ; + int ecode5 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"cipher_init",5,5,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_CIPHER_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "cipher_init" "', argument " "1"" of type '" "EVP_CIPHER_CTX *""'"); + } + arg1 = (EVP_CIPHER_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "cipher_init" "', argument " "2"" of type '" "EVP_CIPHER const *""'"); + } + arg2 = (EVP_CIPHER *)(argp2); + { + arg3=obj2; + } + { + arg4=obj3; + } + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "cipher_init" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)cipher_init(arg1,(EVP_CIPHER const *)arg2,arg3,arg4,arg5); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cipher_update(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER_CTX *arg1 = (EVP_CIPHER_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"cipher_update",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_CIPHER_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "cipher_update" "', argument " "1"" of type '" "EVP_CIPHER_CTX *""'"); + } + arg1 = (EVP_CIPHER_CTX *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)cipher_update(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_cipher_final(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_CIPHER_CTX *arg1 = (EVP_CIPHER_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"cipher_final",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_CIPHER_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "cipher_final" "', argument " "1"" of type '" "EVP_CIPHER_CTX *""'"); + } + arg1 = (EVP_CIPHER_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)cipher_final(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sign_update(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sign_update",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sign_update" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)sign_update(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sign_final(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sign_final",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sign_final" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sign_final" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)sign_final(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_verify_update(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"verify_update",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "verify_update" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)verify_update(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_verify_final(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_MD_CTX *arg1 = (EVP_MD_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + EVP_PKEY *arg3 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"verify_final",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_MD_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "verify_final" "', argument " "1"" of type '" "EVP_MD_CTX *""'"); + } + arg1 = (EVP_MD_CTX *)(argp1); + { + arg2=obj1; + } + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "verify_final" "', argument " "3"" of type '" "EVP_PKEY *""'"); + } + arg3 = (EVP_PKEY *)(argp3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)verify_final(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_get_digestbyname(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + EVP_MD *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"get_digestbyname",1,1,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "get_digestbyname" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + result = (EVP_MD *)get_digestbyname((char const *)arg1); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_EVP_MD, 0); + else { + resultobj = NULL; + } + } + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_write_pem_no_cipher(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + BIO *arg2 = (BIO *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_write_pem_no_cipher",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_write_pem_no_cipher" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkey_write_pem_no_cipher" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!PyCallable_Check(obj2)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pkey_write_pem_no_cipher(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_write_pem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + BIO *arg2 = (BIO *) 0 ; + EVP_CIPHER *arg3 = (EVP_CIPHER *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_write_pem",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_write_pem" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkey_write_pem" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "pkey_write_pem" "', argument " "3"" of type '" "EVP_CIPHER *""'"); + } + arg3 = (EVP_CIPHER *)(argp3); + { + if (!PyCallable_Check(obj3)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg4=obj3; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pkey_write_pem(arg1,arg2,arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *result = 0 ; + + result = (EVP_PKEY *)pkey_new(); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_EVP_PKEY, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_read_pem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + EVP_PKEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_read_pem",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_read_pem" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (EVP_PKEY *)pkey_read_pem(arg1,arg2); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_EVP_PKEY, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_read_pem_pubkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + EVP_PKEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_read_pem_pubkey",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_read_pem_pubkey" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (EVP_PKEY *)pkey_read_pem_pubkey(arg1,arg2); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_EVP_PKEY, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_assign_rsa(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + RSA *arg2 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_assign_rsa",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_assign_rsa" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkey_assign_rsa" "', argument " "2"" of type '" "RSA *""'"); + } + arg2 = (RSA *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pkey_assign_rsa(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_as_der(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_as_der",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_as_der" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)pkey_as_der(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkey_get_modulus(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EVP_PKEY *arg1 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkey_get_modulus",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkey_get_modulus" "', argument " "1"" of type '" "EVP_PKEY *""'"); + } + arg1 = (EVP_PKEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)pkey_get_modulus(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_aes_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + AES_KEY *result = 0 ; + + result = (AES_KEY *)aes_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_AES_KEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_AES_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + AES_KEY *arg1 = (AES_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"AES_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_AES_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AES_free" "', argument " "1"" of type '" "AES_KEY *""'"); + } + arg1 = (AES_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + AES_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_AES_set_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + AES_KEY *arg1 = (AES_KEY *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + int arg3 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"AES_set_key",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_AES_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AES_set_key" "', argument " "1"" of type '" "AES_KEY *""'"); + } + arg1 = (AES_KEY *)(argp1); + { + arg2=obj1; + } + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "AES_set_key" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "AES_set_key" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)AES_set_key(arg1,arg2,arg3,arg4); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_AES_crypt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + AES_KEY *arg1 = (AES_KEY *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + int arg3 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"AES_crypt",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_AES_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AES_crypt" "', argument " "1"" of type '" "AES_KEY const *""'"); + } + arg1 = (AES_KEY *)(argp1); + { + arg2=obj1; + } + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "AES_crypt" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "AES_crypt" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)AES_crypt((AES_KEY const *)arg1,arg2,arg3,arg4); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_AES_type_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + AES_KEY *arg1 = (AES_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"AES_type_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_AES_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AES_type_check" "', argument " "1"" of type '" "AES_KEY *""'"); + } + arg1 = (AES_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)AES_type_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rc4_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RC4_KEY *result = 0 ; + + result = (RC4_KEY *)rc4_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_RC4_KEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rc4_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RC4_KEY *arg1 = (RC4_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rc4_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RC4_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rc4_free" "', argument " "1"" of type '" "RC4_KEY *""'"); + } + arg1 = (RC4_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + rc4_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rc4_set_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RC4_KEY *arg1 = (RC4_KEY *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rc4_set_key",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RC4_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rc4_set_key" "', argument " "1"" of type '" "RC4_KEY *""'"); + } + arg1 = (RC4_KEY *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rc4_set_key(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rc4_update(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RC4_KEY *arg1 = (RC4_KEY *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rc4_update",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RC4_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rc4_update" "', argument " "1"" of type '" "RC4_KEY *""'"); + } + arg1 = (RC4_KEY *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rc4_update(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rc4_type_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RC4_KEY *arg1 = (RC4_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rc4_type_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RC4_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rc4_type_check" "', argument " "1"" of type '" "RC4_KEY *""'"); + } + arg1 = (RC4_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)rc4_type_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *result = 0 ; + + result = (DH *)DH_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_DH, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_free" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + DH_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_size(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dh_size",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_size" "', argument " "1"" of type '" "DH const *""'"); + } + arg1 = (DH *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)DH_size((DH const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_generate_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dh_generate_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_generate_key" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)DH_generate_key(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dhparams_print(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + DH *arg2 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dhparams_print",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dhparams_print" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dhparams_print" "', argument " "2"" of type '" "DH const *""'"); + } + arg2 = (DH *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)DHparams_print(arg1,(DH const *)arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__dh_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_dh_err""' of type '""PyObject *""'"); + } + _dh_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__dh_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_dh_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_dh_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + dh_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_type_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dh_type_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_type_check" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dh_type_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_read_parameters(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + DH *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_read_parameters",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_read_parameters" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (DH *)dh_read_parameters(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_DH, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_generate_parameters(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int arg2 ; + PyObject *arg3 = (PyObject *) 0 ; + int val1 ; + int ecode1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + DH *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_generate_parameters",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "dh_generate_parameters" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "dh_generate_parameters" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!PyCallable_Check(obj2)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg3=obj2; + } + result = (DH *)dh_generate_parameters(arg1,arg2,arg3); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_DH, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dh_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_check" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dh_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_compute_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_compute_key",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_compute_key" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dh_compute_key(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_get_p(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_get_p",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_get_p" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dh_get_p(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_get_g(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_get_g",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_get_g" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dh_get_g(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_get_pub(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_get_pub",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_get_pub" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dh_get_pub(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_get_priv(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_get_priv",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_get_priv" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dh_get_priv(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dh_set_pg(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DH *arg1 = (DH *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dh_set_pg",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dh_set_pg" "', argument " "1"" of type '" "DH *""'"); + } + arg1 = (DH *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dh_set_pg(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_size(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_size",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_size" "', argument " "1"" of type '" "RSA const *""'"); + } + arg1 = (RSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)RSA_size((RSA const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *result = 0 ; + + result = (RSA *)RSA_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_RSA, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_free" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + RSA_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_check_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_check_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_check_key" "', argument " "1"" of type '" "RSA const *""'"); + } + arg1 = (RSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)RSA_check_key((RSA const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__rsa_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_rsa_err""' of type '""PyObject *""'"); + } + _rsa_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__rsa_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_rsa_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_rsa_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + rsa_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_read_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + RSA *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_read_key",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_read_key" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (RSA *)rsa_read_key(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_RSA, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_write_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + BIO *arg2 = (BIO *) 0 ; + EVP_CIPHER *arg3 = (EVP_CIPHER *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_write_key",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_write_key" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "rsa_write_key" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "rsa_write_key" "', argument " "3"" of type '" "EVP_CIPHER *""'"); + } + arg3 = (EVP_CIPHER *)(argp3); + { + if (!PyCallable_Check(obj3)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg4=obj3; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg4) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)rsa_write_key(arg1,arg2,arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_write_key_no_cipher(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + BIO *arg2 = (BIO *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_write_key_no_cipher",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_write_key_no_cipher" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "rsa_write_key_no_cipher" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!PyCallable_Check(obj2)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)rsa_write_key_no_cipher(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_read_pub_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + RSA *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_read_pub_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_read_pub_key" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (RSA *)rsa_read_pub_key(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_RSA, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_write_pub_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_write_pub_key",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_write_pub_key" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "rsa_write_pub_key" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)rsa_write_pub_key(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_get_e(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_get_e",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_get_e" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_get_e(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_get_n(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_get_n",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_get_n" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_get_n(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_set_e(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_set_e",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_set_e" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_set_e(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_set_n(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_set_n",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_set_n" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_set_n(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_set_en(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_set_en",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_set_en" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_set_en(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_PyObject_Bin_AsBIGNUM(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + BIGNUM *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"PyObject_Bin_AsBIGNUM",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + result = (BIGNUM *)PyObject_Bin_AsBIGNUM(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIGNUM, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_set_en_bin(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_set_en_bin",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_set_en_bin" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_set_en_bin(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_private_encrypt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_private_encrypt",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_private_encrypt" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "rsa_private_encrypt" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_private_encrypt(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_public_decrypt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_public_decrypt",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_public_decrypt" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "rsa_public_decrypt" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_public_decrypt(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_public_encrypt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_public_encrypt",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_public_encrypt" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "rsa_public_encrypt" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_public_encrypt(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_private_decrypt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_private_decrypt",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_private_decrypt" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "rsa_private_decrypt" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_private_decrypt(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_padding_add_pkcs1_pss(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + EVP_MD *arg3 = (EVP_MD *) 0 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_padding_add_pkcs1_pss",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_padding_add_pkcs1_pss" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "rsa_padding_add_pkcs1_pss" "', argument " "3"" of type '" "EVP_MD *""'"); + } + arg3 = (EVP_MD *)(argp3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "rsa_padding_add_pkcs1_pss" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_padding_add_pkcs1_pss(arg1,arg2,arg3,arg4); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_verify_pkcs1_pss(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + EVP_MD *arg4 = (EVP_MD *) 0 ; + int arg5 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + int val5 ; + int ecode5 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_verify_pkcs1_pss",5,5,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_verify_pkcs1_pss" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + res4 = SWIG_ConvertPtr(obj3, &argp4,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "rsa_verify_pkcs1_pss" "', argument " "4"" of type '" "EVP_MD *""'"); + } + arg4 = (EVP_MD *)(argp4); + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "rsa_verify_pkcs1_pss" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg4) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)rsa_verify_pkcs1_pss(arg1,arg2,arg3,arg4,arg5); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_sign(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_sign",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_sign" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "rsa_sign" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_sign(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_verify(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_verify",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_verify" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "rsa_verify" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)rsa_verify(arg1,arg2,arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_generate_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + unsigned long arg2 ; + PyObject *arg3 = (PyObject *) 0 ; + int val1 ; + int ecode1 = 0 ; + unsigned long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_generate_key",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "rsa_generate_key" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + ecode2 = SWIG_AsVal_unsigned_SS_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "rsa_generate_key" "', argument " "2"" of type '" "unsigned long""'"); + } + arg2 = (unsigned long)(val2); + { + if (!PyCallable_Check(obj2)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg3=obj2; + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)rsa_generate_key(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_type_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_type_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_type_check" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)rsa_type_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_check_pub_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_check_pub_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_check_pub_key" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)rsa_check_pub_key(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_rsa_write_key_der(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + RSA *arg1 = (RSA *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"rsa_write_key_der",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "rsa_write_key_der" "', argument " "1"" of type '" "RSA *""'"); + } + arg1 = (RSA *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "rsa_write_key_der" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)rsa_write_key_der(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *result = 0 ; + + result = (DSA *)DSA_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_DSA, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_free" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + DSA_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_size(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_size",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_size" "', argument " "1"" of type '" "DSA const *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)DSA_size((DSA const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_gen_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_gen_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_gen_key" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)DSA_generate_key(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__dsa_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_dsa_err""' of type '""PyObject *""'"); + } + _dsa_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__dsa_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_dsa_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_dsa_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + dsa_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_generate_parameters(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + PyObject *arg2 = (PyObject *) 0 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + DSA *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_generate_parameters",2,2,&obj0,&obj1)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "dsa_generate_parameters" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (DSA *)dsa_generate_parameters(arg1,arg2); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_DSA, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_read_params(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + DSA *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_read_params",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_read_params" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (DSA *)dsa_read_params(arg1,arg2); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_DSA, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_read_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + DSA *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_read_key",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_read_key" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (DSA *)dsa_read_key(arg1,arg2); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_DSA, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_read_pub_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + DSA *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_read_pub_key",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_read_pub_key" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (DSA *)dsa_read_pub_key(arg1,arg2); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_DSA, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_get_p(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_get_p",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_get_p" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dsa_get_p(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_get_q(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_get_q",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_get_q" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dsa_get_q(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_get_g(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_get_g",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_get_g" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dsa_get_g(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_get_pub(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_get_pub",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_get_pub" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dsa_get_pub(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_get_priv(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_get_priv",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_get_priv" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dsa_get_priv(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_set_pqg(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_set_pqg",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_set_pqg" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + { + arg4=obj3; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dsa_set_pqg(arg1,arg2,arg3,arg4); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_set_pub(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_set_pub",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_set_pub" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dsa_set_pub(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_write_params_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_write_params_bio",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_write_params_bio" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dsa_write_params_bio" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)dsa_write_params_bio(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_write_key_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + BIO *arg2 = (BIO *) 0 ; + EVP_CIPHER *arg3 = (EVP_CIPHER *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_write_key_bio",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_write_key_bio" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dsa_write_key_bio" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "dsa_write_key_bio" "', argument " "3"" of type '" "EVP_CIPHER *""'"); + } + arg3 = (EVP_CIPHER *)(argp3); + { + if (!PyCallable_Check(obj3)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg4=obj3; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg4) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dsa_write_key_bio(arg1,arg2,arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_write_key_bio_no_cipher(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + BIO *arg2 = (BIO *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_write_key_bio_no_cipher",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_write_key_bio_no_cipher" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dsa_write_key_bio_no_cipher" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!PyCallable_Check(obj2)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dsa_write_key_bio_no_cipher(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_write_pub_key_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_write_pub_key_bio",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_write_pub_key_bio" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dsa_write_pub_key_bio" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)dsa_write_pub_key_bio(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_sign(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_sign",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_sign" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dsa_sign(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_verify(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_verify",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_verify" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + { + arg4=obj3; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dsa_verify(arg1,arg2,arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_sign_asn1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_sign_asn1",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_sign_asn1" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)dsa_sign_asn1(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_verify_asn1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_verify_asn1",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_verify_asn1" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dsa_verify_asn1(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_check_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_check_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_check_key" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dsa_check_key(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_check_pub_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_check_pub_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_check_pub_key" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dsa_check_pub_key(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_keylen(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_keylen",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_keylen" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dsa_keylen(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsa_type_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + DSA *arg1 = (DSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"dsa_type_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_DSA, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsa_type_check" "', argument " "1"" of type '" "DSA *""'"); + } + arg1 = (DSA *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)dsa_type_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_ciphers(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + struct stack_st_SSL_CIPHER *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_ciphers",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_ciphers" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (struct stack_st_SSL_CIPHER *)SSL_get_ciphers((SSL const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st_SSL_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_version(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_version",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_version" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)SSL_get_version((SSL const *)arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_error(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_error",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_error" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_get_error" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_get_error((SSL const *)arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_state(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_state",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_state" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)SSL_state_string((SSL const *)arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_state_v(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_state_v",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_state_v" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)SSL_state_string_long((SSL const *)arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_alert_type(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_alert_type",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ssl_get_alert_type" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (char *)SSL_alert_type_string(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_alert_type_v(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_alert_type_v",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ssl_get_alert_type_v" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (char *)SSL_alert_type_string_long(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_alert_desc(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_alert_desc",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ssl_get_alert_desc" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (char *)SSL_alert_desc_string(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_alert_desc_v(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_alert_desc_v",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ssl_get_alert_desc_v" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (char *)SSL_alert_desc_string_long(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sslv23_method(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_METHOD *result = 0 ; + + result = (SSL_METHOD *)SSLv23_method(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_SSL_METHOD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_METHOD *arg1 = (SSL_METHOD *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + SSL_CTX *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_new",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_METHOD, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_new" "', argument " "1"" of type '" "SSL_METHOD *""'"); + } + arg1 = (SSL_METHOD *)(argp1); + result = (SSL_CTX *)SSL_CTX_new(arg1); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_SSL_CTX, 0); + else { + m2_PyErr_Msg(_ssl_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_free" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + SSL_CTX_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_verify_depth(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_verify_depth",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_verify_depth" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_ctx_set_verify_depth" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + SSL_CTX_set_verify_depth(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_get_verify_depth(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_get_verify_depth",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_get_verify_depth" "', argument " "1"" of type '" "SSL_CTX const *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_CTX_get_verify_depth((SSL_CTX const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_get_verify_mode(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_get_verify_mode",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_get_verify_mode" "', argument " "1"" of type '" "SSL_CTX const *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_CTX_get_verify_mode((SSL_CTX const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_cipher_list(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_cipher_list",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_cipher_list" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_set_cipher_list" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_CTX_set_cipher_list(arg1,(char const *)arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_add_session(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + SSL_SESSION *arg2 = (SSL_SESSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_add_session",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_add_session" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_add_session" "', argument " "2"" of type '" "SSL_SESSION *""'"); + } + arg2 = (SSL_SESSION *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_CTX_add_session(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_remove_session(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + SSL_SESSION *arg2 = (SSL_SESSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_remove_session",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_remove_session" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_remove_session" "', argument " "2"" of type '" "SSL_SESSION *""'"); + } + arg2 = (SSL_SESSION *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_CTX_remove_session(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_session_timeout(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + long arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_session_timeout",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_session_timeout" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_ctx_set_session_timeout" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)SSL_CTX_set_timeout(arg1,arg2); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_get_session_timeout(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_get_session_timeout",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_get_session_timeout" "', argument " "1"" of type '" "SSL_CTX const *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)SSL_CTX_get_timeout((SSL_CTX const *)arg1); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_get_cert_store(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509_STORE *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_get_cert_store",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_get_cert_store" "', argument " "1"" of type '" "SSL_CTX const *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509_STORE *)SSL_CTX_get_cert_store((SSL_CTX const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_STORE, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_default_verify_paths(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_default_verify_paths",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_default_verify_paths" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_CTX_set_default_verify_paths(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_ex_data_x509_store_ctx_idx(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int result; + + result = (int)SSL_get_ex_data_X509_STORE_CTX_idx(); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_new_ssl(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + BIO *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"bio_new_ssl",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_new_ssl" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "bio_new_ssl" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (BIO *)BIO_new_ssl(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_BIO, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + SSL *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_new",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_new" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (SSL *)SSL_new(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_SSL, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_free" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + SSL_free(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_dup(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + SSL *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_dup",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_dup" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (SSL *)SSL_dup(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_SSL, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + BIO *arg2 = (BIO *) 0 ; + BIO *arg3 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_bio",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_bio" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_set_bio" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "ssl_set_bio" "', argument " "3"" of type '" "BIO *""'"); + } + arg3 = (BIO *)(argp3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + SSL_set_bio(arg1,arg2,arg3); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_accept_state(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_accept_state",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_accept_state" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + SSL_set_accept_state(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_connect_state(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_connect_state",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_connect_state" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + SSL_set_connect_state(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_shutdown(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_shutdown",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_shutdown" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_get_shutdown((SSL const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_shutdown(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_shutdown",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_shutdown" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_set_shutdown" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + SSL_set_shutdown(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_shutdown(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_shutdown",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_shutdown" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)SSL_shutdown(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_clear(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_clear",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_clear" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_clear(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_do_handshake(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_do_handshake",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_do_handshake" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)SSL_do_handshake(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_renegotiate(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_renegotiate",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_renegotiate" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)SSL_renegotiate(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_pending(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_pending",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_pending" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_pending((SSL const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_peer_cert(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_peer_cert",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_peer_cert" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509 *)SSL_get_peer_certificate((SSL const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_current_cipher(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + SSL_CIPHER *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_current_cipher",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_current_cipher" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (SSL_CIPHER *)SSL_get_current_cipher((SSL const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_SSL_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_verify_mode(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_verify_mode",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_verify_mode" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_get_verify_mode((SSL const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_verify_depth(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_verify_depth",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_verify_depth" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_get_verify_depth((SSL const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_verify_result(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_verify_result",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_verify_result" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)SSL_get_verify_result((SSL const *)arg1); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_ssl_ctx(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + SSL_CTX *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_ssl_ctx",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_ssl_ctx" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (SSL_CTX *)SSL_get_SSL_CTX((SSL const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_SSL_CTX, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_default_session_timeout(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_default_session_timeout",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_default_session_timeout" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)SSL_get_default_timeout((SSL const *)arg1); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_cipher_list(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_cipher_list",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_cipher_list" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_set_cipher_list" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_set_cipher_list(arg1,(char const *)arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_cipher_list(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_cipher_list",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_cipher_list" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_get_cipher_list" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)SSL_get_cipher_list((SSL const *)arg1,arg2); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_cipher_get_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CIPHER *arg1 = (SSL_CIPHER *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_cipher_get_name",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_cipher_get_name" "', argument " "1"" of type '" "SSL_CIPHER const *""'"); + } + arg1 = (SSL_CIPHER *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)SSL_CIPHER_get_name((SSL_CIPHER const *)arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_cipher_get_version(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CIPHER *arg1 = (SSL_CIPHER *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_cipher_get_version",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_cipher_get_version" "', argument " "1"" of type '" "SSL_CIPHER const *""'"); + } + arg1 = (SSL_CIPHER *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)SSL_CIPHER_get_version((SSL_CIPHER const *)arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_session(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + SSL_SESSION *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_session",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_session" "', argument " "1"" of type '" "SSL const *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (SSL_SESSION *)SSL_get_session((SSL const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get1_session(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + SSL_SESSION *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get1_session",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get1_session" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (SSL_SESSION *)SSL_get1_session(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_session(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + SSL_SESSION *arg2 = (SSL_SESSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_session",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_session" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_set_session" "', argument " "2"" of type '" "SSL_SESSION *""'"); + } + arg2 = (SSL_SESSION *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)SSL_set_session(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_session_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_SESSION *arg1 = (SSL_SESSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_session_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_session_free" "', argument " "1"" of type '" "SSL_SESSION *""'"); + } + arg1 = (SSL_SESSION *)(argp1); + SSL_SESSION_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_session_print(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + SSL_SESSION *arg2 = (SSL_SESSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_session_print",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_session_print" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_session_print" "', argument " "2"" of type '" "SSL_SESSION const *""'"); + } + arg2 = (SSL_SESSION *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)SSL_SESSION_print(arg1,(SSL_SESSION const *)arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_session_set_timeout(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_SESSION *arg1 = (SSL_SESSION *) 0 ; + long arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_session_set_timeout",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_session_set_timeout" "', argument " "1"" of type '" "SSL_SESSION *""'"); + } + arg1 = (SSL_SESSION *)(argp1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_session_set_timeout" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + result = (long)SSL_SESSION_set_timeout(arg1,arg2); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_session_get_timeout(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_SESSION *arg1 = (SSL_SESSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_session_get_timeout",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_session_get_timeout" "', argument " "1"" of type '" "SSL_SESSION const *""'"); + } + arg1 = (SSL_SESSION *)(argp1); + result = (long)SSL_SESSION_get_timeout((SSL_SESSION const *)arg1); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_accept(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + double arg2 = (double) -1 ; + void *argp1 = 0 ; + int res1 = 0 ; + double val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_accept",1,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_accept" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + if (obj1) { + ecode2 = SWIG_AsVal_double(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_accept" "', argument " "2"" of type '" "double""'"); + } + arg2 = (double)(val2); + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)ssl_accept(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_connect(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + double arg2 = (double) -1 ; + void *argp1 = 0 ; + int res1 = 0 ; + double val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_connect",1,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_connect" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + if (obj1) { + ecode2 = SWIG_AsVal_double(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_connect" "', argument " "2"" of type '" "double""'"); + } + arg2 = (double)(val2); + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)ssl_connect(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_read(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + int arg2 ; + double arg3 = (double) -1 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + double val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_read",2,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_read" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_read" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (obj2) { + ecode3 = SWIG_AsVal_double(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "ssl_read" "', argument " "3"" of type '" "double""'"); + } + arg3 = (double)(val3); + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)ssl_read(arg1,arg2,arg3); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_write(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + double arg3 = (double) -1 ; + void *argp1 = 0 ; + int res1 = 0 ; + double val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_write",2,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_write" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + arg2=obj1; + } + if (obj2) { + ecode3 = SWIG_AsVal_double(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "ssl_write" "', argument " "3"" of type '" "double""'"); + } + arg3 = (double)(val3); + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_write(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__ssl_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_ssl_err""' of type '""PyObject *""'"); + } + _ssl_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__ssl_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_ssl_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN int Swig_var__ssl_timeout_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_ssl_timeout_err""' of type '""PyObject *""'"); + } + _ssl_timeout_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__ssl_timeout_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_ssl_timeout_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_ssl_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_init",2,2,&obj0,&obj1)) SWIG_fail; + { + arg1=obj0; + } + { + arg2=obj1; + } + ssl_init(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_tlsv1_method(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_METHOD *result = 0 ; + + result = (SSL_METHOD *)tlsv1_method(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_SSL_METHOD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_passphrase_callback(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_passphrase_callback",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_passphrase_callback" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_ctx_passphrase_callback(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_use_x509(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + X509 *arg2 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_use_x509",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_use_x509" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_use_x509" "', argument " "2"" of type '" "X509 *""'"); + } + arg2 = (X509 *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_use_x509(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_use_cert(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_use_cert",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_use_cert" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_use_cert" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_use_cert(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_use_cert_chain(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_use_cert_chain",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_use_cert_chain" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_use_cert_chain" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_use_cert_chain(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_use_privkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_use_privkey",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_use_privkey" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_use_privkey" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_use_privkey(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_use_rsa_privkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + RSA *arg2 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_use_rsa_privkey",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_use_rsa_privkey" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_use_rsa_privkey" "', argument " "2"" of type '" "RSA *""'"); + } + arg2 = (RSA *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_use_rsa_privkey(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_use_pkey_privkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_use_pkey_privkey",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_use_pkey_privkey" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_use_pkey_privkey" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_use_pkey_privkey(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_check_privkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_check_privkey",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_check_privkey" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_check_privkey(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_client_CA_list_from_file(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_client_CA_list_from_file",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_client_CA_list_from_file" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_set_client_CA_list_from_file" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_ctx_set_client_CA_list_from_file(arg1,(char const *)arg2); + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_verify_default(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_verify_default",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_verify_default" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_ctx_set_verify_default" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_ctx_set_verify_default(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_verify(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + int arg2 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_verify",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_verify" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_ctx_set_verify" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!PyCallable_Check(obj2)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_ctx_set_verify(arg1,arg2,arg3); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_session_id_context(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_session_id_context",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_session_id_context" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_set_session_id_context(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_info_callback(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_info_callback",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_info_callback" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_ctx_set_info_callback(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_tmp_dh(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + DH *arg2 = (DH *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_tmp_dh",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_tmp_dh" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_DH, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_set_tmp_dh" "', argument " "2"" of type '" "DH *""'"); + } + arg2 = (DH *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)ssl_ctx_set_tmp_dh(arg1,arg2); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_tmp_dh_callback(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_tmp_dh_callback",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_tmp_dh_callback" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_ctx_set_tmp_dh_callback(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_tmp_rsa(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + RSA *arg2 = (RSA *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_tmp_rsa",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_tmp_rsa" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_RSA, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_set_tmp_rsa" "', argument " "2"" of type '" "RSA *""'"); + } + arg2 = (RSA *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)ssl_ctx_set_tmp_rsa(arg1,arg2); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_tmp_rsa_callback(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_tmp_rsa_callback",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_tmp_rsa_callback" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_ctx_set_tmp_rsa_callback(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_load_verify_locations(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_load_verify_locations",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_load_verify_locations" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_ctx_load_verify_locations" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "ssl_ctx_load_verify_locations" "', argument " "3"" of type '" "char const *""'"); + } + arg3 = (char *)(buf3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_load_verify_locations(arg1,(char const *)arg2,(char const *)arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_options(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + long arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_options",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_options" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_ctx_set_options" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)ssl_ctx_set_options(arg1,arg2); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_bio_set_ssl(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + SSL *arg2 = (SSL *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"bio_set_ssl",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "bio_set_ssl" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "bio_set_ssl" "', argument " "2"" of type '" "SSL *""'"); + } + arg2 = (SSL *)(argp2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "bio_set_ssl" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)bio_set_ssl(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_mode(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + long arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_mode",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_mode" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_set_mode" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)ssl_set_mode(arg1,arg2); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_mode(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_mode",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_mode" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)ssl_get_mode(arg1); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_tlsext_host_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_tlsext_host_name",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_tlsext_host_name" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_set_tlsext_host_name" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_set_tlsext_host_name(arg1,(char const *)arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_client_CA_list_from_file(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_client_CA_list_from_file",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_client_CA_list_from_file" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_set_client_CA_list_from_file" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_set_client_CA_list_from_file(arg1,(char const *)arg2); + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_client_CA_list_from_context(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + SSL_CTX *arg2 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_client_CA_list_from_context",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_client_CA_list_from_context" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_set_client_CA_list_from_context" "', argument " "2"" of type '" "SSL_CTX *""'"); + } + arg2 = (SSL_CTX *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_set_client_CA_list_from_context(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_session_id_context(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_session_id_context",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_session_id_context" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_set_session_id_context(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_fd(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_fd",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_fd" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_set_fd" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_set_fd(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_set_shutdown1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_set_shutdown1",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_set_shutdown1" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_set_shutdown1" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ssl_set_shutdown1(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_read_nbio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_read_nbio",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_read_nbio" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_read_nbio" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)ssl_read_nbio(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_write_nbio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_write_nbio",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_write_nbio" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_write_nbio(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_cipher_get_bits(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CIPHER *arg1 = (SSL_CIPHER *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_cipher_get_bits",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_cipher_get_bits" "', argument " "1"" of type '" "SSL_CIPHER *""'"); + } + arg1 = (SSL_CIPHER *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_cipher_get_bits(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_ssl_cipher_num(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_SSL_CIPHER *arg1 = (struct stack_st_SSL_CIPHER *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_ssl_cipher_num",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_SSL_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_ssl_cipher_num" "', argument " "1"" of type '" "struct stack_st_SSL_CIPHER *""'"); + } + arg1 = (struct stack_st_SSL_CIPHER *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)sk_ssl_cipher_num(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_ssl_cipher_value(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_SSL_CIPHER *arg1 = (struct stack_st_SSL_CIPHER *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + SSL_CIPHER *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_ssl_cipher_value",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_SSL_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_ssl_cipher_value" "', argument " "1"" of type '" "struct stack_st_SSL_CIPHER *""'"); + } + arg1 = (struct stack_st_SSL_CIPHER *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "sk_ssl_cipher_value" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (SSL_CIPHER *)sk_ssl_cipher_value(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_SSL_CIPHER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_get_peer_cert_chain(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + struct stack_st_X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_get_peer_cert_chain",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_get_peer_cert_chain" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (struct stack_st_X509 *)ssl_get_peer_cert_chain(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st_X509, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_num(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509 *arg1 = (struct stack_st_X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_num",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_num" "', argument " "1"" of type '" "struct stack_st_X509 *""'"); + } + arg1 = (struct stack_st_X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)sk_x509_num(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_value(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509 *arg1 = (struct stack_st_X509 *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_value",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_value" "', argument " "1"" of type '" "struct stack_st_X509 *""'"); + } + arg1 = (struct stack_st_X509 *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "sk_x509_value" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509 *)sk_x509_value(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_i2d_ssl_session(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + SSL_SESSION *arg2 = (SSL_SESSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"i2d_ssl_session",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "i2d_ssl_session" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "i2d_ssl_session" "', argument " "2"" of type '" "SSL_SESSION *""'"); + } + arg2 = (SSL_SESSION *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + i2d_ssl_session(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_session_read_pem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + SSL_SESSION *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_session_read_pem",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_session_read_pem" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (SSL_SESSION *)ssl_session_read_pem(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_SSL_SESSION, 0); + else { + m2_PyErr_Msg(_ssl_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_session_write_pem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_SESSION *arg1 = (SSL_SESSION *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_session_write_pem",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_SESSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_session_write_pem" "', argument " "1"" of type '" "SSL_SESSION *""'"); + } + arg1 = (SSL_SESSION *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ssl_session_write_pem" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)ssl_session_write_pem(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_session_cache_mode(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_session_cache_mode",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_session_cache_mode" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_ctx_set_session_cache_mode" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_set_session_cache_mode(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_get_session_cache_mode(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_get_session_cache_mode",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_get_session_cache_mode" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_ctx_get_session_cache_mode(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_ctx_set_cache_size(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL_CTX *arg1 = (SSL_CTX *) 0 ; + long arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_ctx_set_cache_size",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_ctx_set_cache_size" "', argument " "1"" of type '" "SSL_CTX *""'"); + } + arg1 = (SSL_CTX *)(argp1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ssl_ctx_set_cache_size" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)ssl_ctx_set_cache_size(arg1,arg2); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ssl_is_init_finished(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + SSL *arg1 = (SSL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ssl_is_init_finished",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_SSL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ssl_is_init_finished" "', argument " "1"" of type '" "SSL *""'"); + } + arg1 = (SSL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ssl_is_init_finished(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_check_ca(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_check_ca",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_check_ca" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_check_ca(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *result = 0 ; + + result = (X509 *)X509_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_dup(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_dup",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_dup" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509 *)X509_dup(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_free" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + X509_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_crl_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_CRL *arg1 = (X509_CRL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_crl_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_CRL, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_crl_free" "', argument " "1"" of type '" "X509_CRL *""'"); + } + arg1 = (X509_CRL *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + X509_CRL_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_crl_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_CRL *result = 0 ; + + result = (X509_CRL *)X509_CRL_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_CRL, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_print(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509 *arg2 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_print",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_print" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_print" "', argument " "2"" of type '" "X509 *""'"); + } + arg2 = (X509 *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)X509_print(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_crl_print(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509_CRL *arg2 = (X509_CRL *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_crl_print",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_crl_print" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_CRL, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_crl_print" "', argument " "2"" of type '" "X509_CRL *""'"); + } + arg2 = (X509_CRL *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)X509_CRL_print(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_serial_number(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + ASN1_INTEGER *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_serial_number",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_get_serial_number" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (ASN1_INTEGER *)X509_get_serialNumber(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_INTEGER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_set_serial_number(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + ASN1_INTEGER *arg2 = (ASN1_INTEGER *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_set_serial_number",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_set_serial_number" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ASN1_INTEGER, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_set_serial_number" "', argument " "2"" of type '" "ASN1_INTEGER *""'"); + } + arg2 = (ASN1_INTEGER *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_set_serialNumber(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_pubkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + EVP_PKEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_pubkey",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_get_pubkey" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (EVP_PKEY *)X509_get_pubkey(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_set_pubkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_set_pubkey",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_set_pubkey" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_set_pubkey" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_set_pubkey(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_issuer_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509_NAME *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_issuer_name",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_get_issuer_name" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509_NAME *)X509_get_issuer_name(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_NAME, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_set_issuer_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + X509_NAME *arg2 = (X509_NAME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_set_issuer_name",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_set_issuer_name" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_set_issuer_name" "', argument " "2"" of type '" "X509_NAME *""'"); + } + arg2 = (X509_NAME *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_set_issuer_name(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_subject_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509_NAME *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_subject_name",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_get_subject_name" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509_NAME *)X509_get_subject_name(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_NAME, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_set_subject_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + X509_NAME *arg2 = (X509_NAME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_set_subject_name",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_set_subject_name" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_set_subject_name" "', argument " "2"" of type '" "X509_NAME *""'"); + } + arg2 = (X509_NAME *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_set_subject_name(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_cmp_current_time(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_TIME *arg1 = (ASN1_TIME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_cmp_current_time",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_cmp_current_time" "', argument " "1"" of type '" "ASN1_TIME *""'"); + } + arg1 = (ASN1_TIME *)(argp1); + result = (int)X509_cmp_current_time(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_check_purpose(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + int arg2 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_check_purpose",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_check_purpose" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_check_purpose" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_check_purpose" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_check_purpose(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_check_trust(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + int arg2 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_check_trust",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_check_trust" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_check_trust" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_check_trust" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_check_trust(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_write_pem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509 *arg2 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_write_pem",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_write_pem" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_write_pem" "', argument " "2"" of type '" "X509 *""'"); + } + arg2 = (X509 *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)PEM_write_bio_X509(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_write_pem_file(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + FILE *arg1 = (FILE *) 0 ; + X509 *arg2 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_write_pem_file",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_FILE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_write_pem_file" "', argument " "1"" of type '" "FILE *""'"); + } + arg1 = (FILE *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_write_pem_file" "', argument " "2"" of type '" "X509 *""'"); + } + arg2 = (X509 *)(argp2); + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)PEM_write_X509(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_verify(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_verify",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_verify" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_verify" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_verify(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_verify_error(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + long arg1 ; + long val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_verify_error",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_long(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "x509_get_verify_error" "', argument " "1"" of type '" "long""'"); + } + arg1 = (long)(val1); + result = (char *)X509_verify_cert_error_string(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_add_ext(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + X509_EXTENSION *arg2 = (X509_EXTENSION *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_add_ext",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_add_ext" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_add_ext" "', argument " "2"" of type '" "X509_EXTENSION *""'"); + } + arg2 = (X509_EXTENSION *)(argp2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_add_ext" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_add_ext(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_ext_count(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_ext_count",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_get_ext_count" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_get_ext_count(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_ext(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + X509_EXTENSION *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_ext",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_get_ext" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_get_ext" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509_EXTENSION *)X509_get_ext(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_ext_print(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509_EXTENSION *arg2 = (X509_EXTENSION *) 0 ; + unsigned long arg3 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + unsigned long val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_ext_print",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_ext_print" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_ext_print" "', argument " "2"" of type '" "X509_EXTENSION *""'"); + } + arg2 = (X509_EXTENSION *)(argp2); + ecode3 = SWIG_AsVal_unsigned_SS_long(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_ext_print" "', argument " "3"" of type '" "unsigned long""'"); + } + arg3 = (unsigned long)(val3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "x509_ext_print" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)X509V3_EXT_print(arg1,arg2,arg3,arg4); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *result = 0 ; + + result = (X509_NAME *)X509_NAME_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_NAME, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_free" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + X509_NAME_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_print(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509_NAME *arg2 = (X509_NAME *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_print",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_print" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_name_print" "', argument " "2"" of type '" "X509_NAME *""'"); + } + arg2 = (X509_NAME *)(argp2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_name_print" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)X509_NAME_print(arg1,arg2,arg3); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_get_entry(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + X509_NAME_ENTRY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_get_entry",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_get_entry" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_name_get_entry" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509_NAME_ENTRY *)X509_NAME_get_entry(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_entry_count(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_entry_count",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_entry_count" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_NAME_entry_count(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_delete_entry(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + X509_NAME_ENTRY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_delete_entry",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_delete_entry" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_name_delete_entry" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509_NAME_ENTRY *)X509_NAME_delete_entry(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_add_entry(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + X509_NAME_ENTRY *arg2 = (X509_NAME_ENTRY *) 0 ; + int arg3 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_add_entry",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_add_entry" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_name_add_entry" "', argument " "2"" of type '" "X509_NAME_ENTRY *""'"); + } + arg2 = (X509_NAME_ENTRY *)(argp2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_name_add_entry" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "x509_name_add_entry" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_NAME_add_entry(arg1,arg2,arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_add_entry_by_obj(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + ASN1_OBJECT *arg2 = (ASN1_OBJECT *) 0 ; + int arg3 ; + unsigned char *arg4 = (unsigned char *) 0 ; + int arg5 ; + int arg6 ; + int arg7 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val3 ; + int ecode3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + int val5 ; + int ecode5 = 0 ; + int val6 ; + int ecode6 = 0 ; + int val7 ; + int ecode7 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PyObject * obj5 = 0 ; + PyObject * obj6 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_add_entry_by_obj",7,7,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_add_entry_by_obj" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_name_add_entry_by_obj" "', argument " "2"" of type '" "ASN1_OBJECT *""'"); + } + arg2 = (ASN1_OBJECT *)(argp2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_name_add_entry_by_obj" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + res4 = SWIG_ConvertPtr(obj3, &argp4,SWIGTYPE_p_unsigned_char, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "x509_name_add_entry_by_obj" "', argument " "4"" of type '" "unsigned char *""'"); + } + arg4 = (unsigned char *)(argp4); + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "x509_name_add_entry_by_obj" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + ecode6 = SWIG_AsVal_int(obj5, &val6); + if (!SWIG_IsOK(ecode6)) { + SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "x509_name_add_entry_by_obj" "', argument " "6"" of type '" "int""'"); + } + arg6 = (int)(val6); + ecode7 = SWIG_AsVal_int(obj6, &val7); + if (!SWIG_IsOK(ecode7)) { + SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "x509_name_add_entry_by_obj" "', argument " "7"" of type '" "int""'"); + } + arg7 = (int)(val7); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_NAME_add_entry_by_OBJ(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_add_entry_by_nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + int arg2 ; + int arg3 ; + unsigned char *arg4 = (unsigned char *) 0 ; + int arg5 ; + int arg6 ; + int arg7 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + int val5 ; + int ecode5 = 0 ; + int val6 ; + int ecode6 = 0 ; + int val7 ; + int ecode7 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PyObject * obj5 = 0 ; + PyObject * obj6 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_add_entry_by_nid",7,7,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_add_entry_by_nid" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_name_add_entry_by_nid" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_name_add_entry_by_nid" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + res4 = SWIG_ConvertPtr(obj3, &argp4,SWIGTYPE_p_unsigned_char, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "x509_name_add_entry_by_nid" "', argument " "4"" of type '" "unsigned char *""'"); + } + arg4 = (unsigned char *)(argp4); + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "x509_name_add_entry_by_nid" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + ecode6 = SWIG_AsVal_int(obj5, &val6); + if (!SWIG_IsOK(ecode6)) { + SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "x509_name_add_entry_by_nid" "', argument " "6"" of type '" "int""'"); + } + arg6 = (int)(val6); + ecode7 = SWIG_AsVal_int(obj6, &val7); + if (!SWIG_IsOK(ecode7)) { + SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "x509_name_add_entry_by_nid" "', argument " "7"" of type '" "int""'"); + } + arg7 = (int)(val7); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_NAME_add_entry_by_NID(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_print_ex(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509_NAME *arg2 = (X509_NAME *) 0 ; + int arg3 ; + unsigned long arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val3 ; + int ecode3 = 0 ; + unsigned long val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_print_ex",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_print_ex" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_name_print_ex" "', argument " "2"" of type '" "X509_NAME *""'"); + } + arg2 = (X509_NAME *)(argp2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_name_print_ex" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + ecode4 = SWIG_AsVal_unsigned_SS_long(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "x509_name_print_ex" "', argument " "4"" of type '" "unsigned long""'"); + } + arg4 = (unsigned long)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)X509_NAME_print_ex(arg1,arg2,arg3,arg4); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_hash(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + unsigned long result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_hash",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_hash" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (unsigned long)X509_NAME_hash_old(arg1); + resultobj = SWIG_From_unsigned_SS_long((unsigned long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_get_index_by_nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + int arg2 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_get_index_by_nid",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_get_index_by_nid" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_name_get_index_by_nid" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_name_get_index_by_nid" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_NAME_get_index_by_NID(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_entry_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME_ENTRY *result = 0 ; + + result = (X509_NAME_ENTRY *)X509_NAME_ENTRY_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_entry_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME_ENTRY *arg1 = (X509_NAME_ENTRY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_entry_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_entry_free" "', argument " "1"" of type '" "X509_NAME_ENTRY *""'"); + } + arg1 = (X509_NAME_ENTRY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + X509_NAME_ENTRY_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_entry_create_by_nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME_ENTRY **arg1 = (X509_NAME_ENTRY **) 0 ; + int arg2 ; + int arg3 ; + unsigned char *arg4 = (unsigned char *) 0 ; + int arg5 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + int val5 ; + int ecode5 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + X509_NAME_ENTRY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_entry_create_by_nid",5,5,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_p_X509_NAME_ENTRY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_entry_create_by_nid" "', argument " "1"" of type '" "X509_NAME_ENTRY **""'"); + } + arg1 = (X509_NAME_ENTRY **)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_name_entry_create_by_nid" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_name_entry_create_by_nid" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + res4 = SWIG_ConvertPtr(obj3, &argp4,SWIGTYPE_p_unsigned_char, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "x509_name_entry_create_by_nid" "', argument " "4"" of type '" "unsigned char *""'"); + } + arg4 = (unsigned char *)(argp4); + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "x509_name_entry_create_by_nid" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + result = (X509_NAME_ENTRY *)X509_NAME_ENTRY_create_by_NID(arg1,arg2,arg3,arg4,arg5); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_entry_set_object(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME_ENTRY *arg1 = (X509_NAME_ENTRY *) 0 ; + ASN1_OBJECT *arg2 = (ASN1_OBJECT *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_entry_set_object",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_entry_set_object" "', argument " "1"" of type '" "X509_NAME_ENTRY *""'"); + } + arg1 = (X509_NAME_ENTRY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_name_entry_set_object" "', argument " "2"" of type '" "ASN1_OBJECT *""'"); + } + arg2 = (ASN1_OBJECT *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_NAME_ENTRY_set_object(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_entry_get_object(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME_ENTRY *arg1 = (X509_NAME_ENTRY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + ASN1_OBJECT *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_entry_get_object",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_entry_get_object" "', argument " "1"" of type '" "X509_NAME_ENTRY *""'"); + } + arg1 = (X509_NAME_ENTRY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (ASN1_OBJECT *)X509_NAME_ENTRY_get_object(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_entry_get_data(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME_ENTRY *arg1 = (X509_NAME_ENTRY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + ASN1_STRING *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_entry_get_data",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_entry_get_data" "', argument " "1"" of type '" "X509_NAME_ENTRY *""'"); + } + arg1 = (X509_NAME_ENTRY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (ASN1_STRING *)X509_NAME_ENTRY_get_data(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_STRING, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_entry_set_data(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME_ENTRY *arg1 = (X509_NAME_ENTRY *) 0 ; + int arg2 ; + unsigned char *arg3 = (unsigned char *) 0 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_entry_set_data",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_entry_set_data" "', argument " "1"" of type '" "X509_NAME_ENTRY *""'"); + } + arg1 = (X509_NAME_ENTRY *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_name_entry_set_data" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (PyString_Check(obj2)) { + Py_ssize_t len; + + arg3 = (unsigned char *)PyString_AsString(obj2); + len = PyString_Size(obj2); + + + if (len > INT_MAX) { + PyErr_SetString(_x509_err, "object too large"); + return NULL; + } + arg4 = len; + } else { + PyErr_SetString(PyExc_TypeError, "expected string"); + return NULL; + } + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_NAME_ENTRY_set_data(arg1,arg2,(unsigned char const *)arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *result = 0 ; + + result = (X509_REQ *)X509_REQ_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_REQ, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_free" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + X509_REQ_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_print(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509_REQ *arg2 = (X509_REQ *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_print",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_print" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_req_print" "', argument " "2"" of type '" "X509_REQ *""'"); + } + arg2 = (X509_REQ *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)X509_REQ_print(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_get_pubkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + EVP_PKEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_get_pubkey",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_get_pubkey" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (EVP_PKEY *)X509_REQ_get_pubkey(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_set_pubkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_set_pubkey",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_set_pubkey" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_req_set_pubkey" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_REQ_set_pubkey(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_set_subject_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + X509_NAME *arg2 = (X509_NAME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_set_subject_name",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_set_subject_name" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_req_set_subject_name" "', argument " "2"" of type '" "X509_NAME *""'"); + } + arg2 = (X509_NAME *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_REQ_set_subject_name(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_verify(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_verify",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_verify" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_req_verify" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_REQ_verify(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_sign(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + EVP_MD *arg3 = (EVP_MD *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_sign",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_sign" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_req_sign" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "x509_req_sign" "', argument " "3"" of type '" "EVP_MD const *""'"); + } + arg3 = (EVP_MD *)(argp3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_REQ_sign(arg1,arg2,(EVP_MD const *)arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_i2d_x509_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509 *arg2 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"i2d_x509_bio",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "i2d_x509_bio" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "i2d_x509_bio" "', argument " "2"" of type '" "X509 *""'"); + } + arg2 = (X509 *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)i2d_X509_bio(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_i2d_x509_req_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509_REQ *arg2 = (X509_REQ *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"i2d_x509_req_bio",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "i2d_x509_req_bio" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "i2d_x509_req_bio" "', argument " "2"" of type '" "X509_REQ *""'"); + } + arg2 = (X509_REQ *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)i2d_X509_REQ_bio(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE *result = 0 ; + + result = (X509_STORE *)X509_STORE_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_STORE, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE *arg1 = (X509_STORE *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_free" "', argument " "1"" of type '" "X509_STORE *""'"); + } + arg1 = (X509_STORE *)(argp1); + X509_STORE_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_add_cert(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE *arg1 = (X509_STORE *) 0 ; + X509 *arg2 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_add_cert",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_add_cert" "', argument " "1"" of type '" "X509_STORE *""'"); + } + arg1 = (X509_STORE *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_store_add_cert" "', argument " "2"" of type '" "X509 *""'"); + } + arg2 = (X509 *)(argp2); + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)X509_STORE_add_cert(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_set_verify_cb__SWIG_0(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE *arg1 = (X509_STORE *) 0 ; + int (*arg2)(int,X509_STORE_CTX *) = (int (*)(int,X509_STORE_CTX *)) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_set_verify_cb",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_set_verify_cb" "', argument " "1"" of type '" "X509_STORE *""'"); + } + arg1 = (X509_STORE *)(argp1); + { + int res = SWIG_ConvertFunctionPtr(obj1, (void**)(&arg2), SWIGTYPE_p_f_int_p_X509_STORE_CTX__int); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in method '" "x509_store_set_verify_cb" "', argument " "2"" of type '" "int (*)(int,X509_STORE_CTX *)""'"); + } + } + X509_STORE_set_verify_cb(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_ctx_get_current_cert(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE_CTX *arg1 = (X509_STORE_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_ctx_get_current_cert",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_ctx_get_current_cert" "', argument " "1"" of type '" "X509_STORE_CTX *""'"); + } + arg1 = (X509_STORE_CTX *)(argp1); + result = (X509 *)X509_STORE_CTX_get_current_cert(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_ctx_get_error(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE_CTX *arg1 = (X509_STORE_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_ctx_get_error",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_ctx_get_error" "', argument " "1"" of type '" "X509_STORE_CTX *""'"); + } + arg1 = (X509_STORE_CTX *)(argp1); + result = (int)X509_STORE_CTX_get_error(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_ctx_get_error_depth(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE_CTX *arg1 = (X509_STORE_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_ctx_get_error_depth",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_ctx_get_error_depth" "', argument " "1"" of type '" "X509_STORE_CTX *""'"); + } + arg1 = (X509_STORE_CTX *)(argp1); + result = (int)X509_STORE_CTX_get_error_depth(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_ctx_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE_CTX *arg1 = (X509_STORE_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_ctx_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_ctx_free" "', argument " "1"" of type '" "X509_STORE_CTX *""'"); + } + arg1 = (X509_STORE_CTX *)(argp1); + X509_STORE_CTX_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_ctx_get1_chain(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE_CTX *arg1 = (X509_STORE_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + struct stack_st_X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_ctx_get1_chain",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_ctx_get1_chain" "', argument " "1"" of type '" "X509_STORE_CTX *""'"); + } + arg1 = (X509_STORE_CTX *)(argp1); + result = (struct stack_st_X509 *)X509_STORE_CTX_get1_chain(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st_X509, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_extension_get_critical(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_EXTENSION *arg1 = (X509_EXTENSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_extension_get_critical",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_extension_get_critical" "', argument " "1"" of type '" "X509_EXTENSION *""'"); + } + arg1 = (X509_EXTENSION *)(argp1); + result = (int)X509_EXTENSION_get_critical(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_extension_set_critical(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_EXTENSION *arg1 = (X509_EXTENSION *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_extension_set_critical",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_extension_set_critical" "', argument " "1"" of type '" "X509_EXTENSION *""'"); + } + arg1 = (X509_EXTENSION *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_extension_set_critical" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (int)X509_EXTENSION_set_critical(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_read_pem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_read_pem",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_read_pem" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (X509 *)x509_read_pem(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_X509, 0); + else { + m2_PyErr_Msg(_x509_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_d2i_x509(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"d2i_x509",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "d2i_x509" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (X509 *)d2i_x509(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_X509, 0); + else { + m2_PyErr_Msg(_x509_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__x509_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_x509_err""' of type '""PyObject *""'"); + } + _x509_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__x509_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_x509_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_x509_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + x509_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_d2i_x509_req(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509_REQ *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"d2i_x509_req",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "d2i_x509_req" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (X509_REQ *)d2i_x509_req(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_X509_REQ, 0); + else { + m2_PyErr_Msg(_x509_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_read_pem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509_REQ *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_read_pem",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_read_pem" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (X509_REQ *)x509_req_read_pem(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_X509_REQ, 0); + else { + m2_PyErr_Msg(_x509_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_i2d_x509(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"i2d_x509",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "i2d_x509" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)i2d_x509(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_write_pem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + X509_REQ *arg2 = (X509_REQ *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_write_pem",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_write_pem" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_req_write_pem" "', argument " "2"" of type '" "X509_REQ *""'"); + } + arg2 = (X509_REQ *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)x509_req_write_pem(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_crl_read_pem(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509_CRL *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_crl_read_pem",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_crl_read_pem" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (X509_CRL *)x509_crl_read_pem(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_X509_CRL, 0); + else { + m2_PyErr_Msg(_x509_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_set_version(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + long arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_set_version",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_set_version" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_set_version" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_set_version(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_version(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_version",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_get_version" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)x509_get_version(arg1); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_set_not_before(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + ASN1_TIME *arg2 = (ASN1_TIME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_set_not_before",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_set_not_before" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_set_not_before" "', argument " "2"" of type '" "ASN1_TIME *""'"); + } + arg2 = (ASN1_TIME *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_set_not_before(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_not_before(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + ASN1_TIME *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_not_before",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_get_not_before" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (ASN1_TIME *)x509_get_not_before(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_set_not_after(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + ASN1_TIME *arg2 = (ASN1_TIME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_set_not_after",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_set_not_after" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_set_not_after" "', argument " "2"" of type '" "ASN1_TIME *""'"); + } + arg2 = (ASN1_TIME *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_set_not_after(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_get_not_after(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + ASN1_TIME *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_get_not_after",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_get_not_after" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (ASN1_TIME *)x509_get_not_after(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_sign(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + EVP_MD *arg3 = (EVP_MD *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_sign",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_sign" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_sign" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "x509_sign" "', argument " "3"" of type '" "EVP_MD *""'"); + } + arg3 = (EVP_MD *)(argp3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_sign(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_gmtime_adj(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_TIME *arg1 = (ASN1_TIME *) 0 ; + long arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + ASN1_TIME *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_gmtime_adj",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_gmtime_adj" "', argument " "1"" of type '" "ASN1_TIME *""'"); + } + arg1 = (ASN1_TIME *)(argp1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_gmtime_adj" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + result = (ASN1_TIME *)x509_gmtime_adj(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_by_nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_by_nid",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_by_nid" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_name_by_nid" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)x509_name_by_nid(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_set_by_nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + int arg2 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_set_by_nid",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_set_by_nid" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_name_set_by_nid" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_name_set_by_nid(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_add_entry_by_txt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + char *arg2 = (char *) 0 ; + int arg3 ; + char *arg4 = (char *) 0 ; + int arg5 ; + int arg6 ; + int arg7 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int res4 ; + char *buf4 = 0 ; + int alloc4 = 0 ; + int val5 ; + int ecode5 = 0 ; + int val6 ; + int ecode6 = 0 ; + int val7 ; + int ecode7 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PyObject * obj5 = 0 ; + PyObject * obj6 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_add_entry_by_txt",7,7,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_add_entry_by_txt" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_name_add_entry_by_txt" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_name_add_entry_by_txt" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "x509_name_add_entry_by_txt" "', argument " "4"" of type '" "char *""'"); + } + arg4 = (char *)(buf4); + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "x509_name_add_entry_by_txt" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + ecode6 = SWIG_AsVal_int(obj5, &val6); + if (!SWIG_IsOK(ecode6)) { + SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "x509_name_add_entry_by_txt" "', argument " "6"" of type '" "int""'"); + } + arg6 = (int)(val6); + ecode7 = SWIG_AsVal_int(obj6, &val7); + if (!SWIG_IsOK(ecode7)) { + SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "x509_name_add_entry_by_txt" "', argument " "7"" of type '" "int""'"); + } + arg7 = (int)(val7); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_name_add_entry_by_txt(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_get_der(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_get_der",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_get_der" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)x509_name_get_der(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509 *arg1 = (struct stack_st_X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_free" "', argument " "1"" of type '" "struct stack_st_X509 *""'"); + } + arg1 = (struct stack_st_X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + sk_x509_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_push(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509 *arg1 = (struct stack_st_X509 *) 0 ; + X509 *arg2 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_push",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_push" "', argument " "1"" of type '" "struct stack_st_X509 *""'"); + } + arg1 = (struct stack_st_X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sk_x509_push" "', argument " "2"" of type '" "X509 *""'"); + } + arg2 = (X509 *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)sk_x509_push(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_pop(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509 *arg1 = (struct stack_st_X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_pop",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_pop" "', argument " "1"" of type '" "struct stack_st_X509 *""'"); + } + arg1 = (struct stack_st_X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509 *)sk_x509_pop(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_load_locations(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE *arg1 = (X509_STORE *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_load_locations",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_load_locations" "', argument " "1"" of type '" "X509_STORE *""'"); + } + arg1 = (X509_STORE *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_store_load_locations" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = (int)x509_store_load_locations(arg1,(char const *)arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_type_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_type_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_type_check" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_type_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_type_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_type_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_type_check" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_name_type_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_get_subject_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509_NAME *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_get_subject_name",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_get_subject_name" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509_NAME *)x509_req_get_subject_name(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_NAME, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_get_version(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + long result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_get_version",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_get_version" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (long)x509_req_get_version(arg1); + resultobj = SWIG_From_long((long)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_set_version(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + long arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_set_version",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_set_version" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_req_set_version" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_req_set_version(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_req_add_extensions(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_REQ *arg1 = (X509_REQ *) 0 ; + struct stack_st_X509_EXTENSION *arg2 = (struct stack_st_X509_EXTENSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"x509_req_add_extensions",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_REQ, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_req_add_extensions" "', argument " "1"" of type '" "X509_REQ *""'"); + } + arg1 = (X509_REQ *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_stack_st_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_req_add_extensions" "', argument " "2"" of type '" "struct stack_st_X509_EXTENSION *""'"); + } + arg2 = (struct stack_st_X509_EXTENSION *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)x509_req_add_extensions(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_entry_create_by_txt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME_ENTRY **arg1 = (X509_NAME_ENTRY **) 0 ; + char *arg2 = (char *) 0 ; + int arg3 ; + char *arg4 = (char *) 0 ; + int arg5 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int res4 ; + char *buf4 = 0 ; + int alloc4 = 0 ; + int val5 ; + int ecode5 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + X509_NAME_ENTRY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_entry_create_by_txt",5,5,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_p_X509_NAME_ENTRY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_entry_create_by_txt" "', argument " "1"" of type '" "X509_NAME_ENTRY **""'"); + } + arg1 = (X509_NAME_ENTRY **)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509_name_entry_create_by_txt" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "x509_name_entry_create_by_txt" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "x509_name_entry_create_by_txt" "', argument " "4"" of type '" "char *""'"); + } + arg4 = (char *)(buf4); + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "x509_name_entry_create_by_txt" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + result = (X509_NAME_ENTRY *)x509_name_entry_create_by_txt(arg1,arg2,arg3,arg4,arg5); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_NAME_ENTRY, 0 | 0 ); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509v3_set_nconf(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509V3_CTX *result = 0 ; + + result = (X509V3_CTX *)x509v3_set_nconf(); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_X509V3_CTX, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509v3_ext_conf(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + void *arg1 = (void *) 0 ; + X509V3_CTX *arg2 = (X509V3_CTX *) 0 ; + char *arg3 = (char *) 0 ; + char *arg4 = (char *) 0 ; + int res1 ; + void *argp2 = 0 ; + int res2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + int res4 ; + char *buf4 = 0 ; + int alloc4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + X509_EXTENSION *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509v3_ext_conf",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509v3_ext_conf" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509V3_CTX, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "x509v3_ext_conf" "', argument " "2"" of type '" "X509V3_CTX *""'"); + } + arg2 = (X509V3_CTX *)(argp2); + res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "x509v3_ext_conf" "', argument " "3"" of type '" "char *""'"); + } + arg3 = (char *)(buf3); + res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "x509v3_ext_conf" "', argument " "4"" of type '" "char *""'"); + } + arg4 = (char *)(buf4); + result = (X509_EXTENSION *)x509v3_ext_conf(arg1,arg2,arg3,arg4); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_X509_EXTENSION, 0); + else { + m2_PyErr_Msg(_x509_err); + resultobj = NULL; + } + } + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + return resultobj; +fail: + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_extension_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_EXTENSION *arg1 = (X509_EXTENSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_extension_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_extension_free" "', argument " "1"" of type '" "X509_EXTENSION *""'"); + } + arg1 = (X509_EXTENSION *)(argp1); + x509_extension_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_extension_get_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_EXTENSION *arg1 = (X509_EXTENSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_extension_get_name",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_extension_get_name" "', argument " "1"" of type '" "X509_EXTENSION *""'"); + } + arg1 = (X509_EXTENSION *)(argp1); + result = (PyObject *)x509_extension_get_name(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_extension_new_null(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509_EXTENSION *result = 0 ; + + result = (struct stack_st_X509_EXTENSION *)sk_x509_extension_new_null(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st_X509_EXTENSION, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_extension_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509_EXTENSION *arg1 = (struct stack_st_X509_EXTENSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_extension_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_extension_free" "', argument " "1"" of type '" "struct stack_st_X509_EXTENSION *""'"); + } + arg1 = (struct stack_st_X509_EXTENSION *)(argp1); + sk_x509_extension_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_extension_push(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509_EXTENSION *arg1 = (struct stack_st_X509_EXTENSION *) 0 ; + X509_EXTENSION *arg2 = (X509_EXTENSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_extension_push",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_extension_push" "', argument " "1"" of type '" "struct stack_st_X509_EXTENSION *""'"); + } + arg1 = (struct stack_st_X509_EXTENSION *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "sk_x509_extension_push" "', argument " "2"" of type '" "X509_EXTENSION *""'"); + } + arg2 = (X509_EXTENSION *)(argp2); + result = (int)sk_x509_extension_push(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_extension_pop(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509_EXTENSION *arg1 = (struct stack_st_X509_EXTENSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + X509_EXTENSION *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_extension_pop",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_extension_pop" "', argument " "1"" of type '" "struct stack_st_X509_EXTENSION *""'"); + } + arg1 = (struct stack_st_X509_EXTENSION *)(argp1); + result = (X509_EXTENSION *)sk_x509_extension_pop(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_extension_num(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509_EXTENSION *arg1 = (struct stack_st_X509_EXTENSION *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_extension_num",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_extension_num" "', argument " "1"" of type '" "struct stack_st_X509_EXTENSION *""'"); + } + arg1 = (struct stack_st_X509_EXTENSION *)(argp1); + result = (int)sk_x509_extension_num(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_extension_value(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509_EXTENSION *arg1 = (struct stack_st_X509_EXTENSION *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + X509_EXTENSION *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"sk_x509_extension_value",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509_EXTENSION, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sk_x509_extension_value" "', argument " "1"" of type '" "struct stack_st_X509_EXTENSION *""'"); + } + arg1 = (struct stack_st_X509_EXTENSION *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "sk_x509_extension_value" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (X509_EXTENSION *)sk_x509_extension_value(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509_EXTENSION, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_ctx_get_app_data(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE_CTX *arg1 = (X509_STORE_CTX *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + void *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_ctx_get_app_data",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_ctx_get_app_data" "', argument " "1"" of type '" "X509_STORE_CTX *""'"); + } + arg1 = (X509_STORE_CTX *)(argp1); + result = (void *)x509_store_ctx_get_app_data(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_ctx_get_ex_data(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE_CTX *arg1 = (X509_STORE_CTX *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + void *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_ctx_get_ex_data",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE_CTX, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_ctx_get_ex_data" "', argument " "1"" of type '" "X509_STORE_CTX *""'"); + } + arg1 = (X509_STORE_CTX *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "x509_store_ctx_get_ex_data" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (void *)x509_store_ctx_get_ex_data(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_set_verify_cb__SWIG_1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_STORE *arg1 = (X509_STORE *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_store_set_verify_cb",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_STORE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_store_set_verify_cb" "', argument " "1"" of type '" "X509_STORE *""'"); + } + arg1 = (X509_STORE *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + x509_store_set_verify_cb(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_store_set_verify_cb(PyObject *self, PyObject *args) { + int argc; + PyObject *argv[3]; + int ii; + + if (!PyTuple_Check(args)) SWIG_fail; + argc = args ? (int)PyObject_Length(args) : 0; + for (ii = 0; (ii < 2) && (ii < argc); ii++) { + argv[ii] = PyTuple_GET_ITEM(args,ii); + } + if (argc == 2) { + int _v; + void *vptr = 0; + int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_X509_STORE, 0); + _v = SWIG_CheckState(res); + if (_v) { + void *ptr = 0; + int res = SWIG_ConvertFunctionPtr(argv[1], &ptr, SWIGTYPE_p_f_int_p_X509_STORE_CTX__int); + _v = SWIG_CheckState(res); + if (_v) { + return _wrap_x509_store_set_verify_cb__SWIG_0(self, args); + } + } + } + if (argc == 2) { + int _v; + void *vptr = 0; + int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_X509_STORE, 0); + _v = SWIG_CheckState(res); + if (_v) { + _v = (argv[1] != 0); + if (_v) { + return _wrap_x509_store_set_verify_cb__SWIG_1(self, args); + } + } + } + +fail: + SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number or type of arguments for overloaded function 'x509_store_set_verify_cb'.\n" + " Possible C/C++ prototypes are:\n" + " X509_STORE_set_verify_cb(X509_STORE *,int (*)(int,X509_STORE_CTX *))\n" + " x509_store_set_verify_cb(X509_STORE *,PyObject *)\n"); + return 0; +} + + +SWIGINTERN PyObject *_wrap_make_stack_from_der_sequence(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + struct stack_st_X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"make_stack_from_der_sequence",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + result = (struct stack_st_X509 *)make_stack_from_der_sequence(arg1); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_stack_st_X509, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_sk_x509_new_null(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509 *result = 0 ; + + result = (struct stack_st_X509 *)sk_x509_new_null(); + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_stack_st_X509, 0); + else { + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_get_der_encoding_stack(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509 *arg1 = (struct stack_st_X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"get_der_encoding_stack",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "get_der_encoding_stack" "', argument " "1"" of type '" "struct stack_st_X509 *""'"); + } + arg1 = (struct stack_st_X509 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)get_der_encoding_stack(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_x509_name_oneline(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509_NAME *arg1 = (X509_NAME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"x509_name_oneline",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509_NAME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "x509_name_oneline" "', argument " "1"" of type '" "X509_NAME *""'"); + } + arg1 = (X509_NAME *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)x509_name_oneline(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + { + if (result != NULL) + OPENSSL_free(result); + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_object_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_OBJECT *result = 0 ; + + result = (ASN1_OBJECT *)ASN1_OBJECT_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_object_create(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + unsigned char *arg2 = (unsigned char *) 0 ; + int arg3 ; + char *arg4 = (char *) 0 ; + char *arg5 = (char *) 0 ; + int val1 ; + int ecode1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int res4 ; + char *buf4 = 0 ; + int alloc4 = 0 ; + int res5 ; + char *buf5 = 0 ; + int alloc5 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + ASN1_OBJECT *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_object_create",5,5,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "asn1_object_create" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_unsigned_char, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "asn1_object_create" "', argument " "2"" of type '" "unsigned char *""'"); + } + arg2 = (unsigned char *)(argp2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "asn1_object_create" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "asn1_object_create" "', argument " "4"" of type '" "char const *""'"); + } + arg4 = (char *)(buf4); + res5 = SWIG_AsCharPtrAndSize(obj4, &buf5, NULL, &alloc5); + if (!SWIG_IsOK(res5)) { + SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "asn1_object_create" "', argument " "5"" of type '" "char const *""'"); + } + arg5 = (char *)(buf5); + result = (ASN1_OBJECT *)ASN1_OBJECT_create(arg1,arg2,arg3,(char const *)arg4,(char const *)arg5); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + if (alloc5 == SWIG_NEWOBJ) free((char*)buf5); + return resultobj; +fail: + if (alloc4 == SWIG_NEWOBJ) free((char*)buf4); + if (alloc5 == SWIG_NEWOBJ) free((char*)buf5); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_object_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_OBJECT *arg1 = (ASN1_OBJECT *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_object_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_object_free" "', argument " "1"" of type '" "ASN1_OBJECT *""'"); + } + arg1 = (ASN1_OBJECT *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ASN1_OBJECT_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_i2d_asn1_object(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_OBJECT *arg1 = (ASN1_OBJECT *) 0 ; + unsigned char **arg2 = (unsigned char **) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"i2d_asn1_object",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "i2d_asn1_object" "', argument " "1"" of type '" "ASN1_OBJECT *""'"); + } + arg1 = (ASN1_OBJECT *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_p_unsigned_char, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "i2d_asn1_object" "', argument " "2"" of type '" "unsigned char **""'"); + } + arg2 = (unsigned char **)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)i2d_ASN1_OBJECT(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_d2i_asn1_object(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_OBJECT **arg1 = (ASN1_OBJECT **) 0 ; + unsigned char **arg2 = (unsigned char **) 0 ; + long arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + long val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + ASN1_OBJECT *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"d2i_asn1_object",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_p_ASN1_OBJECT, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "d2i_asn1_object" "', argument " "1"" of type '" "ASN1_OBJECT **""'"); + } + arg1 = (ASN1_OBJECT **)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_p_unsigned_char, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "d2i_asn1_object" "', argument " "2"" of type '" "unsigned char const **""'"); + } + arg2 = (unsigned char **)(argp2); + ecode3 = SWIG_AsVal_long(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "d2i_asn1_object" "', argument " "3"" of type '" "long""'"); + } + arg3 = (long)(val3); + result = (ASN1_OBJECT *)d2i_ASN1_OBJECT(arg1,(unsigned char const **)arg2,arg3); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_bit_string_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_BIT_STRING *result = 0 ; + + result = (ASN1_BIT_STRING *)ASN1_BIT_STRING_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_BIT_STRING, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_string_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_STRING *result = 0 ; + + result = (ASN1_STRING *)ASN1_STRING_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_STRING, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_string_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_STRING *arg1 = (ASN1_STRING *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_string_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_STRING, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_string_free" "', argument " "1"" of type '" "ASN1_STRING *""'"); + } + arg1 = (ASN1_STRING *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ASN1_STRING_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_string_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_STRING *arg1 = (ASN1_STRING *) 0 ; + void *arg2 = (void *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_string_set",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_STRING, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_string_set" "', argument " "1"" of type '" "ASN1_STRING *""'"); + } + arg1 = (ASN1_STRING *)(argp1); + { + if (PyBytes_Check(obj1)) { + Py_ssize_t len; + + arg2 = PyBytes_AsString(obj1); + len = PyBytes_Size(obj1); + + if (len > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "object too large"); + return NULL; + } + arg3 = len; + } + else { + PyErr_SetString(PyExc_TypeError, "expected string"); + return NULL; + } + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ASN1_STRING_set(arg1,(void const *)arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_string_print(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + ASN1_STRING *arg2 = (ASN1_STRING *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_string_print",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_string_print" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ASN1_STRING, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "asn1_string_print" "', argument " "2"" of type '" "ASN1_STRING *""'"); + } + arg2 = (ASN1_STRING *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)ASN1_STRING_print(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_string_print_ex(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + ASN1_STRING *arg2 = (ASN1_STRING *) 0 ; + unsigned long arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + unsigned long val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_string_print_ex",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_string_print_ex" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ASN1_STRING, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "asn1_string_print_ex" "', argument " "2"" of type '" "ASN1_STRING *""'"); + } + arg2 = (ASN1_STRING *)(argp2); + ecode3 = SWIG_AsVal_unsigned_SS_long(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "asn1_string_print_ex" "', argument " "3"" of type '" "unsigned long""'"); + } + arg3 = (unsigned long)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)ASN1_STRING_print_ex(arg1,arg2,arg3); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_time_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_TIME *result = 0 ; + + result = (ASN1_TIME *)ASN1_TIME_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_time_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_TIME *arg1 = (ASN1_TIME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_time_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_time_free" "', argument " "1"" of type '" "ASN1_TIME *""'"); + } + arg1 = (ASN1_TIME *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ASN1_TIME_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_time_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_TIME *arg1 = (ASN1_TIME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_time_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_time_check" "', argument " "1"" of type '" "ASN1_TIME *""'"); + } + arg1 = (ASN1_TIME *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ASN1_TIME_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_time_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_TIME *arg1 = (ASN1_TIME *) 0 ; + long arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + long val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + ASN1_TIME *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_time_set",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_time_set" "', argument " "1"" of type '" "ASN1_TIME *""'"); + } + arg1 = (ASN1_TIME *)(argp1); + ecode2 = SWIG_AsVal_long(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "asn1_time_set" "', argument " "2"" of type '" "long""'"); + } + arg2 = (long)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (ASN1_TIME *)ASN1_TIME_set(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_time_set_string(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_TIME *arg1 = (ASN1_TIME *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_time_set_string",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_time_set_string" "', argument " "1"" of type '" "ASN1_TIME *""'"); + } + arg1 = (ASN1_TIME *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "asn1_time_set_string" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ASN1_TIME_set_string(arg1,(char const *)arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_time_print(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + ASN1_TIME *arg2 = (ASN1_TIME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_time_print",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_time_print" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "asn1_time_print" "', argument " "2"" of type '" "ASN1_TIME *""'"); + } + arg2 = (ASN1_TIME *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)ASN1_TIME_print(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_integer_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_INTEGER *result = 0 ; + + result = (ASN1_INTEGER *)ASN1_INTEGER_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_INTEGER, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_integer_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_INTEGER *arg1 = (ASN1_INTEGER *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_integer_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_INTEGER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_integer_free" "', argument " "1"" of type '" "ASN1_INTEGER *""'"); + } + arg1 = (ASN1_INTEGER *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + ASN1_INTEGER_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_integer_cmp(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_INTEGER *arg1 = (ASN1_INTEGER *) 0 ; + ASN1_INTEGER *arg2 = (ASN1_INTEGER *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_integer_cmp",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_INTEGER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_integer_cmp" "', argument " "1"" of type '" "ASN1_INTEGER *""'"); + } + arg1 = (ASN1_INTEGER *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_ASN1_INTEGER, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "asn1_integer_cmp" "', argument " "2"" of type '" "ASN1_INTEGER *""'"); + } + arg2 = (ASN1_INTEGER *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ASN1_INTEGER_cmp(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_time_type_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_TIME *arg1 = (ASN1_TIME *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_time_type_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_TIME, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_time_type_check" "', argument " "1"" of type '" "ASN1_TIME *""'"); + } + arg1 = (ASN1_TIME *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)asn1_time_type_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_integer_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_INTEGER *arg1 = (ASN1_INTEGER *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_integer_get",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_INTEGER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_integer_get" "', argument " "1"" of type '" "ASN1_INTEGER *""'"); + } + arg1 = (ASN1_INTEGER *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)asn1_integer_get(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_asn1_integer_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_INTEGER *arg1 = (ASN1_INTEGER *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"asn1_integer_set",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_INTEGER, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "asn1_integer_set" "', argument " "1"" of type '" "ASN1_INTEGER *""'"); + } + arg1 = (ASN1_INTEGER *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)asn1_integer_set(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *result = 0 ; + + result = (PKCS7 *)PKCS7_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_PKCS7, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_free" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + PKCS7_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_add_certificate(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + X509 *arg2 = (X509 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_add_certificate",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_add_certificate" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_add_certificate" "', argument " "2"" of type '" "X509 *""'"); + } + arg2 = (X509 *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + PKCS7_add_certificate(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__pkcs7_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_pkcs7_err""' of type '""PyObject *""'"); + } + _pkcs7_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__pkcs7_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_pkcs7_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN int Swig_var__smime_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_smime_err""' of type '""PyObject *""'"); + } + _smime_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__smime_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_smime_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + pkcs7_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_smime_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"smime_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + smime_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_decrypt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + X509 *arg3 = (X509 *) 0 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_decrypt",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_decrypt" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_decrypt" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "pkcs7_decrypt" "', argument " "3"" of type '" "X509 *""'"); + } + arg3 = (X509 *)(argp3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "pkcs7_decrypt" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)pkcs7_decrypt(arg1,arg2,arg3,arg4); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_encrypt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + struct stack_st_X509 *arg1 = (struct stack_st_X509 *) 0 ; + BIO *arg2 = (BIO *) 0 ; + EVP_CIPHER *arg3 = (EVP_CIPHER *) 0 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PKCS7 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_encrypt",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_encrypt" "', argument " "1"" of type '" "struct stack_st_X509 *""'"); + } + arg1 = (struct stack_st_X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_encrypt" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "pkcs7_encrypt" "', argument " "3"" of type '" "EVP_CIPHER *""'"); + } + arg3 = (EVP_CIPHER *)(argp3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "pkcs7_encrypt" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (PKCS7 *)pkcs7_encrypt(arg1,arg2,arg3,arg4); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_PKCS7, 0); + else { + m2_PyErr_Msg(_smime_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_sign1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + struct stack_st_X509 *arg3 = (struct stack_st_X509 *) 0 ; + BIO *arg4 = (BIO *) 0 ; + EVP_MD *arg5 = (EVP_MD *) 0 ; + int arg6 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + void *argp5 = 0 ; + int res5 = 0 ; + int val6 ; + int ecode6 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PyObject * obj5 = 0 ; + PKCS7 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_sign1",6,6,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_sign1" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_sign1" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "pkcs7_sign1" "', argument " "3"" of type '" "struct stack_st_X509 *""'"); + } + arg3 = (struct stack_st_X509 *)(argp3); + res4 = SWIG_ConvertPtr(obj3, &argp4,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "pkcs7_sign1" "', argument " "4"" of type '" "BIO *""'"); + } + arg4 = (BIO *)(argp4); + res5 = SWIG_ConvertPtr(obj4, &argp5,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res5)) { + SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "pkcs7_sign1" "', argument " "5"" of type '" "EVP_MD *""'"); + } + arg5 = (EVP_MD *)(argp5); + ecode6 = SWIG_AsVal_int(obj5, &val6); + if (!SWIG_IsOK(ecode6)) { + SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "pkcs7_sign1" "', argument " "6"" of type '" "int""'"); + } + arg6 = (int)(val6); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg4) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg5) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (PKCS7 *)pkcs7_sign1(arg1,arg2,arg3,arg4,arg5,arg6); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_PKCS7, 0); + else { + m2_PyErr_Msg(_smime_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_sign0(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + X509 *arg1 = (X509 *) 0 ; + EVP_PKEY *arg2 = (EVP_PKEY *) 0 ; + BIO *arg3 = (BIO *) 0 ; + EVP_MD *arg4 = (EVP_MD *) 0 ; + int arg5 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + int val5 ; + int ecode5 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PKCS7 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_sign0",5,5,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_X509, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_sign0" "', argument " "1"" of type '" "X509 *""'"); + } + arg1 = (X509 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_sign0" "', argument " "2"" of type '" "EVP_PKEY *""'"); + } + arg2 = (EVP_PKEY *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "pkcs7_sign0" "', argument " "3"" of type '" "BIO *""'"); + } + arg3 = (BIO *)(argp3); + res4 = SWIG_ConvertPtr(obj3, &argp4,SWIGTYPE_p_EVP_MD, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "pkcs7_sign0" "', argument " "4"" of type '" "EVP_MD *""'"); + } + arg4 = (EVP_MD *)(argp4); + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "pkcs7_sign0" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg4) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (PKCS7 *)pkcs7_sign0(arg1,arg2,arg3,arg4,arg5); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_PKCS7, 0); + else { + m2_PyErr_Msg(_smime_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_read_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PKCS7 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_read_bio",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_read_bio" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (PKCS7 *)pkcs7_read_bio(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_PKCS7, 0); + else { + m2_PyErr_Msg(_pkcs7_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_read_bio_der(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PKCS7 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_read_bio_der",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_read_bio_der" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (PKCS7 *)pkcs7_read_bio_der(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if (result != NULL) + resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_PKCS7, 0); + else { + m2_PyErr_Msg(_pkcs7_err); + resultobj = NULL; + } + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_verify1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + struct stack_st_X509 *arg2 = (struct stack_st_X509 *) 0 ; + X509_STORE *arg3 = (X509_STORE *) 0 ; + BIO *arg4 = (BIO *) 0 ; + int arg5 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + int val5 ; + int ecode5 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_verify1",5,5,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_verify1" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_verify1" "', argument " "2"" of type '" "struct stack_st_X509 *""'"); + } + arg2 = (struct stack_st_X509 *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_X509_STORE, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "pkcs7_verify1" "', argument " "3"" of type '" "X509_STORE *""'"); + } + arg3 = (X509_STORE *)(argp3); + res4 = SWIG_ConvertPtr(obj3, &argp4,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "pkcs7_verify1" "', argument " "4"" of type '" "BIO *""'"); + } + arg4 = (BIO *)(argp4); + ecode5 = SWIG_AsVal_int(obj4, &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "pkcs7_verify1" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg4) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)pkcs7_verify1(arg1,arg2,arg3,arg4,arg5); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_verify0(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + struct stack_st_X509 *arg2 = (struct stack_st_X509 *) 0 ; + X509_STORE *arg3 = (X509_STORE *) 0 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_verify0",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_verify0" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_verify0" "', argument " "2"" of type '" "struct stack_st_X509 *""'"); + } + arg2 = (struct stack_st_X509 *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_X509_STORE, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "pkcs7_verify0" "', argument " "3"" of type '" "X509_STORE *""'"); + } + arg3 = (X509_STORE *)(argp3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "pkcs7_verify0" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)pkcs7_verify0(arg1,arg2,arg3,arg4); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_smime_write_pkcs7_multi(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PKCS7 *arg2 = (PKCS7 *) 0 ; + BIO *arg3 = (BIO *) 0 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"smime_write_pkcs7_multi",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "smime_write_pkcs7_multi" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "smime_write_pkcs7_multi" "', argument " "2"" of type '" "PKCS7 *""'"); + } + arg2 = (PKCS7 *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "smime_write_pkcs7_multi" "', argument " "3"" of type '" "BIO *""'"); + } + arg3 = (BIO *)(argp3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "smime_write_pkcs7_multi" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)smime_write_pkcs7_multi(arg1,arg2,arg3,arg4); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_smime_write_pkcs7(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PKCS7 *arg2 = (PKCS7 *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"smime_write_pkcs7",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "smime_write_pkcs7" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "smime_write_pkcs7" "', argument " "2"" of type '" "PKCS7 *""'"); + } + arg2 = (PKCS7 *)(argp2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "smime_write_pkcs7" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)smime_write_pkcs7(arg1,arg2,arg3); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_smime_read_pkcs7(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"smime_read_pkcs7",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "smime_read_pkcs7" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)smime_read_pkcs7(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_write_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_write_bio",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_write_bio" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_write_bio" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)pkcs7_write_bio(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_write_bio_der(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_write_bio_der",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_write_bio_der" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_write_bio_der" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)pkcs7_write_bio_der(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_type_nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_type_nid",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_type_nid" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)pkcs7_type_nid(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_type_sn(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_type_sn",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_type_sn" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)pkcs7_type_sn(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_smime_crlf_copy(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"smime_crlf_copy",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "smime_crlf_copy" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "smime_crlf_copy" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)smime_crlf_copy(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_pkcs7_get0_signers(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PKCS7 *arg1 = (PKCS7 *) 0 ; + struct stack_st_X509 *arg2 = (struct stack_st_X509 *) 0 ; + int arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + struct stack_st_X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"pkcs7_get0_signers",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_PKCS7, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "pkcs7_get0_signers" "', argument " "1"" of type '" "PKCS7 *""'"); + } + arg1 = (PKCS7 *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_stack_st_X509, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "pkcs7_get0_signers" "', argument " "2"" of type '" "struct stack_st_X509 *""'"); + } + arg2 = (struct stack_st_X509 *)(argp2); + ecode3 = SWIG_AsVal_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "pkcs7_get0_signers" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (struct stack_st_X509 *)pkcs7_get0_signers(arg1,arg2,arg3); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_stack_st_X509, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__util_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_util_err""' of type '""PyObject *""'"); + } + _util_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__util_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_util_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_util_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"util_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + util_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_util_hex_to_string(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"util_hex_to_string",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + result = (PyObject *)util_hex_to_string(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_util_string_to_hex(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"util_string_to_hex",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + result = (PyObject *)util_string_to_hex(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *result = 0 ; + + result = (EC_KEY *)EC_KEY_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EC_KEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_free" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + EC_KEY_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_size(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_size",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_size" "', argument " "1"" of type '" "EC_KEY const *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ECDSA_size((EC_KEY const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_gen_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_gen_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_gen_key" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EC_KEY_generate_key(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_check_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_check_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_check_key" "', argument " "1"" of type '" "EC_KEY const *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)EC_KEY_check_key((EC_KEY const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int Swig_var__ec_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_ec_err""' of type '""PyObject *""'"); + } + _ec_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__ec_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_ec_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_ec_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ec_init",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + ec_init(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_get_builtin_curves(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *result = 0 ; + + result = (PyObject *)ec_get_builtin_curves(); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_new_by_curve_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + EC_KEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_new_by_curve_name",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ec_key_new_by_curve_name" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (EC_KEY *)ec_key_new_by_curve_name(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EC_KEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_get_public_der(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_get_public_der",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_get_public_der" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)ec_key_get_public_der(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_get_public_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_get_public_key",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_get_public_key" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)ec_key_get_public_key(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_read_pubkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + EC_KEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_read_pubkey",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_read_pubkey" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (EC_KEY *)ec_key_read_pubkey(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EC_KEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_write_pubkey(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + BIO *arg2 = (BIO *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_write_pubkey",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_write_pubkey" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ec_key_write_pubkey" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (int)ec_key_write_pubkey(arg1,arg2); + SWIG_PYTHON_THREAD_END_ALLOW; + } + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_read_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + BIO *arg1 = (BIO *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + EC_KEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_read_bio",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_read_bio" "', argument " "1"" of type '" "BIO *""'"); + } + arg1 = (BIO *)(argp1); + { + if (!PyCallable_Check(obj1)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (EC_KEY *)ec_key_read_bio(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EC_KEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_write_bio(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + BIO *arg2 = (BIO *) 0 ; + EVP_CIPHER *arg3 = (EVP_CIPHER *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_write_bio",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_write_bio" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ec_key_write_bio" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_EVP_CIPHER, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "ec_key_write_bio" "', argument " "3"" of type '" "EVP_CIPHER *""'"); + } + arg3 = (EVP_CIPHER *)(argp3); + { + if (!PyCallable_Check(obj3)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg4=obj3; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg4) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ec_key_write_bio(arg1,arg2,arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_write_bio_no_cipher(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + BIO *arg2 = (BIO *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_write_bio_no_cipher",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_write_bio_no_cipher" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_BIO, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ec_key_write_bio_no_cipher" "', argument " "2"" of type '" "BIO *""'"); + } + arg2 = (BIO *)(argp2); + { + if (!PyCallable_Check(obj2)) { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ec_key_write_bio_no_cipher(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ecdsa_sig_get_r(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ECDSA_SIG *arg1 = (ECDSA_SIG *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ecdsa_sig_get_r",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ECDSA_SIG, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ecdsa_sig_get_r" "', argument " "1"" of type '" "ECDSA_SIG *""'"); + } + arg1 = (ECDSA_SIG *)(argp1); + result = (PyObject *)ecdsa_sig_get_r(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ecdsa_sig_get_s(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ECDSA_SIG *arg1 = (ECDSA_SIG *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ecdsa_sig_get_s",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ECDSA_SIG, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ecdsa_sig_get_s" "', argument " "1"" of type '" "ECDSA_SIG *""'"); + } + arg1 = (ECDSA_SIG *)(argp1); + result = (PyObject *)ecdsa_sig_get_s(arg1); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ecdsa_sign(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ecdsa_sign",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ecdsa_sign" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)ecdsa_sign(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ecdsa_verify(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + PyObject *arg4 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ecdsa_verify",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ecdsa_verify" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + { + arg4=obj3; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ecdsa_verify(arg1,arg2,arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ecdsa_sign_asn1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ecdsa_sign_asn1",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ecdsa_sign_asn1" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + arg2=obj1; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)ecdsa_sign_asn1(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ecdsa_verify_asn1(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + PyObject *arg2 = (PyObject *) 0 ; + PyObject *arg3 = (PyObject *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ecdsa_verify_asn1",3,3,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ecdsa_verify_asn1" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + arg2=obj1; + } + { + arg3=obj2; + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ecdsa_verify_asn1(arg1,arg2,arg3); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ecdh_compute_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + EC_KEY *arg2 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ecdh_compute_key",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ecdh_compute_key" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ecdh_compute_key" "', argument " "2"" of type '" "EC_KEY *""'"); + } + arg2 = (EC_KEY *)(argp2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)ecdh_compute_key(arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_from_pubkey_der(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + EC_KEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_from_pubkey_der",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + result = (EC_KEY *)ec_key_from_pubkey_der(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EC_KEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_from_pubkey_params(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + PyObject *arg2 = (PyObject *) 0 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + EC_KEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_from_pubkey_params",2,2,&obj0,&obj1)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ec_key_from_pubkey_params" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + { + arg2=obj1; + } + result = (EC_KEY *)ec_key_from_pubkey_params(arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EC_KEY, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_keylen(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_keylen",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_keylen" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ec_key_keylen(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ec_key_type_check(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + EC_KEY *arg1 = (EC_KEY *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"ec_key_type_check",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_EC_KEY, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ec_key_type_check" "', argument " "1"" of type '" "EC_KEY *""'"); + } + arg1 = (EC_KEY *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ec_key_type_check(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_load_builtin_engines(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + ENGINE_load_builtin_engines(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_load_dynamic(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + ENGINE_load_dynamic(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_load_openssl(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + ENGINE_load_openssl(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_cleanup(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + + ENGINE_cleanup(); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *result = 0 ; + + result = (ENGINE *)ENGINE_new(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ENGINE, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_by_id(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + ENGINE *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"engine_by_id",1,1,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_by_id" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (ENGINE *)ENGINE_by_id((char const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ENGINE, 0 | 0 ); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"engine_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_free" "', argument " "1"" of type '" "ENGINE *""'"); + } + arg1 = (ENGINE *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ENGINE_free(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_init(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"engine_init",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_init" "', argument " "1"" of type '" "ENGINE *""'"); + } + arg1 = (ENGINE *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ENGINE_init(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_finish(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"engine_finish",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_finish" "', argument " "1"" of type '" "ENGINE *""'"); + } + arg1 = (ENGINE *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ENGINE_finish(arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_get_id(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"engine_get_id",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_get_id" "', argument " "1"" of type '" "ENGINE const *""'"); + } + arg1 = (ENGINE *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)ENGINE_get_id((ENGINE const *)arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_get_name(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"engine_get_name",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_get_name" "', argument " "1"" of type '" "ENGINE const *""'"); + } + arg1 = (ENGINE *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (char *)ENGINE_get_name((ENGINE const *)arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_ctrl_cmd_string(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + int arg4 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"engine_ctrl_cmd_string",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_ctrl_cmd_string" "', argument " "1"" of type '" "ENGINE *""'"); + } + arg1 = (ENGINE *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "engine_ctrl_cmd_string" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "engine_ctrl_cmd_string" "', argument " "3"" of type '" "char const *""'"); + } + arg3 = (char *)(buf3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "engine_ctrl_cmd_string" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ENGINE_ctrl_cmd_string(arg1,(char const *)arg2,(char const *)arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ui_openssl(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + UI_METHOD *result = 0 ; + + result = (UI_METHOD *)UI_OpenSSL(); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_UI_METHOD, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__cbd_t_password_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _cbd_t *arg1 = (_cbd_t *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"_cbd_t_password_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p__cbd_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_cbd_t_password_set" "', argument " "1"" of type '" "_cbd_t *""'"); + } + arg1 = (_cbd_t *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "_cbd_t_password_set" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + if (arg1->password) free((char*)arg1->password); + if (arg2) { + size_t size = strlen((const char *)(arg2)) + 1; + arg1->password = (char *)(char *)memcpy((char *)malloc((size)*sizeof(char)), (const char *)(arg2), sizeof(char)*(size)); + } else { + arg1->password = 0; + } + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap__cbd_t_password_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _cbd_t *arg1 = (_cbd_t *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + char *result = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p__cbd_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_cbd_t_password_get" "', argument " "1"" of type '" "_cbd_t *""'"); + } + arg1 = (_cbd_t *)(argp1); + result = (char *) ((arg1)->password); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap__cbd_t_prompt_set(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _cbd_t *arg1 = (_cbd_t *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj1 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"_cbd_t_prompt_set",1,1,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p__cbd_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_cbd_t_prompt_set" "', argument " "1"" of type '" "_cbd_t *""'"); + } + arg1 = (_cbd_t *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "_cbd_t_prompt_set" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + if (arg1->prompt) free((char*)arg1->prompt); + if (arg2) { + size_t size = strlen((const char *)(arg2)) + 1; + arg1->prompt = (char *)(char *)memcpy((char *)malloc((size)*sizeof(char)), (const char *)(arg2), sizeof(char)*(size)); + } else { + arg1->prompt = 0; + } + resultobj = SWIG_Py_Void(); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap__cbd_t_prompt_get(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _cbd_t *arg1 = (_cbd_t *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + char *result = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p__cbd_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_cbd_t_prompt_get" "', argument " "1"" of type '" "_cbd_t *""'"); + } + arg1 = (_cbd_t *)(argp1); + result = (char *) ((arg1)->prompt); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN int _wrap_new__cbd_t(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _cbd_t *result = 0 ; + + result = (_cbd_t *)calloc(1, sizeof(_cbd_t)); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p__cbd_t, SWIG_BUILTIN_INIT | 0 ); + return resultobj == Py_None ? -1 : 0; +fail: + return -1; +} + + +SWIGINTERN PyObject *_wrap_delete__cbd_t(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + _cbd_t *arg1 = (_cbd_t *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + + res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p__cbd_t, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete__cbd_t" "', argument " "1"" of type '" "_cbd_t *""'"); + } + arg1 = (_cbd_t *)(argp1); + free((char *) arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_pkcs11_data_new(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + void *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"engine_pkcs11_data_new",1,1,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_pkcs11_data_new" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + result = (void *)engine_pkcs11_data_new((char const *)arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_void, 0 | 0 ); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_pkcs11_data_free(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + void *arg1 = (void *) 0 ; + int res1 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"engine_pkcs11_data_free",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0,SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_pkcs11_data_free" "', argument " "1"" of type '" "void *""'"); + } + engine_pkcs11_data_free(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_load_private_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + char *arg2 = (char *) 0 ; + UI_METHOD *arg3 = (UI_METHOD *) 0 ; + void *arg4 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + int res4 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + EVP_PKEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"engine_load_private_key",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_load_private_key" "', argument " "1"" of type '" "ENGINE *""'"); + } + arg1 = (ENGINE *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "engine_load_private_key" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_UI_METHOD, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "engine_load_private_key" "', argument " "3"" of type '" "UI_METHOD *""'"); + } + arg3 = (UI_METHOD *)(argp3); + res4 = SWIG_ConvertPtr(obj3,SWIG_as_voidptrptr(&arg4), 0, 0); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "engine_load_private_key" "', argument " "4"" of type '" "void *""'"); + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (EVP_PKEY *)ENGINE_load_private_key(arg1,(char const *)arg2,arg3,arg4); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_load_public_key(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + char *arg2 = (char *) 0 ; + UI_METHOD *arg3 = (UI_METHOD *) 0 ; + void *arg4 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + int res4 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + EVP_PKEY *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"engine_load_public_key",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_load_public_key" "', argument " "1"" of type '" "ENGINE *""'"); + } + arg1 = (ENGINE *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "engine_load_public_key" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_UI_METHOD, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "engine_load_public_key" "', argument " "3"" of type '" "UI_METHOD *""'"); + } + arg3 = (UI_METHOD *)(argp3); + res4 = SWIG_ConvertPtr(obj3,SWIG_as_voidptrptr(&arg4), 0, 0); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "engine_load_public_key" "', argument " "4"" of type '" "void *""'"); + } + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (EVP_PKEY *)ENGINE_load_public_key(arg1,(char const *)arg2,arg3,arg4); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_EVP_PKEY, 0 | 0 ); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN int Swig_var__engine_err_set(PyObject *_val) { + { + void *argp = 0; + int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_PyObject, 0 ); + if (!SWIG_IsOK(res)) { + SWIG_exception_fail(SWIG_ArgError(res), "in variable '""_engine_err""' of type '""PyObject *""'"); + } + _engine_err = (PyObject *)(argp); + } + return 0; +fail: + return 1; +} + + +SWIGINTERN PyObject *Swig_var__engine_err_get(void) { + PyObject *pyobj = 0; + PyObject *self = 0; + + (void)self; + pyobj = SWIG_NewPointerObj(SWIG_as_voidptr(_engine_err), SWIGTYPE_p_PyObject, 0 ); + return pyobj; +} + + +SWIGINTERN PyObject *_wrap_engine_init_error(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + PyObject *arg1 = (PyObject *) 0 ; + PyObject * obj0 = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"engine_init_error",1,1,&obj0)) SWIG_fail; + { + arg1=obj0; + } + engine_init_error(arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_load_certificate(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + X509 *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"engine_load_certificate",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_load_certificate" "', argument " "1"" of type '" "ENGINE *""'"); + } + arg1 = (ENGINE *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "engine_load_certificate" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + { + if (!arg2) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (X509 *)engine_load_certificate(arg1,(char const *)arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_X509, 0 | 0 ); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_engine_set_default(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ENGINE *arg1 = (ENGINE *) 0 ; + unsigned int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + unsigned int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"engine_set_default",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ENGINE, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "engine_set_default" "', argument " "1"" of type '" "ENGINE *""'"); + } + arg1 = (ENGINE *)(argp1); + ecode2 = SWIG_AsVal_unsigned_SS_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "engine_set_default" "', argument " "2"" of type '" "unsigned int""'"); + } + arg2 = (unsigned int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)ENGINE_set_default(arg1,arg2); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_obj_nid2obj(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + ASN1_OBJECT *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"obj_nid2obj",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "obj_nid2obj" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (ASN1_OBJECT *)OBJ_nid2obj(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_obj_nid2ln(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"obj_nid2ln",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "obj_nid2ln" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (char *)OBJ_nid2ln(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_obj_nid2sn(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"obj_nid2sn",1,1,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "obj_nid2sn" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (char *)OBJ_nid2sn(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_obj_obj2nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_OBJECT *arg1 = (ASN1_OBJECT *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"obj_obj2nid",1,1,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "obj_obj2nid" "', argument " "1"" of type '" "ASN1_OBJECT const *""'"); + } + arg1 = (ASN1_OBJECT *)(argp1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)OBJ_obj2nid((ASN1_OBJECT const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_obj_ln2nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"obj_ln2nid",1,1,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "obj_ln2nid" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)OBJ_ln2nid((char const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_obj_sn2nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"obj_sn2nid",1,1,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "obj_sn2nid" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)OBJ_sn2nid((char const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_obj_txt2nid(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + PyObject * obj0 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"obj_txt2nid",1,1,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "obj_txt2nid" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)OBJ_txt2nid((char const *)arg1); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_obj_txt2obj(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int arg2 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + ASN1_OBJECT *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"obj_txt2obj",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "obj_txt2obj" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = (char *)(buf1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "obj_txt2obj" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (ASN1_OBJECT *)OBJ_txt2obj((char const *)arg1,arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap__obj_obj2txt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + char *arg1 = (char *) 0 ; + int arg2 ; + ASN1_OBJECT *arg3 = (ASN1_OBJECT *) 0 ; + int arg4 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + int val2 ; + int ecode2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + int val4 ; + int ecode4 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + int result; + + if(!PyArg_UnpackTuple(args,(char *)"_obj_obj2txt",4,4,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_obj_obj2txt" "', argument " "1"" of type '" "char *""'"); + } + arg1 = (char *)(buf1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "_obj_obj2txt" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "_obj_obj2txt" "', argument " "3"" of type '" "ASN1_OBJECT const *""'"); + } + arg3 = (ASN1_OBJECT *)(argp3); + ecode4 = SWIG_AsVal_int(obj3, &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "_obj_obj2txt" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + { + if (!arg3) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (int)OBJ_obj2txt(arg1,arg2,(ASN1_OBJECT const *)arg3,arg4); + { + resultobj=PyLong_FromLong(result); + if (PyErr_Occurred()) SWIG_fail; + } + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return resultobj; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_obj_obj2txt(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + ASN1_OBJECT *arg1 = (ASN1_OBJECT *) 0 ; + int arg2 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject *result = 0 ; + + if(!PyArg_UnpackTuple(args,(char *)"obj_obj2txt",2,2,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ASN1_OBJECT, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "obj_obj2txt" "', argument " "1"" of type '" "ASN1_OBJECT const *""'"); + } + arg1 = (ASN1_OBJECT *)(argp1); + ecode2 = SWIG_AsVal_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "obj_obj2txt" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + { + if (!arg1) { + SWIG_exception(SWIG_ValueError,"Received a NULL pointer."); + } + } + result = (PyObject *)obj_obj2txt((ASN1_OBJECT const *)arg1,arg2); + { + resultobj=result; + } + return resultobj; +fail: + return NULL; +} + + +static PyMethodDef SwigMethods[] = { + { (char *)"SWIG_PyInstanceMethod_New", (PyCFunction)SWIG_PyInstanceMethod_New, METH_O, NULL}, + { (char *)"sk_num", _wrap_sk_num, METH_VARARGS, NULL}, + { (char *)"sk_value", _wrap_sk_value, METH_VARARGS, NULL}, + { (char *)"sk_set", _wrap_sk_set, METH_VARARGS, NULL}, + { (char *)"sk_new", _wrap_sk_new, METH_VARARGS, NULL}, + { (char *)"sk_new_null", _wrap_sk_new_null, METH_VARARGS, NULL}, + { (char *)"sk_free", _wrap_sk_free, METH_VARARGS, NULL}, + { (char *)"sk_pop_free", _wrap_sk_pop_free, METH_VARARGS, NULL}, + { (char *)"sk_deep_copy", _wrap_sk_deep_copy, METH_VARARGS, NULL}, + { (char *)"sk_insert", _wrap_sk_insert, METH_VARARGS, NULL}, + { (char *)"sk_delete", _wrap_sk_delete, METH_VARARGS, NULL}, + { (char *)"sk_delete_ptr", _wrap_sk_delete_ptr, METH_VARARGS, NULL}, + { (char *)"sk_find", _wrap_sk_find, METH_VARARGS, NULL}, + { (char *)"sk_find_ex", _wrap_sk_find_ex, METH_VARARGS, NULL}, + { (char *)"sk_push", _wrap_sk_push, METH_VARARGS, NULL}, + { (char *)"sk_unshift", _wrap_sk_unshift, METH_VARARGS, NULL}, + { (char *)"sk_shift", _wrap_sk_shift, METH_VARARGS, NULL}, + { (char *)"sk_pop", _wrap_sk_pop, METH_VARARGS, NULL}, + { (char *)"sk_zero", _wrap_sk_zero, METH_VARARGS, NULL}, + { (char *)"sk_set_cmp_func", _wrap_sk_set_cmp_func, METH_VARARGS, NULL}, + { (char *)"sk_dup", _wrap_sk_dup, METH_VARARGS, NULL}, + { (char *)"sk_sort", _wrap_sk_sort, METH_VARARGS, NULL}, + { (char *)"sk_is_sorted", _wrap_sk_is_sorted, METH_VARARGS, NULL}, + { (char *)"threading_init", _wrap_threading_init, METH_VARARGS, NULL}, + { (char *)"threading_cleanup", _wrap_threading_cleanup, METH_VARARGS, NULL}, + { (char *)"lib_init", _wrap_lib_init, METH_VARARGS, NULL}, + { (char *)"bn_to_mpi", _wrap_bn_to_mpi, METH_VARARGS, NULL}, + { (char *)"mpi_to_bn", _wrap_mpi_to_bn, METH_VARARGS, NULL}, + { (char *)"bn_to_bin", _wrap_bn_to_bin, METH_VARARGS, NULL}, + { (char *)"bin_to_bn", _wrap_bin_to_bn, METH_VARARGS, NULL}, + { (char *)"bn_to_hex", _wrap_bn_to_hex, METH_VARARGS, NULL}, + { (char *)"hex_to_bn", _wrap_hex_to_bn, METH_VARARGS, NULL}, + { (char *)"dec_to_bn", _wrap_dec_to_bn, METH_VARARGS, NULL}, + { (char *)"err_print_errors", _wrap_err_print_errors, METH_VARARGS, NULL}, + { (char *)"err_get_error", _wrap_err_get_error, METH_VARARGS, NULL}, + { (char *)"err_peek_error", _wrap_err_peek_error, METH_VARARGS, NULL}, + { (char *)"err_lib_error_string", _wrap_err_lib_error_string, METH_VARARGS, NULL}, + { (char *)"err_func_error_string", _wrap_err_func_error_string, METH_VARARGS, NULL}, + { (char *)"err_reason_error_string", _wrap_err_reason_error_string, METH_VARARGS, NULL}, + { (char *)"bio_s_bio", _wrap_bio_s_bio, METH_VARARGS, NULL}, + { (char *)"bio_s_mem", _wrap_bio_s_mem, METH_VARARGS, NULL}, + { (char *)"bio_s_socket", _wrap_bio_s_socket, METH_VARARGS, NULL}, + { (char *)"bio_f_ssl", _wrap_bio_f_ssl, METH_VARARGS, NULL}, + { (char *)"bio_f_buffer", _wrap_bio_f_buffer, METH_VARARGS, NULL}, + { (char *)"bio_f_cipher", _wrap_bio_f_cipher, METH_VARARGS, NULL}, + { (char *)"bio_new", _wrap_bio_new, METH_VARARGS, NULL}, + { (char *)"bio_new_socket", _wrap_bio_new_socket, METH_VARARGS, NULL}, + { (char *)"bio_free_all", _wrap_bio_free_all, METH_VARARGS, NULL}, + { (char *)"bio_dup_chain", _wrap_bio_dup_chain, METH_VARARGS, NULL}, + { (char *)"bio_push", _wrap_bio_push, METH_VARARGS, NULL}, + { (char *)"bio_pop", _wrap_bio_pop, METH_VARARGS, NULL}, + { (char *)"bio_eof", _wrap_bio_eof, METH_VARARGS, NULL}, + { (char *)"pyfd_init", _wrap_pyfd_init, METH_VARARGS, NULL}, + { (char *)"bio_init", _wrap_bio_init, METH_VARARGS, NULL}, + { (char *)"bio_free", _wrap_bio_free, METH_VARARGS, NULL}, + { (char *)"bio_new_file", _wrap_bio_new_file, METH_VARARGS, NULL}, + { (char *)"bio_new_pyfile", _wrap_bio_new_pyfile, METH_VARARGS, NULL}, + { (char *)"bio_read", _wrap_bio_read, METH_VARARGS, NULL}, + { (char *)"bio_gets", _wrap_bio_gets, METH_VARARGS, NULL}, + { (char *)"bio_write", _wrap_bio_write, METH_VARARGS, NULL}, + { (char *)"bio_ctrl_pending", _wrap_bio_ctrl_pending, METH_VARARGS, NULL}, + { (char *)"bio_ctrl_wpending", _wrap_bio_ctrl_wpending, METH_VARARGS, NULL}, + { (char *)"bio_ctrl_get_write_guarantee", _wrap_bio_ctrl_get_write_guarantee, METH_VARARGS, NULL}, + { (char *)"bio_reset", _wrap_bio_reset, METH_VARARGS, NULL}, + { (char *)"bio_flush", _wrap_bio_flush, METH_VARARGS, NULL}, + { (char *)"bio_seek", _wrap_bio_seek, METH_VARARGS, NULL}, + { (char *)"bio_tell", _wrap_bio_tell, METH_VARARGS, NULL}, + { (char *)"bio_set_flags", _wrap_bio_set_flags, METH_VARARGS, NULL}, + { (char *)"bio_get_flags", _wrap_bio_get_flags, METH_VARARGS, NULL}, + { (char *)"bio_set_cipher", _wrap_bio_set_cipher, METH_VARARGS, NULL}, + { (char *)"bio_set_mem_eof_return", _wrap_bio_set_mem_eof_return, METH_VARARGS, NULL}, + { (char *)"bio_get_fd", _wrap_bio_get_fd, METH_VARARGS, NULL}, + { (char *)"bio_do_handshake", _wrap_bio_do_handshake, METH_VARARGS, NULL}, + { (char *)"bio_make_bio_pair", _wrap_bio_make_bio_pair, METH_VARARGS, NULL}, + { (char *)"bio_set_write_buf_size", _wrap_bio_set_write_buf_size, METH_VARARGS, NULL}, + { (char *)"bio_should_retry", _wrap_bio_should_retry, METH_VARARGS, NULL}, + { (char *)"bio_should_read", _wrap_bio_should_read, METH_VARARGS, NULL}, + { (char *)"bio_should_write", _wrap_bio_should_write, METH_VARARGS, NULL}, + { (char *)"BIO_meth_new", _wrap_BIO_meth_new, METH_VARARGS, NULL}, + { (char *)"BIO_meth_free", _wrap_BIO_meth_free, METH_VARARGS, NULL}, + { (char *)"pyfd_write", _wrap_pyfd_write, METH_VARARGS, NULL}, + { (char *)"pyfd_read", _wrap_pyfd_read, METH_VARARGS, NULL}, + { (char *)"pyfd_puts", _wrap_pyfd_puts, METH_VARARGS, NULL}, + { (char *)"pyfd_gets", _wrap_pyfd_gets, METH_VARARGS, NULL}, + { (char *)"pyfd_new", _wrap_pyfd_new, METH_VARARGS, NULL}, + { (char *)"pyfd_free", _wrap_pyfd_free, METH_VARARGS, NULL}, + { (char *)"pyfd_ctrl", _wrap_pyfd_ctrl, METH_VARARGS, NULL}, + { (char *)"bio_new_pyfd", _wrap_bio_new_pyfd, METH_VARARGS, NULL}, + { (char *)"bn_rand", _wrap_bn_rand, METH_VARARGS, NULL}, + { (char *)"bn_rand_range", _wrap_bn_rand_range, METH_VARARGS, NULL}, + { (char *)"rand_load_file", _wrap_rand_load_file, METH_VARARGS, NULL}, + { (char *)"rand_save_file", _wrap_rand_save_file, METH_VARARGS, NULL}, + { (char *)"rand_poll", _wrap_rand_poll, METH_VARARGS, NULL}, + { (char *)"rand_status", _wrap_rand_status, METH_VARARGS, NULL}, + { (char *)"rand_cleanup", _wrap_rand_cleanup, METH_VARARGS, NULL}, + { (char *)"rand_init", _wrap_rand_init, METH_VARARGS, NULL}, + { (char *)"rand_seed", _wrap_rand_seed, METH_VARARGS, NULL}, + { (char *)"rand_add", _wrap_rand_add, METH_VARARGS, NULL}, + { (char *)"rand_bytes", _wrap_rand_bytes, METH_VARARGS, NULL}, + { (char *)"rand_pseudo_bytes", _wrap_rand_pseudo_bytes, METH_VARARGS, NULL}, + { (char *)"rand_file_name", _wrap_rand_file_name, METH_VARARGS, NULL}, + { (char *)"rand_screen", _wrap_rand_screen, METH_VARARGS, NULL}, + { (char *)"rand_win32_event", _wrap_rand_win32_event, METH_VARARGS, NULL}, + { (char *)"md5", _wrap_md5, METH_VARARGS, NULL}, + { (char *)"sha1", _wrap_sha1, METH_VARARGS, NULL}, + { (char *)"ripemd160", _wrap_ripemd160, METH_VARARGS, NULL}, + { (char *)"sha224", _wrap_sha224, METH_VARARGS, NULL}, + { (char *)"sha256", _wrap_sha256, METH_VARARGS, NULL}, + { (char *)"sha384", _wrap_sha384, METH_VARARGS, NULL}, + { (char *)"sha512", _wrap_sha512, METH_VARARGS, NULL}, + { (char *)"digest_init", _wrap_digest_init, METH_VARARGS, NULL}, + { (char *)"des_ecb", _wrap_des_ecb, METH_VARARGS, NULL}, + { (char *)"des_ede_ecb", _wrap_des_ede_ecb, METH_VARARGS, NULL}, + { (char *)"des_ede3_ecb", _wrap_des_ede3_ecb, METH_VARARGS, NULL}, + { (char *)"des_cbc", _wrap_des_cbc, METH_VARARGS, NULL}, + { (char *)"des_ede_cbc", _wrap_des_ede_cbc, METH_VARARGS, NULL}, + { (char *)"des_ede3_cbc", _wrap_des_ede3_cbc, METH_VARARGS, NULL}, + { (char *)"des_cfb", _wrap_des_cfb, METH_VARARGS, NULL}, + { (char *)"des_ede_cfb", _wrap_des_ede_cfb, METH_VARARGS, NULL}, + { (char *)"des_ede3_cfb", _wrap_des_ede3_cfb, METH_VARARGS, NULL}, + { (char *)"des_ofb", _wrap_des_ofb, METH_VARARGS, NULL}, + { (char *)"des_ede_ofb", _wrap_des_ede_ofb, METH_VARARGS, NULL}, + { (char *)"des_ede3_ofb", _wrap_des_ede3_ofb, METH_VARARGS, NULL}, + { (char *)"bf_ecb", _wrap_bf_ecb, METH_VARARGS, NULL}, + { (char *)"bf_cbc", _wrap_bf_cbc, METH_VARARGS, NULL}, + { (char *)"bf_cfb", _wrap_bf_cfb, METH_VARARGS, NULL}, + { (char *)"bf_ofb", _wrap_bf_ofb, METH_VARARGS, NULL}, + { (char *)"cast5_ecb", _wrap_cast5_ecb, METH_VARARGS, NULL}, + { (char *)"cast5_cbc", _wrap_cast5_cbc, METH_VARARGS, NULL}, + { (char *)"cast5_cfb", _wrap_cast5_cfb, METH_VARARGS, NULL}, + { (char *)"cast5_ofb", _wrap_cast5_ofb, METH_VARARGS, NULL}, + { (char *)"rc4", _wrap_rc4, METH_VARARGS, NULL}, + { (char *)"rc2_40_cbc", _wrap_rc2_40_cbc, METH_VARARGS, NULL}, + { (char *)"aes_128_ecb", _wrap_aes_128_ecb, METH_VARARGS, NULL}, + { (char *)"aes_128_cbc", _wrap_aes_128_cbc, METH_VARARGS, NULL}, + { (char *)"aes_128_cfb", _wrap_aes_128_cfb, METH_VARARGS, NULL}, + { (char *)"aes_128_ofb", _wrap_aes_128_ofb, METH_VARARGS, NULL}, + { (char *)"aes_128_ctr", _wrap_aes_128_ctr, METH_VARARGS, NULL}, + { (char *)"aes_192_ecb", _wrap_aes_192_ecb, METH_VARARGS, NULL}, + { (char *)"aes_192_cbc", _wrap_aes_192_cbc, METH_VARARGS, NULL}, + { (char *)"aes_192_cfb", _wrap_aes_192_cfb, METH_VARARGS, NULL}, + { (char *)"aes_192_ofb", _wrap_aes_192_ofb, METH_VARARGS, NULL}, + { (char *)"aes_192_ctr", _wrap_aes_192_ctr, METH_VARARGS, NULL}, + { (char *)"aes_256_ecb", _wrap_aes_256_ecb, METH_VARARGS, NULL}, + { (char *)"aes_256_cbc", _wrap_aes_256_cbc, METH_VARARGS, NULL}, + { (char *)"aes_256_cfb", _wrap_aes_256_cfb, METH_VARARGS, NULL}, + { (char *)"aes_256_ofb", _wrap_aes_256_ofb, METH_VARARGS, NULL}, + { (char *)"aes_256_ctr", _wrap_aes_256_ctr, METH_VARARGS, NULL}, + { (char *)"cipher_set_padding", _wrap_cipher_set_padding, METH_VARARGS, NULL}, + { (char *)"pkey_free", _wrap_pkey_free, METH_VARARGS, NULL}, + { (char *)"pkey_assign", _wrap_pkey_assign, METH_VARARGS, NULL}, + { (char *)"pkey_assign_ec", _wrap_pkey_assign_ec, METH_VARARGS, NULL}, + { (char *)"pkey_set1_rsa", _wrap_pkey_set1_rsa, METH_VARARGS, NULL}, + { (char *)"sign_init", _wrap_sign_init, METH_VARARGS, NULL}, + { (char *)"verify_init", _wrap_verify_init, METH_VARARGS, NULL}, + { (char *)"pkey_size", _wrap_pkey_size, METH_VARARGS, NULL}, + { (char *)"evp_init", _wrap_evp_init, METH_VARARGS, NULL}, + { (char *)"pkey_get1_rsa", _wrap_pkey_get1_rsa, METH_VARARGS, NULL}, + { (char *)"pkcs5_pbkdf2_hmac_sha1", _wrap_pkcs5_pbkdf2_hmac_sha1, METH_VARARGS, NULL}, + { (char *)"md_ctx_new", _wrap_md_ctx_new, METH_VARARGS, NULL}, + { (char *)"md_ctx_free", _wrap_md_ctx_free, METH_VARARGS, NULL}, + { (char *)"digest_update", _wrap_digest_update, METH_VARARGS, NULL}, + { (char *)"digest_final", _wrap_digest_final, METH_VARARGS, NULL}, + { (char *)"hmac_ctx_new", _wrap_hmac_ctx_new, METH_VARARGS, NULL}, + { (char *)"hmac_ctx_free", _wrap_hmac_ctx_free, METH_VARARGS, NULL}, + { (char *)"hmac_init", _wrap_hmac_init, METH_VARARGS, NULL}, + { (char *)"hmac_update", _wrap_hmac_update, METH_VARARGS, NULL}, + { (char *)"hmac_final", _wrap_hmac_final, METH_VARARGS, NULL}, + { (char *)"hmac", _wrap_hmac, METH_VARARGS, NULL}, + { (char *)"cipher_ctx_new", _wrap_cipher_ctx_new, METH_VARARGS, NULL}, + { (char *)"cipher_ctx_free", _wrap_cipher_ctx_free, METH_VARARGS, NULL}, + { (char *)"bytes_to_key", _wrap_bytes_to_key, METH_VARARGS, NULL}, + { (char *)"cipher_init", _wrap_cipher_init, METH_VARARGS, NULL}, + { (char *)"cipher_update", _wrap_cipher_update, METH_VARARGS, NULL}, + { (char *)"cipher_final", _wrap_cipher_final, METH_VARARGS, NULL}, + { (char *)"sign_update", _wrap_sign_update, METH_VARARGS, NULL}, + { (char *)"sign_final", _wrap_sign_final, METH_VARARGS, NULL}, + { (char *)"verify_update", _wrap_verify_update, METH_VARARGS, NULL}, + { (char *)"verify_final", _wrap_verify_final, METH_VARARGS, NULL}, + { (char *)"get_digestbyname", _wrap_get_digestbyname, METH_VARARGS, NULL}, + { (char *)"pkey_write_pem_no_cipher", _wrap_pkey_write_pem_no_cipher, METH_VARARGS, NULL}, + { (char *)"pkey_write_pem", _wrap_pkey_write_pem, METH_VARARGS, NULL}, + { (char *)"pkey_new", _wrap_pkey_new, METH_VARARGS, NULL}, + { (char *)"pkey_read_pem", _wrap_pkey_read_pem, METH_VARARGS, NULL}, + { (char *)"pkey_read_pem_pubkey", _wrap_pkey_read_pem_pubkey, METH_VARARGS, NULL}, + { (char *)"pkey_assign_rsa", _wrap_pkey_assign_rsa, METH_VARARGS, NULL}, + { (char *)"pkey_as_der", _wrap_pkey_as_der, METH_VARARGS, NULL}, + { (char *)"pkey_get_modulus", _wrap_pkey_get_modulus, METH_VARARGS, NULL}, + { (char *)"aes_new", _wrap_aes_new, METH_VARARGS, NULL}, + { (char *)"AES_free", _wrap_AES_free, METH_VARARGS, NULL}, + { (char *)"AES_set_key", _wrap_AES_set_key, METH_VARARGS, NULL}, + { (char *)"AES_crypt", _wrap_AES_crypt, METH_VARARGS, NULL}, + { (char *)"AES_type_check", _wrap_AES_type_check, METH_VARARGS, NULL}, + { (char *)"rc4_new", _wrap_rc4_new, METH_VARARGS, NULL}, + { (char *)"rc4_free", _wrap_rc4_free, METH_VARARGS, NULL}, + { (char *)"rc4_set_key", _wrap_rc4_set_key, METH_VARARGS, NULL}, + { (char *)"rc4_update", _wrap_rc4_update, METH_VARARGS, NULL}, + { (char *)"rc4_type_check", _wrap_rc4_type_check, METH_VARARGS, NULL}, + { (char *)"dh_new", _wrap_dh_new, METH_VARARGS, NULL}, + { (char *)"dh_free", _wrap_dh_free, METH_VARARGS, NULL}, + { (char *)"dh_size", _wrap_dh_size, METH_VARARGS, NULL}, + { (char *)"dh_generate_key", _wrap_dh_generate_key, METH_VARARGS, NULL}, + { (char *)"dhparams_print", _wrap_dhparams_print, METH_VARARGS, NULL}, + { (char *)"dh_init", _wrap_dh_init, METH_VARARGS, NULL}, + { (char *)"dh_type_check", _wrap_dh_type_check, METH_VARARGS, NULL}, + { (char *)"dh_read_parameters", _wrap_dh_read_parameters, METH_VARARGS, NULL}, + { (char *)"dh_generate_parameters", _wrap_dh_generate_parameters, METH_VARARGS, NULL}, + { (char *)"dh_check", _wrap_dh_check, METH_VARARGS, NULL}, + { (char *)"dh_compute_key", _wrap_dh_compute_key, METH_VARARGS, NULL}, + { (char *)"dh_get_p", _wrap_dh_get_p, METH_VARARGS, NULL}, + { (char *)"dh_get_g", _wrap_dh_get_g, METH_VARARGS, NULL}, + { (char *)"dh_get_pub", _wrap_dh_get_pub, METH_VARARGS, NULL}, + { (char *)"dh_get_priv", _wrap_dh_get_priv, METH_VARARGS, NULL}, + { (char *)"dh_set_pg", _wrap_dh_set_pg, METH_VARARGS, NULL}, + { (char *)"rsa_size", _wrap_rsa_size, METH_VARARGS, NULL}, + { (char *)"rsa_new", _wrap_rsa_new, METH_VARARGS, NULL}, + { (char *)"rsa_free", _wrap_rsa_free, METH_VARARGS, NULL}, + { (char *)"rsa_check_key", _wrap_rsa_check_key, METH_VARARGS, NULL}, + { (char *)"rsa_init", _wrap_rsa_init, METH_VARARGS, NULL}, + { (char *)"rsa_read_key", _wrap_rsa_read_key, METH_VARARGS, NULL}, + { (char *)"rsa_write_key", _wrap_rsa_write_key, METH_VARARGS, NULL}, + { (char *)"rsa_write_key_no_cipher", _wrap_rsa_write_key_no_cipher, METH_VARARGS, NULL}, + { (char *)"rsa_read_pub_key", _wrap_rsa_read_pub_key, METH_VARARGS, NULL}, + { (char *)"rsa_write_pub_key", _wrap_rsa_write_pub_key, METH_VARARGS, NULL}, + { (char *)"rsa_get_e", _wrap_rsa_get_e, METH_VARARGS, NULL}, + { (char *)"rsa_get_n", _wrap_rsa_get_n, METH_VARARGS, NULL}, + { (char *)"rsa_set_e", _wrap_rsa_set_e, METH_VARARGS, NULL}, + { (char *)"rsa_set_n", _wrap_rsa_set_n, METH_VARARGS, NULL}, + { (char *)"rsa_set_en", _wrap_rsa_set_en, METH_VARARGS, NULL}, + { (char *)"PyObject_Bin_AsBIGNUM", _wrap_PyObject_Bin_AsBIGNUM, METH_VARARGS, NULL}, + { (char *)"rsa_set_en_bin", _wrap_rsa_set_en_bin, METH_VARARGS, NULL}, + { (char *)"rsa_private_encrypt", _wrap_rsa_private_encrypt, METH_VARARGS, NULL}, + { (char *)"rsa_public_decrypt", _wrap_rsa_public_decrypt, METH_VARARGS, NULL}, + { (char *)"rsa_public_encrypt", _wrap_rsa_public_encrypt, METH_VARARGS, NULL}, + { (char *)"rsa_private_decrypt", _wrap_rsa_private_decrypt, METH_VARARGS, NULL}, + { (char *)"rsa_padding_add_pkcs1_pss", _wrap_rsa_padding_add_pkcs1_pss, METH_VARARGS, NULL}, + { (char *)"rsa_verify_pkcs1_pss", _wrap_rsa_verify_pkcs1_pss, METH_VARARGS, NULL}, + { (char *)"rsa_sign", _wrap_rsa_sign, METH_VARARGS, NULL}, + { (char *)"rsa_verify", _wrap_rsa_verify, METH_VARARGS, NULL}, + { (char *)"rsa_generate_key", _wrap_rsa_generate_key, METH_VARARGS, NULL}, + { (char *)"rsa_type_check", _wrap_rsa_type_check, METH_VARARGS, NULL}, + { (char *)"rsa_check_pub_key", _wrap_rsa_check_pub_key, METH_VARARGS, NULL}, + { (char *)"rsa_write_key_der", _wrap_rsa_write_key_der, METH_VARARGS, NULL}, + { (char *)"dsa_new", _wrap_dsa_new, METH_VARARGS, NULL}, + { (char *)"dsa_free", _wrap_dsa_free, METH_VARARGS, NULL}, + { (char *)"dsa_size", _wrap_dsa_size, METH_VARARGS, NULL}, + { (char *)"dsa_gen_key", _wrap_dsa_gen_key, METH_VARARGS, NULL}, + { (char *)"dsa_init", _wrap_dsa_init, METH_VARARGS, NULL}, + { (char *)"dsa_generate_parameters", _wrap_dsa_generate_parameters, METH_VARARGS, NULL}, + { (char *)"dsa_read_params", _wrap_dsa_read_params, METH_VARARGS, NULL}, + { (char *)"dsa_read_key", _wrap_dsa_read_key, METH_VARARGS, NULL}, + { (char *)"dsa_read_pub_key", _wrap_dsa_read_pub_key, METH_VARARGS, NULL}, + { (char *)"dsa_get_p", _wrap_dsa_get_p, METH_VARARGS, NULL}, + { (char *)"dsa_get_q", _wrap_dsa_get_q, METH_VARARGS, NULL}, + { (char *)"dsa_get_g", _wrap_dsa_get_g, METH_VARARGS, NULL}, + { (char *)"dsa_get_pub", _wrap_dsa_get_pub, METH_VARARGS, NULL}, + { (char *)"dsa_get_priv", _wrap_dsa_get_priv, METH_VARARGS, NULL}, + { (char *)"dsa_set_pqg", _wrap_dsa_set_pqg, METH_VARARGS, NULL}, + { (char *)"dsa_set_pub", _wrap_dsa_set_pub, METH_VARARGS, NULL}, + { (char *)"dsa_write_params_bio", _wrap_dsa_write_params_bio, METH_VARARGS, NULL}, + { (char *)"dsa_write_key_bio", _wrap_dsa_write_key_bio, METH_VARARGS, NULL}, + { (char *)"dsa_write_key_bio_no_cipher", _wrap_dsa_write_key_bio_no_cipher, METH_VARARGS, NULL}, + { (char *)"dsa_write_pub_key_bio", _wrap_dsa_write_pub_key_bio, METH_VARARGS, NULL}, + { (char *)"dsa_sign", _wrap_dsa_sign, METH_VARARGS, NULL}, + { (char *)"dsa_verify", _wrap_dsa_verify, METH_VARARGS, NULL}, + { (char *)"dsa_sign_asn1", _wrap_dsa_sign_asn1, METH_VARARGS, NULL}, + { (char *)"dsa_verify_asn1", _wrap_dsa_verify_asn1, METH_VARARGS, NULL}, + { (char *)"dsa_check_key", _wrap_dsa_check_key, METH_VARARGS, NULL}, + { (char *)"dsa_check_pub_key", _wrap_dsa_check_pub_key, METH_VARARGS, NULL}, + { (char *)"dsa_keylen", _wrap_dsa_keylen, METH_VARARGS, NULL}, + { (char *)"dsa_type_check", _wrap_dsa_type_check, METH_VARARGS, NULL}, + { (char *)"ssl_get_ciphers", _wrap_ssl_get_ciphers, METH_VARARGS, NULL}, + { (char *)"ssl_get_version", _wrap_ssl_get_version, METH_VARARGS, NULL}, + { (char *)"ssl_get_error", _wrap_ssl_get_error, METH_VARARGS, NULL}, + { (char *)"ssl_get_state", _wrap_ssl_get_state, METH_VARARGS, NULL}, + { (char *)"ssl_get_state_v", _wrap_ssl_get_state_v, METH_VARARGS, NULL}, + { (char *)"ssl_get_alert_type", _wrap_ssl_get_alert_type, METH_VARARGS, NULL}, + { (char *)"ssl_get_alert_type_v", _wrap_ssl_get_alert_type_v, METH_VARARGS, NULL}, + { (char *)"ssl_get_alert_desc", _wrap_ssl_get_alert_desc, METH_VARARGS, NULL}, + { (char *)"ssl_get_alert_desc_v", _wrap_ssl_get_alert_desc_v, METH_VARARGS, NULL}, + { (char *)"sslv23_method", _wrap_sslv23_method, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_new", _wrap_ssl_ctx_new, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_free", _wrap_ssl_ctx_free, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_verify_depth", _wrap_ssl_ctx_set_verify_depth, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_get_verify_depth", _wrap_ssl_ctx_get_verify_depth, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_get_verify_mode", _wrap_ssl_ctx_get_verify_mode, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_cipher_list", _wrap_ssl_ctx_set_cipher_list, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_add_session", _wrap_ssl_ctx_add_session, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_remove_session", _wrap_ssl_ctx_remove_session, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_session_timeout", _wrap_ssl_ctx_set_session_timeout, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_get_session_timeout", _wrap_ssl_ctx_get_session_timeout, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_get_cert_store", _wrap_ssl_ctx_get_cert_store, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_default_verify_paths", _wrap_ssl_ctx_set_default_verify_paths, METH_VARARGS, NULL}, + { (char *)"ssl_get_ex_data_x509_store_ctx_idx", _wrap_ssl_get_ex_data_x509_store_ctx_idx, METH_VARARGS, NULL}, + { (char *)"bio_new_ssl", _wrap_bio_new_ssl, METH_VARARGS, NULL}, + { (char *)"ssl_new", _wrap_ssl_new, METH_VARARGS, NULL}, + { (char *)"ssl_free", _wrap_ssl_free, METH_VARARGS, NULL}, + { (char *)"ssl_dup", _wrap_ssl_dup, METH_VARARGS, NULL}, + { (char *)"ssl_set_bio", _wrap_ssl_set_bio, METH_VARARGS, NULL}, + { (char *)"ssl_set_accept_state", _wrap_ssl_set_accept_state, METH_VARARGS, NULL}, + { (char *)"ssl_set_connect_state", _wrap_ssl_set_connect_state, METH_VARARGS, NULL}, + { (char *)"ssl_get_shutdown", _wrap_ssl_get_shutdown, METH_VARARGS, NULL}, + { (char *)"ssl_set_shutdown", _wrap_ssl_set_shutdown, METH_VARARGS, NULL}, + { (char *)"ssl_shutdown", _wrap_ssl_shutdown, METH_VARARGS, NULL}, + { (char *)"ssl_clear", _wrap_ssl_clear, METH_VARARGS, NULL}, + { (char *)"ssl_do_handshake", _wrap_ssl_do_handshake, METH_VARARGS, NULL}, + { (char *)"ssl_renegotiate", _wrap_ssl_renegotiate, METH_VARARGS, NULL}, + { (char *)"ssl_pending", _wrap_ssl_pending, METH_VARARGS, NULL}, + { (char *)"ssl_get_peer_cert", _wrap_ssl_get_peer_cert, METH_VARARGS, NULL}, + { (char *)"ssl_get_current_cipher", _wrap_ssl_get_current_cipher, METH_VARARGS, NULL}, + { (char *)"ssl_get_verify_mode", _wrap_ssl_get_verify_mode, METH_VARARGS, NULL}, + { (char *)"ssl_get_verify_depth", _wrap_ssl_get_verify_depth, METH_VARARGS, NULL}, + { (char *)"ssl_get_verify_result", _wrap_ssl_get_verify_result, METH_VARARGS, NULL}, + { (char *)"ssl_get_ssl_ctx", _wrap_ssl_get_ssl_ctx, METH_VARARGS, NULL}, + { (char *)"ssl_get_default_session_timeout", _wrap_ssl_get_default_session_timeout, METH_VARARGS, NULL}, + { (char *)"ssl_set_cipher_list", _wrap_ssl_set_cipher_list, METH_VARARGS, NULL}, + { (char *)"ssl_get_cipher_list", _wrap_ssl_get_cipher_list, METH_VARARGS, NULL}, + { (char *)"ssl_cipher_get_name", _wrap_ssl_cipher_get_name, METH_VARARGS, NULL}, + { (char *)"ssl_cipher_get_version", _wrap_ssl_cipher_get_version, METH_VARARGS, NULL}, + { (char *)"ssl_get_session", _wrap_ssl_get_session, METH_VARARGS, NULL}, + { (char *)"ssl_get1_session", _wrap_ssl_get1_session, METH_VARARGS, NULL}, + { (char *)"ssl_set_session", _wrap_ssl_set_session, METH_VARARGS, NULL}, + { (char *)"ssl_session_free", _wrap_ssl_session_free, METH_VARARGS, NULL}, + { (char *)"ssl_session_print", _wrap_ssl_session_print, METH_VARARGS, NULL}, + { (char *)"ssl_session_set_timeout", _wrap_ssl_session_set_timeout, METH_VARARGS, NULL}, + { (char *)"ssl_session_get_timeout", _wrap_ssl_session_get_timeout, METH_VARARGS, NULL}, + { (char *)"ssl_accept", _wrap_ssl_accept, METH_VARARGS, NULL}, + { (char *)"ssl_connect", _wrap_ssl_connect, METH_VARARGS, NULL}, + { (char *)"ssl_read", _wrap_ssl_read, METH_VARARGS, NULL}, + { (char *)"ssl_write", _wrap_ssl_write, METH_VARARGS, NULL}, + { (char *)"ssl_init", _wrap_ssl_init, METH_VARARGS, NULL}, + { (char *)"tlsv1_method", _wrap_tlsv1_method, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_passphrase_callback", _wrap_ssl_ctx_passphrase_callback, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_use_x509", _wrap_ssl_ctx_use_x509, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_use_cert", _wrap_ssl_ctx_use_cert, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_use_cert_chain", _wrap_ssl_ctx_use_cert_chain, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_use_privkey", _wrap_ssl_ctx_use_privkey, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_use_rsa_privkey", _wrap_ssl_ctx_use_rsa_privkey, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_use_pkey_privkey", _wrap_ssl_ctx_use_pkey_privkey, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_check_privkey", _wrap_ssl_ctx_check_privkey, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_client_CA_list_from_file", _wrap_ssl_ctx_set_client_CA_list_from_file, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_verify_default", _wrap_ssl_ctx_set_verify_default, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_verify", _wrap_ssl_ctx_set_verify, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_session_id_context", _wrap_ssl_ctx_set_session_id_context, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_info_callback", _wrap_ssl_ctx_set_info_callback, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_tmp_dh", _wrap_ssl_ctx_set_tmp_dh, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_tmp_dh_callback", _wrap_ssl_ctx_set_tmp_dh_callback, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_tmp_rsa", _wrap_ssl_ctx_set_tmp_rsa, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_tmp_rsa_callback", _wrap_ssl_ctx_set_tmp_rsa_callback, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_load_verify_locations", _wrap_ssl_ctx_load_verify_locations, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_options", _wrap_ssl_ctx_set_options, METH_VARARGS, NULL}, + { (char *)"bio_set_ssl", _wrap_bio_set_ssl, METH_VARARGS, NULL}, + { (char *)"ssl_set_mode", _wrap_ssl_set_mode, METH_VARARGS, NULL}, + { (char *)"ssl_get_mode", _wrap_ssl_get_mode, METH_VARARGS, NULL}, + { (char *)"ssl_set_tlsext_host_name", _wrap_ssl_set_tlsext_host_name, METH_VARARGS, NULL}, + { (char *)"ssl_set_client_CA_list_from_file", _wrap_ssl_set_client_CA_list_from_file, METH_VARARGS, NULL}, + { (char *)"ssl_set_client_CA_list_from_context", _wrap_ssl_set_client_CA_list_from_context, METH_VARARGS, NULL}, + { (char *)"ssl_set_session_id_context", _wrap_ssl_set_session_id_context, METH_VARARGS, NULL}, + { (char *)"ssl_set_fd", _wrap_ssl_set_fd, METH_VARARGS, NULL}, + { (char *)"ssl_set_shutdown1", _wrap_ssl_set_shutdown1, METH_VARARGS, NULL}, + { (char *)"ssl_read_nbio", _wrap_ssl_read_nbio, METH_VARARGS, NULL}, + { (char *)"ssl_write_nbio", _wrap_ssl_write_nbio, METH_VARARGS, NULL}, + { (char *)"ssl_cipher_get_bits", _wrap_ssl_cipher_get_bits, METH_VARARGS, NULL}, + { (char *)"sk_ssl_cipher_num", _wrap_sk_ssl_cipher_num, METH_VARARGS, NULL}, + { (char *)"sk_ssl_cipher_value", _wrap_sk_ssl_cipher_value, METH_VARARGS, NULL}, + { (char *)"ssl_get_peer_cert_chain", _wrap_ssl_get_peer_cert_chain, METH_VARARGS, NULL}, + { (char *)"sk_x509_num", _wrap_sk_x509_num, METH_VARARGS, NULL}, + { (char *)"sk_x509_value", _wrap_sk_x509_value, METH_VARARGS, NULL}, + { (char *)"i2d_ssl_session", _wrap_i2d_ssl_session, METH_VARARGS, NULL}, + { (char *)"ssl_session_read_pem", _wrap_ssl_session_read_pem, METH_VARARGS, NULL}, + { (char *)"ssl_session_write_pem", _wrap_ssl_session_write_pem, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_session_cache_mode", _wrap_ssl_ctx_set_session_cache_mode, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_get_session_cache_mode", _wrap_ssl_ctx_get_session_cache_mode, METH_VARARGS, NULL}, + { (char *)"ssl_ctx_set_cache_size", _wrap_ssl_ctx_set_cache_size, METH_VARARGS, NULL}, + { (char *)"ssl_is_init_finished", _wrap_ssl_is_init_finished, METH_VARARGS, NULL}, + { (char *)"x509_check_ca", _wrap_x509_check_ca, METH_VARARGS, NULL}, + { (char *)"x509_new", _wrap_x509_new, METH_VARARGS, NULL}, + { (char *)"x509_dup", _wrap_x509_dup, METH_VARARGS, NULL}, + { (char *)"x509_free", _wrap_x509_free, METH_VARARGS, NULL}, + { (char *)"x509_crl_free", _wrap_x509_crl_free, METH_VARARGS, NULL}, + { (char *)"x509_crl_new", _wrap_x509_crl_new, METH_VARARGS, NULL}, + { (char *)"x509_print", _wrap_x509_print, METH_VARARGS, NULL}, + { (char *)"x509_crl_print", _wrap_x509_crl_print, METH_VARARGS, NULL}, + { (char *)"x509_get_serial_number", _wrap_x509_get_serial_number, METH_VARARGS, NULL}, + { (char *)"x509_set_serial_number", _wrap_x509_set_serial_number, METH_VARARGS, NULL}, + { (char *)"x509_get_pubkey", _wrap_x509_get_pubkey, METH_VARARGS, NULL}, + { (char *)"x509_set_pubkey", _wrap_x509_set_pubkey, METH_VARARGS, NULL}, + { (char *)"x509_get_issuer_name", _wrap_x509_get_issuer_name, METH_VARARGS, NULL}, + { (char *)"x509_set_issuer_name", _wrap_x509_set_issuer_name, METH_VARARGS, NULL}, + { (char *)"x509_get_subject_name", _wrap_x509_get_subject_name, METH_VARARGS, NULL}, + { (char *)"x509_set_subject_name", _wrap_x509_set_subject_name, METH_VARARGS, NULL}, + { (char *)"x509_cmp_current_time", _wrap_x509_cmp_current_time, METH_VARARGS, NULL}, + { (char *)"x509_check_purpose", _wrap_x509_check_purpose, METH_VARARGS, NULL}, + { (char *)"x509_check_trust", _wrap_x509_check_trust, METH_VARARGS, NULL}, + { (char *)"x509_write_pem", _wrap_x509_write_pem, METH_VARARGS, NULL}, + { (char *)"x509_write_pem_file", _wrap_x509_write_pem_file, METH_VARARGS, NULL}, + { (char *)"x509_verify", _wrap_x509_verify, METH_VARARGS, NULL}, + { (char *)"x509_get_verify_error", _wrap_x509_get_verify_error, METH_VARARGS, NULL}, + { (char *)"x509_add_ext", _wrap_x509_add_ext, METH_VARARGS, NULL}, + { (char *)"x509_get_ext_count", _wrap_x509_get_ext_count, METH_VARARGS, NULL}, + { (char *)"x509_get_ext", _wrap_x509_get_ext, METH_VARARGS, NULL}, + { (char *)"x509_ext_print", _wrap_x509_ext_print, METH_VARARGS, NULL}, + { (char *)"x509_name_new", _wrap_x509_name_new, METH_VARARGS, NULL}, + { (char *)"x509_name_free", _wrap_x509_name_free, METH_VARARGS, NULL}, + { (char *)"x509_name_print", _wrap_x509_name_print, METH_VARARGS, NULL}, + { (char *)"x509_name_get_entry", _wrap_x509_name_get_entry, METH_VARARGS, NULL}, + { (char *)"x509_name_entry_count", _wrap_x509_name_entry_count, METH_VARARGS, NULL}, + { (char *)"x509_name_delete_entry", _wrap_x509_name_delete_entry, METH_VARARGS, NULL}, + { (char *)"x509_name_add_entry", _wrap_x509_name_add_entry, METH_VARARGS, NULL}, + { (char *)"x509_name_add_entry_by_obj", _wrap_x509_name_add_entry_by_obj, METH_VARARGS, NULL}, + { (char *)"x509_name_add_entry_by_nid", _wrap_x509_name_add_entry_by_nid, METH_VARARGS, NULL}, + { (char *)"x509_name_print_ex", _wrap_x509_name_print_ex, METH_VARARGS, NULL}, + { (char *)"x509_name_hash", _wrap_x509_name_hash, METH_VARARGS, NULL}, + { (char *)"x509_name_get_index_by_nid", _wrap_x509_name_get_index_by_nid, METH_VARARGS, NULL}, + { (char *)"x509_name_entry_new", _wrap_x509_name_entry_new, METH_VARARGS, NULL}, + { (char *)"x509_name_entry_free", _wrap_x509_name_entry_free, METH_VARARGS, NULL}, + { (char *)"x509_name_entry_create_by_nid", _wrap_x509_name_entry_create_by_nid, METH_VARARGS, NULL}, + { (char *)"x509_name_entry_set_object", _wrap_x509_name_entry_set_object, METH_VARARGS, NULL}, + { (char *)"x509_name_entry_get_object", _wrap_x509_name_entry_get_object, METH_VARARGS, NULL}, + { (char *)"x509_name_entry_get_data", _wrap_x509_name_entry_get_data, METH_VARARGS, NULL}, + { (char *)"x509_name_entry_set_data", _wrap_x509_name_entry_set_data, METH_VARARGS, NULL}, + { (char *)"x509_req_new", _wrap_x509_req_new, METH_VARARGS, NULL}, + { (char *)"x509_req_free", _wrap_x509_req_free, METH_VARARGS, NULL}, + { (char *)"x509_req_print", _wrap_x509_req_print, METH_VARARGS, NULL}, + { (char *)"x509_req_get_pubkey", _wrap_x509_req_get_pubkey, METH_VARARGS, NULL}, + { (char *)"x509_req_set_pubkey", _wrap_x509_req_set_pubkey, METH_VARARGS, NULL}, + { (char *)"x509_req_set_subject_name", _wrap_x509_req_set_subject_name, METH_VARARGS, NULL}, + { (char *)"x509_req_verify", _wrap_x509_req_verify, METH_VARARGS, NULL}, + { (char *)"x509_req_sign", _wrap_x509_req_sign, METH_VARARGS, NULL}, + { (char *)"i2d_x509_bio", _wrap_i2d_x509_bio, METH_VARARGS, NULL}, + { (char *)"i2d_x509_req_bio", _wrap_i2d_x509_req_bio, METH_VARARGS, NULL}, + { (char *)"x509_store_new", _wrap_x509_store_new, METH_VARARGS, NULL}, + { (char *)"x509_store_free", _wrap_x509_store_free, METH_VARARGS, NULL}, + { (char *)"x509_store_add_cert", _wrap_x509_store_add_cert, METH_VARARGS, NULL}, + { (char *)"x509_store_ctx_get_current_cert", _wrap_x509_store_ctx_get_current_cert, METH_VARARGS, NULL}, + { (char *)"x509_store_ctx_get_error", _wrap_x509_store_ctx_get_error, METH_VARARGS, NULL}, + { (char *)"x509_store_ctx_get_error_depth", _wrap_x509_store_ctx_get_error_depth, METH_VARARGS, NULL}, + { (char *)"x509_store_ctx_free", _wrap_x509_store_ctx_free, METH_VARARGS, NULL}, + { (char *)"x509_store_ctx_get1_chain", _wrap_x509_store_ctx_get1_chain, METH_VARARGS, NULL}, + { (char *)"x509_extension_get_critical", _wrap_x509_extension_get_critical, METH_VARARGS, NULL}, + { (char *)"x509_extension_set_critical", _wrap_x509_extension_set_critical, METH_VARARGS, NULL}, + { (char *)"x509_read_pem", _wrap_x509_read_pem, METH_VARARGS, NULL}, + { (char *)"d2i_x509", _wrap_d2i_x509, METH_VARARGS, NULL}, + { (char *)"x509_init", _wrap_x509_init, METH_VARARGS, NULL}, + { (char *)"d2i_x509_req", _wrap_d2i_x509_req, METH_VARARGS, NULL}, + { (char *)"x509_req_read_pem", _wrap_x509_req_read_pem, METH_VARARGS, NULL}, + { (char *)"i2d_x509", _wrap_i2d_x509, METH_VARARGS, NULL}, + { (char *)"x509_req_write_pem", _wrap_x509_req_write_pem, METH_VARARGS, NULL}, + { (char *)"x509_crl_read_pem", _wrap_x509_crl_read_pem, METH_VARARGS, NULL}, + { (char *)"x509_set_version", _wrap_x509_set_version, METH_VARARGS, NULL}, + { (char *)"x509_get_version", _wrap_x509_get_version, METH_VARARGS, NULL}, + { (char *)"x509_set_not_before", _wrap_x509_set_not_before, METH_VARARGS, NULL}, + { (char *)"x509_get_not_before", _wrap_x509_get_not_before, METH_VARARGS, NULL}, + { (char *)"x509_set_not_after", _wrap_x509_set_not_after, METH_VARARGS, NULL}, + { (char *)"x509_get_not_after", _wrap_x509_get_not_after, METH_VARARGS, NULL}, + { (char *)"x509_sign", _wrap_x509_sign, METH_VARARGS, NULL}, + { (char *)"x509_gmtime_adj", _wrap_x509_gmtime_adj, METH_VARARGS, NULL}, + { (char *)"x509_name_by_nid", _wrap_x509_name_by_nid, METH_VARARGS, NULL}, + { (char *)"x509_name_set_by_nid", _wrap_x509_name_set_by_nid, METH_VARARGS, NULL}, + { (char *)"x509_name_add_entry_by_txt", _wrap_x509_name_add_entry_by_txt, METH_VARARGS, NULL}, + { (char *)"x509_name_get_der", _wrap_x509_name_get_der, METH_VARARGS, NULL}, + { (char *)"sk_x509_free", _wrap_sk_x509_free, METH_VARARGS, NULL}, + { (char *)"sk_x509_push", _wrap_sk_x509_push, METH_VARARGS, NULL}, + { (char *)"sk_x509_pop", _wrap_sk_x509_pop, METH_VARARGS, NULL}, + { (char *)"x509_store_load_locations", _wrap_x509_store_load_locations, METH_VARARGS, NULL}, + { (char *)"x509_type_check", _wrap_x509_type_check, METH_VARARGS, NULL}, + { (char *)"x509_name_type_check", _wrap_x509_name_type_check, METH_VARARGS, NULL}, + { (char *)"x509_req_get_subject_name", _wrap_x509_req_get_subject_name, METH_VARARGS, NULL}, + { (char *)"x509_req_get_version", _wrap_x509_req_get_version, METH_VARARGS, NULL}, + { (char *)"x509_req_set_version", _wrap_x509_req_set_version, METH_VARARGS, NULL}, + { (char *)"x509_req_add_extensions", _wrap_x509_req_add_extensions, METH_VARARGS, NULL}, + { (char *)"x509_name_entry_create_by_txt", _wrap_x509_name_entry_create_by_txt, METH_VARARGS, NULL}, + { (char *)"x509v3_set_nconf", _wrap_x509v3_set_nconf, METH_VARARGS, NULL}, + { (char *)"x509v3_ext_conf", _wrap_x509v3_ext_conf, METH_VARARGS, NULL}, + { (char *)"x509_extension_free", _wrap_x509_extension_free, METH_VARARGS, NULL}, + { (char *)"x509_extension_get_name", _wrap_x509_extension_get_name, METH_VARARGS, NULL}, + { (char *)"sk_x509_extension_new_null", _wrap_sk_x509_extension_new_null, METH_VARARGS, NULL}, + { (char *)"sk_x509_extension_free", _wrap_sk_x509_extension_free, METH_VARARGS, NULL}, + { (char *)"sk_x509_extension_push", _wrap_sk_x509_extension_push, METH_VARARGS, NULL}, + { (char *)"sk_x509_extension_pop", _wrap_sk_x509_extension_pop, METH_VARARGS, NULL}, + { (char *)"sk_x509_extension_num", _wrap_sk_x509_extension_num, METH_VARARGS, NULL}, + { (char *)"sk_x509_extension_value", _wrap_sk_x509_extension_value, METH_VARARGS, NULL}, + { (char *)"x509_store_ctx_get_app_data", _wrap_x509_store_ctx_get_app_data, METH_VARARGS, NULL}, + { (char *)"x509_store_ctx_get_ex_data", _wrap_x509_store_ctx_get_ex_data, METH_VARARGS, NULL}, + { (char *)"x509_store_set_verify_cb", _wrap_x509_store_set_verify_cb, METH_VARARGS, NULL}, + { (char *)"make_stack_from_der_sequence", _wrap_make_stack_from_der_sequence, METH_VARARGS, NULL}, + { (char *)"sk_x509_new_null", _wrap_sk_x509_new_null, METH_VARARGS, NULL}, + { (char *)"get_der_encoding_stack", _wrap_get_der_encoding_stack, METH_VARARGS, NULL}, + { (char *)"x509_name_oneline", _wrap_x509_name_oneline, METH_VARARGS, NULL}, + { (char *)"asn1_object_new", _wrap_asn1_object_new, METH_VARARGS, NULL}, + { (char *)"asn1_object_create", _wrap_asn1_object_create, METH_VARARGS, NULL}, + { (char *)"asn1_object_free", _wrap_asn1_object_free, METH_VARARGS, NULL}, + { (char *)"i2d_asn1_object", _wrap_i2d_asn1_object, METH_VARARGS, NULL}, + { (char *)"d2i_asn1_object", _wrap_d2i_asn1_object, METH_VARARGS, NULL}, + { (char *)"asn1_bit_string_new", _wrap_asn1_bit_string_new, METH_VARARGS, NULL}, + { (char *)"asn1_string_new", _wrap_asn1_string_new, METH_VARARGS, NULL}, + { (char *)"asn1_string_free", _wrap_asn1_string_free, METH_VARARGS, NULL}, + { (char *)"asn1_string_set", _wrap_asn1_string_set, METH_VARARGS, NULL}, + { (char *)"asn1_string_print", _wrap_asn1_string_print, METH_VARARGS, NULL}, + { (char *)"asn1_string_print_ex", _wrap_asn1_string_print_ex, METH_VARARGS, NULL}, + { (char *)"asn1_time_new", _wrap_asn1_time_new, METH_VARARGS, NULL}, + { (char *)"asn1_time_free", _wrap_asn1_time_free, METH_VARARGS, NULL}, + { (char *)"asn1_time_check", _wrap_asn1_time_check, METH_VARARGS, NULL}, + { (char *)"asn1_time_set", _wrap_asn1_time_set, METH_VARARGS, NULL}, + { (char *)"asn1_time_set_string", _wrap_asn1_time_set_string, METH_VARARGS, NULL}, + { (char *)"asn1_time_print", _wrap_asn1_time_print, METH_VARARGS, NULL}, + { (char *)"asn1_integer_new", _wrap_asn1_integer_new, METH_VARARGS, NULL}, + { (char *)"asn1_integer_free", _wrap_asn1_integer_free, METH_VARARGS, NULL}, + { (char *)"asn1_integer_cmp", _wrap_asn1_integer_cmp, METH_VARARGS, NULL}, + { (char *)"asn1_time_type_check", _wrap_asn1_time_type_check, METH_VARARGS, NULL}, + { (char *)"asn1_integer_get", _wrap_asn1_integer_get, METH_VARARGS, NULL}, + { (char *)"asn1_integer_set", _wrap_asn1_integer_set, METH_VARARGS, NULL}, + { (char *)"pkcs7_new", _wrap_pkcs7_new, METH_VARARGS, NULL}, + { (char *)"pkcs7_free", _wrap_pkcs7_free, METH_VARARGS, NULL}, + { (char *)"pkcs7_add_certificate", _wrap_pkcs7_add_certificate, METH_VARARGS, NULL}, + { (char *)"pkcs7_init", _wrap_pkcs7_init, METH_VARARGS, NULL}, + { (char *)"smime_init", _wrap_smime_init, METH_VARARGS, NULL}, + { (char *)"pkcs7_decrypt", _wrap_pkcs7_decrypt, METH_VARARGS, NULL}, + { (char *)"pkcs7_encrypt", _wrap_pkcs7_encrypt, METH_VARARGS, NULL}, + { (char *)"pkcs7_sign1", _wrap_pkcs7_sign1, METH_VARARGS, NULL}, + { (char *)"pkcs7_sign0", _wrap_pkcs7_sign0, METH_VARARGS, NULL}, + { (char *)"pkcs7_read_bio", _wrap_pkcs7_read_bio, METH_VARARGS, NULL}, + { (char *)"pkcs7_read_bio_der", _wrap_pkcs7_read_bio_der, METH_VARARGS, NULL}, + { (char *)"pkcs7_verify1", _wrap_pkcs7_verify1, METH_VARARGS, NULL}, + { (char *)"pkcs7_verify0", _wrap_pkcs7_verify0, METH_VARARGS, NULL}, + { (char *)"smime_write_pkcs7_multi", _wrap_smime_write_pkcs7_multi, METH_VARARGS, NULL}, + { (char *)"smime_write_pkcs7", _wrap_smime_write_pkcs7, METH_VARARGS, NULL}, + { (char *)"smime_read_pkcs7", _wrap_smime_read_pkcs7, METH_VARARGS, NULL}, + { (char *)"pkcs7_write_bio", _wrap_pkcs7_write_bio, METH_VARARGS, NULL}, + { (char *)"pkcs7_write_bio_der", _wrap_pkcs7_write_bio_der, METH_VARARGS, NULL}, + { (char *)"pkcs7_type_nid", _wrap_pkcs7_type_nid, METH_VARARGS, NULL}, + { (char *)"pkcs7_type_sn", _wrap_pkcs7_type_sn, METH_VARARGS, NULL}, + { (char *)"smime_crlf_copy", _wrap_smime_crlf_copy, METH_VARARGS, NULL}, + { (char *)"pkcs7_get0_signers", _wrap_pkcs7_get0_signers, METH_VARARGS, NULL}, + { (char *)"util_init", _wrap_util_init, METH_VARARGS, NULL}, + { (char *)"util_hex_to_string", _wrap_util_hex_to_string, METH_VARARGS, NULL}, + { (char *)"util_string_to_hex", _wrap_util_string_to_hex, METH_VARARGS, NULL}, + { (char *)"ec_key_new", _wrap_ec_key_new, METH_VARARGS, NULL}, + { (char *)"ec_key_free", _wrap_ec_key_free, METH_VARARGS, NULL}, + { (char *)"ec_key_size", _wrap_ec_key_size, METH_VARARGS, NULL}, + { (char *)"ec_key_gen_key", _wrap_ec_key_gen_key, METH_VARARGS, NULL}, + { (char *)"ec_key_check_key", _wrap_ec_key_check_key, METH_VARARGS, NULL}, + { (char *)"ec_init", _wrap_ec_init, METH_VARARGS, NULL}, + { (char *)"ec_get_builtin_curves", _wrap_ec_get_builtin_curves, METH_VARARGS, NULL}, + { (char *)"ec_key_new_by_curve_name", _wrap_ec_key_new_by_curve_name, METH_VARARGS, NULL}, + { (char *)"ec_key_get_public_der", _wrap_ec_key_get_public_der, METH_VARARGS, NULL}, + { (char *)"ec_key_get_public_key", _wrap_ec_key_get_public_key, METH_VARARGS, NULL}, + { (char *)"ec_key_read_pubkey", _wrap_ec_key_read_pubkey, METH_VARARGS, NULL}, + { (char *)"ec_key_write_pubkey", _wrap_ec_key_write_pubkey, METH_VARARGS, NULL}, + { (char *)"ec_key_read_bio", _wrap_ec_key_read_bio, METH_VARARGS, NULL}, + { (char *)"ec_key_write_bio", _wrap_ec_key_write_bio, METH_VARARGS, NULL}, + { (char *)"ec_key_write_bio_no_cipher", _wrap_ec_key_write_bio_no_cipher, METH_VARARGS, NULL}, + { (char *)"ecdsa_sig_get_r", _wrap_ecdsa_sig_get_r, METH_VARARGS, NULL}, + { (char *)"ecdsa_sig_get_s", _wrap_ecdsa_sig_get_s, METH_VARARGS, NULL}, + { (char *)"ecdsa_sign", _wrap_ecdsa_sign, METH_VARARGS, NULL}, + { (char *)"ecdsa_verify", _wrap_ecdsa_verify, METH_VARARGS, NULL}, + { (char *)"ecdsa_sign_asn1", _wrap_ecdsa_sign_asn1, METH_VARARGS, NULL}, + { (char *)"ecdsa_verify_asn1", _wrap_ecdsa_verify_asn1, METH_VARARGS, NULL}, + { (char *)"ecdh_compute_key", _wrap_ecdh_compute_key, METH_VARARGS, NULL}, + { (char *)"ec_key_from_pubkey_der", _wrap_ec_key_from_pubkey_der, METH_VARARGS, NULL}, + { (char *)"ec_key_from_pubkey_params", _wrap_ec_key_from_pubkey_params, METH_VARARGS, NULL}, + { (char *)"ec_key_keylen", _wrap_ec_key_keylen, METH_VARARGS, NULL}, + { (char *)"ec_key_type_check", _wrap_ec_key_type_check, METH_VARARGS, NULL}, + { (char *)"engine_load_builtin_engines", _wrap_engine_load_builtin_engines, METH_VARARGS, NULL}, + { (char *)"engine_load_dynamic", _wrap_engine_load_dynamic, METH_VARARGS, NULL}, + { (char *)"engine_load_openssl", _wrap_engine_load_openssl, METH_VARARGS, NULL}, + { (char *)"engine_cleanup", _wrap_engine_cleanup, METH_VARARGS, NULL}, + { (char *)"engine_new", _wrap_engine_new, METH_VARARGS, NULL}, + { (char *)"engine_by_id", _wrap_engine_by_id, METH_VARARGS, NULL}, + { (char *)"engine_free", _wrap_engine_free, METH_VARARGS, NULL}, + { (char *)"engine_init", _wrap_engine_init, METH_VARARGS, NULL}, + { (char *)"engine_finish", _wrap_engine_finish, METH_VARARGS, NULL}, + { (char *)"engine_get_id", _wrap_engine_get_id, METH_VARARGS, NULL}, + { (char *)"engine_get_name", _wrap_engine_get_name, METH_VARARGS, NULL}, + { (char *)"engine_ctrl_cmd_string", _wrap_engine_ctrl_cmd_string, METH_VARARGS, NULL}, + { (char *)"ui_openssl", _wrap_ui_openssl, METH_VARARGS, NULL}, + { (char *)"engine_pkcs11_data_new", _wrap_engine_pkcs11_data_new, METH_VARARGS, NULL}, + { (char *)"engine_pkcs11_data_free", _wrap_engine_pkcs11_data_free, METH_VARARGS, NULL}, + { (char *)"engine_load_private_key", _wrap_engine_load_private_key, METH_VARARGS, NULL}, + { (char *)"engine_load_public_key", _wrap_engine_load_public_key, METH_VARARGS, NULL}, + { (char *)"engine_init_error", _wrap_engine_init_error, METH_VARARGS, NULL}, + { (char *)"engine_load_certificate", _wrap_engine_load_certificate, METH_VARARGS, NULL}, + { (char *)"engine_set_default", _wrap_engine_set_default, METH_VARARGS, NULL}, + { (char *)"obj_nid2obj", _wrap_obj_nid2obj, METH_VARARGS, NULL}, + { (char *)"obj_nid2ln", _wrap_obj_nid2ln, METH_VARARGS, NULL}, + { (char *)"obj_nid2sn", _wrap_obj_nid2sn, METH_VARARGS, NULL}, + { (char *)"obj_obj2nid", _wrap_obj_obj2nid, METH_VARARGS, NULL}, + { (char *)"obj_ln2nid", _wrap_obj_ln2nid, METH_VARARGS, NULL}, + { (char *)"obj_sn2nid", _wrap_obj_sn2nid, METH_VARARGS, NULL}, + { (char *)"obj_txt2nid", _wrap_obj_txt2nid, METH_VARARGS, NULL}, + { (char *)"obj_txt2obj", _wrap_obj_txt2obj, METH_VARARGS, NULL}, + { (char *)"_obj_obj2txt", _wrap__obj_obj2txt, METH_VARARGS, NULL}, + { (char *)"obj_obj2txt", _wrap_obj_obj2txt, METH_VARARGS, NULL}, + { NULL, NULL, 0, NULL } +}; + +SWIGPY_DESTRUCTOR_CLOSURE(_wrap_delete__STACK) +static SwigPyGetSet _STACK_num_alloc_getset = { _wrap__STACK_num_alloc_get, _wrap__STACK_num_alloc_set }; +static SwigPyGetSet _STACK_data_getset = { _wrap__STACK_data_get, _wrap__STACK_data_set }; +static SwigPyGetSet _STACK_comp_getset = { _wrap__STACK_comp_get, _wrap__STACK_comp_set }; +static SwigPyGetSet _STACK_sorted_getset = { _wrap__STACK_sorted_get, _wrap__STACK_sorted_set }; +static SwigPyGetSet _STACK_num_getset = { _wrap__STACK_num_get, _wrap__STACK_num_set }; +SWIGINTERN PyGetSetDef SwigPyBuiltin__stack_st_getset[] = { + { (char*) "num_alloc", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"stack_st.num_alloc", (void*) &_STACK_num_alloc_getset } +, + { (char*) "data", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"stack_st.data", (void*) &_STACK_data_getset } +, + { (char*) "comp", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"stack_st.comp", (void*) &_STACK_comp_getset } +, + { (char*) "sorted", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"stack_st.sorted", (void*) &_STACK_sorted_getset } +, + { (char*) "num", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"stack_st.num", (void*) &_STACK_num_getset } +, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +SWIGINTERN PyObject * +SwigPyBuiltin__stack_st_richcompare(PyObject *self, PyObject *other, int op) { + PyObject *result = NULL; + PyObject *tuple = PyTuple_New(1); + assert(tuple); + PyTuple_SET_ITEM(tuple, 0, other); + Py_XINCREF(other); + if (!result) { + if (SwigPyObject_Check(self) && SwigPyObject_Check(other)) { + result = SwigPyObject_richcompare((SwigPyObject *)self, (SwigPyObject *)other, op); + } else { + result = Py_NotImplemented; + Py_INCREF(result); + } + } + Py_DECREF(tuple); + return result; +} + +SWIGINTERN PyMethodDef SwigPyBuiltin__stack_st_methods[] = { + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +static PyHeapTypeObject SwigPyBuiltin__stack_st_type = { + { +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "_STACK", /* tp_name */ + sizeof(SwigPyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) _wrap_delete__STACK_closure, /* tp_dealloc */ + (printfunc) 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ +#if PY_VERSION_HEX >= 0x03000000 + 0, /* tp_compare */ +#else + (cmpfunc) 0, /* tp_compare */ +#endif + (reprfunc) 0, /* tp_repr */ + &SwigPyBuiltin__stack_st_type.as_number, /* tp_as_number */ + &SwigPyBuiltin__stack_st_type.as_sequence, /* tp_as_sequence */ + &SwigPyBuiltin__stack_st_type.as_mapping, /* tp_as_mapping */ + (hashfunc) 0, /* tp_hash */ + (ternaryfunc) 0, /* tp_call */ + (reprfunc) 0, /* tp_str */ + (getattrofunc) 0, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + &SwigPyBuiltin__stack_st_type.as_buffer, /* tp_as_buffer */ +#if PY_VERSION_HEX >= 0x03000000 + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ +#else + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */ +#endif + "::stack_st", /* tp_doc */ + (traverseproc) 0, /* tp_traverse */ + (inquiry) 0, /* tp_clear */ + (richcmpfunc) SwigPyBuiltin__stack_st_richcompare, /* feature:python:tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc) 0, /* tp_iter */ + (iternextfunc) 0, /* tp_iternext */ + SwigPyBuiltin__stack_st_methods, /* tp_methods */ + 0, /* tp_members */ + SwigPyBuiltin__stack_st_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc) 0, /* tp_descr_get */ + (descrsetfunc) 0, /* tp_descr_set */ + (size_t)(((char*)&((SwigPyObject *) 64L)->dict) - (char*) 64L), /* tp_dictoffset */ + (initproc) _wrap_new__STACK, /* tp_init */ + (allocfunc) 0, /* tp_alloc */ + (newfunc) 0, /* tp_new */ + (freefunc) 0, /* tp_free */ + (inquiry) 0, /* tp_is_gc */ + (PyObject*) 0, /* tp_bases */ + (PyObject*) 0, /* tp_mro */ + (PyObject*) 0, /* tp_cache */ + (PyObject*) 0, /* tp_subclasses */ + (PyObject*) 0, /* tp_weaklist */ + (destructor) 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + (int) 0, /* tp_version_tag */ +#endif + }, + { + (binaryfunc) 0, /* nb_add */ + (binaryfunc) 0, /* nb_subtract */ + (binaryfunc) 0, /* nb_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_divide */ +#endif + (binaryfunc) 0, /* nb_remainder */ + (binaryfunc) 0, /* nb_divmod */ + (ternaryfunc) 0, /* nb_power */ + (unaryfunc) 0, /* nb_negative */ + (unaryfunc) 0, /* nb_positive */ + (unaryfunc) 0, /* nb_absolute */ + (inquiry) 0, /* nb_nonzero */ + (unaryfunc) 0, /* nb_invert */ + (binaryfunc) 0, /* nb_lshift */ + (binaryfunc) 0, /* nb_rshift */ + (binaryfunc) 0, /* nb_and */ + (binaryfunc) 0, /* nb_xor */ + (binaryfunc) 0, /* nb_or */ +#if PY_VERSION_HEX < 0x03000000 + (coercion) 0, /* nb_coerce */ +#endif + (unaryfunc) 0, /* nb_int */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* nb_reserved */ +#else + (unaryfunc) 0, /* nb_long */ +#endif + (unaryfunc) 0, /* nb_float */ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc) 0, /* nb_oct */ + (unaryfunc) 0, /* nb_hex */ +#endif + (binaryfunc) 0, /* nb_inplace_add */ + (binaryfunc) 0, /* nb_inplace_subtract */ + (binaryfunc) 0, /* nb_inplace_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_inplace_divide */ +#endif + (binaryfunc) 0, /* nb_inplace_remainder */ + (ternaryfunc) 0, /* nb_inplace_power */ + (binaryfunc) 0, /* nb_inplace_lshift */ + (binaryfunc) 0, /* nb_inplace_rshift */ + (binaryfunc) 0, /* nb_inplace_and */ + (binaryfunc) 0, /* nb_inplace_xor */ + (binaryfunc) 0, /* nb_inplace_or */ + (binaryfunc) 0, /* nb_floor_divide */ + (binaryfunc) 0, /* nb_true_divide */ + (binaryfunc) 0, /* nb_inplace_floor_divide */ + (binaryfunc) 0, /* nb_inplace_true_divide */ +#if PY_VERSION_HEX >= 0x02050000 + (unaryfunc) 0, /* nb_index */ +#endif + }, + { + (lenfunc) 0, /* mp_length */ + (binaryfunc) 0, /* mp_subscript */ + (objobjargproc) 0, /* mp_ass_subscript */ + }, + { + (lenfunc) 0, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (ssizeargfunc) 0, /* sq_repeat */ + (ssizeargfunc) 0, /* sq_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_slice */ +#else + (ssizessizeargfunc) 0, /* sq_slice */ +#endif + (ssizeobjargproc) 0, /* sq_ass_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_ass_slice */ +#else + (ssizessizeobjargproc) 0, /* sq_ass_slice */ +#endif + (objobjproc) 0, /* sq_contains */ + (binaryfunc) 0, /* sq_inplace_concat */ + (ssizeargfunc) 0, /* sq_inplace_repeat */ + }, + { +#if PY_VERSION_HEX < 0x03000000 + (readbufferproc) 0, /* bf_getreadbuffer */ + (writebufferproc) 0, /* bf_getwritebuffer */ + (segcountproc) 0, /* bf_getsegcount */ + (charbufferproc) 0, /* bf_getcharbuffer */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + (getbufferproc) 0, /* bf_getbuffer */ + (releasebufferproc) 0, /* bf_releasebuffer */ +#endif + }, + (PyObject*) 0, /* ht_name */ + (PyObject*) 0, /* ht_slots */ +}; + +SWIGINTERN SwigPyClientData SwigPyBuiltin__stack_st_clientdata = {0, 0, 0, 0, 0, 0, (PyTypeObject *)&SwigPyBuiltin__stack_st_type}; + +SWIGPY_DESTRUCTOR_CLOSURE(_wrap_delete_stack_st_OPENSSL_STRING) +static SwigPyGetSet stack_st_OPENSSL_STRING_stack_getset = { _wrap_stack_st_OPENSSL_STRING_stack_get, _wrap_stack_st_OPENSSL_STRING_stack_set }; +SWIGINTERN PyGetSetDef SwigPyBuiltin__stack_st_OPENSSL_STRING_getset[] = { + { (char*) "stack", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"stack_st_OPENSSL_STRING.stack", (void*) &stack_st_OPENSSL_STRING_stack_getset } +, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +SWIGINTERN PyObject * +SwigPyBuiltin__stack_st_OPENSSL_STRING_richcompare(PyObject *self, PyObject *other, int op) { + PyObject *result = NULL; + PyObject *tuple = PyTuple_New(1); + assert(tuple); + PyTuple_SET_ITEM(tuple, 0, other); + Py_XINCREF(other); + if (!result) { + if (SwigPyObject_Check(self) && SwigPyObject_Check(other)) { + result = SwigPyObject_richcompare((SwigPyObject *)self, (SwigPyObject *)other, op); + } else { + result = Py_NotImplemented; + Py_INCREF(result); + } + } + Py_DECREF(tuple); + return result; +} + +SWIGINTERN PyMethodDef SwigPyBuiltin__stack_st_OPENSSL_STRING_methods[] = { + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +static PyHeapTypeObject SwigPyBuiltin__stack_st_OPENSSL_STRING_type = { + { +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "stack_st_OPENSSL_STRING", /* tp_name */ + sizeof(SwigPyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) _wrap_delete_stack_st_OPENSSL_STRING_closure, /* tp_dealloc */ + (printfunc) 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ +#if PY_VERSION_HEX >= 0x03000000 + 0, /* tp_compare */ +#else + (cmpfunc) 0, /* tp_compare */ +#endif + (reprfunc) 0, /* tp_repr */ + &SwigPyBuiltin__stack_st_OPENSSL_STRING_type.as_number, /* tp_as_number */ + &SwigPyBuiltin__stack_st_OPENSSL_STRING_type.as_sequence, /* tp_as_sequence */ + &SwigPyBuiltin__stack_st_OPENSSL_STRING_type.as_mapping, /* tp_as_mapping */ + (hashfunc) 0, /* tp_hash */ + (ternaryfunc) 0, /* tp_call */ + (reprfunc) 0, /* tp_str */ + (getattrofunc) 0, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + &SwigPyBuiltin__stack_st_OPENSSL_STRING_type.as_buffer, /* tp_as_buffer */ +#if PY_VERSION_HEX >= 0x03000000 + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ +#else + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */ +#endif + "::stack_st_OPENSSL_STRING", /* tp_doc */ + (traverseproc) 0, /* tp_traverse */ + (inquiry) 0, /* tp_clear */ + (richcmpfunc) SwigPyBuiltin__stack_st_OPENSSL_STRING_richcompare, /* feature:python:tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc) 0, /* tp_iter */ + (iternextfunc) 0, /* tp_iternext */ + SwigPyBuiltin__stack_st_OPENSSL_STRING_methods, /* tp_methods */ + 0, /* tp_members */ + SwigPyBuiltin__stack_st_OPENSSL_STRING_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc) 0, /* tp_descr_get */ + (descrsetfunc) 0, /* tp_descr_set */ + (size_t)(((char*)&((SwigPyObject *) 64L)->dict) - (char*) 64L), /* tp_dictoffset */ + (initproc) _wrap_new_stack_st_OPENSSL_STRING, /* tp_init */ + (allocfunc) 0, /* tp_alloc */ + (newfunc) 0, /* tp_new */ + (freefunc) 0, /* tp_free */ + (inquiry) 0, /* tp_is_gc */ + (PyObject*) 0, /* tp_bases */ + (PyObject*) 0, /* tp_mro */ + (PyObject*) 0, /* tp_cache */ + (PyObject*) 0, /* tp_subclasses */ + (PyObject*) 0, /* tp_weaklist */ + (destructor) 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + (int) 0, /* tp_version_tag */ +#endif + }, + { + (binaryfunc) 0, /* nb_add */ + (binaryfunc) 0, /* nb_subtract */ + (binaryfunc) 0, /* nb_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_divide */ +#endif + (binaryfunc) 0, /* nb_remainder */ + (binaryfunc) 0, /* nb_divmod */ + (ternaryfunc) 0, /* nb_power */ + (unaryfunc) 0, /* nb_negative */ + (unaryfunc) 0, /* nb_positive */ + (unaryfunc) 0, /* nb_absolute */ + (inquiry) 0, /* nb_nonzero */ + (unaryfunc) 0, /* nb_invert */ + (binaryfunc) 0, /* nb_lshift */ + (binaryfunc) 0, /* nb_rshift */ + (binaryfunc) 0, /* nb_and */ + (binaryfunc) 0, /* nb_xor */ + (binaryfunc) 0, /* nb_or */ +#if PY_VERSION_HEX < 0x03000000 + (coercion) 0, /* nb_coerce */ +#endif + (unaryfunc) 0, /* nb_int */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* nb_reserved */ +#else + (unaryfunc) 0, /* nb_long */ +#endif + (unaryfunc) 0, /* nb_float */ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc) 0, /* nb_oct */ + (unaryfunc) 0, /* nb_hex */ +#endif + (binaryfunc) 0, /* nb_inplace_add */ + (binaryfunc) 0, /* nb_inplace_subtract */ + (binaryfunc) 0, /* nb_inplace_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_inplace_divide */ +#endif + (binaryfunc) 0, /* nb_inplace_remainder */ + (ternaryfunc) 0, /* nb_inplace_power */ + (binaryfunc) 0, /* nb_inplace_lshift */ + (binaryfunc) 0, /* nb_inplace_rshift */ + (binaryfunc) 0, /* nb_inplace_and */ + (binaryfunc) 0, /* nb_inplace_xor */ + (binaryfunc) 0, /* nb_inplace_or */ + (binaryfunc) 0, /* nb_floor_divide */ + (binaryfunc) 0, /* nb_true_divide */ + (binaryfunc) 0, /* nb_inplace_floor_divide */ + (binaryfunc) 0, /* nb_inplace_true_divide */ +#if PY_VERSION_HEX >= 0x02050000 + (unaryfunc) 0, /* nb_index */ +#endif + }, + { + (lenfunc) 0, /* mp_length */ + (binaryfunc) 0, /* mp_subscript */ + (objobjargproc) 0, /* mp_ass_subscript */ + }, + { + (lenfunc) 0, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (ssizeargfunc) 0, /* sq_repeat */ + (ssizeargfunc) 0, /* sq_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_slice */ +#else + (ssizessizeargfunc) 0, /* sq_slice */ +#endif + (ssizeobjargproc) 0, /* sq_ass_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_ass_slice */ +#else + (ssizessizeobjargproc) 0, /* sq_ass_slice */ +#endif + (objobjproc) 0, /* sq_contains */ + (binaryfunc) 0, /* sq_inplace_concat */ + (ssizeargfunc) 0, /* sq_inplace_repeat */ + }, + { +#if PY_VERSION_HEX < 0x03000000 + (readbufferproc) 0, /* bf_getreadbuffer */ + (writebufferproc) 0, /* bf_getwritebuffer */ + (segcountproc) 0, /* bf_getsegcount */ + (charbufferproc) 0, /* bf_getcharbuffer */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + (getbufferproc) 0, /* bf_getbuffer */ + (releasebufferproc) 0, /* bf_releasebuffer */ +#endif + }, + (PyObject*) 0, /* ht_name */ + (PyObject*) 0, /* ht_slots */ +}; + +SWIGINTERN SwigPyClientData SwigPyBuiltin__stack_st_OPENSSL_STRING_clientdata = {0, 0, 0, 0, 0, 0, (PyTypeObject *)&SwigPyBuiltin__stack_st_OPENSSL_STRING_type}; + +SWIGPY_DESTRUCTOR_CLOSURE(_wrap_delete_stack_st_OPENSSL_BLOCK) +static SwigPyGetSet stack_st_OPENSSL_BLOCK_stack_getset = { _wrap_stack_st_OPENSSL_BLOCK_stack_get, _wrap_stack_st_OPENSSL_BLOCK_stack_set }; +SWIGINTERN PyGetSetDef SwigPyBuiltin__stack_st_OPENSSL_BLOCK_getset[] = { + { (char*) "stack", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"stack_st_OPENSSL_BLOCK.stack", (void*) &stack_st_OPENSSL_BLOCK_stack_getset } +, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +SWIGINTERN PyObject * +SwigPyBuiltin__stack_st_OPENSSL_BLOCK_richcompare(PyObject *self, PyObject *other, int op) { + PyObject *result = NULL; + PyObject *tuple = PyTuple_New(1); + assert(tuple); + PyTuple_SET_ITEM(tuple, 0, other); + Py_XINCREF(other); + if (!result) { + if (SwigPyObject_Check(self) && SwigPyObject_Check(other)) { + result = SwigPyObject_richcompare((SwigPyObject *)self, (SwigPyObject *)other, op); + } else { + result = Py_NotImplemented; + Py_INCREF(result); + } + } + Py_DECREF(tuple); + return result; +} + +SWIGINTERN PyMethodDef SwigPyBuiltin__stack_st_OPENSSL_BLOCK_methods[] = { + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +static PyHeapTypeObject SwigPyBuiltin__stack_st_OPENSSL_BLOCK_type = { + { +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "stack_st_OPENSSL_BLOCK", /* tp_name */ + sizeof(SwigPyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) _wrap_delete_stack_st_OPENSSL_BLOCK_closure, /* tp_dealloc */ + (printfunc) 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ +#if PY_VERSION_HEX >= 0x03000000 + 0, /* tp_compare */ +#else + (cmpfunc) 0, /* tp_compare */ +#endif + (reprfunc) 0, /* tp_repr */ + &SwigPyBuiltin__stack_st_OPENSSL_BLOCK_type.as_number, /* tp_as_number */ + &SwigPyBuiltin__stack_st_OPENSSL_BLOCK_type.as_sequence, /* tp_as_sequence */ + &SwigPyBuiltin__stack_st_OPENSSL_BLOCK_type.as_mapping, /* tp_as_mapping */ + (hashfunc) 0, /* tp_hash */ + (ternaryfunc) 0, /* tp_call */ + (reprfunc) 0, /* tp_str */ + (getattrofunc) 0, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + &SwigPyBuiltin__stack_st_OPENSSL_BLOCK_type.as_buffer, /* tp_as_buffer */ +#if PY_VERSION_HEX >= 0x03000000 + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ +#else + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */ +#endif + "::stack_st_OPENSSL_BLOCK", /* tp_doc */ + (traverseproc) 0, /* tp_traverse */ + (inquiry) 0, /* tp_clear */ + (richcmpfunc) SwigPyBuiltin__stack_st_OPENSSL_BLOCK_richcompare, /* feature:python:tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc) 0, /* tp_iter */ + (iternextfunc) 0, /* tp_iternext */ + SwigPyBuiltin__stack_st_OPENSSL_BLOCK_methods, /* tp_methods */ + 0, /* tp_members */ + SwigPyBuiltin__stack_st_OPENSSL_BLOCK_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc) 0, /* tp_descr_get */ + (descrsetfunc) 0, /* tp_descr_set */ + (size_t)(((char*)&((SwigPyObject *) 64L)->dict) - (char*) 64L), /* tp_dictoffset */ + (initproc) _wrap_new_stack_st_OPENSSL_BLOCK, /* tp_init */ + (allocfunc) 0, /* tp_alloc */ + (newfunc) 0, /* tp_new */ + (freefunc) 0, /* tp_free */ + (inquiry) 0, /* tp_is_gc */ + (PyObject*) 0, /* tp_bases */ + (PyObject*) 0, /* tp_mro */ + (PyObject*) 0, /* tp_cache */ + (PyObject*) 0, /* tp_subclasses */ + (PyObject*) 0, /* tp_weaklist */ + (destructor) 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + (int) 0, /* tp_version_tag */ +#endif + }, + { + (binaryfunc) 0, /* nb_add */ + (binaryfunc) 0, /* nb_subtract */ + (binaryfunc) 0, /* nb_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_divide */ +#endif + (binaryfunc) 0, /* nb_remainder */ + (binaryfunc) 0, /* nb_divmod */ + (ternaryfunc) 0, /* nb_power */ + (unaryfunc) 0, /* nb_negative */ + (unaryfunc) 0, /* nb_positive */ + (unaryfunc) 0, /* nb_absolute */ + (inquiry) 0, /* nb_nonzero */ + (unaryfunc) 0, /* nb_invert */ + (binaryfunc) 0, /* nb_lshift */ + (binaryfunc) 0, /* nb_rshift */ + (binaryfunc) 0, /* nb_and */ + (binaryfunc) 0, /* nb_xor */ + (binaryfunc) 0, /* nb_or */ +#if PY_VERSION_HEX < 0x03000000 + (coercion) 0, /* nb_coerce */ +#endif + (unaryfunc) 0, /* nb_int */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* nb_reserved */ +#else + (unaryfunc) 0, /* nb_long */ +#endif + (unaryfunc) 0, /* nb_float */ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc) 0, /* nb_oct */ + (unaryfunc) 0, /* nb_hex */ +#endif + (binaryfunc) 0, /* nb_inplace_add */ + (binaryfunc) 0, /* nb_inplace_subtract */ + (binaryfunc) 0, /* nb_inplace_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_inplace_divide */ +#endif + (binaryfunc) 0, /* nb_inplace_remainder */ + (ternaryfunc) 0, /* nb_inplace_power */ + (binaryfunc) 0, /* nb_inplace_lshift */ + (binaryfunc) 0, /* nb_inplace_rshift */ + (binaryfunc) 0, /* nb_inplace_and */ + (binaryfunc) 0, /* nb_inplace_xor */ + (binaryfunc) 0, /* nb_inplace_or */ + (binaryfunc) 0, /* nb_floor_divide */ + (binaryfunc) 0, /* nb_true_divide */ + (binaryfunc) 0, /* nb_inplace_floor_divide */ + (binaryfunc) 0, /* nb_inplace_true_divide */ +#if PY_VERSION_HEX >= 0x02050000 + (unaryfunc) 0, /* nb_index */ +#endif + }, + { + (lenfunc) 0, /* mp_length */ + (binaryfunc) 0, /* mp_subscript */ + (objobjargproc) 0, /* mp_ass_subscript */ + }, + { + (lenfunc) 0, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (ssizeargfunc) 0, /* sq_repeat */ + (ssizeargfunc) 0, /* sq_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_slice */ +#else + (ssizessizeargfunc) 0, /* sq_slice */ +#endif + (ssizeobjargproc) 0, /* sq_ass_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_ass_slice */ +#else + (ssizessizeobjargproc) 0, /* sq_ass_slice */ +#endif + (objobjproc) 0, /* sq_contains */ + (binaryfunc) 0, /* sq_inplace_concat */ + (ssizeargfunc) 0, /* sq_inplace_repeat */ + }, + { +#if PY_VERSION_HEX < 0x03000000 + (readbufferproc) 0, /* bf_getreadbuffer */ + (writebufferproc) 0, /* bf_getwritebuffer */ + (segcountproc) 0, /* bf_getsegcount */ + (charbufferproc) 0, /* bf_getcharbuffer */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + (getbufferproc) 0, /* bf_getbuffer */ + (releasebufferproc) 0, /* bf_releasebuffer */ +#endif + }, + (PyObject*) 0, /* ht_name */ + (PyObject*) 0, /* ht_slots */ +}; + +SWIGINTERN SwigPyClientData SwigPyBuiltin__stack_st_OPENSSL_BLOCK_clientdata = {0, 0, 0, 0, 0, 0, (PyTypeObject *)&SwigPyBuiltin__stack_st_OPENSSL_BLOCK_type}; + +SWIGPY_DESTRUCTOR_CLOSURE(_wrap_delete_BIO_PYFD_CTX) +static SwigPyGetSet BIO_PYFD_CTX_fd_getset = { _wrap_BIO_PYFD_CTX_fd_get, _wrap_BIO_PYFD_CTX_fd_set }; +SWIGINTERN PyGetSetDef SwigPyBuiltin__pyfd_struct_getset[] = { + { (char*) "fd", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"pyfd_struct.fd", (void*) &BIO_PYFD_CTX_fd_getset } +, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +SWIGINTERN PyObject * +SwigPyBuiltin__pyfd_struct_richcompare(PyObject *self, PyObject *other, int op) { + PyObject *result = NULL; + PyObject *tuple = PyTuple_New(1); + assert(tuple); + PyTuple_SET_ITEM(tuple, 0, other); + Py_XINCREF(other); + if (!result) { + if (SwigPyObject_Check(self) && SwigPyObject_Check(other)) { + result = SwigPyObject_richcompare((SwigPyObject *)self, (SwigPyObject *)other, op); + } else { + result = Py_NotImplemented; + Py_INCREF(result); + } + } + Py_DECREF(tuple); + return result; +} + +SWIGINTERN PyMethodDef SwigPyBuiltin__pyfd_struct_methods[] = { + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +static PyHeapTypeObject SwigPyBuiltin__pyfd_struct_type = { + { +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "BIO_PYFD_CTX", /* tp_name */ + sizeof(SwigPyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) _wrap_delete_BIO_PYFD_CTX_closure, /* tp_dealloc */ + (printfunc) 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ +#if PY_VERSION_HEX >= 0x03000000 + 0, /* tp_compare */ +#else + (cmpfunc) 0, /* tp_compare */ +#endif + (reprfunc) 0, /* tp_repr */ + &SwigPyBuiltin__pyfd_struct_type.as_number, /* tp_as_number */ + &SwigPyBuiltin__pyfd_struct_type.as_sequence, /* tp_as_sequence */ + &SwigPyBuiltin__pyfd_struct_type.as_mapping, /* tp_as_mapping */ + (hashfunc) 0, /* tp_hash */ + (ternaryfunc) 0, /* tp_call */ + (reprfunc) 0, /* tp_str */ + (getattrofunc) 0, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + &SwigPyBuiltin__pyfd_struct_type.as_buffer, /* tp_as_buffer */ +#if PY_VERSION_HEX >= 0x03000000 + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ +#else + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */ +#endif + "::pyfd_struct", /* tp_doc */ + (traverseproc) 0, /* tp_traverse */ + (inquiry) 0, /* tp_clear */ + (richcmpfunc) SwigPyBuiltin__pyfd_struct_richcompare, /* feature:python:tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc) 0, /* tp_iter */ + (iternextfunc) 0, /* tp_iternext */ + SwigPyBuiltin__pyfd_struct_methods, /* tp_methods */ + 0, /* tp_members */ + SwigPyBuiltin__pyfd_struct_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc) 0, /* tp_descr_get */ + (descrsetfunc) 0, /* tp_descr_set */ + (size_t)(((char*)&((SwigPyObject *) 64L)->dict) - (char*) 64L), /* tp_dictoffset */ + (initproc) _wrap_new_BIO_PYFD_CTX, /* tp_init */ + (allocfunc) 0, /* tp_alloc */ + (newfunc) 0, /* tp_new */ + (freefunc) 0, /* tp_free */ + (inquiry) 0, /* tp_is_gc */ + (PyObject*) 0, /* tp_bases */ + (PyObject*) 0, /* tp_mro */ + (PyObject*) 0, /* tp_cache */ + (PyObject*) 0, /* tp_subclasses */ + (PyObject*) 0, /* tp_weaklist */ + (destructor) 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + (int) 0, /* tp_version_tag */ +#endif + }, + { + (binaryfunc) 0, /* nb_add */ + (binaryfunc) 0, /* nb_subtract */ + (binaryfunc) 0, /* nb_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_divide */ +#endif + (binaryfunc) 0, /* nb_remainder */ + (binaryfunc) 0, /* nb_divmod */ + (ternaryfunc) 0, /* nb_power */ + (unaryfunc) 0, /* nb_negative */ + (unaryfunc) 0, /* nb_positive */ + (unaryfunc) 0, /* nb_absolute */ + (inquiry) 0, /* nb_nonzero */ + (unaryfunc) 0, /* nb_invert */ + (binaryfunc) 0, /* nb_lshift */ + (binaryfunc) 0, /* nb_rshift */ + (binaryfunc) 0, /* nb_and */ + (binaryfunc) 0, /* nb_xor */ + (binaryfunc) 0, /* nb_or */ +#if PY_VERSION_HEX < 0x03000000 + (coercion) 0, /* nb_coerce */ +#endif + (unaryfunc) 0, /* nb_int */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* nb_reserved */ +#else + (unaryfunc) 0, /* nb_long */ +#endif + (unaryfunc) 0, /* nb_float */ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc) 0, /* nb_oct */ + (unaryfunc) 0, /* nb_hex */ +#endif + (binaryfunc) 0, /* nb_inplace_add */ + (binaryfunc) 0, /* nb_inplace_subtract */ + (binaryfunc) 0, /* nb_inplace_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_inplace_divide */ +#endif + (binaryfunc) 0, /* nb_inplace_remainder */ + (ternaryfunc) 0, /* nb_inplace_power */ + (binaryfunc) 0, /* nb_inplace_lshift */ + (binaryfunc) 0, /* nb_inplace_rshift */ + (binaryfunc) 0, /* nb_inplace_and */ + (binaryfunc) 0, /* nb_inplace_xor */ + (binaryfunc) 0, /* nb_inplace_or */ + (binaryfunc) 0, /* nb_floor_divide */ + (binaryfunc) 0, /* nb_true_divide */ + (binaryfunc) 0, /* nb_inplace_floor_divide */ + (binaryfunc) 0, /* nb_inplace_true_divide */ +#if PY_VERSION_HEX >= 0x02050000 + (unaryfunc) 0, /* nb_index */ +#endif + }, + { + (lenfunc) 0, /* mp_length */ + (binaryfunc) 0, /* mp_subscript */ + (objobjargproc) 0, /* mp_ass_subscript */ + }, + { + (lenfunc) 0, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (ssizeargfunc) 0, /* sq_repeat */ + (ssizeargfunc) 0, /* sq_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_slice */ +#else + (ssizessizeargfunc) 0, /* sq_slice */ +#endif + (ssizeobjargproc) 0, /* sq_ass_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_ass_slice */ +#else + (ssizessizeobjargproc) 0, /* sq_ass_slice */ +#endif + (objobjproc) 0, /* sq_contains */ + (binaryfunc) 0, /* sq_inplace_concat */ + (ssizeargfunc) 0, /* sq_inplace_repeat */ + }, + { +#if PY_VERSION_HEX < 0x03000000 + (readbufferproc) 0, /* bf_getreadbuffer */ + (writebufferproc) 0, /* bf_getwritebuffer */ + (segcountproc) 0, /* bf_getsegcount */ + (charbufferproc) 0, /* bf_getcharbuffer */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + (getbufferproc) 0, /* bf_getbuffer */ + (releasebufferproc) 0, /* bf_releasebuffer */ +#endif + }, + (PyObject*) 0, /* ht_name */ + (PyObject*) 0, /* ht_slots */ +}; + +SWIGINTERN SwigPyClientData SwigPyBuiltin__pyfd_struct_clientdata = {0, 0, 0, 0, 0, 0, (PyTypeObject *)&SwigPyBuiltin__pyfd_struct_type}; + +SWIGPY_DESTRUCTOR_CLOSURE(_wrap_delete__cbd_t) +static SwigPyGetSet _cbd_t_password_getset = { _wrap__cbd_t_password_get, _wrap__cbd_t_password_set }; +static SwigPyGetSet _cbd_t_prompt_getset = { _wrap__cbd_t_prompt_get, _wrap__cbd_t_prompt_set }; +SWIGINTERN PyGetSetDef SwigPyBuiltin___cbd_t_getset[] = { + { (char*) "password", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"_cbd_t.password", (void*) &_cbd_t_password_getset } +, + { (char*) "prompt", (getter) SwigPyBuiltin_GetterClosure, (setter) SwigPyBuiltin_SetterClosure, (char*)"_cbd_t.prompt", (void*) &_cbd_t_prompt_getset } +, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +SWIGINTERN PyObject * +SwigPyBuiltin___cbd_t_richcompare(PyObject *self, PyObject *other, int op) { + PyObject *result = NULL; + PyObject *tuple = PyTuple_New(1); + assert(tuple); + PyTuple_SET_ITEM(tuple, 0, other); + Py_XINCREF(other); + if (!result) { + if (SwigPyObject_Check(self) && SwigPyObject_Check(other)) { + result = SwigPyObject_richcompare((SwigPyObject *)self, (SwigPyObject *)other, op); + } else { + result = Py_NotImplemented; + Py_INCREF(result); + } + } + Py_DECREF(tuple); + return result; +} + +SWIGINTERN PyMethodDef SwigPyBuiltin___cbd_t_methods[] = { + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +static PyHeapTypeObject SwigPyBuiltin___cbd_t_type = { + { +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + "_cbd_t", /* tp_name */ + sizeof(SwigPyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) _wrap_delete__cbd_t_closure, /* tp_dealloc */ + (printfunc) 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ +#if PY_VERSION_HEX >= 0x03000000 + 0, /* tp_compare */ +#else + (cmpfunc) 0, /* tp_compare */ +#endif + (reprfunc) 0, /* tp_repr */ + &SwigPyBuiltin___cbd_t_type.as_number, /* tp_as_number */ + &SwigPyBuiltin___cbd_t_type.as_sequence, /* tp_as_sequence */ + &SwigPyBuiltin___cbd_t_type.as_mapping, /* tp_as_mapping */ + (hashfunc) 0, /* tp_hash */ + (ternaryfunc) 0, /* tp_call */ + (reprfunc) 0, /* tp_str */ + (getattrofunc) 0, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + &SwigPyBuiltin___cbd_t_type.as_buffer, /* tp_as_buffer */ +#if PY_VERSION_HEX >= 0x03000000 + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ +#else + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */ +#endif + "::_cbd_t", /* tp_doc */ + (traverseproc) 0, /* tp_traverse */ + (inquiry) 0, /* tp_clear */ + (richcmpfunc) SwigPyBuiltin___cbd_t_richcompare, /* feature:python:tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc) 0, /* tp_iter */ + (iternextfunc) 0, /* tp_iternext */ + SwigPyBuiltin___cbd_t_methods, /* tp_methods */ + 0, /* tp_members */ + SwigPyBuiltin___cbd_t_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc) 0, /* tp_descr_get */ + (descrsetfunc) 0, /* tp_descr_set */ + (size_t)(((char*)&((SwigPyObject *) 64L)->dict) - (char*) 64L), /* tp_dictoffset */ + (initproc) _wrap_new__cbd_t, /* tp_init */ + (allocfunc) 0, /* tp_alloc */ + (newfunc) 0, /* tp_new */ + (freefunc) 0, /* tp_free */ + (inquiry) 0, /* tp_is_gc */ + (PyObject*) 0, /* tp_bases */ + (PyObject*) 0, /* tp_mro */ + (PyObject*) 0, /* tp_cache */ + (PyObject*) 0, /* tp_subclasses */ + (PyObject*) 0, /* tp_weaklist */ + (destructor) 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + (int) 0, /* tp_version_tag */ +#endif + }, + { + (binaryfunc) 0, /* nb_add */ + (binaryfunc) 0, /* nb_subtract */ + (binaryfunc) 0, /* nb_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_divide */ +#endif + (binaryfunc) 0, /* nb_remainder */ + (binaryfunc) 0, /* nb_divmod */ + (ternaryfunc) 0, /* nb_power */ + (unaryfunc) 0, /* nb_negative */ + (unaryfunc) 0, /* nb_positive */ + (unaryfunc) 0, /* nb_absolute */ + (inquiry) 0, /* nb_nonzero */ + (unaryfunc) 0, /* nb_invert */ + (binaryfunc) 0, /* nb_lshift */ + (binaryfunc) 0, /* nb_rshift */ + (binaryfunc) 0, /* nb_and */ + (binaryfunc) 0, /* nb_xor */ + (binaryfunc) 0, /* nb_or */ +#if PY_VERSION_HEX < 0x03000000 + (coercion) 0, /* nb_coerce */ +#endif + (unaryfunc) 0, /* nb_int */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* nb_reserved */ +#else + (unaryfunc) 0, /* nb_long */ +#endif + (unaryfunc) 0, /* nb_float */ +#if PY_VERSION_HEX < 0x03000000 + (unaryfunc) 0, /* nb_oct */ + (unaryfunc) 0, /* nb_hex */ +#endif + (binaryfunc) 0, /* nb_inplace_add */ + (binaryfunc) 0, /* nb_inplace_subtract */ + (binaryfunc) 0, /* nb_inplace_multiply */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc) 0, /* nb_inplace_divide */ +#endif + (binaryfunc) 0, /* nb_inplace_remainder */ + (ternaryfunc) 0, /* nb_inplace_power */ + (binaryfunc) 0, /* nb_inplace_lshift */ + (binaryfunc) 0, /* nb_inplace_rshift */ + (binaryfunc) 0, /* nb_inplace_and */ + (binaryfunc) 0, /* nb_inplace_xor */ + (binaryfunc) 0, /* nb_inplace_or */ + (binaryfunc) 0, /* nb_floor_divide */ + (binaryfunc) 0, /* nb_true_divide */ + (binaryfunc) 0, /* nb_inplace_floor_divide */ + (binaryfunc) 0, /* nb_inplace_true_divide */ +#if PY_VERSION_HEX >= 0x02050000 + (unaryfunc) 0, /* nb_index */ +#endif + }, + { + (lenfunc) 0, /* mp_length */ + (binaryfunc) 0, /* mp_subscript */ + (objobjargproc) 0, /* mp_ass_subscript */ + }, + { + (lenfunc) 0, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (ssizeargfunc) 0, /* sq_repeat */ + (ssizeargfunc) 0, /* sq_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_slice */ +#else + (ssizessizeargfunc) 0, /* sq_slice */ +#endif + (ssizeobjargproc) 0, /* sq_ass_item */ +#if PY_VERSION_HEX >= 0x03000000 + (void*) 0, /* was_sq_ass_slice */ +#else + (ssizessizeobjargproc) 0, /* sq_ass_slice */ +#endif + (objobjproc) 0, /* sq_contains */ + (binaryfunc) 0, /* sq_inplace_concat */ + (ssizeargfunc) 0, /* sq_inplace_repeat */ + }, + { +#if PY_VERSION_HEX < 0x03000000 + (readbufferproc) 0, /* bf_getreadbuffer */ + (writebufferproc) 0, /* bf_getwritebuffer */ + (segcountproc) 0, /* bf_getsegcount */ + (charbufferproc) 0, /* bf_getcharbuffer */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + (getbufferproc) 0, /* bf_getbuffer */ + (releasebufferproc) 0, /* bf_releasebuffer */ +#endif + }, + (PyObject*) 0, /* ht_name */ + (PyObject*) 0, /* ht_slots */ +}; + +SWIGINTERN SwigPyClientData SwigPyBuiltin___cbd_t_clientdata = {0, 0, 0, 0, 0, 0, (PyTypeObject *)&SwigPyBuiltin___cbd_t_type}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + +static swig_type_info _swigt__p_AES_KEY = {"_p_AES_KEY", "AES_KEY *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ASN1_BIT_STRING = {"_p_ASN1_BIT_STRING", "ASN1_BIT_STRING *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ASN1_INTEGER = {"_p_ASN1_INTEGER", "ASN1_INTEGER *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ASN1_OBJECT = {"_p_ASN1_OBJECT", "ASN1_OBJECT *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ASN1_STRING = {"_p_ASN1_STRING", "ASN1_STRING *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ASN1_TIME = {"_p_ASN1_TIME", "ASN1_TIME *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_BIGNUM = {"_p_BIGNUM", "BIGNUM *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_BIO = {"_p_BIO", "BIO *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_BIO_METHOD = {"_p_BIO_METHOD", "BIO_METHOD *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_DH = {"_p_DH", "DH *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_DSA = {"_p_DSA", "DSA *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ECDSA_SIG = {"_p_ECDSA_SIG", "ECDSA_SIG *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_EC_KEY = {"_p_EC_KEY", "EC_KEY *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ENGINE = {"_p_ENGINE", "ENGINE *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_EVP_CIPHER = {"_p_EVP_CIPHER", "EVP_CIPHER *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_EVP_CIPHER_CTX = {"_p_EVP_CIPHER_CTX", "EVP_CIPHER_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_EVP_MD = {"_p_EVP_MD", "EVP_MD *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_EVP_MD_CTX = {"_p_EVP_MD_CTX", "EVP_MD_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_EVP_PKEY = {"_p_EVP_PKEY", "EVP_PKEY *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_FILE = {"_p_FILE", "FILE *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_HMAC_CTX = {"_p_HMAC_CTX", "HMAC_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_PKCS7 = {"_p_PKCS7", "PKCS7 *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_PyObject = {"_p_PyObject", "PyObject *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_RC4_KEY = {"_p_RC4_KEY", "RC4_KEY *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_RSA = {"_p_RSA", "RSA *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_SSL = {"_p_SSL", "SSL *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_SSL_CIPHER = {"_p_SSL_CIPHER", "SSL_CIPHER *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_SSL_CTX = {"_p_SSL_CTX", "SSL_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_SSL_METHOD = {"_p_SSL_METHOD", "SSL_METHOD *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_SSL_SESSION = {"_p_SSL_SESSION", "SSL_SESSION *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_SwigPyObject = {"_p_SwigPyObject", "SwigPyObject *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_UI_METHOD = {"_p_UI_METHOD", "UI_METHOD *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_X509 = {"_p_X509", "X509 *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_X509V3_CTX = {"_p_X509V3_CTX", "X509V3_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_X509_CRL = {"_p_X509_CRL", "X509_CRL *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_X509_EXTENSION = {"_p_X509_EXTENSION", "X509_EXTENSION *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_X509_NAME = {"_p_X509_NAME", "X509_NAME *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_X509_NAME_ENTRY = {"_p_X509_NAME_ENTRY", "X509_NAME_ENTRY *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_X509_REQ = {"_p_X509_REQ", "X509_REQ *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_X509_STORE = {"_p_X509_STORE", "X509_STORE *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_X509_STORE_CTX = {"_p_X509_STORE_CTX", "X509_STORE_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p__cbd_t = {"_p__cbd_t", "_cbd_t *", 0, 0, (void*)&SwigPyBuiltin___cbd_t_clientdata, 0}; +static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_f_int_p_X509_STORE_CTX__int = {"_p_f_int_p_X509_STORE_CTX__int", "int (*)(int,X509_STORE_CTX *)", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_f_p_q_const__void_p_q_const__void__int = {"_p_f_p_q_const__void_p_q_const__void__int", "int (*)(void const *,void const *)", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_f_p_void__p_void = {"_p_f_p_void__p_void", "void *(*)(void *)", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_f_p_void__void = {"_p_f_p_void__void", "void (*)(void *)", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_ASN1_OBJECT = {"_p_p_ASN1_OBJECT", "ASN1_OBJECT **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_X509_NAME_ENTRY = {"_p_p_X509_NAME_ENTRY", "X509_NAME_ENTRY **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_unsigned_char = {"_p_p_unsigned_char", "unsigned char **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_pyfd_struct = {"_p_pyfd_struct", "BIO_PYFD_CTX *|struct pyfd_struct *|pyfd_struct *", 0, 0, (void*)&SwigPyBuiltin__pyfd_struct_clientdata, 0}; +static swig_type_info _swigt__p_stack_st = {"_p_stack_st", "struct stack_st *|stack_st *|_STACK *", 0, 0, (void*)&SwigPyBuiltin__stack_st_clientdata, 0}; +static swig_type_info _swigt__p_stack_st_OPENSSL_BLOCK = {"_p_stack_st_OPENSSL_BLOCK", "struct stack_st_OPENSSL_BLOCK *|stack_st_OPENSSL_BLOCK *", 0, 0, (void*)&SwigPyBuiltin__stack_st_OPENSSL_BLOCK_clientdata, 0}; +static swig_type_info _swigt__p_stack_st_OPENSSL_STRING = {"_p_stack_st_OPENSSL_STRING", "struct stack_st_OPENSSL_STRING *|stack_st_OPENSSL_STRING *", 0, 0, (void*)&SwigPyBuiltin__stack_st_OPENSSL_STRING_clientdata, 0}; +static swig_type_info _swigt__p_stack_st_SSL_CIPHER = {"_p_stack_st_SSL_CIPHER", "struct stack_st_SSL_CIPHER *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_stack_st_X509 = {"_p_stack_st_X509", "struct stack_st_X509 *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_stack_st_X509_EXTENSION = {"_p_stack_st_X509_EXTENSION", "struct stack_st_X509_EXTENSION *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_void = {"_p_void", "void *", 0, 0, (void*)0, 0}; + +static swig_type_info *swig_type_initial[] = { + &_swigt__p_AES_KEY, + &_swigt__p_ASN1_BIT_STRING, + &_swigt__p_ASN1_INTEGER, + &_swigt__p_ASN1_OBJECT, + &_swigt__p_ASN1_STRING, + &_swigt__p_ASN1_TIME, + &_swigt__p_BIGNUM, + &_swigt__p_BIO, + &_swigt__p_BIO_METHOD, + &_swigt__p_DH, + &_swigt__p_DSA, + &_swigt__p_ECDSA_SIG, + &_swigt__p_EC_KEY, + &_swigt__p_ENGINE, + &_swigt__p_EVP_CIPHER, + &_swigt__p_EVP_CIPHER_CTX, + &_swigt__p_EVP_MD, + &_swigt__p_EVP_MD_CTX, + &_swigt__p_EVP_PKEY, + &_swigt__p_FILE, + &_swigt__p_HMAC_CTX, + &_swigt__p_PKCS7, + &_swigt__p_PyObject, + &_swigt__p_RC4_KEY, + &_swigt__p_RSA, + &_swigt__p_SSL, + &_swigt__p_SSL_CIPHER, + &_swigt__p_SSL_CTX, + &_swigt__p_SSL_METHOD, + &_swigt__p_SSL_SESSION, + &_swigt__p_SwigPyObject, + &_swigt__p_UI_METHOD, + &_swigt__p_X509, + &_swigt__p_X509V3_CTX, + &_swigt__p_X509_CRL, + &_swigt__p_X509_EXTENSION, + &_swigt__p_X509_NAME, + &_swigt__p_X509_NAME_ENTRY, + &_swigt__p_X509_REQ, + &_swigt__p_X509_STORE, + &_swigt__p_X509_STORE_CTX, + &_swigt__p__cbd_t, + &_swigt__p_char, + &_swigt__p_f_int_p_X509_STORE_CTX__int, + &_swigt__p_f_p_q_const__void_p_q_const__void__int, + &_swigt__p_f_p_void__p_void, + &_swigt__p_f_p_void__void, + &_swigt__p_p_ASN1_OBJECT, + &_swigt__p_p_X509_NAME_ENTRY, + &_swigt__p_p_char, + &_swigt__p_p_unsigned_char, + &_swigt__p_pyfd_struct, + &_swigt__p_stack_st, + &_swigt__p_stack_st_OPENSSL_BLOCK, + &_swigt__p_stack_st_OPENSSL_STRING, + &_swigt__p_stack_st_SSL_CIPHER, + &_swigt__p_stack_st_X509, + &_swigt__p_stack_st_X509_EXTENSION, + &_swigt__p_unsigned_char, + &_swigt__p_void, +}; + +static swig_cast_info _swigc__p_AES_KEY[] = { {&_swigt__p_AES_KEY, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ASN1_BIT_STRING[] = { {&_swigt__p_ASN1_BIT_STRING, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ASN1_INTEGER[] = { {&_swigt__p_ASN1_INTEGER, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ASN1_OBJECT[] = { {&_swigt__p_ASN1_OBJECT, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ASN1_STRING[] = { {&_swigt__p_ASN1_STRING, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ASN1_TIME[] = { {&_swigt__p_ASN1_TIME, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_BIGNUM[] = { {&_swigt__p_BIGNUM, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_BIO[] = { {&_swigt__p_BIO, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_BIO_METHOD[] = { {&_swigt__p_BIO_METHOD, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_DH[] = { {&_swigt__p_DH, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_DSA[] = { {&_swigt__p_DSA, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ECDSA_SIG[] = { {&_swigt__p_ECDSA_SIG, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_EC_KEY[] = { {&_swigt__p_EC_KEY, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ENGINE[] = { {&_swigt__p_ENGINE, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_EVP_CIPHER[] = { {&_swigt__p_EVP_CIPHER, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_EVP_CIPHER_CTX[] = { {&_swigt__p_EVP_CIPHER_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_EVP_MD[] = { {&_swigt__p_EVP_MD, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_EVP_MD_CTX[] = { {&_swigt__p_EVP_MD_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_EVP_PKEY[] = { {&_swigt__p_EVP_PKEY, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_FILE[] = { {&_swigt__p_FILE, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_HMAC_CTX[] = { {&_swigt__p_HMAC_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_PKCS7[] = { {&_swigt__p_PKCS7, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_PyObject[] = { {&_swigt__p_PyObject, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_RC4_KEY[] = { {&_swigt__p_RC4_KEY, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_RSA[] = { {&_swigt__p_RSA, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_SSL[] = { {&_swigt__p_SSL, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_SSL_CIPHER[] = { {&_swigt__p_SSL_CIPHER, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_SSL_CTX[] = { {&_swigt__p_SSL_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_SSL_METHOD[] = { {&_swigt__p_SSL_METHOD, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_SSL_SESSION[] = { {&_swigt__p_SSL_SESSION, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_SwigPyObject[] = { {&_swigt__p_SwigPyObject, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_UI_METHOD[] = { {&_swigt__p_UI_METHOD, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_X509[] = { {&_swigt__p_X509, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_X509V3_CTX[] = { {&_swigt__p_X509V3_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_X509_CRL[] = { {&_swigt__p_X509_CRL, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_X509_EXTENSION[] = { {&_swigt__p_X509_EXTENSION, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_X509_NAME[] = { {&_swigt__p_X509_NAME, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_X509_NAME_ENTRY[] = { {&_swigt__p_X509_NAME_ENTRY, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_X509_REQ[] = { {&_swigt__p_X509_REQ, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_X509_STORE[] = { {&_swigt__p_X509_STORE, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_X509_STORE_CTX[] = { {&_swigt__p_X509_STORE_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p__cbd_t[] = { {&_swigt__p__cbd_t, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_f_int_p_X509_STORE_CTX__int[] = { {&_swigt__p_f_int_p_X509_STORE_CTX__int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_f_p_q_const__void_p_q_const__void__int[] = { {&_swigt__p_f_p_q_const__void_p_q_const__void__int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_f_p_void__p_void[] = { {&_swigt__p_f_p_void__p_void, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_f_p_void__void[] = { {&_swigt__p_f_p_void__void, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_ASN1_OBJECT[] = { {&_swigt__p_p_ASN1_OBJECT, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_X509_NAME_ENTRY[] = { {&_swigt__p_p_X509_NAME_ENTRY, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_char[] = { {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_unsigned_char[] = { {&_swigt__p_p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_pyfd_struct[] = { {&_swigt__p_pyfd_struct, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_stack_st[] = { {&_swigt__p_stack_st, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_stack_st_OPENSSL_BLOCK[] = { {&_swigt__p_stack_st_OPENSSL_BLOCK, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_stack_st_OPENSSL_STRING[] = { {&_swigt__p_stack_st_OPENSSL_STRING, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_stack_st_SSL_CIPHER[] = { {&_swigt__p_stack_st_SSL_CIPHER, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_stack_st_X509[] = { {&_swigt__p_stack_st_X509, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_stack_st_X509_EXTENSION[] = { {&_swigt__p_stack_st_X509_EXTENSION, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_char[] = { {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_void[] = { {&_swigt__p_void, 0, 0, 0},{0, 0, 0, 0}}; + +static swig_cast_info *swig_cast_initial[] = { + _swigc__p_AES_KEY, + _swigc__p_ASN1_BIT_STRING, + _swigc__p_ASN1_INTEGER, + _swigc__p_ASN1_OBJECT, + _swigc__p_ASN1_STRING, + _swigc__p_ASN1_TIME, + _swigc__p_BIGNUM, + _swigc__p_BIO, + _swigc__p_BIO_METHOD, + _swigc__p_DH, + _swigc__p_DSA, + _swigc__p_ECDSA_SIG, + _swigc__p_EC_KEY, + _swigc__p_ENGINE, + _swigc__p_EVP_CIPHER, + _swigc__p_EVP_CIPHER_CTX, + _swigc__p_EVP_MD, + _swigc__p_EVP_MD_CTX, + _swigc__p_EVP_PKEY, + _swigc__p_FILE, + _swigc__p_HMAC_CTX, + _swigc__p_PKCS7, + _swigc__p_PyObject, + _swigc__p_RC4_KEY, + _swigc__p_RSA, + _swigc__p_SSL, + _swigc__p_SSL_CIPHER, + _swigc__p_SSL_CTX, + _swigc__p_SSL_METHOD, + _swigc__p_SSL_SESSION, + _swigc__p_SwigPyObject, + _swigc__p_UI_METHOD, + _swigc__p_X509, + _swigc__p_X509V3_CTX, + _swigc__p_X509_CRL, + _swigc__p_X509_EXTENSION, + _swigc__p_X509_NAME, + _swigc__p_X509_NAME_ENTRY, + _swigc__p_X509_REQ, + _swigc__p_X509_STORE, + _swigc__p_X509_STORE_CTX, + _swigc__p__cbd_t, + _swigc__p_char, + _swigc__p_f_int_p_X509_STORE_CTX__int, + _swigc__p_f_p_q_const__void_p_q_const__void__int, + _swigc__p_f_p_void__p_void, + _swigc__p_f_p_void__void, + _swigc__p_p_ASN1_OBJECT, + _swigc__p_p_X509_NAME_ENTRY, + _swigc__p_p_char, + _swigc__p_p_unsigned_char, + _swigc__p_pyfd_struct, + _swigc__p_stack_st, + _swigc__p_stack_st_OPENSSL_BLOCK, + _swigc__p_stack_st_OPENSSL_STRING, + _swigc__p_stack_st_SSL_CIPHER, + _swigc__p_stack_st_X509, + _swigc__p_stack_st_X509_EXTENSION, + _swigc__p_unsigned_char, + _swigc__p_void, +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_const_info swig_const_table[] = { +{0, 0, 0, 0.0, 0, 0}}; + +#ifdef __cplusplus +} +#endif +static PyTypeObject *builtin_bases[2]; + +/* ----------------------------------------------------------------------------- + * Type initialization: + * This problem is tough by the requirement that no dynamic + * memory is used. Also, since swig_type_info structures store pointers to + * swig_cast_info structures and swig_cast_info structures store pointers back + * to swig_type_info structures, we need some lookup code at initialization. + * The idea is that swig generates all the structures that are needed. + * The runtime then collects these partially filled structures. + * The SWIG_InitializeModule function takes these initial arrays out of + * swig_module, and does all the lookup, filling in the swig_module.types + * array with the correct data and linking the correct swig_cast_info + * structures together. + * + * The generated swig_type_info structures are assigned staticly to an initial + * array. We just loop through that array, and handle each type individually. + * First we lookup if this type has been already loaded, and if so, use the + * loaded structure instead of the generated one. Then we have to fill in the + * cast linked list. The cast data is initially stored in something like a + * two-dimensional array. Each row corresponds to a type (there are the same + * number of rows as there are in the swig_type_initial array). Each entry in + * a column is one of the swig_cast_info structures for that type. + * The cast_initial array is actually an array of arrays, because each row has + * a variable number of columns. So to actually build the cast linked list, + * we find the array of casts associated with the type, and loop through it + * adding the casts to the list. The one last trick we need to do is making + * sure the type pointer in the swig_cast_info struct is correct. + * + * First off, we lookup the cast->type name to see if it is already loaded. + * There are three cases to handle: + * 1) If the cast->type has already been loaded AND the type we are adding + * casting info to has not been loaded (it is in this module), THEN we + * replace the cast->type pointer with the type pointer that has already + * been loaded. + * 2) If BOTH types (the one we are adding casting info to, and the + * cast->type) are loaded, THEN the cast info has already been loaded by + * the previous module so we just ignore it. + * 3) Finally, if cast->type has not already been loaded, then we add that + * swig_cast_info to the linked list (because the cast->type) pointer will + * be correct. + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* c-mode */ +#endif +#endif + +#if 0 +#define SWIGRUNTIME_DEBUG +#endif + + +SWIGRUNTIME void +SWIG_InitializeModule(void *clientdata) { + size_t i; + swig_module_info *module_head, *iter; + int found, init; + + /* check to see if the circular list has been setup, if not, set it up */ + if (swig_module.next==0) { + /* Initialize the swig_module */ + swig_module.type_initial = swig_type_initial; + swig_module.cast_initial = swig_cast_initial; + swig_module.next = &swig_module; + init = 1; + } else { + init = 0; + } + + /* Try and load any already created modules */ + module_head = SWIG_GetModule(clientdata); + if (!module_head) { + /* This is the first module loaded for this interpreter */ + /* so set the swig module into the interpreter */ + SWIG_SetModule(clientdata, &swig_module); + module_head = &swig_module; + } else { + /* the interpreter has loaded a SWIG module, but has it loaded this one? */ + found=0; + iter=module_head; + do { + if (iter==&swig_module) { + found=1; + break; + } + iter=iter->next; + } while (iter!= module_head); + + /* if the is found in the list, then all is done and we may leave */ + if (found) return; + /* otherwise we must add out module into the list */ + swig_module.next = module_head->next; + module_head->next = &swig_module; + } + + /* When multiple interpeters are used, a module could have already been initialized in + a different interpreter, but not yet have a pointer in this interpreter. + In this case, we do not want to continue adding types... everything should be + set up already */ + if (init == 0) return; + + /* Now work on filling in swig_module.types */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: size %d\n", swig_module.size); +#endif + for (i = 0; i < swig_module.size; ++i) { + swig_type_info *type = 0; + swig_type_info *ret; + swig_cast_info *cast; + +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); +#endif + + /* if there is another module already loaded */ + if (swig_module.next != &swig_module) { + type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); + } + if (type) { + /* Overwrite clientdata field */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found type %s\n", type->name); +#endif + if (swig_module.type_initial[i]->clientdata) { + type->clientdata = swig_module.type_initial[i]->clientdata; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); +#endif + } + } else { + type = swig_module.type_initial[i]; + } + + /* Insert casting types */ + cast = swig_module.cast_initial[i]; + while (cast->type) { + /* Don't need to add information already in the list */ + ret = 0; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); +#endif + if (swig_module.next != &swig_module) { + ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); +#ifdef SWIGRUNTIME_DEBUG + if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); +#endif + } + if (ret) { + if (type == swig_module.type_initial[i]) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: skip old type %s\n", ret->name); +#endif + cast->type = ret; + ret = 0; + } else { + /* Check for casting already in the list */ + swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); +#ifdef SWIGRUNTIME_DEBUG + if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); +#endif + if (!ocast) ret = 0; + } + } + + if (!ret) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); +#endif + if (type->cast) { + type->cast->prev = cast; + cast->next = type->cast; + } + type->cast = cast; + } + cast++; + } + /* Set entry in modules->types array equal to the type */ + swig_module.types[i] = type; + } + swig_module.types[i] = 0; + +#ifdef SWIGRUNTIME_DEBUG + printf("**** SWIG_InitializeModule: Cast List ******\n"); + for (i = 0; i < swig_module.size; ++i) { + int j = 0; + swig_cast_info *cast = swig_module.cast_initial[i]; + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); + while (cast->type) { + printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); + cast++; + ++j; + } + printf("---- Total casts: %d\n",j); + } + printf("**** SWIG_InitializeModule: Cast List ******\n"); +#endif +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientData(void) { + size_t i; + swig_cast_info *equiv; + static int init_run = 0; + + if (init_run) return; + init_run = 1; + + for (i = 0; i < swig_module.size; i++) { + if (swig_module.types[i]->clientdata) { + equiv = swig_module.types[i]->cast; + while (equiv) { + if (!equiv->converter) { + if (equiv->type && !equiv->type->clientdata) + SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); + } + equiv = equiv->next; + } + } + } +} + +#ifdef __cplusplus +#if 0 +{ + /* c-mode */ +#endif +} +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + /* Python-specific SWIG API */ +#define SWIG_newvarlink() SWIG_Python_newvarlink() +#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr) +#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants) + + /* ----------------------------------------------------------------------------- + * global variable support code. + * ----------------------------------------------------------------------------- */ + + typedef struct swig_globalvar { + char *name; /* Name of global variable */ + PyObject *(*get_attr)(void); /* Return the current value */ + int (*set_attr)(PyObject *); /* Set the value */ + struct swig_globalvar *next; + } swig_globalvar; + + typedef struct swig_varlinkobject { + PyObject_HEAD + swig_globalvar *vars; + } swig_varlinkobject; + + SWIGINTERN PyObject * + swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_InternFromString(""); +#else + return PyString_FromString(""); +#endif + } + + SWIGINTERN PyObject * + swig_varlink_str(swig_varlinkobject *v) { +#if PY_VERSION_HEX >= 0x03000000 + PyObject *str = PyUnicode_InternFromString("("); + PyObject *tail; + PyObject *joined; + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + tail = PyUnicode_FromString(var->name); + joined = PyUnicode_Concat(str, tail); + Py_DecRef(str); + Py_DecRef(tail); + str = joined; + if (var->next) { + tail = PyUnicode_InternFromString(", "); + joined = PyUnicode_Concat(str, tail); + Py_DecRef(str); + Py_DecRef(tail); + str = joined; + } + } + tail = PyUnicode_InternFromString(")"); + joined = PyUnicode_Concat(str, tail); + Py_DecRef(str); + Py_DecRef(tail); + str = joined; +#else + PyObject *str = PyString_FromString("("); + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + PyString_ConcatAndDel(&str,PyString_FromString(var->name)); + if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); + } + PyString_ConcatAndDel(&str,PyString_FromString(")")); +#endif + return str; + } + + SWIGINTERN int + swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { + char *tmp; + PyObject *str = swig_varlink_str(v); + fprintf(fp,"Swig global variables "); + fprintf(fp,"%s\n", tmp = SWIG_Python_str_AsChar(str)); + SWIG_Python_str_DelForPy3(tmp); + Py_DECREF(str); + return 0; + } + + SWIGINTERN void + swig_varlink_dealloc(swig_varlinkobject *v) { + swig_globalvar *var = v->vars; + while (var) { + swig_globalvar *n = var->next; + free(var->name); + free(var); + var = n; + } + } + + SWIGINTERN PyObject * + swig_varlink_getattr(swig_varlinkobject *v, char *n) { + PyObject *res = NULL; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->get_attr)(); + break; + } + var = var->next; + } + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN int + swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { + int res = 1; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->set_attr)(p); + break; + } + var = var->next; + } + if (res == 1 && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN PyTypeObject* + swig_varlink_type(void) { + static char varlink__doc__[] = "Swig var link object"; + static PyTypeObject varlink_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp = { + /* PyObject header changed in Python 3 */ +#if PY_VERSION_HEX >= 0x03000000 + PyVarObject_HEAD_INIT(NULL, 0) +#else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ +#endif + (char *)"swigvarlink", /* tp_name */ + sizeof(swig_varlinkobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) swig_varlink_dealloc, /* tp_dealloc */ + (printfunc) swig_varlink_print, /* tp_print */ + (getattrfunc) swig_varlink_getattr, /* tp_getattr */ + (setattrfunc) swig_varlink_setattr, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc) swig_varlink_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc) swig_varlink_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + varlink__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + varlink_type = tmp; + type_init = 1; +#if PY_VERSION_HEX < 0x02020000 + varlink_type.ob_type = &PyType_Type; +#else + if (PyType_Ready(&varlink_type) < 0) + return NULL; +#endif + } + return &varlink_type; + } + + /* Create a variable linking object for use later */ + SWIGINTERN PyObject * + SWIG_Python_newvarlink(void) { + swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type()); + if (result) { + result->vars = 0; + } + return ((PyObject*) result); + } + + SWIGINTERN void + SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) { + swig_varlinkobject *v = (swig_varlinkobject *) p; + swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar)); + if (gv) { + size_t size = strlen(name)+1; + gv->name = (char *)malloc(size); + if (gv->name) { + strncpy(gv->name,name,size); + gv->get_attr = get_attr; + gv->set_attr = set_attr; + gv->next = v->vars; + } + } + v->vars = gv; + } + + SWIGINTERN PyObject * + SWIG_globals(void) { + static PyObject *_SWIG_globals = 0; + if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink(); + return _SWIG_globals; + } + + /* ----------------------------------------------------------------------------- + * constants/methods manipulation + * ----------------------------------------------------------------------------- */ + + /* Install Constants */ + SWIGINTERN void + SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) { + PyObject *obj = 0; + size_t i; + for (i = 0; constants[i].type; ++i) { + switch(constants[i].type) { + case SWIG_PY_POINTER: + obj = SWIG_InternalNewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); + break; + case SWIG_PY_BINARY: + obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); + break; + default: + obj = 0; + break; + } + if (obj) { + PyDict_SetItemString(d, constants[i].name, obj); + Py_DECREF(obj); + } + } + } + + /* -----------------------------------------------------------------------------*/ + /* Fix SwigMethods to carry the callback ptrs when needed */ + /* -----------------------------------------------------------------------------*/ + + SWIGINTERN void + SWIG_Python_FixMethods(PyMethodDef *methods, + swig_const_info *const_table, + swig_type_info **types, + swig_type_info **types_initial) { + size_t i; + for (i = 0; methods[i].ml_name; ++i) { + const char *c = methods[i].ml_doc; + if (c && (c = strstr(c, "swig_ptr: "))) { + int j; + swig_const_info *ci = 0; + const char *name = c + 10; + for (j = 0; const_table[j].type; ++j) { + if (strncmp(const_table[j].name, name, + strlen(const_table[j].name)) == 0) { + ci = &(const_table[j]); + break; + } + } + if (ci) { + void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0; + if (ptr) { + size_t shift = (ci->ptype) - types; + swig_type_info *ty = types_initial[shift]; + size_t ldoc = (c - methods[i].ml_doc); + size_t lptr = strlen(ty->name)+2*sizeof(void*)+2; + char *ndoc = (char*)malloc(ldoc + lptr + 10); + if (ndoc) { + char *buff = ndoc; + strncpy(buff, methods[i].ml_doc, ldoc); + buff += ldoc; + strncpy(buff, "swig_ptr: ", 10); + buff += 10; + SWIG_PackVoidPtr(buff, ptr, ty->name, lptr); + methods[i].ml_doc = ndoc; + } + } + } + } + } + } + +#ifdef __cplusplus +} +#endif + +/* -----------------------------------------------------------------------------* + * Partial Init method + * -----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" +#endif + +SWIGEXPORT +#if PY_VERSION_HEX >= 0x03000000 +PyObject* +#else +void +#endif +SWIG_init(void) { + PyObject *m, *d, *md; +#if PY_VERSION_HEX >= 0x03000000 + static struct PyModuleDef SWIG_module = { +# if PY_VERSION_HEX >= 0x03020000 + PyModuleDef_HEAD_INIT, +# else + { + PyObject_HEAD_INIT(NULL) + NULL, /* m_init */ + 0, /* m_index */ + NULL, /* m_copy */ + }, +# endif + (char *) SWIG_name, + NULL, + -1, + SwigMethods, + NULL, + NULL, + NULL, + NULL + }; +#endif + +#if defined(SWIGPYTHON_BUILTIN) + static SwigPyClientData SwigPyObject_clientdata = { + 0, 0, 0, 0, 0, 0, 0 + }; + static PyGetSetDef this_getset_def = { + (char *)"this", &SwigPyBuiltin_ThisClosure, NULL, NULL, NULL + }; + static SwigPyGetSet thisown_getset_closure = { + (PyCFunction) SwigPyObject_own, + (PyCFunction) SwigPyObject_own + }; + static PyGetSetDef thisown_getset_def = { + (char *)"thisown", SwigPyBuiltin_GetterClosure, SwigPyBuiltin_SetterClosure, NULL, &thisown_getset_closure + }; + PyObject *metatype_args; + PyTypeObject *builtin_pytype; + int builtin_base_count; + swig_type_info *builtin_basetype; + PyObject *tuple; + PyGetSetDescrObject *static_getset; + PyTypeObject *metatype; + SwigPyClientData *cd; + PyObject *public_interface, *public_symbol; + PyObject *this_descr; + PyObject *thisown_descr; + int i; + + (void)builtin_pytype; + (void)builtin_base_count; + (void)builtin_basetype; + (void)tuple; + (void)static_getset; + + /* metatype is used to implement static member variables. */ + metatype_args = Py_BuildValue("(s(O){})", "SwigPyObjectType", &PyType_Type); + assert(metatype_args); + metatype = (PyTypeObject *) PyType_Type.tp_call((PyObject *) &PyType_Type, metatype_args, NULL); + assert(metatype); + Py_DECREF(metatype_args); + metatype->tp_setattro = (setattrofunc) &SwigPyObjectType_setattro; + assert(PyType_Ready(metatype) >= 0); +#endif + + /* Fix SwigMethods to carry the callback ptrs when needed */ + SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); + +#if PY_VERSION_HEX >= 0x03000000 + m = PyModule_Create(&SWIG_module); +#else + m = Py_InitModule((char *) SWIG_name, SwigMethods); +#endif + md = d = PyModule_GetDict(m); + (void)md; + + SWIG_InitializeModule(0); + +#ifdef SWIGPYTHON_BUILTIN + SwigPyObject_stype = SWIG_MangledTypeQuery("_p_SwigPyObject"); + assert(SwigPyObject_stype); + cd = (SwigPyClientData*) SwigPyObject_stype->clientdata; + if (!cd) { + SwigPyObject_stype->clientdata = &SwigPyObject_clientdata; + SwigPyObject_clientdata.pytype = SwigPyObject_TypeOnce(); + } else if (SwigPyObject_TypeOnce()->tp_basicsize != cd->pytype->tp_basicsize) { + PyErr_SetString(PyExc_RuntimeError, "Import error: attempted to load two incompatible swig-generated modules."); +# if PY_VERSION_HEX >= 0x03000000 + return NULL; +# else + return; +# endif + } + + /* All objects have a 'this' attribute */ + this_descr = PyDescr_NewGetSet(SwigPyObject_type(), &this_getset_def); + (void)this_descr; + + /* All objects have a 'thisown' attribute */ + thisown_descr = PyDescr_NewGetSet(SwigPyObject_type(), &thisown_getset_def); + (void)thisown_descr; + + public_interface = PyList_New(0); + public_symbol = 0; + (void)public_symbol; + + PyDict_SetItemString(md, "__all__", public_interface); + Py_DECREF(public_interface); + for (i = 0; SwigMethods[i].ml_name != NULL; ++i) + SwigPyBuiltin_AddPublicSymbol(public_interface, SwigMethods[i].ml_name); + for (i = 0; swig_const_table[i].name != 0; ++i) + SwigPyBuiltin_AddPublicSymbol(public_interface, swig_const_table[i].name); +#endif + + SWIG_InstallConstants(d,swig_const_table); + + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "OPENSSL_VERSION_NUMBER",SWIG_From_long((long)(0x100020bfL))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "OPENSSL_VERSION_TEXT",SWIG_FromCharPtr("OpenSSL 1.0.2k 26 Jan 2017")); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "OPENSSL_VERSION_PTEXT",SWIG_FromCharPtr(" part of OpenSSL 1.0.2k 26 Jan 2017")); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SHLIB_VERSION_HISTORY",SWIG_FromCharPtr("")); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SHLIB_VERSION_NUMBER",SWIG_FromCharPtr("1.0.2k")); + + /* type '::stack_st' */ + builtin_pytype = (PyTypeObject *)&SwigPyBuiltin__stack_st_type; + builtin_pytype->tp_dict = d = PyDict_New(); + SwigPyBuiltin_SetMetaType(builtin_pytype, metatype); + builtin_pytype->tp_new = PyType_GenericNew; + builtin_base_count = 0; + builtin_bases[builtin_base_count] = NULL; + SwigPyBuiltin_InitBases(builtin_pytype, builtin_bases); + PyDict_SetItemString(d, "this", this_descr); + PyDict_SetItemString(d, "thisown", thisown_descr); + if (PyType_Ready(builtin_pytype) < 0) { + PyErr_SetString(PyExc_TypeError, "Could not create type '_STACK'."); +#if PY_VERSION_HEX >= 0x03000000 + return NULL; +#else + return; +#endif + } + Py_INCREF(builtin_pytype); + PyModule_AddObject(m, "_STACK", (PyObject*) builtin_pytype); + SwigPyBuiltin_AddPublicSymbol(public_interface, "_STACK"); + d = md; + + /* type '::stack_st_OPENSSL_STRING' */ + builtin_pytype = (PyTypeObject *)&SwigPyBuiltin__stack_st_OPENSSL_STRING_type; + builtin_pytype->tp_dict = d = PyDict_New(); + SwigPyBuiltin_SetMetaType(builtin_pytype, metatype); + builtin_pytype->tp_new = PyType_GenericNew; + builtin_base_count = 0; + builtin_bases[builtin_base_count] = NULL; + SwigPyBuiltin_InitBases(builtin_pytype, builtin_bases); + PyDict_SetItemString(d, "this", this_descr); + PyDict_SetItemString(d, "thisown", thisown_descr); + if (PyType_Ready(builtin_pytype) < 0) { + PyErr_SetString(PyExc_TypeError, "Could not create type 'stack_st_OPENSSL_STRING'."); +#if PY_VERSION_HEX >= 0x03000000 + return NULL; +#else + return; +#endif + } + Py_INCREF(builtin_pytype); + PyModule_AddObject(m, "stack_st_OPENSSL_STRING", (PyObject*) builtin_pytype); + SwigPyBuiltin_AddPublicSymbol(public_interface, "stack_st_OPENSSL_STRING"); + d = md; + + /* type '::stack_st_OPENSSL_BLOCK' */ + builtin_pytype = (PyTypeObject *)&SwigPyBuiltin__stack_st_OPENSSL_BLOCK_type; + builtin_pytype->tp_dict = d = PyDict_New(); + SwigPyBuiltin_SetMetaType(builtin_pytype, metatype); + builtin_pytype->tp_new = PyType_GenericNew; + builtin_base_count = 0; + builtin_bases[builtin_base_count] = NULL; + SwigPyBuiltin_InitBases(builtin_pytype, builtin_bases); + PyDict_SetItemString(d, "this", this_descr); + PyDict_SetItemString(d, "thisown", thisown_descr); + if (PyType_Ready(builtin_pytype) < 0) { + PyErr_SetString(PyExc_TypeError, "Could not create type 'stack_st_OPENSSL_BLOCK'."); +#if PY_VERSION_HEX >= 0x03000000 + return NULL; +#else + return; +#endif + } + Py_INCREF(builtin_pytype); + PyModule_AddObject(m, "stack_st_OPENSSL_BLOCK", (PyObject*) builtin_pytype); + SwigPyBuiltin_AddPublicSymbol(public_interface, "stack_st_OPENSSL_BLOCK"); + d = md; + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "bio_noclose",SWIG_From_int((int)(BIO_NOCLOSE))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "bio_close",SWIG_From_int((int)(BIO_CLOSE))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "BIO_FLAGS_READ",SWIG_From_int((int)(0x01))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "BIO_FLAGS_WRITE",SWIG_From_int((int)(0x02))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "BIO_FLAGS_IO_SPECIAL",SWIG_From_int((int)(0x04))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "BIO_FLAGS_RWS",SWIG_From_int((int)((BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "BIO_FLAGS_SHOULD_RETRY",SWIG_From_int((int)(0x08))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "BIO_FLAGS_MEM_RDONLY",SWIG_From_int((int)(0x200))); + PyDict_SetItemString(md,(char*)"cvar", SWIG_globals()); + SwigPyBuiltin_AddPublicSymbol(public_interface, "cvar"); + SWIG_addvarlink(SWIG_globals(),(char*)"_bio_err",Swig_var__bio_err_get, Swig_var__bio_err_set); + + /* type '::pyfd_struct' */ + builtin_pytype = (PyTypeObject *)&SwigPyBuiltin__pyfd_struct_type; + builtin_pytype->tp_dict = d = PyDict_New(); + SwigPyBuiltin_SetMetaType(builtin_pytype, metatype); + builtin_pytype->tp_new = PyType_GenericNew; + builtin_base_count = 0; + builtin_bases[builtin_base_count] = NULL; + SwigPyBuiltin_InitBases(builtin_pytype, builtin_bases); + PyDict_SetItemString(d, "this", this_descr); + PyDict_SetItemString(d, "thisown", thisown_descr); + if (PyType_Ready(builtin_pytype) < 0) { + PyErr_SetString(PyExc_TypeError, "Could not create type 'BIO_PYFD_CTX'."); +#if PY_VERSION_HEX >= 0x03000000 + return NULL; +#else + return; +#endif + } + Py_INCREF(builtin_pytype); + PyModule_AddObject(m, "BIO_PYFD_CTX", (PyObject*) builtin_pytype); + SwigPyBuiltin_AddPublicSymbol(public_interface, "BIO_PYFD_CTX"); + d = md; + SWIG_addvarlink(SWIG_globals(),(char*)"methods_fdp",Swig_var_methods_fdp_get, Swig_var_methods_fdp_set); + SWIG_addvarlink(SWIG_globals(),(char*)"_rand_err",Swig_var__rand_err_get, Swig_var__rand_err_set); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS5_SALT_LEN",SWIG_From_int((int)(8))); + SWIG_addvarlink(SWIG_globals(),(char*)"_evp_err",Swig_var__evp_err_get, Swig_var__evp_err_set); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "AES_BLOCK_SIZE",SWIG_From_int((int)(AES_BLOCK_SIZE))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "OPENSSL_NO_RC4",SWIG_From_int((int)(0))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "dh_check_ok",SWIG_From_int((int)(0))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "dh_check_p_not_prime",SWIG_From_int((int)(DH_CHECK_P_NOT_PRIME))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "dh_check_p_not_strong",SWIG_From_int((int)(DH_CHECK_P_NOT_STRONG_PRIME))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "dh_check_g_failed",SWIG_From_int((int)(DH_UNABLE_TO_CHECK_GENERATOR))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "dh_check_bad_g",SWIG_From_int((int)(DH_NOT_SUITABLE_GENERATOR))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "DH_GENERATOR_2",SWIG_From_int((int)(2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "DH_GENERATOR_5",SWIG_From_int((int)(5))); + SWIG_addvarlink(SWIG_globals(),(char*)"_dh_err",Swig_var__dh_err_get, Swig_var__dh_err_set); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "no_padding",SWIG_From_int((int)(RSA_NO_PADDING))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "pkcs1_padding",SWIG_From_int((int)(RSA_PKCS1_PADDING))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "sslv23_padding",SWIG_From_int((int)(RSA_SSLV23_PADDING))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "pkcs1_oaep_padding",SWIG_From_int((int)(RSA_PKCS1_OAEP_PADDING))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sha1",SWIG_From_int((int)(NID_sha1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sha224",SWIG_From_int((int)(NID_sha224))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sha256",SWIG_From_int((int)(NID_sha256))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sha384",SWIG_From_int((int)(NID_sha384))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sha512",SWIG_From_int((int)(NID_sha512))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_md5",SWIG_From_int((int)(NID_md5))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_ripemd160",SWIG_From_int((int)(NID_ripemd160))); + SWIG_addvarlink(SWIG_globals(),(char*)"_rsa_err",Swig_var__rsa_err_get, Swig_var__rsa_err_set); + SWIG_addvarlink(SWIG_globals(),(char*)"_dsa_err",Swig_var__dsa_err_get, Swig_var__dsa_err_set); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ssl_error_none",SWIG_From_int((int)(SSL_ERROR_NONE))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ssl_error_ssl",SWIG_From_int((int)(SSL_ERROR_SSL))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ssl_error_want_read",SWIG_From_int((int)(SSL_ERROR_WANT_READ))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ssl_error_want_write",SWIG_From_int((int)(SSL_ERROR_WANT_WRITE))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ssl_error_want_x509_lookup",SWIG_From_int((int)(SSL_ERROR_WANT_X509_LOOKUP))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ssl_error_syscall",SWIG_From_int((int)(SSL_ERROR_SYSCALL))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ssl_error_zero_return",SWIG_From_int((int)(SSL_ERROR_ZERO_RETURN))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ssl_error_want_connect",SWIG_From_int((int)(SSL_ERROR_WANT_CONNECT))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_VERIFY_NONE",SWIG_From_int((int)(0x00))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_VERIFY_PEER",SWIG_From_int((int)(0x01))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_VERIFY_FAIL_IF_NO_PEER_CERT",SWIG_From_int((int)(0x02))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_VERIFY_CLIENT_ONCE",SWIG_From_int((int)(0x04))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_ST_CONNECT",SWIG_From_int((int)(0x1000))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_ST_ACCEPT",SWIG_From_int((int)(0x2000))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_ST_MASK",SWIG_From_int((int)(0x0FFF))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_ST_INIT",SWIG_From_int((int)((SSL_ST_CONNECT|SSL_ST_ACCEPT)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_ST_BEFORE",SWIG_From_int((int)(0x4000))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_ST_OK",SWIG_From_int((int)(0x03))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_ST_RENEGOTIATE",SWIG_From_int((int)((0x04|SSL_ST_CONNECT|SSL_ST_ACCEPT)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_LOOP",SWIG_From_int((int)(0x01))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_EXIT",SWIG_From_int((int)(0x02))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_READ",SWIG_From_int((int)(0x04))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_WRITE",SWIG_From_int((int)(0x08))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_ALERT",SWIG_From_int((int)(0x4000))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_READ_ALERT",SWIG_From_int((int)((SSL_CB_ALERT|SSL_CB_READ)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_WRITE_ALERT",SWIG_From_int((int)((SSL_CB_ALERT|SSL_CB_WRITE)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_ACCEPT_LOOP",SWIG_From_int((int)((SSL_ST_ACCEPT|SSL_CB_LOOP)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_ACCEPT_EXIT",SWIG_From_int((int)((SSL_ST_ACCEPT|SSL_CB_EXIT)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_CONNECT_LOOP",SWIG_From_int((int)((SSL_ST_CONNECT|SSL_CB_LOOP)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_CONNECT_EXIT",SWIG_From_int((int)((SSL_ST_CONNECT|SSL_CB_EXIT)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_HANDSHAKE_START",SWIG_From_int((int)(0x10))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_CB_HANDSHAKE_DONE",SWIG_From_int((int)(0x20))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_SENT_SHUTDOWN",SWIG_From_int((int)(1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_RECEIVED_SHUTDOWN",SWIG_From_int((int)(2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_SESS_CACHE_OFF",SWIG_From_int((int)(0x000))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_SESS_CACHE_CLIENT",SWIG_From_int((int)(0x001))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_SESS_CACHE_SERVER",SWIG_From_int((int)(0x002))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_SESS_CACHE_BOTH",SWIG_From_int((int)((SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_OP_ALL",SWIG_From_int((int)(0x00000FFFL))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_OP_NO_SSLv2",SWIG_From_int((int)(0x01000000L))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_OP_NO_SSLv3",SWIG_From_int((int)(0x02000000L))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_OP_NO_TLSv1",SWIG_From_int((int)(0x04000000L))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS",SWIG_From_int((int)(0x00000800L))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_MODE_ENABLE_PARTIAL_WRITE",SWIG_From_int((int)(SSL_MODE_ENABLE_PARTIAL_WRITE))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER",SWIG_From_int((int)(SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "SSL_MODE_AUTO_RETRY",SWIG_From_int((int)(SSL_MODE_AUTO_RETRY))); + SWIG_addvarlink(SWIG_globals(),(char*)"_ssl_err",Swig_var__ssl_err_get, Swig_var__ssl_err_set); + SWIG_addvarlink(SWIG_globals(),(char*)"_ssl_timeout_err",Swig_var__ssl_timeout_err_get, Swig_var__ssl_timeout_err_set); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_DEFAULT",SWIG_From_int((int)(-1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_COMPAT",SWIG_From_int((int)(1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_SSL_CLIENT",SWIG_From_int((int)(2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_SSL_SERVER",SWIG_From_int((int)(3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_EMAIL",SWIG_From_int((int)(4))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_OBJECT_SIGN",SWIG_From_int((int)(5))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_OCSP_SIGN",SWIG_From_int((int)(6))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_OCSP_REQUEST",SWIG_From_int((int)(7))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_DYNAMIC",SWIG_From_int((int)(1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_DYNAMIC_NAME",SWIG_From_int((int)(2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_TRUSTED",SWIG_From_int((int)(1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_REJECTED",SWIG_From_int((int)(2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_TRUST_UNTRUSTED",SWIG_From_int((int)(3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_PURPOSE_SSL_CLIENT",SWIG_From_int((int)(1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_PURPOSE_SSL_SERVER",SWIG_From_int((int)(2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_PURPOSE_NS_SSL_SERVER",SWIG_From_int((int)(3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_PURPOSE_SMIME_SIGN",SWIG_From_int((int)(4))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_PURPOSE_SMIME_ENCRYPT",SWIG_From_int((int)(5))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_PURPOSE_CRL_SIGN",SWIG_From_int((int)(6))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_PURPOSE_ANY",SWIG_From_int((int)(7))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_PURPOSE_OCSP_HELPER",SWIG_From_int((int)(8))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509V3_EXT_UNKNOWN_MASK",SWIG_From_long((long)((0xfL << 16)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509V3_EXT_DEFAULT",SWIG_From_long((long)(0))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509V3_EXT_ERROR_UNKNOWN",SWIG_From_long((long)((1L << 16)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509V3_EXT_PARSE_UNKNOWN",SWIG_From_long((long)((2L << 16)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509V3_EXT_DUMP_UNKNOWN",SWIG_From_long((long)((3L << 16)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_commonName",SWIG_From_int((int)(13))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_countryName",SWIG_From_int((int)(14))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_localityName",SWIG_From_int((int)(15))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_stateOrProvinceName",SWIG_From_int((int)(16))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_organizationName",SWIG_From_int((int)(17))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_organizationalUnitName",SWIG_From_int((int)(18))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_serialNumber",SWIG_From_int((int)(105))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_surname",SWIG_From_int((int)(100))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_givenName",SWIG_From_int((int)(99))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_pkcs9_emailAddress",SWIG_From_int((int)(48))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_OK",SWIG_From_int((int)(0))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT",SWIG_From_int((int)(2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_UNABLE_TO_GET_CRL",SWIG_From_int((int)(3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE",SWIG_From_int((int)(4))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE",SWIG_From_int((int)(5))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY",SWIG_From_int((int)(6))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CERT_SIGNATURE_FAILURE",SWIG_From_int((int)(7))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CRL_SIGNATURE_FAILURE",SWIG_From_int((int)(8))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CERT_NOT_YET_VALID",SWIG_From_int((int)(9))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CERT_HAS_EXPIRED",SWIG_From_int((int)(10))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CRL_NOT_YET_VALID",SWIG_From_int((int)(11))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CRL_HAS_EXPIRED",SWIG_From_int((int)(12))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD",SWIG_From_int((int)(13))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD",SWIG_From_int((int)(14))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD",SWIG_From_int((int)(15))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD",SWIG_From_int((int)(16))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_OUT_OF_MEM",SWIG_From_int((int)(17))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT",SWIG_From_int((int)(18))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN",SWIG_From_int((int)(19))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY",SWIG_From_int((int)(20))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE",SWIG_From_int((int)(21))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CERT_CHAIN_TOO_LONG",SWIG_From_int((int)(22))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CERT_REVOKED",SWIG_From_int((int)(23))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_INVALID_CA",SWIG_From_int((int)(24))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_PATH_LENGTH_EXCEEDED",SWIG_From_int((int)(25))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_INVALID_PURPOSE",SWIG_From_int((int)(26))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CERT_UNTRUSTED",SWIG_From_int((int)(27))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_CERT_REJECTED",SWIG_From_int((int)(28))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "X509_V_ERR_APPLICATION_VERIFICATION",SWIG_From_int((int)(50))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_COMPAT",SWIG_From_int((int)(0))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_SEP_COMMA_PLUS",SWIG_From_int((int)((1 << 16)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_SEP_CPLUS_SPC",SWIG_From_int((int)((2 << 16)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_SEP_MULTILINE",SWIG_From_int((int)((4 << 16)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_DN_REV",SWIG_From_int((int)((1 << 20)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_FN_LN",SWIG_From_int((int)((1 << 21)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_SPC_EQ",SWIG_From_int((int)((1 << 23)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_DUMP_UNKNOWN_FIELDS",SWIG_From_int((int)((1 << 24)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_FN_ALIGN",SWIG_From_int((int)((1 << 25)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_ONELINE",SWIG_From_int((int)((ASN1_STRFLGS_RFC2253|ASN1_STRFLGS_ESC_QUOTE|XN_FLAG_SEP_CPLUS_SPC|XN_FLAG_SPC_EQ)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_MULTILINE",SWIG_From_int((int)((ASN1_STRFLGS_ESC_CTRL|ASN1_STRFLGS_ESC_MSB|XN_FLAG_SEP_MULTILINE|XN_FLAG_SPC_EQ|XN_FLAG_FN_LN|XN_FLAG_FN_ALIGN)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "XN_FLAG_RFC2253",SWIG_From_int((int)((ASN1_STRFLGS_RFC2253|XN_FLAG_SEP_COMMA_PLUS|XN_FLAG_DN_REV|XN_FLAG_DUMP_UNKNOWN_FIELDS)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "RSA_3",SWIG_From_int((int)(0x3L))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "RSA_F4",SWIG_From_int((int)(0x10001L))); + SWIG_addvarlink(SWIG_globals(),(char*)"_x509_err",Swig_var__x509_err_get, Swig_var__x509_err_set); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_ESC_2253",SWIG_From_int((int)(1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_ESC_CTRL",SWIG_From_int((int)(2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_ESC_MSB",SWIG_From_int((int)(4))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_ESC_QUOTE",SWIG_From_int((int)(8))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_UTF8_CONVERT",SWIG_From_int((int)(0x10))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_IGNORE_TYPE",SWIG_From_int((int)(0x20))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_SHOW_TYPE",SWIG_From_int((int)(0x40))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_DUMP_ALL",SWIG_From_int((int)(0x80))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_DUMP_UNKNOWN",SWIG_From_int((int)(0x100))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_DUMP_DER",SWIG_From_int((int)(0x200))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ASN1_STRFLGS_RFC2253",SWIG_From_int((int)((ASN1_STRFLGS_ESC_2253|ASN1_STRFLGS_ESC_CTRL|ASN1_STRFLGS_ESC_MSB|ASN1_STRFLGS_UTF8_CONVERT|ASN1_STRFLGS_DUMP_UNKNOWN|ASN1_STRFLGS_DUMP_DER)))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_TEXT",SWIG_From_int((int)(0x1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_NOCERTS",SWIG_From_int((int)(0x2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_NOSIGS",SWIG_From_int((int)(0x4))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_NOCHAIN",SWIG_From_int((int)(0x8))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_NOINTERN",SWIG_From_int((int)(0x10))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_NOVERIFY",SWIG_From_int((int)(0x20))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_DETACHED",SWIG_From_int((int)(0x40))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_BINARY",SWIG_From_int((int)(0x80))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_NOATTR",SWIG_From_int((int)(0x100))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_SIGNED",SWIG_From_int((int)(NID_pkcs7_signed))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_ENVELOPED",SWIG_From_int((int)(NID_pkcs7_enveloped))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_SIGNED_ENVELOPED",SWIG_From_int((int)(NID_pkcs7_signedAndEnveloped))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "PKCS7_DATA",SWIG_From_int((int)(NID_pkcs7_data))); + SWIG_addvarlink(SWIG_globals(),(char*)"_pkcs7_err",Swig_var__pkcs7_err_get, Swig_var__pkcs7_err_set); + SWIG_addvarlink(SWIG_globals(),(char*)"_smime_err",Swig_var__smime_err_get, Swig_var__smime_err_set); + SWIG_addvarlink(SWIG_globals(),(char*)"_util_err",Swig_var__util_err_get, Swig_var__util_err_set); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "OPENSSL_NO_EC",SWIG_From_int((int)(0))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp112r1",SWIG_From_int((int)(NID_secp112r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp112r2",SWIG_From_int((int)(NID_secp112r2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp128r1",SWIG_From_int((int)(NID_secp128r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp128r2",SWIG_From_int((int)(NID_secp128r2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp160k1",SWIG_From_int((int)(NID_secp160k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp160r1",SWIG_From_int((int)(NID_secp160r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp160r2",SWIG_From_int((int)(NID_secp160r2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp192k1",SWIG_From_int((int)(NID_secp192k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp224k1",SWIG_From_int((int)(NID_secp224k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp224r1",SWIG_From_int((int)(NID_secp224r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp256k1",SWIG_From_int((int)(NID_secp256k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp384r1",SWIG_From_int((int)(NID_secp384r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_secp521r1",SWIG_From_int((int)(NID_secp521r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect113r1",SWIG_From_int((int)(NID_sect113r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect113r2",SWIG_From_int((int)(NID_sect113r2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect131r1",SWIG_From_int((int)(NID_sect131r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect131r2",SWIG_From_int((int)(NID_sect131r2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect163k1",SWIG_From_int((int)(NID_sect163k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect163r1",SWIG_From_int((int)(NID_sect163r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect163r2",SWIG_From_int((int)(NID_sect163r2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect193r1",SWIG_From_int((int)(NID_sect193r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect193r2",SWIG_From_int((int)(NID_sect193r2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect233k1",SWIG_From_int((int)(NID_sect233k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect233r1",SWIG_From_int((int)(NID_sect233r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect239k1",SWIG_From_int((int)(NID_sect239k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect283k1",SWIG_From_int((int)(NID_sect283k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect283r1",SWIG_From_int((int)(NID_sect283r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect409k1",SWIG_From_int((int)(NID_sect409k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect409r1",SWIG_From_int((int)(NID_sect409r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect571k1",SWIG_From_int((int)(NID_sect571k1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_sect571r1",SWIG_From_int((int)(NID_sect571r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_prime192v1",SWIG_From_int((int)(NID_X9_62_prime192v1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_prime192v2",SWIG_From_int((int)(NID_X9_62_prime192v2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_prime192v3",SWIG_From_int((int)(NID_X9_62_prime192v3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_prime239v1",SWIG_From_int((int)(NID_X9_62_prime239v1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_prime239v2",SWIG_From_int((int)(NID_X9_62_prime239v2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_prime239v3",SWIG_From_int((int)(NID_X9_62_prime239v3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_prime256v1",SWIG_From_int((int)(NID_X9_62_prime256v1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2pnb163v1",SWIG_From_int((int)(NID_X9_62_c2pnb163v1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2pnb163v2",SWIG_From_int((int)(NID_X9_62_c2pnb163v2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2pnb163v3",SWIG_From_int((int)(NID_X9_62_c2pnb163v3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2pnb176v1",SWIG_From_int((int)(NID_X9_62_c2pnb176v1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2tnb191v1",SWIG_From_int((int)(NID_X9_62_c2tnb191v1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2tnb191v2",SWIG_From_int((int)(NID_X9_62_c2tnb191v2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2tnb191v3",SWIG_From_int((int)(NID_X9_62_c2tnb191v3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2pnb208w1",SWIG_From_int((int)(NID_X9_62_c2pnb208w1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2tnb239v1",SWIG_From_int((int)(NID_X9_62_c2tnb239v1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2tnb239v2",SWIG_From_int((int)(NID_X9_62_c2tnb239v2))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2tnb239v3",SWIG_From_int((int)(NID_X9_62_c2tnb239v3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2pnb272w1",SWIG_From_int((int)(NID_X9_62_c2pnb272w1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2pnb304w1",SWIG_From_int((int)(NID_X9_62_c2pnb304w1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2tnb359v1",SWIG_From_int((int)(NID_X9_62_c2tnb359v1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2pnb368w1",SWIG_From_int((int)(NID_X9_62_c2pnb368w1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_X9_62_c2tnb431r1",SWIG_From_int((int)(NID_X9_62_c2tnb431r1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls1",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls3",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls4",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls4))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls5",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls5))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls6",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls6))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls7",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls7))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls8",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls8))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls9",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls9))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls10",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls10))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls11",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls11))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_wap_wsg_idm_ecid_wtls12",SWIG_From_int((int)(NID_wap_wsg_idm_ecid_wtls12))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_ipsec3",SWIG_From_int((int)(NID_ipsec3))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "NID_ipsec4",SWIG_From_int((int)(NID_ipsec4))); + SWIG_addvarlink(SWIG_globals(),(char*)"_ec_err",Swig_var__ec_err_get, Swig_var__ec_err_set); + + /* type '::_cbd_t' */ + builtin_pytype = (PyTypeObject *)&SwigPyBuiltin___cbd_t_type; + builtin_pytype->tp_dict = d = PyDict_New(); + SwigPyBuiltin_SetMetaType(builtin_pytype, metatype); + builtin_pytype->tp_new = PyType_GenericNew; + builtin_base_count = 0; + builtin_bases[builtin_base_count] = NULL; + SwigPyBuiltin_InitBases(builtin_pytype, builtin_bases); + PyDict_SetItemString(d, "this", this_descr); + PyDict_SetItemString(d, "thisown", thisown_descr); + if (PyType_Ready(builtin_pytype) < 0) { + PyErr_SetString(PyExc_TypeError, "Could not create type '_cbd_t'."); +#if PY_VERSION_HEX >= 0x03000000 + return NULL; +#else + return; +#endif + } + Py_INCREF(builtin_pytype); + PyModule_AddObject(m, "_cbd_t", (PyObject*) builtin_pytype); + SwigPyBuiltin_AddPublicSymbol(public_interface, "_cbd_t"); + d = md; + SWIG_addvarlink(SWIG_globals(),(char*)"_engine_err",Swig_var__engine_err_get, Swig_var__engine_err_set); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_RSA",SWIG_From_int((int)(0x0001))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_DSA",SWIG_From_int((int)(0x0002))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_DH",SWIG_From_int((int)(0x0004))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_RAND",SWIG_From_int((int)(0x0008))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_ECDH",SWIG_From_int((int)(0x0010))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_ECDSA",SWIG_From_int((int)(0x0020))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_CIPHERS",SWIG_From_int((int)(0x0040))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_DIGESTS",SWIG_From_int((int)(0x0080))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_STORE",SWIG_From_int((int)(0x0100))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_ALL",SWIG_From_int((int)(0xFFFF))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "ENGINE_METHOD_NONE",SWIG_From_int((int)(0x0000))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "encrypt",SWIG_From_int((int)(1))); + SWIG_Python_SetConstant(d, d == md ? public_interface : NULL, "decrypt",SWIG_From_int((int)(0))); + + /* Initialize threading */ + SWIG_PYTHON_INITIALIZE_THREADS; +#if PY_VERSION_HEX >= 0x03000000 + return m; +#else + return; +#endif +} + diff --git a/SWIG/_objects.i b/SWIG/_objects.i index 40f5e51..b389d7f 100644 --- a/SWIG/_objects.i +++ b/SWIG/_objects.i @@ -3,7 +3,7 @@ * vim: syntax=c sts=4 sw=4 * * ASN1_OBJECT manipulation functions from OBJ_obj2txt(3SSL). - * + * * Pavel Shramov * IMEC MSU */ @@ -68,7 +68,7 @@ PyObject *obj_obj2txt(const ASN1_OBJECT *obj, int no_name) len = OBJ_obj2txt(dummy, 1, obj, no_name); if (len < 0) { - PyErr_SetString(PyExc_RuntimeError, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(PyExc_RuntimeError); return NULL; } else if (len == 0) { /* XXX: For OpenSSL prior to 0.9.8b. @@ -87,7 +87,9 @@ PyObject *obj_obj2txt(const ASN1_OBJECT *obj, int no_name) buf = PyMem_Malloc(len + 1); len = OBJ_obj2txt(buf, len + 1, obj, no_name); - ret = PyString_FromStringAndSize(buf, len); + + ret = PyBytes_FromStringAndSize(buf, len); + PyMem_Free(buf); return ret; diff --git a/SWIG/_pkcs7.i b/SWIG/_pkcs7.i index 174f40a..d1fddfb 100644 --- a/SWIG/_pkcs7.i +++ b/SWIG/_pkcs7.i @@ -1,7 +1,7 @@ /* Copyright (c) 2000 Ng Pheng Siong. All rights reserved. * Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. */ -/* $Id: _pkcs7.i 723 2010-02-13 06:53:13Z heikki $ */ +/* $Id$ */ %{ #include @@ -40,6 +40,8 @@ extern void PKCS7_add_certificate(PKCS7 *, X509 *); %constant int PKCS7_SIGNED_ENVELOPED = NID_pkcs7_signedAndEnveloped; %constant int PKCS7_DATA = NID_pkcs7_data; +%warnfilter(454) _pkcs7_err; +%warnfilter(454) _smime_err; %inline %{ static PyObject *_pkcs7_err, *_smime_err; @@ -54,24 +56,19 @@ void smime_init(PyObject *smime_err) { } %} -%threadallow pkcs7_encrypt; %inline %{ -PKCS7 *pkcs7_encrypt(STACK_OF(X509) *stack, BIO *bio, EVP_CIPHER *cipher, int flags) { - return PKCS7_encrypt(stack, bio, cipher, flags); -} - PyObject *pkcs7_decrypt(PKCS7 *pkcs7, EVP_PKEY *pkey, X509 *cert, int flags) { int outlen; char *outbuf; BIO *bio; - PyObject *ret; + PyObject *ret; if (!(bio=BIO_new(BIO_s_mem()))) { PyErr_SetString(PyExc_MemoryError, "pkcs7_decrypt"); return NULL; } if (!PKCS7_decrypt(pkcs7, pkey, cert, bio, flags)) { - PyErr_SetString(_pkcs7_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_pkcs7_err); BIO_free(bio); return NULL; } @@ -82,33 +79,90 @@ PyObject *pkcs7_decrypt(PKCS7 *pkcs7, EVP_PKEY *pkey, X509 *cert, int flags) { return NULL; } BIO_read(bio, outbuf, outlen); - ret = PyString_FromStringAndSize(outbuf, outlen); + + ret = PyBytes_FromStringAndSize(outbuf, outlen); + BIO_free(bio); PyMem_Free(outbuf); return ret; } %} -%threadallow pkcs7_sign0; +%typemap(out) PKCS7 * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + m2_PyErr_Msg(_smime_err); + $result = NULL; + } +} +%threadallow pkcs7_encrypt; %inline %{ -PKCS7 *pkcs7_sign0(X509 *x509, EVP_PKEY *pkey, BIO *bio, int flags) { - return PKCS7_sign(x509, pkey, NULL, bio, flags); +PKCS7 *pkcs7_encrypt(STACK_OF(X509) *stack, BIO *bio, EVP_CIPHER *cipher, int flags) { + return PKCS7_encrypt(stack, bio, cipher, flags); } + %} %threadallow pkcs7_sign1; %inline %{ -PKCS7 *pkcs7_sign1(X509 *x509, EVP_PKEY *pkey, STACK_OF(X509) *stack, BIO *bio, int flags) { - return PKCS7_sign(x509, pkey, stack, bio, flags); +PKCS7 *pkcs7_sign1(X509 *x509, EVP_PKEY *pkey, STACK_OF(X509) *stack, BIO *bio, EVP_MD *hash, int flags) { + + PKCS7 *p7 = PKCS7_sign(NULL, NULL, stack, bio, flags | PKCS7_STREAM); + if (p7 == NULL) { + return NULL; + } + if (PKCS7_sign_add_signer(p7, x509, pkey, hash, flags) == NULL) { + return NULL; + } + if (PKCS7_final(p7, bio, flags) != 1) { + return NULL; + } + return p7; } %} +%threadallow pkcs7_sign0; +%inline %{ +PKCS7 *pkcs7_sign0(X509 *x509, EVP_PKEY *pkey, BIO *bio, EVP_MD *hash, int flags) { + return pkcs7_sign1(x509, pkey, NULL, bio, hash, flags); +} +%} + +%typemap(out) PKCS7 * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + m2_PyErr_Msg(_pkcs7_err); + $result = NULL; + } +} +%threadallow pkcs7_read_bio; +%inline %{ +PKCS7 *pkcs7_read_bio(BIO *bio) { + return PEM_read_bio_PKCS7(bio, NULL, NULL, NULL); +} +%} + +%threadallow pkcs7_read_bio_der; +%inline %{ +PKCS7 *pkcs7_read_bio_der(BIO *bio) { + return d2i_PKCS7_bio(bio, NULL); +} +%} + +%typemap(out) PKCS7 * ; + %inline %{ PyObject *pkcs7_verify1(PKCS7 *pkcs7, STACK_OF(X509) *stack, X509_STORE *store, BIO *data, int flags) { int res, outlen; char *outbuf; BIO *bio; - PyObject *ret; + PyObject *ret; if (!(bio=BIO_new(BIO_s_mem()))) { PyErr_SetString(PyExc_MemoryError, "pkcs7_verify1"); @@ -118,7 +172,7 @@ PyObject *pkcs7_verify1(PKCS7 *pkcs7, STACK_OF(X509) *stack, X509_STORE *store, res = PKCS7_verify(pkcs7, stack, store, data, bio, flags); Py_END_ALLOW_THREADS if (!res) { - PyErr_SetString(_pkcs7_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_pkcs7_err); BIO_free(bio); return NULL; } @@ -129,7 +183,9 @@ PyObject *pkcs7_verify1(PKCS7 *pkcs7, STACK_OF(X509) *stack, X509_STORE *store, return NULL; } BIO_read(bio, outbuf, outlen); - ret = PyString_FromStringAndSize(outbuf, outlen); + + ret = PyBytes_FromStringAndSize(outbuf, outlen); + BIO_free(bio); PyMem_Free(outbuf); return ret; @@ -157,6 +213,7 @@ PyObject *smime_read_pkcs7(BIO *bio) { BIO *bcont = NULL; PKCS7 *p7; PyObject *tuple, *_p7, *_BIO; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if (BIO_method_type(bio) == BIO_TYPE_MEM) { /* OpenSSL FAQ explains that this is needed for mem BIO to return EOF, @@ -170,7 +227,7 @@ PyObject *smime_read_pkcs7(BIO *bio) { p7=SMIME_read_PKCS7(bio, &bcont); Py_END_ALLOW_THREADS if (!p7) { - PyErr_SetString(_smime_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_smime_err); return NULL; } if (!(tuple=PyTuple_New(2))) { @@ -190,20 +247,6 @@ PyObject *smime_read_pkcs7(BIO *bio) { } %} -%threadallow pkcs7_read_bio; -%inline %{ -PKCS7 *pkcs7_read_bio(BIO *bio) { - return PEM_read_bio_PKCS7(bio, NULL, NULL, NULL); -} -%} - -%threadallow pkcs7_read_bio_der; -%inline %{ -PKCS7 *pkcs7_read_bio_der(BIO *bio) { - return d2i_PKCS7_bio(bio, NULL); -} -%} - %threadallow pkcs7_write_bio; %inline %{ int pkcs7_write_bio(PKCS7 *pkcs7, BIO* bio) { @@ -232,9 +275,9 @@ int smime_crlf_copy(BIO *in, BIO *out) { return SMIME_crlf_copy(in, out, PKCS7_TEXT); } -/* return STACK_OF(X509)* */ -STACK_OF(X509) *pkcs7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags) { - return PKCS7_get0_signers(p7, certs, flags); +/* return STACK_OF(X509)* */ +STACK_OF(X509) *pkcs7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags) { + return PKCS7_get0_signers(p7, certs, flags); } %} diff --git a/SWIG/_py3k_compat.i b/SWIG/_py3k_compat.i new file mode 100644 index 0000000..7c90bb4 --- /dev/null +++ b/SWIG/_py3k_compat.i @@ -0,0 +1,43 @@ +%{ +#if PY_MAJOR_VERSION >= 3 + +FILE* PyFile_AsFile(PyObject *pyfile) { + FILE* fp; + int fd; + const char *mode_str = NULL; + PyObject *mode_obj; + + if ((fd = PyObject_AsFileDescriptor(pyfile)) == -1) { + PyErr_SetString(PyExc_BlockingIOError, + "Cannot find file handler for the Python file!"); + return NULL; + } + + if ((mode_obj = PyObject_GetAttrString(pyfile, "mode")) == NULL) { + mode_str = "rb"; + PyErr_Clear(); + } + else { + /* convert to plain string + * note that error checking is embedded in the function + */ + mode_str = PyUnicode_AsUTF8AndSize(mode_obj, NULL); + } + + if((fp = fdopen(fd, mode_str)) == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + } + + Py_XDECREF(mode_obj); + return fp; +} + +#else /* PY2K */ + +#define PyLong_FromLong(x) PyInt_FromLong(x) +#define PyUnicode_AsUTF8(x) PyString_AsString(x) +#define PyUnicode_FromString(x) PyString_FromString(x) +#define PyUnicode_Format(x, y) PyString_Format(x, y) + +#endif /* PY_MAJOR_VERSION */ +%} diff --git a/SWIG/_rand.i b/SWIG/_rand.i index 2d4f144..01ab4ef 100644 --- a/SWIG/_rand.i +++ b/SWIG/_rand.i @@ -6,6 +6,8 @@ %module _rand +%rename(rand_file_name) RAND_file_name; +extern const char *RAND_file_name(char *, size_t ); %rename(rand_load_file) RAND_load_file; extern int RAND_load_file(const char *, long); %rename(rand_save_file) RAND_write_file; @@ -17,6 +19,7 @@ extern int RAND_status(void); %rename(rand_cleanup) RAND_cleanup; extern void RAND_cleanup(void); +%warnfilter(454) _rand_err; %inline %{ static PyObject *_rand_err; @@ -27,44 +30,51 @@ void rand_init(PyObject *rand_err) { PyObject *rand_seed(PyObject *seed) { const void *buf; - int len; + int len = 0; - if (m2_PyObject_AsReadBufferInt(seed, &buf, &len) == -1) - return NULL; + m2_PyObject_AsReadBufferInt(seed, &buf, &len); RAND_seed(buf, len); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject *rand_add(PyObject *blob, double entropy) { const void *buf; - int len; + int len = 0; - if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1) - return NULL; + m2_PyObject_AsReadBufferInt(blob, &buf, &len); RAND_add(buf, len, entropy); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject *rand_bytes(int n) { void *blob; + int ret; PyObject *obj; if (!(blob = PyMem_Malloc(n))) { - PyErr_SetString(PyExc_MemoryError, "rand_bytes"); + PyErr_SetString(PyExc_MemoryError, + "Insufficient memory for rand_bytes."); return NULL; } - if (RAND_bytes(blob, n)) { - obj = PyString_FromStringAndSize(blob, n); + if ((ret = RAND_bytes(blob, n)) == 1) { + obj = PyBytes_FromStringAndSize(blob, n); PyMem_Free(blob); return obj; + } else if (ret == 0) { + PyErr_SetString(_rand_err, "Not enough randomness."); + PyMem_Free(blob); + return NULL; + } else if (ret == -1) { + PyErr_SetString(_rand_err, + "Not supported by the current RAND method."); + PyMem_Free(blob); + return NULL; } else { PyMem_Free(blob); - Py_INCREF(Py_None); - return Py_None; + m2_PyErr_Msg(_rand_err); + return NULL; } } @@ -74,7 +84,7 @@ PyObject *rand_pseudo_bytes(int n) { PyObject *tuple; if (!(blob=(unsigned char *)PyMem_Malloc(n))) { - PyErr_SetString(PyExc_MemoryError, "rand_pseudo_bytes"); + PyErr_SetString(PyExc_MemoryError, "Insufficient memory for rand_pseudo_bytes."); return NULL; } if (!(tuple=PyTuple_New(2))) { @@ -86,24 +96,43 @@ PyObject *rand_pseudo_bytes(int n) { if (ret == -1) { PyMem_Free(blob); Py_DECREF(tuple); - Py_INCREF(Py_None); - return Py_None; + PyErr_SetString(_rand_err, + "Function RAND_pseudo_bytes not supported by the current RAND method."); + return NULL; } else { - PyTuple_SET_ITEM(tuple, 0, PyString_FromStringAndSize((char*)blob, n)); + PyTuple_SET_ITEM(tuple, 0, PyBytes_FromStringAndSize((char*)blob, n)); + PyMem_Free(blob); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong((long)ret)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong((long)ret)); return tuple; } } +PyObject *rand_file_name(void) { + PyObject *obj; + char *str; + if ((obj = PyBytes_FromStringAndSize(NULL, BUFSIZ))==NULL) { + PyErr_SetString(PyExc_MemoryError, "rand_file_name"); + return NULL; + } + str=PyBytes_AS_STRING(obj); + if (RAND_file_name(str, BUFSIZ)==NULL) { + PyErr_SetString(PyExc_RuntimeError, "rand_file_name"); + return NULL; + } + if (_PyBytes_Resize(&obj, (Py_ssize_t)strlen(str))!=0) + return NULL; /* mem exception set by _PyBytes_Resize */ + return obj; +} + void rand_screen(void) { -#ifdef __WINDOWS__ +#ifdef _WIN32 RAND_screen(); #endif } int rand_win32_event(unsigned int imsg, int wparam, long lparam) { -#ifdef __WINDOWS__ +#ifdef _WIN32 return RAND_event(imsg, wparam, lparam); #else return 0; @@ -116,7 +145,6 @@ int rand_win32_event(unsigned int imsg, int wparam, long lparam) { RAND_egd RAND_egd_bytes RAND_query_egd_bytes - RAND_file_name */ diff --git a/SWIG/_rc4.i b/SWIG/_rc4.i index 3259997..eb4747e 100644 --- a/SWIG/_rc4.i +++ b/SWIG/_rc4.i @@ -1,6 +1,14 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */ -/* $Id: _rc4.i 522 2007-05-08 22:21:51Z heikki $ */ +/* $Id$ */ + +%include + +#if defined(OPENSSL_NO_RC4) +#undef OPENSSL_NO_RC4 +%constant OPENSSL_NO_RC4 = 1; +#else +%constant OPENSSL_NO_RC4 = 0; %{ #include @@ -11,11 +19,11 @@ %inline %{ RC4_KEY *rc4_new(void) { RC4_KEY *key; - + if (!(key = (RC4_KEY *)PyMem_Malloc(sizeof(RC4_KEY)))) PyErr_SetString(PyExc_MemoryError, "rc4_new"); return key; -} +} void rc4_free(RC4_KEY *key) { PyMem_Free((void *)key); @@ -23,14 +31,13 @@ void rc4_free(RC4_KEY *key) { PyObject *rc4_set_key(RC4_KEY *key, PyObject *value) { const void *vbuf; - int vlen; + int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; RC4_set_key(key, vlen, vbuf); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject *rc4_update(RC4_KEY *key, PyObject *in) { @@ -47,7 +54,9 @@ PyObject *rc4_update(RC4_KEY *key, PyObject *in) { return NULL; } RC4(key, len, buf, out); - ret = PyString_FromStringAndSize(out, len); + + ret = PyBytes_FromStringAndSize(out, len); + PyMem_Free(out); return ret; } @@ -56,3 +65,5 @@ int rc4_type_check(RC4_KEY *key) { return 1; } %} + +#endif diff --git a/SWIG/_rsa.i b/SWIG/_rsa.i index 537e802..4ffae01 100644 --- a/SWIG/_rsa.i +++ b/SWIG/_rsa.i @@ -1,5 +1,5 @@ /* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. */ -/* $Id: _rsa.i 723 2010-02-13 06:53:13Z heikki $ */ +/* $Id$ */ %{ #include @@ -12,12 +12,12 @@ %apply Pointer NONNULL { RSA * }; %apply Pointer NONNULL { PyObject *pyfunc }; +%rename(rsa_size) RSA_size; +extern int RSA_size(const RSA*); %rename(rsa_new) RSA_new; extern RSA *RSA_new(void); %rename(rsa_free) RSA_free; extern void RSA_free(RSA *); -%rename(rsa_size) RSA_size; -extern int RSA_size(const RSA *); %rename(rsa_check_key) RSA_check_key; extern int RSA_check_key(const RSA *); @@ -39,6 +39,7 @@ extern int RSA_check_key(const RSA *); %constant int NID_ripemd160 = NID_ripemd160; +%warnfilter(454) _rsa_err; %inline %{ static PyObject *_rsa_err; @@ -81,7 +82,7 @@ int rsa_write_key_no_cipher(RSA *rsa, BIO *f, PyObject *pyfunc) { Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS - ret = PEM_write_bio_RSAPrivateKey(f, rsa, NULL, NULL, 0, + ret = PEM_write_bio_RSAPrivateKey(f, rsa, NULL, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); @@ -92,7 +93,7 @@ int rsa_write_key_no_cipher(RSA *rsa, BIO *f, PyObject *pyfunc) { %threadallow rsa_read_pub_key; %inline %{ RSA *rsa_read_pub_key(BIO *f) { - return PEM_read_bio_RSA_PUBKEY(f, NULL, NULL, NULL); + return PEM_read_bio_RSA_PUBKEY(f, NULL, NULL, NULL); } %} @@ -103,118 +104,146 @@ int rsa_write_pub_key(RSA *rsa, BIO *f) { } PyObject *rsa_get_e(RSA *rsa) { - if (!rsa->e) { + const BIGNUM* e = NULL; + RSA_get0_key(rsa, NULL, &e, NULL); + if (!e) { PyErr_SetString(_rsa_err, "'e' is unset"); return NULL; } - return bn_to_mpi(rsa->e); + return bn_to_mpi(e); } PyObject *rsa_get_n(RSA *rsa) { - if (!rsa->n) { + const BIGNUM* n = NULL; + RSA_get0_key(rsa, &n, NULL, NULL); + if (!n) { PyErr_SetString(_rsa_err, "'n' is unset"); return NULL; } - return bn_to_mpi(rsa->n); + return bn_to_mpi(n); } -PyObject *rsa_set_e(RSA *rsa, PyObject *value) { - BIGNUM *bn; - const void *vbuf; - int vlen; +PyObject *rsa_set_e(RSA *rsa, PyObject *eval) { + const BIGNUM* n_read = NULL; + BIGNUM* n = NULL; + BIGNUM* e; - if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + if (!(e = m2_PyObject_AsBIGNUM(eval, _rsa_err))) { return NULL; + } - if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); + /* n and e must be set at the same time so if e is unset, set it to zero */ + RSA_get0_key(rsa, &n_read, NULL, NULL); + if (!n_read) { + n = BN_new(); + } + + if (RSA_set0_key(rsa, n, e, NULL) != 1) { + PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); + BN_free(e); + BN_free(n); return NULL; } - if (rsa->e) - BN_free(rsa->e); - rsa->e = bn; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyObject *rsa_set_n(RSA *rsa, PyObject *value) { - BIGNUM *bn; - const void *vbuf; - int vlen; +PyObject *rsa_set_n(RSA *rsa, PyObject *nval) { + BIGNUM* n; + const BIGNUM* e_read = NULL; + BIGNUM* e = NULL; - if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + if (!(n = m2_PyObject_AsBIGNUM(nval, _rsa_err))) { return NULL; + } + + /* n and e must be set at the same time so if e is unset, set it to zero */ + RSA_get0_key(rsa, NULL, &e_read, NULL); + if (!e_read) { + e = BN_new(); + } - if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); + if (RSA_set0_key(rsa, n, e, NULL) != 1) { + PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); + BN_free(n); + BN_free(e); return NULL; } - if (rsa->n) - BN_free(rsa->n); - rsa->n = bn; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyObject *rsa_set_e_bin(RSA *rsa, PyObject *value) { - BIGNUM *bn; - const void *vbuf; - int vlen; +PyObject *rsa_set_en(RSA *rsa, PyObject *eval, PyObject* nval) { + BIGNUM* e, *n; - if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) + if (!(e = m2_PyObject_AsBIGNUM(eval, _rsa_err)) || + !(n = m2_PyObject_AsBIGNUM(nval, _rsa_err))) { return NULL; + } - if (!(bn = BN_bin2bn((unsigned char *)vbuf, vlen, NULL))) { - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); + if (!RSA_set0_key(rsa, n, e, NULL)) { + PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); + BN_free(e); + BN_free(n); return NULL; } - if (rsa->e) - BN_free(rsa->e); - rsa->e = bn; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyObject *rsa_set_n_bin(RSA *rsa, PyObject *value) { - BIGNUM *bn; - const void *vbuf; - int vlen; +static BIGNUM* PyObject_Bin_AsBIGNUM(PyObject* value) { + BIGNUM* bn; + const void* vbuf; + int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(bn = BN_bin2bn((unsigned char *)vbuf, vlen, NULL))) { - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_rsa_err); + return NULL; + } + + return bn; +} + +PyObject *rsa_set_en_bin(RSA *rsa, PyObject *eval, PyObject* nval) { + BIGNUM* e, *n; + + if (!(e = PyObject_Bin_AsBIGNUM(eval)) || + !(n = PyObject_Bin_AsBIGNUM(nval))) { + return NULL; + } + + if (!RSA_set0_key(rsa, e, n, NULL)) { + PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); + BN_free(e); + BN_free(n); return NULL; } - if (rsa->n) - BN_free(rsa->n); - rsa->n = bn; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject *rsa_private_encrypt(RSA *rsa, PyObject *from, int padding) { const void *fbuf; void *tbuf; - int flen, tlen; + int flen = 0, tlen; PyObject *ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return NULL; - if (!(tbuf = PyMem_Malloc(BN_num_bytes(rsa->n)))) { + if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_private_encrypt"); return NULL; } - tlen = RSA_private_encrypt(flen, (unsigned char *)fbuf, + tlen = RSA_private_encrypt(flen, (unsigned char *)fbuf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { + m2_PyErr_Msg(_rsa_err); PyMem_Free(tbuf); - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); return NULL; } - ret = PyString_FromStringAndSize((const char *)tbuf, tlen); + + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); + PyMem_Free(tbuf); return ret; } @@ -222,24 +251,29 @@ PyObject *rsa_private_encrypt(RSA *rsa, PyObject *from, int padding) { PyObject *rsa_public_decrypt(RSA *rsa, PyObject *from, int padding) { const void *fbuf; void *tbuf; - int flen, tlen; + int flen = 0, tlen = 0; PyObject *ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return NULL; - if (!(tbuf = PyMem_Malloc(BN_num_bytes(rsa->n)))) { + /* OpenSSL docs are confused here: it says we only need buffer + * 'RSA_size()-11', but it is true only for RSA PKCS#1 type 1 + * padding. For other uses we need to use different sizes. */ + if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_public_decrypt"); return NULL; } - tlen = RSA_public_decrypt(flen, (unsigned char *)fbuf, + tlen = RSA_public_decrypt(flen, (unsigned char *)fbuf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { + m2_PyErr_Msg(_rsa_err); PyMem_Free(tbuf); - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); return NULL; } - ret = PyString_FromStringAndSize((const char *)tbuf, tlen); + + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); + PyMem_Free(tbuf); return ret; } @@ -247,24 +281,26 @@ PyObject *rsa_public_decrypt(RSA *rsa, PyObject *from, int padding) { PyObject *rsa_public_encrypt(RSA *rsa, PyObject *from, int padding) { const void *fbuf; void *tbuf; - int flen, tlen; + int flen = 0, tlen; PyObject *ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return NULL; - if (!(tbuf = PyMem_Malloc(BN_num_bytes(rsa->n)))) { + if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_public_encrypt"); return NULL; } - tlen = RSA_public_encrypt(flen, (unsigned char *)fbuf, + tlen = RSA_public_encrypt(flen, (unsigned char *)fbuf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { + m2_PyErr_Msg(_rsa_err); PyMem_Free(tbuf); - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); return NULL; } - ret = PyString_FromStringAndSize((const char *)tbuf, tlen); + + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); + PyMem_Free(tbuf); return ret; } @@ -272,24 +308,25 @@ PyObject *rsa_public_encrypt(RSA *rsa, PyObject *from, int padding) { PyObject *rsa_private_decrypt(RSA *rsa, PyObject *from, int padding) { const void *fbuf; void *tbuf; - int flen, tlen; + int flen = 0, tlen; PyObject *ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return NULL; - if (!(tbuf = PyMem_Malloc(BN_num_bytes(rsa->n)))) { + if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_private_decrypt"); return NULL; } - tlen = RSA_private_decrypt(flen, (unsigned char *)fbuf, + tlen = RSA_private_decrypt(flen, (unsigned char *)fbuf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { + m2_PyErr_Msg(_rsa_err); PyMem_Free(tbuf); - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); return NULL; } - ret = PyString_FromStringAndSize((const char *)tbuf, tlen); + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); + PyMem_Free(tbuf); return ret; } @@ -304,7 +341,7 @@ PyObject *rsa_padding_add_pkcs1_pss(RSA *rsa, PyObject *digest, EVP_MD *hash, in if (m2_PyObject_AsReadBufferInt(digest, &dbuf, &dlen) == -1) return NULL; - tlen = RSA_size(rsa); + tlen = RSA_size(rsa); if (!(tbuf = OPENSSL_malloc(tlen))) { PyErr_SetString(PyExc_MemoryError, "rsa_padding_add_pkcs1_pss"); @@ -318,12 +355,12 @@ PyObject *rsa_padding_add_pkcs1_pss(RSA *rsa, PyObject *digest, EVP_MD *hash, in salt_length); if (result == -1) { + m2_PyErr_Msg(_rsa_err); OPENSSL_cleanse(tbuf, tlen); OPENSSL_free(tbuf); - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); return NULL; } - ret = PyString_FromStringAndSize((const char *)tbuf, tlen); + ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); OPENSSL_cleanse(tbuf, tlen); OPENSSL_free(tbuf); return ret; @@ -360,30 +397,32 @@ PyObject *rsa_sign(RSA *rsa, PyObject *py_digest_string, int method_type) { unsigned int real_buf_len = 0; char *digest_string = NULL; unsigned char * sign_buf = NULL; - PyObject *signature; - + PyObject *signature; + ret = m2_PyString_AsStringAndSizeInt(py_digest_string, &digest_string, - &digest_len); + &digest_len); if (ret == -1) { /* PyString_AsStringAndSize raises the correct exceptions. */ return NULL; } - + buf_len = RSA_size(rsa); sign_buf = (unsigned char *)PyMem_Malloc(buf_len); - ret = RSA_sign(method_type, (const unsigned char *)digest_string, digest_len, + ret = RSA_sign(method_type, (const unsigned char *)digest_string, digest_len, sign_buf, &real_buf_len, rsa); - + if (!ret) { + m2_PyErr_Msg(_rsa_err); PyMem_Free(sign_buf); - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); return NULL; } - signature = PyString_FromStringAndSize((const char*) sign_buf, buf_len); + + signature = PyBytes_FromStringAndSize((const char*) sign_buf, buf_len); + PyMem_Free(sign_buf); return signature; -} - +} + int rsa_verify(RSA *rsa, PyObject *py_verify_string, PyObject* py_sign_string, int method_type){ int ret = 0; char * sign_string = NULL; @@ -407,31 +446,57 @@ int rsa_verify(RSA *rsa, PyObject *py_verify_string, PyObject* py_sign_string, i verify_len, (unsigned char *) sign_string, sign_len, rsa); if (!ret) { - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); - } + m2_PyErr_Msg(_rsa_err); + return 0; + } return ret; } -void genrsa_callback(int p, int n, void *arg) { - PyObject *argv, *ret, *cbfunc; +PyObject *rsa_generate_key(int bits, unsigned long e, PyObject *pyfunc) { + RSA *rsa; + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + BN_GENCB *gencb; + BIGNUM *e_big; + int ret; - cbfunc = (PyObject *)arg; - argv = Py_BuildValue("(ii)", p, n); - ret = PyEval_CallObject(cbfunc, argv); - PyErr_Clear(); - Py_DECREF(argv); - Py_XDECREF(ret); -} + if ((e_big=BN_new()) == NULL) { + m2_PyErr_Msg(_rsa_err); + return NULL; + } -RSA *rsa_generate_key(int bits, unsigned long e, PyObject *pyfunc) { - RSA *rsa; + if (BN_set_word(e_big, e) == 0) { + m2_PyErr_Msg(_rsa_err); + BN_free(e_big); + return NULL; + } + + if ((gencb=BN_GENCB_new()) == NULL) { + m2_PyErr_Msg(_rsa_err); + BN_free(e_big); + return NULL; + } + + if ((rsa = RSA_new()) == NULL) { + m2_PyErr_Msg(_rsa_err); + BN_free(e_big); + BN_GENCB_free(gencb); + return NULL; + } + + BN_GENCB_set(gencb, bn_gencb_callback, (void *) pyfunc); Py_INCREF(pyfunc); - rsa = RSA_generate_key(bits, e, genrsa_callback, (void *)pyfunc); + ret = RSA_generate_key_ex(rsa, bits, e_big, gencb); + BN_free(e_big); + BN_GENCB_free(gencb); Py_DECREF(pyfunc); - if (!rsa) - PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); - return rsa; + + if (ret) + return SWIG_NewPointerObj((void *)rsa, SWIGTYPE_p_RSA, 0); + + m2_PyErr_Msg(_rsa_err); + RSA_free(rsa); + return NULL; } int rsa_type_check(RSA *rsa) { @@ -439,7 +504,9 @@ int rsa_type_check(RSA *rsa) { } int rsa_check_pub_key(RSA *rsa) { - return (rsa->e) && (rsa->n); + const BIGNUM* n, *e; + RSA_get0_key(rsa, &n, &e, NULL); + return n && e; } %} @@ -449,4 +516,3 @@ int rsa_write_key_der(RSA *rsa, BIO *bio) { return i2d_RSAPrivateKey_bio(bio, rsa); } %} - diff --git a/SWIG/_ssl.i b/SWIG/_ssl.i index c66418a..7257656 100644 --- a/SWIG/_ssl.i +++ b/SWIG/_ssl.i @@ -7,16 +7,30 @@ ** Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. ** */ -/* $Id: _ssl.i 721 2010-02-13 06:30:33Z heikki $ */ - +/* $Id$ */ %{ #include +#include #include #include #include +#include #include +#ifdef _WIN32 +#include +#include +#pragma comment(lib, "Ws2_32") +typedef unsigned __int64 uint64_t; +#else +#include +#include +#endif %} +#if OPENSSL_VERSION_NUMBER >= 0x10100005L +%include +#endif + %apply Pointer NONNULL { SSL_CTX * }; %apply Pointer NONNULL { SSL * }; %apply Pointer NONNULL { SSL_CIPHER * }; @@ -32,9 +46,9 @@ extern STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl); %rename(ssl_get_version) SSL_get_version; -extern const char *SSL_get_version(CONST SSL *); +extern const char *SSL_get_version(const SSL *); %rename(ssl_get_error) SSL_get_error; -extern int SSL_get_error(CONST SSL *, int); +extern int SSL_get_error(const SSL *, int); %rename(ssl_get_state) SSL_state_string; extern const char *SSL_state_string(const SSL *); %rename(ssl_get_state_v) SSL_state_string_long; @@ -48,29 +62,33 @@ extern const char *SSL_alert_desc_string(int); %rename(ssl_get_alert_desc_v) SSL_alert_desc_string_long; extern const char *SSL_alert_desc_string_long(int); -#ifndef OPENSSL_NO_SSL2 -%rename(sslv2_method) SSLv2_method; -extern SSL_METHOD *SSLv2_method(void); -#endif -#ifndef OPENSSL_NO_SSL3 -%rename(sslv3_method) SSLv3_method; -extern SSL_METHOD *SSLv3_method(void); -#endif %rename(sslv23_method) SSLv23_method; extern SSL_METHOD *SSLv23_method(void); -%rename(tlsv1_method) TLSv1_method; +%ignore TLSv1_method; extern SSL_METHOD *TLSv1_method(void); +%typemap(out) SSL_CTX * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + m2_PyErr_Msg(_ssl_err); + $result = NULL; + } +} %rename(ssl_ctx_new) SSL_CTX_new; extern SSL_CTX *SSL_CTX_new(SSL_METHOD *); +%typemap(out) SSL_CTX *; + %rename(ssl_ctx_free) SSL_CTX_free; extern void SSL_CTX_free(SSL_CTX *); %rename(ssl_ctx_set_verify_depth) SSL_CTX_set_verify_depth; extern void SSL_CTX_set_verify_depth(SSL_CTX *, int); %rename(ssl_ctx_get_verify_depth) SSL_CTX_get_verify_depth; -extern int SSL_CTX_get_verify_depth(CONST SSL_CTX *); +extern int SSL_CTX_get_verify_depth(const SSL_CTX *); %rename(ssl_ctx_get_verify_mode) SSL_CTX_get_verify_mode; -extern int SSL_CTX_get_verify_mode(CONST SSL_CTX *); +extern int SSL_CTX_get_verify_mode(const SSL_CTX *); %rename(ssl_ctx_set_cipher_list) SSL_CTX_set_cipher_list; extern int SSL_CTX_set_cipher_list(SSL_CTX *, const char *); %rename(ssl_ctx_add_session) SSL_CTX_add_session; @@ -80,9 +98,13 @@ extern int SSL_CTX_remove_session(SSL_CTX *, SSL_SESSION *); %rename(ssl_ctx_set_session_timeout) SSL_CTX_set_timeout; extern long SSL_CTX_set_timeout(SSL_CTX *, long); %rename(ssl_ctx_get_session_timeout) SSL_CTX_get_timeout; -extern long SSL_CTX_get_timeout(CONST SSL_CTX *); +extern long SSL_CTX_get_timeout(const SSL_CTX *); %rename(ssl_ctx_get_cert_store) SSL_CTX_get_cert_store; -extern X509_STORE *SSL_CTX_get_cert_store(CONST SSL_CTX *); +extern X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); +%rename(ssl_ctx_set_default_verify_paths) SSL_CTX_set_default_verify_paths; +extern int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); +%rename(ssl_get_ex_data_x509_store_ctx_idx) SSL_get_ex_data_X509_STORE_CTX_idx; +extern int SSL_get_ex_data_X509_STORE_CTX_idx(void); %rename(bio_new_ssl) BIO_new_ssl; extern BIO *BIO_new_ssl(SSL_CTX *, int); @@ -101,7 +123,7 @@ extern void SSL_set_accept_state(SSL *); %rename(ssl_set_connect_state) SSL_set_connect_state; extern void SSL_set_connect_state(SSL *); %rename(ssl_get_shutdown) SSL_get_shutdown; -extern int SSL_get_shutdown(CONST SSL *); +extern int SSL_get_shutdown(const SSL *); %rename(ssl_set_shutdown) SSL_set_shutdown; extern void SSL_set_shutdown(SSL *, int); %rename(ssl_shutdown) SSL_shutdown; @@ -116,35 +138,35 @@ extern int SSL_do_handshake(SSL *); %threadallow SSL_renegotiate; extern int SSL_renegotiate(SSL *); %rename(ssl_pending) SSL_pending; -extern int SSL_pending(CONST SSL *); +extern int SSL_pending(const SSL *); %rename(ssl_get_peer_cert) SSL_get_peer_certificate; -extern X509 *SSL_get_peer_certificate(CONST SSL *); +extern X509 *SSL_get_peer_certificate(const SSL *); %rename(ssl_get_current_cipher) SSL_get_current_cipher; -extern SSL_CIPHER *SSL_get_current_cipher(CONST SSL *); +extern SSL_CIPHER *SSL_get_current_cipher(const SSL *); %rename(ssl_get_verify_mode) SSL_get_verify_mode; -extern int SSL_get_verify_mode(CONST SSL *); +extern int SSL_get_verify_mode(const SSL *); %rename(ssl_get_verify_depth) SSL_get_verify_depth; -extern int SSL_get_verify_depth(CONST SSL *); +extern int SSL_get_verify_depth(const SSL *); %rename(ssl_get_verify_result) SSL_get_verify_result; -extern long SSL_get_verify_result(CONST SSL *); +extern long SSL_get_verify_result(const SSL *); %rename(ssl_get_ssl_ctx) SSL_get_SSL_CTX; -extern SSL_CTX *SSL_get_SSL_CTX(CONST SSL *); +extern SSL_CTX *SSL_get_SSL_CTX(const SSL *); %rename(ssl_get_default_session_timeout) SSL_get_default_timeout; -extern long SSL_get_default_timeout(CONST SSL *); +extern long SSL_get_default_timeout(const SSL *); %rename(ssl_set_cipher_list) SSL_set_cipher_list; extern int SSL_set_cipher_list(SSL *, const char *); %rename(ssl_get_cipher_list) SSL_get_cipher_list; -extern const char *SSL_get_cipher_list(CONST SSL *, int); +extern const char *SSL_get_cipher_list(const SSL *, int); %rename(ssl_cipher_get_name) SSL_CIPHER_get_name; -extern const char *SSL_CIPHER_get_name(CONST SSL_CIPHER *); +extern const char *SSL_CIPHER_get_name(const SSL_CIPHER *); %rename(ssl_cipher_get_version) SSL_CIPHER_get_version; -extern char *SSL_CIPHER_get_version(CONST SSL_CIPHER *); +extern char *SSL_CIPHER_get_version(const SSL_CIPHER *); %rename(ssl_get_session) SSL_get_session; -extern SSL_SESSION *SSL_get_session(CONST SSL *); +extern SSL_SESSION *SSL_get_session(const SSL *); %rename(ssl_get1_session) SSL_get1_session; extern SSL_SESSION *SSL_get1_session(SSL *); %rename(ssl_set_session) SSL_set_session; @@ -153,11 +175,16 @@ extern int SSL_set_session(SSL *, SSL_SESSION *); extern void SSL_SESSION_free(SSL_SESSION *); %rename(ssl_session_print) SSL_SESSION_print; %threadallow SSL_SESSION_print; -extern int SSL_SESSION_print(BIO *, CONST SSL_SESSION *); +extern int SSL_SESSION_print(BIO *, const SSL_SESSION *); %rename(ssl_session_set_timeout) SSL_SESSION_set_timeout; extern long SSL_SESSION_set_timeout(SSL_SESSION *, long); %rename(ssl_session_get_timeout) SSL_SESSION_get_timeout; -extern long SSL_SESSION_get_timeout(CONST SSL_SESSION *); +extern long SSL_SESSION_get_timeout(const SSL_SESSION *); + +extern PyObject *ssl_accept(SSL *ssl, double timeout = -1); +extern PyObject *ssl_connect(SSL *ssl, double timeout = -1); +extern PyObject *ssl_read(SSL *ssl, int num, double timeout = -1); +extern int ssl_write(SSL *ssl, PyObject *blob, double timeout = -1); %constant int ssl_error_none = SSL_ERROR_NONE; %constant int ssl_error_ssl = SSL_ERROR_SSL; @@ -179,7 +206,9 @@ extern long SSL_SESSION_get_timeout(CONST SSL_SESSION *); %constant int SSL_ST_INIT = (SSL_ST_CONNECT|SSL_ST_ACCEPT); %constant int SSL_ST_BEFORE = 0x4000; %constant int SSL_ST_OK = 0x03; -%constant int SSL_ST_RENEGOTIATE = (0x04|SSL_ST_INIT); +/* SWIG 3.0.1 complains about the next line -- simplified declaration for now */ +/*%constant int SSL_ST_RENEGOTIATE = (0x04|SSL_ST_INIT);*/ +%constant int SSL_ST_RENEGOTIATE = (0x04|SSL_ST_CONNECT|SSL_ST_ACCEPT); %constant int SSL_CB_LOOP = 0x01; %constant int SSL_CB_EXIT = 0x02; @@ -211,17 +240,32 @@ extern long SSL_SESSION_get_timeout(CONST SSL_SESSION *); %constant int SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800L; %constant int SSL_MODE_ENABLE_PARTIAL_WRITE = SSL_MODE_ENABLE_PARTIAL_WRITE; -%constant int SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = SSL_MODE_ENABLE_PARTIAL_WRITE; +%constant int SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; %constant int SSL_MODE_AUTO_RETRY = SSL_MODE_AUTO_RETRY; +%ignore ssl_handle_error; +%ignore ssl_sleep_with_timeout; +%warnfilter(454) _ssl_err; +%warnfilter(454) _ssl_timeout_err; %inline %{ static PyObject *_ssl_err; +static PyObject *_ssl_timeout_err; -void ssl_init(PyObject *ssl_err) { +void ssl_init(PyObject *ssl_err, PyObject *ssl_timeout_err) { SSL_library_init(); SSL_load_error_strings(); Py_INCREF(ssl_err); + Py_INCREF(ssl_timeout_err); _ssl_err = ssl_err; + _ssl_timeout_err = ssl_timeout_err; +} + +const SSL_METHOD *tlsv1_method(void) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + PyErr_WarnEx(PyExc_DeprecationWarning, + "Function TLSv1_method has been deprecated.", 1); +#endif + return TLSv1_method(); } void ssl_ctx_passphrase_callback(SSL_CTX *ctx, PyObject *pyfunc) { @@ -232,9 +276,9 @@ void ssl_ctx_passphrase_callback(SSL_CTX *ctx, PyObject *pyfunc) { int ssl_ctx_use_x509(SSL_CTX *ctx, X509 *x) { int i; - + if (!(i = SSL_CTX_use_certificate(ctx, x))) { - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ssl_err); return -1; } return i; @@ -243,9 +287,9 @@ int ssl_ctx_use_x509(SSL_CTX *ctx, X509 *x) { int ssl_ctx_use_cert(SSL_CTX *ctx, char *file) { int i; - + if (!(i = SSL_CTX_use_certificate_file(ctx, file, SSL_FILETYPE_PEM))) { - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ssl_err); return -1; } return i; @@ -255,7 +299,7 @@ int ssl_ctx_use_cert_chain(SSL_CTX *ctx, char *file) { int i; if (!(i = SSL_CTX_use_certificate_chain_file(ctx, file))) { - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ssl_err); return -1; } return i; @@ -264,9 +308,9 @@ int ssl_ctx_use_cert_chain(SSL_CTX *ctx, char *file) { int ssl_ctx_use_privkey(SSL_CTX *ctx, char *file) { int i; - + if (!(i = SSL_CTX_use_PrivateKey_file(ctx, file, SSL_FILETYPE_PEM))) { - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ssl_err); return -1; } return i; @@ -276,7 +320,7 @@ int ssl_ctx_use_rsa_privkey(SSL_CTX *ctx, RSA *rsakey) { int i; if (!(i = SSL_CTX_use_RSAPrivateKey(ctx, rsakey))) { - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ssl_err); return -1; } return i; @@ -286,7 +330,7 @@ int ssl_ctx_use_pkey_privkey(SSL_CTX *ctx, EVP_PKEY *pkey) { int i; if (!(i = SSL_CTX_use_PrivateKey(ctx, pkey))) { - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ssl_err); return -1; } return i; @@ -295,9 +339,9 @@ int ssl_ctx_use_pkey_privkey(SSL_CTX *ctx, EVP_PKEY *pkey) { int ssl_ctx_check_privkey(SSL_CTX *ctx) { int ret; - + if (!(ret = SSL_CTX_check_private_key(ctx))) { - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ssl_err); return -1; } return ret; @@ -320,7 +364,7 @@ void ssl_ctx_set_verify(SSL_CTX *ctx, int mode, PyObject *pyfunc) { int ssl_ctx_set_session_id_context(SSL_CTX *ctx, PyObject *sid_ctx) { const void *buf; - int len; + int len = 0; if (m2_PyObject_AsReadBufferInt(sid_ctx, &buf, &len) == -1) return -1; @@ -379,6 +423,17 @@ long ssl_get_mode(SSL *ssl) { return SSL_get_mode(ssl); } +int ssl_set_tlsext_host_name(SSL *ssl, const char *name) { + long l; + + if (!(l = SSL_set_tlsext_host_name(ssl, name))) { + m2_PyErr_Msg(_ssl_err); + return -1; + } + /* Return an "int" to match the 'typemap(out) int' in _lib.i */ + return 1; +} + void ssl_set_client_CA_list_from_file(SSL *ssl, const char *ca_file) { SSL_set_client_CA_list(ssl, SSL_load_client_CA_file(ca_file)); } @@ -389,7 +444,7 @@ void ssl_set_client_CA_list_from_context(SSL *ssl, SSL_CTX *ctx) { int ssl_set_session_id_context(SSL *ssl, PyObject *sid_ctx) { const void *buf; - int len; + int len = 0; if (m2_PyObject_AsReadBufferInt(sid_ctx, &buf, &len) == -1) return -1; @@ -399,44 +454,172 @@ int ssl_set_session_id_context(SSL *ssl, PyObject *sid_ctx) { int ssl_set_fd(SSL *ssl, int fd) { int ret; - + if (!(ret = SSL_set_fd(ssl, fd))) { - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ssl_err); return -1; } return ret; } -PyObject *ssl_accept(SSL *ssl) { +static void ssl_handle_error(int ssl_err, int ret) { + int err; + + switch (ssl_err) { + case SSL_ERROR_SSL: + PyErr_SetString(_ssl_err, + ERR_reason_error_string(ERR_get_error())); + break; + case SSL_ERROR_SYSCALL: + err = ERR_get_error(); + if (err) + PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); + else if (ret == 0) + PyErr_SetString(_ssl_err, "unexpected eof"); + else if (ret == -1) + PyErr_SetFromErrno(_ssl_err); + else + assert(0); + break; + default: + PyErr_SetString(_ssl_err, "unexpected SSL error"); + } +} + +#ifdef _WIN32 +/* http://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows */ +int gettimeofday(struct timeval *tp, void *tzp) +{ + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime( &system_time ); + SystemTimeToFileTime( &system_time, &file_time ); + time = ((uint64_t)file_time.dwLowDateTime ) ; + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long) ((time - EPOCH) / 10000000L); + tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + return 0; +} +#endif + +static int ssl_sleep_with_timeout(SSL *ssl, const struct timeval *start, + double timeout, int ssl_err) { +#ifdef _WIN32 +WSAPOLLFD fd; +#else +struct pollfd fd; +#endif + struct timeval tv; + int ms, tmp; + + assert(timeout > 0); + again: + gettimeofday(&tv, NULL); + /* tv >= start */ + if ((timeout + start->tv_sec - tv.tv_sec) > INT_MAX / 1000) + ms = -1; + else { + int fract; + + ms = ((start->tv_sec + (int)timeout) - tv.tv_sec) * 1000; + fract = (int)((start->tv_usec + (timeout - (int)timeout) * 1000000 + - tv.tv_usec + 999) / 1000); + if (ms > 0 && fract > INT_MAX - ms) + ms = -1; + else { + ms += fract; + if (ms <= 0) + goto timeout; + } + } + switch (ssl_err) { + case SSL_ERROR_WANT_READ: + fd.fd = SSL_get_rfd(ssl); + fd.events = POLLIN; + break; + + case SSL_ERROR_WANT_WRITE: + fd.fd = SSL_get_wfd(ssl); + fd.events = POLLOUT; + break; + + case SSL_ERROR_WANT_X509_LOOKUP: + return 0; /* FIXME: is this correct? */ + + default: + assert(0); + } + if (fd.fd == -1) { + PyErr_SetString(_ssl_err, "timeout on a non-FD SSL"); + return -1; + } + Py_BEGIN_ALLOW_THREADS +#ifdef _WIN32 + tmp = WSAPoll(&fd, 1, ms); +#else + tmp = poll(&fd, 1, ms); +#endif + Py_END_ALLOW_THREADS + switch (tmp) { + case 1: + return 0; + case 0: + goto timeout; + case -1: +#ifdef _WIN32 + if (WSAGetLastError() == EINTR) +#else + if (errno == EINTR) +#endif + goto again; + PyErr_SetFromErrno(_ssl_err); + return -1; + } + return 0; + + timeout: + PyErr_SetString(_ssl_timeout_err, "timed out"); + return -1; +} + +PyObject *ssl_accept(SSL *ssl, double timeout) { PyObject *obj = NULL; - int r, err; + int r, ssl_err; + struct timeval tv; + if (timeout > 0) + gettimeofday(&tv, NULL); + again: Py_BEGIN_ALLOW_THREADS r = SSL_accept(ssl); + ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS - switch (SSL_get_error(ssl, r)) { + switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: - obj = PyInt_FromLong((long)1); + obj = PyLong_FromLong((long)1); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: - obj = PyInt_FromLong((long)0); - break; - case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + if (timeout <= 0) { + obj = PyLong_FromLong((long)0); + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; obj = NULL; break; + case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: - err = ERR_get_error(); - if (err) - PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); - else if (r == 0) - PyErr_SetString(_ssl_err, "unexpected eof"); - else if (r == -1) - PyErr_SetFromErrno(_ssl_err); + ssl_handle_error(ssl_err, r); obj = NULL; break; } @@ -445,36 +628,38 @@ PyObject *ssl_accept(SSL *ssl) { return obj; } -PyObject *ssl_connect(SSL *ssl) { +PyObject *ssl_connect(SSL *ssl, double timeout) { PyObject *obj = NULL; - int r, err; + int r, ssl_err; + struct timeval tv; + if (timeout > 0) + gettimeofday(&tv, NULL); + again: Py_BEGIN_ALLOW_THREADS r = SSL_connect(ssl); + ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS - switch (SSL_get_error(ssl, r)) { + switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: - obj = PyInt_FromLong((long)1); + obj = PyLong_FromLong((long)1); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: - obj = PyInt_FromLong((long)0); - break; - case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + if (timeout <= 0) { + obj = PyLong_FromLong((long)0); + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; obj = NULL; break; + case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: - err = ERR_get_error(); - if (err) - PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); - else if (r == 0) - PyErr_SetString(_ssl_err, "unexpected eof"); - else if (r == -1) - PyErr_SetFromErrno(_ssl_err); + ssl_handle_error(ssl_err, r); obj = NULL; break; } @@ -487,10 +672,11 @@ void ssl_set_shutdown1(SSL *ssl, int mode) { SSL_set_shutdown(ssl, mode); } -PyObject *ssl_read(SSL *ssl, int num) { +PyObject *ssl_read(SSL *ssl, int num, double timeout) { PyObject *obj = NULL; void *buf; - int r, err; + int r; + struct timeval tv; if (!(buf = PyMem_Malloc(num))) { PyErr_SetString(PyExc_MemoryError, "ssl_read"); @@ -498,37 +684,43 @@ PyObject *ssl_read(SSL *ssl, int num) { } + if (timeout > 0) + gettimeofday(&tv, NULL); + again: Py_BEGIN_ALLOW_THREADS r = SSL_read(ssl, buf, num); Py_END_ALLOW_THREADS - - switch (SSL_get_error(ssl, r)) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - buf = PyMem_Realloc(buf, r); - obj = PyString_FromStringAndSize(buf, r); - break; - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_X509_LOOKUP: - Py_INCREF(Py_None); - obj = Py_None; - break; - case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); - obj = NULL; - break; - case SSL_ERROR_SYSCALL: - err = ERR_get_error(); - if (err) - PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); - else if (r == 0) - PyErr_SetString(_ssl_err, "unexpected eof"); - else if (r == -1) - PyErr_SetFromErrno(_ssl_err); - obj = NULL; - break; + if (r >= 0) { + buf = PyMem_Realloc(buf, r); + obj = PyBytes_FromStringAndSize(buf, r); + } else { + int ssl_err; + + ssl_err = SSL_get_error(ssl, r); + switch (ssl_err) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + assert(0); + + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + if (timeout <= 0) { + Py_INCREF(Py_None); + obj = Py_None; + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; + obj = NULL; + break; + case SSL_ERROR_SSL: + case SSL_ERROR_SYSCALL: + ssl_handle_error(ssl_err, r); + obj = NULL; + break; + } } PyMem_Free(buf); @@ -546,18 +738,20 @@ PyObject *ssl_read_nbio(SSL *ssl, int num) { PyErr_SetString(PyExc_MemoryError, "ssl_read"); return NULL; } - - + + Py_BEGIN_ALLOW_THREADS r = SSL_read(ssl, buf, num); Py_END_ALLOW_THREADS - - + + switch (SSL_get_error(ssl, r)) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: buf = PyMem_Realloc(buf, r); - obj = PyString_FromStringAndSize(buf, r); + + obj = PyBytes_FromStringAndSize(buf, r); + break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: @@ -566,7 +760,7 @@ PyObject *ssl_read_nbio(SSL *ssl, int num) { obj = Py_None; break; case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_ssl_err); obj = NULL; break; case SSL_ERROR_SYSCALL: @@ -581,27 +775,31 @@ PyObject *ssl_read_nbio(SSL *ssl, int num) { break; } PyMem_Free(buf); - - + + return obj; } -int ssl_write(SSL *ssl, PyObject *blob) { - const void *buf; - int len, r, err, ret; +int ssl_write(SSL *ssl, PyObject *blob, double timeout) { + Py_buffer buf; + int r, ssl_err, ret; + struct timeval tv; - if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1) { + if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_CONTIG_RO) == -1) { return -1; } - + if (timeout > 0) + gettimeofday(&tv, NULL); + again: Py_BEGIN_ALLOW_THREADS - r = SSL_write(ssl, buf, len); + r = SSL_write(ssl, buf.buf, buf.len); + ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS - switch (SSL_get_error(ssl, r)) { + switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: ret = r; @@ -609,43 +807,40 @@ int ssl_write(SSL *ssl, PyObject *blob) { case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: + if (timeout <= 0) { + ret = -1; + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; ret = -1; break; case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); - ret = -1; - break; case SSL_ERROR_SYSCALL: - err = ERR_get_error(); - if (err) - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); - else if (r == 0) - PyErr_SetString(_ssl_err, "unexpected eof"); - else if (r == -1) - PyErr_SetFromErrno(_ssl_err); + ssl_handle_error(ssl_err, r); default: ret = -1; } - - + + m2_PyBuffer_Release(blob, &buf); return ret; } int ssl_write_nbio(SSL *ssl, PyObject *blob) { - const void *buf; - int len, r, err, ret; + Py_buffer buf; + int r, err, ret; - if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1) { + if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_CONTIG_RO) == -1) { return -1; } - + Py_BEGIN_ALLOW_THREADS - r = SSL_write(ssl, buf, len); + r = SSL_write(ssl, buf.buf, buf.len); Py_END_ALLOW_THREADS - - + + switch (SSL_get_error(ssl, r)) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: @@ -670,8 +865,8 @@ int ssl_write_nbio(SSL *ssl, PyObject *blob) { default: ret = -1; } - - + + m2_PyBuffer_Release(blob, &buf); return ret; } @@ -683,7 +878,7 @@ int sk_ssl_cipher_num(STACK_OF(SSL_CIPHER) *stack) { return sk_SSL_CIPHER_num(stack); } -SSL_CIPHER *sk_ssl_cipher_value(STACK_OF(SSL_CIPHER) *stack, int idx) { +const SSL_CIPHER *sk_ssl_cipher_value(STACK_OF(SSL_CIPHER) *stack, int idx) { return sk_SSL_CIPHER_value(stack, idx); } @@ -707,12 +902,23 @@ void i2d_ssl_session(BIO *bio, SSL_SESSION *sess) { } %} +%typemap(out) SSL_SESSION * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + m2_PyErr_Msg(_ssl_err); + $result = NULL; + } +} %threadallow ssl_session_read_pem; %inline %{ SSL_SESSION *ssl_session_read_pem(BIO *bio) { return PEM_read_bio_SSL_SESSION(bio, NULL, NULL, NULL); } %} +%typemap(out) SSL_SESSION * ; %threadallow ssl_session_write_pem; %inline %{ diff --git a/SWIG/_threads.i b/SWIG/_threads.i index bb625df..69adb9f 100644 --- a/SWIG/_threads.i +++ b/SWIG/_threads.i @@ -1,18 +1,19 @@ /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */ -/* $Id: _threads.i 690 2009-07-22 08:32:43Z heikki $ */ +/* $Id$ */ %{ #include #include -#ifdef THREADING -static PyThread_type_lock lock_cs[CRYPTO_NUM_LOCKS]; -static long lock_count[CRYPTO_NUM_LOCKS]; +#if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L +#define CRYPTO_num_locks() (CRYPTO_NUM_LOCKS) +static PyThread_type_lock lock_cs[CRYPTO_num_locks()]; +static long lock_count[CRYPTO_num_locks()]; static int thread_mode = 0; #endif void threading_locking_callback(int mode, int type, const char *file, int line) { -#ifdef THREADING +#if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L if (mode & CRYPTO_LOCK) { PyThread_acquire_lock(lock_cs[type], WAIT_LOCK); lock_count[type]++; @@ -24,7 +25,7 @@ void threading_locking_callback(int mode, int type, const char *file, int line) } unsigned long threading_id_callback(void) { -#ifdef THREADING +#if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L return (unsigned long)PyThread_get_thread_ident(); #else return (unsigned long)0; @@ -34,10 +35,10 @@ unsigned long threading_id_callback(void) { %inline %{ void threading_init(void) { -#ifdef THREADING +#if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L int i; if (!thread_mode) { - for (i=0; i %} +%warnfilter(454) _util_err; %inline %{ static PyObject *_util_err; @@ -26,10 +27,12 @@ PyObject *util_hex_to_string(PyObject *blob) { ret = hex_to_string((unsigned char *)buf, len); if (!ret) { - PyErr_SetString(_util_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_util_err); return NULL; } - obj = PyString_FromString(ret); + + obj = PyBytes_FromString(ret); + OPENSSL_free(ret); return obj; } @@ -47,10 +50,10 @@ PyObject *util_string_to_hex(PyObject *blob) { len = len0; ret = string_to_hex((char *)buf, &len); if (ret == NULL) { - PyErr_SetString(_util_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_util_err); return NULL; } - obj = PyString_FromStringAndSize((char*)ret, len); + obj = PyBytes_FromStringAndSize((char*)ret, len); OPENSSL_free(ret); return obj; } diff --git a/SWIG/_x509.i b/SWIG/_x509.i index 0471f68..3c3e83e 100644 --- a/SWIG/_x509.i +++ b/SWIG/_x509.i @@ -7,11 +7,22 @@ ** Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. ** */ -/* $Id: _x509.i 721 2010-02-13 06:30:33Z heikki $ */ +/* $Id$ */ %{ +#include #include #include + +#include + +typedef STACK_OF(X509) SEQ_CERT; + +ASN1_ITEM_TEMPLATE(SEQ_CERT) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, SeqCert, X509) +ASN1_ITEM_TEMPLATE_END(SEQ_CERT) + +IMPLEMENT_ASN1_FUNCTIONS(SEQ_CERT) %} %apply Pointer NONNULL { BIO * }; @@ -62,9 +73,9 @@ extern X509_NAME *X509_get_subject_name(X509 *); %rename(x509_set_subject_name) X509_set_subject_name; extern int X509_set_subject_name(X509 *, X509_NAME *); %rename(x509_cmp_current_time) X509_cmp_current_time; -extern int X509_cmp_current_time(ASN1_UTCTIME *); +extern int X509_cmp_current_time(ASN1_TIME *); + - /* From x509.h */ /* standard trust ids */ %constant int X509_TRUST_DEFAULT = -1; @@ -149,8 +160,6 @@ extern int X509_NAME_add_entry_by_NID(X509_NAME *, int, int, unsigned char *, in %rename(x509_name_print_ex) X509_NAME_print_ex; %threadallow X509_NAME_print_ex; extern int X509_NAME_print_ex(BIO *, X509_NAME *, int, unsigned long); -%rename(x509_name_print_ex_fp) X509_NAME_print_ex_fp; -extern int X509_NAME_print_ex_fp(FILE *, X509_NAME *, int, unsigned long); #if OPENSSL_VERSION_NUMBER >= 0x10000000L %rename(x509_name_hash) X509_NAME_hash_old; @@ -177,14 +186,23 @@ extern ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *); %rename(x509_name_entry_get_data) X509_NAME_ENTRY_get_data; extern ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *); -%typemap(in) (CONST unsigned char *, int) { +%typemap(in) (const unsigned char *, int) { +#if PY_MAJOR_VERSION >= 3 + if (PyBytes_Check($input)) { + Py_ssize_t len; + + $1 = PyBytes_AsString($input); + len = PyBytes_Size($input); +#else if (PyString_Check($input)) { Py_ssize_t len; - $1 = (unsigned char *)PyString_AsString($input); + $1 = (unsigned char *)PyString_AsString($input); len = PyString_Size($input); +#endif // PY_MAJOR_VERSION >= 3 + if (len > INT_MAX) { - PyErr_SetString(PyExc_ValueError, "object too large"); + PyErr_SetString(_x509_err, "object too large"); return NULL; } $2 = len; @@ -194,8 +212,8 @@ extern ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *); } } %rename(x509_name_entry_set_data) X509_NAME_ENTRY_set_data; -extern int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *, int, CONST unsigned char *, int); -%typemap(in) (CONST unsigned char *, int); +extern int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *, int, const unsigned char *, int); +%typemap(in) (const unsigned char *, int); %rename(x509_req_new) X509_REQ_new; extern X509_REQ * X509_REQ_new(); @@ -230,6 +248,9 @@ extern X509_STORE *X509_STORE_new(void); extern void X509_STORE_free(X509_STORE *); %rename(x509_store_add_cert) X509_STORE_add_cert; extern int X509_STORE_add_cert(X509_STORE *, X509 *); +%rename(x509_store_set_verify_cb) X509_STORE_set_verify_cb; +extern void X509_STORE_set_verify_cb(X509_STORE *st, + int (*verify_cb)(int ok, X509_STORE_CTX *ctx)); %rename(x509_store_ctx_get_current_cert) X509_STORE_CTX_get_current_cert; extern X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *); @@ -247,6 +268,35 @@ extern int X509_EXTENSION_get_critical(X509_EXTENSION *); %rename(x509_extension_set_critical) X509_EXTENSION_set_critical; extern int X509_EXTENSION_set_critical(X509_EXTENSION *, int); +%typemap(out) X509 * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + m2_PyErr_Msg(_x509_err); + $result = NULL; + } +} + + +/* Functions using m2_PyErr_Msg and thus using internal Python C API are + * not thread safe, so if we want to have %threadallow here, error + * handling must be done outside of these internal functions. */ +%threadallow x509_read_pem; +%inline %{ +X509 *x509_read_pem(BIO *bio) { + return PEM_read_bio_X509(bio, NULL, NULL, NULL); +} +%} + +%threadallow d2i_x509; +%inline %{ +X509 *d2i_x509(BIO *bio) { + return d2i_X509_bio(bio, NULL); +} +%} +%typemap(out) X509 *; %constant int NID_commonName = 13; %constant int NID_countryName = 14; @@ -319,6 +369,7 @@ extern int X509_EXTENSION_set_critical(X509_EXTENSION *, int); %constant int RSA_3 = 0x3L; %constant int RSA_F4 = 0x10001L; +%warnfilter(454) _x509_err; %inline %{ static PyObject *_x509_err; @@ -328,50 +379,51 @@ void x509_init(PyObject *x509_err) { } %} -%threadallow x509_read_pem; +%typemap(out) X509_REQ * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + m2_PyErr_Msg(_x509_err); + $result = NULL; + } +} +%threadallow d2i_x509_req; %inline %{ -X509 *x509_read_pem(BIO *bio) { - return PEM_read_bio_X509(bio, NULL, NULL, NULL); +X509_REQ *d2i_x509_req(BIO *bio) { + return d2i_X509_REQ_bio(bio, NULL); } %} -%threadallow d2i_x509; +%threadallow x509_req_read_pem; %inline %{ -X509 *d2i_x509(BIO *bio) { - return d2i_X509_bio(bio, NULL); +X509_REQ *x509_req_read_pem(BIO *bio) { + return PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL); } %} -%threadallow d2i_x509_req; -%inline %{ -X509_REQ *d2i_x509_req(BIO *bio) { - return d2i_X509_REQ_bio(bio, NULL); -} +%typemap(out) X509_REQ *; -PyObject *i2d_x509(X509 *x) -{ +%inline %{ +PyObject *i2d_x509(X509 *x) { int len; PyObject *ret = NULL; unsigned char *buf = NULL; len = i2d_X509(x, &buf); if (len < 0) { - PyErr_SetString(_x509_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_x509_err); } - else { - ret = PyString_FromStringAndSize((char*)buf, len); + else { + + ret = PyBytes_FromStringAndSize((char*)buf, len); + OPENSSL_free(buf); } return ret; } %} -%threadallow x509_req_read_pem; -%inline %{ -X509_REQ *x509_req_read_pem(BIO *bio) { - return PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL); -} -%} - %threadallow x509_req_write_pem; %inline %{ int x509_req_write_pem(BIO *bio, X509_REQ *x) { @@ -379,12 +431,25 @@ int x509_req_write_pem(BIO *bio, X509_REQ *x) { } %} +%typemap(out) X509_CRL * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + m2_PyErr_Msg(_x509_err); + $result = NULL; + } +} %threadallow x509_crl_read_pem; %inline %{ X509_CRL *x509_crl_read_pem(BIO *bio) { return PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL); } +%} +%typemap(out) X509_CRL * ; +%inline %{ /* X509_set_version() is a macro. */ int x509_set_version(X509 *x, long version) { return X509_set_version(x, version); @@ -396,22 +461,22 @@ long x509_get_version(X509 *x) { } /* X509_set_notBefore() is a macro. */ -int x509_set_not_before(X509 *x, ASN1_UTCTIME *tm) { +int x509_set_not_before(X509 *x, ASN1_TIME *tm) { return X509_set_notBefore(x, tm); } /* X509_get_notBefore() is a macro. */ -ASN1_UTCTIME *x509_get_not_before(X509 *x) { +ASN1_TIME *x509_get_not_before(X509 *x) { return X509_get_notBefore(x); } /* X509_set_notAfter() is a macro. */ -int x509_set_not_after(X509 *x, ASN1_UTCTIME *tm) { +int x509_set_not_after(X509 *x, ASN1_TIME *tm) { return X509_set_notAfter(x, tm); } /* X509_get_notAfter() is a macro. */ -ASN1_UTCTIME *x509_get_not_after(X509 *x) { +ASN1_TIME *x509_get_not_after(X509 *x) { return X509_get_notAfter(x); } @@ -419,8 +484,8 @@ int x509_sign(X509 *x, EVP_PKEY *pkey, EVP_MD *md) { return X509_sign(x, pkey, md); } -/* XXX The first parameter is really ASN1_TIME, does it matter? */ -ASN1_TIME *x509_gmtime_adj(ASN1_UTCTIME *s, long adj) { +/* x509_gmtime_adj() is a macro. */ +ASN1_TIME *x509_gmtime_adj(ASN1_TIME *s, long adj) { return X509_gmtime_adj(s, adj); } @@ -430,8 +495,7 @@ PyObject *x509_name_by_nid(X509_NAME *name, int nid) { PyObject *ret; if ((len = X509_NAME_get_text_by_NID(name, nid, NULL, 0)) == -1) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } len++; if (!(buf = PyMem_Malloc(len))) { @@ -439,13 +503,15 @@ PyObject *x509_name_by_nid(X509_NAME *name, int nid) { return NULL; } xlen = X509_NAME_get_text_by_NID(name, nid, buf, len); - ret = PyString_FromStringAndSize(buf, xlen); + + ret = PyBytes_FromStringAndSize(buf, xlen); + PyMem_Free(buf); return ret; } int x509_name_set_by_nid(X509_NAME *name, int nid, PyObject *obj) { - return X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (unsigned char *)PyString_AsString(obj), -1, -1, 0); + return X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (unsigned char *)PyBytes_AsString(obj), -1, -1, 0); } /* x509_name_add_entry_by_txt */ @@ -453,15 +519,15 @@ int x509_name_add_entry_by_txt(X509_NAME *name, char *field, int type, char *byt return X509_NAME_add_entry_by_txt(name, field, type, (unsigned char *)bytes, len, loc, set); } -PyObject *x509_name_get_der(X509_NAME *name) -{ +PyObject *x509_name_get_der(X509_NAME *name) { + const char* pder=""; + size_t pderlen; i2d_X509_NAME(name, 0); - return PyString_FromStringAndSize(name->bytes->data, name->bytes->length); -} - -/* sk_X509_new_null() is a macro returning "STACK_OF(X509) *". */ -STACK_OF(X509) *sk_x509_new_null(void) { - return sk_X509_new_null(); + if (!X509_NAME_get0_der(name, (const unsigned char **)pder, &pderlen)) { + m2_PyErr_Msg(_x509_err); + return NULL; + } + return PyBytes_FromStringAndSize(pder, pderlen); } /* sk_X509_free() is a macro. */ @@ -478,9 +544,16 @@ int sk_x509_push(STACK_OF(X509) *stack, X509 *x509) { X509 *sk_x509_pop(STACK_OF(X509) *stack) { return sk_X509_pop(stack); } +%} +%inline %{ int x509_store_load_locations(X509_STORE *store, const char *file) { - return X509_STORE_load_locations(store, file, NULL); + int locations = 0; + + if ((locations = X509_STORE_load_locations(store, file, NULL)) < 1) { + m2_PyErr_Msg(_x509_err); + } + return locations; } int x509_type_check(X509 *x509) { @@ -510,48 +583,56 @@ int x509_req_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts) { X509_NAME_ENTRY *x509_name_entry_create_by_txt(X509_NAME_ENTRY **ne, char *field, int type, char *bytes, int len) { return X509_NAME_ENTRY_create_by_txt( ne, field, type, (unsigned char *)bytes, len); } +%} -#if OPENSSL_VERSION_NUMBER >= 0x10000000L -LHASH_OF(CONF_VALUE) -#else -LHASH -#endif -*x509v3_lhash() { - return lh_new(NULL, NULL); /* Should probably be lh_CONF_VALUE_new but won't compile. */ -} +%typemap(out) X509V3_CTX * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + $result = NULL; + } +} +%inline %{ X509V3_CTX * -#if OPENSSL_VERSION_NUMBER >= 0x10000000L -x509v3_set_conf_lhash(LHASH_OF(CONF_VALUE) * lhash) { -#else -x509v3_set_conf_lhash(LHASH * lhash) { -#endif +x509v3_set_nconf(void) { X509V3_CTX * ctx; + CONF *conf = NCONF_new(NULL); + if (!(ctx=(X509V3_CTX *)PyMem_Malloc(sizeof(X509V3_CTX)))) { - PyErr_SetString(PyExc_MemoryError, "x509v3_set_conf_lhash"); + PyErr_SetString(PyExc_MemoryError, "x509v3_set_nconf"); return NULL; } - X509V3_set_conf_lhash(ctx, lhash); + /* X509V3_set_nconf does not generate any error signs at all. */ + X509V3_set_nconf(ctx, conf); return ctx; } +%} +%typemap(out) X509V3_CTX * ; + +%typemap(out) X509_EXTENSION * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + m2_PyErr_Msg(_x509_err); + $result = NULL; + } +} +%inline %{ X509_EXTENSION * -#if OPENSSL_VERSION_NUMBER >= 0x10000000L -x509v3_ext_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, char *name, char *value) { -#else -x509v3_ext_conf(LHASH *conf, X509V3_CTX *ctx, char *name, char *value) { -#endif +x509v3_ext_conf(void *conf, X509V3_CTX *ctx, char *name, char *value) { X509_EXTENSION * ext = NULL; - ext = X509V3_EXT_conf(conf, ctx, name, value); - PyMem_Free(ctx); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - lh_CONF_VALUE_free(conf); -#else - lh_free(conf); -#endif + ext = X509V3_EXT_conf(conf, ctx, name, value); + PyMem_Free(ctx); return ext; } +%} +%typemap(out) X509_EXTENSION * ; +%inline %{ /* X509_EXTENSION_free() might be a macro, didn't find definition. */ void x509_extension_free(X509_EXTENSION *ext) { X509_EXTENSION_free(ext); @@ -559,13 +640,13 @@ void x509_extension_free(X509_EXTENSION *ext) { PyObject *x509_extension_get_name(X509_EXTENSION *ext) { PyObject * ext_name; - const char * ext_name_str; + const char * ext_name_str; ext_name_str = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); if (!ext_name_str) { - PyErr_SetString(_x509_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_x509_err); return NULL; } - ext_name = PyString_FromStringAndSize(ext_name_str, strlen(ext_name_str)); + ext_name = PyBytes_FromStringAndSize(ext_name_str, strlen(ext_name_str)); return ext_name; } @@ -604,59 +685,89 @@ void *x509_store_ctx_get_app_data(X509_STORE_CTX *ctx) { return X509_STORE_CTX_get_app_data(ctx); } -/*#defines for i2d and d2i types, which are typed differently -in openssl-0.9.8 than they are in openssl-0.9.7. This will -be picked up by the C preprocessor, not the SWIG preprocessor. -Used in the wrapping of ASN1_seq_unpack and ASN1_seq_pack functions. -*/ -#if OPENSSL_VERSION_NUMBER >= 0x0090800fL -#define D2ITYPE d2i_of_void * -#define I2DTYPE i2d_of_void * -#else -#define D2ITYPE char *(*)() -#define I2DTYPE int (*)() -#endif +/* X509_STORE_CTX_get_app_data is a macro. */ +void *x509_store_ctx_get_ex_data(X509_STORE_CTX *ctx, int idx) { + return X509_STORE_CTX_get_ex_data(ctx, idx); +} + +void x509_store_set_verify_cb(X509_STORE *store, PyObject *pyfunc) { + Py_XDECREF(x509_store_verify_cb_func); + Py_INCREF(pyfunc); + x509_store_verify_cb_func = pyfunc; + X509_STORE_set_verify_cb(store, x509_store_verify_callback); +} +%} +%typemap(out) STACK_OF(X509) * { + PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ + + if ($1 != NULL) + $result = SWIG_NewPointerObj($1, $1_descriptor, 0); + else { + $result = NULL; + } +} + +%inline %{ STACK_OF(X509) * make_stack_from_der_sequence(PyObject * pyEncodedString){ STACK_OF(X509) *certs; Py_ssize_t encoded_string_len; char *encoded_string; + const unsigned char *tmp_str; + + encoded_string_len = PyBytes_Size(pyEncodedString); - encoded_string_len = PyString_Size(pyEncodedString); if (encoded_string_len > INT_MAX) { - PyErr_SetString(PyExc_ValueError, "object too large"); + PyErr_Format(_x509_err, "object too large"); return NULL; } - encoded_string = PyString_AsString(pyEncodedString); + + encoded_string = PyBytes_AsString(pyEncodedString); + if (!encoded_string) { + PyErr_SetString(_x509_err, + "Cannot convert Python Bytes to (char *)."); return NULL; } - certs = ASN1_seq_unpack_X509((unsigned char *)encoded_string, encoded_string_len, d2i_X509, X509_free ); - if (!certs) { - PyErr_SetString(_x509_err, ERR_reason_error_string(ERR_get_error())); - return NULL; + tmp_str = (unsigned char *)encoded_string; + certs = d2i_SEQ_CERT(NULL, &tmp_str, encoded_string_len); + if (certs == NULL) { + PyErr_SetString(_x509_err, "Generating STACK_OF(X509) failed."); + return NULL; } - return certs; } +/* sk_X509_new_null() is a macro returning "STACK_OF(X509) *". */ +STACK_OF(X509) *sk_x509_new_null(void) { + return sk_X509_new_null(); +} +%} + +%typemap(out) STACK_OF(X509) *; + +%inline %{ PyObject * get_der_encoding_stack(STACK_OF(X509) *stack){ PyObject * encodedString; - - unsigned char * encoding; - int len; - - encoding = ASN1_seq_pack_X509(stack, i2d_X509, NULL, &len); + + unsigned char * encoding = NULL; + int len; + + len = i2d_SEQ_CERT(stack, &encoding); if (!encoding) { - PyErr_SetString(_x509_err, ERR_reason_error_string(ERR_get_error())); + m2_PyErr_Msg(_x509_err); return NULL; } - encodedString = PyString_FromStringAndSize((const char *)encoding, len); - OPENSSL_free(encoding); - return encodedString; + + encodedString = PyBytes_FromStringAndSize((const char *)encoding, len); + + if (encoding) + OPENSSL_free(encoding); + + return encodedString; } %} @@ -664,7 +775,7 @@ get_der_encoding_stack(STACK_OF(X509) *stack){ /* Free malloc'ed return value for x509_name_oneline */ %typemap(ret) char * { if ($1 != NULL) - OPENSSL_free($1); + OPENSSL_free($1); } %inline %{ char *x509_name_oneline(X509_NAME *x) { diff --git a/SWIG/libcrypto-compat.h b/SWIG/libcrypto-compat.h new file mode 100644 index 0000000..7c4c913 --- /dev/null +++ b/SWIG/libcrypto-compat.h @@ -0,0 +1,62 @@ +#ifndef LIBCRYPTO_COMPAT_H +#define LIBCRYPTO_COMPAT_H + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +#include +#include +#include +#include +#include +#include + +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d); +int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q); +int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp); +void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d); +void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q); +void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp); + +void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); +int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g); +void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key); +int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key); + +void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); +int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s); + +void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); +int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s); + +void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); +int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); +void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key); +int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key); +int DH_set_length(DH *dh, long length); + +const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx); +unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx); +EVP_MD_CTX *EVP_MD_CTX_new(void); +void EVP_MD_CTX_free(EVP_MD_CTX *ctx); +#define EVP_CIPHER_impl_ctx_size(e) e->ctx_size +#define EVP_CIPHER_CTX_get_cipher_data(ctx) ctx->cipher_data + +int RSA_size(const RSA* rsa); +RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth); +int RSA_meth_set1_name(RSA_METHOD *meth, const char *name); +#define RSA_meth_get_finish(meth) meth->finish +int RSA_meth_set_priv_enc(RSA_METHOD *meth, int (*priv_enc) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)); +int RSA_meth_set_priv_dec(RSA_METHOD *meth, int (*priv_dec) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)); +int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)); +void RSA_meth_free(RSA_METHOD *meth); + +int RSA_bits(const RSA *r); + +RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey); + +int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, + size_t *pderlen); + +#endif /* OPENSSL_VERSION_NUMBER */ + +#endif /* LIBCRYPTO_COMPAT_H */ diff --git a/SWIG/py3k_compat.h b/SWIG/py3k_compat.h new file mode 100644 index 0000000..2e914a5 --- /dev/null +++ b/SWIG/py3k_compat.h @@ -0,0 +1,32 @@ +#ifndef PY3K_COMPAT_H +#define PY3K_COMPAT_H + +#if PY_MAJOR_VERSION >= 3 + +FILE* PyFile_AsFile(PyObject *p); +PyObject* PyFile_Name(PyObject *p); + +#else /* PY2K */ + +/* Concerning PyBytes* functions: + * + * Python 3’s str() type is equivalent to Python 2’s unicode(); the + * C functions are called PyUnicode_* for both. The old 8-bit string + * type has become bytes(), with C functions called PyBytes_*. Python + * 2.6 and later provide a compatibility header, bytesobject.h, mapping + * PyBytes names to PyString ones. For best compatibility with Python 3, + * PyUnicode should be used for textual data and PyBytes for binary + * data. It’s also important to remember that PyBytes and PyUnicode in + * Python 3 are not interchangeable like PyString and PyUnicode are in + * Python 2. The following example shows best practices with regards to + * PyUnicode, PyString, and PyBytes. + * + * From https://docs.python.org/2.7/howto/cporting.html + */ + +PyObject* PyLong_FromLong(long x); +const char* PyUnicode_AsUTF8(PyObject *unicode); + +#endif /* PY_MAJOR_VERSION */ + +#endif /* PY3K_COMPAT_H */ diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..8d39bc4 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,151 @@ +environment: + global: + # PyPI login environment: + USER: + secure: oqWqarxnd4H23FMywnlQeg== + PASS: + secure: j/VSxdYJ7mdR44u8OdywLg== + X86_OPENSSL_INSTALLER: Win32OpenSSL-1_1_0k.exe + X64_OPENSSL_INSTALLER: Win64OpenSSL-1_1_0k.exe + + matrix: + + # Pre-installed Python versions, which Appveyor may upgrade to + # a later point release. + - PYTHON: "C:\\Python36" + PYTHON_VERSION: "3.6.x" # currently 3.6.4 + PYTHON_ARCH: "32" + OPENSSL_PATH: "C:\\OpenSSL-1-1-Win32" + PYWIN32: "pywin32-222.win32-py3.6.exe" + PYWIN32_RELEASE: b222 + + - PYTHON: "C:\\Python36-x64" + PYTHON_VERSION: "3.6.x" # currently 3.6.4 + PYTHON_ARCH: "64" + OPENSSL_PATH: "C:\\OpenSSL-1-1-Win64" + PYWIN32: "pywin32-222.win-amd64-py3.6.exe" + PYWIN32_RELEASE: b222 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + + - PYTHON: "C:\\Python35" + PYTHON_VERSION: "3.5.x" # currently 3.6.4 + PYTHON_ARCH: "32" + OPENSSL_PATH: "C:\\OpenSSL-1-1-Win32" + PYWIN32: "pywin32-222.win32-py3.5.exe" + PYWIN32_RELEASE: b222 + + - PYTHON: "C:\\Python35-x64" + PYTHON_VERSION: "3.5.x" # currently 3.6.4 + PYTHON_ARCH: "64" + OPENSSL_PATH: "C:\\OpenSSL-1-1-Win64" + PYWIN32: "pywin32-222.win-amd64-py3.5.exe" + PYWIN32_RELEASE: b222 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + + - PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7.x" # currently 2.7.9 + PYTHON_ARCH: "32" + OPENSSL_PATH: "C:\\OpenSSL-Win32" + PYWIN32: "pywin32-222.win32-py2.7.exe" + PYWIN32_RELEASE: b222 + + - PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7.x" # currently 2.7.9 + PYTHON_ARCH: "32" + OPENSSL_PATH: "C:\\OpenSSL-1-1-Win32" + PYWIN32: "pywin32-222.win32-py2.7.exe" + PYWIN32_RELEASE: b222 + + - PYTHON: "C:\\Python27-x64" + PYTHON_VERSION: "2.7.x" # currently 2.7.9 + PYTHON_ARCH: "64" + OPENSSL_PATH: "C:\\OpenSSL-1-1-Win64" + PYWIN32: "pywin32-222.win-amd64-py2.7.exe" + PYWIN32_RELEASE: b222 + + - PYTHON: "C:\\Python27-x64" + PYTHON_VERSION: "2.7.x" # currently 2.7.9 + PYTHON_ARCH: "64" + OPENSSL_PATH: "C:\\OpenSSL-1-1-Win64" + PYWIN32: "pywin32-222.win-amd64-py2.7.exe" + PYWIN32_RELEASE: b222 + +nuget: + account_feed: true + +install: + # Install non-python dependencies using chocolatey package manager + - choco install -r -y swig + + + # Install Python (from the official .msi of http://python.org) and pip when + # not already installed. + - ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 } + + # Prepend newly installed Python to the PATH of this build (this cannot be + # done from inside the powershell script as it would require to restart + # the parent CMD process). + - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%;%OPENSSL_PATH%\\bin" + + # Check that we have the expected version and architecture for Python + - "python --version" + - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" + + # Install the build dependencies of the project. If some dependencies contain + # compiled extensions and are not provided as pre-built wheel packages, + # pip will build them from source using the MSVC compiler matching the + # target Python version and architecture + - "%PYTHON%\\Scripts\\pip.exe install -r dev-requirements.txt" + + - ECHO "Install OpenSSL 1.1.0 32bit" + - curl -o "c:\\%X86_OPENSSL_INSTALLER%" -fsSL "https://slproweb.com/download/%X86_OPENSSL_INSTALLER%" + - "c:\\%X86_OPENSSL_INSTALLER% /silent /verysilent /DIR=C:\\OpenSSL-1-1-Win32" + + - ECHO "Install OpenSSL 1.1.0 64bit" + - curl -o "c:\\%X64_OPENSSL_INSTALLER%" -fsSL "https://slproweb.com/download/%X64_OPENSSL_INSTALLER%" + - "c:\\%X64_OPENSSL_INSTALLER% /silent /verysilent /DIR=C:\\OpenSSL-1-1-Win64" + + - ECHO "Install pywin32" + - curl -o "%PYWIN32%" -fsSL "https://github.com/mhammond/pywin32/releases/download/%PYWIN32_RELEASE%/%PYWIN32%" + - "%PYTHON%\\Scripts\\easy_install.exe %PYWIN32%" + #- mkdir pywin32 + #- 7z x "%PYWIN32%" -opywin32 + #- xcopy /e "pywin32\\PLATLIB" "%PYTHON%\\Lib\\site-packages" + + - ECHO "Filesystem root:" + - ps: "ls \"C:/\"" + + - ps: "ls \"C:/OpenSSL-Win32\"" + - ECHO "Installed SDKs:" + - ps: if (Test-Path "C:/Program Files/Microsoft SDKs/Windows") { ls "C:/Program Files/Microsoft SDKs/Windows" } + + - ECHO "Appveyor OpenSSL Version (%OPENSSL_VERSION%)" + - "%OPENSSL_PATH%/bin/openssl.exe version" + + - ECHO "Python OpenSSL Version (%PYTHON%)" + - "%PYTHON%\\python.exe -c \"import ssl; print(getattr(ssl, 'OPENSSL_VERSION', None))\"" + +build_script: + - "%PYTHON%\\python.exe setup.py build --openssl=\"%OPENSSL_PATH%\" --bundledlls" + +test_script: + - "%PYTHON%\\python.exe setup.py test" + +after_test: + # If tests are successful, create a whl package for the project. + - "%PYTHON%\\python.exe setup.py bdist_wheel bdist_wininst bdist_msi" + - ps: "ls dist" + +artifacts: + # Archive the generated wheel package in the ci.appveyor.com build report. + - path: dist\* + + - path: SWIG/_m2crypto_wrap.c + name: _m2crypto_wrap.zip + type: zip + +after_build: + - ps: Get-ChildItem SWIG\_m2crypto_wrap.c | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } + +on_failure: + - ps: Get-ChildItem SWIG\_m2crypto_wrap.c | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } diff --git a/contrib/SimpleX509create.py b/contrib/SimpleX509create.py index 7f5fc67..84fe242 100644 --- a/contrib/SimpleX509create.py +++ b/contrib/SimpleX509create.py @@ -2,6 +2,7 @@ # #vim: ts=4 sw=4 nowrap # +from __future__ import print_function """PKI demo by Peter Teniz """ @@ -13,150 +14,150 @@ MBSTRING_ASC = MBSTRING_FLAG | 1 MBSTRING_BMP = MBSTRING_FLAG | 2 -class Cert: - def __init__ ( self ): - self.RsaKey = { 'KeyLength' : 1024, - 'PubExponent' : 0x10001, # -> 65537 - 'keygen_callback' : self.callback - } +class Cert(object): + def __init__ ( self ): + self.RsaKey = { 'KeyLength' : 1024, + 'PubExponent' : 0x10001, # -> 65537 + 'keygen_callback' : self.callback + } - self.KeyPair = None - self.PKey = None + self.KeyPair = None + self.PKey = None - self.X509Request = None - self.X509Certificate = None + self.X509Request = None + self.X509Certificate = None - def callback ( self, *args ): - return 'p' + def callback ( self, *args ): + return 'p' - def CreatePKey ( self ): - self.KeyPair = M2Crypto.RSA.gen_key( self.RsaKey['KeyLength'], self.RsaKey['PubExponent'], self.RsaKey['keygen_callback'] ) - #PubKey = M2Crypto.RSA.new_pub_key( self.KeyPair.pub () ) + def CreatePKey ( self ): + self.KeyPair = M2Crypto.RSA.gen_key( self.RsaKey['KeyLength'], self.RsaKey['PubExponent'], self.RsaKey['keygen_callback'] ) + #PubKey = M2Crypto.RSA.new_pub_key( self.KeyPair.pub () ) - self.KeyPair.save_key( 'KeyPair.pem', cipher='des_ede3_cbc', callback=self.callback ) - - self.PKey = M2Crypto.EVP.PKey ( md='sha1') - self.PKey.assign_rsa ( self.KeyPair ) + self.KeyPair.save_key( 'KeyPair.pem', cipher='des_ede3_cbc', callback=self.callback ) + self.PKey = M2Crypto.EVP.PKey ( md='sha1') + self.PKey.assign_rsa ( self.KeyPair ) - def CreateX509Request ( self ): - # - # X509 REQUEST - # - self.X509Request = M2Crypto.X509.Request () + def CreateX509Request ( self ): + # + # X509 REQUEST + # - # - # subject - # + self.X509Request = M2Crypto.X509.Request () - X509Name = M2Crypto.X509.X509_Name () + # + # subject + # - X509Name.add_entry_by_txt ( field='C', type=MBSTRING_ASC, entry='austria', len=-1, loc=-1, set=0 ) # country name - X509Name.add_entry_by_txt ( field='SP', type=MBSTRING_ASC, entry='kernten', len=-1, loc=-1, set=0 ) # state of province name - X509Name.add_entry_by_txt ( field='L', type=MBSTRING_ASC, entry='stgallen', len=-1, loc=-1, set=0 ) # locality name - X509Name.add_entry_by_txt ( field='O', type=MBSTRING_ASC, entry='labor', len=-1, loc=-1, set=0 ) # organization name - X509Name.add_entry_by_txt ( field='OU', type=MBSTRING_ASC, entry='it-department', len=-1, loc=-1, set=0 ) # organizational unit name - X509Name.add_entry_by_txt ( field='CN', type=MBSTRING_ASC, entry='Certificate client', len=-1, loc=-1, set=0 ) # common name - X509Name.add_entry_by_txt ( field='Email', type=MBSTRING_ASC, entry='user@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address - X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='user@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address + X509Name = M2Crypto.X509.X509_Name () - self.X509Request.set_subject_name( X509Name ) + X509Name.add_entry_by_txt ( field='C', type=MBSTRING_ASC, entry='austria', len=-1, loc=-1, set=0 ) # country name + X509Name.add_entry_by_txt ( field='SP', type=MBSTRING_ASC, entry='kernten', len=-1, loc=-1, set=0 ) # state of province name + X509Name.add_entry_by_txt ( field='L', type=MBSTRING_ASC, entry='stgallen', len=-1, loc=-1, set=0 ) # locality name + X509Name.add_entry_by_txt ( field='O', type=MBSTRING_ASC, entry='labor', len=-1, loc=-1, set=0 ) # organization name + X509Name.add_entry_by_txt ( field='OU', type=MBSTRING_ASC, entry='it-department', len=-1, loc=-1, set=0 ) # organizational unit name + X509Name.add_entry_by_txt ( field='CN', type=MBSTRING_ASC, entry='Certificate client', len=-1, loc=-1, set=0 ) # common name + X509Name.add_entry_by_txt ( field='Email', type=MBSTRING_ASC, entry='user@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address + X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='user@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address - # - # publickey - # + self.X509Request.set_subject_name( X509Name ) - self.X509Request.set_pubkey ( pkey=self.PKey ) - self.X509Request.sign ( pkey=self.PKey, md='sha1' ) - #print X509Request.as_text () + # + # publickey + # + self.X509Request.set_pubkey ( pkey=self.PKey ) + self.X509Request.sign ( pkey=self.PKey, md='sha1' ) + #print(X509Request.as_text ()) - def CreateX509Certificate ( self ): - # - # X509 CERTIFICATE - # - self.X509Certificate = M2Crypto.X509.X509 () + def CreateX509Certificate ( self ): + # + # X509 CERTIFICATE + # - # - # version - # + self.X509Certificate = M2Crypto.X509.X509 () - self.X509Certificate.set_version ( 0 ) + # + # version + # - # - # time notBefore - # + self.X509Certificate.set_version ( 0 ) - ASN1 = M2Crypto.ASN1.ASN1_UTCTIME () - ASN1.set_time ( 500 ) - self.X509Certificate.set_not_before( ASN1 ) + # + # time notBefore + # - # - # time notAfter - # + ASN1 = M2Crypto.ASN1.ASN1_TIME () + ASN1.set_time ( 500 ) + self.X509Certificate.set_not_before( ASN1 ) - ASN1 = M2Crypto.ASN1.ASN1_UTCTIME () - ASN1.set_time ( 500 ) - self.X509Certificate.set_not_after( ASN1 ) + # + # time notAfter + # - # - # public key - # + ASN1 = M2Crypto.ASN1.ASN1_TIME () + ASN1.set_time ( 500 ) + self.X509Certificate.set_not_after( ASN1 ) - self.X509Certificate.set_pubkey ( pkey=self.PKey ) - - # - # subject - # + # + # public key + # - X509Name = self.X509Request.get_subject () + self.X509Certificate.set_pubkey ( pkey=self.PKey ) - #print X509Name.entry_count () - #print X509Name.as_text () + # + # subject + # - self.X509Certificate.set_subject_name( X509Name ) + X509Name = self.X509Request.get_subject () - # - # issuer - # + #print(X509Name.entry_count ()) + #print(X509Name.as_text ()) - X509Name = M2Crypto.X509.X509_Name ( M2Crypto.m2.x509_name_new () ) + self.X509Certificate.set_subject_name( X509Name ) - X509Name.add_entry_by_txt ( field='C', type=MBSTRING_ASC, entry='germany', len=-1, loc=-1, set=0 ) # country name - X509Name.add_entry_by_txt ( field='SP', type=MBSTRING_ASC, entry='bavaria', len=-1, loc=-1, set=0 ) # state of province name - X509Name.add_entry_by_txt ( field='L', type=MBSTRING_ASC, entry='munich', len=-1, loc=-1, set=0 ) # locality name - X509Name.add_entry_by_txt ( field='O', type=MBSTRING_ASC, entry='sbs', len=-1, loc=-1, set=0 ) # organization name - X509Name.add_entry_by_txt ( field='OU', type=MBSTRING_ASC, entry='it-department', len=-1, loc=-1, set=0 ) # organizational unit name - X509Name.add_entry_by_txt ( field='CN', type=MBSTRING_ASC, entry='Certificate Authority', len=-1, loc=-1, set=0 ) # common name - X509Name.add_entry_by_txt ( field='Email', type=MBSTRING_ASC, entry='admin@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address - X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='admin@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address + # + # issuer + # - #print X509Name.entry_count () - #print X509Name.as_text () + X509Name = M2Crypto.X509.X509_Name ( M2Crypto.m2.x509_name_new () ) - self.X509Certificate.set_issuer_name( X509Name ) + X509Name.add_entry_by_txt ( field='C', type=MBSTRING_ASC, entry='germany', len=-1, loc=-1, set=0 ) # country name + X509Name.add_entry_by_txt ( field='SP', type=MBSTRING_ASC, entry='bavaria', len=-1, loc=-1, set=0 ) # state of province name + X509Name.add_entry_by_txt ( field='L', type=MBSTRING_ASC, entry='munich', len=-1, loc=-1, set=0 ) # locality name + X509Name.add_entry_by_txt ( field='O', type=MBSTRING_ASC, entry='sbs', len=-1, loc=-1, set=0 ) # organization name + X509Name.add_entry_by_txt ( field='OU', type=MBSTRING_ASC, entry='it-department', len=-1, loc=-1, set=0 ) # organizational unit name + X509Name.add_entry_by_txt ( field='CN', type=MBSTRING_ASC, entry='Certificate Authority', len=-1, loc=-1, set=0 ) # common name + X509Name.add_entry_by_txt ( field='Email', type=MBSTRING_ASC, entry='admin@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address + X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='admin@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address - # - # signing - # + #print(X509Name.entry_count ()) + #print(X509Name.as_text ()) - self.X509Certificate.sign( pkey=self.PKey, md='sha1' ) - print self.X509Certificate.as_text () + self.X509Certificate.set_issuer_name( X509Name ) + + # + # signing + # + + self.X509Certificate.sign( pkey=self.PKey, md='sha1' ) + print(self.X509Certificate.as_text ()) if __name__ == '__main__': - run = Cert () - run.CreatePKey () - run.CreateX509Request () - run.CreateX509Certificate () + run = Cert () + run.CreatePKey () + run.CreateX509Request () + run.CreateX509Certificate () diff --git a/contrib/dave.patch b/contrib/dave.patch deleted file mode 100644 index 6e41073..0000000 --- a/contrib/dave.patch +++ /dev/null @@ -1,180 +0,0 @@ ---- _ssl.i.orig Tue Sep 18 06:06:34 2001 -+++ _ssl.i Thu Dec 12 08:57:39 2002 -@@ -238,9 +238,18 @@ - return ret; - } - -+void SetWantRWError(int which) { -+ PyObject *o = Py_BuildValue("(is)", which, -+ -ERR_reason_error_string(ERR_get_error())); -+ if (o != NULL) { -+ PyErr_SetObject(_ssl_err, o); -+ Py_DECREF(o); -+ } -+} -+ - PyObject *ssl_accept(SSL *ssl) { - PyObject *obj; -- int r, err; -+ int r, err, which; - PyThreadState *_save; - - if (thread_mode) { -@@ -252,14 +261,15 @@ - _save = (PyThreadState *)SSL_get_app_data(ssl); - PyEval_RestoreThread(_save); - } -- switch (SSL_get_error(ssl, r)) { -+ switch ((which = SSL_get_error(ssl, r))) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - obj = PyInt_FromLong((long)1); - break; - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_WANT_READ: -- obj = PyInt_FromLong((long)0); -+ SetWantRWError(which); -+ obj = NULL; - break; - case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, -ERR_reason_error_string(ERR_get_error())); -@@ -281,7 +291,7 @@ - - PyObject *ssl_connect(SSL *ssl) { - PyObject *obj; -- int r, err; -+ int r, err, which; - PyThreadState *_save; - - if (thread_mode) { -@@ -293,14 +303,15 @@ - _save = (PyThreadState *)SSL_get_app_data(ssl); - PyEval_RestoreThread(_save); - } -- switch (SSL_get_error(ssl, r)) { -+ switch ((which = SSL_get_error(ssl, r))) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - obj = PyInt_FromLong((long)1); - break; - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_WANT_READ: -- obj = PyInt_FromLong((long)0); -+ SetWantRWError(which); -+ obj = NULL; - break; - case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, -ERR_reason_error_string(ERR_get_error())); -@@ -327,7 +338,7 @@ - PyObject *ssl_read(SSL *ssl, int num) { - PyObject *obj; - void *buf; -- int r, err; -+ int r, err, which; - PyThreadState *_save; - - if (!(buf = PyMem_Malloc(num))) { -@@ -343,7 +354,7 @@ - _save = (PyThreadState *)SSL_get_app_data(ssl); - PyEval_RestoreThread(_save); - } -- switch (SSL_get_error(ssl, r)) { -+ switch ((which = SSL_get_error(ssl, r))) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - buf = PyMem_Realloc(buf, r); -@@ -352,8 +363,8 @@ - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_X509_LOOKUP: -- Py_INCREF(Py_None); -- obj = Py_None; -+ SetWantRWError(which); -+ obj = NULL; - break; - case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, -ERR_reason_error_string(ERR_get_error())); -@@ -377,14 +388,14 @@ - PyObject *ssl_read_nbio(SSL *ssl, int num) { - PyObject *obj; - void *buf; -- int r, err; -+ int r, err, which; - - if (!(buf = PyMem_Malloc(num))) { - PyErr_SetString(PyExc_MemoryError, "ssl_read"); - return NULL; - } - r = SSL_read(ssl, buf, num); -- switch (SSL_get_error(ssl, r)) { -+ switch ((which = SSL_get_error(ssl, r))) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - buf = PyMem_Realloc(buf, r); -@@ -392,6 +403,9 @@ - break; - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_WANT_READ: -+ SetWantRWError(which); -+ obj = NULL; -+ break; - case SSL_ERROR_WANT_X509_LOOKUP: - Py_INCREF(Py_None); - obj = Py_None; -@@ -417,7 +431,7 @@ - - int ssl_write(SSL *ssl, PyObject *blob) { - const void *buf; -- int len, r, err; -+ int len, r, err, which; - PyThreadState *_save; - - #if PYTHON_API_VERSION >= 1009 -@@ -440,12 +454,14 @@ - _save = (PyThreadState *)SSL_get_app_data(ssl); - PyEval_RestoreThread(_save); - } -- switch (SSL_get_error(ssl, r)) { -+ switch ((which = SSL_get_error(ssl, r))) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - return r; - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_WANT_READ: -+ SetWantRWError(which); -+ return -1; - case SSL_ERROR_WANT_X509_LOOKUP: - return -1; - case SSL_ERROR_SSL: -@@ -466,7 +482,7 @@ - - int ssl_write_nbio(SSL *ssl, PyObject *blob) { - const void *buf; -- int len, r, err; -+ int len, r, err, which; - - #if PYTHON_API_VERSION >= 1009 - if (PyObject_AsReadBuffer(blob, &buf, &len) == -1) -@@ -480,12 +496,14 @@ - buf = (const void *)PyString_AsString(blob); - #endif - r = SSL_write(ssl, buf, len); -- switch (SSL_get_error(ssl, r)) { -+ switch ((which = SSL_get_error(ssl, r))) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - return r; - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_WANT_READ: -+ SetWantRWError(which); -+ return -1; - case SSL_ERROR_WANT_X509_LOOKUP: - return -1; - case SSL_ERROR_SSL: - - - diff --git a/contrib/dispatcher.py b/contrib/dispatcher.py index 6e7302d..6f3b0e0 100644 --- a/contrib/dispatcher.py +++ b/contrib/dispatcher.py @@ -1,191 +1,177 @@ -#!/usr/local/bin/python -O -""" - Implements a [hopefully] non-blocking SSL dispatcher on top of - M2Crypto package. - - Written by Ilya Etingof , 05/2001 -""" -import asyncore, socket - -# M2Crypto -from M2Crypto import SSL - -class _nb_connection (SSL.Connection): - """Functional equivalent of SSL.Connection class. Facilitates - possibly delayed socket.connect() and socket.accept() - termination. - """ - def __init__ (self, ctx, sock): - SSL.Connection.__init__ (self, ctx, sock) - - def connect(self, addr): - self._setup_ssl(addr) - return self._check_ssl_return(SSL.m2.ssl_connect(self.ssl)) - - def accept(self, addr): - self._setup_ssl(addr) - self.accept_ssl() - -class dispatcher(asyncore.dispatcher_with_send): - """A non-blocking SSL dispatcher that mimics the - asyncode.dispatcher API. - """ - def __init__ (self, cert, key, sock=None, serving=None): - asyncore.dispatcher_with_send.__init__ (self) - - self.__serving = serving - - # XXX - if sock: - if self.__serving: - self.set_socket(sock) - else: - self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - - self.ctx = SSL.Context('sslv23') - self.ctx.set_verify(SSL.verify_none, 10) - self.ctx.load_cert(cert, key) - self.ctx.set_info_callback() - - self.ssl = _nb_connection(self.ctx, self.socket) - - self.__output = '' - self.__want_write = 1 - - # - # The following are asyncore overloaded methods - # - - def handle_connect (self): - """Initiate SSL connection negotiation - """ - if self.__serving: - self.ssl.accept (self.addr) - - self.peer = self.ssl.get_peer_cert() - - self.handle_ssl_accept() - - else: - self.ssl.connect (self.addr) - - self.handle_ssl_connect() - - def handle_read(self): - """Read user and/or SSL protocol data from SSL connection - """ - ret = self.ssl._read_nbio() - - if ret: - self.handle_ssl_read(ret) - else: - # Assume write is wanted - self.__want_write = 1 - - def handle_write(self): - """Write pending user and/or SSL protocol data down to SSL - connection - """ - self.__want_write = 0 - - ret = self.ssl._write_nbio(self.__output) - - if ret < 0: - try: - err = SSL.m2.ssl_get_error(self.ssl.ssl, ret) - - except SSL.SSLError: - return - - if err == SSL.m2.ssl_error_want_write: - self.__want_write = 1 - else: - self.__output = self.__output[ret:] - - def writable (self): - """Indicate that write is desired if here're some - user and/or SSL protocol data. - """ - if self.__output or self.__want_write: - return 1 - - return self.ssl_writable() - - def handle_close (self): - """Shutdown SSL connection. - """ - self.ssl = None - - self.ctx = None - self.close () - - self.handle_ssl_close() - - def handle_error (self, *info): - """A trap for asyncore errors - """ - self.handle_ssl_error(info) - - # - # The following are ssl.dispatcher API - # - - def ssl_connect(self, server): - """Initiate SSL connection - """ - self.connect(server) - - def ssl_write(self, data): - """Write data to SSL connection - """ - self.__output = self.__output + data - - def ssl_close(self): - """Close SSL connection - """ - self.handle_close() - - def handle_ssl_connect(self): - """Invoked on SSL connection establishment (whilst - in client mode) - """ - print 'Unhandled handle_ssl_connect()' - - def handle_ssl_accept(self): - """Invoked on SSL connection establishment (whilst - in server mode) - """ - print 'Unhandled handle_ssl_accept()' - - def handle_ssl_read(self, data): - """Invoked on new data arrival to SSL connection - """ - print 'Unhandled handle_ssl_read event' - - def handle_ssl_close(self): - """Invoked on SSL connection termination - """ - pass - - def ssl_writable(self): - """Invoked prior to every select() call - """ - return 0 - -if __name__=='__main__': - """Give it a test run - """ - class client(dispatcher): - """SSL client class - """ - def __init__ (self, cert, key): - dispatcher.__init__(self, cert, key) - - def handle_ssl_read(self, data): - print data - self.ssl_write('test write') - - ssl = client('test.cert', 'test.key') - ssl.ssl_connect(('localhost', 7777)) - - asyncore.loop() +#!/usr/local/bin/python -O +from __future__ import print_function +"""Implements a [hopefully] non-blocking SSL Dispatcher on top of M2Crypto. + + Written by Ilya Etingof , 05/2001 +""" +import asyncore # type: ignore # https://github.com/python/typeshed/issues/356 +import socket + +# M2Crypto +from M2Crypto import SSL # type: ignore # we are not in proper directory + + +class NBConnection(SSL.Connection): + """Functional equivalent of SSL.Connection class. + + Facilitates possibly delayed socket.connect() and socket.accept() + termination. + """ + def __init__(self, ctx, sock): + SSL.Connection.__init__(self, ctx, sock) + + def connect(self, addr): + self._setup_ssl(addr) + # FIXME SSL.Connection doesn't have _check_ssl_return method + return self._check_ssl_return(SSL.m2.ssl_connect(self.ssl)) + + def accept(self, addr): + self._setup_ssl(addr) + self.accept_ssl() + + +class Dispatcher(asyncore.dispatcher_with_send): + """A non-blocking SSL Dispatcher that mimics the asyncode.dispatcher API""" + def __init__(self, cert, key, sock=None, serving=None): + asyncore.dispatcher_with_send.__init__(self) + + self.__serving = serving + + # XXX + if sock: + if self.__serving: + self.set_socket(sock) + else: + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + + self.ctx = SSL.Context() + self.ctx.set_verify(SSL.verify_none, 10) + self.ctx.load_cert(cert, key) + self.ctx.set_info_callback() + + self.ssl = NBConnection(self.ctx, self.socket) + self.peer = None + + self.__output = '' + self.__want_write = 1 + + # + # The following are asyncore overloaded methods + # + + def handle_connect(self): + """Initiate SSL connection negotiation""" + if self.__serving: + self.ssl.accept(self.addr) + + self.peer = self.ssl.get_peer_cert() + + self.handle_ssl_accept() + + else: + self.ssl.connect(self.addr) + + self.handle_ssl_connect() + + def handle_read(self): + """Read user and/or SSL protocol data from SSL connection""" + ret = self.ssl._read_nbio() + + if ret: + self.handle_ssl_read(ret) + else: + # Assume write is wanted + self.__want_write = 1 + + def handle_write(self): + """Write pending user or SSL protocol data down to SSL connection""" + self.__want_write = 0 + + ret = self.ssl._write_nbio(self.__output) + + if ret < 0: + try: + err = SSL.m2.ssl_get_error(self.ssl.ssl, ret) + + except SSL.SSLError: + return + + if err == SSL.m2.ssl_error_want_write: + self.__want_write = 1 + else: + self.__output = self.__output[ret:] + + def writable(self): + """Indicate that write is desired. + + Happens if there's some user and/or SSL protocol data. + """ + if self.__output or self.__want_write: + return 1 + + return self.ssl_writable() + + def handle_close(self): + """Shutdown SSL connection.""" + self.ssl = None + + self.ctx = None + self.close() + + self.handle_ssl_close() + + def handle_error(self, *info): + """A trap for asyncore errors""" + self.handle_ssl_error(info) + + # + # The following are ssl.dispatcher API + # + + def ssl_connect(self, server): + """Initiate SSL connection""" + self.connect(server) + + def ssl_write(self, data): + """Write data to SSL connection""" + self.__output = self.__output + data + + def ssl_close(self): + """Close SSL connection""" + self.handle_close() + + def handle_ssl_connect(self): + """Invoked on SSL connection establishment (whilst in Client mode)""" + print('Unhandled handle_ssl_connect()') + + def handle_ssl_accept(self): + """Invoked on SSL connection establishment (whilst in server mode)""" + print('Unhandled handle_ssl_accept()') + + def handle_ssl_read(self, data): + """Invoked on new data arrival to SSL connection""" + print('Unhandled handle_ssl_read event') + + def handle_ssl_close(self): + """Invoked on SSL connection termination""" + pass + + def ssl_writable(self): + """Invoked prior to every select() call""" + return 0 + +if __name__ == '__main__': + """Give it a test run""" + class Client(Dispatcher): + """SSL Client class""" + def __init__(self, cert, key): + Dispatcher.__init__(self, cert, key) + + def handle_ssl_read(self, data): + print(data) + self.ssl_write('test write') + + ssl = Client('test.cert', 'test.key') + ssl.ssl_connect(('localhost', 7777)) + + asyncore.loop() diff --git a/contrib/isaac.httpslib.py b/contrib/isaac.httpslib.py index ae9d23d..c5474b8 100644 --- a/contrib/isaac.httpslib.py +++ b/contrib/isaac.httpslib.py @@ -1,116 +1,85 @@ -"""M2Crypto support for Python 1.5.2 and Python 2.x's httplib. +from __future__ import print_function + +"""M2Crypto support for Python 2.x's httplib. Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" -import string, sys -from httplib import * -import SSL +import string -if sys.version[0] == '2': - - if sys.version[:3] in ['2.1', '2.2']: - # In 2.1 and above, httplib exports "HTTP" only. - from httplib import HTTPConnection, HTTPS_PORT - # ISS Added: - from httplib import HTTPResponse,FakeSocket +from M2Crypto import SSL - class HTTPSConnection(HTTPConnection): - - """ - This class allows communication via SSL using M2Crypto. - """ - - default_port = HTTPS_PORT - - def __init__(self, host, port=None, **ssl): - keys = ssl.keys() - try: - keys.remove('key_file') - except ValueError: - pass - try: - keys.remove('cert_file') - except ValueError: - pass - try: - keys.remove('ssl_context') - except ValueError: - pass - if keys: - raise IllegalKeywordArgument() - try: - self.ssl_ctx = ssl['ssl_context'] - assert isinstance(self.ssl_ctx, SSL.Context) - except KeyError: - self.ssl_ctx = SSL.Context('sslv23') - HTTPConnection.__init__(self, host, port) - - def connect(self): - self.sock = SSL.Connection(self.ssl_ctx) - self.sock.connect((self.host, self.port)) - - def close(self): - # This kludges around line 545 of httplib.py, - # which closes the connection in this object; - # the connection remains open in the response - # object. - # - # M2Crypto doesn't close-here-keep-open-there, - # so, in effect, we don't close until the whole - # business is over and gc kicks in. - # - # Long-running callers beware leakage. - # - # 05-Jan-2002: This module works with Python 2.2, - # but I've not investigated if the above conditions - # remain. - pass +from httplib import FakeSocket, HTTP, HTTPConnection, HTTPResponse, HTTPS_PORT - class HTTPS(HTTP): - - _connection_class = HTTPSConnection - - def __init__(self, host='', port=None, **ssl): - HTTP.__init__(self, host, port) - try: - self.ssl_ctx = ssl['ssl_context'] - except KeyError: - self.ssl_ctx = SSL.Context('sslv23') - - -elif sys.version[:3] == '1.5': - - class HTTPS(HTTP): - - def __init__(self, ssl_context, host='', port=None): - assert isinstance(ssl_context, SSL.Context) - self.debuglevel=0 - self.file=None - self.ssl_ctx=ssl_context - if host: - self.connect(host, port) - - def connect(self, host, port=None): - # Cribbed from httplib.HTTP. - if not port: - i = string.find(host, ':') - if i >= 0: - host, port = host[:i], host[i+1:] - try: port = string.atoi(port) - except string.atoi_error: - raise socket.error, "nonnumeric port" - if not port: port = HTTPS_PORT - self.sock = SSL.Connection(self.ssl_ctx) - if self.debuglevel > 0: print 'connect:', (host, port) - self.sock.connect((host, port)) +class HTTPSConnection(HTTPConnection): + + """ + This class allows communication via SSL using M2Crypto. + """ + + default_port = HTTPS_PORT + + def __init__(self, host, port=None, **ssl): + keys = ssl.keys() + try: + keys.remove('key_file') + except ValueError: + pass + try: + keys.remove('cert_file') + except ValueError: + pass + try: + keys.remove('ssl_context') + except ValueError: + pass + if keys: + raise ValueError() + try: + self.ssl_ctx = ssl['ssl_context'] + assert isinstance(self.ssl_ctx, SSL.Context) + except KeyError: + self.ssl_ctx = SSL.Context('sslv23') + HTTPConnection.__init__(self, host, port) + + def connect(self): + self.sock = SSL.Connection(self.ssl_ctx) + self.sock.connect((self.host, self.port)) + + def close(self): + # This kludges around line 545 of httplib.py, + # which closes the connection in this object; + # the connection remains open in the response + # object. + # + # M2Crypto doesn't close-here-keep-open-there, + # so, in effect, we don't close until the whole + # business is over and gc kicks in. + # + # Long-running callers beware leakage. + # + # 05-Jan-2002: This module works with Python 2.2, + # but I've not investigated if the above conditions + # remain. + pass + +class HTTPS(HTTP): + + _connection_class = HTTPSConnection + + def __init__(self, host='', port=None, **ssl): + HTTP.__init__(self, host, port) + try: + self.ssl_ctx = ssl['ssl_context'] + except KeyError: + self.ssl_ctx = SSL.Context('sslv23') # ISS Added. # From here, starts the proxy patch class HTTPProxyConnection(HTTPConnection): """ This class provides HTTP access through (authenticated) proxies. - + Example: If the HTTP proxy address is proxy.your.org:8080, an authenticated proxy (one which requires a username/password combination in order to serve @@ -161,7 +130,7 @@ class HTTPProxyConnection(HTTPConnection): HTTPConnection.putrequest(self, method, newurl) # Add proxy-specific headers self._add_auth_proxy_header() - + def _add_auth_proxy_header(self): """Adds an HTTP header for authenticated proxies """ @@ -177,7 +146,7 @@ class HTTPProxyConnection(HTTPConnection): class HTTPSProxyResponse(HTTPResponse): """ Replacement class for HTTPResponse - Proxy responses (made through SSL) have to keep the connection open + Proxy responses (made through SSL) have to keep the connection open after the initial request, since the connection is tunneled to the SSL host with the CONNECT method. """ @@ -187,7 +156,7 @@ class HTTPSProxyResponse(HTTPResponse): class HTTPSProxyConnection(HTTPProxyConnection): """This class provides HTTP access through (authenticated) proxies. - + Example: If the HTTP proxy address is proxy.your.org:8080, an authenticated proxy (one which requires a username/password combination in order to serve @@ -207,8 +176,8 @@ class HTTPSProxyConnection(HTTPProxyConnection): def __init__(self, proxy, host, port=None, username=None, password=None, **x509): for key in x509.keys(): - if key not in ['cert_file', 'key_file','ssl_context']: - raise IllegalKeywordArgument() + if key not in ['cert_file', 'key_file', 'ssl_context']: + raise ValueError() self.key_file = x509.get('key_file') self.cert_file = x509.get('cert_file') #ISS Added @@ -217,12 +186,12 @@ class HTTPSProxyConnection(HTTPProxyConnection): HTTPProxyConnection.__init__(self, proxy, host, port, username, password) def connect(self): - """Connect (using SSL) to the host and port specified in __init__ + """Connect (using SSL) to the host and port specified in __init__ (through a proxy).""" import socket # Set the connection with the proxy HTTPProxyConnection.connect(self) - # Use the stock HTTPConnection putrequest + # Use the stock HTTPConnection putrequest host = "%s:%s" % (self._host, self._port) HTTPConnection.putrequest(self, "CONNECT", host) # Add proxy-specific stuff @@ -257,7 +226,7 @@ class HTTPSProxyConnection(HTTPProxyConnection): # Fake the socket ssl = socket.ssl(self.sock, self.key_file, self.cert_file) self.sock = FakeSocket(self.sock, ssl) - if self.debuglevel > 0: print 'socket type:', self.sock + if self.debuglevel > 0: print('socket type:', self.sock) def putrequest(self, method, url): """Send a request to the server. diff --git a/contrib/m2crypto.spec b/contrib/m2crypto.spec deleted file mode 100644 index f80cddb..0000000 --- a/contrib/m2crypto.spec +++ /dev/null @@ -1,46 +0,0 @@ -%define name m2crypto -%define version 0.06 -%define snap snap5 -%define release %{snap}.1 -%define prefix %{_prefix} - -Summary: Python crypto library -Name: %{name} -Version: %{version} -Release: %{release} -Copyright: tummy.com, ltd. -Group: Applications/Crypto -Source: %{name}-%{version}-%{snap}.zip -Packager: Sean Reifschneider -BuildRoot: /var/tmp/%{name}-root -Requires: openssl >= 0.9.6a -Patch0: m2crypto-makefile.patch -BuildPrereq: openssl-devel >= 0.9.6a -BuildPrereq: swig >= 1.1p5 - -%description -M2Crypto makes available to the Python programmer the following: - - RSA, DH, DSA, HMACs, message digests, symmetric ciphers. - SSL functionality to implement clients and servers. - HTTPS extensions to Python's httplib, urllib, and the eff-bot's xmlrpclib. - S/MIME v2. - -%prep -%setup -n %{name}-%{version}-%{snap} -%patch0 -p1 -%build -( cd swig; make -f Makefile.py1 ) - -%install -[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" -mkdir -p "$RPM_BUILD_ROOT"/usr/lib/python1.5/site-packages -cp -a M2Crypto "$RPM_BUILD_ROOT"/usr/lib/python1.5/site-packages - -%clean -[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" - -%files -%defattr(755,root,root) -%doc BUGS CHANGES INSTALL LICENCE README STORIES doc demo tests patches -/usr/lib/python1.5/site-packages diff --git a/contrib/smimeplus.py b/contrib/smimeplus.py index 5a9c22d..9475ab0 100644 --- a/contrib/smimeplus.py +++ b/contrib/smimeplus.py @@ -1,13 +1,10 @@ -import sys, os, tempfile import UserDict -from email import Message +import os +import tempfile + import M2Crypto -if not (sys.version_info[0] >= 2 and sys.version_info[1] >= 2): - class object: - pass - True=1 - False=0 +from email import Message class smimeplus(object): @@ -17,7 +14,7 @@ class smimeplus(object): self.setcacert(cacert) self.randfile = randfile self.__loadrand() - + def __passcallback(self, v): """private key passphrase callback function""" return self.passphrase @@ -43,7 +40,7 @@ class smimeplus(object): return _data def __pack(self, msg): - """Convert 'msg' to string and put it into an memory buffer for + """Convert 'msg' to string and put it into an memory buffer for openssl operation""" return M2Crypto.BIO.MemoryBuffer(self.__gettext(msg)) @@ -64,7 +61,7 @@ class smimeplus(object): _sender.load_key_bio(self.__pack(self.key), self.__pack(self.cert), callback=self.__passcallback) - _signed = _sender.sign(self.__pack(msg)) + _signed = _sender.sign(self.__pack(msg), M2Crypto.SMIME.PKCS7_DETACHED) _out = self.__pack(None) _sender.write(_out, _signed, self.__pack(msg)) @@ -72,7 +69,7 @@ class smimeplus(object): def verify(self, smsg, scert): """Verify to see if 'smsg' was signed by 'scert', and scert was - issued by cacert of this object. Return message signed if success, + issued by cacert of this object. Return message signed if success, None otherwise""" # Load signer's cert. _x509 = M2Crypto.X509.load_cert_bio(self.__pack(scert)) @@ -89,34 +86,34 @@ class smimeplus(object): _sender = M2Crypto.SMIME.SMIME() _sender.set_x509_stack(_stack) _sender.set_x509_store(_store) - + # Load signed message, verify it, and return result _p7, _data = M2Crypto.SMIME.smime_load_pkcs7_bio(self.__pack(smsg)) try: - return _sender.verify(_p7, flags=M2Crypto.SMIME.PKCS7_SIGNED) - except M2Crypto.SMIME.SMIME_Error, _msg: + return _sender.verify(_p7, _data, flags=M2Crypto.SMIME.PKCS7_SIGNED) + except M2Crypto.SMIME.SMIME_Error: return None def encrypt(self, rcert, msg): # Instantiate an SMIME object. _sender = M2Crypto.SMIME.SMIME() - + # Load target cert to encrypt to. _x509 = M2Crypto.X509.load_cert_bio(self.__pack(rcert)) _stack = M2Crypto.X509.X509_Stack() _stack.push(_x509) _sender.set_x509_stack(_stack) - + _sender.set_cipher(M2Crypto.SMIME.Cipher(self.cipher)) - + # Encrypt the buffer. _buf = self.__pack(self.__gettext(msg)) _p7 = _sender.encrypt(_buf) - + # Output p7 in mail-friendly format. _out = self.__pack('') _sender.write(_out, _p7) - + # Save the PRNG's state. self.__saverand() @@ -129,14 +126,14 @@ class smimeplus(object): _sender = M2Crypto.SMIME.SMIME() _sender.load_key_bio(self.__pack(self.key), self.__pack(self.cert), callback=self.__passcallback) - + # Load the encrypted data. _p7, _data = M2Crypto.SMIME.smime_load_pkcs7_bio(self.__pack(emsg)) - + # Decrypt p7. try: return _sender.decrypt(_p7) - except M2Crypto.SMIME.SMIME_Error, _msg: + except M2Crypto.SMIME.SMIME_Error: return None def addHeader(self, rcert, content, subject=''): @@ -160,14 +157,14 @@ class X509_Subject(UserDict.UserDict): UserDict.UserDict.__init__(self) try: _data = substr.strip().split('/') - except AttributeError, _msg: + except AttributeError: pass else: for _i in _data: try: _k, _v = _i.split('=') self[_k] = _v - except ValueError, _msg: + except ValueError: pass diff --git a/demo/CipherSaber/CipherSaber.py b/demo/CipherSaber/CipherSaber.py deleted file mode 100644 index 81bd4c6..0000000 --- a/demo/CipherSaber/CipherSaber.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python - -"""CipherSaber, http://ciphersaber.gurus.com. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -# XXX getopt handling has bugs. - -from M2Crypto import RC4, Rand -import getopt, getpass, sys - -class argerr(Exception): pass - -cmd = -1 -inf = sys.stdin -outf = sys.stdout - -optlist, optarg = getopt.getopt(sys.argv[1:], 'dei:o:') -for opt in optlist: - if '-d' in opt: - cmd = cmd + 1 - elif '-e' in opt: - cmd = cmd + 2 - elif '-i' in opt: - i = opt[1] - if i == '-': - inf = sys.stdin - else: - inf = open(i, 'rb') - elif '-o' in opt: - o = opt[1] - if o == '-': - outf = sys.stdout - else: - outf = open(o, 'wb') -if cmd < 0: - raise argerr, "either -d or -e" -if cmd > 1: - raise argerr, "either -d or -e, not both" - -if cmd == 0: - iv = inf.read(10) - pp = getpass.getpass('Enter decryption passphrase: ') -else: - iv = Rand.rand_bytes(10) - outf.write(iv) - pp = getpass.getpass('Enter encryption passphrase: ') - pp2 = getpass.getpass('Enter passphrase again: ') - if pp != pp2: - raise SystemExit, 'passphrase mismatch, I\'m outta here...' - -ci = RC4.RC4(pp + iv) -del pp, iv - -while 1: - buf = inf.read() - if not buf: - break - outf.write(ci.update(buf)) -outf.write(ci.final()) - - diff --git a/demo/CipherSaber/cstest1.cs1 b/demo/CipherSaber/cstest1.cs1 deleted file mode 100644 index a9794b6..0000000 --- a/demo/CipherSaber/cstest1.cs1 +++ /dev/null @@ -1 +0,0 @@ -om «óªg0í¶wÊtàÐ縅CV»Hã|Ûïçó¨OO_³ý \ No newline at end of file diff --git a/demo/Zope/ZServer/HTTPS_Server.py b/demo/Zope/ZServer/HTTPS_Server.py deleted file mode 100644 index 06a2668..0000000 --- a/demo/Zope/ZServer/HTTPS_Server.py +++ /dev/null @@ -1,187 +0,0 @@ -############################################################################## -# -# Copyright (c) 2000-2004, Ng Pheng Siong. All Rights Reserved. -# This file is derived from Zope's ZServer/HTTPServer.py. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE -# -############################################################################## - -""" -Medusa HTTPS server for Zope - -changes from Medusa's http_server: - - Request Threads -- Requests are processed by threads from a thread - pool. - - Output Handling -- Output is pushed directly into the producer - fifo by the request-handling thread. The HTTP server does not do - any post-processing such as chunking. - - Pipelineable -- This is needed for protocols such as HTTP/1.1 in - which mutiple requests come in on the same channel, before - responses are sent back. When requests are pipelined, the client - doesn't wait for the response before sending another request. The - server must ensure that responses are sent back in the same order - as requests are received. - - -changes from Zope's HTTP server: - - Well, this is a *HTTPS* server :) - - X.509 certificate-based authentication -- When this is in force, - zhttps_handler, a subclass of zhttp_handler, is installed. The - https server is configured to request an X.509 certificate from - the client. When the request reaches zhttps_handler, it sets - REMOTE_USER to the client's subject distinguished name (DN) from - the certificate. Zope's REMOTE_USER machinery takes care of the - rest, e.g., in conjunction with the RemoteUserFolder product. - -""" - -import sys, time, types - -from PubCore import handle -from medusa import asyncore -from ZServer import CONNECTION_LIMIT, ZOPE_VERSION -from HTTPServer import zhttp_handler -from zLOG import register_subsystem - -from M2Crypto import SSL, version -from medusa.https_server import https_server, https_channel -from medusa.asyncore import dispatcher - - -ZSERVER_SSL_VERSION=version - -register_subsystem('ZServer HTTPS_Server') - - -class zhttps0_handler(zhttp_handler): - "zhttps0 handler - sets SSL request headers a la mod_ssl" - - def __init__ (self, module, uri_base=None, env=None): - zhttp_handler.__init__(self, module, uri_base, env) - - def get_environment(self, request): - env = zhttp_handler.get_environment(self, request) - env['SSL_CIPHER'] = request.channel.get_cipher() - return env - - -class zhttps_handler(zhttps0_handler): - "zhttps handler - sets REMOTE_USER to user's X.509 certificate Subject DN" - - def __init__ (self, module, uri_base=None, env=None): - zhttps0_handler.__init__(self, module, uri_base, env) - - def get_environment(self, request): - env = zhttps0_handler.get_environment(self, request) - peer = request.channel.get_peer_cert() - if peer is not None: - env['REMOTE_USER'] = str(peer.get_subject()) - return env - - -class zhttps_channel(https_channel): - "https channel" - - closed=0 - zombie_timeout=100*60 # 100 minutes - - def __init__(self, server, conn, addr): - https_channel.__init__(self, server, conn, addr) - self.queue=[] - self.working=0 - self.peer_found=0 - - def push(self, producer, send=1): - # this is thread-safe when send is false - # note, that strings are not wrapped in - # producers by default - if self.closed: - return - self.producer_fifo.push(producer) - if send: self.initiate_send() - - push_with_producer=push - - def work(self): - "try to handle a request" - if not self.working: - if self.queue: - self.working=1 - try: module_name, request, response=self.queue.pop(0) - except: return - handle(module_name, request, response) - - def close(self): - self.closed=1 - while self.queue: - self.queue.pop() - if self.current_request is not None: - self.current_request.channel=None # break circ refs - self.current_request=None - while self.producer_fifo: - p=self.producer_fifo.first() - if p is not None and type(p) != types.StringType: - p.more() # free up resources held by producer - self.producer_fifo.pop() - self.del_channel() - #self.socket.set_shutdown(SSL.SSL_SENT_SHUTDOWN|SSL.SSL_RECEIVED_SHUTDOWN) - self.socket.close() - - def done(self): - "Called when a publishing request is finished" - self.working=0 - self.work() - - def kill_zombies(self): - now = int (time.time()) - for channel in asyncore.socket_map.values(): - if channel.__class__ == self.__class__: - if (now - channel.creation_time) > channel.zombie_timeout: - channel.close() - - -class zhttps_server(https_server): - "https server" - - SERVER_IDENT='ZServerSSL/%s' % (ZSERVER_SSL_VERSION,) - - channel_class = zhttps_channel - shutup = 0 - - def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): - self.shutup = 1 - https_server.__init__(self, ip, port, ssl_ctx, resolver, logger_object) - self.ssl_ctx = ssl_ctx - self.shutup = 0 - self.log_info('(%s) HTTPS server started at %s\n' - '\tHostname: %s\n\tPort: %d' % ( - self.SERVER_IDENT, - time.ctime(time.time()), - self.server_name, - self.server_port - )) - - def log_info(self, message, type='info'): - if self.shutup: return - dispatcher.log_info(self, message, type) - - def readable(self): - return self.accepting and \ - len(asyncore.socket_map) < CONNECTION_LIMIT - - def listen(self, num): - # override asyncore limits for nt's listen queue size - self.accepting = 1 - return self.socket.listen (num) - diff --git a/demo/Zope/ZServer/__init__.py b/demo/Zope/ZServer/__init__.py deleted file mode 100644 index 69fe9b1..0000000 --- a/demo/Zope/ZServer/__init__.py +++ /dev/null @@ -1,95 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE -# -############################################################################## - -import sys, os - -# HACKERY to get around asyncore issues. This ought to go away! We're -# currently using the Python 2.2 asyncore bundled with Zope to override -# brokenness in the Python 2.1 version. We need to do some funny business -# to make this work, as a 2.2-ism crept into the asyncore code. -if os.name == 'posix': - import fcntl - if not hasattr(fcntl, 'F_GETFL'): - import FCNTL - fcntl.F_GETFL = FCNTL.F_GETFL - fcntl.F_SETFL = FCNTL.F_SETFL - -from medusa import asyncore -sys.modules['asyncore'] = asyncore - - - -from medusa.test import max_sockets -CONNECTION_LIMIT=max_sockets.max_select_sockets() - -ZSERVER_VERSION='1.1b1' -import App.FindHomes -try: - import App.version_txt - ZOPE_VERSION=App.version_txt.version_txt() -except: - ZOPE_VERSION='experimental' - - -# Try to poke zLOG default logging into asyncore -# XXX We should probably should do a better job of this, -# however that would mean that ZServer required zLOG. -try: - from zLOG import LOG, register_subsystem, BLATHER, INFO, WARNING, ERROR - register_subsystem('ZServer') - severity={'info':INFO, 'warning':WARNING, 'error': ERROR} - - def log_info(self, message, type='info'): - if message[:14]=='adding channel' or \ - message[:15]=='closing channel' or \ - message == 'Computing default hostname': - LOG('ZServer', BLATHER, message) - else: - LOG('ZServer', severity[type], message) - - import asyncore - asyncore.dispatcher.log_info=log_info -except: - pass - -# A routine to try to arrange for request sockets to be closed -# on exec. This makes it easier for folks who spawn long running -# processes from Zope code. Thanks to Dieter Maurer for this. -try: - import fcntl - try: - from fcntl import F_SETFD, FD_CLOEXEC - except ImportError: - from FCNTL import F_SETFD, FD_CLOEXEC - - def requestCloseOnExec(sock): - try: fcntl.fcntl(sock.fileno(), F_SETFD, FD_CLOEXEC) - except: pass - -except (ImportError, AttributeError): - - def requestCloseOnExec(sock): - pass - -import asyncore -from medusa import resolver, logger -from HTTPServer import zhttp_server, zhttp_handler -from HTTPS_Server import zhttps_server, zhttps0_handler, zhttps_handler -from PCGIServer import PCGIServer -from FCGIServer import FCGIServer -from FTPServer import FTPServer -from PubCore import setNumberOfThreads -from medusa.monitor import secure_monitor_server - -# override the service name in logger.syslog_logger -logger.syslog_logger.svc_name='ZServer' diff --git a/demo/Zope/ZServer/medusa/ftps_server.py b/demo/Zope/ZServer/medusa/ftps_server.py deleted file mode 100644 index 8fee339..0000000 --- a/demo/Zope/ZServer/medusa/ftps_server.py +++ /dev/null @@ -1,438 +0,0 @@ -"""An FTP/TLS server built on Medusa's ftp_server. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -# Python -import socket, string, sys, time - -# Medusa -from counter import counter -import asynchat, asyncore, ftp_server, logger - -# M2Crypto -from M2Crypto import SSL - -VERSION_STRING='0.09' - -class ftp_tls_channel(ftp_server.ftp_channel): - - """FTP/TLS server channel for Medusa.""" - - def __init__(self, server, ssl_ctx, conn, addr): - """Initialise the channel.""" - self.ssl_ctx = ssl_ctx - self.server = server - self.current_mode = 'a' - self.addr = addr - asynchat.async_chat.__init__(self, conn) - self.set_terminator('\r\n') - self.client_addr = (addr[0], 21) - self.client_dc = None - self.in_buffer = '' - self.closing = 0 - self.passive_acceptor = None - self.passive_connection = None - self.filesystem = None - self.authorized = 0 - self._ssl_accepting = 0 - self._ssl_accepted = 0 - self._pbsz = None - self._prot = None - resp = '220 %s M2Crypto (Medusa) FTP/TLS server v%s ready.' - self.respond(resp % (self.server.hostname, VERSION_STRING)) - - def writable(self): - return self._ssl_accepting or self._ssl_accepted - - def handle_read(self): - """Handle a read event.""" - if self._ssl_accepting: - self._ssl_accepted = self.socket.accept_ssl() - if self._ssl_accepted: - self._ssl_accepting = 0 - else: - try: - ftp_server.ftp_channel.handle_read(self) - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - self.close() - else: - raise - - def handle_write(self): - """Handle a write event.""" - if self._ssl_accepting: - self._ssl_accepted = self.socket.accept_ssl() - if self._ssl_accepted: - self._ssl_accepting = 0 - else: - try: - ftp_server.ftp_channel.handle_write(self) - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - self.close() - else: - raise - - def send(self, data): - """Send data over SSL.""" - try: - result = self.socket.send(data) - if result <= 0: - return 0 - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), what)) - return 0 - - def recv(self, buffer_size): - """Receive data over SSL.""" - try: - result = self.socket.recv(buffer_size) - if not result: - return '' - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), what)) - return '' - - def found_terminator(self): - """Dispatch the FTP command.""" - line = self.in_buffer - if not len(line): - return - - sp = string.find(line, ' ') - if sp != -1: - line = [line[:sp], line[sp+1:]] - else: - line = [line] - - command = string.lower(line[0]) - if string.find(command, 'stor') != -1: - while command and command[0] not in string.letters: - command = command[1:] - - func_name = 'cmd_%s' % command - if command != 'pass': - self.log('<== %s' % repr(self.in_buffer)[1:-1]) - else: - self.log('<== %s' % line[0]+' ') - - self.in_buffer = '' - if not hasattr(self, func_name): - self.command_not_understood(line[0]) - return - - func = getattr(self, func_name) - if not self.check_command_authorization(command): - self.command_not_authorized(command) - else: - try: - result = apply(func, (line,)) - except: - self.server.total_exceptions.increment() - (file, func, line), t, v, tbinfo = asyncore.compact_traceback() - if self.client_dc: - try: - self.client_dc_close() - except: - pass - resp = '451 Server error: %s, %s: file %s line: %s' - self.respond(resp % (t, v, file, line)) - - def make_xmit_channel(self): - """Create a connection for sending data.""" - pa = self.passive_acceptor - if pa: - if pa.ready: - conn, addr = pa.ready - if self._prot: - cdc = tls_xmit_channel(self, conn, self.ssl_ctx, addr) - else: - cdc = ftp_server.xmit_channel(self, addr) - cdc.set_socket(conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - if self._prot: - cdc = tls_xmit_channel(self, None, self.ssl_ctx, None) - else: - cdc = ftp_server.xmit_channel(self) - else: - if self._prot: - cdc = tls_xmit_channel(self, None, self.ssl_ctx, self.client_addr) - else: - cdc = ftp_server.xmit_channel(self, self.client_addr) - cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) - if self.bind_local_minus_one: - cdc.bind(('', self.server.port - 1)) - try: - cdc.connect(self.client_addr) - except socket.error, what: - self.respond('425 Cannot build data connection') - self.client_dc = cdc - - def make_recv_channel(self, fd): - """Create a connection for receiving data.""" - pa = self.passive_acceptor - if pa: - if pa.ready: - conn, addr = pa.ready - if self._prot: - cdc = tls_recv_channel(self, conn, self.ssl_ctx, addr, fd) - else: - cdc = ftp_server.recv_channel(self, addr, fd) - cdc.set_socket(conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - if self._prot: - cdc = tls_recv_channel(self, None, self.ssl_ctx, None, fd) - else: - cdc = ftp_server.recv_channel(self, None, fd) - else: - if self._prot: - cdc = tls_recv_channel(self, None, self.ssl_ctx, self._prot, self.client_addr, fd) - else: - cdc = ftp_server.recv_channel(self, self.client_addr, fd) - cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) - try: - cdc.connect(self.client_addr) - except socket.error, what: - self.respond('425 Cannot build data connection') - self.client_dc = cdc - - def cmd_auth(self, line): - """Prepare for TLS operation.""" - # XXX Handle variations. - if line[1] != 'TLS': - self.command_not_understood (string.join(line)) - else: - self.respond('234 AUTH TLS successful') - self._ssl_accepting = 1 - self.socket = SSL.Connection(self.ssl_ctx, self.socket) - self.socket.setup_addr(self.addr) - self.socket.setup_ssl() - self.socket.set_accept_state() - self._ssl_accepted = self.socket.accept_ssl() - if self._ssl_accepted: - self._ssl_accepting = 0 - - def cmd_pbsz(self, line): - """Negotiate size of buffer for secure data transfer. For - FTP/TLS the only valid value for the parameter is '0'; any - other value is accepted but ignored.""" - if not (self._ssl_accepting or self._ssl_accepted): - return self.respond('503 AUTH TLS must be issued prior to PBSZ') - self._pbsz = 1 - self.respond('200 PBSZ=0 successful.') - - def cmd_prot(self, line): - """Negotiate the security level of the data connection.""" - if self._pbsz is None: - return self.respond('503 PBSZ must be issued prior to PROT') - if line[1] == 'C': - self.respond('200 Protection set to Clear') - self._pbsz = None - self._prot = None - elif line[1] == 'P': - self.respond('200 Protection set to Private') - self._prot = 1 - elif line[1] in ('S', 'E'): - self.respond('536 PROT %s unsupported' % line[1]) - else: - self.respond('504 PROT %s unsupported' % line[1]) - - -class ftp_tls_server(ftp_server.ftp_server): - - """FTP/TLS server for Medusa.""" - - SERVER_IDENT = 'M2Crypto FTP/TLS Server (v%s)' % VERSION_STRING - - ftp_channel_class = ftp_tls_channel - - def __init__(self, authz, ssl_ctx, host=None, ip='', port=21, resolver=None, log_obj=None): - """Initialise the server.""" - self.ssl_ctx = ssl_ctx - self.ip = ip - self.port = port - self.authorizer = authz - - if host is None: - self.hostname = socket.gethostname() - else: - self.hostname = host - - self.total_sessions = counter() - self.closed_sessions = counter() - self.total_files_out = counter() - self.total_files_in = counter() - self.total_bytes_out = counter() - self.total_bytes_in = counter() - self.total_exceptions = counter() - - asyncore.dispatcher.__init__(self) - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.set_reuse_addr() - self.bind((self.ip, self.port)) - self.listen(5) - - if log_obj is None: - log_obj = sys.stdout - - if resolver: - self.logger = logger.resolving_logger(resolver, log_obj) - else: - self.logger = logger.unresolving_logger(logger.file_logger(sys.stdout)) - - l = 'M2Crypto (Medusa) FTP/TLS server started at %s\n\tAuthz: %s\n\tHostname: %s\n\tPort: %d' - self.log_info(l % (time.ctime(time.time()), repr(self.authorizer), self.hostname, self.port)) - - def handle_accept(self): - """Accept a socket and dispatch a channel to handle it.""" - conn, addr = self.accept() - self.total_sessions.increment() - self.log_info('Connection from %s:%d' % addr) - self.ftp_channel_class(self, self.ssl_ctx, conn, addr) - - -class nbio_ftp_tls_actor: - - """TLS protocol negotiation mixin for FTP/TLS.""" - - def tls_init(self, sock, ssl_ctx, client_addr): - """Perform TLS protocol negotiation.""" - self.ssl_ctx = ssl_ctx - self.client_addr = client_addr - self._ssl_handshaking = 1 - self._ssl_handshake_ok = 0 - if sock: - self.socket = SSL.Connection(self.ssl_ctx, sock) - self.socket.setup_addr(self.client_addr) - self.socket.setup_ssl() - self._ssl_handshake_ok = self.socket.accept_ssl() - if self._ssl_handshake_ok: - self._ssl_handshaking = 0 - self.add_channel() - # else the client hasn't connected yet; when that happens, - # handle_connect() will be triggered. - - def tls_neg_ok(self): - """Return status of TLS protocol negotiation.""" - if self._ssl_handshaking: - self._ssl_handshake_ok = self.socket.accept_ssl() - if self._ssl_handshake_ok: - self._ssl_handshaking = 0 - return self._ssl_handshake_ok - - def handle_connect(self): - """Handle a data connection that occurs after this instance came - into being. When this handler is triggered, self.socket has been - created and refers to the underlying connected socket.""" - self.socket = SSL.Connection(self.ssl_ctx, self.socket) - self.socket.setup_addr(self.client_addr) - self.socket.setup_ssl() - self._ssl_handshake_ok = self.socket.accept_ssl() - if self._ssl_handshake_ok: - self._ssl_handshaking = 0 - self.add_channel() - - def send(self, data): - """Send data over SSL.""" - try: - result = self.socket.send(data) - if result <= 0: - return 0 - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), what)) - return 0 - - def recv(self, buffer_size): - """Receive data over SSL.""" - try: - result = self.socket.recv(buffer_size) - if not result: - return '' - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), what)) - return '' - - -class tls_xmit_channel(nbio_ftp_tls_actor, ftp_server.xmit_channel): - - """TLS driver for a send-only data connection.""" - - def __init__(self, channel, conn, ssl_ctx, client_addr=None): - """Initialise the driver.""" - ftp_server.xmit_channel.__init__(self, channel, client_addr) - self.tls_init(conn, ssl_ctx, client_addr) - - def readable(self): - """This channel is readable iff TLS negotiation is in progress. - (Which implies a connected channel, of course.)""" - if not self.connected: - return 0 - else: - return self._ssl_handshaking - - def writable(self): - """This channel is writable iff TLS negotiation is in progress - or the application has data to send.""" - if self._ssl_handshaking: - return 1 - else: - return ftp_server.xmit_channel.writable(self) - - def handle_read(self): - """Handle a read event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.xmit_channel.handle_read(self) - - def handle_write(self): - """Handle a write event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.xmit_channel.handle_write(self) - - -class tls_recv_channel(nbio_ftp_tls_actor, ftp_server.recv_channel): - - """TLS driver for a receive-only data connection.""" - - def __init__(self, channel, conn, ssl_ctx, client_addr, fd): - """Initialise the driver.""" - ftp_server.recv_channel.__init__(self, channel, client_addr, fd) - self.tls_init(conn, ssl_ctx, client_addr) - - def writable(self): - """This channel is writable iff TLS negotiation is in progress.""" - return self._ssl_handshaking - - def handle_read(self): - """Handle a read event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.recv_channel.handle_read(self) - - def handle_write(self): - """Handle a write event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.recv_channel.handle_write(self) - - diff --git a/demo/Zope/ZServer/medusa/https_server.py b/demo/Zope/ZServer/medusa/https_server.py deleted file mode 100644 index 9b932b7..0000000 --- a/demo/Zope/ZServer/medusa/https_server.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python - -"""A https server built on Medusa's http_server. - -Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" - -import asynchat, asyncore, http_server, socket, sys -from M2Crypto import SSL, version - -VERSION_STRING=version - -class https_channel(http_server.http_channel): - - ac_in_buffer_size = 1 << 16 - - def __init__(self, server, conn, addr): - http_server.http_channel.__init__(self, server, conn, addr) - - def send(self, data): - try: - result = self.socket._write_nbio(data) - if result <= 0: - return 0 - else: - self.server.bytes_out.increment(result) - return result - except SSL.SSLError, why: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), why)) - return 0 - - def recv(self, buffer_size): - try: - result = self.socket._read_nbio(buffer_size) - if result is None: - return '' - elif result == '': - self.close() - return '' - else: - self.server.bytes_in.increment(len(result)) - return result - except SSL.SSLError, why: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), why)) - return '' - - -class https_server(http_server.http_server): - - SERVER_IDENT='M2Crypto HTTPS Server (v%s)' % VERSION_STRING - - channel_class=https_channel - - def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): - http_server.http_server.__init__(self, ip, port, resolver, logger_object) - self.ssl_ctx=ssl_ctx - - def handle_accept(self): - # Cribbed from http_server. - self.total_clients.increment() - try: - conn, addr = self.accept() - except socket.error: - # linux: on rare occasions we get a bogus socket back from - # accept. socketmodule.c:makesockaddr complains that the - # address family is unknown. We don't want the whole server - # to shut down because of this. - sys.stderr.write ('warning: server accept() threw an exception\n') - return - - # Turn the vanilla socket into an SSL connection. - try: - ssl_conn=SSL.Connection(self.ssl_ctx, conn) - ssl_conn._setup_ssl(addr) - ssl_conn.accept_ssl() - self.channel_class(self, ssl_conn, addr) - except SSL.SSLError: - pass - - def writeable(self): - return 0 - diff --git a/demo/Zope/ca.pem b/demo/Zope/ca.pem deleted file mode 100644 index b7c84a1..0000000 --- a/demo/Zope/ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 -NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML -TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl -cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK -q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N -e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf -q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G -A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV -BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex -JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 -DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG -SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ -dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J -vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf ------END CERTIFICATE----- diff --git a/demo/Zope/dh1024.pem b/demo/Zope/dh1024.pem deleted file mode 100644 index 81d43f6..0000000 --- a/demo/Zope/dh1024.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq -/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx -/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC ------END DH PARAMETERS----- diff --git a/demo/Zope/lib/python/Products/GuardedFile/GuardedFile.py b/demo/Zope/lib/python/Products/GuardedFile/GuardedFile.py deleted file mode 100644 index 1e3137f..0000000 --- a/demo/Zope/lib/python/Products/GuardedFile/GuardedFile.py +++ /dev/null @@ -1,53 +0,0 @@ -"""GuardedFile.GuardedFile - -Copyright (c) 2000-2003 Ng Pheng Siong. All rights reserved. -This software is released under the ZPL. Usual disclaimers apply.""" - -__version__ = '1.3' - -from AccessControl import getSecurityManager -from Globals import HTMLFile, MessageDialog -from OFS.Image import File, cookId - -manage_addForm = HTMLFile('add', globals(),Kind='GuardedFile',kind='GuardedFile') -def manage_addGuardedFile(self, id, file, title='', precondition='', content_type='', REQUEST=None): - """ - Add a new GuardedFile object. - - Creates a new GuardedFile object 'id' with the content of 'file'. - """ - # Object creation stuff, cribbed from OFS.Image.manage_addFile(). - id, title = cookId(id, title, file) - self = self.this() - self._setObject(id, GuardedFile(id, title, '', content_type, precondition)) - obj = self._getOb(id) - obj.manage_upload(file) - - # Unset permission acquisition. - obj.manage_acquiredPermissions() - - # Create a proxy role and set a specific permission for it. - proxy_role = "proxy_for_%s" % id - self._addRole(proxy_role) - obj.manage_role(proxy_role, ['View']) - uname = getSecurityManager().getUser().getUserName() - self.manage_addLocalRoles(uname, (proxy_role,), REQUEST) - - # Feedback. - if REQUEST: return MessageDialog( - title ='Success!', - message='GuardedFile "%s" has been created.' % id, - action ='manage_main') - - -class GuardedFile(File): - """A File object accessible by proxy only.""" - meta_type = "GuardedFile" - - def manage_beforeDelete(self, item, container): - """Delete self's proxy role.""" - role = "proxy_for_%s" % self.__name__ - container._delRoles([role], None) - self.manage_delLocalRoles(self.users_with_local_role(role)) - - diff --git a/demo/Zope/lib/python/Products/GuardedFile/README.txt b/demo/Zope/lib/python/Products/GuardedFile/README.txt deleted file mode 100644 index d35b9a5..0000000 --- a/demo/Zope/lib/python/Products/GuardedFile/README.txt +++ /dev/null @@ -1,16 +0,0 @@ -GuardedFile - - A GuardedFile is a Zope File that is accessible *by proxy* only. - - When a GuardedFile is created, all acquired permissions are unset. - A proxy role is created in its container with the sole permission - "View". - - When the GuardedFile is deleted, its associated proxy role is also - removed. - - In all other aspects a GuardedFile behaves exactly like a File. - - - $Id: README.txt 299 2005-06-09 17:32:28Z heikki $ - $Revision: 1.2 $ diff --git a/demo/Zope/lib/python/Products/GuardedFile/TODO.txt b/demo/Zope/lib/python/Products/GuardedFile/TODO.txt deleted file mode 100644 index 8afc8c7..0000000 --- a/demo/Zope/lib/python/Products/GuardedFile/TODO.txt +++ /dev/null @@ -1 +0,0 @@ -1. Icon. diff --git a/demo/Zope/lib/python/Products/GuardedFile/__init__.py b/demo/Zope/lib/python/Products/GuardedFile/__init__.py deleted file mode 100644 index f587c75..0000000 --- a/demo/Zope/lib/python/Products/GuardedFile/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -"""GuardedFile.__init__ - -Copyright (c) 2000 Ng Pheng Siong. All rights reserved. -This software is released under the ZPL.""" - -__version__ = '1.1' - -import GuardedFile - -def initialize(context): - try: - context.registerClass( - GuardedFile.GuardedFile, - constructors=(GuardedFile.manage_addForm, GuardedFile.manage_addGuardedFile) - #icon='folder.gif' - ) - context.registerBaseClass(GuardedFile.GuardedFile) - - except: - import sys, traceback, string - type, val, tb = sys.exc_info() - sys.stderr.write(string.join( - traceback.format_exception(type, val, tb),'')) - del type, val, tb - diff --git a/demo/Zope/lib/python/Products/GuardedFile/add.dtml b/demo/Zope/lib/python/Products/GuardedFile/add.dtml deleted file mode 100644 index ed78fa6..0000000 --- a/demo/Zope/lib/python/Products/GuardedFile/add.dtml +++ /dev/null @@ -1,78 +0,0 @@ - - - - -

- A GuardedFile is a Zope File that is accessible by proxy only. -

- -

- When a GuardedFile is created, all acquired permissions are unset. - A proxy role is created in its container with the sole permission - "View". -

- -

- When the GuardedFile is deleted, its associated proxy role is also - removed. -

- -

- In all other aspects a GuardedFile behaves exactly like a File. -

- -

- You can create a new using the form below. - Select a file from your local computer by clicking the - Browse button. The file you select will be uploaded - to Zope as a . -

- -
- - - - - - - - - - - - - - - - - -
-
- Id -
-
- -
-
- Title -
-
- -
-
- File -
-
- -
- -
- -
-
-
- - - diff --git a/demo/Zope/lib/python/Products/GuardedFile/refresh.txt b/demo/Zope/lib/python/Products/GuardedFile/refresh.txt deleted file mode 100644 index e69de29..0000000 diff --git a/demo/Zope/lib/python/Products/GuardedFile/version.txt b/demo/Zope/lib/python/Products/GuardedFile/version.txt deleted file mode 100644 index 1e5ebbf..0000000 --- a/demo/Zope/lib/python/Products/GuardedFile/version.txt +++ /dev/null @@ -1 +0,0 @@ -GuardedFile-1-1-0 diff --git a/demo/Zope/lib/python/Products/ZSmime/README.txt b/demo/Zope/lib/python/Products/ZSmime/README.txt deleted file mode 100644 index f43740b..0000000 --- a/demo/Zope/lib/python/Products/ZSmime/README.txt +++ /dev/null @@ -1,18 +0,0 @@ -ZSmime enables Zope to generate S/MIME-signed/encrypted messages. - -ZSmime is useful where Zope accepts confidential information over the -web, e.g., credit card information, Swiss bank account instructions, etc. -Such information can be protected by ZSmime and relayed off-site -immediately. This reduces the value of the information carried on-site -and in turn reduces the effect of a successful attack against the site. - -Even if the S/MIME-protected information remains on-site, it is now -encrypted - this introduces additional cost in defeating the protection -and may mitigate the impact of a successful site penetration. - -ZSmime adds a DTML tag "dtml-smime" to Zope. - - -$Id: README.txt 299 2005-06-09 17:32:28Z heikki $ -$Revision: 1.1 $ - diff --git a/demo/Zope/lib/python/Products/ZSmime/SmimeTag.py b/demo/Zope/lib/python/Products/ZSmime/SmimeTag.py deleted file mode 100644 index 142bec9..0000000 --- a/demo/Zope/lib/python/Products/ZSmime/SmimeTag.py +++ /dev/null @@ -1,104 +0,0 @@ -"""ZSmime.SmimeTag - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved. -This software is released under the ZPL. Usual disclaimers apply.""" - -__version__ = '1.2' - -# Zope tag stuff. -from DocumentTemplate.DT_String import String -from DocumentTemplate.DT_Util import * -from DocumentTemplate.DT_Var import Var, Call - -# M2Crypto. -from M2Crypto import BIO, SMIME, X509 - -SmimeError = "SmimeTag Error" - -class SmimeTag: - """""" - - name = 'smime' - blockContinuations = () - - def __init__(self, blocks): - tname, args, section = blocks[0] - self.section = section - - args = parse_params(args, signer=None, recipients=None) - has_key = args.has_key - - if has_key('signer'): - self.signer = args['signer'] - try: - Call(self.signer) - except ParseError: - raise SmimeError, ('Invalid parameter "signer".') - else: - raise SmimeError, ('The parameter "signer" was not specified in tag.') - - if has_key('recipients'): - self.recipients = args['recipients'] - try: - Call(self.recipients) - except ParseError: - raise SmimeError, ('Invalid parameter "recipients".') - else: - raise SmimeError, ('The parameter "recipients" was not specified in tag.') - - - def render(self, md): - # Render the dtml block. - data = render_blocks(self.section.blocks, md) - data_bio = BIO.MemoryBuffer(data) - - # Prepare to S/MIME. - s = SMIME.SMIME() - - # Render the signer key, load into BIO. - try: - signer = Var(self.signer).render(md) - except ParseError: - raise SmimeError, ('Invalid parameter "signer".') - signer_key_bio = BIO.MemoryBuffer(signer) - signer_cert_bio = BIO.MemoryBuffer(signer) # XXX Kludge. - - # Sign the data. - s.load_key_bio(signer_key_bio, signer_cert_bio) - p7 = s.sign(data_bio, flags=SMIME.PKCS7_TEXT) - - # Recreate coz sign() has consumed the MemoryBuffer. - # May be cheaper to seek to start. - data_bio = BIO.MemoryBuffer(data) - - # Render recipients, load into BIO. - try: - recip = Var(self.recipients).render(md) - except ParseError: - raise SmimeError, ('Invalid parameter "recipients".') - recip_bio = BIO.MemoryBuffer(recip) - - # Load recipient certificates. - sk = X509.X509_Stack() - sk.push(X509.load_cert_bio(recip_bio)) - s.set_x509_stack(sk) - - # Set a cipher. - s.set_cipher(SMIME.Cipher('des_ede3_cbc')) - - # Encrypt. - tmp_bio = BIO.MemoryBuffer() - s.write(tmp_bio, p7) - p7 = s.encrypt(tmp_bio) - - # Finally, return the now signed/encrypted PKCS7. - out = BIO.MemoryBuffer() - s.write(out, p7) - return out.getvalue() - - - __call__ = render - - -String.commands['smime'] = SmimeTag - diff --git a/demo/Zope/lib/python/Products/ZSmime/__init__.py b/demo/Zope/lib/python/Products/ZSmime/__init__.py deleted file mode 100644 index ebb77f6..0000000 --- a/demo/Zope/lib/python/Products/ZSmime/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -"""ZSmime.__init__ - -Copyright (c) 2000 Ng Pheng Siong. All rights reserved. -This software is released under the ZPL. Usual disclaimers apply.""" - -__version__='1.1' - -import SmimeTag - diff --git a/demo/Zope/lib/python/Products/ZSmime/version.txt b/demo/Zope/lib/python/Products/ZSmime/version.txt deleted file mode 100644 index ac26a94..0000000 --- a/demo/Zope/lib/python/Products/ZSmime/version.txt +++ /dev/null @@ -1 +0,0 @@ -ZSmime-1-0-1 diff --git a/demo/Zope/server.pem b/demo/Zope/server.pem deleted file mode 100644 index 1ee9282..0000000 --- a/demo/Zope/server.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx -NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls -b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c -kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 -KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp -/y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 -QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB -H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 -du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv -MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm -aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t -ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy -lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW -iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 -0QkPQNdP ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu -6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe -I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB -AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ -u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 -xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 -1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp -IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx -luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I -lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS -38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy -v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z -DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= ------END RSA PRIVATE KEY----- diff --git a/demo/Zope/starts b/demo/Zope/starts deleted file mode 100644 index 2676243..0000000 --- a/demo/Zope/starts +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -umask 077 -reldir=`dirname $0` -cwd=`cd $reldir; pwd` -# Zope's event logger is controlled by the "EVENT_LOG_FILE" environment -# variable. If you don't have a "EVENT_LOG_FILE" environment variable -# (or its older alias "STUPID_LOG_FILE") set, Zope will log to the standard -# output. For more information on EVENT_LOG_FILE, see doc/ENVIRONMENT.txt. -ZLOGFILE=$EVENT_LOG_FILE -if [ -z "$ZLOGFILE" ]; then - ZLOGFILE=$STUPID_LOG_FILE -fi -if [ -z "$ZLOGFILE" ]; then - EVENT_LOG_FILE="" - export EVENT_LOG_FILE -fi -exec /usr/local/bin/python2.1 $cwd/z2s.py -D "$@" diff --git a/demo/Zope/starts.bat b/demo/Zope/starts.bat deleted file mode 100755 index c8bd3b6..0000000 --- a/demo/Zope/starts.bat +++ /dev/null @@ -1 +0,0 @@ -"C:\pkg\zope260\bin\python.exe" "C:\pkg\zope260\z2s.py" -D %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/demo/Zope/utilities/x509_user.py b/demo/Zope/utilities/x509_user.py deleted file mode 100644 index 1d350d6..0000000 --- a/demo/Zope/utilities/x509_user.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python - -""" -This is a very simple program to manage the access_x509 database. The -overriding goal is program portability, hence its use of 'anydbm'. - -Invoke it thusly: - - x509_user.py - -u - [ -x ] - [ -f ] - - is the Zope username; it must be present. - - is the X.509 certificate's subject distinguished name -to associate with the user. If it is present, the association is created -or updated. If it is absent, the association is removed. - - defaults to 'access_x509'. - -(I told you this is a dumb program.) - - -To read the subject distinguished name from the certificate 'client.pem', -invoke 'openssl' thusly: - - openssl x509 -subject -noout -in client.pem - -This produces the output: - - subject=/C=SG/O=M2Crypto Client/CN=M2Crypto Client/Email=ngps@post1.com - - -Next, invoke this tool: - - x509_user.py -u superuser \\ - -f "/C=SG/O=M2Crypto Client/CN=M2Crypto Client/Email=ngps@post1.com" - -This associates the user who owns client.pem to the Zope "superuser". - - -Copyright (c) 2000 Ng Pheng Siong. This program is released under the ZPL. -""" - -import anydbm, getopt, sys - -x509_db = 'access_x509' -username = subject_dn = None - -argerr='Usage' - -optlist, optarg=getopt.getopt(sys.argv[1:], 'f:u:x:') # ;-) -for opt in optlist: - if '-f' in opt: - x509_db = opt[1] - elif '-u' in opt: - username = opt[1] - elif '-x' in opt: - subject_dn = opt[1] - -if username is None: - raise argerr, '\n' + __doc__ - -db = anydbm.open(x509_db, 'cw') -if subject_dn is None: - # Remove the association... - try: - subject_dn = db[username] - del db[subject_dn] - del db[username] - except: - pass -else: - # Create/update the association. - db[subject_dn] = username - db[username] = subject_dn -db.close() - diff --git a/demo/Zope/z2s.py b/demo/Zope/z2s.py deleted file mode 100644 index 33885ab..0000000 --- a/demo/Zope/z2s.py +++ /dev/null @@ -1,1078 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE -# -############################################################################## -"""Zope 2 ZServer start-up file - -Usage: %(program)s [options] [environment settings] - -Options: - - -h - - Output this text. - - -z path - - The location of the Zope installation. - The default is the location of this script, %(here)s. - - -Z 0 or 1 - - UNIX only! This option is ignored on Windows. - - This option controls whether a management process will be created - that restarts Zope after a shutdown or crash. - - If the argument to -Z is non-null (e.g. "-Z1" or "-Zyes"), a - management process will be used. If the argument to -Z is "-", or - "0", (e.g. "-Z-" or "-Z0"), a management process will not be used. - On UNIX, the default behavior is to create a separate management - process (e.g. -Z1) if the -Z option is not specified. - - (Note: the -Z option in Zopes before Zope 2.6 used to be used to specify - a pidfile name for the management process. This pidfile no longer - exists). - - -t n - - The number of threads to use, if ZODB3 is used. The default is - %(NUMBER_OF_THREADS)s. - - -i n - - Set the interpreter check interval. This integer value - determines how often the interpreter checks for periodic things - such as thread switches and signal handlers. The Zope default - is 500, but you may want to experiment with other values that - may increase performance in your particular environment. - - -D - - Run in Zope debug mode. This causes the Zope process not to - detach from the controlling terminal, and is equivalent to - supplying the environment variable setting Z_DEBUG_MODE=1 - - -a ipaddress - - The IP address to listen on. If this is an empty string - (e.g. -a ''), then all addresses on the machine are used. The - default is %(IP_ADDRESS)s. - - -d ipaddress - - IP address of your DNS server. If this is an empty string - (e.g. -d ''), then IP addresses will not be logged. If you have - DNS service on your local machine then you can set this to - 127.0.0.1. The default is: %(DNS_IP)s. - - -u username or uid number - - The username to run ZServer as. You may want to run ZServer as - a dedicated user. This only works under Unix, and if ZServer - is started as root, and is required in that case. - - -P [ipaddress:]number - - Set the web, ftp and monitor port numbers simultaneously - as offsets from the number. The web port number will be number+80. - The FTP port number will be number+21. The monitor port number will - be number+99. - - The number can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple -P options can be provided to run multiple sets of servers. - - -w port - - The Web server (HTTP) port. This defaults to %(HTTP_PORT)s. The - standard port for HTTP services is 80. If this is a dash - (e.g. -w -), then HTTP is disabled. - - The number can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple -w options can be provided to run multiple servers. - - -y port - - The SSL Web server (HTTPS) port. This defaults to %(HTTPS_PORT)s. The - standard port for HTTPS services is 443. If this is a dash - (e.g. -y -), then HTTPS is disabled. - - The number can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple -y options can be provided to run multiple servers. - - -W port - - The "WebDAV source" port. If this is a dash (e.g. -W -), then - "WebDAV source" is disabled. The default is disabled. Note that - this feature is a workaround for the lack of "source-link" support - in standard WebDAV clients. - - The port can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple -W options can be provided to run multiple servers. - - -Y port - - The "WebDAV source over HTTPS" port. If this is a dash (e.g. -Y -), then - "WebDAV source over HTTPS" is disabled. The default is disabled. Note that - this feature is a workaround for the lack of "source-link" support - in standard WebDAV clients. - - The port can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple -Y options can be provided to run multiple servers. - - -x - - If present, this option causes Zope to run in X.509 certificate-based - authentication mode. - - -C - --force-http-connection-close - - If present, this option causes Zope to close all HTTP connections, - regardless of the 'Connection:' header (or lack of one) sent by - the client. - - -f port - - The FTP port. If this is a dash (e.g. -f -), then FTP - is disabled. The standard port for FTP services is 21. The - default is %(FTP_PORT)s. - - The port can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple -f options can be provided to run multiple servers. - - -p path - - Path to the PCGI resource file. The default value is - %(PCGI_FILE)s, relative to the Zope location. If this is a dash - (-p -) or the file does not exist, then PCGI is disabled. - - -F path_or_port - - Either a port number (for inet sockets) or a path name (for unix - domain sockets) for the FastCGI Server. If the flag and value are - not specified then the FastCGI Server is disabled. - - -m port - - The secure monitor server port. If this is a dash - (-m -), then the monitor server is disabled. The monitor server - allows interactive Python style access to a running ZServer. To - access the server see medusa/monitor_client.py or - medusa/monitor_client_win32.py. The monitor server password is the - same as the Zope emergency user password set in the 'access' - file. The default is to not start up a monitor server. - - The port can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple -m options can be provided to run multiple servers. - - --icp port - - The ICP port. ICP can be used to distribute load between back-end - zope servers, if you are using an ICP-aware front-end proxy such - as Squid. - - The port can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple --icp options can be provided to run multiple servers. - - -l path - - Path to the ZServer log file. If this is a relative path then the - log file will be written to the 'var' directory. The default is - %(LOG_FILE)s. - - -r - - Run ZServer is read-only mode. ZServer won't write anything to disk. - No log files, no pid files, nothing. This means that you can't do a - lot of stuff like use PCGI, and zdaemon. ZServer will log hits to - STDOUT and zLOG will log to STDERR. - - -L - - Enable locale (internationalization) support. The value passed for - this option should be the name of the locale to be used (see your - operating system documentation for locale information specific to - your system). If an empty string is passed for this option (-L ''), - Zope will set the locale to the user's default setting (typically - specified in the $LANG environment variable). If your Python - installation does not support the locale module, the requested - locale is not supported by your system or an empty string was - passed but no default locale can be found, an error will be raised - and Zope will not start. - - -X - - Disable servers. This might be used to effectively disable all - default server settings or previous server settings in the option - list before providing new settings. For example to provide just a - web server: - - %(program)s -X -w80 - - -M file - - Save detailed logging information to the given file. - This log includes separate entries for: - - - The start of a request, - - The start of processing the request in an application thread, - - The start of response output, and - - The end of the request. - -Environment settings are of the form: NAME=VALUE. - -Note: you *must* use Python 2.1 or later! -""" - - -# This is required path hackery for the win32 binary distribution -# that ensures that the bundled python libraries are used. In a -# win32 binary distribution, the installer will have replaced the -# marker string with the actual software home. If that has not -# happened, then the path munging code is skipped. -swhome=r'INSERT_SOFTWARE_HOME' -if swhome != 'INSERT_SOFTWARE_HOME': - import sys - sys.path.insert(0, '%s/lib/python' % swhome) - sys.path.insert(1, '%s/bin/lib' % swhome) - sys.path.insert(2, '%s/bin/lib/plat-win' % swhome) - sys.path.insert(3, '%s/bin/lib/win32' % swhome) - sys.path.insert(4, '%s/bin/lib/win32/lib' % swhome) - sys.path.insert(5, '%s' % swhome) - - -import os, sys, getopt, codecs, string -import socket - -from types import StringType, IntType -# workaround to allow unicode encoding conversions in DTML -dummy = codecs.lookup('iso-8859-1') - -sys.setcheckinterval(500) - -program=sys.argv[0] -here=os.path.join(os.getcwd(), os.path.split(program)[0]) - -######################################################################## -# Configuration section - -## General configuration options -## - -# This is the IP address of the network interface you want your servers to -# be visible from. This can be changed to '' to listen on all interfaces. -IP_ADDRESS='' - -# IP address of your DNS server. Set to '' if you do not want to resolve -# IP addresses. If you have DNS service on your local machine then you can -# set this to '127.0.0.1' -DNS_IP='' - -# User id to run ZServer as. Note that this only works under Unix, and if -# ZServer is started by root. This no longer defaults to 'nobody' since -# that can lead to a Zope file compromise. -UID=None - -# Log file location. If this is a relative path, then it is joined the -# the 'var' directory. -LOG_FILE='Z2.log' - -## HTTP configuration -## - -# Port for HTTP Server. The standard port for HTTP services is 80. -HTTP_PORT=8080 - -# Port for HTTPS Server. The standard port for HTTPS services is 443. -HTTPS_PORT=8443 - -# HTTP enivornment settings. -HTTP_ENV={} - -# HTTPS enivornment settings. -HTTPS_ENV={} - -# Should we close all HTTP connections, ignoring the (usually absent) -# 'Connection:' header? -FORCE_HTTP_CONNECTION_CLOSE=0 - -# Port for the special "WebDAV source view" HTTP handler. There is no -# standard port for this handler, which is disabled by default. -WEBDAV_SOURCE_PORT=[] - -# Port for the special "WebDAV source view over SSL" HTTP handler. There is no -# standard port for this handler, which is disabled by default. -WEBDAV_SSL_SOURCE_PORT=[] - -# Should we use client X.509 certificate-based authentication? -X509_REMOTE_USER=None - -## FTP configuration - -# Port for the FTP Server. The standard port for FTP services is 21. -FTP_PORT=8021 - -## PCGI configuration - -# You can configure the PCGI server manually, or have it read its -# configuration information from a PCGI info file. -PCGI_FILE='Zope.cgi' - -## Monitor configuration -MONITOR_PORT=0 - -## ICP configuration -ICP_PORT=0 - -# Module to be published, which must be Main or Zope -MODULE='Zope' - -# The size of the thread pool, if ZODB3 is used. -NUMBER_OF_THREADS=4 - -# Localization support -LOCALE_ID=None - -# Socket path or port for the FastCGI Server -FCGI_PORT=None - -# Detailed log file -DETAILED_LOG_FILE='' - -# Use a daemon process -USE_DAEMON = 1 - -# -######################################################################## - -######################################################################## -# Handle command-line arguments: - -def server_info(old, v, offset=0): - # interpret v as a port or address/port and get new value - if v == '-': v='' - l=v.find(':') - if l >= 0: - a=v[:l] - v=v[l+1:] - else: - a=IP_ADDRESS - - if not v: return v - - try: - v=int(v) - if v < 0: raise 'Invalid port', v - v=v+offset - except: raise 'Invalid port', v - - if isinstance(old, IntType): old=[(a,v)] - else: old.append((a,v)) - - return old - - -try: - python_version = sys.version.split()[0] - if python_version < '2.1': - raise 'Invalid python version', python_version - if python_version[:3] == '2.1': - if python_version[4:5] < '3': - import warnings - err = ('You are running Python version %s. This Python version ' - 'has known bugs that may cause Zope to run improperly. ' - 'Consider upgrading to a Python in the 2.1 series ' - 'with at least version number 2.1.3. (Note that Zope does ' - 'not yet run under any Python 2.2 version).' % - python_version) - warnings.warn(err) - if python_version[:3] == '2.2': - import warnings - err = ('You are running Python version %s. This Python version ' - 'has not yet been tested with Zope and you may experience ' - 'operational problems as a result. Consider using ' - 'Python 2.1.3 instead.' % python_version) - warnings.warn(err) - - - opts, args = getopt.getopt(sys.argv[1:], - 'hz:Z:t:i:a:d:u:w:W:y:Y:x:f:p:m:Sl:2DP:rF:L:XM:C', - ['icp=', 'force-http-connection-close' - ]) - - DEBUG=0 - READ_ONLY=0 - if sys.platform == 'win32': - USE_DAEMON = 0 - - - # Get environment variables - for a in args: - if a.find('='): - a=a.split('=') - o=a[0] - v='='.join(a[1:]) - if o: - os.environ[o]=v - HTTP_ENV[o]=v - else: - raise 'Invalid argument', a - - for o, v in opts: - if o=='-z': here=v - elif o=='-Z': - if v in ('-', '0', ''): - USE_DAEMON=0 - elif sys.platform != 'win32': - USE_DAEMON = 1 - elif o=='-r': READ_ONLY=1 - elif o=='-t': - try: v=int(v) - except: raise 'Invalid number of threads', v - NUMBER_OF_THREADS=v - - elif o=='-i': - try: v=int(v) - except: raise 'Invalid value for -i option', v - sys.setcheckinterval(v) - - elif o=='-a': IP_ADDRESS=v - elif o=='-d': - if v=='-': v='' - DNS_IP=v - elif o=='-u': UID=v - elif o=='-D': - os.environ['Z_DEBUG_MODE']='1' - DEBUG=1 - elif o=='-S': sys.ZMANAGED=1 - elif o=='-X': - MONITOR_PORT=HTTP_PORT=FTP_PORT=FCGI_PORT=ICP_PORT=0 - WEBDAV_SOURCE_PORT=0 - PCGI_FILE='' - elif o=='-m': - MONITOR_PORT=server_info(MONITOR_PORT, v) - elif o=='-w': - HTTP_PORT=server_info(HTTP_PORT, v) - elif o=='-y': - HTTPS_PORT=server_info(HTTPS_PORT, v) - elif o=='-C' or o=='--force-http-connection-close': - FORCE_HTTP_CONNECTION_CLOSE=1 - elif o=='-W': - WEBDAV_SOURCE_PORT=server_info(WEBDAV_SOURCE_PORT, v) - elif o=='-Y': - WEBDAV_SSL_SOURCE_PORT=server_info(WEBDAV_SSL_SOURCE_PORT, v) - elif o=='-x': - if v in ('-', '0', ''): - X509_REMOTE_USER=None - else: - X509_REMOTE_USER=1 - elif o=='-f': - FTP_PORT=server_info(FTP_PORT, v) - elif o=='-P': - HTTP_PORT=server_info(HTTP_PORT, v, 80) - FTP_PORT=server_info(FTP_PORT, v, 21) - elif o=='--icp': - ICP_PORT=server_info(ICP_PORT, v) - - elif o=='-p': - if v=='-': v='' - PCGI_FILE=v - elif o=='-h': - print __doc__ % vars() - sys.exit(0) - elif o=='-2': MODULE='Main' - elif o=='-l': LOG_FILE=v - elif o=='-L': - if v: LOCALE_ID=v - else: LOCALE_ID='' - elif o=='-F': - if v=='-': v='' - FCGI_PORT=v - elif o=='-M': DETAILED_LOG_FILE=v - -except SystemExit: sys.exit(0) -except: - print __doc__ % vars() - print - print 'Error:' - print "%s: %s" % (sys.exc_type, sys.exc_value) - sys.exit(1) - -# -######################################################################## - -######################################################################## -# OK, let's get going! - -# Jigger path: -sys.path=[os.path.join(here,'lib','python'),here - ]+filter(None, sys.path) - - - -# Try to set the locale if specified on the command -# line. If the locale module is not available or the -# requested locale is not supported by the local -# machine, raise an error so that the user is made -# aware of the problem. - -def set_locale(val): - try: - import locale - except: - raise SystemExit, ( - 'The locale module could not be imported.\n' - 'To use localization options, you must ensure\n' - 'that the locale module is compiled into your\n' - 'Python installation.' - ) - try: - locale.setlocale(locale.LC_ALL, val) - except: - raise SystemExit, ( - 'The specified locale is not supported by your system.\n' - 'See your operating system documentation for more\n' - 'information on locale support.' - ) -if LOCALE_ID is not None: - set_locale(LOCALE_ID) - -import zdaemon -# from this point forward we can use the zope logger -# importing ZDaemon before importing ZServer causes ZServer logging -# not to work. - -# Import ZServer before we open the database or get at interesting -# application code so that ZServer's asyncore gets to be the -# official one. Also gets SOFTWARE_HOME, INSTANCE_HOME, and CLIENT_HOME -import ZServer - -# install signal handlers if on posix -if os.name == 'posix': - from Signals import Signals - Signals.registerZopeSignals() - -# Location of the ZServer pid file. When Zope starts up it will write -# its PID to this file. If Zope is run under zdaemon control, zdaemon -# will write to this pidfile instead of Zope. -PID_FILE=os.path.join(CLIENT_HOME, 'Z2.pid') - -if USE_DAEMON and not READ_ONLY: - import App.FindHomes - sys.ZMANAGED=1 - # zdaemon.run creates a process which "manages" the actual Zope - # process (restarts it if it dies). The management process passes along - # signals that it receives to its child. - zdaemon.run(sys.argv, os.path.join(CLIENT_HOME, PID_FILE)) - -os.chdir(CLIENT_HOME) - -def _warn_nobody(): - zLOG.LOG("z2", zLOG.INFO, ("Running Zope as 'nobody' can compromise " - "your Zope files; consider using a " - "dedicated user account for Zope") ) - -try: - # Import logging support - import zLOG - import ZLogger - - if READ_ONLY: - if hasattr(zLOG, '_set_stupid_dest'): - zLOG._set_stupid_dest(sys.stderr) - else: - zLOG._stupid_dest = sys.stderr - else: - zLOG.log_write = ZLogger.ZLogger.log_write - - if DETAILED_LOG_FILE: - from ZServer import DebugLogger - logfile=os.path.join(CLIENT_HOME, DETAILED_LOG_FILE) - zLOG.LOG('z2', zLOG.BLATHER, - 'Using detailed request log file %s' % logfile) - DL=DebugLogger.DebugLogger(logfile) - DebugLogger.log=DL.log - DebugLogger.reopen=DL.reopen - sys.__detailedlog=DL - - # Import Zope (or Main) - if MODULE == 'Zope': - import Zope - Zope.startup() - else: - exec "import "+MODULE in {} - - # Location of the ZServer log file. This file logs all ZServer activity. - # You may wish to create different logs for different servers. See - # medusa/logger.py for more information. - if not os.path.isabs(LOG_FILE): - LOG_PATH=os.path.join(CLIENT_HOME, LOG_FILE) - else: - LOG_PATH=LOG_FILE - - # import ZServer stuff - - # First, we need to increase the number of threads - if MODULE=='Zope': - from ZServer import setNumberOfThreads - setNumberOfThreads(NUMBER_OF_THREADS) - - from ZServer import resolver, logger, asyncore - - from ZServer import zhttp_server, zhttp_handler - from ZServer import zhttps_server, zhttps0_handler, zhttps_handler - from ZServer.WebDAVSrcHandler import WebDAVSrcHandler - from ZServer import PCGIServer,FTPServer,FCGIServer - - from ZServer import secure_monitor_server - - from M2Crypto import SSL, Rand - - ## ZServer startup - ## - - ## In X509_REMOTE_USER mode, we log the client cert's subject DN. - if X509_REMOTE_USER: - - import base64, string, time - - def log (self, bytes): - user_agent=self.get_header('user-agent') - if not user_agent: user_agent='' - referer=self.get_header('referer') - if not referer: referer='' - - get_peer_cert = getattr(self.channel, 'get_peer_cert', None) - if get_peer_cert is not None: - name = str(get_peer_cert().get_subject()) - else: - name = 'Anonymous' - auth=self.get_header('Authorization') - if auth is not None: - if string.lower(auth[:6]) == 'basic ': - try: decoded=base64.decodestring(auth[6:]) - except base64.binascii.Error: decoded='' - t = string.split(decoded, ':', 1) - if len(t) < 2: - name = 'Unknown (bad auth string)' - else: - name = t[0] - - self.channel.server.logger.log ( - self.channel.addr[0], - ' - %s [%s] "%s" %d %d "%s" "%s"\n' % ( - name, - self.log_date_string (time.time()), - self.request, - self.reply_code, - bytes, - referer, - user_agent - ) - ) - - from ZServer.medusa import http_server - http_server.http_request.log = log - - # Resolver and Logger, used by other servers - if DNS_IP: - rs = resolver.caching_resolver(DNS_IP) - else: - rs=None - - if READ_ONLY: - lg = logger.file_logger('-') # log to stdout - zLOG.LOG('z2', zLOG.BLATHER, 'Logging access log to stdout') - elif os.environ.has_key('ZSYSLOG_ACCESS'): - if os.environ.has_key("ZSYSLOG_ACCESS_FACILITY"): - lg = logger.syslog_logger( - os.environ['ZSYSLOG_ACCESS'], - facility=os.environ['ZSYSLOG_ACCESS_FACILITY']) - else: - lg = logger.syslog_logger(os.environ['ZSYSLOG_ACCESS']) - zLOG.LOG('z2', zLOG.BLATHER, 'Using local syslog access log') - elif os.environ.has_key('ZSYSLOG_ACCESS_SERVER'): - (addr, port) = os.environ['ZSYSLOG_ACCESS_SERVER'].split( ':') - lg = logger.syslog_logger((addr, int(port))) - zLOG.LOG('z2', zLOG.BLATHER, 'Using remote syslog access log') - else: - lg = logger.file_logger(LOG_PATH) - zLOG.LOG('z2', zLOG.BLATHER, 'Using access log file %s' % LOG_PATH) - sys.__lg = lg - - port_err=('\n\nZope wants to use %(socktype)s port %(port)s for its ' - '%(protocol)s service, but it is already in use by another ' - 'application on this machine. Either shut the application down ' - 'which is using this port, or start Zope with a different ' - '%(protocol)s port via the "%(switch)s" command-line switch.\n') - - # HTTP Server - if HTTP_PORT: - if isinstance(HTTP_PORT, IntType): HTTP_PORT=((IP_ADDRESS, HTTP_PORT),) - for address, port in HTTP_PORT: - try: - hs = zhttp_server( - ip=address, - port=port, - resolver=rs, - logger_object=lg) - except socket.error, why: - if why[0] == 98: # address in use - raise port_err % {'port':port, - 'socktype':'TCP', - 'protocol':'HTTP', - 'switch':'-w'} - raise - # Handler for a published module. zhttp_handler takes 3 arguments: - # The name of the module to publish, and optionally the URI base - # which is basically the SCRIPT_NAME, and optionally a dictionary - # with CGI environment variables which override default - # settings. The URI base setting is useful when you want to - # publish more than one module with the same HTTP server. The CGI - # environment setting is useful when you want to proxy requests - # from another web server to ZServer, and would like the CGI - # environment to reflect the CGI environment of the other web - # server. - try: - del HTTP_ENV['HTTPS'] - except KeyError: - pass - zh = zhttp_handler(MODULE, '', HTTP_ENV) - if FORCE_HTTP_CONNECTION_CLOSE: - zh._force_connection_close = 1 - hs.install_handler(zh) - - # HTTPS Server - if HTTPS_PORT: - ssl_ctx = SSL.Context('sslv23') - ssl_ctx.load_cert_chain('%s/server.pem' % INSTANCE_HOME) - ssl_ctx.load_verify_locations('%s/ca.pem' % INSTANCE_HOME) - ssl_ctx.load_client_CA('%s/ca.pem' % INSTANCE_HOME) - #ssl_ctx.set_allow_unknown_ca(1) - ssl_ctx.set_session_id_ctx(MODULE) - ssl_ctx.set_tmp_dh('%s/dh1024.pem' % INSTANCE_HOME) - if X509_REMOTE_USER: - ssl_ctx.set_verify(SSL.verify_peer, 10) - else: - ssl_ctx.set_verify(SSL.verify_none, 10) - if type(HTTPS_PORT) is type(0): HTTPS_PORT=((IP_ADDRESS, HTTPS_PORT),) - - for address, port in HTTPS_PORT: - hss = zhttps_server( - ip=address, - port=port, - ssl_ctx=ssl_ctx, - resolver=rs, - logger_object=lg) - - try: - del HTTPS_ENV['HTTP'] - except KeyError: - pass - HTTPS_ENV['HTTPS']='ON' - - if X509_REMOTE_USER: - zsh = zhttps_handler(MODULE, '', HTTPS_ENV) - else: - zsh = zhttps0_handler(MODULE, '', HTTPS_ENV) - hss.install_handler(zsh) - - # WebDAV source Server (runs HTTP, but munges request to return - # 'manage_FTPget'). - if WEBDAV_SOURCE_PORT: - if isinstance(WEBDAV_SOURCE_PORT, IntType): - WEBDAV_SOURCE_PORT=((IP_ADDRESS, WEBDAV_SOURCE_PORT),) - for address, port in WEBDAV_SOURCE_PORT: - try: - hs = zhttp_server( - ip=address, - port=port, - resolver=rs, - logger_object=lg) - except socket.error, why: - if why[0] == 98: # address in use - raise port_err % {'port':port, - 'socktype':'TCP', - 'protocol':'WebDAV source', - 'switch':'-W'} - raise - - # Handler for a published module. zhttp_handler takes 3 arguments: - # The name of the module to publish, and optionally the URI base - # which is basically the SCRIPT_NAME, and optionally a dictionary - # with CGI environment variables which override default - # settings. The URI base setting is useful when you want to - # publish more than one module with the same HTTP server. The CGI - # environment setting is useful when you want to proxy requests - # from another web server to ZServer, and would like the CGI - # environment to reflect the CGI environment of the other web - # server. - zh = WebDAVSrcHandler(MODULE, '', HTTP_ENV) - hs.install_handler(zh) - - # enable document retrieval of the document source on the - # standard HTTP port - - clients = os.environ.get('WEBDAV_SOURCE_PORT_CLIENTS') - if clients: - import re - sys.WEBDAV_SOURCE_PORT_CLIENTS = re.compile(clients).search - else: - sys.WEBDAV_SOURCE_PORT_CLIENTS = None - - # WebDAV-over-SSL source Server (runs HTTPS, but munges request to return - # 'manage_FTPget'). - if WEBDAV_SSL_SOURCE_PORT: - ssl_ctx = SSL.Context('sslv23') - ssl_ctx.load_cert_chain('%s/server.pem' % INSTANCE_HOME) - ssl_ctx.load_verify_locations('%s/ca.pem' % INSTANCE_HOME) - ssl_ctx.load_client_CA('%s/ca.pem' % INSTANCE_HOME) - ssl_ctx.set_verify(SSL.verify_none, 10) - ssl_ctx.set_session_id_ctx(MODULE) - ssl_ctx.set_tmp_dh('%s/dh1024.pem' % INSTANCE_HOME) - if type(WEBDAV_SSL_SOURCE_PORT) is type(0): - WEBDAV_SSL_SOURCE_PORT=((IP_ADDRESS, WEBDAV_SSL_SOURCE_PORT),) - for address, port in WEBDAV_SSL_SOURCE_PORT: - hss = zhttps_server( - ip=address, - port=port, - ssl_ctx=ssl_ctx, - resolver=rs, - logger_object=lg) - - try: - del HTTPS_ENV['HTTP'] - except KeyError: - pass - HTTPS_ENV['HTTPS']='ON' - - zsh = WebDAVSrcHandler(MODULE, '', HTTPS_ENV) - hss.install_handler(zsh) - - # FTP Server - if FTP_PORT: - if isinstance(FTP_PORT, IntType): FTP_PORT=((IP_ADDRESS, FTP_PORT),) - for address, port in FTP_PORT: - try: - FTPServer( - module=MODULE, - ip=address, - port=port, - resolver=rs, - logger_object=lg) - except socket.error, why: - if why[0] == 98: # address in use - raise port_err % {'port':port, - 'socktype':'TCP', - 'protocol':'FTP', - 'switch':'-f'} - raise - - # PCGI Server - if PCGI_FILE and not READ_ONLY: - PCGI_FILE=os.path.join(here, PCGI_FILE) - if os.path.exists(PCGI_FILE): - zpcgi = PCGIServer( - module=MODULE, - ip=IP_ADDRESS, - pcgi_file=PCGI_FILE, - resolver=rs, - logger_object=lg) - - - # FastCGI Server - if FCGI_PORT and not READ_ONLY: - fcgiPort = None - fcgiPath = None - try: - fcgiPort = int(FCGI_PORT) - except ValueError: - fcgiPath = FCGI_PORT - try: - zfcgi = FCGIServer(module=MODULE, - ip=IP_ADDRESS, - port=fcgiPort, - socket_file=fcgiPath, - resolver=rs, - logger_object=lg) - except socket.error, why: - if why[0] == 98: # address in use - raise port_err % {'port':fcgiPort, - 'socktype':'TCP', - 'protocol':'FastCGI', - 'switch':'-F'} - raise - - - # Monitor Server - if MONITOR_PORT: - from AccessControl.User import emergency_user - if not hasattr(emergency_user, '__null_user__'): - pw = emergency_user._getPassword() - else: - pw = None - zLOG.LOG("z2", zLOG.WARNING, 'Monitor server not started' - ' because no emergency user exists.') - if pw: - if isinstance(MONITOR_PORT, IntType): - MONITOR_PORT=((IP_ADDRESS, MONITOR_PORT),) - for address, port in MONITOR_PORT: - try: - monitor=secure_monitor_server( - password=pw, - hostname=address, - port=port) - except socket.error, why: - if why[0] == 98: # address in use - raise port_err % {'port':port, - 'socktype':'TCP', - 'protocol':'monitor server', - 'switch':'-m'} - raise - - if ICP_PORT: - if isinstance(ICP_PORT, IntType): ICP_PORT=((IP_ADDRESS, ICP_PORT),) - from ZServer.ICPServer import ICPServer - for address, port in ICP_PORT: - try: - ICPServer(address,port) - except socket.error, why: - if why[0] == 98: # address in use - raise port_err % {'port':port, - 'socktype':'UDP', - 'protocol':'ICP', - 'switch':'--icp'} - raise - - if not USE_DAEMON and not READ_ONLY: - if os.path.exists(PID_FILE): os.unlink(PID_FILE) - pf = open(PID_FILE, 'w') - pid='%s\n' % os.getpid() - pf.write(pid) - pf.close() - - # Warn if we were started as nobody. - try: - import pwd - if os.getuid(): - if pwd.getpwuid(os.getuid())[0] == 'nobody': - _warn_nobody() - except: - pass - - # Drop root privileges if we have them, and do some sanity checking - # to make sure we're not starting with an obviously insecure setup. - try: - if os.getuid() == 0: - try: - import initgroups - except: - raise SystemExit, 'initgroups is required to safely setuid' - if UID == None: - raise SystemExit, ('A user was not specified to setuid ' - 'to; fix this to start as root (see ' - 'doc/SETUID.txt)') - import stat - client_home_stat = os.stat(CLIENT_HOME) - client_home_faults = [] - if not (client_home_stat[stat.ST_MODE]&01000): - client_home_faults.append('does not have the sticky bit set') - if client_home_stat[stat.ST_UID] != 0: - client_home_faults.append('is not owned by root') - if client_home_faults: - client_home_faults.append('fix this to start as root (see ' - 'doc/SETUID.txt)') - err = '%s %s' % (CLIENT_HOME, ', '.join(client_home_faults)) - raise SystemExit, err - - try: - try: UID = string.atoi(UID) - except: pass - gid = None - if isinstance(UID, StringType): - uid = pwd.getpwnam(UID)[2] - gid = pwd.getpwnam(UID)[3] - elif isinstance(UID, IntType): - uid = pwd.getpwuid(UID)[2] - gid = pwd.getpwuid(UID)[3] - UID = pwd.getpwuid(UID)[0] - else: - raise KeyError - if UID == 'nobody': - _warn_nobody() - try: - initgroups.initgroups(UID, gid) - if gid is not None: - try: - os.setgid(gid) - except OSError: - pass - os.setuid(uid) - except OSError: - pass - except KeyError: - zLOG.LOG("z2", zLOG.ERROR, ("Can't find UID %s" % UID)) - except AttributeError: - pass - except: - raise - - # Check umask sanity if we're on posix. - if os.name == 'posix' and not os.environ.get('Z_DEBUG_MODE'): - # umask is silly, blame POSIX. We have to set it to get its value. - current_umask = os.umask(0) - os.umask(current_umask) - if current_umask != 077: - current_umask = '%03o' % current_umask - zLOG.LOG("z2", zLOG.INFO, ( - 'Your umask of %s may be too permissive; for the security of ' - 'your Zope data, it is recommended you use 077' % current_umask - )) - -except: - # Log startup exception and tell zdaemon not to restart us. - try: - zLOG.LOG("z2", zLOG.PANIC, "Startup exception", - error=sys.exc_info()) - except: pass - sys.exit(0) - -# Start Medusa, Ye Hass! -Rand.load_file('%s/randpool.dat' % INSTANCE_HOME, -1) -sys.ZServerExitCode=0 -asyncore.loop() -Rand.save_file('%s/randpool.dat' % INSTANCE_HOME) -sys.exit(sys.ZServerExitCode) diff --git a/demo/Zope/z2s.py.diff b/demo/Zope/z2s.py.diff deleted file mode 100644 index f79cd94..0000000 --- a/demo/Zope/z2s.py.diff +++ /dev/null @@ -1,266 +0,0 @@ ---- z2s.py Sun Oct 26 17:51:00 2003 -+++ /usr/local/home/ngps/pkg/zope261/z2.py Thu Jan 30 22:41:42 2003 -@@ -105,21 +105,9 @@ - - Multiple -w options can be provided to run multiple servers. - -- -y port -- -- The SSL Web server (HTTPS) port. This defaults to %(HTTPS_PORT)s. The -- standard port for HTTPS services is 443. If this is a dash -- (e.g. -y -), then HTTPS is disabled. -- -- The number can be preeceeded by an ip address follwed by a colon -- to specify an address to listen on. This allows different servers -- to listen on different addresses. -- -- Multiple -y options can be provided to run multiple servers. -- - -W port - -- The "WebDAV source" port. If this is a dash (e.g. -W -), then -+ The "WebDAV source" port. If this is a dash (e.g. -w -), then - "WebDAV source" is disabled. The default is disabled. Note that - this feature is a workaround for the lack of "source-link" support - in standard WebDAV clients. -@@ -130,24 +118,6 @@ - - Multiple -W options can be provided to run multiple servers. - -- -Y port -- -- The "WebDAV source over HTTPS" port. If this is a dash (e.g. -Y -), then -- "WebDAV source over HTTPS" is disabled. The default is disabled. Note that -- this feature is a workaround for the lack of "source-link" support -- in standard WebDAV clients. -- -- The port can be preeceeded by an ip address follwed by a colon -- to specify an address to listen on. This allows different servers -- to listen on different addresses. -- -- Multiple -Y options can be provided to run multiple servers. -- -- -x -- -- If present, this option causes Zope to run in X.509 certificate-based -- authentication mode. -- - -C - --force-http-connection-close - -@@ -316,15 +286,9 @@ - # Port for HTTP Server. The standard port for HTTP services is 80. - HTTP_PORT=8080 - --# Port for HTTPS Server. The standard port for HTTPS services is 443. --HTTPS_PORT=8443 -- - # HTTP enivornment settings. - HTTP_ENV={} - --# HTTPS enivornment settings. --HTTPS_ENV={} -- - # Should we close all HTTP connections, ignoring the (usually absent) - # 'Connection:' header? - FORCE_HTTP_CONNECTION_CLOSE=0 -@@ -333,13 +297,6 @@ - # standard port for this handler, which is disabled by default. - WEBDAV_SOURCE_PORT=[] - --# Port for the special "WebDAV source view over SSL" HTTP handler. There is no --# standard port for this handler, which is disabled by default. --WEBDAV_SSL_SOURCE_PORT=[] -- --# Should we use client X.509 certificate-based authentication? --X509_REMOTE_USER=None -- - ## FTP configuration - - # Port for the FTP Server. The standard port for FTP services is 21. -@@ -429,7 +386,7 @@ - - - opts, args = getopt.getopt(sys.argv[1:], -- 'hz:Z:t:i:a:d:u:w:W:y:Y:x:f:p:m:Sl:2DP:rF:L:XM:C', -+ 'hz:Z:t:i:a:d:u:w:W:f:p:m:Sl:2DP:rF:L:XM:C', - ['icp=', 'force-http-connection-close' - ]) - -@@ -486,19 +443,10 @@ - MONITOR_PORT=server_info(MONITOR_PORT, v) - elif o=='-w': - HTTP_PORT=server_info(HTTP_PORT, v) -- elif o=='-y': -- HTTPS_PORT=server_info(HTTPS_PORT, v) - elif o=='-C' or o=='--force-http-connection-close': - FORCE_HTTP_CONNECTION_CLOSE=1 - elif o=='-W': - WEBDAV_SOURCE_PORT=server_info(WEBDAV_SOURCE_PORT, v) -- elif o=='-Y': -- WEBDAV_SSL_SOURCE_PORT=server_info(WEBDAV_SSL_SOURCE_PORT, v) -- elif o=='-x': -- if v in ('-', '0', ''): -- X509_REMOTE_USER=None -- else: -- X509_REMOTE_USER=1 - elif o=='-f': - FTP_PORT=server_info(FTP_PORT, v) - elif o=='-P': -@@ -653,60 +601,14 @@ - from ZServer import resolver, logger, asyncore - - from ZServer import zhttp_server, zhttp_handler -- from ZServer import zhttps_server, zhttps0_handler, zhttps_handler - from ZServer.WebDAVSrcHandler import WebDAVSrcHandler - from ZServer import PCGIServer,FTPServer,FCGIServer - - from ZServer import secure_monitor_server - -- from M2Crypto import SSL, Rand -- - ## ZServer startup - ## - -- ## In X509_REMOTE_USER mode, we log the client cert's subject DN. -- if X509_REMOTE_USER: -- -- import base64, string, time -- -- def log (self, bytes): -- user_agent=self.get_header('user-agent') -- if not user_agent: user_agent='' -- referer=self.get_header('referer') -- if not referer: referer='' -- -- get_peer_cert = getattr(self.channel, 'get_peer_cert', None) -- if get_peer_cert is not None: -- name = str(get_peer_cert().get_subject()) -- else: -- name = 'Anonymous' -- auth=self.get_header('Authorization') -- if auth is not None: -- if string.lower(auth[:6]) == 'basic ': -- try: decoded=base64.decodestring(auth[6:]) -- except base64.binascii.Error: decoded='' -- t = string.split(decoded, ':', 1) -- if len(t) < 2: -- name = 'Unknown (bad auth string)' -- else: -- name = t[0] -- -- self.channel.server.logger.log ( -- self.channel.addr[0], -- ' - %s [%s] "%s" %d %d "%s" "%s"\n' % ( -- name, -- self.log_date_string (time.time()), -- self.request, -- self.reply_code, -- bytes, -- referer, -- user_agent -- ) -- ) -- -- from ZServer.medusa import http_server -- http_server.http_request.log = log -- - # Resolver and Logger, used by other servers - if DNS_IP: - rs = resolver.caching_resolver(DNS_IP) -@@ -766,51 +668,11 @@ - # from another web server to ZServer, and would like the CGI - # environment to reflect the CGI environment of the other web - # server. -- try: -- del HTTP_ENV['HTTPS'] -- except KeyError: -- pass - zh = zhttp_handler(MODULE, '', HTTP_ENV) - if FORCE_HTTP_CONNECTION_CLOSE: - zh._force_connection_close = 1 - hs.install_handler(zh) - -- # HTTPS Server -- if HTTPS_PORT: -- ssl_ctx = SSL.Context('sslv23') -- ssl_ctx.load_cert_chain('%s/server.pem' % INSTANCE_HOME) -- ssl_ctx.load_verify_locations('%s/ca.pem' % INSTANCE_HOME) -- ssl_ctx.load_client_CA('%s/ca.pem' % INSTANCE_HOME) -- #ssl_ctx.set_allow_unknown_ca(1) -- ssl_ctx.set_session_id_ctx(MODULE) -- ssl_ctx.set_tmp_dh('%s/dh1024.pem' % INSTANCE_HOME) -- if X509_REMOTE_USER: -- ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) -- #ssl_ctx.set_verify(SSL.verify_peer, 10) -- else: -- ssl_ctx.set_verify(SSL.verify_none, 10) -- if type(HTTPS_PORT) is type(0): HTTPS_PORT=((IP_ADDRESS, HTTPS_PORT),) -- -- for address, port in HTTPS_PORT: -- hss = zhttps_server( -- ip=address, -- port=port, -- ssl_ctx=ssl_ctx, -- resolver=rs, -- logger_object=lg) -- -- try: -- del HTTPS_ENV['HTTP'] -- except KeyError: -- pass -- HTTPS_ENV['HTTPS']='ON' -- -- if X509_REMOTE_USER: -- zsh = zhttps_handler(MODULE, '', HTTPS_ENV) -- else: -- zsh = zhttps0_handler(MODULE, '', HTTPS_ENV) -- hss.install_handler(zsh) -- - # WebDAV source Server (runs HTTP, but munges request to return - # 'manage_FTPget'). - if WEBDAV_SOURCE_PORT: -@@ -854,34 +716,6 @@ - else: - sys.WEBDAV_SOURCE_PORT_CLIENTS = None - -- # WebDAV-over-SSL source Server (runs HTTPS, but munges request to return -- # 'manage_FTPget'). -- if WEBDAV_SSL_SOURCE_PORT: -- ssl_ctx = SSL.Context('sslv23') -- ssl_ctx.load_cert_chain('%s/server.pem' % INSTANCE_HOME) -- ssl_ctx.load_verify_locations('%s/ca.pem' % INSTANCE_HOME) -- ssl_ctx.load_client_CA('%s/ca.pem' % INSTANCE_HOME) -- ssl_ctx.set_verify(SSL.verify_none, 10) -- ssl_ctx.set_session_id_ctx(MODULE) -- ssl_ctx.set_tmp_dh('%s/dh1024.pem' % INSTANCE_HOME) -- if type(WEBDAV_SSL_SOURCE_PORT) is type(0): -- WEBDAV_SSL_SOURCE_PORT=((IP_ADDRESS, WEBDAV_SSL_SOURCE_PORT),) -- for address, port in WEBDAV_SSL_SOURCE_PORT: -- hss = zhttps_server( -- ip=address, -- port=port, -- ssl_ctx=ssl_ctx, -- resolver=rs, -- logger_object=lg) -- -- try: -- del HTTPS_ENV['HTTP'] -- except KeyError: -- pass -- HTTPS_ENV['HTTPS']='ON' -- -- zsh = WebDAVSrcHandler(MODULE, '', HTTPS_ENV) -- hss.install_handler(zsh) - - # FTP Server - if FTP_PORT: -@@ -1072,8 +906,6 @@ - sys.exit(0) - - # Start Medusa, Ye Hass! --Rand.load_file('%s/randpool.dat' % INSTANCE_HOME, -1) - sys.ZServerExitCode=0 - asyncore.loop() --Rand.save_file('%s/randpool.dat' % INSTANCE_HOME) - sys.exit(sys.ZServerExitCode) diff --git a/demo/Zope27/INSTALL.txt b/demo/Zope27/INSTALL.txt deleted file mode 100644 index b3728c5..0000000 --- a/demo/Zope27/INSTALL.txt +++ /dev/null @@ -1,200 +0,0 @@ -========================================= - ZServerSSL for Zope 2.7.0b2 -========================================= - -:Author: Ng Pheng Siong -:Id: $Id$ -:Date: $Date$ -:Web-Site: http://sandbox.rulemaker.net/ngps/zope/zssl/ - -.. contents:: - - -Directories ------------------------ - -This distribution is contained in ``m2crypto-0.12/demo/Zope27/``. Its -directory structure assumes the following: - -- Zope 2.7.0b2 is installed in . -- An instance has been created in . - - - ------------------------ - -The following files are to be copied to the corresponding directories -in your : - -- install_dir/lib/python/ZServer/HTTPS_Server.py -- install_dir/lib/python/ZServer/medusa/https_server.py - -The following patch files are to be applied to the corresponding -directories in your : - -- install_dir/lib/python/ZServer/__init__.py.patch -- install_dir/lib/python/ZServer/component.xml.patch -- install_dir/lib/python/ZServer/datatypes.py.patch - - - ------------------------ - -The following files are to be copied to the corresponding directories -in your : - -- instance_home/ssl/ca.pem -- instance_home/ssl/server.pem -- instance_home/ssl/dh1024.pem - -These are example files. For more information on them, consult the -ZServerSSL HOWTO for Zope 2.6. - -The following patch files are to be applied to the corresponding -directories in your : - -- instance_home/README.txt.patch -- instance_home/etc/zope.conf.patch - -(Patching README.txt is optional.) - -There appears to be a bug in Zope 2.7.0b2, where INSTANCE_HOME in a -running Zope points to , not . Workaround -this with the following: - -:: - - $ (cd ; ln -s /ssl) - - -Launch ZServerSSL -------------------- - -:: - - $ /bin/runzope - - -Testing ---------- - -Below, we assume your Zope server is running on ``localhost``. - - -HTTPS -~~~~~~~ - -This testing is done with Mozilla 1.1 on FreeBSD. - -1. With a browser, connect to https://localhost:8443/. Browse - around. Check out your browser's HTTPS informational screens. - -2. Connect to https://localhost:8443/manage. Verify that you can - access Zope's management functionality. - - -WebDAV-over-HTTPS -~~~~~~~~~~~~~~~~~~~ - -This testing is done with Cadaver 0.21.0 on FreeBSD. - -:: - - $ cadaver https://localhost:8443/ - WARNING: Untrusted server certificate presented: - Issued to: M2Crypto, SG - Issued by: M2Crypto, SG - Do you wish to accept the certificate? (y/n) y - Authentication required for Zope on server `localhost': - Username: admin - Password: - dav:/> ls - Listing collection `/': succeeded. - Coll: Control_Panel 0 Sep 28 00:38 - Coll: temp_folder 0 Sep 28 17:30 - acl_users 0 Sep 28 00:38 - browser_id_manager 0 Sep 28 00:38 - error_log 0 Sep 28 00:38 - index_html 28 Sep 28 00:39 - session_data_manager 0 Sep 28 00:38 - standard_error_message 1189 Sep 28 00:39 - standard_html_footer 18 Sep 28 00:39 - standard_html_header 82 Sep 28 00:39 - standard_template.pt 282 Sep 28 00:39 - dav:/> quit - Connection to `localhost' closed. - $ - - -Python with M2Crypto -~~~~~~~~~~~~~~~~~~~~~~ - -This testing is done with M2Crypto 0.12 and Python 2.2.3 on FreeBSD. - -HTTPS -``````` - ->>> from M2Crypto import Rand, SSL, m2urllib ->>> url = m2urllib.FancyURLopener() ->>> url.addheader('Connection', 'close') ->>> u = url.open('https://127.0.0.1:8443/') -send: 'GET / HTTP/1.1\r\nHost: 127.0.0.1:8443\r\nAccept-Encoding: identity\r\nUser-agent: Python-urllib/1.15\r\nConnection: close\r\n\r\n' -reply: 'HTTP/1.1 200 OK\r\n' -header: Server: ZServerSSL/0.12 -header: Date: Sun, 28 Sep 2003 09:40:14 GMT -header: Content-Length: 3055 -header: Etag: -header: Content-Type: text/html -header: Connection: close ->>> while 1: -... data = u.read() -... if not data: break -... print data -... - -:: - - [blah blah blah] - -

- Go directly to the - Zope Management Interface if you'd like to start working with Zope - right away. NOTE: Some versions of Microsoft Internet Explorer, - (specifically IE 5.01 and early versions of IE 5.5) may have problems - displaying Zope management pages. If you cannot view the management pages, - try upgrading your IE installation to the latest release version, or use - a different browser. -

- - -
  • -

    - Find out about Zope - Corporation, the publishers of Zope. -

    -
  • - - - - - - ->>> u.close() ->>> - - -XMLRPC-over-HTTPS -``````````````````` - ->>> from M2Crypto.m2xmlrpclib import Server, SSL_Transport ->>> zs = Server('https://127.0.0.1:8443/', SSL_Transport()) ->>> print zs.propertyMap() -[{'type': 'string', 'id': 'title', 'mode': 'w'}] ->>> - - -Conclusion ------------- - -Yes, it works! ;-) - diff --git a/demo/Zope27/install_dir/lib/python/ZServer/HTTPS_Server.py b/demo/Zope27/install_dir/lib/python/ZServer/HTTPS_Server.py deleted file mode 100644 index 49b6177..0000000 --- a/demo/Zope27/install_dir/lib/python/ZServer/HTTPS_Server.py +++ /dev/null @@ -1,187 +0,0 @@ -############################################################################## -# -# Copyright (c) 2000-2003, Ng Pheng Siong. All Rights Reserved. -# This file is derived from Zope's ZServer/HTTPServer.py. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE -# -############################################################################## - -""" -Medusa HTTPS server for Zope - -changes from Medusa's http_server: - - Request Threads -- Requests are processed by threads from a thread - pool. - - Output Handling -- Output is pushed directly into the producer - fifo by the request-handling thread. The HTTP server does not do - any post-processing such as chunking. - - Pipelineable -- This is needed for protocols such as HTTP/1.1 in - which mutiple requests come in on the same channel, before - responses are sent back. When requests are pipelined, the client - doesn't wait for the response before sending another request. The - server must ensure that responses are sent back in the same order - as requests are received. - - -changes from Zope's HTTP server: - - Well, this is a *HTTPS* server :) - - X.509 certificate-based authentication -- When this is in force, - zhttps_handler, a subclass of zhttp_handler, is installed. The - https server is configured to request an X.509 certificate from - the client. When the request reaches zhttps_handler, it sets - REMOTE_USER to the client's subject distinguished name (DN) from - the certificate. Zope's REMOTE_USER machinery takes care of the - rest, e.g., in conjunction with the RemoteUserFolder product. - -""" - -import sys, time, types - -from PubCore import handle -import asyncore -from ZServer import CONNECTION_LIMIT, ZOPE_VERSION -from HTTPServer import zhttp_handler -from zLOG import register_subsystem - -from M2Crypto import SSL -from medusa.https_server import https_server, https_channel -from asyncore import dispatcher - - -ZSERVER_SSL_VERSION='0.12' - -register_subsystem('ZServer HTTPS_Server') - - -class zhttps0_handler(zhttp_handler): - "zhttps0 handler - sets SSL request headers a la mod_ssl" - - def __init__ (self, module, uri_base=None, env=None): - zhttp_handler.__init__(self, module, uri_base, env) - - def get_environment(self, request): - env = zhttp_handler.get_environment(self, request) - env['SSL_CIPHER'] = request.channel.get_cipher() - return env - - -class zhttps_handler(zhttps0_handler): - "zhttps handler - sets REMOTE_USER to user's X.509 certificate Subject DN" - - def __init__ (self, module, uri_base=None, env=None): - zhttps0_handler.__init__(self, module, uri_base, env) - - def get_environment(self, request): - env = zhttps0_handler.get_environment(self, request) - peer = request.channel.get_peer_cert() - if peer is not None: - env['REMOTE_USER'] = str(peer.get_subject()) - return env - - -class zhttps_channel(https_channel): - "https channel" - - closed=0 - zombie_timeout=100*60 # 100 minutes - - def __init__(self, server, conn, addr): - https_channel.__init__(self, server, conn, addr) - self.queue=[] - self.working=0 - self.peer_found=0 - - def push(self, producer, send=1): - # this is thread-safe when send is false - # note, that strings are not wrapped in - # producers by default - if self.closed: - return - self.producer_fifo.push(producer) - if send: self.initiate_send() - - push_with_producer=push - - def work(self): - "try to handle a request" - if not self.working: - if self.queue: - self.working=1 - try: module_name, request, response=self.queue.pop(0) - except: return - handle(module_name, request, response) - - def close(self): - self.closed=1 - while self.queue: - self.queue.pop() - if self.current_request is not None: - self.current_request.channel=None # break circ refs - self.current_request=None - while self.producer_fifo: - p=self.producer_fifo.first() - if p is not None and type(p) != types.StringType: - p.more() # free up resources held by producer - self.producer_fifo.pop() - self.del_channel() - #self.socket.set_shutdown(SSL.SSL_SENT_SHUTDOWN|SSL.SSL_RECEIVED_SHUTDOWN) - self.socket.close() - - def done(self): - "Called when a publishing request is finished" - self.working=0 - self.work() - - def kill_zombies(self): - now = int (time.time()) - for channel in asyncore.socket_map.values(): - if channel.__class__ == self.__class__: - if (now - channel.creation_time) > channel.zombie_timeout: - channel.close() - - -class zhttps_server(https_server): - "https server" - - SERVER_IDENT='ZServerSSL/%s' % (ZSERVER_SSL_VERSION,) - - channel_class = zhttps_channel - shutup = 0 - - def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): - self.shutup = 1 - https_server.__init__(self, ip, port, ssl_ctx, resolver, logger_object) - self.ssl_ctx = ssl_ctx - self.shutup = 0 - self.log_info('(%s) HTTPS server started at %s\n' - '\tHostname: %s\n\tPort: %d' % ( - self.SERVER_IDENT, - time.ctime(time.time()), - self.server_name, - self.server_port - )) - - def log_info(self, message, type='info'): - if self.shutup: return - dispatcher.log_info(self, message, type) - - def readable(self): - return self.accepting and \ - len(asyncore.socket_map) < CONNECTION_LIMIT - - def listen(self, num): - # override asyncore limits for nt's listen queue size - self.accepting = 1 - return self.socket.listen (num) - diff --git a/demo/Zope27/install_dir/lib/python/ZServer/__init__.py.patch b/demo/Zope27/install_dir/lib/python/ZServer/__init__.py.patch deleted file mode 100644 index 0ba84b7..0000000 --- a/demo/Zope27/install_dir/lib/python/ZServer/__init__.py.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- __init__.py.org Sat Sep 27 20:23:00 2003 -+++ __init__.py Sun Oct 26 18:01:27 2003 -@@ -68,6 +68,7 @@ - import asyncore - from medusa import resolver, logger - from HTTPServer import zhttp_server, zhttp_handler -+from HTTPS_Server import zhttps_server, zhttps0_handler, zhttps_handler - from PCGIServer import PCGIServer - from FCGIServer import FCGIServer - from FTPServer import FTPServer diff --git a/demo/Zope27/install_dir/lib/python/ZServer/component.xml.patch b/demo/Zope27/install_dir/lib/python/ZServer/component.xml.patch deleted file mode 100644 index 364d91f..0000000 --- a/demo/Zope27/install_dir/lib/python/ZServer/component.xml.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- component.xml.org Sat Sep 27 20:21:22 2003 -+++ component.xml Sat Sep 27 21:11:26 2003 -@@ -21,6 +21,25 @@ - - - -+ -+ -+ -+ -+ -+ Regular expression used to identify clients who should -+ receive WebDAV source responses to GET requests. -+ -+ -+ -+ -+ If "on", request client X.509 certificate and set REMOTE_USER to -+ said certificate's Subject Distinguished Name. -+ -+ -+ -+ - diff --git a/demo/Zope27/install_dir/lib/python/ZServer/datatypes.py.patch b/demo/Zope27/install_dir/lib/python/ZServer/datatypes.py.patch deleted file mode 100644 index b2ad9c8..0000000 --- a/demo/Zope27/install_dir/lib/python/ZServer/datatypes.py.patch +++ /dev/null @@ -1,59 +0,0 @@ ---- datatypes.py.org Sat Sep 27 20:21:15 2003 -+++ datatypes.py Sun Oct 26 21:19:58 2003 -@@ -72,7 +72,56 @@ - - def createHandler(self): - from ZServer import HTTPServer -+ try: -+ del self.cgienv['HTTPS'] -+ except KeyError: -+ pass - return HTTPServer.zhttp_handler(self.module, '', self.cgienv) -+ -+ -+class HTTPS_ServerFactory(HTTPServerFactory): -+ def __init__(self, section): -+ HTTPServerFactory.__init__(self, section) -+ self.x509_remote_user = section.x509_remote_user -+ from M2Crypto import Rand, SSL -+ Rand.load_file('%s/randpool.dat' % INSTANCE_HOME, -1) -+ ssl_ctx = SSL.Context('sslv23') -+ ssl_ctx.load_cert_chain('%s/ssl/server.pem' % INSTANCE_HOME) -+ ssl_ctx.load_verify_locations('%s/ssl/ca.pem' % INSTANCE_HOME,'') -+ ssl_ctx.load_client_CA('%s/ssl/ca.pem' % INSTANCE_HOME) -+ ssl_ctx.set_session_id_ctx('Zope 2.7.0b2') -+ ssl_ctx.set_tmp_dh('%s/ssl/dh1024.pem' % INSTANCE_HOME) -+ if self.x509_remote_user: -+ ssl_ctx.set_verify(SSL.verify_peer, 10) -+ else: -+ ssl_ctx.set_verify(SSL.verify_none, 10) -+ self.ssl_ctx = ssl_ctx -+ -+ def create(self): -+ from ZServer import HTTPS_Server -+ from ZServer.AccessLogger import access_logger -+ handler = self.createHandler() -+ handler._force_connection_close = self.force_connection_close -+ if self.webdav_source_clients: -+ handler.set_webdav_source_clients(self.webdav_source_clients) -+ server = HTTPS_Server.zhttps_server(ip=self.host, port=self.port, -+ ssl_ctx=self.ssl_ctx, -+ resolver=self.dnsresolver, -+ logger_object=access_logger) -+ server.install_handler(handler) -+ return server -+ -+ def createHandler(self): -+ from ZServer import HTTPS_Server -+ try: -+ del self.cgienv['HTTP'] -+ except KeyError: -+ pass -+ self.cgienv['HTTPS'] = 'ON' -+ if self.x509_remote_user: -+ return HTTPS_Server.zhttps_handler(self.module, '', self.cgienv) -+ else: -+ return HTTPS_Server.zhttps0_handler(self.module, '', self.cgienv) - - - class WebDAVSourceServerFactory(HTTPServerFactory): diff --git a/demo/Zope27/install_dir/lib/python/ZServer/medusa/https_server.py b/demo/Zope27/install_dir/lib/python/ZServer/medusa/https_server.py deleted file mode 100644 index 84a0197..0000000 --- a/demo/Zope27/install_dir/lib/python/ZServer/medusa/https_server.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python - -"""A https server built on Medusa's http_server. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -import asynchat, asyncore, http_server, socket, sys -from M2Crypto import SSL, version - -VERSION_STRING=version - -class https_channel(http_server.http_channel): - - ac_in_buffer_size = 1 << 16 - - def __init__(self, server, conn, addr): - http_server.http_channel.__init__(self, server, conn, addr) - - def send(self, data): - try: - result = self.socket._write_nbio(data) - if result <= 0: - return 0 - else: - self.server.bytes_out.increment(result) - return result - except SSL.SSLError, why: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), why)) - return 0 - - def recv(self, buffer_size): - try: - result = self.socket._read_nbio(buffer_size) - if result is None: - return '' - elif result == '': - self.close() - return '' - else: - self.server.bytes_in.increment(len(result)) - return result - except SSL.SSLError, why: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), why)) - return '' - - -class https_server(http_server.http_server): - - SERVER_IDENT='M2Crypto HTTPS Server (v%s)' % VERSION_STRING - - channel_class=https_channel - - def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): - http_server.http_server.__init__(self, ip, port, resolver, logger_object) - self.ssl_ctx=ssl_ctx - - def handle_accept(self): - # Cribbed from http_server. - self.total_clients.increment() - try: - conn, addr = self.accept() - except socket.error: - # linux: on rare occasions we get a bogus socket back from - # accept. socketmodule.c:makesockaddr complains that the - # address family is unknown. We don't want the whole server - # to shut down because of this. - sys.stderr.write ('warning: server accept() threw an exception\n') - return - - # Turn the vanilla socket into an SSL connection. - try: - ssl_conn=SSL.Connection(self.ssl_ctx, conn) - ssl_conn._setup_ssl(addr) - ssl_conn.accept_ssl() - self.channel_class(self, ssl_conn, addr) - except SSL.SSLError: - pass - - def writeable(self): - return 0 - diff --git a/demo/Zope27/instance_home/README.txt.patch b/demo/Zope27/instance_home/README.txt.patch deleted file mode 100644 index 0d39005..0000000 --- a/demo/Zope27/instance_home/README.txt.patch +++ /dev/null @@ -1,7 +0,0 @@ ---- README.txt.org Sat Sep 27 20:56:11 2003 -+++ README.txt Sat Sep 27 20:56:44 2003 -@@ -7,3 +7,4 @@ - log/ Log files - Products/ Installed products specific to the instance - var/ Run-time data files, including the object database -+ ssl/ ZServerSSL data files diff --git a/demo/Zope27/instance_home/etc/zope.conf.patch b/demo/Zope27/instance_home/etc/zope.conf.patch deleted file mode 100644 index cc9b093..0000000 --- a/demo/Zope27/instance_home/etc/zope.conf.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- zope.conf.org Sat Sep 27 21:03:22 2003 -+++ zope.conf Sat Sep 27 21:05:08 2003 -@@ -650,6 +650,13 @@ - # force-connection-close on - - -+ -+ # valid keys are "address", "force-connection-close" and "x509-remote-user" -+ address 8443 -+ # force-connection-close on -+ x509-remote-user on -+ -+ - - # valid key is "address" - address 8021 diff --git a/demo/Zope27/instance_home/ssl/ca.pem b/demo/Zope27/instance_home/ssl/ca.pem deleted file mode 100644 index b7c84a1..0000000 --- a/demo/Zope27/instance_home/ssl/ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 -NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML -TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl -cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK -q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N -e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf -q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G -A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV -BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex -JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 -DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG -SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ -dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J -vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf ------END CERTIFICATE----- diff --git a/demo/Zope27/instance_home/ssl/dh1024.pem b/demo/Zope27/instance_home/ssl/dh1024.pem deleted file mode 100644 index 81d43f6..0000000 --- a/demo/Zope27/instance_home/ssl/dh1024.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq -/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx -/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC ------END DH PARAMETERS----- diff --git a/demo/Zope27/instance_home/ssl/server.pem b/demo/Zope27/instance_home/ssl/server.pem deleted file mode 100644 index 1ee9282..0000000 --- a/demo/Zope27/instance_home/ssl/server.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx -NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls -b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c -kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 -KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp -/y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 -QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB -H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 -du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv -MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm -aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t -ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy -lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW -iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 -0QkPQNdP ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu -6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe -I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB -AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ -u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 -xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 -1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp -IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx -luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I -lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS -38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy -v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z -DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= ------END RSA PRIVATE KEY----- diff --git a/demo/ZopeX3/INSTALL.txt b/demo/ZopeX3/INSTALL.txt deleted file mode 100644 index 67adbc8..0000000 --- a/demo/ZopeX3/INSTALL.txt +++ /dev/null @@ -1,73 +0,0 @@ -========================================= - ZServerSSL for ZopeX3.0.0 -========================================= - -:Author: Ng Pheng Siong -:Id: $Id: INSTALL.txt 354 2006-02-25 00:13:15Z heikki $ -:Date: $Date$ -:Web-Site: http://sandbox.rulemaker.net/ngps/zope/zssl/ - -.. contents:: - - -Directories ------------------------ - -Directory structure assumes the following: - -- ZopeX3.0.0 is installed in . -- An instance has been created in . - - - ------------------------ - -The following files are to be copied to the corresponding directories -in your : - -- install_dir/lib/python/zope/server/http/https_server.py -- install_dir/lib/python/zope/server/http/https_serverchannel.py -- install_dir/lib/python/zope/server/http/publisherhttps_server.py -- install_dir/lib/python/zope/app/server/https.py - - - ------------------------ - -The following files are to be copied to the corresponding directories -in your : - -- instance_home/ssl/ca.pem -- instance_home/ssl/server.pem -- instance_home/ssl/dh1024.pem - -These are example files. For more information on them, consult the -ZServerSSL HOWTO for Zope 2.6. - -The following patch files are to be applied to the corresponding -directories: - -- install_dir/lib/python/zope/app/server/configure.zcml.patch -- instance_home/etc/zope.conf.patch - - -Launch ZServerSSL -------------------- - -:: - - $ /bin/runzope - - -Testing ---------- - -This section TDB. I have tested ZServerSSL for Zope 3 with 'openssl -s_client' and 'openssl s_client -nbio' successfully. - - -Conclusion ------------- - -Yes, it works! ;-) - diff --git a/demo/ZopeX3/install_dir/lib/python/zope/app/server/configure.zcml.patch b/demo/ZopeX3/install_dir/lib/python/zope/app/server/configure.zcml.patch deleted file mode 100644 index 8d8f031..0000000 --- a/demo/ZopeX3/install_dir/lib/python/zope/app/server/configure.zcml.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- configure.zcml.org Mon Sep 27 16:10:47 2004 -+++ configure.zcml Mon Sep 27 16:11:42 2004 -@@ -5,6 +5,12 @@ - provides="zope.app.applicationcontrol.interfaces.IServerControl" /> - - -+ -+ -+ -+ - diff --git a/demo/ZopeX3/install_dir/lib/python/zope/app/server/https.py b/demo/ZopeX3/install_dir/lib/python/zope/app/server/https.py deleted file mode 100644 index 2278f3e..0000000 --- a/demo/ZopeX3/install_dir/lib/python/zope/app/server/https.py +++ /dev/null @@ -1,28 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004, Ng Pheng Siong. -# All Rights Reserved. -# -# XXX license TBD; should be Zope 3's ZPL, I just haven't read thru that. -# -############################################################################## -"""HTTPS server factories - -$Id: https.py 240 2004-10-02 12:40:14Z ngps $ -""" - -from zope.app.publication.httpfactory import HTTPPublicationRequestFactory -from zope.app.server.servertype import ServerType -from zope.server.http.commonaccesslogger import CommonAccessLogger -from zope.server.http.publisherhttps_server import PMDBHTTPS_Server -from zope.server.http.publisherhttps_server import PublisherHTTPS_Server - -https = ServerType(PublisherHTTPS_Server, - HTTPPublicationRequestFactory, - CommonAccessLogger, - 8443, True) - -pmhttps = ServerType(PMDBHTTPS_Server, - HTTPPublicationRequestFactory, - CommonAccessLogger, - 8376, True) diff --git a/demo/ZopeX3/install_dir/lib/python/zope/server/http/https_server.py b/demo/ZopeX3/install_dir/lib/python/zope/server/http/https_server.py deleted file mode 100644 index 9e1eb3e..0000000 --- a/demo/ZopeX3/install_dir/lib/python/zope/server/http/https_server.py +++ /dev/null @@ -1,104 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004, Ng Pheng Siong. -# All Rights Reserved. -# -# XXX license TBD; should be Zope 3's ZPL, I just haven't read thru that. -# -############################################################################## -"""HTTPS Server - -This is a HTTPS version of HTTPServer. - -$Id: https_server.py 240 2004-10-02 12:40:14Z ngps $ -""" - -import asyncore, logging, os.path - -from zope.server.http.httpserver import HTTPServer -from zope.server.http.https_serverchannel import HTTPS_ServerChannel -from M2Crypto import SSL, version - - -# 2004-09-27, ngps: -# 'sslv2' or 'sslv23' interoperates with Firefox and IE. -# 'sslv3' or 'tlsv1' doesn't. -def make_ssl_context(dir, ssl_proto='sslv23'): - sslctx = SSL.Context(ssl_proto) - sslctx.load_cert(os.path.join(dir, 'server.pem')) - sslctx.load_verify_locations(os.path.join(dir, 'ca.pem')) - sslctx.load_client_CA(os.path.join(dir, 'ca.pem')) - sslctx.set_verify(SSL.verify_none, 10) - sslctx.set_session_id_ctx('someblahblahthing') - sslctx.set_tmp_dh(os.path.join(dir, 'dh1024.pem')) - #sslctx.set_info_callback() # debugging only; not thread-safe - return sslctx - - -class HTTPS_Server(HTTPServer): - """This is a generic HTTPS Server.""" - - channel_class = HTTPS_ServerChannel - SERVER_IDENT = 'zope.server.zserverssl_https' - - def __init__(self, ip, port, ssl_ctx=None, task_dispatcher=None, adj=None, start=1, - hit_log=None, verbose=0): - HTTPServer.__init__(self, ip, port, task_dispatcher, adj, start, hit_log, verbose) - if ssl_ctx is None: - self.ssl_ctx = make_ssl_context(os.path.realpath(__file__)) - else: - self.ssl_ctx = ssl_ctx - - def executeRequest(self, task): - """Execute an HTTP request.""" - # This is a default implementation, meant to be overridden. - body = "The HTTPS server is running!\r\n" * 10 - task.response_headers['Content-Type'] = 'text/plain' - task.response_headers['Content-Length'] = str(len(body)) - task.write(body) - - def handle_accept(self): - """See zope.server.interfaces.IDispatcherEventHandler""" - try: - v = self.accept() - if v is None: - return - conn, addr = v - except socket.error: - # Linux: On rare occasions we get a bogus socket back from - # accept. socketmodule.c:makesockaddr complains that the - # address family is unknown. We don't want the whole server - # to shut down because of this. - if self.adj.log_socket_errors: - self.log_info ('warning: server accept() threw an exception', - 'warning') - return - for (level, optname, value) in self.adj.socket_options: - conn.setsockopt(level, optname, value) - # Turn the vanilla socket into an SSL connection. - try: - ssl_conn = SSL.Connection(self.ssl_ctx, conn) - ssl_conn._setup_ssl(addr) - ssl_conn.accept_ssl() - self.channel_class(self, ssl_conn, addr, self.adj) - except SSL.SSLError, why: - self.log_info('accept: cannot make SSL connection %s' % (why,), 'warning') - pass - - - -if __name__ == '__main__': - - from zope.server.taskthreads import ThreadedTaskDispatcher - td = ThreadedTaskDispatcher() - td.setThreadCount(4) - HTTPS_Server('', 8443, ssl_ctx=None, task_dispatcher=td, verbose=1) - - try: - import asyncore - while 1: - asyncore.poll(5) - - except KeyboardInterrupt: - print 'shutting down...' - td.shutdown() diff --git a/demo/ZopeX3/install_dir/lib/python/zope/server/http/https_serverchannel.py b/demo/ZopeX3/install_dir/lib/python/zope/server/http/https_serverchannel.py deleted file mode 100644 index c33a84d..0000000 --- a/demo/ZopeX3/install_dir/lib/python/zope/server/http/https_serverchannel.py +++ /dev/null @@ -1,55 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004, Ng Pheng Siong. -# All Rights Reserved. -# -# XXX license TBD; should be Zope 3's ZPL, I just haven't read thru that. -# -############################################################################## -"""HTTPS Server Channel - -$Id: https_serverchannel.py 240 2004-10-02 12:40:14Z ngps $ -""" -from zope.server.serverchannelbase import ServerChannelBase -from zope.server.http.httptask import HTTPTask -from zope.server.http.httprequestparser import HTTPRequestParser -from zope.server.http.httpserverchannel import HTTPServerChannel -from M2Crypto import SSL - - -class HTTPS_ServerChannel(HTTPServerChannel): - """HTTPS-specific Server Channel""" - - task_class = HTTPTask - parser_class = HTTPRequestParser - - def send(self, data): - try: - result = self.socket._write_nbio(data) - if result <= 0: - return 0 - else: - #self.server.bytes_out.increment(result) - return result - except SSL.SSLError, why: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), why), 'warning') - return 0 - - def recv(self, buffer_size): - try: - result = self.socket._read_nbio(buffer_size) - if result is None: - return '' - elif result == '': - self.close() - return '' - else: - #self.server.bytes_in.increment(len(result)) - return result - except SSL.SSLError, why: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), why), 'warning') - return '' - - diff --git a/demo/ZopeX3/install_dir/lib/python/zope/server/http/publisherhttps_server.py b/demo/ZopeX3/install_dir/lib/python/zope/server/http/publisherhttps_server.py deleted file mode 100644 index aa8738d..0000000 --- a/demo/ZopeX3/install_dir/lib/python/zope/server/http/publisherhttps_server.py +++ /dev/null @@ -1,83 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004, Ng Pheng Siong. -# All Rights Reserved. -# -# XXX license TBD; should be Zope 3's ZPL, I just haven't read thru that. -# -############################################################################## -"""HTTPS Server that uses the Zope Publisher for executing a task. - -$Id: publisherhttps_server.py 240 2004-10-02 12:40:14Z ngps $ -""" -import os.path, sys -from zope.server.http.https_server import HTTPS_Server, make_ssl_context -from zope.publisher.publish import publish - - -def get_instance_ssldir(): - # This is real cheesy: It seems Zope3 doesn't have convenient - # programmatic access to INSTANCE_HOME. This code relies on zopectl - # setting the first entry of PYTHONPATH to $INSTANCE_HOME/lib/python. - return os.path.join(os.path.dirname(os.path.dirname(sys.path[0])), 'ssl') - - -class PublisherHTTPS_Server(HTTPS_Server): - """Zope Publisher-specific HTTPS Server""" - - def __init__(self, request_factory, sub_protocol=None, *args, **kw): - - # The common HTTP - self.request_factory = request_factory - - # An HTTP server is not limited to serving up HTML; it can be - # used for other protocols, like XML-RPC, SOAP and so as well - # Here we just allow the logger to output the sub-protocol type. - if sub_protocol: - self.SERVER_IDENT += ' (%s)' %str(sub_protocol) - - kw['ssl_ctx'] = make_ssl_context(get_instance_ssldir()) - HTTPS_Server.__init__(self, *args, **kw) - - def executeRequest(self, task): - """Overrides HTTPServer.executeRequest().""" - env = task.getCGIEnvironment() - env['HTTPS'] = 'ON' - try: - del env['HTTP'] - except KeyError: - pass - instream = task.request_data.getBodyStream() - - request = self.request_factory(instream, task, env) - response = request.response - response.setHeaderOutput(task) - response.setHTTPTransaction(task) - publish(request) - - -class PMDBHTTPS_Server(PublisherHTTPS_Server): - """Enter the post-mortem debugger when there's an error""" - - def executeRequest(self, task): - """Overrides HTTPServer.executeRequest().""" - env = task.getCGIEnvironment() - env['HTTPS'] = 'ON' - try: - del env['HTTP'] - except KeyError: - pass - instream = task.request_data.getBodyStream() - - request = self.request_factory(instream, task, env) - response = request.response - response.setHeaderOutput(task) - try: - publish(request, handle_errors=False) - except: - import sys, pdb - print "%s:" % sys.exc_info()[0] - print sys.exc_info()[1] - pdb.post_mortem(sys.exc_info()[2]) - raise - diff --git a/demo/ZopeX3/instance_home/etc/zope.conf.patch b/demo/ZopeX3/instance_home/etc/zope.conf.patch deleted file mode 100644 index f281246..0000000 --- a/demo/ZopeX3/instance_home/etc/zope.conf.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- zope.conf.org Tue Sep 28 09:49:02 2004 -+++ zope.conf Tue Sep 28 09:49:27 2004 -@@ -20,6 +20,11 @@ - address 8080 - - -+ -+ type HTTPS -+ address 8443 -+ -+ - # For debugging purposes, you can use this publisher instead/as well - # (obviously if it's as well, use a different port number). If there's - # an exception, Zope will drop into pdb at the point of the exception. -@@ -27,6 +32,11 @@ - # - # type PostmortemDebuggingHTTP - # address 8080 -+# -+# -+# -+# type PostmortemDebuggingHTTPS -+# address 8443 - # - - diff --git a/demo/ZopeX3/instance_home/ssl/ca.pem b/demo/ZopeX3/instance_home/ssl/ca.pem deleted file mode 100644 index b7c84a1..0000000 --- a/demo/ZopeX3/instance_home/ssl/ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 -NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML -TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl -cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK -q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N -e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf -q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G -A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV -BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex -JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 -DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG -SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ -dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J -vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf ------END CERTIFICATE----- diff --git a/demo/ZopeX3/instance_home/ssl/dh1024.pem b/demo/ZopeX3/instance_home/ssl/dh1024.pem deleted file mode 100644 index 81d43f6..0000000 --- a/demo/ZopeX3/instance_home/ssl/dh1024.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq -/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx -/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC ------END DH PARAMETERS----- diff --git a/demo/ZopeX3/instance_home/ssl/server.pem b/demo/ZopeX3/instance_home/ssl/server.pem deleted file mode 100644 index 1ee9282..0000000 --- a/demo/ZopeX3/instance_home/ssl/server.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx -NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls -b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c -kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 -KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp -/y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 -QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB -H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 -du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv -MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm -aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t -ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy -lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW -iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 -0QkPQNdP ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu -6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe -I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB -AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ -u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 -xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 -1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp -IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx -luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I -lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS -38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy -v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z -DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= ------END RSA PRIVATE KEY----- diff --git a/demo/bio_mem_rw.py b/demo/bio_mem_rw.py deleted file mode 100644 index bcb78b8..0000000 --- a/demo/bio_mem_rw.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python2.0 - -"""Demonstrates the use of m2.bio_set_mem_eof_return(). -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import m2 -m2.lib_init() - -use_mem = 1 - -if use_mem: - bio = m2.bio_new(m2.bio_s_mem()) -else: - bio = m2.bio_new_file('XXX', 'wb') -ciph = m2.bf_cbc() -filt = m2.bio_new(m2.bio_f_cipher()) -m2.bio_set_cipher(filt, ciph, 'key', 'iv', 1) -m2.bio_push(filt, bio) -m2.bio_write(filt, '12345678901234567890') -m2.bio_flush(filt) -m2.bio_pop(filt) -m2.bio_free(filt) -if use_mem: - m2.bio_set_mem_eof_return(bio, 0) - xxx = m2.bio_read(bio, 100) - print `xxx`, len(xxx) -m2.bio_free(bio) - -if use_mem: - bio = m2.bio_new(m2.bio_s_mem()) - m2.bio_write(bio, xxx) - m2.bio_set_mem_eof_return(bio, 0) -else: - bio = m2.bio_new_file('XXX', 'rb') -ciph = m2.bf_cbc() -filt = m2.bio_new(m2.bio_f_cipher()) -m2.bio_set_cipher(filt, ciph, 'key', 'iv', 0) -m2.bio_push(filt, bio) -yyy = m2.bio_read(filt, 100) -print `yyy` -m2.bio_pop(filt) -m2.bio_free(filt) -m2.bio_free(bio) - diff --git a/demo/dhtest.py b/demo/dhtest.py deleted file mode 100644 index 9fd87c6..0000000 --- a/demo/dhtest.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python - -"""DH demonstration. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import DH, Rand - -def test(): - print 'generating dh params:' - a = DH.gen_params(128, 2) - b = DH.set_params(a.p, a.g) - a.gen_key() - b.gen_key() - print 'p = ', `a.p` - print 'g = ', `a.g` - print 'a.pub =', `a.pub` - print 'a.priv =', `a.priv` - print 'b.pub =', `b.pub` - print 'b.priv =', `b.priv` - print 'a.key = ', `a.compute_key(b.pub)` - print 'b.key = ', `b.compute_key(a.pub)` - -if __name__=='__main__': - Rand.load_file('randpool.dat', -1) - test() - Rand.save_file('randpool.dat') diff --git a/demo/dsa1024pvtkey.pem b/demo/dsa1024pvtkey.pem deleted file mode 100644 index 8379ed1..0000000 --- a/demo/dsa1024pvtkey.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIIBvQIBAAKBgQD08iE3LXjSB/lA6Gq19XMzfmTvRBgFn+t9qNN6awFhrkowgyrI -HaR6oCCHSvUcjdC0JcJdz8lSqofZkPknX6EEDkmlzZiUhtTZf0XiooeKigAiSlE2 -PpoS4RFcOOqOwVwRJI3mC2lzypI46/OPS0IOZFsxhXQpn1xnkmpEt83ZwwIVAPNw -e6agkM25mv12Il7IuBBNl3cPAoGBAKOES1BV2E3zWj6gXOXFP02dk5A+zd7z4Qj+ -cx5euat07cAHYU0BZGJMTXlHSGf7YQOePuaxs9vTtSeUb1TeMFEr63Jispc9Kzce -rd+E/IjiX7KCMbeGHnhtzC0FU/squZ76vp1TAXSozpfBvn73zAwAFPo/rHO4k6kH -lXAez1QqAoGBAN6iYzbOnMckBtouHGBrdF4ea750DYnH5O2cij+yjgLMttuaxmZe -0iFtJpXp6m4IHKAzIGgKhUGabAz+4O2/ZnmNu0oZzXkpBLL84pksDd0nObtgueL6 -sdTbhGl1kqpWRiK9T16gwqYxdcZiG5M5qbWtJIWWdv3mI9ql0XfUPWfpAhUA8e81 -iGFXunNE3ecKjCOKUL2EnEA= ------END DSA PRIVATE KEY----- diff --git a/demo/dsa_bench.py b/demo/dsa_bench.py deleted file mode 100644 index cd4b1f9..0000000 --- a/demo/dsa_bench.py +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env python - -""" - DSA demo and benchmark. - - Usage: python -O dsa_bench.py [option option option ...] - where options may include: - makenewkey showpubkey showdigest showprofile - md5 sha1 sha256 sha512 - - - NB: - DSA is formally defined with SHA-1 and key length 1024. - The OpenSSL implementation actually supports most any - hashing algorithm and key length, as long as the key - length is longer than the digest length. If not SHA-1 - and 1024, you should be very clear. The use of "DSA" - without any qualifiers implies SHA-1 and 1024. - - Larry Bugbee - November 2006 - - - Some portions are Copyright (c) 1999-2003 Ng Pheng Siong. - All rights reserved. - - Portions created by Open Source Applications Foundation - (OSAF) are Copyright (C) 2004 OSAF. All Rights Reserved. - -""" - -from M2Crypto import DSA, EVP, Rand -from M2Crypto.EVP import MessageDigest -import sys, base64 - -# -------------------------------------------------------------- -# program parameters - -makenewkey = 0 # 1 = make/save new key, 0 = use existing -showpubkey = 0 # 1 = show the public key value -showdigest = 0 # 1 = show the digest value -showprofile = 0 # 1 = use the python profiler - -hashalgs = ['md5', 'ripemd160', 'sha1', - 'sha224', 'sha256', 'sha384', 'sha512'] - -# default hashing algorithm -hashalg = 'sha1' - -# default key length -keylen = 1024 - -# number of speed test loops -N1 = N2 = 100 - -# -------------------------------------------------------------- -# functions - -def test(dsa, dgst): - print ' testing signing and verification...', - try: - r,s = dsa.sign(dgst) - except Exception, e: - print '\n\n *** %s *** \n' % e - sys.exit() - if not dsa.verify(dgst, r, s): - print 'not ok' - else: - print 'ok' - -def test_asn1(dsa, dgst): - # XXX Randomly fails: bug in there somewhere... (0.9.4) - print ' testing asn1 signing and verification...', - blob = dsa.sign_asn1(dgst) - if not dsa.verify_asn1(dgst, blob): - print 'not ok' - else: - print 'ok' - -def speed(): - from time import time - t1 = time() - for i in range(N1): - r,s = dsa.sign(dgst) - print ' %d signings: %8.2fs' % (N1, (time() - t1)) - t1 = time() - for i in range(N2): - dsa.verify(dgst, r, s) - print ' %d verifications: %8.2fs' % (N2, (time() - t1)) - -def test_speed(dsa, dgst): - print ' measuring speed...' - if showprofile: - import profile - profile.run('speed()') - else: - speed() - print - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def main(keylen, hashalg): - global dsa, dgst # this exists ONLY for speed testing - - Rand.load_file('randpool.dat', -1) - - pvtkeyfilename = 'DSA%dpvtkey.pem' % (keylen) - pubkeyfilename = 'DSA%dpubkey.pem' % (keylen) - - if makenewkey: - print ' making and saving a new key' - dsa = DSA.gen_params(keylen) - dsa.gen_key() - dsa.save_key(pvtkeyfilename, None ) # no pswd callback - dsa.save_pub_key(pubkeyfilename) - else: - print ' loading an existing key' - dsa = DSA.load_key(pvtkeyfilename) - print ' dsa key length:', len(dsa) - - if not dsa.check_key(): - raise 'key is not initialised' - - if showpubkey: - dsa_pub = dsa.pub - pub_pem = base64.encodestring(dsa_pub) - print ' PEM public key is: \n',pub_pem - - # since we are testing signing and verification, let's not - # be fussy about the digest. Just make one. - md = EVP.MessageDigest(hashalg) - md.update('can you spell subliminal channel?') - dgst = md.digest() - print ' hash algorithm: %s' % hashalg - if showdigest: - print ' %s digest: \n%s' % (hashalg, base64.encodestring(dgst)) - - test(dsa, dgst) -# test_asn1(dsa, dgst) - test_speed(dsa, dgst) - Rand.save_file('randpool.dat') - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def print_usage(): - print """ - Usage: python -O %s [option option option ...] - where options may include: - makenewkey showpubkey showdigest showprofile - md5 sha1 sha256 sha512 - -""" % sys.argv[0] - sys.exit() - -# -------------------------------------------------------------- -# -------------------------------------------------------------- - -if __name__=='__main__': - for arg in sys.argv[1:]: - if arg in hashalgs: hashalg = arg; continue - if arg == 'makenewkey': makenewkey = 1; continue - if arg == 'showpubkey': showpubkey = 1; continue - if arg == 'showdigest': showdigest = 1; continue - if arg == 'showprofile': showprofile = 1; continue - try: - keylen = int(arg) - except: - print '\n *** argument "%s" not understood ***' % arg - print_usage() - - main(keylen, hashalg) - - -# -------------------------------------------------------------- -# -------------------------------------------------------------- -# -------------------------------------------------------------- diff --git a/demo/dsatest.pem b/demo/dsatest.pem deleted file mode 100644 index 8d5d97f..0000000 --- a/demo/dsatest.pem +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIH4AgEAAkEA0NGZ0GRXdPLh/0c980Ot8ZbfV/DvJ19ZzsDhKXRxNNw36Ms4lb9Y -ZMnJ1CliIDkpHx8sXEak0vkdeB2efGGBPQIVAJY7PF7CiA+jj+t3EyHf/sgVagPP -AkEApkvDehftx8Kt+3GRsYkEgcKqsU6tue+QQOFOFYsCbMq/3rxIEKk0q1PqHfid -+BsMiEY4FFmF5BqmgGAf6+V9twJATbbgPKi/EboVrtBdkTM52LSCQHPa/CEcj322 -0s5Ix1dwojdQaNpq6HhCm6+g9SXPENy9I/PK85YnawI4A6w1pQIULRB2HSm1X14c -+guvmhIobv6wE50= ------END DSA PRIVATE KEY----- diff --git a/demo/dsatest.py b/demo/dsatest.py deleted file mode 100644 index 854b8b9..0000000 --- a/demo/dsatest.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python - -"""DSA demonstration. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import DSA, EVP, Rand - -md=EVP.MessageDigest('sha1') -md.update('can you spell subliminal channel?') -dgst=md.digest() - -d=DSA.load_key('dsatest.pem') - -def test(): - print 'testing signing...', - r,s=d.sign(dgst) - if not d.verify(dgst, r, s): - print 'not ok' - else: - print 'ok' - -def test_asn1(): - # XXX Randomly fails: bug in there somewhere... (0.9.4) - print 'testing asn1 signing...', - blob=d.sign_asn1(dgst) - if not d.verify_asn1(dgst, blob): - print 'not ok' - else: - print 'ok' - -def speed(): - from time import time - N1 = 5242 - N2 = 2621 - t1 = time() - for i in range(N1): - r,s = d.sign(dgst) - print '%d signings: %8.2fs' % (N1, (time() - t1)) - t1 = time() - for i in range(N2): - d.verify(dgst, r, s) - print '%d verifications: %8.2fs' % (N2, (time() - t1)) - -def test_speed(): - print 'measuring speed...' - import profile - profile.run('speed()') - - -if __name__=='__main__': - Rand.load_file('randpool.dat', -1) - test() - test_asn1() - #test_speed() - Rand.save_file('randpool.dat') - diff --git a/demo/ec/ecdhtest.py b/demo/ec/ecdhtest.py deleted file mode 100644 index 6d407b6..0000000 --- a/demo/ec/ecdhtest.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python - -"""ECDH demonstration. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. - -Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. -All rights reserved.""" - -from M2Crypto import EC,Rand - -def test(): - print 'generating ec keys:' - a=EC.gen_params(EC.NID_sect233k1) - a.gen_key() - b=EC.gen_params(EC.NID_sect233k1) - b.gen_key() - a_shared_key = a.compute_dh_key(b.pub()) - b_shared_key = b.compute_dh_key(a.pub()) - print 'shared key according to a = ', `a_shared_key` - print 'shared key according to b = ', `b_shared_key` - if a_shared_key == b_shared_key: - print 'ok' - else: - print 'not ok' - - -if __name__=='__main__': - Rand.load_file('randpool.dat', -1) - test() - Rand.save_file('randpool.dat') diff --git a/demo/ec/ecdsa_bench.py b/demo/ec/ecdsa_bench.py deleted file mode 100644 index bafceb1..0000000 --- a/demo/ec/ecdsa_bench.py +++ /dev/null @@ -1,368 +0,0 @@ -#!/usr/bin/env python - -""" - ECDSA demo and benchmark. - - Usage: python -O ecdsa_bench.py [option option option ...] - where options may include: - makenewkey showpubkey showdigest showprofile - md5 sha1 sha256 sha512 - secp160r1 secp224r1 secp192k1 sect283r1 - sect283k1 secp256k1 secp384r1 secp521r1 - (other curves and hashes are supported, see below) - - Larry Bugbee, June 2006 - - Portions: - Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. - Copyright (c) 2005 Vrije Universiteit Amsterdam. All rights reserved. - -""" - -from M2Crypto import EC, EVP, Rand -from M2Crypto.EVP import MessageDigest -import sys, base64 - -# -------------------------------------------------------------- -# program parameters - -makenewkey = 0 # 1 = make/save new key, 0 = use existing -showpubkey = 0 # 1 = show the public key value -showdigest = 0 # 1 = show the digest value -showprofile = 0 # 1 = use the python profiler - -hashalgs = ['md5', 'ripemd160', 'sha1', - 'sha224', 'sha256', 'sha384', 'sha512'] - -curves = ['secp112r1', - 'secp112r2', - 'secp128r1', - 'secp128r2', - 'secp160k1', - 'secp160r1', - 'secp160r2', - 'secp192k1', - 'secp224k1', - 'secp224r1', - 'secp256k1', - 'secp384r1', - 'secp521r1', - 'sect113r1', - 'sect113r2', - 'sect131r1', - 'sect131r2', - 'sect163k1', - 'sect163r1', - 'sect163r2', - 'sect193r1', - 'sect193r2', - 'sect233k1', - 'sect233r1', - 'sect239k1', - 'sect283k1', - 'sect283r1', - 'sect409k1', - 'sect409r1', - 'sect571k1', - 'sect571r1', - 'X9_62_prime192v1', - 'X9_62_prime192v2', - 'X9_62_prime192v3', - 'X9_62_prime239v1', - 'X9_62_prime239v2', - 'X9_62_prime239v3', - 'X9_62_prime256v1', - 'X9_62_c2pnb163v1', - 'X9_62_c2pnb163v2', - 'X9_62_c2pnb163v3', - 'X9_62_c2pnb176v1', - 'X9_62_c2tnb191v1', - 'X9_62_c2tnb191v2', - 'X9_62_c2tnb191v3', - 'X9_62_c2pnb208w1', - 'X9_62_c2tnb239v1', - 'X9_62_c2tnb239v2', - 'X9_62_c2tnb239v3', - 'X9_62_c2pnb272w1', - 'X9_62_c2pnb304w1', - 'X9_62_c2tnb359v1', - 'X9_62_c2pnb368w1', - 'X9_62_c2tnb431r1', - 'wap_wsg_idm_ecid_wtls1', - 'wap_wsg_idm_ecid_wtls3', - 'wap_wsg_idm_ecid_wtls4', - 'wap_wsg_idm_ecid_wtls5', - 'wap_wsg_idm_ecid_wtls6', - 'wap_wsg_idm_ecid_wtls7', - 'wap_wsg_idm_ecid_wtls8', - 'wap_wsg_idm_ecid_wtls9', - 'wap_wsg_idm_ecid_wtls10', - 'wap_wsg_idm_ecid_wtls11', - 'wap_wsg_idm_ecid_wtls12', - ] - -# The following two curves, according to OpenSSL, have a -# "Questionable extension field!" and are not supported by -# the OpenSSL inverse function. ECError: no inverse. -# As such they cannot be used for signing. They might, -# however, be usable for encryption but that has not -# been tested. Until thir usefulness can be established, -# they are not supported at this time. -# -# Oakley-EC2N-3: -# IPSec/IKE/Oakley curve #3 over a 155 bit binary field. -# Oakley-EC2N-4: -# IPSec/IKE/Oakley curve #4 over a 185 bit binary field. -# -# aka 'ipsec3' and 'ipsec4' - -# curves2 is a shorthand convenience so as to not require the -# entering the "X9_62_" prefix -curves2 = ['prime192v1', - 'prime192v2', - 'prime192v3', - 'prime239v1', - 'prime239v2', - 'prime239v3', - 'prime256v1', - 'c2pnb163v1', - 'c2pnb163v2', - 'c2pnb163v3', - 'c2pnb176v1', - 'c2tnb191v1', - 'c2tnb191v2', - 'c2tnb191v3', - 'c2pnb208w1', - 'c2tnb239v1', - 'c2tnb239v2', - 'c2tnb239v3', - 'c2pnb272w1', - 'c2pnb304w1', - 'c2tnb359v1', - 'c2pnb368w1', - 'c2tnb431r1', - ] - -# default hashing algorithm -hashalg = 'sha1' - -# default elliptical curve -curve = 'secp160r1' - -# for a complete list of supported algorithms and curves, see -# the bottom of this file - -# number of speed test loops -N1 = N2 = 100 - -# -------------------------------------------------------------- -# functions - -def test(ec, dgst): - print ' testing signing and verification...', - try: -# ec = EC.gen_params(EC.NID_secp160r1) -# ec.gen_key() - r,s = ec.sign_dsa(dgst) - except Exception, e: - print '\n\n *** %s *** \n' % e - sys.exit() - if not ec.verify_dsa(dgst, r, s): - print 'not ok' - else: - print 'ok' - -def test_asn1(ec, dgst): - print ' testing asn1 signing and verification...', - blob = ec.sign_dsa_asn1(dgst) - if not ec.verify_dsa_asn1(dgst, blob): - print 'not ok' - else: - print 'ok' - -def speed(): - from time import time - t1 = time() - for i in range(N1): - r,s = ec.sign_dsa(dgst) - print ' %d signings: %8.2fs' % (N1, (time() - t1)) - t1 = time() - for i in range(N2): - ec.verify_dsa(dgst, r, s) - print ' %d verifications: %8.2fs' % (N2, (time() - t1)) - -def test_speed(ec, dgst): - print ' measuring speed...' - if showprofile: - import profile - profile.run('speed()') - else: - speed() - print - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def main(curve, hashalg): - global ec, dgst # this exists ONLY for speed testing - - Rand.load_file('randpool.dat', -1) - - if curve in curves2: - curve = 'X9_62_' + curve - ec_curve = eval('EC.NID_%s' % curve) - - pvtkeyfilename = '%spvtkey.pem' % (curve) - pubkeyfilename = '%spubkey.pem' % (curve) - - if makenewkey: - print ' making and saving a new key' - ec = EC.gen_params(ec_curve) - ec.gen_key() - ec.save_key(pvtkeyfilename, None ) - ec.save_pub_key(pubkeyfilename) - else: - print ' loading an existing key' - ec=EC.load_key(pvtkeyfilename) - print ' ecdsa key length:', len(ec) - print ' curve: %s' % curve - - if not ec.check_key(): - raise 'key is not initialised' - - if showpubkey: - ec_pub = ec.pub() - pub_der = ec_pub.get_der() - pub_pem = base64.encodestring(pub_der) - print ' PEM public key is: \n',pub_pem - - # since we are testing signing and verification, let's not - # be fussy about the digest. Just make one. - md = EVP.MessageDigest(hashalg) - md.update('can you spell subliminal channel?') - dgst = md.digest() - print ' hash algorithm: %s' % hashalg - if showdigest: - print ' %s digest: \n%s' % (base64.encodestring(dgst)) - - test(ec, dgst) -# test_asn1(ec, dgst) - test_speed(ec, dgst) - Rand.save_file('randpool.dat') - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def print_usage(): - print """ - Usage: python -O %s [option option option ...] - where options may include: - makenewkey showpubkey showdigest showprofile - md5 sha1 sha256 sha512 - secp160r1 secp224r1 secp192k1 sect283r1 - sect283k1 secp256k1 secp384r1 secp521r1 - (other curves and hashes are supported, check pgm src) -""" % sys.argv[0] - sys.exit() - -# -------------------------------------------------------------- -# -------------------------------------------------------------- - -if __name__=='__main__': - for arg in sys.argv[1:]: - if arg in hashalgs: hashalg = arg; continue - if arg in curves + curves2: curve = arg; continue - if arg == 'makenewkey': makenewkey = 1; continue - if arg == 'showpubkey': showpubkey = 1; continue - if arg == 'showdigest': showdigest = 1; continue - if arg == 'showprofile': showprofile = 1; continue - - print '\n *** argument "%s" not understood ***' % arg - print_usage() - - main(curve, hashalg) - - -# -------------------------------------------------------------- -# -------------------------------------------------------------- -# -------------------------------------------------------------- - - -""" - Elliptical curves supported by OpenSSL - ====================================== - -$ openssl ecparam -list_curves - secp112r1 : SECG/WTLS curve over a 112 bit prime field - secp112r2 : SECG curve over a 112 bit prime field - secp128r1 : SECG curve over a 128 bit prime field - secp128r2 : SECG curve over a 128 bit prime field - secp160k1 : SECG curve over a 160 bit prime field - secp160r1 : SECG curve over a 160 bit prime field - secp160r2 : SECG/WTLS curve over a 160 bit prime field - secp192k1 : SECG curve over a 192 bit prime field - secp224k1 : SECG curve over a 224 bit prime field - secp224r1 : NIST/SECG curve over a 224 bit prime field - secp256k1 : SECG curve over a 256 bit prime field - secp384r1 : NIST/SECG curve over a 384 bit prime field - secp521r1 : NIST/SECG curve over a 521 bit prime field - prime192v1: NIST/X9.62/SECG curve over a 192 bit prime field - prime192v2: X9.62 curve over a 192 bit prime field - prime192v3: X9.62 curve over a 192 bit prime field - prime239v1: X9.62 curve over a 239 bit prime field - prime239v2: X9.62 curve over a 239 bit prime field - prime239v3: X9.62 curve over a 239 bit prime field - prime256v1: X9.62/SECG curve over a 256 bit prime field - sect113r1 : SECG curve over a 113 bit binary field - sect113r2 : SECG curve over a 113 bit binary field - sect131r1 : SECG/WTLS curve over a 131 bit binary field - sect131r2 : SECG curve over a 131 bit binary field - sect163k1 : NIST/SECG/WTLS curve over a 163 bit binary field - sect163r1 : SECG curve over a 163 bit binary field - sect163r2 : NIST/SECG curve over a 163 bit binary field - sect193r1 : SECG curve over a 193 bit binary field - sect193r2 : SECG curve over a 193 bit binary field - sect233k1 : NIST/SECG/WTLS curve over a 233 bit binary field - sect233r1 : NIST/SECG/WTLS curve over a 233 bit binary field - sect239k1 : SECG curve over a 239 bit binary field - sect283k1 : NIST/SECG curve over a 283 bit binary field - sect283r1 : NIST/SECG curve over a 283 bit binary field - sect409k1 : NIST/SECG curve over a 409 bit binary field - sect409r1 : NIST/SECG curve over a 409 bit binary field - sect571k1 : NIST/SECG curve over a 571 bit binary field - sect571r1 : NIST/SECG curve over a 571 bit binary field - c2pnb163v1: X9.62 curve over a 163 bit binary field - c2pnb163v2: X9.62 curve over a 163 bit binary field - c2pnb163v3: X9.62 curve over a 163 bit binary field - c2pnb176v1: X9.62 curve over a 176 bit binary field - c2tnb191v1: X9.62 curve over a 191 bit binary field - c2tnb191v2: X9.62 curve over a 191 bit binary field - c2tnb191v3: X9.62 curve over a 191 bit binary field - c2pnb208w1: X9.62 curve over a 208 bit binary field - c2tnb239v1: X9.62 curve over a 239 bit binary field - c2tnb239v2: X9.62 curve over a 239 bit binary field - c2tnb239v3: X9.62 curve over a 239 bit binary field - c2pnb272w1: X9.62 curve over a 272 bit binary field - c2pnb304w1: X9.62 curve over a 304 bit binary field - c2tnb359v1: X9.62 curve over a 359 bit binary field - c2pnb368w1: X9.62 curve over a 368 bit binary field - c2tnb431r1: X9.62 curve over a 431 bit binary field - wap-wsg-idm-ecid-wtls1: WTLS curve over a 113 bit binary field - wap-wsg-idm-ecid-wtls3: NIST/SECG/WTLS curve over a 163 bit binary field - wap-wsg-idm-ecid-wtls4: SECG curve over a 113 bit binary field - wap-wsg-idm-ecid-wtls5: X9.62 curve over a 163 bit binary field - wap-wsg-idm-ecid-wtls6: SECG/WTLS curve over a 112 bit prime field - wap-wsg-idm-ecid-wtls7: SECG/WTLS curve over a 160 bit prime field - wap-wsg-idm-ecid-wtls8: WTLS curve over a 112 bit prime field - wap-wsg-idm-ecid-wtls9: WTLS curve over a 160 bit prime field - wap-wsg-idm-ecid-wtls10: NIST/SECG/WTLS curve over a 233 bit binary field - wap-wsg-idm-ecid-wtls11: NIST/SECG/WTLS curve over a 233 bit binary field - wap-wsg-idm-ecid-wtls12: WTLS curvs over a 224 bit prime field - Oakley-EC2N-3: - IPSec/IKE/Oakley curve #3 over a 155 bit binary field. - Not suitable for ECDSA. - Questionable extension field! - Oakley-EC2N-4: - IPSec/IKE/Oakley curve #4 over a 185 bit binary field. - Not suitable for ECDSA. - Questionable extension field! - -""" diff --git a/demo/ec/ecdsatest.pem b/demo/ec/ecdsatest.pem deleted file mode 100644 index cc37a65..0000000 --- a/demo/ec/ecdsatest.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MG0CAQEEHVkQ54w5gN39TScPaC+TTKmJunupCfuNqEcWOZeXoAcGBSuBBAAaoUAD -PgAEAIcWBNwIi1fP2Sd33wpayKBuw2oqBVvgvfYiipMcASzxCf6IFUC03IOob/Lu -Y3mPHRZKwzSKBlD1ZkXh ------END EC PRIVATE KEY----- diff --git a/demo/ec/ecdsatest.py b/demo/ec/ecdsatest.py deleted file mode 100644 index 61ad625..0000000 --- a/demo/ec/ecdsatest.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python - -"""ECDSA demonstration. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. -Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. -""" - -from M2Crypto import EC, EVP, Rand -import base64 - -md=EVP.MessageDigest('sha1') -md.update('can you spell subliminal channel?') -dgst=md.digest() - -ec=EC.load_key('ecdsatest.pem') -#ec=EC.gen_params(EC.NID_sect233k1) -#ec.gen_key() -ec_pub = ec.pub() -pub_der = ec_pub.get_der() -pub_pem = base64.encodestring(pub_der) -print 'PEM public key is',pub_pem -ec.save_key( 'ecdsatest.pem', None ) - - -def test(): - print 'testing signing...', - r,s=ec.sign_dsa(dgst) - if not ec.verify_dsa(dgst, r, s): - print 'not ok' - else: - print 'ok' - -def test_asn1(): - # XXX Randomly fails: bug in there somewhere... (0.9.4) - print 'testing asn1 signing...', - blob=ec.sign_dsa_asn1(dgst) - if not ec.verify_dsa_asn1(dgst, blob): - print 'not ok' - else: - print 'ok' - -def speed(): - from time import time - N1 = 5242 - N2 = 2621 - t1 = time() - for i in range(N1): - r,s = ec.sign(dgst) - print '%d signings: %8.2fs' % (N1, (time() - t1)) - t1 = time() - for i in range(N2): - ec.verify(dgst, r, s) - print '%d verifications: %8.2fs' % (N2, (time() - t1)) - -def test_speed(): - print 'measuring speed...' - import profile - profile.run('speed()') - - -if __name__=='__main__': - Rand.load_file('randpool.dat', -1) - test() - test_asn1() - #test_speed() - Rand.save_file('randpool.dat') - diff --git a/demo/ec/secp160r1pvtkey.pem b/demo/ec/secp160r1pvtkey.pem deleted file mode 100644 index 6eac827..0000000 --- a/demo/ec/secp160r1pvtkey.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MFACAQEEFN1C7AYNKDl9dBLfm0QW1nB7WGs7oAcGBSuBBAAIoSwDKgEErnCVbfXH -11Ax4AZq4eh8c3gWIBeaRu6tGRpITFCjtHot78c/oVqBrg== ------END EC PRIVATE KEY----- diff --git a/demo/https.howto/ca.pem b/demo/https.howto/ca.pem deleted file mode 100644 index d8ba0d3..0000000 --- a/demo/https.howto/ca.pem +++ /dev/null @@ -1,59 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 0 (0x0) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, ST=CA, O=M2Crypto CA, CN=localhost - Validity - Not Before: Apr 22 04:35:56 2006 GMT - Not After : Apr 21 04:35:56 2009 GMT - Subject: C=US, ST=CA, O=M2Crypto CA, CN=localhost - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public Key: (1024 bit) - Modulus (1024 bit): - 00:d8:80:02:8f:b5:7d:9f:9b:79:76:67:a5:66:64: - c0:30:0c:71:65:f1:c6:78:01:a0:29:d4:3a:2c:e5: - ee:58:4d:db:53:c5:74:6e:4e:f7:b6:a5:8e:ef:ab: - e8:7c:f5:5d:2d:18:ba:95:b8:15:43:6e:5a:78:c2: - 91:05:08:b2:7e:cf:c4:d3:bb:ac:c7:43:27:fb:8f: - 43:0d:7b:d0:d1:32:51:86:11:6e:3e:aa:68:19:88: - b9:cf:d5:72:f0:a4:73:d1:69:c4:65:14:0e:12:64: - 7e:1f:df:18:09:0b:6a:4b:cd:bf:ae:59:82:15:1c: - 90:0f:c3:e5:cb:b3:ed:86:4d - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:TRUE - Netscape Comment: - OpenSSL Generated Certificate - X509v3 Subject Key Identifier: - 5C:F9:C5:9B:B0:02:37:3C:66:73:4D:0E:CB:5A:3D:BB:3A:46:22:DD - X509v3 Authority Key Identifier: - keyid:5C:F9:C5:9B:B0:02:37:3C:66:73:4D:0E:CB:5A:3D:BB:3A:46:22:DD - - Signature Algorithm: sha1WithRSAEncryption - 6b:9e:71:4a:ad:d2:1c:b7:58:1a:6e:8b:89:92:8d:4e:62:61: - 06:2e:e8:11:f8:9c:a0:e2:11:7c:b6:e2:be:ef:b9:b1:35:20: - d1:81:62:c5:ca:3c:4f:c9:88:72:f7:50:d8:e8:e0:06:43:ee: - c5:5c:38:9b:e7:24:46:a6:ee:8d:b0:70:4e:75:96:00:db:d6: - 59:f9:58:74:67:9f:ca:9c:12:fc:77:a7:0e:5a:38:22:5b:de: - c9:33:35:bd:d0:4c:9f:6a:0f:71:7b:db:cb:fd:da:bc:39:4f: - 23:1e:74:5b:ff:8d:73:72:16:a9:9f:57:54:96:3e:2c:f0:65: - af:df ------BEGIN CERTIFICATE----- -MIICfDCCAeWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEL -MAkGA1UECBMCQ0ExFDASBgNVBAoTC00yQ3J5cHRvIENBMRIwEAYDVQQDEwlsb2Nh -bGhvc3QwHhcNMDYwNDIyMDQzNTU2WhcNMDkwNDIxMDQzNTU2WjBEMQswCQYDVQQG -EwJVUzELMAkGA1UECBMCQ0ExFDASBgNVBAoTC00yQ3J5cHRvIENBMRIwEAYDVQQD -Ewlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANiAAo+1fZ+b -eXZnpWZkwDAMcWXxxngBoCnUOizl7lhN21PFdG5O97alju+r6Hz1XS0YupW4FUNu -WnjCkQUIsn7PxNO7rMdDJ/uPQw170NEyUYYRbj6qaBmIuc/VcvCkc9FpxGUUDhJk -fh/fGAkLakvNv65ZghUckA/D5cuz7YZNAgMBAAGjfjB8MAwGA1UdEwQFMAMBAf8w -LAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0G -A1UdDgQWBBRc+cWbsAI3PGZzTQ7LWj27OkYi3TAfBgNVHSMEGDAWgBRc+cWbsAI3 -PGZzTQ7LWj27OkYi3TANBgkqhkiG9w0BAQUFAAOBgQBrnnFKrdIct1gabouJko1O -YmEGLugR+Jyg4hF8tuK+77mxNSDRgWLFyjxPyYhy91DY6OAGQ+7FXDib5yRGpu6N -sHBOdZYA29ZZ+Vh0Z5/KnBL8d6cOWjgiW97JMzW90Eyfag9xe9vL/dq8OU8jHnRb -/41zchapn1dUlj4s8GWv3w== ------END CERTIFICATE----- diff --git a/demo/https.howto/dh1024.pem b/demo/https.howto/dh1024.pem deleted file mode 100644 index 81d43f6..0000000 --- a/demo/https.howto/dh1024.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq -/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx -/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC ------END DH PARAMETERS----- diff --git a/demo/https.howto/get_https.py b/demo/https.howto/get_https.py deleted file mode 100755 index 9728fab..0000000 --- a/demo/https.howto/get_https.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python -"""Demonstrations of M2Crypto.httpslib. - -Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved. - -Portions created by Open Source Applications Foundation (OSAF) are -Copyright (C) 2006 OSAF. All Rights Reserved. -""" - -from M2Crypto import Rand, SSL, httpslib - -def get_https(): - ctx = SSL.Context() - if ctx.load_verify_locations('ca.pem') != 1: - raise Exception('CA certificates not loaded') - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) - h = httpslib.HTTPSConnection('localhost', 9443, ssl_context=ctx) - h.set_debuglevel(1) - h.putrequest('GET', '/') - h.endheaders() - resp = h.getresponse() - while 1: - data = resp.read() - if not data: - break - print data - h.close() - -Rand.load_file('../randpool.dat', -1) -get_https() -Rand.save_file('../randpool.dat') - diff --git a/demo/https.howto/https_cli.py b/demo/https.howto/https_cli.py deleted file mode 100644 index bb34625..0000000 --- a/demo/https.howto/https_cli.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -"""Demonstrations of M2Crypto.httpslib. - -Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved. - -Portions created by Open Source Applications Foundation (OSAF) are -Copyright (C) 2006 OSAF. All Rights Reserved. -""" - -import sys -from M2Crypto import Rand, SSL, httpslib, threading - - -def test_httpslib(): - ctx = SSL.Context() - if ctx.load_verify_locations('ca.pem') != 1: - raise Exception('CA certificates not loaded') - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) - ctx.set_info_callback() - h = httpslib.HTTPSConnection('localhost', 9443, ssl_context=ctx) - h.set_debuglevel(1) - h.putrequest('GET', '/') - h.putheader('Accept', 'text/html') - h.putheader('Accept', 'text/plain') - h.putheader('Connection', 'close') - h.endheaders() - resp = h.getresponse() - f = resp.fp - c = 0 - while 1: - # Either of following two works. - #data = f.readline() - data = resp.read() - if not data: break - c = c + len(data) - sys.stdout.write(data) - sys.stdout.flush() - f.close() - h.close() - - -if __name__=='__main__': - Rand.load_file('../randpool.dat', -1) - #threading.init() - test_httpslib() - #threading.cleanup() - Rand.save_file('../randpool.dat') - diff --git a/demo/https.howto/orig_https_srv.py b/demo/https.howto/orig_https_srv.py deleted file mode 100644 index 83be0fb..0000000 --- a/demo/https.howto/orig_https_srv.py +++ /dev/null @@ -1,153 +0,0 @@ -"""This server extends BaseHTTPServer and SimpleHTTPServer thusly: -1. One thread per connection. -2. Generates directory listings. - -In addition, it has the following properties: -1. Works over HTTPS only. -2. Displays SSL handshaking and SSL session info. -3. Performs SSL renegotiation when a magic url is requested. - -TODO: -1. Cache stat() of directory entries. -2. Fancy directory indexing. -3. Interface ZPublisher. - -Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. - -Portions created by Open Source Applications Foundation (OSAF) are -Copyright (C) 2006 OSAF. All Rights Reserved. -""" - -import os, sys -from SimpleHTTPServer import SimpleHTTPRequestHandler - -from M2Crypto import Rand, SSL, threading -from M2Crypto.SSL.SSLServer import ThreadingSSLServer - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - - -def mkdirlist(path, url): - dirlist = os.listdir(path) - dirlist.sort() - f = StringIO() - f.write('Index listing for %s\r\n' % (url,)) - f.write('

    Index listing for %s

    \r\n' % (url,)) - f.write('
    \r\n')
    -    for d in dirlist:
    -        if os.path.isdir(os.path.join(path, d)):
    -            d2 = d + '/'
    -        else:
    -            d2 = d
    -        if url == '/':
    -            f.write('%s
    \r\n' % (d, d2)) - else: - f.write('%s
    \r\n' % (url, d, d2)) - f.write('
    \r\n\r\n') - f.reset() - return f - - -class HTTP_Handler(SimpleHTTPRequestHandler): - - server_version = "https_srv/0.1" - reneg = 0 - - # Cribbed from SimpleHTTPRequestHander to add the ".der" entry, - # which facilitates installing your own certificates into browsers. - extensions_map = { - '': 'text/plain', # Default, *must* be present - '.html': 'text/html', - '.htm': 'text/html', - '.gif': 'image/gif', - '.jpg': 'image/jpeg', - '.jpeg': 'image/jpeg', - '.der': 'application/x-x509-ca-cert' - } - - def send_head(self): - if self.path[1:8] == '_reneg_': - self.reneg = 1 - self.path = self.path[8:] - path = self.translate_path(self.path) - if os.path.isdir(path): - f = mkdirlist(path, self.path) - filetype = 'text/html' - else: - try: - f = open(path, 'rb') - filetype = self.guess_type(path) - except IOError: - self.send_error(404, "File not found") - return None - self.send_response(200) - self.send_header("Content-type", filetype) - self.end_headers() - return f - - def do_GET(self): - #sess = self.request.get_session() - #self.log_message('\n%s', sess.as_text()) - f = self.send_head() - if self.reneg: - self.reneg = 0 - self.request.renegotiate() - sess = self.request.get_session() - self.log_message('\n%s', sess.as_text()) - if f: - self.copyfile(f, self.wfile) - f.close() - - def do_HEAD(self): - #sess = self.request.get_session() - #self.log_message('\n%s', sess.as_text()) - f = self.send_head() - if f: - f.close() - - -class HTTPS_Server(ThreadingSSLServer): - def __init__(self, server_addr, handler, ssl_ctx): - ThreadingSSLServer.__init__(self, server_addr, handler, ssl_ctx) - self.server_name = server_addr[0] - self.server_port = server_addr[1] - - def finish(self): - self.request.set_shutdown(SSL.SSL_RECEIVED_SHUTDOWN | SSL.SSL_SENT_SHUTDOWN) - self.request.close() - - -def init_context(protocol, certfile, cafile, verify, verify_depth=10): - ctx=SSL.Context(protocol) - ctx.load_cert(certfile) - ctx.load_client_ca(cafile) - if ctx.load_verify_locations(cafile) != 1: - raise Exception('CA certificates not loaded') - ctx.set_verify(verify, verify_depth) - ctx.set_allow_unknown_ca(1) - ctx.set_session_id_ctx('https_srv') - ctx.set_info_callback() - return ctx - - -if __name__ == '__main__': - if len(sys.argv) < 2: - wdir = '.' - else: - wdir = sys.argv[1] - Rand.load_file('../randpool.dat', -1) - threading.init() - ctx = init_context('sslv23', 'server.pem', 'ca.pem', \ - SSL.verify_none) - #SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) - ctx.set_tmp_dh('dh1024.pem') - os.chdir(wdir) - httpsd = HTTPS_Server(('', 9443), HTTP_Handler, ctx) - httpsd.serve_forever() - threading.cleanup() - Rand.save_file('../randpool.dat') - - diff --git a/demo/https.howto/server.pem b/demo/https.howto/server.pem deleted file mode 100644 index bcd826c..0000000 --- a/demo/https.howto/server.pem +++ /dev/null @@ -1,74 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 1 (0x1) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, ST=CA, O=M2Crypto CA, CN=localhost - Validity - Not Before: Apr 22 04:36:56 2006 GMT - Not After : Apr 22 04:36:56 2007 GMT - Subject: C=US, ST=CA, O=M2Crypto Server, CN=localhost - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public Key: (1024 bit) - Modulus (1024 bit): - 00:a5:cc:39:ad:ba:81:3d:bd:05:f4:61:50:9f:9c: - f6:ad:ec:29:d9:78:1e:24:61:f7:1b:36:bf:69:d8: - b3:45:ae:6f:3a:4c:4f:d6:13:6d:60:8d:f2:bb:2a: - c4:1b:79:fd:e2:f8:d6:3c:56:53:3b:27:f7:3f:70: - a4:64:99:63:46:2e:3f:ef:52:da:a9:04:5b:6e:d4: - 40:57:c5:59:61:d3:3f:7d:b8:03:c1:9b:65:46:2a: - c5:9d:70:b7:ca:79:6e:dd:e4:3f:c2:f4:2f:2e:81: - 32:c8:e9:a6:b6:a8:c8:1f:48:be:7a:66:56:98:fc: - 3c:25:fc:d9:3d:73:07:30:71 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:FALSE - Netscape Comment: - OpenSSL Generated Certificate - X509v3 Subject Key Identifier: - F0:48:3A:32:88:8C:80:D7:22:AB:56:F8:86:B3:04:47:10:76:37:BE - X509v3 Authority Key Identifier: - keyid:5C:F9:C5:9B:B0:02:37:3C:66:73:4D:0E:CB:5A:3D:BB:3A:46:22:DD - - Signature Algorithm: sha1WithRSAEncryption - 39:47:95:5c:ea:7e:db:b8:e0:80:f6:e5:d4:9f:83:bc:41:89: - 31:97:c8:a4:95:0d:5d:6d:cc:64:8d:19:71:17:75:4b:7f:fb: - 35:88:bf:68:e2:a2:be:c5:71:71:56:2a:92:31:25:2a:4b:98: - 4e:77:42:45:78:45:21:a5:76:99:92:39:32:7d:a2:4c:38:b0: - f1:db:7f:d1:4d:23:99:35:1e:0e:a1:59:a3:ff:9c:51:ef:4c: - 11:c9:32:61:38:11:7d:57:2a:81:9a:96:1f:b3:88:f7:ab:5b: - 58:f7:79:9b:a8:e3:b7:09:90:8e:c9:7d:44:4f:af:85:dc:c8: - 29:4d ------BEGIN CERTIFICATE----- -MIICfTCCAeagAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEL -MAkGA1UECBMCQ0ExFDASBgNVBAoTC00yQ3J5cHRvIENBMRIwEAYDVQQDEwlsb2Nh -bGhvc3QwHhcNMDYwNDIyMDQzNjU2WhcNMDcwNDIyMDQzNjU2WjBIMQswCQYDVQQG -EwJVUzELMAkGA1UECBMCQ0ExGDAWBgNVBAoTD00yQ3J5cHRvIFNlcnZlcjESMBAG -A1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClzDmt -uoE9vQX0YVCfnPat7CnZeB4kYfcbNr9p2LNFrm86TE/WE21gjfK7KsQbef3i+NY8 -VlM7J/c/cKRkmWNGLj/vUtqpBFtu1EBXxVlh0z99uAPBm2VGKsWdcLfKeW7d5D/C -9C8ugTLI6aa2qMgfSL56ZlaY/Dwl/Nk9cwcwcQIDAQABo3sweTAJBgNVHRMEAjAA -MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd -BgNVHQ4EFgQU8Eg6MoiMgNciq1b4hrMERxB2N74wHwYDVR0jBBgwFoAUXPnFm7AC -Nzxmc00Oy1o9uzpGIt0wDQYJKoZIhvcNAQEFBQADgYEAOUeVXOp+27jggPbl1J+D -vEGJMZfIpJUNXW3MZI0ZcRd1S3/7NYi/aOKivsVxcVYqkjElKkuYTndCRXhFIaV2 -mZI5Mn2iTDiw8dt/0U0jmTUeDqFZo/+cUe9MEckyYTgRfVcqgZqWH7OI96tbWPd5 -m6jjtwmQjsl9RE+vhdzIKU0= ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQClzDmtuoE9vQX0YVCfnPat7CnZeB4kYfcbNr9p2LNFrm86TE/W -E21gjfK7KsQbef3i+NY8VlM7J/c/cKRkmWNGLj/vUtqpBFtu1EBXxVlh0z99uAPB -m2VGKsWdcLfKeW7d5D/C9C8ugTLI6aa2qMgfSL56ZlaY/Dwl/Nk9cwcwcQIDAQAB -AoGBAIwzbZbePsnxXOaxoBbJCcQ7D4yJSZvkh6womKauC7Lh9carn1tc5EIg5uCl -Il5Fw466c5dkPE+q1SZ9X1Z+avYh4ypHjpcr1Lfvwo0wfOBx5MBj6ppMdwgrMXuo -jRChK3gBZXmKaIH19h/sGp/lZRW2HiX63aN11KDmtfwo6Bq9AkEA2OftYJUqceK3 -/E8q6OE1oQLm+oK6CPZ29A5TRNOadRu1opDR/y59GcUQ5ebJNH8DXyF82lSi3DKt -SNoSOF32cwJBAMOuKGUAwnq1yH3q+MAF7CZjGou7Ar6VRseyLnD5nttynT85QRW8 -N/WCosKLhV7wi9kKJmHGUJfRAqdo14D8IIsCQQCVjrU6FyABDpZVvjCUClT0BBBH -QsQLUgWLGiWIG28wuD5xLPHexas0jZCtNIgfTkSA35I66Iiy065vwQ03GHLJAkAG -eGC/jjngAtjBSR62grufPVGoYyOhF6CCg+LDO43EJdMLPyJmzJVxGcO1+RUM4ZlO -MOa5/uu1SWT0EiRmEHAnAkBusVcHcd6d4uaoiCybIhF4hL4GsbKoImIciakNlteA -c1RZZHc2jzO/Ihoz50H1njXwY86YbjncOXw8shtayd8j ------END RSA PRIVATE KEY----- diff --git a/demo/medusa/00_README b/demo/medusa/00_README deleted file mode 100644 index 1f0ce36..0000000 --- a/demo/medusa/00_README +++ /dev/null @@ -1,32 +0,0 @@ - - 19 Sep 2001 -------------- - -M2Crypto HTTPS and FTP/TLS servers - -All the files in this directory are from the Apr 2001 release -of Medusa, except for the following: - -- 00_README (this file) -- server.pem, the server's certificate -- ca.pem, my CA certificate -- https_server.py -- ftps_server.py -- START.py -- START_xmlrpc.py -- index.html, a sample HTML file -- poison_handler.py, a webpoison clone - -By default, http_server listens on port 9080 and https_server port 9443. -Document root is current directory, and serves up index.html. - -The xmlrpc server is accessible below '/RPC2'. It requires Fredrik Lundh's -xmlrpc_handler on PYTHONPATH. - -The FTP/TLS server listens on port 9021 by default. I've only tested it with -the 'anonymous' authentication handler. - -Medusa files are copyright Sam Rushing. My files are copyright me. - - - diff --git a/demo/medusa/START.py b/demo/medusa/START.py deleted file mode 100644 index 62021f7..0000000 --- a/demo/medusa/START.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python - -# Standard Python library -import os -import os.path -import sys - -# Medusa -import asyncore -import default_handler -import filesys -import ftp_server -import http_server -import status_handler - -# M2Crypto -import https_server -import poison_handler -import ftps_server -from M2Crypto import Rand, SSL, threading - -HTTP_PORT=9080 -HTTPS_PORT=9443 -FTP_PORT = 9021 - -hs=http_server.http_server('', HTTP_PORT) - -Rand.load_file('../randpool.dat', -1) -ssl_ctx=SSL.Context('sslv23') -ssl_ctx.load_cert('server.pem') -ssl_ctx.load_verify_location('ca.pem') -ssl_ctx.load_client_CA('ca.pem') -#ssl_ctx.set_verify(SSL.verify_peer, 10) -#ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) -#ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_client_once, 10) -ssl_ctx.set_verify(SSL.verify_none, 10) -ssl_ctx.set_session_id_ctx('127.0.0.1:9443') -ssl_ctx.set_tmp_dh('dh1024.pem') -ssl_ctx.set_info_callback() - -hss=https_server.https_server('', HTTPS_PORT, ssl_ctx) - -#fs=filesys.os_filesystem(os.path.abspath(os.curdir)) -fs=filesys.os_filesystem('/usr/local/pkg/apache/htdocs') -#fs=filesys.os_filesystem('c:/pkg/jdk130/docs') -dh=default_handler.default_handler(fs) -hs.install_handler(dh) -hss.install_handler(dh) - -#class rpc_demo (xmlrpc_handler.xmlrpc_handler): -# def call (self, method, params): -# print 'method="%s" params=%s' % (method, params) -# return "Sure, that works" -#rpch = rpc_demo() -#hs.install_handler(rpch) -#hss.install_handler(rpch) - -ph=poison_handler.poison_handler(10) -hs.install_handler(ph) -hss.install_handler(ph) - -fauthz = ftp_server.anon_authorizer('/usr/local/pkg/apache/htdocs') -ftps = ftps_server.ftp_tls_server(fauthz, ssl_ctx, port=FTP_PORT) - -sh=status_handler.status_extension([hs, hss, ftps]) -hs.install_handler(sh) -hss.install_handler(sh) - -asyncore.loop() -Rand.save_file('../randpool.dat') - diff --git a/demo/medusa/START_xmlrpc.py b/demo/medusa/START_xmlrpc.py deleted file mode 100644 index 193e8bf..0000000 --- a/demo/medusa/START_xmlrpc.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python - -# Standard Python library -import os -import os.path -import sys - -# Medusa -import asyncore -import default_handler -import filesys -import http_server -import status_handler - -# M2Crypto -import https_server -import poison_handler -from M2Crypto import Rand, SSL - -# XMLrpc -import xmlrpc_handler - - -HTTP_PORT=9080 -HTTPS_PORT=9443 - -hs=http_server.http_server('', HTTP_PORT) - -Rand.load_file('../randpool.dat', -1) -ssl_ctx=SSL.Context('sslv23') -ssl_ctx.load_cert('server.pem') -#ssl_ctx.load_verify_location('ca.pem') -#ssl_ctx.load_client_CA('ca.pem') -#ssl_ctx.set_verify(SSL.verify_peer, 10) -#ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) -#ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_client_once, 10) -ssl_ctx.set_verify(SSL.verify_none, 10) -ssl_ctx.set_session_id_ctx('127.0.0.1:9443') -ssl_ctx.set_tmp_dh('dh1024.pem') -#ssl_ctx.set_info_callback() - -hss=https_server.https_server('', HTTPS_PORT, ssl_ctx) - -#fs=filesys.os_filesystem(os.path.abspath(os.curdir)) -fs=filesys.os_filesystem('/usr/local/pkg/apache/htdocs') -#fs=filesys.os_filesystem('c:/pkg/jdk118/docs') -dh=default_handler.default_handler(fs) -hs.install_handler(dh) -hss.install_handler(dh) - -# Cribbed from xmlrpc_handler.py. -# This is where you implement your RPC functionality. -class rpc_demo (xmlrpc_handler.xmlrpc_handler): - def call (self, method, params): - print 'method="%s" params=%s' % (method, params) - return "Sure, that works" - -rpch = rpc_demo() -hs.install_handler(rpch) -hss.install_handler(rpch) - -ph=poison_handler.poison_handler(10) -hs.install_handler(ph) -hss.install_handler(ph) - -sh=status_handler.status_extension([hss]) -hs.install_handler(sh) -hss.install_handler(sh) - -asyncore.loop() -Rand.save_file('../randpool.dat') - diff --git a/demo/medusa/asynchat.py b/demo/medusa/asynchat.py deleted file mode 100644 index 2e51f1a..0000000 --- a/demo/medusa/asynchat.py +++ /dev/null @@ -1,292 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- -# $Id: asynchat.py 299 2005-06-09 17:32:28Z heikki $ -# Author: Sam Rushing - -# ====================================================================== -# Copyright 1996 by Sam Rushing -# -# All Rights Reserved -# -# Permission to use, copy, modify, and distribute this software and -# its documentation for any purpose and without fee is hereby -# granted, provided that the above copyright notice appear in all -# copies and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of Sam -# Rushing not be used in advertising or publicity pertaining to -# distribution of the software without specific, written prior -# permission. -# -# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN -# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# ====================================================================== - -"""A class supporting chat-style (command/response) protocols. - -This class adds support for 'chat' style protocols - where one side -sends a 'command', and the other sends a response (examples would be -the common internet protocols - smtp, nntp, ftp, etc..). - -The handle_read() method looks at the input stream for the current -'terminator' (usually '\r\n' for single-line responses, '\r\n.\r\n' -for multi-line output), calling self.found_terminator() on its -receipt. - -for example: -Say you build an async nntp client using this class. At the start -of the connection, you'll have self.terminator set to '\r\n', in -order to process the single-line greeting. Just before issuing a -'LIST' command you'll set it to '\r\n.\r\n'. The output of the LIST -command will be accumulated (using your own 'collect_incoming_data' -method) up to the terminator, and then control will be returned to -you - by calling your self.found_terminator() method. -""" - -import socket -import asyncore -import string - -class async_chat (asyncore.dispatcher): - """This is an abstract class. You must derive from this class, and add - the two methods collect_incoming_data() and found_terminator()""" - - # these are overridable defaults - - ac_in_buffer_size = 4096 - ac_out_buffer_size = 4096 - - def __init__ (self, conn=None): - self.ac_in_buffer = '' - self.ac_out_buffer = '' - self.producer_fifo = fifo() - asyncore.dispatcher.__init__ (self, conn) - - def set_terminator (self, term): - "Set the input delimiter. Can be a fixed string of any length, an integer, or None" - self.terminator = term - - def get_terminator (self): - return self.terminator - - # grab some more data from the socket, - # throw it to the collector method, - # check for the terminator, - # if found, transition to the next state. - - def handle_read (self): - - try: - data = self.recv (self.ac_in_buffer_size) - except socket.error, why: - self.handle_error() - return - - self.ac_in_buffer = self.ac_in_buffer + data - - # Continue to search for self.terminator in self.ac_in_buffer, - # while calling self.collect_incoming_data. The while loop - # is necessary because we might read several data+terminator - # combos with a single recv(1024). - - while self.ac_in_buffer: - lb = len(self.ac_in_buffer) - terminator = self.get_terminator() - if terminator is None: - # no terminator, collect it all - self.collect_incoming_data (self.ac_in_buffer) - self.ac_in_buffer = '' - elif type(terminator) == type(0): - # numeric terminator - n = terminator - if lb < n: - self.collect_incoming_data (self.ac_in_buffer) - self.ac_in_buffer = '' - self.terminator = self.terminator - lb - else: - self.collect_incoming_data (self.ac_in_buffer[:n]) - self.ac_in_buffer = self.ac_in_buffer[n:] - self.terminator = 0 - self.found_terminator() - else: - # 3 cases: - # 1) end of buffer matches terminator exactly: - # collect data, transition - # 2) end of buffer matches some prefix: - # collect data to the prefix - # 3) end of buffer does not match any prefix: - # collect data - terminator_len = len(terminator) - index = string.find (self.ac_in_buffer, terminator) - if index != -1: - # we found the terminator - if index > 0: - # don't bother reporting the empty string (source of subtle bugs) - self.collect_incoming_data (self.ac_in_buffer[:index]) - self.ac_in_buffer = self.ac_in_buffer[index+terminator_len:] - # This does the Right Thing if the terminator is changed here. - self.found_terminator() - else: - # check for a prefix of the terminator - index = find_prefix_at_end (self.ac_in_buffer, terminator) - if index: - if index != lb: - # we found a prefix, collect up to the prefix - self.collect_incoming_data (self.ac_in_buffer[:-index]) - self.ac_in_buffer = self.ac_in_buffer[-index:] - break - else: - # no prefix, collect it all - self.collect_incoming_data (self.ac_in_buffer) - self.ac_in_buffer = '' - - def handle_write (self): - self.initiate_send () - - def handle_close (self): - self.close() - - def push (self, data): - self.producer_fifo.push (simple_producer (data)) - self.initiate_send() - - def push_with_producer (self, producer): - self.producer_fifo.push (producer) - self.initiate_send() - - def readable (self): - "predicate for inclusion in the readable for select()" - return (len(self.ac_in_buffer) <= self.ac_in_buffer_size) - - def writable (self): - "predicate for inclusion in the writable for select()" - # return len(self.ac_out_buffer) or len(self.producer_fifo) or (not self.connected) - # this is about twice as fast, though not as clear. - return not ( - (self.ac_out_buffer is '') and - self.producer_fifo.is_empty() and - self.connected - ) - - def close_when_done (self): - "automatically close this channel once the outgoing queue is empty" - self.producer_fifo.push (None) - - # refill the outgoing buffer by calling the more() method - # of the first producer in the queue - def refill_buffer (self): - _string_type = type('') - while 1: - if len(self.producer_fifo): - p = self.producer_fifo.first() - # a 'None' in the producer fifo is a sentinel, - # telling us to close the channel. - if p is None: - if not self.ac_out_buffer: - self.producer_fifo.pop() - self.close() - return - elif type(p) is _string_type: - self.producer_fifo.pop() - self.ac_out_buffer = self.ac_out_buffer + p - return - data = p.more() - if data: - self.ac_out_buffer = self.ac_out_buffer + data - return - else: - self.producer_fifo.pop() - else: - return - - def initiate_send (self): - obs = self.ac_out_buffer_size - # try to refill the buffer - if (len (self.ac_out_buffer) < obs): - self.refill_buffer() - - if self.ac_out_buffer and self.connected: - # try to send the buffer - try: - num_sent = self.send (self.ac_out_buffer[:obs]) - if num_sent: - self.ac_out_buffer = self.ac_out_buffer[num_sent:] - - except socket.error, why: - self.handle_error() - return - - def discard_buffers (self): - # Emergencies only! - self.ac_in_buffer = '' - self.ac_out_buffer = '' - while self.producer_fifo: - self.producer_fifo.pop() - - -class simple_producer: - - def __init__ (self, data, buffer_size=512): - self.data = data - self.buffer_size = buffer_size - - def more (self): - if len (self.data) > self.buffer_size: - result = self.data[:self.buffer_size] - self.data = self.data[self.buffer_size:] - return result - else: - result = self.data - self.data = '' - return result - -class fifo: - def __init__ (self, list=None): - if not list: - self.list = [] - else: - self.list = list - - def __len__ (self): - return len(self.list) - - def is_empty (self): - return self.list == [] - - def first (self): - return self.list[0] - - def push (self, data): - self.list.append (data) - - def pop (self): - if self.list: - result = self.list[0] - del self.list[0] - return (1, result) - else: - return (0, None) - -# Given 'haystack', see if any prefix of 'needle' is at its end. This -# assumes an exact match has already been checked. Return the number of -# characters matched. -# for example: -# f_p_a_e ("qwerty\r", "\r\n") => 1 -# f_p_a_e ("qwertydkjf", "\r\n") => 0 -# f_p_a_e ("qwerty\r\n", "\r\n") => - -# this could maybe be made faster with a computed regex? -# [answer: no; circa Python-2.0, Jan 2001] -# new python: 28961/s -# old python: 18307/s -# re: 12820/s -# regex: 14035/s - -def find_prefix_at_end (haystack, needle): - l = len(needle) - 1 - while l and not haystack.endswith(needle[:l]): - l -= 1 - return l diff --git a/demo/medusa/asyncore.py b/demo/medusa/asyncore.py deleted file mode 100644 index 7f751aa..0000000 --- a/demo/medusa/asyncore.py +++ /dev/null @@ -1,552 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- -# $Id: asyncore.py 299 2005-06-09 17:32:28Z heikki $ -# Author: Sam Rushing - -# ====================================================================== -# Copyright 1996 by Sam Rushing -# -# All Rights Reserved -# -# Permission to use, copy, modify, and distribute this software and -# its documentation for any purpose and without fee is hereby -# granted, provided that the above copyright notice appear in all -# copies and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of Sam -# Rushing not be used in advertising or publicity pertaining to -# distribution of the software without specific, written prior -# permission. -# -# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN -# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# ====================================================================== - -"""Basic infrastructure for asynchronous socket service clients and servers. - -There are only two ways to have a program on a single processor do "more -than one thing at a time". Multi-threaded programming is the simplest and -most popular way to do it, but there is another very different technique, -that lets you have nearly all the advantages of multi-threading, without -actually using multiple threads. it's really only practical if your program -is largely I/O bound. If your program is CPU bound, then pre-emptive -scheduled threads are probably what you really need. Network servers are -rarely CPU-bound, however. - -If your operating system supports the select() system call in its I/O -library (and nearly all do), then you can use it to juggle multiple -communication channels at once; doing other work while your I/O is taking -place in the "background." Although this strategy can seem strange and -complex, especially at first, it is in many ways easier to understand and -control than multi-threaded programming. The module documented here solves -many of the difficult problems for you, making the task of building -sophisticated high-performance network servers and clients a snap. -""" - -import exceptions -import select -import socket -import string -import sys - -import os -if os.name == 'nt': - EWOULDBLOCK = 10035 - EINPROGRESS = 10036 - EALREADY = 10037 - ECONNRESET = 10054 - ENOTCONN = 10057 - ESHUTDOWN = 10058 -else: - from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN - -try: - socket_map -except NameError: - socket_map = {} - -class ExitNow (exceptions.Exception): - pass - -DEBUG = 0 - -def poll (timeout=0.0, map=None): - global DEBUG - if map is None: - map = socket_map - if map: - r = []; w = []; e = [] - for fd, obj in map.items(): - if obj.readable(): - r.append (fd) - if obj.writable(): - w.append (fd) - r,w,e = select.select (r,w,e, timeout) - - if DEBUG: - print r,w,e - - for fd in r: - try: - obj = map[fd] - try: - obj.handle_read_event() - except ExitNow: - raise ExitNow - except: - obj.handle_error() - except KeyError: - pass - - for fd in w: - try: - obj = map[fd] - try: - obj.handle_write_event() - except ExitNow: - raise ExitNow - except: - obj.handle_error() - except KeyError: - pass - -def poll2 (timeout=0.0, map=None): - import poll - if map is None: - map=socket_map - # timeout is in milliseconds - timeout = int(timeout*1000) - if map: - l = [] - for fd, obj in map.items(): - flags = 0 - if obj.readable(): - flags = poll.POLLIN - if obj.writable(): - flags = flags | poll.POLLOUT - if flags: - l.append ((fd, flags)) - r = poll.poll (l, timeout) - for fd, flags in r: - try: - obj = map[fd] - try: - if (flags & poll.POLLIN): - obj.handle_read_event() - if (flags & poll.POLLOUT): - obj.handle_write_event() - except ExitNow: - raise ExitNow - except: - obj.handle_error() - except KeyError: - pass - -def poll3 (timeout=0.0, map=None): - # Use the poll() support added to the select module in Python 2.0 - if map is None: - map=socket_map - # timeout is in milliseconds - timeout = int(timeout*1000) - pollster = select.poll() - if map: - l = [] - for fd, obj in map.items(): - flags = 0 - if obj.readable(): - flags = select.POLLIN - if obj.writable(): - flags = flags | select.POLLOUT - if flags: - pollster.register(fd, flags) - r = pollster.poll (timeout) - for fd, flags in r: - try: - obj = map[fd] - try: - if (flags & select.POLLIN): - obj.handle_read_event() - if (flags & select.POLLOUT): - obj.handle_write_event() - except ExitNow: - raise ExitNow - except: - obj.handle_error() - except KeyError: - pass - -def loop (timeout=30.0, use_poll=0, map=None): - - if use_poll: - if hasattr (select, 'poll'): - poll_fun = poll3 - else: - poll_fun = poll2 - else: - poll_fun = poll - - if map is None: - map=socket_map - - while map: - poll_fun (timeout, map) - -class dispatcher: - debug = 0 - connected = 0 - accepting = 0 - closing = 0 - addr = None - - def __init__ (self, sock=None, map=None): - if sock: - self.set_socket (sock, map) - # I think it should inherit this anyway - self.socket.setblocking (0) - self.connected = 1 - - def __repr__ (self): - try: - status = [] - if self.accepting and self.addr: - status.append ('listening') - elif self.connected: - status.append ('connected') - if self.addr: - status.append ('%s:%d' % self.addr) - return '<%s %s at %x>' % ( - self.__class__.__name__, - string.join (status, ' '), - id(self) - ) - except: - try: - ar = repr(self.addr) - except: - ar = 'no self.addr!' - - return '<__repr__ (self) failed for object at %x (addr=%s)>' % (id(self),ar) - - def add_channel (self, map=None): - #self.log_info ('adding channel %s' % self) - if map is None: - map=socket_map - map [self._fileno] = self - - def del_channel (self, map=None): - fd = self._fileno - if map is None: - map=socket_map - if map.has_key (fd): - #self.log_info ('closing channel %d:%s' % (fd, self)) - del map [fd] - - def create_socket (self, family, type): - self.family_and_type = family, type - self.socket = socket.socket (family, type) - self.socket.setblocking(0) - self._fileno = self.socket.fileno() - self.add_channel() - - def set_socket (self, sock, map=None): - self.__dict__['socket'] = sock - self._fileno = sock.fileno() - self.add_channel (map) - - def set_reuse_addr (self): - # try to re-use a server port if possible - try: - self.socket.setsockopt ( - socket.SOL_SOCKET, socket.SO_REUSEADDR, - self.socket.getsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR) | 1 - ) - except: - pass - - # ================================================== - # predicates for select() - # these are used as filters for the lists of sockets - # to pass to select(). - # ================================================== - - def readable (self): - return 1 - - if os.name == 'mac': - # The macintosh will select a listening socket for - # write if you let it. What might this mean? - def writable (self): - return not self.accepting - else: - def writable (self): - return 1 - - # ================================================== - # socket object methods. - # ================================================== - - def listen (self, num): - self.accepting = 1 - if os.name == 'nt' and num > 5: - num = 1 - return self.socket.listen (num) - - def bind (self, addr): - self.addr = addr - return self.socket.bind (addr) - - def connect (self, address): - self.connected = 0 - try: - self.socket.connect (address) - except socket.error, why: - if why[0] in (EINPROGRESS, EALREADY, EWOULDBLOCK): - return - else: - raise socket.error, why - self.connected = 1 - self.handle_connect() - - def accept (self): - try: - conn, addr = self.socket.accept() - return conn, addr - except socket.error, why: - if why[0] == EWOULDBLOCK: - pass - else: - raise socket.error, why - - def send (self, data): - try: - result = self.socket.send (data) - return result - except socket.error, why: - if why[0] == EWOULDBLOCK: - return 0 - else: - raise socket.error, why - return 0 - - def recv (self, buffer_size): - try: - data = self.socket.recv (buffer_size) - if not data: - # a closed connection is indicated by signaling - # a read condition, and having recv() return 0. - self.handle_close() - return '' - else: - return data - except socket.error, why: - # winsock sometimes throws ENOTCONN - if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]: - self.handle_close() - return '' - else: - raise socket.error, why - - def close (self): - self.del_channel() - self.socket.close() - - # cheap inheritance, used to pass all other attribute - # references to the underlying socket object. - def __getattr__ (self, attr): - return getattr (self.socket, attr) - - # log and log_info maybe overriden to provide more sophisitcated - # logging and warning methods. In general, log is for 'hit' logging - # and 'log_info' is for informational, warning and error logging. - - def log (self, message): - sys.stderr.write ('log: %s\n' % str(message)) - - def log_info (self, message, type='info'): - if __debug__ or type != 'info': - print '%s: %s' % (type, message) - - def handle_read_event (self): - if self.accepting: - # for an accepting socket, getting a read implies - # that we are connected - if not self.connected: - self.connected = 1 - self.handle_accept() - elif not self.connected: - self.handle_connect() - self.connected = 1 - self.handle_read() - else: - self.handle_read() - - def handle_write_event (self): - # getting a write implies that we are connected - if not self.connected: - self.handle_connect() - self.connected = 1 - self.handle_write() - - def handle_expt_event (self): - self.handle_expt() - - def handle_error (self): - (file,fun,line), t, v, tbinfo = compact_traceback() - - # sometimes a user repr method will crash. - try: - self_repr = repr (self) - except: - self_repr = '<__repr__ (self) failed for object at %0x>' % id(self) - - self.log_info ( - 'uncaptured python exception, closing channel %s (%s:%s %s)' % ( - self_repr, - t, - v, - tbinfo - ), - 'error' - ) - self.close() - - def handle_expt (self): - self.log_info ('unhandled exception', 'warning') - - def handle_read (self): - self.log_info ('unhandled read event', 'warning') - - def handle_write (self): - self.log_info ('unhandled write event', 'warning') - - def handle_connect (self): - self.log_info ('unhandled connect event', 'warning') - - def handle_accept (self): - self.log_info ('unhandled accept event', 'warning') - - def handle_close (self): - self.log_info ('unhandled close event', 'warning') - self.close() - -# --------------------------------------------------------------------------- -# adds simple buffered output capability, useful for simple clients. -# [for more sophisticated usage use asynchat.async_chat] -# --------------------------------------------------------------------------- - -class dispatcher_with_send (dispatcher): - def __init__ (self, sock=None): - dispatcher.__init__ (self, sock) - self.out_buffer = '' - - def initiate_send (self): - num_sent = 0 - num_sent = dispatcher.send (self, self.out_buffer[:512]) - self.out_buffer = self.out_buffer[num_sent:] - - def handle_write (self): - self.initiate_send() - - def writable (self): - return (not self.connected) or len(self.out_buffer) - - def send (self, data): - if self.debug: - self.log_info ('sending %s' % repr(data)) - self.out_buffer = self.out_buffer + data - self.initiate_send() - -# --------------------------------------------------------------------------- -# used for debugging. -# --------------------------------------------------------------------------- - -def compact_traceback (): - t,v,tb = sys.exc_info() - tbinfo = [] - while 1: - tbinfo.append (( - tb.tb_frame.f_code.co_filename, - tb.tb_frame.f_code.co_name, - str(tb.tb_lineno) - )) - tb = tb.tb_next - if not tb: - break - - # just to be safe - del tb - - file, function, line = tbinfo[-1] - info = '[' + string.join ( - map ( - lambda x: string.join (x, '|'), - tbinfo - ), - '] [' - ) + ']' - return (file, function, line), t, v, info - -def close_all (map=None): - if map is None: - map=socket_map - for x in map.values(): - x.socket.close() - map.clear() - -# Asynchronous File I/O: -# -# After a little research (reading man pages on various unixen, and -# digging through the linux kernel), I've determined that select() -# isn't meant for doing doing asynchronous file i/o. -# Heartening, though - reading linux/mm/filemap.c shows that linux -# supports asynchronous read-ahead. So _MOST_ of the time, the data -# will be sitting in memory for us already when we go to read it. -# -# What other OS's (besides NT) support async file i/o? [VMS?] -# -# Regardless, this is useful for pipes, and stdin/stdout... - -import os -if os.name == 'posix': - import fcntl - import FCNTL - - class file_wrapper: - # here we override just enough to make a file - # look like a socket for the purposes of asyncore. - def __init__ (self, fd): - self.fd = fd - - def recv (self, *args): - return apply (os.read, (self.fd,)+args) - - def send (self, *args): - return apply (os.write, (self.fd,)+args) - - read = recv - write = send - - def close (self): - return os.close (self.fd) - - def fileno (self): - return self.fd - - class file_dispatcher (dispatcher): - def __init__ (self, fd): - dispatcher.__init__ (self) - self.connected = 1 - # set it to non-blocking mode - flags = fcntl.fcntl (fd, FCNTL.F_GETFL, 0) - flags = flags | FCNTL.O_NONBLOCK - fcntl.fcntl (fd, FCNTL.F_SETFL, flags) - self.set_file (fd) - - def set_file (self, fd): - self._fileno = fd - self.socket = file_wrapper (fd) - self.add_channel() - diff --git a/demo/medusa/auth_handler.py b/demo/medusa/auth_handler.py deleted file mode 100644 index 70eaf3c..0000000 --- a/demo/medusa/auth_handler.py +++ /dev/null @@ -1,135 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- -# -# Author: Sam Rushing -# Copyright 1996-2000 by Sam Rushing -# All Rights Reserved. -# - -# support for 'basic' authenticaion. - -import base64 -import md5 -import re -import string -import time -import counter - -import default_handler - -get_header = default_handler.get_header - -import http_server -import producers - -# This is a 'handler' that wraps an authorization method -# around access to the resources normally served up by -# another handler. - -# does anyone support digest authentication? (rfc2069) - -class auth_handler: - def __init__ (self, dict, handler, realm='default'): - self.authorizer = dictionary_authorizer (dict) - self.handler = handler - self.realm = realm - self.pass_count = counter.counter() - self.fail_count = counter.counter() - - def match (self, request): - # by default, use the given handler's matcher - return self.handler.match (request) - - def handle_request (self, request): - # authorize a request before handling it... - scheme = get_header (AUTHORIZATION, request.header) - - if scheme: - scheme = string.lower (scheme) - if scheme == 'basic': - cookie = AUTHORIZATION.group(2) - try: - decoded = base64.decodestring (cookie) - except: - print 'malformed authorization info <%s>' % cookie - request.error (400) - return - auth_info = string.split (decoded, ':') - if self.authorizer.authorize (auth_info): - self.pass_count.increment() - request.auth_info = auth_info - self.handler.handle_request (request) - else: - self.handle_unauthorized (request) - #elif scheme == 'digest': - # print 'digest: ',AUTHORIZATION.group(2) - else: - print 'unknown/unsupported auth method: %s' % scheme - self.handle_unauthorized() - else: - # list both? prefer one or the other? - # you could also use a 'nonce' here. [see below] - #auth = 'Basic realm="%s" Digest realm="%s"' % (self.realm, self.realm) - #nonce = self.make_nonce (request) - #auth = 'Digest realm="%s" nonce="%s"' % (self.realm, nonce) - #request['WWW-Authenticate'] = auth - #print 'sending header: %s' % request['WWW-Authenticate'] - self.handle_unauthorized (request) - - def handle_unauthorized (self, request): - # We are now going to receive data that we want to ignore. - # to ignore the file data we're not interested in. - self.fail_count.increment() - request.channel.set_terminator (None) - request['Connection'] = 'close' - request['WWW-Authenticate'] = 'Basic realm="%s"' % self.realm - request.error (401) - - def make_nonce (self, request): - "A digest-authentication , constructed as suggested in RFC 2069" - ip = request.channel.server.ip - now = str (long (time.time()))[:-1] - private_key = str (id (self)) - nonce = string.join ([ip, now, private_key], ':') - return self.apply_hash (nonce) - - def apply_hash (self, s): - "Apply MD5 to a string , then wrap it in base64 encoding." - m = md5.new() - m.update (s) - d = m.digest() - # base64.encodestring tacks on an extra linefeed. - return base64.encodestring (d)[:-1] - - def status (self): - # Thanks to mwm@contessa.phone.net (Mike Meyer) - r = [ - producers.simple_producer ( - '
  • Authorization Extension : ' - 'Unauthorized requests: %s
      ' % self.fail_count - ) - ] - if hasattr (self.handler, 'status'): - r.append (self.handler.status()) - r.append ( - producers.simple_producer ('
    ') - ) - return producers.composite_producer ( - http_server.fifo (r) - ) - -class dictionary_authorizer: - def __init__ (self, dict): - self.dict = dict - - def authorize (self, auth_info): - [username, password] = auth_info - if (self.dict.has_key (username)) and (self.dict[username] == password): - return 1 - else: - return 0 - -AUTHORIZATION = re.compile ( - # scheme challenge - 'Authorization: ([^ ]+) (.*)', - re.IGNORECASE - ) diff --git a/demo/medusa/ca.pem b/demo/medusa/ca.pem deleted file mode 100644 index b7c84a1..0000000 --- a/demo/medusa/ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 -NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML -TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl -cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK -q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N -e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf -q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G -A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV -BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex -JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 -DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG -SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ -dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J -vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf ------END CERTIFICATE----- diff --git a/demo/medusa/counter.py b/demo/medusa/counter.py deleted file mode 100644 index 997d687..0000000 --- a/demo/medusa/counter.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- - -# It is tempting to add an __int__ method to this class, but it's not -# a good idea. This class tries to gracefully handle integer -# overflow, and to hide this detail from both the programmer and the -# user. Note that the __str__ method can be relied on for printing out -# the value of a counter: -# -# >>> print 'Total Client: %s' % self.total_clients -# -# If you need to do arithmetic with the value, then use the 'as_long' -# method, the use of long arithmetic is a reminder that the counter -# will overflow. - -class counter: - "general-purpose counter" - - def __init__ (self, initial_value=0): - self.value = initial_value - - def increment (self, delta=1): - result = self.value - try: - self.value = self.value + delta - except OverflowError: - self.value = long(self.value) + delta - return result - - def decrement (self, delta=1): - result = self.value - try: - self.value = self.value - delta - except OverflowError: - self.value = long(self.value) - delta - return result - - def as_long (self): - return long(self.value) - - def __nonzero__ (self): - return self.value != 0 - - def __repr__ (self): - return '' % (self.value, id(self)) - - def __str__ (self): - return str(long(self.value)) - #return str(long(self.value))[:-1] diff --git a/demo/medusa/default_handler.py b/demo/medusa/default_handler.py deleted file mode 100644 index 4585b0f..0000000 --- a/demo/medusa/default_handler.py +++ /dev/null @@ -1,215 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- -# -# Author: Sam Rushing -# Copyright 1997 by Sam Rushing -# All Rights Reserved. -# - -# standard python modules -import os -import re -import posixpath -import stat -import string -import time - -# medusa modules -import http_date -import http_server -import mime_type_table -import status_handler -import producers - -unquote = http_server.unquote - -# This is the 'default' handler. it implements the base set of -# features expected of a simple file-delivering HTTP server. file -# services are provided through a 'filesystem' object, the very same -# one used by the FTP server. -# -# You can replace or modify this handler if you want a non-standard -# HTTP server. You can also derive your own handler classes from -# it. -# -# support for handling POST requests is available in the derived -# class , defined below. -# - -from counter import counter - -class default_handler: - - valid_commands = ['get', 'head'] - - IDENT = 'Default HTTP Request Handler' - - # Pathnames that are tried when a URI resolves to a directory name - directory_defaults = [ - 'index.html', - 'default.html' - ] - - default_file_producer = producers.file_producer - - def __init__ (self, filesystem): - self.filesystem = filesystem - # count total hits - self.hit_counter = counter() - # count file deliveries - self.file_counter = counter() - # count cache hits - self.cache_counter = counter() - - hit_counter = 0 - - def __repr__ (self): - return '<%s (%s hits) at %x>' % ( - self.IDENT, - self.hit_counter, - id (self) - ) - - # always match, since this is a default - def match (self, request): - return 1 - - # handle a file request, with caching. - - def handle_request (self, request): - - if request.command not in self.valid_commands: - request.error (400) # bad request - return - - self.hit_counter.increment() - - path, params, query, fragment = request.split_uri() - - if '%' in path: - path = unquote (path) - - # strip off all leading slashes - while path and path[0] == '/': - path = path[1:] - - if self.filesystem.isdir (path): - if path and path[-1] != '/': - request['Location'] = 'http://%s/%s/' % ( - request.channel.server.server_name, - path - ) - request.error (301) - return - - # we could also generate a directory listing here, - # may want to move this into another method for that - # purpose - found = 0 - if path and path[-1] != '/': - path = path + '/' - for default in self.directory_defaults: - p = path + default - if self.filesystem.isfile (p): - path = p - found = 1 - break - if not found: - request.error (404) # Not Found - return - - elif not self.filesystem.isfile (path): - request.error (404) # Not Found - return - - file_length = self.filesystem.stat (path)[stat.ST_SIZE] - - ims = get_header_match (IF_MODIFIED_SINCE, request.header) - - length_match = 1 - if ims: - length = ims.group (4) - if length: - try: - length = string.atoi (length) - if length != file_length: - length_match = 0 - except: - pass - - ims_date = 0 - - if ims: - ims_date = http_date.parse_http_date (ims.group (1)) - - try: - mtime = self.filesystem.stat (path)[stat.ST_MTIME] - except: - request.error (404) - return - - if length_match and ims_date: - if mtime <= ims_date: - request.reply_code = 304 - request.done() - self.cache_counter.increment() - return - try: - file = self.filesystem.open (path, 'rb') - except IOError: - request.error (404) - return - - request['Last-Modified'] = http_date.build_http_date (mtime) - request['Content-Length'] = file_length - self.set_content_type (path, request) - - if request.command == 'get': - request.push (self.default_file_producer (file)) - - self.file_counter.increment() - request.done() - - def set_content_type (self, path, request): - ext = string.lower (get_extension (path)) - if mime_type_table.content_type_map.has_key (ext): - request['Content-Type'] = mime_type_table.content_type_map[ext] - else: - # TODO: test a chunk off the front of the file for 8-bit - # characters, and use application/octet-stream instead. - request['Content-Type'] = 'text/plain' - - def status (self): - return producers.simple_producer ( - '
  • %s' % status_handler.html_repr (self) - + '
      ' - + '
    • Total Hits: %s' % self.hit_counter - + '
    • Files Delivered: %s' % self.file_counter - + '
    • Cache Hits: %s' % self.cache_counter - + '
    ' - ) - -# HTTP/1.0 doesn't say anything about the "; length=nnnn" addition -# to this header. I suppose it's purpose is to avoid the overhead -# of parsing dates... -IF_MODIFIED_SINCE = re.compile ( - 'If-Modified-Since: ([^;]+)((; length=([0-9]+)$)|$)', - re.IGNORECASE - ) - -USER_AGENT = re.compile ('User-Agent: (.*)', re.IGNORECASE) - -CONTENT_TYPE = re.compile ( - r'Content-Type: ([^;]+)((; boundary=([A-Za-z0-9\'\(\)+_,./:=?-]+)$)|$)', - re.IGNORECASE - ) - -get_header = http_server.get_header -get_header_match = http_server.get_header_match - -def get_extension (path): - dirsep = string.rfind (path, '/') - dotsep = string.rfind (path, '.') - if dotsep > dirsep: - return path[dotsep+1:] - else: - return '' diff --git a/demo/medusa/dh1024.pem b/demo/medusa/dh1024.pem deleted file mode 100644 index 81d43f6..0000000 --- a/demo/medusa/dh1024.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq -/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx -/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC ------END DH PARAMETERS----- diff --git a/demo/medusa/filesys.py b/demo/medusa/filesys.py deleted file mode 100644 index 003af2e..0000000 --- a/demo/medusa/filesys.py +++ /dev/null @@ -1,466 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- -# $Id: filesys.py 299 2005-06-09 17:32:28Z heikki $ -# Author: Sam Rushing -# -# Generic filesystem interface. -# - -# We want to provide a complete wrapper around any and all -# filesystem operations. - -# this class is really just for documentation, -# identifying the API for a filesystem object. - -# opening files for reading, and listing directories, should -# return a producer. - -class abstract_filesystem: - def __init__ (self): - pass - - def current_directory (self): - "Return a string representing the current directory." - pass - - def listdir (self, path, long=0): - """Return a listing of the directory at 'path' The empty string - indicates the current directory. If 'long' is set, instead - return a list of (name, stat_info) tuples - """ - pass - - def open (self, path, mode): - "Return an open file object" - pass - - def stat (self, path): - "Return the equivalent of os.stat() on the given path." - pass - - def isdir (self, path): - "Does the path represent a directory?" - pass - - def isfile (self, path): - "Does the path represent a plain file?" - pass - - def cwd (self, path): - "Change the working directory." - pass - - def cdup (self): - "Change to the parent of the current directory." - pass - - - def longify (self, path): - """Return a 'long' representation of the filename - [for the output of the LIST command]""" - pass - -# standard wrapper around a unix-like filesystem, with a 'false root' -# capability. - -# security considerations: can symbolic links be used to 'escape' the -# root? should we allow it? if not, then we could scan the -# filesystem on startup, but that would not help if they were added -# later. We will probably need to check for symlinks in the cwd method. - -# what to do if wd is an invalid directory? - -import os -import stat - -import string - -def safe_stat (path): - try: - return (path, os.stat (path)) - except: - return None - -import regsub -import glob - -class os_filesystem: - path_module = os.path - - # set this to zero if you want to disable pathname globbing. - # [we currently don't glob, anyway] - do_globbing = 1 - - def __init__ (self, root, wd='/'): - self.root = root - self.wd = wd - - def current_directory (self): - return self.wd - - def isfile (self, path): - p = self.normalize (self.path_module.join (self.wd, path)) - return self.path_module.isfile (self.translate(p)) - - def isdir (self, path): - p = self.normalize (self.path_module.join (self.wd, path)) - return self.path_module.isdir (self.translate(p)) - - def cwd (self, path): - p = self.normalize (self.path_module.join (self.wd, path)) - translated_path = self.translate(p) - if not self.path_module.isdir (translated_path): - return 0 - else: - old_dir = os.getcwd() - # temporarily change to that directory, in order - # to see if we have permission to do so. - try: - can = 0 - try: - os.chdir (translated_path) - can = 1 - self.wd = p - except: - pass - finally: - if can: - os.chdir (old_dir) - return can - - def cdup (self): - return self.cwd ('..') - - def listdir (self, path, long=0): - p = self.translate (path) - # I think we should glob, but limit it to the current - # directory only. - ld = os.listdir (p) - if not long: - return list_producer (ld, 0, None) - else: - old_dir = os.getcwd() - try: - os.chdir (p) - # if os.stat fails we ignore that file. - result = filter (None, map (safe_stat, ld)) - finally: - os.chdir (old_dir) - return list_producer (result, 1, self.longify) - - # TODO: implement a cache w/timeout for stat() - def stat (self, path): - p = self.translate (path) - return os.stat (p) - - def open (self, path, mode): - p = self.translate (path) - return open (p, mode) - - def unlink (self, path): - p = self.translate (path) - return os.unlink (p) - - def mkdir (self, path): - p = self.translate (path) - return os.mkdir (p) - - def rmdir (self, path): - p = self.translate (path) - return os.rmdir (p) - - # utility methods - def normalize (self, path): - # watch for the ever-sneaky '/+' path element - path = regsub.gsub ('/+', '/', path) - p = self.path_module.normpath (path) - # remove 'dangling' cdup's. - if len(p) > 2 and p[:3] == '/..': - p = '/' - return p - - def translate (self, path): - # we need to join together three separate - # path components, and do it safely. - # // - # use the operating system's path separator. - path = string.join (string.split (path, '/'), os.sep) - p = self.normalize (self.path_module.join (self.wd, path)) - p = self.normalize (self.path_module.join (self.root, p[1:])) - return p - - def longify (self, (path, stat_info)): - return unix_longify (path, stat_info) - - def __repr__ (self): - return '' % ( - self.root, - self.wd - ) - -if os.name == 'posix': - - class unix_filesystem (os_filesystem): - pass - - class schizophrenic_unix_filesystem (os_filesystem): - PROCESS_UID = os.getuid() - PROCESS_EUID = os.geteuid() - PROCESS_GID = os.getgid() - PROCESS_EGID = os.getegid() - - def __init__ (self, root, wd='/', persona=(None, None)): - os_filesystem.__init__ (self, root, wd) - self.persona = persona - - def become_persona (self): - if self.persona is not (None, None): - uid, gid = self.persona - # the order of these is important! - os.setegid (gid) - os.seteuid (uid) - - def become_nobody (self): - if self.persona is not (None, None): - os.seteuid (self.PROCESS_UID) - os.setegid (self.PROCESS_GID) - - # cwd, cdup, open, listdir - def cwd (self, path): - try: - self.become_persona() - return os_filesystem.cwd (self, path) - finally: - self.become_nobody() - - def cdup (self, path): - try: - self.become_persona() - return os_filesystem.cdup (self) - finally: - self.become_nobody() - - def open (self, filename, mode): - try: - self.become_persona() - return os_filesystem.open (self, filename, mode) - finally: - self.become_nobody() - - def listdir (self, path, long=0): - try: - self.become_persona() - return os_filesystem.listdir (self, path, long) - finally: - self.become_nobody() - -# This hasn't been very reliable across different platforms. -# maybe think about a separate 'directory server'. -# -# import posixpath -# import fcntl -# import FCNTL -# import select -# import asyncore -# -# # pipes /bin/ls for directory listings. -# class unix_filesystem (os_filesystem): -# pass -# path_module = posixpath -# -# def listdir (self, path, long=0): -# p = self.translate (path) -# if not long: -# return list_producer (os.listdir (p), 0, None) -# else: -# command = '/bin/ls -l %s' % p -# print 'opening pipe to "%s"' % command -# fd = os.popen (command, 'rt') -# return pipe_channel (fd) -# -# # this is both a dispatcher, _and_ a producer -# class pipe_channel (asyncore.file_dispatcher): -# buffer_size = 4096 -# -# def __init__ (self, fd): -# asyncore.file_dispatcher.__init__ (self, fd) -# self.fd = fd -# self.done = 0 -# self.data = '' -# -# def handle_read (self): -# if len (self.data) < self.buffer_size: -# self.data = self.data + self.fd.read (self.buffer_size) -# #print '%s.handle_read() => len(self.data) == %d' % (self, len(self.data)) -# -# def handle_expt (self): -# #print '%s.handle_expt()' % self -# self.done = 1 -# -# def ready (self): -# #print '%s.ready() => %d' % (self, len(self.data)) -# return ((len (self.data) > 0) or self.done) -# -# def more (self): -# if self.data: -# r = self.data -# self.data = '' -# elif self.done: -# self.close() -# self.downstream.finished() -# r = '' -# else: -# r = None -# #print '%s.more() => %s' % (self, (r and len(r))) -# return r - -# For the 'real' root, we could obtain a list of drives, and then -# use that. Doesn't win32 provide such a 'real' filesystem? -# [yes, I think something like this "\\.\c\windows"] - -class msdos_filesystem (os_filesystem): - def longify (self, (path, stat_info)): - return msdos_longify (path, stat_info) - -# A merged filesystem will let you plug other filesystems together. -# We really need the equivalent of a 'mount' capability - this seems -# to be the most general idea. So you'd use a 'mount' method to place -# another filesystem somewhere in the hierarchy. - -# Note: this is most likely how I will handle ~user directories -# with the http server. - -class merged_filesystem: - def __init__ (self, *fsys): - pass - -# this matches the output of NT's ftp server (when in -# MSDOS mode) exactly. - -def msdos_longify (file, stat_info): - if stat.S_ISDIR (stat_info[stat.ST_MODE]): - dir = '' - else: - dir = ' ' - date = msdos_date (stat_info[stat.ST_MTIME]) - return '%s %s %8d %s' % ( - date, - dir, - stat_info[stat.ST_SIZE], - file - ) - -def msdos_date (t): - try: - info = time.gmtime (t) - except: - info = time.gmtime (0) - # year, month, day, hour, minute, second, ... - if info[3] > 11: - merid = 'PM' - info[3] = info[3] - 12 - else: - merid = 'AM' - return '%02d-%02d-%02d %02d:%02d%s' % ( - info[1], - info[2], - info[0]%100, - info[3], - info[4], - merid - ) - -months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - -mode_table = { - '0':'---', - '1':'--x', - '2':'-w-', - '3':'-wx', - '4':'r--', - '5':'r-x', - '6':'rw-', - '7':'rwx' - } - -import time - -def unix_longify (file, stat_info): - # for now, only pay attention to the lower bits - mode = ('%o' % stat_info[stat.ST_MODE])[-3:] - mode = string.join (map (lambda x: mode_table[x], mode), '') - if stat.S_ISDIR (stat_info[stat.ST_MODE]): - dirchar = 'd' - else: - dirchar = '-' - date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) - return '%s%s %3d %-8d %-8d %8d %s %s' % ( - dirchar, - mode, - stat_info[stat.ST_NLINK], - stat_info[stat.ST_UID], - stat_info[stat.ST_GID], - stat_info[stat.ST_SIZE], - date, - file - ) - -# Emulate the unix 'ls' command's date field. -# it has two formats - if the date is more than 180 -# days in the past, then it's like this: -# Oct 19 1995 -# otherwise, it looks like this: -# Oct 19 17:33 - -def ls_date (now, t): - try: - info = time.gmtime (t) - except: - info = time.gmtime (0) - # 15,600,000 == 86,400 * 180 - if (now - t) > 15600000: - return '%s %2d %d' % ( - months[info[1]-1], - info[2], - info[0] - ) - else: - return '%s %2d %02d:%02d' % ( - months[info[1]-1], - info[2], - info[3], - info[4] - ) - -# =========================================================================== -# Producers -# =========================================================================== - -class list_producer: - def __init__ (self, file_list, long, longify): - self.file_list = file_list - self.long = long - self.longify = longify - self.done = 0 - - def ready (self): - if len(self.file_list): - return 1 - else: - if not self.done: - self.done = 1 - return 0 - return (len(self.file_list) > 0) - - # this should do a pushd/popd - def more (self): - if not self.file_list: - return '' - else: - # do a few at a time - bunch = self.file_list[:50] - if self.long: - bunch = map (self.longify, bunch) - self.file_list = self.file_list[50:] - return string.joinfields (bunch, '\r\n') + '\r\n' - diff --git a/demo/medusa/ftp_server.py b/demo/medusa/ftp_server.py deleted file mode 100644 index 78363cf..0000000 --- a/demo/medusa/ftp_server.py +++ /dev/null @@ -1,1127 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- - -# Author: Sam Rushing -# Copyright 1996-2000 by Sam Rushing -# All Rights Reserved. -# - -# An extensible, configurable, asynchronous FTP server. -# -# All socket I/O is non-blocking, however file I/O is currently -# blocking. Eventually file I/O may be made non-blocking, too, if it -# seems necessary. Currently the only CPU-intensive operation is -# getting and formatting a directory listing. [this could be moved -# into another process/directory server, or another thread?] -# -# Only a subset of RFC 959 is implemented, but much of that RFC is -# vestigial anyway. I've attempted to include the most commonly-used -# commands, using the feature set of wu-ftpd as a guide. - -import asyncore -import asynchat - -import os -import regsub -import socket -import stat -import string -import sys -import time - -# TODO: implement a directory listing cache. On very-high-load -# servers this could save a lot of disk abuse, and possibly the -# work of computing emulated unix ls output. - -# Potential security problem with the FTP protocol? I don't think -# there's any verification of the origin of a data connection. Not -# really a problem for the server (since it doesn't send the port -# command, except when in PASV mode) But I think a data connection -# could be spoofed by a program with access to a sniffer - it could -# watch for a PORT command to go over a command channel, and then -# connect to that port before the server does. - -# Unix user id's: -# In order to support assuming the id of a particular user, -# it seems there are two options: -# 1) fork, and seteuid in the child -# 2) carefully control the effective uid around filesystem accessing -# methods, using try/finally. [this seems to work] - -VERSION = '1.1' - -from counter import counter -import producers -import status_handler -import logger -import string - -class ftp_channel (asynchat.async_chat): - - # defaults for a reliable __repr__ - addr = ('unknown','0') - - # unset this in a derived class in order - # to enable the commands in 'self.write_commands' - read_only = 1 - write_commands = ['appe','dele','mkd','rmd','rnfr','rnto','stor','stou'] - - restart_position = 0 - - # comply with (possibly troublesome) RFC959 requirements - # This is necessary to correctly run an active data connection - # through a firewall that triggers on the source port (expected - # to be 'L-1', or 20 in the normal case). - bind_local_minus_one = 0 - - def __init__ (self, server, conn, addr): - self.server = server - self.current_mode = 'a' - self.addr = addr - asynchat.async_chat.__init__ (self, conn) - self.set_terminator ('\r\n') - - # client data port. Defaults to 'the same as the control connection'. - self.client_addr = (addr[0], 21) - - self.client_dc = None - self.in_buffer = '' - self.closing = 0 - self.passive_acceptor = None - self.passive_connection = None - self.filesystem = None - self.authorized = 0 - # send the greeting - self.respond ( - '220 %s FTP server (Medusa Async V%s [experimental]) ready.' % ( - self.server.hostname, - VERSION - ) - ) - -# def __del__ (self): -# print 'ftp_channel.__del__()' - - # -------------------------------------------------- - # async-library methods - # -------------------------------------------------- - - def handle_expt (self): - # this is handled below. not sure what I could - # do here to make that code less kludgish. - pass - - def collect_incoming_data (self, data): - self.in_buffer = self.in_buffer + data - if len(self.in_buffer) > 4096: - # silently truncate really long lines - # (possible denial-of-service attack) - self.in_buffer = '' - - def found_terminator (self): - - line = self.in_buffer - - if not len(line): - return - - sp = string.find (line, ' ') - if sp != -1: - line = [line[:sp], line[sp+1:]] - else: - line = [line] - - command = string.lower (line[0]) - # watch especially for 'urgent' abort commands. - if string.find (command, 'abor') != -1: - # strip off telnet sync chars and the like... - while command and command[0] not in string.letters: - command = command[1:] - fun_name = 'cmd_%s' % command - if command != 'pass': - self.log ('<== %s' % repr(self.in_buffer)[1:-1]) - else: - self.log ('<== %s' % line[0]+' ') - self.in_buffer = '' - if not hasattr (self, fun_name): - self.command_not_understood (line[0]) - return - fun = getattr (self, fun_name) - if (not self.authorized) and (command not in ('user', 'pass', 'help', 'quit')): - self.respond ('530 Please log in with USER and PASS') - elif (not self.check_command_authorization (command)): - self.command_not_authorized (command) - else: - try: - result = apply (fun, (line,)) - except: - self.server.total_exceptions.increment() - (file, fun, line), t,v, tbinfo = asyncore.compact_traceback() - if self.client_dc: - try: - self.client_dc.close() - except: - pass - self.respond ( - '451 Server Error: %s, %s: file: %s line: %s' % ( - t,v,file,line, - ) - ) - - closed = 0 - def close (self): - if not self.closed: - self.closed = 1 - if self.passive_acceptor: - self.passive_acceptor.close() - if self.client_dc: - self.client_dc.close() - self.server.closed_sessions.increment() - asynchat.async_chat.close (self) - - # -------------------------------------------------- - # filesystem interface functions. - # override these to provide access control or perform - # other functions. - # -------------------------------------------------- - - def cwd (self, line): - return self.filesystem.cwd (line[1]) - - def cdup (self, line): - return self.filesystem.cdup() - - def open (self, path, mode): - return self.filesystem.open (path, mode) - - # returns a producer - def listdir (self, path, long=0): - return self.filesystem.listdir (path, long) - - def get_dir_list (self, line, long=0): - # we need to scan the command line for arguments to '/bin/ls'... - args = line[1:] - path_args = [] - for arg in args: - if arg[0] != '-': - path_args.append (arg) - else: - # ignore arguments - pass - if len(path_args) < 1: - dir = '.' - else: - dir = path_args[0] - return self.listdir (dir, long) - - # -------------------------------------------------- - # authorization methods - # -------------------------------------------------- - - def check_command_authorization (self, command): - if command in self.write_commands and self.read_only: - return 0 - else: - return 1 - - # -------------------------------------------------- - # utility methods - # -------------------------------------------------- - - def log (self, message): - self.server.logger.log ( - self.addr[0], - '%d %s' % ( - self.addr[1], message - ) - ) - - def respond (self, resp): - self.log ('==> %s' % resp) - self.push (resp + '\r\n') - - def command_not_understood (self, command): - self.respond ("500 '%s': command not understood." % command) - - def command_not_authorized (self, command): - self.respond ( - "530 You are not authorized to perform the '%s' command" % ( - command - ) - ) - - def make_xmit_channel (self): - # In PASV mode, the connection may or may _not_ have been made - # yet. [although in most cases it is... FTP Explorer being - # the only exception I've yet seen]. This gets somewhat confusing - # because things may happen in any order... - pa = self.passive_acceptor - if pa: - if pa.ready: - # a connection has already been made. - conn, addr = self.passive_acceptor.ready - cdc = xmit_channel (self, addr) - cdc.set_socket (conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - # we're still waiting for a connect to the PASV port. - cdc = xmit_channel (self) - else: - # not in PASV mode. - ip, port = self.client_addr - cdc = xmit_channel (self, self.client_addr) - cdc.create_socket (socket.AF_INET, socket.SOCK_STREAM) - if self.bind_local_minus_one: - cdc.bind (('', self.server.port - 1)) - try: - cdc.connect ((ip, port)) - except socket.error, why: - self.respond ("425 Can't build data connection") - self.client_dc = cdc - - # pretty much the same as xmit, but only right on the verge of - # being worth a merge. - def make_recv_channel (self, fd): - pa = self.passive_acceptor - if pa: - if pa.ready: - # a connection has already been made. - conn, addr = pa.ready - cdc = recv_channel (self, addr, fd) - cdc.set_socket (conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - # we're still waiting for a connect to the PASV port. - cdc = recv_channel (self, None, fd) - else: - # not in PASV mode. - ip, port = self.client_addr - cdc = recv_channel (self, self.client_addr, fd) - cdc.create_socket (socket.AF_INET, socket.SOCK_STREAM) - try: - cdc.connect ((ip, port)) - except socket.error, why: - self.respond ("425 Can't build data connection") - self.client_dc = cdc - - type_map = { - 'a':'ASCII', - 'i':'Binary', - 'e':'EBCDIC', - 'l':'Binary' - } - - type_mode_map = { - 'a':'t', - 'i':'b', - 'e':'b', - 'l':'b' - } - - # -------------------------------------------------- - # command methods - # -------------------------------------------------- - - def cmd_type (self, line): - 'specify data transfer type' - # ascii, ebcdic, image, local - t = string.lower (line[1]) - # no support for EBCDIC - # if t not in ['a','e','i','l']: - if t not in ['a','i','l']: - self.command_not_understood (string.join (line)) - elif t == 'l' and (len(line) > 2 and line[2] != '8'): - self.respond ('504 Byte size must be 8') - else: - self.current_mode = t - self.respond ('200 Type set to %s.' % self.type_map[t]) - - - def cmd_quit (self, line): - 'terminate session' - self.respond ('221 Goodbye.') - self.close_when_done() - - def cmd_port (self, line): - 'specify data connection port' - info = string.split (line[1], ',') - ip = string.join (info[:4], '.') - port = string.atoi(info[4])*256 + string.atoi(info[5]) - # how many data connections at a time? - # I'm assuming one for now... - # TODO: we should (optionally) verify that the - # ip number belongs to the client. [wu-ftpd does this?] - self.client_addr = (ip, port) - self.respond ('200 PORT command successful.') - - def new_passive_acceptor (self): - # ensure that only one of these exists at a time. - if self.passive_acceptor is not None: - self.passive_acceptor.close() - self.passive_acceptor = None - self.passive_acceptor = passive_acceptor (self) - return self.passive_acceptor - - def cmd_pasv (self, line): - 'prepare for server-to-server transfer' - pc = self.new_passive_acceptor() - port = pc.addr[1] - ip_addr = pc.control_channel.getsockname()[0] - self.respond ( - '227 Entering Passive Mode (%s,%d,%d)' % ( - string.join (string.split (ip_addr, '.'), ','), - port/256, - port%256 - ) - ) - self.client_dc = None - - def cmd_nlst (self, line): - 'give name list of files in directory' - # ncftp adds the -FC argument for the user-visible 'nlist' - # command. We could try to emulate ls flags, but not just yet. - if '-FC' in line: - line.remove ('-FC') - try: - dir_list_producer = self.get_dir_list (line, 0) - except os.error, why: - self.respond ('550 Could not list directory: %s' % repr(why)) - return - self.respond ( - '150 Opening %s mode data connection for file list' % ( - self.type_map[self.current_mode] - ) - ) - self.make_xmit_channel() - self.client_dc.push_with_producer (dir_list_producer) - self.client_dc.close_when_done() - - def cmd_list (self, line): - 'give list files in a directory' - try: - dir_list_producer = self.get_dir_list (line, 1) - except os.error, why: - self.respond ('550 Could not list directory: %s' % repr(why)) - return - self.respond ( - '150 Opening %s mode data connection for file list' % ( - self.type_map[self.current_mode] - ) - ) - self.make_xmit_channel() - self.client_dc.push_with_producer (dir_list_producer) - self.client_dc.close_when_done() - - def cmd_cwd (self, line): - 'change working directory' - if self.cwd (line): - self.respond ('250 CWD command successful.') - else: - self.respond ('550 No such directory.') - - def cmd_cdup (self, line): - 'change to parent of current working directory' - if self.cdup(line): - self.respond ('250 CDUP command successful.') - else: - self.respond ('550 No such directory.') - - def cmd_pwd (self, line): - 'print the current working directory' - self.respond ( - '257 "%s" is the current directory.' % ( - self.filesystem.current_directory() - ) - ) - - # modification time - # example output: - # 213 19960301204320 - def cmd_mdtm (self, line): - 'show last modification time of file' - filename = line[1] - if not self.filesystem.isfile (filename): - self.respond ('550 "%s" is not a file' % filename) - else: - mtime = time.gmtime(self.filesystem.stat(filename)[stat.ST_MTIME]) - self.respond ( - '213 %4d%02d%02d%02d%02d%02d' % ( - mtime[0], - mtime[1], - mtime[2], - mtime[3], - mtime[4], - mtime[5] - ) - ) - - def cmd_noop (self, line): - 'do nothing' - self.respond ('200 NOOP command successful.') - - def cmd_size (self, line): - 'return size of file' - filename = line[1] - if not self.filesystem.isfile (filename): - self.respond ('550 "%s" is not a file' % filename) - else: - self.respond ( - '213 %d' % (self.filesystem.stat(filename)[stat.ST_SIZE]) - ) - - def cmd_retr (self, line): - 'retrieve a file' - if len(line) < 2: - self.command_not_understood (string.join (line)) - else: - file = line[1] - if not self.filesystem.isfile (file): - self.log_info ('checking %s' % file) - self.respond ('550 No such file') - else: - try: - # FIXME: for some reason, 'rt' isn't working on win95 - mode = 'r'+self.type_mode_map[self.current_mode] - fd = self.open (file, mode) - except IOError, why: - self.respond ('553 could not open file for reading: %s' % (repr(why))) - return - self.respond ( - "150 Opening %s mode data connection for file '%s'" % ( - self.type_map[self.current_mode], - file - ) - ) - self.make_xmit_channel() - - if self.restart_position: - # try to position the file as requested, but - # give up silently on failure (the 'file object' - # may not support seek()) - try: - fd.seek (self.restart_position) - except: - pass - self.restart_position = 0 - - self.client_dc.push_with_producer ( - file_producer (self, self.client_dc, fd) - ) - self.client_dc.close_when_done() - - def cmd_stor (self, line, mode='wb'): - 'store a file' - if len (line) < 2: - self.command_not_understood (string.join (line)) - else: - if self.restart_position: - restart_position = 0 - self.respond ('553 restart on STOR not yet supported') - return - file = line[1] - # todo: handle that type flag - try: - fd = self.open (file, mode) - except IOError, why: - self.respond ('553 could not open file for writing: %s' % (repr(why))) - return - self.respond ( - '150 Opening %s connection for %s' % ( - self.type_map[self.current_mode], - file - ) - ) - self.make_recv_channel (fd) - - def cmd_abor (self, line): - 'abort operation' - if self.client_dc: - self.client_dc.close() - self.respond ('226 ABOR command successful.') - - def cmd_appe (self, line): - 'append to a file' - return self.cmd_stor (line, 'ab') - - def cmd_dele (self, line): - if len (line) != 2: - self.command_not_understood (string.join (line)) - else: - file = line[1] - if self.filesystem.isfile (file): - try: - self.filesystem.unlink (file) - self.respond ('250 DELE command successful.') - except: - self.respond ('550 error deleting file.') - else: - self.respond ('550 %s: No such file.' % file) - - def cmd_mkd (self, line): - if len (line) != 2: - self.command.not_understood (string.join (line)) - else: - path = line[1] - try: - self.filesystem.mkdir (path) - self.respond ('257 MKD command successful.') - except: - self.respond ('550 error creating directory.') - - def cmd_rmd (self, line): - if len (line) != 2: - self.command.not_understood (string.join (line)) - else: - path = line[1] - try: - self.filesystem.rmdir (path) - self.respond ('250 RMD command successful.') - except: - self.respond ('550 error removing directory.') - - def cmd_user (self, line): - 'specify user name' - if len(line) > 1: - self.user = line[1] - self.respond ('331 Password required.') - else: - self.command_not_understood (string.join (line)) - - def cmd_pass (self, line): - 'specify password' - if len(line) < 2: - pw = '' - else: - pw = line[1] - result, message, fs = self.server.authorizer.authorize (self, self.user, pw) - if result: - self.respond ('230 %s' % message) - self.filesystem = fs - self.authorized = 1 - self.log_info('Successful login: Filesystem=%s' % repr(fs)) - else: - self.respond ('530 %s' % message) - - def cmd_rest (self, line): - 'restart incomplete transfer' - try: - pos = string.atoi (line[1]) - except ValueError: - self.command_not_understood (string.join (line)) - self.restart_position = pos - self.respond ( - '350 Restarting at %d. Send STORE or RETRIEVE to initiate transfer.' % pos - ) - - def cmd_stru (self, line): - 'obsolete - set file transfer structure' - if line[1] in 'fF': - # f == 'file' - self.respond ('200 STRU F Ok') - else: - self.respond ('504 Unimplemented STRU type') - - def cmd_mode (self, line): - 'obsolete - set file transfer mode' - if line[1] in 'sS': - # f == 'file' - self.respond ('200 MODE S Ok') - else: - self.respond ('502 Unimplemented MODE type') - -# The stat command has two personalities. Normally it returns status -# information about the current connection. But if given an argument, -# it is equivalent to the LIST command, with the data sent over the -# control connection. Strange. But wuftpd, ftpd, and nt's ftp server -# all support it. -# -## def cmd_stat (self, line): -## 'return status of server' -## pass - - def cmd_syst (self, line): - 'show operating system type of server system' - # Replying to this command is of questionable utility, because - # this server does not behave in a predictable way w.r.t. the - # output of the LIST command. We emulate Unix ls output, but - # on win32 the pathname can contain drive information at the front - # Currently, the combination of ensuring that os.sep == '/' - # and removing the leading slash when necessary seems to work. - # [cd'ing to another drive also works] - # - # This is how wuftpd responds, and is probably - # the most expected. The main purpose of this reply is so that - # the client knows to expect Unix ls-style LIST output. - self.respond ('215 UNIX Type: L8') - # one disadvantage to this is that some client programs - # assume they can pass args to /bin/ls. - # a few typical responses: - # 215 UNIX Type: L8 (wuftpd) - # 215 Windows_NT version 3.51 - # 215 VMS MultiNet V3.3 - # 500 'SYST': command not understood. (SVR4) - - def cmd_help (self, line): - 'give help information' - # find all the methods that match 'cmd_xxxx', - # use their docstrings for the help response. - attrs = dir(self.__class__) - help_lines = [] - for attr in attrs: - if attr[:4] == 'cmd_': - x = getattr (self, attr) - if type(x) == type(self.cmd_help): - if x.__doc__: - help_lines.append ('\t%s\t%s' % (attr[4:], x.__doc__)) - if help_lines: - self.push ('214-The following commands are recognized\r\n') - self.push_with_producer (producers.lines_producer (help_lines)) - self.push ('214\r\n') - else: - self.push ('214-\r\n\tHelp Unavailable\r\n214\r\n') - -class ftp_server (asyncore.dispatcher): - # override this to spawn a different FTP channel class. - ftp_channel_class = ftp_channel - - SERVER_IDENT = 'FTP Server (V%s)' % VERSION - - def __init__ ( - self, - authorizer, - hostname =None, - ip ='', - port =21, - resolver =None, - logger_object=logger.file_logger (sys.stdout) - ): - self.ip = ip - self.port = port - self.authorizer = authorizer - - if hostname is None: - self.hostname = socket.gethostname() - else: - self.hostname = hostname - - # statistics - self.total_sessions = counter() - self.closed_sessions = counter() - self.total_files_out = counter() - self.total_files_in = counter() - self.total_bytes_out = counter() - self.total_bytes_in = counter() - self.total_exceptions = counter() - # - asyncore.dispatcher.__init__ (self) - self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - - self.set_reuse_addr() - self.bind ((self.ip, self.port)) - self.listen (5) - - if not logger_object: - logger_object = sys.stdout - - if resolver: - self.logger = logger.resolving_logger (resolver, logger_object) - else: - self.logger = logger.unresolving_logger (logger_object) - - self.log_info('FTP server started at %s\n\tAuthorizer:%s\n\tHostname: %s\n\tPort: %d' % ( - time.ctime(time.time()), - repr (self.authorizer), - self.hostname, - self.port) - ) - - def writable (self): - return 0 - - def handle_read (self): - pass - - def handle_connect (self): - pass - - def handle_accept (self): - conn, addr = self.accept() - self.total_sessions.increment() - self.log_info('Incoming connection from %s:%d' % (addr[0], addr[1])) - self.ftp_channel_class (self, conn, addr) - - # return a producer describing the state of the server - def status (self): - - def nice_bytes (n): - return string.join (status_handler.english_bytes (n)) - - return producers.lines_producer ( - ['

    %s

    ' % self.SERVER_IDENT, - '
    Listening on Host: %s' % self.hostname, - 'Port: %d' % self.port, - '
    Sessions', - 'Total: %s' % self.total_sessions, - 'Current: %d' % (self.total_sessions.as_long() - self.closed_sessions.as_long()), - '
    Files', - 'Sent: %s' % self.total_files_out, - 'Received: %s' % self.total_files_in, - '
    Bytes', - 'Sent: %s' % nice_bytes (self.total_bytes_out.as_long()), - 'Received: %s' % nice_bytes (self.total_bytes_in.as_long()), - '
    Exceptions: %s' % self.total_exceptions, - ] - ) - -# ====================================================================== -# Data Channel Classes -# ====================================================================== - -# This socket accepts a data connection, used when the server has been -# placed in passive mode. Although the RFC implies that we ought to -# be able to use the same acceptor over and over again, this presents -# a problem: how do we shut it off, so that we are accepting -# connections only when we expect them? [we can't] -# -# wuftpd, and probably all the other servers, solve this by allowing -# only one connection to hit this acceptor. They then close it. Any -# subsequent data-connection command will then try for the default -# port on the client side [which is of course never there]. So the -# 'always-send-PORT/PASV' behavior seems required. -# -# Another note: wuftpd will also be listening on the channel as soon -# as the PASV command is sent. It does not wait for a data command -# first. - -# --- we need to queue up a particular behavior: -# 1) xmit : queue up producer[s] -# 2) recv : the file object -# -# It would be nice if we could make both channels the same. Hmmm.. -# - -class passive_acceptor (asyncore.dispatcher): - ready = None - - def __init__ (self, control_channel): - # connect_fun (conn, addr) - asyncore.dispatcher.__init__ (self) - self.control_channel = control_channel - self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - # bind to an address on the interface that the - # control connection is coming from. - self.bind (( - self.control_channel.getsockname()[0], - 0 - )) - self.addr = self.getsockname() - self.listen (1) - -# def __del__ (self): -# print 'passive_acceptor.__del__()' - - def log (self, *ignore): - pass - - def handle_accept (self): - conn, addr = self.accept() - dc = self.control_channel.client_dc - if dc is not None: - dc.set_socket (conn) - dc.addr = addr - dc.connected = 1 - self.control_channel.passive_acceptor = None - else: - self.ready = conn, addr - self.close() - - -class xmit_channel (asynchat.async_chat): - - # for an ethernet, you want this to be fairly large, in fact, it - # _must_ be large for performance comparable to an ftpd. [64k] we - # ought to investigate automatically-sized buffers... - - ac_out_buffer_size = 16384 - bytes_out = 0 - - def __init__ (self, channel, client_addr=None): - self.channel = channel - self.client_addr = client_addr - asynchat.async_chat.__init__ (self) - -# def __del__ (self): -# print 'xmit_channel.__del__()' - - def log (*args): - pass - - def readable (self): - return not self.connected - - def writable (self): - return 1 - - def send (self, data): - result = asynchat.async_chat.send (self, data) - self.bytes_out = self.bytes_out + result - return result - - def handle_error (self): - # usually this is to catch an unexpected disconnect. - self.log_info ('unexpected disconnect on data xmit channel', 'error') - try: - self.close() - except: - pass - - # TODO: there's a better way to do this. we need to be able to - # put 'events' in the producer fifo. to do this cleanly we need - # to reposition the 'producer' fifo as an 'event' fifo. - - def close (self): - c = self.channel - s = c.server - c.client_dc = None - s.total_files_out.increment() - s.total_bytes_out.increment (self.bytes_out) - if not len(self.producer_fifo): - c.respond ('226 Transfer complete') - elif not c.closed: - c.respond ('426 Connection closed; transfer aborted') - del c - del s - del self.channel - asynchat.async_chat.close (self) - -class recv_channel (asyncore.dispatcher): - def __init__ (self, channel, client_addr, fd): - self.channel = channel - self.client_addr = client_addr - self.fd = fd - asyncore.dispatcher.__init__ (self) - self.bytes_in = counter() - - def log (self, *ignore): - pass - - def handle_connect (self): - pass - - def writable (self): - return 0 - - def recv (*args): - result = apply (asyncore.dispatcher.recv, args) - self = args[0] - self.bytes_in.increment(len(result)) - return result - - buffer_size = 8192 - - def handle_read (self): - block = self.recv (self.buffer_size) - if block: - try: - self.fd.write (block) - except IOError: - self.log_info ('got exception writing block...', 'error') - - def handle_close (self): - s = self.channel.server - s.total_files_in.increment() - s.total_bytes_in.increment(self.bytes_in.as_long()) - self.fd.close() - self.channel.respond ('226 Transfer complete.') - self.close() - -import filesys - -# not much of a doorman! 8^) -class dummy_authorizer: - def __init__ (self, root='/'): - self.root = root - def authorize (self, channel, username, password): - channel.persona = -1, -1 - channel.read_only = 1 - return 1, 'Ok.', filesys.os_filesystem (self.root) - -class anon_authorizer: - def __init__ (self, root='/'): - self.root = root - - def authorize (self, channel, username, password): - if username in ('ftp', 'anonymous'): - channel.persona = -1, -1 - channel.read_only = 1 - return 1, 'Ok.', filesys.os_filesystem (self.root) - else: - return 0, 'Password invalid.', None - -# =========================================================================== -# Unix-specific improvements -# =========================================================================== - -if os.name == 'posix': - - class unix_authorizer: - # return a trio of (success, reply_string, filesystem) - def authorize (self, channel, username, password): - import crypt - import pwd - try: - info = pwd.getpwnam (username) - except KeyError: - return 0, 'No such user.', None - mangled = info[1] - if crypt.crypt (password, mangled[:2]) == mangled: - channel.read_only = 0 - fs = filesys.schizophrenic_unix_filesystem ( - '/', - info[5], - persona = (info[2], info[3]) - ) - return 1, 'Login successful.', fs - else: - return 0, 'Password invalid.', None - - def __repr__ (self): - return '' - - # simple anonymous ftp support - class unix_authorizer_with_anonymous (unix_authorizer): - def __init__ (self, root=None, real_users=0): - self.root = root - self.real_users = real_users - - def authorize (self, channel, username, password): - if string.lower(username) in ['anonymous', 'ftp']: - import pwd - try: - # ok, here we run into lots of confusion. - # on some os', anon runs under user 'nobody', - # on others as 'ftp'. ownership is also critical. - # need to investigate. - # linux: new linuxen seem to have nobody's UID=-1, - # which is an illegal value. Use ftp. - ftp_user_info = pwd.getpwnam ('ftp') - if string.lower(os.uname()[0]) == 'linux': - nobody_user_info = pwd.getpwnam ('ftp') - else: - nobody_user_info = pwd.getpwnam ('nobody') - channel.read_only = 1 - if self.root is None: - self.root = ftp_user_info[5] - fs = filesys.unix_filesystem (self.root, '/') - return 1, 'Anonymous Login Successful', fs - except KeyError: - return 0, 'Anonymous account not set up', None - elif self.real_users: - return unix_authorizer.authorize ( - self, - channel, - username, - password - ) - else: - return 0, 'User logins not allowed', None - -class file_producer: - block_size = 16384 - def __init__ (self, server, dc, fd): - self.fd = fd - self.done = 0 - - def more (self): - if self.done: - return '' - else: - block = self.fd.read (self.block_size) - if not block: - self.fd.close() - self.done = 1 - return block - -# usage: ftp_server /PATH/TO/FTP/ROOT PORT -# for example: -# $ ftp_server /home/users/ftp 8021 - -if os.name == 'posix': - def test (port='8021'): - import sys - fs = ftp_server ( - unix_authorizer(), - port=string.atoi (port) - ) - try: - asyncore.loop() - except KeyboardInterrupt: - self.log_info('FTP server shutting down. (received SIGINT)', 'warning') - # close everything down on SIGINT. - # of course this should be a cleaner shutdown. - asyncore.close_all() - - if __name__ == '__main__': - test (sys.argv[1]) -# not unix -else: - def test (): - fs = ftp_server (dummy_authorizer()) - if __name__ == '__main__': - test () - -# this is the command list from the wuftpd man page -# '*' means we've implemented it. -# '!' requires write access -# -command_documentation = { - 'abor': 'abort previous command', #* - 'acct': 'specify account (ignored)', - 'allo': 'allocate storage (vacuously)', - 'appe': 'append to a file', #*! - 'cdup': 'change to parent of current working directory', #* - 'cwd': 'change working directory', #* - 'dele': 'delete a file', #! - 'help': 'give help information', #* - 'list': 'give list files in a directory', #* - 'mkd': 'make a directory', #! - 'mdtm': 'show last modification time of file', #* - 'mode': 'specify data transfer mode', - 'nlst': 'give name list of files in directory', #* - 'noop': 'do nothing', #* - 'pass': 'specify password', #* - 'pasv': 'prepare for server-to-server transfer', #* - 'port': 'specify data connection port', #* - 'pwd': 'print the current working directory', #* - 'quit': 'terminate session', #* - 'rest': 'restart incomplete transfer', #* - 'retr': 'retrieve a file', #* - 'rmd': 'remove a directory', #! - 'rnfr': 'specify rename-from file name', #! - 'rnto': 'specify rename-to file name', #! - 'site': 'non-standard commands (see next section)', - 'size': 'return size of file', #* - 'stat': 'return status of server', #* - 'stor': 'store a file', #*! - 'stou': 'store a file with a unique name', #! - 'stru': 'specify data transfer structure', - 'syst': 'show operating system type of server system', #* - 'type': 'specify data transfer type', #* - 'user': 'specify user name', #* - 'xcup': 'change to parent of current working directory (deprecated)', - 'xcwd': 'change working directory (deprecated)', - 'xmkd': 'make a directory (deprecated)', #! - 'xpwd': 'print the current working directory (deprecated)', - 'xrmd': 'remove a directory (deprecated)', #! -} - - -# debugging aid (linux) -def get_vm_size (): - return string.atoi (string.split(open ('/proc/self/stat').readline())[22]) - -def print_vm(): - print 'vm: %8dk' % (get_vm_size()/1024) diff --git a/demo/medusa/ftps_server.py b/demo/medusa/ftps_server.py deleted file mode 100644 index 8fee339..0000000 --- a/demo/medusa/ftps_server.py +++ /dev/null @@ -1,438 +0,0 @@ -"""An FTP/TLS server built on Medusa's ftp_server. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -# Python -import socket, string, sys, time - -# Medusa -from counter import counter -import asynchat, asyncore, ftp_server, logger - -# M2Crypto -from M2Crypto import SSL - -VERSION_STRING='0.09' - -class ftp_tls_channel(ftp_server.ftp_channel): - - """FTP/TLS server channel for Medusa.""" - - def __init__(self, server, ssl_ctx, conn, addr): - """Initialise the channel.""" - self.ssl_ctx = ssl_ctx - self.server = server - self.current_mode = 'a' - self.addr = addr - asynchat.async_chat.__init__(self, conn) - self.set_terminator('\r\n') - self.client_addr = (addr[0], 21) - self.client_dc = None - self.in_buffer = '' - self.closing = 0 - self.passive_acceptor = None - self.passive_connection = None - self.filesystem = None - self.authorized = 0 - self._ssl_accepting = 0 - self._ssl_accepted = 0 - self._pbsz = None - self._prot = None - resp = '220 %s M2Crypto (Medusa) FTP/TLS server v%s ready.' - self.respond(resp % (self.server.hostname, VERSION_STRING)) - - def writable(self): - return self._ssl_accepting or self._ssl_accepted - - def handle_read(self): - """Handle a read event.""" - if self._ssl_accepting: - self._ssl_accepted = self.socket.accept_ssl() - if self._ssl_accepted: - self._ssl_accepting = 0 - else: - try: - ftp_server.ftp_channel.handle_read(self) - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - self.close() - else: - raise - - def handle_write(self): - """Handle a write event.""" - if self._ssl_accepting: - self._ssl_accepted = self.socket.accept_ssl() - if self._ssl_accepted: - self._ssl_accepting = 0 - else: - try: - ftp_server.ftp_channel.handle_write(self) - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - self.close() - else: - raise - - def send(self, data): - """Send data over SSL.""" - try: - result = self.socket.send(data) - if result <= 0: - return 0 - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), what)) - return 0 - - def recv(self, buffer_size): - """Receive data over SSL.""" - try: - result = self.socket.recv(buffer_size) - if not result: - return '' - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), what)) - return '' - - def found_terminator(self): - """Dispatch the FTP command.""" - line = self.in_buffer - if not len(line): - return - - sp = string.find(line, ' ') - if sp != -1: - line = [line[:sp], line[sp+1:]] - else: - line = [line] - - command = string.lower(line[0]) - if string.find(command, 'stor') != -1: - while command and command[0] not in string.letters: - command = command[1:] - - func_name = 'cmd_%s' % command - if command != 'pass': - self.log('<== %s' % repr(self.in_buffer)[1:-1]) - else: - self.log('<== %s' % line[0]+' ') - - self.in_buffer = '' - if not hasattr(self, func_name): - self.command_not_understood(line[0]) - return - - func = getattr(self, func_name) - if not self.check_command_authorization(command): - self.command_not_authorized(command) - else: - try: - result = apply(func, (line,)) - except: - self.server.total_exceptions.increment() - (file, func, line), t, v, tbinfo = asyncore.compact_traceback() - if self.client_dc: - try: - self.client_dc_close() - except: - pass - resp = '451 Server error: %s, %s: file %s line: %s' - self.respond(resp % (t, v, file, line)) - - def make_xmit_channel(self): - """Create a connection for sending data.""" - pa = self.passive_acceptor - if pa: - if pa.ready: - conn, addr = pa.ready - if self._prot: - cdc = tls_xmit_channel(self, conn, self.ssl_ctx, addr) - else: - cdc = ftp_server.xmit_channel(self, addr) - cdc.set_socket(conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - if self._prot: - cdc = tls_xmit_channel(self, None, self.ssl_ctx, None) - else: - cdc = ftp_server.xmit_channel(self) - else: - if self._prot: - cdc = tls_xmit_channel(self, None, self.ssl_ctx, self.client_addr) - else: - cdc = ftp_server.xmit_channel(self, self.client_addr) - cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) - if self.bind_local_minus_one: - cdc.bind(('', self.server.port - 1)) - try: - cdc.connect(self.client_addr) - except socket.error, what: - self.respond('425 Cannot build data connection') - self.client_dc = cdc - - def make_recv_channel(self, fd): - """Create a connection for receiving data.""" - pa = self.passive_acceptor - if pa: - if pa.ready: - conn, addr = pa.ready - if self._prot: - cdc = tls_recv_channel(self, conn, self.ssl_ctx, addr, fd) - else: - cdc = ftp_server.recv_channel(self, addr, fd) - cdc.set_socket(conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - if self._prot: - cdc = tls_recv_channel(self, None, self.ssl_ctx, None, fd) - else: - cdc = ftp_server.recv_channel(self, None, fd) - else: - if self._prot: - cdc = tls_recv_channel(self, None, self.ssl_ctx, self._prot, self.client_addr, fd) - else: - cdc = ftp_server.recv_channel(self, self.client_addr, fd) - cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) - try: - cdc.connect(self.client_addr) - except socket.error, what: - self.respond('425 Cannot build data connection') - self.client_dc = cdc - - def cmd_auth(self, line): - """Prepare for TLS operation.""" - # XXX Handle variations. - if line[1] != 'TLS': - self.command_not_understood (string.join(line)) - else: - self.respond('234 AUTH TLS successful') - self._ssl_accepting = 1 - self.socket = SSL.Connection(self.ssl_ctx, self.socket) - self.socket.setup_addr(self.addr) - self.socket.setup_ssl() - self.socket.set_accept_state() - self._ssl_accepted = self.socket.accept_ssl() - if self._ssl_accepted: - self._ssl_accepting = 0 - - def cmd_pbsz(self, line): - """Negotiate size of buffer for secure data transfer. For - FTP/TLS the only valid value for the parameter is '0'; any - other value is accepted but ignored.""" - if not (self._ssl_accepting or self._ssl_accepted): - return self.respond('503 AUTH TLS must be issued prior to PBSZ') - self._pbsz = 1 - self.respond('200 PBSZ=0 successful.') - - def cmd_prot(self, line): - """Negotiate the security level of the data connection.""" - if self._pbsz is None: - return self.respond('503 PBSZ must be issued prior to PROT') - if line[1] == 'C': - self.respond('200 Protection set to Clear') - self._pbsz = None - self._prot = None - elif line[1] == 'P': - self.respond('200 Protection set to Private') - self._prot = 1 - elif line[1] in ('S', 'E'): - self.respond('536 PROT %s unsupported' % line[1]) - else: - self.respond('504 PROT %s unsupported' % line[1]) - - -class ftp_tls_server(ftp_server.ftp_server): - - """FTP/TLS server for Medusa.""" - - SERVER_IDENT = 'M2Crypto FTP/TLS Server (v%s)' % VERSION_STRING - - ftp_channel_class = ftp_tls_channel - - def __init__(self, authz, ssl_ctx, host=None, ip='', port=21, resolver=None, log_obj=None): - """Initialise the server.""" - self.ssl_ctx = ssl_ctx - self.ip = ip - self.port = port - self.authorizer = authz - - if host is None: - self.hostname = socket.gethostname() - else: - self.hostname = host - - self.total_sessions = counter() - self.closed_sessions = counter() - self.total_files_out = counter() - self.total_files_in = counter() - self.total_bytes_out = counter() - self.total_bytes_in = counter() - self.total_exceptions = counter() - - asyncore.dispatcher.__init__(self) - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.set_reuse_addr() - self.bind((self.ip, self.port)) - self.listen(5) - - if log_obj is None: - log_obj = sys.stdout - - if resolver: - self.logger = logger.resolving_logger(resolver, log_obj) - else: - self.logger = logger.unresolving_logger(logger.file_logger(sys.stdout)) - - l = 'M2Crypto (Medusa) FTP/TLS server started at %s\n\tAuthz: %s\n\tHostname: %s\n\tPort: %d' - self.log_info(l % (time.ctime(time.time()), repr(self.authorizer), self.hostname, self.port)) - - def handle_accept(self): - """Accept a socket and dispatch a channel to handle it.""" - conn, addr = self.accept() - self.total_sessions.increment() - self.log_info('Connection from %s:%d' % addr) - self.ftp_channel_class(self, self.ssl_ctx, conn, addr) - - -class nbio_ftp_tls_actor: - - """TLS protocol negotiation mixin for FTP/TLS.""" - - def tls_init(self, sock, ssl_ctx, client_addr): - """Perform TLS protocol negotiation.""" - self.ssl_ctx = ssl_ctx - self.client_addr = client_addr - self._ssl_handshaking = 1 - self._ssl_handshake_ok = 0 - if sock: - self.socket = SSL.Connection(self.ssl_ctx, sock) - self.socket.setup_addr(self.client_addr) - self.socket.setup_ssl() - self._ssl_handshake_ok = self.socket.accept_ssl() - if self._ssl_handshake_ok: - self._ssl_handshaking = 0 - self.add_channel() - # else the client hasn't connected yet; when that happens, - # handle_connect() will be triggered. - - def tls_neg_ok(self): - """Return status of TLS protocol negotiation.""" - if self._ssl_handshaking: - self._ssl_handshake_ok = self.socket.accept_ssl() - if self._ssl_handshake_ok: - self._ssl_handshaking = 0 - return self._ssl_handshake_ok - - def handle_connect(self): - """Handle a data connection that occurs after this instance came - into being. When this handler is triggered, self.socket has been - created and refers to the underlying connected socket.""" - self.socket = SSL.Connection(self.ssl_ctx, self.socket) - self.socket.setup_addr(self.client_addr) - self.socket.setup_ssl() - self._ssl_handshake_ok = self.socket.accept_ssl() - if self._ssl_handshake_ok: - self._ssl_handshaking = 0 - self.add_channel() - - def send(self, data): - """Send data over SSL.""" - try: - result = self.socket.send(data) - if result <= 0: - return 0 - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), what)) - return 0 - - def recv(self, buffer_size): - """Receive data over SSL.""" - try: - result = self.socket.recv(buffer_size) - if not result: - return '' - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), what)) - return '' - - -class tls_xmit_channel(nbio_ftp_tls_actor, ftp_server.xmit_channel): - - """TLS driver for a send-only data connection.""" - - def __init__(self, channel, conn, ssl_ctx, client_addr=None): - """Initialise the driver.""" - ftp_server.xmit_channel.__init__(self, channel, client_addr) - self.tls_init(conn, ssl_ctx, client_addr) - - def readable(self): - """This channel is readable iff TLS negotiation is in progress. - (Which implies a connected channel, of course.)""" - if not self.connected: - return 0 - else: - return self._ssl_handshaking - - def writable(self): - """This channel is writable iff TLS negotiation is in progress - or the application has data to send.""" - if self._ssl_handshaking: - return 1 - else: - return ftp_server.xmit_channel.writable(self) - - def handle_read(self): - """Handle a read event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.xmit_channel.handle_read(self) - - def handle_write(self): - """Handle a write event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.xmit_channel.handle_write(self) - - -class tls_recv_channel(nbio_ftp_tls_actor, ftp_server.recv_channel): - - """TLS driver for a receive-only data connection.""" - - def __init__(self, channel, conn, ssl_ctx, client_addr, fd): - """Initialise the driver.""" - ftp_server.recv_channel.__init__(self, channel, client_addr, fd) - self.tls_init(conn, ssl_ctx, client_addr) - - def writable(self): - """This channel is writable iff TLS negotiation is in progress.""" - return self._ssl_handshaking - - def handle_read(self): - """Handle a read event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.recv_channel.handle_read(self) - - def handle_write(self): - """Handle a write event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.recv_channel.handle_write(self) - - diff --git a/demo/medusa/http_date.py b/demo/medusa/http_date.py deleted file mode 100644 index c40f70d..0000000 --- a/demo/medusa/http_date.py +++ /dev/null @@ -1,126 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- - -import re -import string -import time - -def concat (*args): - return ''.join (args) - -def join (seq, field=' '): - return field.join (seq) - -def group (s): - return '(' + s + ')' - -short_days = ['sun','mon','tue','wed','thu','fri','sat'] -long_days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday'] - -short_day_reg = group (join (short_days, '|')) -long_day_reg = group (join (long_days, '|')) - -daymap = {} -for i in range(7): - daymap[short_days[i]] = i - daymap[long_days[i]] = i - -hms_reg = join (3 * [group('[0-9][0-9]')], ':') - -months = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'] - -monmap = {} -for i in range(12): - monmap[months[i]] = i+1 - -months_reg = group (join (months, '|')) - -# From draft-ietf-http-v11-spec-07.txt/3.3.1 -# Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 -# Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 -# Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format - -# rfc822 format -rfc822_date = join ( - [concat (short_day_reg,','), # day - group('[0-9][0-9]?'), # date - months_reg, # month - group('[0-9]+'), # year - hms_reg, # hour minute second - 'gmt' - ], - ' ' - ) - -rfc822_reg = re.compile (rfc822_date) - -def unpack_rfc822 (m): - g = m.group - a = string.atoi - return ( - a(g(4)), # year - monmap[g(3)], # month - a(g(2)), # day - a(g(5)), # hour - a(g(6)), # minute - a(g(7)), # second - 0, - 0, - 0 - ) - -# rfc850 format -rfc850_date = join ( - [concat (long_day_reg,','), - join ( - [group ('[0-9][0-9]?'), - months_reg, - group ('[0-9]+') - ], - '-' - ), - hms_reg, - 'gmt' - ], - ' ' - ) - -rfc850_reg = re.compile (rfc850_date) -# they actually unpack the same way -def unpack_rfc850 (m): - g = m.group - a = string.atoi - return ( - a(g(4)), # year - monmap[g(3)], # month - a(g(2)), # day - a(g(5)), # hour - a(g(6)), # minute - a(g(7)), # second - 0, - 0, - 0 - ) - -# parsdate.parsedate - ~700/sec. -# parse_http_date - ~1333/sec. - -def build_http_date (when): - return time.strftime ('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(when)) - -def parse_http_date (d): - d = string.lower (d) - tz = time.timezone - m = rfc850_reg.match (d) - if m and m.end() == len(d): - retval = int (time.mktime (unpack_rfc850(m)) - tz) - else: - m = rfc822_reg.match (d) - if m and m.end() == len(d): - retval = int (time.mktime (unpack_rfc822(m)) - tz) - else: - return 0 - # Thanks to Craig Silverstein for pointing - # out the DST discrepancy - if time.daylight and time.localtime(retval)[-1] == 1: # DST correction - retval = retval + (tz - time.altzone) - return retval diff --git a/demo/medusa/http_server.py b/demo/medusa/http_server.py deleted file mode 100644 index 2f261ab..0000000 --- a/demo/medusa/http_server.py +++ /dev/null @@ -1,784 +0,0 @@ -#! /usr/local/bin/python -# -*- Mode: Python; tab-width: 4 -*- -# -# Author: Sam Rushing -# Copyright 1996-2000 by Sam Rushing -# All Rights Reserved. -# - -# python modules -import os -import re -import socket -import stat -import string -import sys -import time - -# async modules -import asyncore -import asynchat - -# medusa modules -import http_date -import producers -import status_handler -import logger - -VERSION_STRING = '1.1' - -from counter import counter -from urllib import unquote - -# =========================================================================== -# Request Object -# =========================================================================== - -class http_request: - - # default reply code - reply_code = 200 - - request_counter = counter() - - # Whether to automatically use chunked encoding when - # - # HTTP version is 1.1 - # Content-Length is not set - # Chunked encoding is not already in effect - # - # If your clients are having trouble, you might want to disable this. - use_chunked = 1 - - # by default, this request object ignores user data. - collector = None - - def __init__ (self, *args): - # unpack information about the request - (self.channel, self.request, - self.command, self.uri, self.version, - self.header) = args - - self.outgoing = fifo() - self.reply_headers = { - 'Server' : 'Medusa/%s' % VERSION_STRING, - 'Date' : http_date.build_http_date (time.time()) - } - self.request_number = http_request.request_counter.increment() - self._split_uri = None - self._header_cache = {} - - # -------------------------------------------------- - # reply header management - # -------------------------------------------------- - def __setitem__ (self, key, value): - self.reply_headers[key] = value - - def __getitem__ (self, key): - return self.reply_headers[key] - - def has_key (self, key): - return self.reply_headers.has_key (key) - - def build_reply_header (self): - return string.join ( - [self.response(self.reply_code)] + map ( - lambda x: '%s: %s' % x, - self.reply_headers.items() - ), - '\r\n' - ) + '\r\n\r\n' - - # -------------------------------------------------- - # split a uri - # -------------------------------------------------- - - # ;?# - path_regex = re.compile ( - # path params query fragment - r'([^;?#]*)(;[^?#]*)?(\?[^#]*)?(#.*)?' - ) - - def split_uri (self): - if self._split_uri is None: - m = self.path_regex.match (self.uri) - if m.end() != len(self.uri): - raise ValueError, "Broken URI" - else: - self._split_uri = m.groups() - return self._split_uri - - def get_header_with_regex (self, head_reg, group): - for line in self.header: - m = head_reg.match (line) - if m.end() == len(line): - return head_reg.group (group) - return '' - - def get_header (self, header): - header = string.lower (header) - hc = self._header_cache - if not hc.has_key (header): - h = header + ': ' - hl = len(h) - for line in self.header: - if string.lower (line[:hl]) == h: - r = line[hl:] - hc[header] = r - return r - hc[header] = None - return None - else: - return hc[header] - - # -------------------------------------------------- - # user data - # -------------------------------------------------- - - def collect_incoming_data (self, data): - if self.collector: - self.collector.collect_incoming_data (data) - else: - self.log_info( - 'Dropping %d bytes of incoming request data' % len(data), - 'warning' - ) - - def found_terminator (self): - if self.collector: - self.collector.found_terminator() - else: - self.log_info ( - 'Unexpected end-of-record for incoming request', - 'warning' - ) - - def push (self, thing): - if type(thing) == type(''): - self.outgoing.push (producers.simple_producer (thing)) - else: - self.outgoing.push (thing) - - def response (self, code=200): - message = self.responses[code] - self.reply_code = code - return 'HTTP/%s %d %s' % (self.version, code, message) - - def error (self, code): - self.reply_code = code - message = self.responses[code] - s = self.DEFAULT_ERROR_MESSAGE % { - 'code': code, - 'message': message, - } - self['Content-Length'] = len(s) - self['Content-Type'] = 'text/html' - # make an error reply - self.push (s) - self.done() - - # can also be used for empty replies - reply_now = error - - def done (self): - "finalize this transaction - send output to the http channel" - - # ---------------------------------------- - # persistent connection management - # ---------------------------------------- - - # --- BUCKLE UP! ---- - - connection = string.lower (get_header (CONNECTION, self.header)) - - close_it = 0 - wrap_in_chunking = 0 - - if self.version == '1.0': - if connection == 'keep-alive': - if not self.has_key ('Content-Length'): - close_it = 1 - else: - self['Connection'] = 'Keep-Alive' - else: - close_it = 1 - elif self.version == '1.1': - if connection == 'close': - close_it = 1 - elif not self.has_key ('Content-Length'): - if self.has_key ('Transfer-Encoding'): - if not self['Transfer-Encoding'] == 'chunked': - close_it = 1 - elif self.use_chunked: - self['Transfer-Encoding'] = 'chunked' - wrap_in_chunking = 1 - else: - close_it = 1 - elif self.version is None: - # Although we don't *really* support http/0.9 (because we'd have to - # use \r\n as a terminator, and it would just yuck up a lot of stuff) - # it's very common for developers to not want to type a version number - # when using telnet to debug a server. - close_it = 1 - - outgoing_header = producers.simple_producer (self.build_reply_header()) - - if close_it: - self['Connection'] = 'close' - - if wrap_in_chunking: - outgoing_producer = producers.chunked_producer ( - producers.composite_producer (self.outgoing) - ) - # prepend the header - outgoing_producer = producers.composite_producer ( - fifo([outgoing_header, outgoing_producer]) - ) - else: - # prepend the header - self.outgoing.push_front (outgoing_header) - outgoing_producer = producers.composite_producer (self.outgoing) - - # apply a few final transformations to the output - self.channel.push_with_producer ( - # globbing gives us large packets - producers.globbing_producer ( - # hooking lets us log the number of bytes sent - producers.hooked_producer ( - outgoing_producer, - self.log - ) - ) - ) - - self.channel.current_request = None - - if close_it: - self.channel.close_when_done() - - def log_date_string (self, when): - return time.strftime ( - '%d/%b/%Y:%H:%M:%S ', - time.gmtime(when) - ) + tz_for_log - - def log (self, bytes): - self.channel.server.logger.log ( - self.channel.addr[0], - '%d - - [%s] "%s" %d %d\n' % ( - self.channel.addr[1], - self.log_date_string (time.time()), - self.request, - self.reply_code, - bytes - ) - ) - - responses = { - 100: "Continue", - 101: "Switching Protocols", - 200: "OK", - 201: "Created", - 202: "Accepted", - 203: "Non-Authoritative Information", - 204: "No Content", - 205: "Reset Content", - 206: "Partial Content", - 300: "Multiple Choices", - 301: "Moved Permanently", - 302: "Moved Temporarily", - 303: "See Other", - 304: "Not Modified", - 305: "Use Proxy", - 400: "Bad Request", - 401: "Unauthorized", - 402: "Payment Required", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 406: "Not Acceptable", - 407: "Proxy Authentication Required", - 408: "Request Time-out", - 409: "Conflict", - 410: "Gone", - 411: "Length Required", - 412: "Precondition Failed", - 413: "Request Entity Too Large", - 414: "Request-URI Too Large", - 415: "Unsupported Media Type", - 500: "Internal Server Error", - 501: "Not Implemented", - 502: "Bad Gateway", - 503: "Service Unavailable", - 504: "Gateway Time-out", - 505: "HTTP Version not supported" - } - - # Default error message - DEFAULT_ERROR_MESSAGE = string.join ( - ['', - 'Error response', - '', - '', - '

    Error response

    ', - '

    Error code %(code)d.', - '

    Message: %(message)s.', - '', - '' - ], - '\r\n' - ) - - -# =========================================================================== -# HTTP Channel Object -# =========================================================================== - -class http_channel (asynchat.async_chat): - - # use a larger default output buffer - ac_out_buffer_size = 1<<16 - - current_request = None - channel_counter = counter() - - def __init__ (self, server, conn, addr): - self.channel_number = http_channel.channel_counter.increment() - self.request_counter = counter() - asynchat.async_chat.__init__ (self, conn) - self.server = server - self.addr = addr - self.set_terminator ('\r\n\r\n') - self.in_buffer = '' - self.creation_time = int (time.time()) - self.check_maintenance() - - def __repr__ (self): - ar = asynchat.async_chat.__repr__(self)[1:-1] - return '<%s channel#: %s requests:%s>' % ( - ar, - self.channel_number, - self.request_counter - ) - - # Channel Counter, Maintenance Interval... - maintenance_interval = 500 - - def check_maintenance (self): - if not self.channel_number % self.maintenance_interval: - self.maintenance() - - def maintenance (self): - self.kill_zombies() - - # 30-minute zombie timeout. status_handler also knows how to kill zombies. - zombie_timeout = 30 * 60 - - def kill_zombies (self): - now = int (time.time()) - for channel in asyncore.socket_map.values(): - if channel.__class__ == self.__class__: - if (now - channel.creation_time) > channel.zombie_timeout: - channel.close() - - # -------------------------------------------------- - # send/recv overrides, good place for instrumentation. - # -------------------------------------------------- - - # this information needs to get into the request object, - # so that it may log correctly. - def send (self, data): - result = asynchat.async_chat.send (self, data) - self.server.bytes_out.increment (len(data)) - return result - - def recv (self, buffer_size): - try: - result = asynchat.async_chat.recv (self, buffer_size) - self.server.bytes_in.increment (len(result)) - return result - except MemoryError: - # --- Save a Trip to Your Service Provider --- - # It's possible for a process to eat up all the memory of - # the machine, and put it in an extremely wedged state, - # where medusa keeps running and can't be shut down. This - # is where MemoryError tends to get thrown, though of - # course it could get thrown elsewhere. - sys.exit ("Out of Memory!") - - def handle_error (self): - t, v = sys.exc_info()[:2] - if t is SystemExit: - raise t, v - else: - asynchat.async_chat.handle_error (self) - - def log (self, *args): - pass - - # -------------------------------------------------- - # async_chat methods - # -------------------------------------------------- - - def collect_incoming_data (self, data): - if self.current_request: - # we are receiving data (probably POST data) for a request - self.current_request.collect_incoming_data (data) - else: - # we are receiving header (request) data - self.in_buffer = self.in_buffer + data - - def found_terminator (self): - if self.current_request: - self.current_request.found_terminator() - else: - header = self.in_buffer - self.in_buffer = '' - lines = string.split (header, '\r\n') - - # -------------------------------------------------- - # crack the request header - # -------------------------------------------------- - - while lines and not lines[0]: - # as per the suggestion of http-1.1 section 4.1, (and - # Eric Parker ), ignore a leading - # blank lines (buggy browsers tack it onto the end of - # POST requests) - lines = lines[1:] - - if not lines: - self.close_when_done() - return - - request = lines[0] - - # unquote path if necessary (thanks to Skip Montaro for pointing - # out that we must unquote in piecemeal fashion). - if '%' in request: - request = unquote (request) - - command, uri, version = crack_request (request) - header = join_headers (lines[1:]) - - r = http_request (self, request, command, uri, version, header) - self.request_counter.increment() - self.server.total_requests.increment() - - if command is None: - self.log_info ('Bad HTTP request: %s' % repr(request), 'error') - r.error (400) - return - - # -------------------------------------------------- - # handler selection and dispatch - # -------------------------------------------------- - for h in self.server.handlers: - if h.match (r): - try: - self.current_request = r - # This isn't used anywhere. - # r.handler = h # CYCLE - h.handle_request (r) - except: - self.server.exceptions.increment() - (file, fun, line), t, v, tbinfo = asyncore.compact_traceback() - self.log_info( - 'Server Error: %s, %s: file: %s line: %s' % (t,v,file,line), - 'error') - try: - r.error (500) - except: - pass - return - - # no handlers, so complain - r.error (404) - - def writable (self): - # this is just the normal async_chat 'writable', here for comparison - return self.ac_out_buffer or len(self.producer_fifo) - - def writable_for_proxy (self): - # this version of writable supports the idea of a 'stalled' producer - # [i.e., it's not ready to produce any output yet] This is needed by - # the proxy, which will be waiting for the magic combination of - # 1) hostname resolved - # 2) connection made - # 3) data available. - if self.ac_out_buffer: - return 1 - elif len(self.producer_fifo): - p = self.producer_fifo.first() - if hasattr (p, 'stalled'): - return not p.stalled() - else: - return 1 - -# =========================================================================== -# HTTP Server Object -# =========================================================================== - -class http_server (asyncore.dispatcher): - - SERVER_IDENT = 'HTTP Server (V%s)' % VERSION_STRING - - channel_class = http_channel - - def __init__ (self, ip, port, resolver=None, logger_object=None): - self.ip = ip - self.port = port - asyncore.dispatcher.__init__ (self) - self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - - self.handlers = [] - - if not logger_object: - logger_object = logger.file_logger (sys.stdout) - - self.set_reuse_addr() - self.bind ((ip, port)) - - # lower this to 5 if your OS complains - self.listen (1024) - - host, port = self.socket.getsockname() - if not ip: - self.log_info('Computing default hostname', 'warning') - ip = socket.gethostbyname (socket.gethostname()) - try: - self.server_name = socket.gethostbyaddr (ip)[0] - except socket.error: - self.log_info('Cannot do reverse lookup', 'warning') - self.server_name = ip # use the IP address as the "hostname" - - self.server_port = port - self.total_clients = counter() - self.total_requests = counter() - self.exceptions = counter() - self.bytes_out = counter() - self.bytes_in = counter() - - if not logger_object: - logger_object = logger.file_logger (sys.stdout) - - if resolver: - self.logger = logger.resolving_logger (resolver, logger_object) - else: - self.logger = logger.unresolving_logger (logger_object) - - self.log_info ( - 'Medusa (V%s) started at %s' - '\n\tHostname: %s' - '\n\tPort:%d' - '\n' % ( - VERSION_STRING, - time.ctime(time.time()), - self.server_name, - port, - ) - ) - - def writable (self): - return 0 - - def handle_read (self): - pass - - def readable (self): - return self.accepting - - def handle_connect (self): - pass - - def handle_accept (self): - self.total_clients.increment() - try: - conn, addr = self.accept() - except socket.error: - # linux: on rare occasions we get a bogus socket back from - # accept. socketmodule.c:makesockaddr complains that the - # address family is unknown. We don't want the whole server - # to shut down because of this. - self.log_info ('warning: server accept() threw an exception', 'warning') - return - except TypeError: - # unpack non-sequence. this can happen when a read event - # fires on a listening socket, but when we call accept() - # we get EWOULDBLOCK, so dispatcher.accept() returns None. - # Seen on FreeBSD3. - self.log_info ('warning: server accept() threw EWOULDBLOCK', 'warning') - return - - self.channel_class (self, conn, addr) - - def install_handler (self, handler, back=0): - if back: - self.handlers.append (handler) - else: - self.handlers.insert (0, handler) - - def remove_handler (self, handler): - self.handlers.remove (handler) - - def status (self): - def nice_bytes (n): - return string.join (status_handler.english_bytes (n)) - - handler_stats = filter (None, map (maybe_status, self.handlers)) - - if self.total_clients: - ratio = self.total_requests.as_long() / float(self.total_clients.as_long()) - else: - ratio = 0.0 - - return producers.composite_producer ( - fifo ([producers.lines_producer ( - ['

    %s

    ' % self.SERVER_IDENT, - '
    Listening on: Host: %s' % self.server_name, - 'Port: %d' % self.port, - '

      ' - '
    • Total Clients: %s' % self.total_clients, - 'Requests: %s' % self.total_requests, - 'Requests/Client: %.1f' % (ratio), - '
    • Total Bytes In: %s' % (nice_bytes (self.bytes_in.as_long())), - 'Bytes Out: %s' % (nice_bytes (self.bytes_out.as_long())), - '
    • Total Exceptions: %s' % self.exceptions, - '

    ' - 'Extension List

      ', - ])] + handler_stats + [producers.simple_producer('
    ')] - ) - ) - -def maybe_status (thing): - if hasattr (thing, 'status'): - return thing.status() - else: - return None - -CONNECTION = re.compile ('Connection: (.*)', re.IGNORECASE) - -# merge multi-line headers -# [486dx2: ~500/sec] -def join_headers (headers): - r = [] - for i in range(len(headers)): - if headers[i][0] in ' \t': - r[-1] = r[-1] + headers[i][1:] - else: - r.append (headers[i]) - return r - -def get_header (head_reg, lines, group=1): - for line in lines: - m = head_reg.match (line) - if m and m.end() == len(line): - return m.group (group) - return '' - -def get_header_match (head_reg, lines): - for line in lines: - m = head_reg.match (line) - if m and m.end() == len(line): - return m - return '' - -REQUEST = re.compile ('([^ ]+) ([^ ]+)(( HTTP/([0-9.]+))$|$)') - -def crack_request (r): - m = REQUEST.match (r) - if m.end() == len(r): - if m.group(3): - version = m.group(5) - else: - version = None - return string.lower (m.group(1)), m.group(2), version - else: - return None, None, None - -class fifo: - def __init__ (self, list=None): - if not list: - self.list = [] - else: - self.list = list - - def __len__ (self): - return len(self.list) - - def first (self): - return self.list[0] - - def push_front (self, object): - self.list.insert (0, object) - - def push (self, data): - self.list.append (data) - - def pop (self): - if self.list: - result = self.list[0] - del self.list[0] - return (1, result) - else: - return (0, None) - -def compute_timezone_for_log (): - if time.daylight: - tz = time.altzone - else: - tz = time.timezone - if tz > 0: - neg = 1 - else: - neg = 0 - tz = -tz - h, rem = divmod (tz, 3600) - m, rem = divmod (rem, 60) - if neg: - return '-%02d%02d' % (h, m) - else: - return '+%02d%02d' % (h, m) - -# if you run this program over a TZ change boundary, this will be invalid. -tz_for_log = compute_timezone_for_log() - -if __name__ == '__main__': - import sys - if len(sys.argv) < 2: - print 'usage: %s ' % (sys.argv[0]) - else: - import monitor - import filesys - import default_handler - import status_handler - import ftp_server - import chat_server - import resolver - import logger - rs = resolver.caching_resolver ('127.0.0.1') - lg = logger.file_logger (sys.stdout) - ms = monitor.secure_monitor_server ('fnord', '127.0.0.1', 9999) - fs = filesys.os_filesystem (sys.argv[1]) - dh = default_handler.default_handler (fs) - hs = http_server ('', string.atoi (sys.argv[2]), rs, lg) - hs.install_handler (dh) - ftp = ftp_server.ftp_server ( - ftp_server.dummy_authorizer(sys.argv[1]), - port=8021, - resolver=rs, - logger_object=lg - ) - cs = chat_server.chat_server ('', 7777) - sh = status_handler.status_extension([hs,ms,ftp,cs,rs]) - hs.install_handler (sh) - if ('-p' in sys.argv): - def profile_loop (): - try: - asyncore.loop() - except KeyboardInterrupt: - pass - import profile - profile.run ('profile_loop()', 'profile.out') - else: - asyncore.loop() diff --git a/demo/medusa/https_server.py b/demo/medusa/https_server.py deleted file mode 100644 index 1492586..0000000 --- a/demo/medusa/https_server.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python - -"""A https server built on Medusa's http_server. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -import asynchat, asyncore, http_server, socket, sys -from M2Crypto import SSL - -VERSION_STRING='0.09' - -class https_channel(http_server.http_channel): - - def __init__(self, server, conn, addr): - http_server.http_channel.__init__(self, server, conn, addr) - - def send(self, data): - try: - result = self.socket._write_nbio(data) - if result <= 0: - return 0 - else: - self.server.bytes_out.increment(result) - return result - except SSL.SSLError, why: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), why)) - return 0 - - def recv(self, buffer_size): - try: - result = self.socket._read_nbio(buffer_size) - if result is None: - return '' - elif result == '': - self.close() - return '' - else: - self.server.bytes_in.increment(len(result)) - return result - except SSL.SSLError, why: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), why)) - return '' - - -class https_server(http_server.http_server): - - SERVER_IDENT='M2Crypto HTTPS Server (v%s)' % VERSION_STRING - - channel_class=https_channel - - def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): - http_server.http_server.__init__(self, ip, port, resolver, logger_object) - sys.stdout.write(self.SERVER_IDENT + '\n\n') - sys.stdout.flush() - self.ssl_ctx=ssl_ctx - - def handle_accept(self): - # Cribbed from http_server. - self.total_clients.increment() - try: - conn, addr = self.accept() - except socket.error: - # linux: on rare occasions we get a bogus socket back from - # accept. socketmodule.c:makesockaddr complains that the - # address family is unknown. We don't want the whole server - # to shut down because of this. - sys.stderr.write ('warning: server accept() threw an exception\n') - return - - # Turn the vanilla socket into an SSL connection. - try: - ssl_conn=SSL.Connection(self.ssl_ctx, conn) - ssl_conn._setup_ssl(addr) - ssl_conn.accept_ssl() - self.channel_class(self, ssl_conn, addr) - except SSL.SSLError: - pass - - def writeable(self): - return 0 - diff --git a/demo/medusa/index.html b/demo/medusa/index.html deleted file mode 100644 index 0f7de19..0000000 --- a/demo/medusa/index.html +++ /dev/null @@ -1,6 +0,0 @@ - -M2Crypto HTTPS Server - -

    M2Crypto HTTPS Server - It works!

    - - diff --git a/demo/medusa/logger.py b/demo/medusa/logger.py deleted file mode 100644 index 48be665..0000000 --- a/demo/medusa/logger.py +++ /dev/null @@ -1,262 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- - -import asynchat -import socket -import string -import time # these three are for the rotating logger -import os # | -import stat # v - -# -# three types of log: -# 1) file -# with optional flushing. Also, one that rotates the log. -# 2) socket -# dump output directly to a socket connection. [how do we -# keep it open?] -# 3) syslog -# log to syslog via tcp. this is a per-line protocol. -# - -# -# The 'standard' interface to a logging object is simply -# log_object.log (message) -# - -# a file-like object that captures output, and -# makes sure to flush it always... this could -# be connected to: -# o stdio file -# o low-level file -# o socket channel -# o syslog output... - -class file_logger: - - # pass this either a path or a file object. - def __init__ (self, file, flush=1, mode='a'): - if type(file) == type(''): - if (file == '-'): - import sys - self.file = sys.stdout - else: - self.file = open (file, mode) - else: - self.file = file - self.do_flush = flush - - def __repr__ (self): - return '' % self.file - - def write (self, data): - self.file.write (data) - self.maybe_flush() - - def writeline (self, line): - self.file.writeline (line) - self.maybe_flush() - - def writelines (self, lines): - self.file.writelines (lines) - self.maybe_flush() - - def maybe_flush (self): - if self.do_flush: - self.file.flush() - - def flush (self): - self.file.flush() - - def softspace (self, *args): - pass - - def log (self, message): - if message[-1] not in ('\r', '\n'): - self.write (message + '\n') - else: - self.write (message) - -# like a file_logger, but it must be attached to a filename. -# When the log gets too full, or a certain time has passed, -# it backs up the log and starts a new one. Note that backing -# up the log is done via "mv" because anything else (cp, gzip) -# would take time, during which medusa would do nothing else. - -class rotating_file_logger (file_logger): - - # If freq is non-None we back up "daily", "weekly", or "monthly". - # Else if maxsize is non-None we back up whenever the log gets - # to big. If both are None we never back up. - def __init__ (self, file, freq=None, maxsize=None, flush=1, mode='a'): - self.filename = file - self.mode = mode - self.file = open (file, mode) - self.freq = freq - self.maxsize = maxsize - self.rotate_when = self.next_backup(self.freq) - self.do_flush = flush - - def __repr__ (self): - return '' % self.file - - # We back up at midnight every 1) day, 2) monday, or 3) 1st of month - def next_backup (self, freq): - (yr, mo, day, hr, min, sec, wd, jday, dst) = time.localtime(time.time()) - if freq == 'daily': - return time.mktime(yr,mo,day+1, 0,0,0, 0,0,-1) - elif freq == 'weekly': - return time.mktime(yr,mo,day-wd+7, 0,0,0, 0,0,-1) # wd(monday)==0 - elif freq == 'monthly': - return time.mktime(yr,mo+1,1, 0,0,0, 0,0,-1) - else: - return None # not a date-based backup - - def maybe_flush (self): # rotate first if necessary - self.maybe_rotate() - if self.do_flush: # from file_logger() - self.file.flush() - - def maybe_rotate (self): - if self.freq and time.time() > self.rotate_when: - self.rotate() - self.rotate_when = self.next_backup(self.freq) - elif self.maxsize: # rotate when we get too big - try: - if os.stat(self.filename)[stat.ST_SIZE] > self.maxsize: - self.rotate() - except os.error: # file not found, probably - self.rotate() # will create a new file - - def rotate (self): - (yr, mo, day, hr, min, sec, wd, jday, dst) = time.localtime(time.time()) - try: - self.file.close() - newname = '%s.ends%04d%02d%02d' % (self.filename, yr, mo, day) - try: - open(newname, "r").close() # check if file exists - newname = newname + "-%02d%02d%02d" % (hr, min, sec) - except: # YEARMODY is unique - pass - os.rename(self.filename, newname) - self.file = open(self.filename, self.mode) - except: - pass - -# syslog is a line-oriented log protocol - this class would be -# appropriate for FTP or HTTP logs, but not for dumping stderr to. - -# TODO: a simple safety wrapper that will ensure that the line sent -# to syslog is reasonable. - -# TODO: async version of syslog_client: now, log entries use blocking -# send() - -import m_syslog -syslog_logger = m_syslog.syslog_client - -class syslog_logger (m_syslog.syslog_client): - def __init__ (self, address, facility='user'): - m_syslog.syslog_client.__init__ (self, address) - self.facility = m_syslog.facility_names[facility] - self.address=address - - def __repr__ (self): - return '' % (repr(self.address)) - - def log (self, message): - m_syslog.syslog_client.log ( - self, - message, - facility=self.facility, - priority=m_syslog.LOG_INFO - ) - -# log to a stream socket, asynchronously - -class socket_logger (asynchat.async_chat): - - def __init__ (self, address): - - if type(address) == type(''): - self.create_socket (socket.AF_UNIX, socket.SOCK_STREAM) - else: - self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - - self.connect (address) - self.address = address - - def __repr__ (self): - return '' % (self.address) - - def log (self, message): - if message[-2:] != '\r\n': - self.socket.push (message + '\r\n') - else: - self.socket.push (message) - -# log to multiple places -class multi_logger: - def __init__ (self, loggers): - self.loggers = loggers - - def __repr__ (self): - return '' % (repr(self.loggers)) - - def log (self, message): - for logger in self.loggers: - logger.log (message) - -class resolving_logger: - """Feed (ip, message) combinations into this logger to get a - resolved hostname in front of the message. The message will not - be logged until the PTR request finishes (or fails).""" - - def __init__ (self, resolver, logger): - self.resolver = resolver - self.logger = logger - - class logger_thunk: - def __init__ (self, message, logger): - self.message = message - self.logger = logger - - def __call__ (self, host, ttl, answer): - if not answer: - answer = host - self.logger.log ('%s:%s' % (answer, self.message)) - - def log (self, ip, message): - self.resolver.resolve_ptr ( - ip, - self.logger_thunk ( - message, - self.logger - ) - ) - -class unresolving_logger: - "Just in case you don't want to resolve" - def __init__ (self, logger): - self.logger = logger - - def log (self, ip, message): - self.logger.log ('%s:%s' % (ip, message)) - - -def strip_eol (line): - while line and line[-1] in '\r\n': - line = line[:-1] - return line - -class tail_logger: - "Keep track of the last log messages" - def __init__ (self, logger, size=500): - self.size = size - self.logger = logger - self.messages = [] - - def log (self, message): - self.messages.append (strip_eol (message)) - if len (self.messages) > self.size: - del self.messages[0] - self.logger.log (message) diff --git a/demo/medusa/m_syslog.py b/demo/medusa/m_syslog.py deleted file mode 100644 index bb376db..0000000 --- a/demo/medusa/m_syslog.py +++ /dev/null @@ -1,177 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- - -# ====================================================================== -# Copyright 1997 by Sam Rushing -# -# All Rights Reserved -# -# Permission to use, copy, modify, and distribute this software and -# its documentation for any purpose and without fee is hereby -# granted, provided that the above copyright notice appear in all -# copies and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of Sam -# Rushing not be used in advertising or publicity pertaining to -# distribution of the software without specific, written prior -# permission. -# -# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN -# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# ====================================================================== - -"""socket interface to unix syslog. -On Unix, there are usually two ways of getting to syslog: via a -local unix-domain socket, or via the TCP service. - -Usually "/dev/log" is the unix domain socket. This may be different -for other systems. - ->>> my_client = syslog_client ('/dev/log') - -Otherwise, just use the UDP version, port 514. - ->>> my_client = syslog_client (('my_log_host', 514)) - -On win32, you will have to use the UDP version. Note that -you can use this to log to other hosts (and indeed, multiple -hosts). - -This module is not a drop-in replacement for the python - extension module - the interface is different. - -Usage: - ->>> c = syslog_client() ->>> c = syslog_client ('/strange/non_standard_log_location') ->>> c = syslog_client (('other_host.com', 514)) ->>> c.log ('testing', facility='local0', priority='debug') - -""" - -# TODO: support named-pipe syslog. -# [see ftp://sunsite.unc.edu/pub/Linux/system/Daemons/syslog-fifo.tar.z] - -# from : -# =========================================================================== -# priorities/facilities are encoded into a single 32-bit quantity, where the -# bottom 3 bits are the priority (0-7) and the top 28 bits are the facility -# (0-big number). Both the priorities and the facilities map roughly -# one-to-one to strings in the syslogd(8) source code. This mapping is -# included in this file. -# -# priorities (these are ordered) - -LOG_EMERG = 0 # system is unusable -LOG_ALERT = 1 # action must be taken immediately -LOG_CRIT = 2 # critical conditions -LOG_ERR = 3 # error conditions -LOG_WARNING = 4 # warning conditions -LOG_NOTICE = 5 # normal but significant condition -LOG_INFO = 6 # informational -LOG_DEBUG = 7 # debug-level messages - -# facility codes -LOG_KERN = 0 # kernel messages -LOG_USER = 1 # random user-level messages -LOG_MAIL = 2 # mail system -LOG_DAEMON = 3 # system daemons -LOG_AUTH = 4 # security/authorization messages -LOG_SYSLOG = 5 # messages generated internally by syslogd -LOG_LPR = 6 # line printer subsystem -LOG_NEWS = 7 # network news subsystem -LOG_UUCP = 8 # UUCP subsystem -LOG_CRON = 9 # clock daemon -LOG_AUTHPRIV = 10 # security/authorization messages (private) - -# other codes through 15 reserved for system use -LOG_LOCAL0 = 16 # reserved for local use -LOG_LOCAL1 = 17 # reserved for local use -LOG_LOCAL2 = 18 # reserved for local use -LOG_LOCAL3 = 19 # reserved for local use -LOG_LOCAL4 = 20 # reserved for local use -LOG_LOCAL5 = 21 # reserved for local use -LOG_LOCAL6 = 22 # reserved for local use -LOG_LOCAL7 = 23 # reserved for local use - -priority_names = { - "alert": LOG_ALERT, - "crit": LOG_CRIT, - "debug": LOG_DEBUG, - "emerg": LOG_EMERG, - "err": LOG_ERR, - "error": LOG_ERR, # DEPRECATED - "info": LOG_INFO, - "notice": LOG_NOTICE, - "panic": LOG_EMERG, # DEPRECATED - "warn": LOG_WARNING, # DEPRECATED - "warning": LOG_WARNING, - } - -facility_names = { - "auth": LOG_AUTH, - "authpriv": LOG_AUTHPRIV, - "cron": LOG_CRON, - "daemon": LOG_DAEMON, - "kern": LOG_KERN, - "lpr": LOG_LPR, - "mail": LOG_MAIL, - "news": LOG_NEWS, - "security": LOG_AUTH, # DEPRECATED - "syslog": LOG_SYSLOG, - "user": LOG_USER, - "uucp": LOG_UUCP, - "local0": LOG_LOCAL0, - "local1": LOG_LOCAL1, - "local2": LOG_LOCAL2, - "local3": LOG_LOCAL3, - "local4": LOG_LOCAL4, - "local5": LOG_LOCAL5, - "local6": LOG_LOCAL6, - "local7": LOG_LOCAL7, - } - -import socket - -class syslog_client: - def __init__ (self, address='/dev/log'): - self.address = address - if type (address) == type(''): - self.socket = socket.socket (socket.AF_UNIX, socket.SOCK_STREAM) - self.socket.connect (address) - self.unix = 1 - else: - self.socket = socket.socket (socket.AF_INET, socket.SOCK_DGRAM) - self.unix = 0 - - # curious: when talking to the unix-domain '/dev/log' socket, a - # zero-terminator seems to be required. this string is placed - # into a class variable so that it can be overridden if - # necessary. - - log_format_string = '<%d>%s\000' - - def log (self, message, facility=LOG_USER, priority=LOG_INFO): - message = self.log_format_string % ( - self.encode_priority (facility, priority), - message - ) - if self.unix: - self.socket.send (message) - else: - self.socket.sendto (message, self.address) - - def encode_priority (self, facility, priority): - if type(facility) == type(''): - facility = facility_names[facility] - if type(priority) == type(''): - priority = priority_names[priority] - return (facility<<3) | priority - - def close (self): - if self.unix: - self.socket.close() - diff --git a/demo/medusa/medusa_gif.py b/demo/medusa/medusa_gif.py deleted file mode 100644 index 005644a..0000000 --- a/demo/medusa/medusa_gif.py +++ /dev/null @@ -1,8 +0,0 @@ -# -*- Mode: Python -*- - -# the medusa icon as a python source file. - -width = 97 -height = 61 - -data = 'GIF89aa\000=\000\204\000\000\000\000\000\255\255\255\245\245\245ssskkkccc111)))\326\326\326!!!\316\316\316\300\300\300\204\204\000\224\224\224\214\214\214\200\200\200RRR\377\377\377JJJ\367\367\367BBB\347\347\347\000\204\000\020\020\020\265\265\265\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000!\371\004\001\000\000\021\000,\000\000\000\000a\000=\000\000\005\376`$\216di\236h\252\256l\353\276p,\317tm\337x\256\357|m\001@\240E\305\000\364\2164\206R)$\005\201\214\007r\012{X\255\312a\004\260\\>\026\3240\353)\224n\001W+X\334\373\231~\344.\303b\216\024\027x<\273\307\255G,rJiWN\014{S}k"?ti\013EdPQ\207G@_%\000\026yy\\\201\202\227\224<\221Fs$pOjWz\241\272\002\325\307g\012(\007\205\312#j\317(\012A\200\224.\241\003\346GS\247\033\245\344\264\366\015L\'PXQl]\266\263\243\232\260?\245\316\371\362\225\035\332\243J\273\332Q\263\357-D\241T\327\270\265\013W&\330\010u\371b\322IW0\214\261]\003\033Va\365Z#\207\213a\030k\2647\262\014p\354\024[n\321N\363\346\317\003\037P\000\235C\302\000\3228(\244\363YaA\005\022\255_\237@\260\000A\212\326\256qbp\321\332\266\011\334=T\023\010"!B\005\003A\010\224\020\220 H\002\337#\020 O\276E\357h\221\327\003\\\000b@v\004\351A.h\365\354\342B\002\011\257\025\\ \220\340\301\353\006\000\024\214\200pA\300\353\012\364\241k/\340\033C\202\003\000\310fZ\011\003V\240R\005\007\354\376\026A\000\000\360\'\202\177\024\004\210\003\000\305\215\360\000\000\015\220\240\332\203\027@\'\202\004\025VpA\000%\210x\321\206\032J\341\316\010\262\211H"l\333\341\200\200>"]P\002\212\011\010`\002\0066FP\200\001\'\024p]\004\027(8B\221\306]\000\201w>\002iB\001\007\340\260"v7J1\343(\257\020\251\243\011\242i\263\017\215\337\035\220\200\221\365m4d\015\016D\251\341iN\354\346Ng\253\200I\240\031\35609\245\2057\311I\302\2007t\231"&`\314\310\244\011e\226(\236\010w\212\300\234\011\012HX(\214\253\311@\001\233^\222pg{% \340\035\224&H\000\246\201\362\215`@\001"L\340\004\030\234\022\250\'\015(V:\302\235\030\240q\337\205\224\212h@\177\006\000\250\210\004\007\310\207\337\005\257-P\346\257\367]p\353\203\271\256:\203\236\211F\340\247\010\3329g\244\010\307*=A\000\203\260y\012\304s#\014\007D\207,N\007\304\265\027\021C\233\207%B\366[m\353\006\006\034j\360\306+\357\274a\204\000\000;' diff --git a/demo/medusa/mime_type_table.py b/demo/medusa/mime_type_table.py deleted file mode 100644 index dbc64a4..0000000 --- a/demo/medusa/mime_type_table.py +++ /dev/null @@ -1,113 +0,0 @@ -# -*- Python -*- -# Converted by ./convert_mime_type_table.py from: -# /usr/src2/apache_1.2b6/conf/mime.types -# -content_type_map = \ - { - 'ai': 'application/postscript', - 'aif': 'audio/x-aiff', - 'aifc': 'audio/x-aiff', - 'aiff': 'audio/x-aiff', - 'au': 'audio/basic', - 'avi': 'video/x-msvideo', - 'bcpio': 'application/x-bcpio', - 'bin': 'application/octet-stream', - 'cdf': 'application/x-netcdf', - 'class': 'application/octet-stream', - 'cpio': 'application/x-cpio', - 'cpt': 'application/mac-compactpro', - 'csh': 'application/x-csh', - 'dcr': 'application/x-director', - 'dir': 'application/x-director', - 'dms': 'application/octet-stream', - 'doc': 'application/msword', - 'dvi': 'application/x-dvi', - 'dxr': 'application/x-director', - 'eps': 'application/postscript', - 'etx': 'text/x-setext', - 'exe': 'application/octet-stream', - 'gif': 'image/gif', - 'gtar': 'application/x-gtar', - 'gz': 'application/x-gzip', - 'hdf': 'application/x-hdf', - 'hqx': 'application/mac-binhex40', - 'htm': 'text/html', - 'html': 'text/html', - 'ice': 'x-conference/x-cooltalk', - 'ief': 'image/ief', - 'jpe': 'image/jpeg', - 'jpeg': 'image/jpeg', - 'jpg': 'image/jpeg', - 'kar': 'audio/midi', - 'latex': 'application/x-latex', - 'lha': 'application/octet-stream', - 'lzh': 'application/octet-stream', - 'man': 'application/x-troff-man', - 'me': 'application/x-troff-me', - 'mid': 'audio/midi', - 'midi': 'audio/midi', - 'mif': 'application/x-mif', - 'mov': 'video/quicktime', - 'movie': 'video/x-sgi-movie', - 'mp2': 'audio/mpeg', - 'mpe': 'video/mpeg', - 'mpeg': 'video/mpeg', - 'mpg': 'video/mpeg', - 'mpga': 'audio/mpeg', - 'mp3': 'audio/mpeg', - 'ms': 'application/x-troff-ms', - 'nc': 'application/x-netcdf', - 'oda': 'application/oda', - 'pbm': 'image/x-portable-bitmap', - 'pdb': 'chemical/x-pdb', - 'pdf': 'application/pdf', - 'pgm': 'image/x-portable-graymap', - 'png': 'image/png', - 'pnm': 'image/x-portable-anymap', - 'ppm': 'image/x-portable-pixmap', - 'ppt': 'application/powerpoint', - 'ps': 'application/postscript', - 'qt': 'video/quicktime', - 'ra': 'audio/x-realaudio', - 'ram': 'audio/x-pn-realaudio', - 'ras': 'image/x-cmu-raster', - 'rgb': 'image/x-rgb', - 'roff': 'application/x-troff', - 'rpm': 'audio/x-pn-realaudio-plugin', - 'rtf': 'application/rtf', - 'rtx': 'text/richtext', - 'sgm': 'text/x-sgml', - 'sgml': 'text/x-sgml', - 'sh': 'application/x-sh', - 'shar': 'application/x-shar', - 'sit': 'application/x-stuffit', - 'skd': 'application/x-koan', - 'skm': 'application/x-koan', - 'skp': 'application/x-koan', - 'skt': 'application/x-koan', - 'snd': 'audio/basic', - 'src': 'application/x-wais-source', - 'sv4cpio': 'application/x-sv4cpio', - 'sv4crc': 'application/x-sv4crc', - 't': 'application/x-troff', - 'tar': 'application/x-tar', - 'tcl': 'application/x-tcl', - 'tex': 'application/x-tex', - 'texi': 'application/x-texinfo', - 'texinfo': 'application/x-texinfo', - 'tif': 'image/tiff', - 'tiff': 'image/tiff', - 'tr': 'application/x-troff', - 'tsv': 'text/tab-separated-values', - 'txt': 'text/plain', - 'ustar': 'application/x-ustar', - 'vcd': 'application/x-cdlink', - 'vrml': 'x-world/x-vrml', - 'wav': 'audio/x-wav', - 'wrl': 'x-world/x-vrml', - 'xbm': 'image/x-xbitmap', - 'xpm': 'image/x-xpixmap', - 'xwd': 'image/x-xwindowdump', - 'xyz': 'chemical/x-pdb', - 'zip': 'application/zip', - } diff --git a/demo/medusa/poison_handler.py b/demo/medusa/poison_handler.py deleted file mode 100644 index acc78ab..0000000 --- a/demo/medusa/poison_handler.py +++ /dev/null @@ -1,69 +0,0 @@ - -import string -import whrandom - -RESP_HEAD="""\ - -""" - -RESP_MIDDLE=""" -

    M2Crypto https server demonstration

    - -This web page is generated by the "poison" http request handler. -
    -The links just go on and on and on... -

    -""" - -RESP_TAIL=""" - -""" - -charset='012345678/90ABCDEFGHIJKLM/NOPQRSTUVWXYZabcd/efghijklmnopqrs/tuvwxyz' -numchar=len(charset) - -def makepage(numlinks): - - title='' - for u in range(whrandom.randint(3, 15)): - pick=whrandom.randint(0, numchar-1) - title=title+charset[pick] - title=title+'' - - url='\r\n' - numlinks=whrandom.randint(2, numlinks) - for i in range(numlinks): - url=url+'' - for u in range(whrandom.randint(3, 15)): - pick=whrandom.randint(0, numchar-1) - url=url+charset[pick] - url=url+'
    \r\n' - - url=RESP_HEAD+title+RESP_MIDDLE+url+RESP_TAIL - return url - - -class poison_handler: - """This is a clone of webpoison - every URL returns a page of URLs, each of which - returns a page of URLs, each of _which_ returns a page of URLs, ad infinitum. - The objective is to sucker address-harvesting bots run by spammers.""" - - def __init__(self, numlinks=10): - self.numlinks = numlinks - self.poison_level = 0 - - def match(self, request): - return (request.uri[:7] == '/poison') - - def handle_request(self, request): - if request.command == 'get': - request.push(makepage(self.numlinks)) - request.done() - diff --git a/demo/medusa/producers.py b/demo/medusa/producers.py deleted file mode 100644 index 2138258..0000000 --- a/demo/medusa/producers.py +++ /dev/null @@ -1,329 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- - -import string - -""" -A collection of producers. -Each producer implements a particular feature: They can be combined -in various ways to get interesting and useful behaviors. - -For example, you can feed dynamically-produced output into the compressing -producer, then wrap this with the 'chunked' transfer-encoding producer. -""" - -class simple_producer: - "producer for a string" - def __init__ (self, data, buffer_size=1024): - self.data = data - self.buffer_size = buffer_size - - def more (self): - if len (self.data) > self.buffer_size: - result = self.data[:self.buffer_size] - self.data = self.data[self.buffer_size:] - return result - else: - result = self.data - self.data = '' - return result - -class scanning_producer: - "like simple_producer, but more efficient for large strings" - def __init__ (self, data, buffer_size=1024): - self.data = data - self.buffer_size = buffer_size - self.pos = 0 - - def more (self): - if self.pos < len(self.data): - lp = self.pos - rp = min ( - len(self.data), - self.pos + self.buffer_size - ) - result = self.data[lp:rp] - self.pos = self.pos + len(result) - return result - else: - return '' - -class lines_producer: - "producer for a list of lines" - - def __init__ (self, lines): - self.lines = lines - - def ready (self): - return len(self.lines) - - def more (self): - if self.lines: - chunk = self.lines[:50] - self.lines = self.lines[50:] - return string.join (chunk, '\r\n') + '\r\n' - else: - return '' - -class buffer_list_producer: - "producer for a list of buffers" - - # i.e., data == string.join (buffers, '') - - def __init__ (self, buffers): - - self.index = 0 - self.buffers = buffers - - def more (self): - if self.index >= len(self.buffers): - return '' - else: - data = self.buffers[self.index] - self.index = self.index + 1 - return data - -class file_producer: - "producer wrapper for file[-like] objects" - - # match http_channel's outgoing buffer size - out_buffer_size = 1<<16 - - def __init__ (self, file): - self.done = 0 - self.file = file - - def more (self): - if self.done: - return '' - else: - data = self.file.read (self.out_buffer_size) - if not data: - self.file.close() - del self.file - self.done = 1 - return '' - else: - return data - -# A simple output producer. This one does not [yet] have -# the safety feature builtin to the monitor channel: runaway -# output will not be caught. - -# don't try to print from within any of the methods -# of this object. - -class output_producer: - "Acts like an output file; suitable for capturing sys.stdout" - def __init__ (self): - self.data = '' - - def write (self, data): - lines = string.splitfields (data, '\n') - data = string.join (lines, '\r\n') - self.data = self.data + data - - def writeline (self, line): - self.data = self.data + line + '\r\n' - - def writelines (self, lines): - self.data = self.data + string.joinfields ( - lines, - '\r\n' - ) + '\r\n' - - def ready (self): - return (len (self.data) > 0) - - def flush (self): - pass - - def softspace (self, *args): - pass - - def more (self): - if self.data: - result = self.data[:512] - self.data = self.data[512:] - return result - else: - return '' - -class composite_producer: - "combine a fifo of producers into one" - def __init__ (self, producers): - self.producers = producers - - def more (self): - while len(self.producers): - p = self.producers.first() - d = p.more() - if d: - return d - else: - self.producers.pop() - else: - return '' - - -class globbing_producer: - """ - 'glob' the output from a producer into a particular buffer size. - helps reduce the number of calls to send(). [this appears to - gain about 30% performance on requests to a single channel] - """ - - def __init__ (self, producer, buffer_size=1<<16): - self.producer = producer - self.buffer = '' - self.buffer_size = buffer_size - - def more (self): - while len(self.buffer) < self.buffer_size: - data = self.producer.more() - if data: - self.buffer = self.buffer + data - else: - break - r = self.buffer - self.buffer = '' - return r - - -class hooked_producer: - """ - A producer that will call when it empties,. - with an argument of the number of bytes produced. Useful - for logging/instrumentation purposes. - """ - - def __init__ (self, producer, function): - self.producer = producer - self.function = function - self.bytes = 0 - - def more (self): - if self.producer: - result = self.producer.more() - if not result: - self.producer = None - self.function (self.bytes) - else: - self.bytes = self.bytes + len(result) - return result - else: - return '' - -# HTTP 1.1 emphasizes that an advertised Content-Length header MUST be -# correct. In the face of Strange Files, it is conceivable that -# reading a 'file' may produce an amount of data not matching that -# reported by os.stat() [text/binary mode issues, perhaps the file is -# being appended to, etc..] This makes the chunked encoding a True -# Blessing, and it really ought to be used even with normal files. -# How beautifully it blends with the concept of the producer. - -class chunked_producer: - """A producer that implements the 'chunked' transfer coding for HTTP/1.1. - Here is a sample usage: - request['Transfer-Encoding'] = 'chunked' - request.push ( - producers.chunked_producer (your_producer) - ) - request.done() - """ - - def __init__ (self, producer, footers=None): - self.producer = producer - self.footers = footers - - def more (self): - if self.producer: - data = self.producer.more() - if data: - return '%x\r\n%s\r\n' % (len(data), data) - else: - self.producer = None - if self.footers: - return string.join ( - ['0'] + self.footers, - '\r\n' - ) + '\r\n\r\n' - else: - return '0\r\n\r\n' - else: - return '' - -# Unfortunately this isn't very useful right now (Aug 97), because -# apparently the browsers don't do on-the-fly decompression. Which -# is sad, because this could _really_ speed things up, especially for -# low-bandwidth clients (i.e., most everyone). - -try: - import zlib -except ImportError: - zlib = None - -class compressed_producer: - """ - Compress another producer on-the-fly, using ZLIB - [Unfortunately, none of the current browsers seem to support this] - """ - - # Note: It's not very efficient to have the server repeatedly - # compressing your outgoing files: compress them ahead of time, or - # use a compress-once-and-store scheme. However, if you have low - # bandwidth and low traffic, this may make more sense than - # maintaining your source files compressed. - # - # Can also be used for compressing dynamically-produced output. - - def __init__ (self, producer, level=5): - self.producer = producer - self.compressor = zlib.compressobj (level) - - def more (self): - if self.producer: - cdata = '' - # feed until we get some output - while not cdata: - data = self.producer.more() - if not data: - self.producer = None - return self.compressor.flush() - else: - cdata = self.compressor.compress (data) - return cdata - else: - return '' - -class escaping_producer: - - "A producer that escapes a sequence of characters" - " Common usage: escaping the CRLF.CRLF sequence in SMTP, NNTP, etc..." - - def __init__ (self, producer, esc_from='\r\n.', esc_to='\r\n..'): - self.producer = producer - self.esc_from = esc_from - self.esc_to = esc_to - self.buffer = '' - from asynchat import find_prefix_at_end - self.find_prefix_at_end = find_prefix_at_end - - def more (self): - esc_from = self.esc_from - esc_to = self.esc_to - - buffer = self.buffer + self.producer.more() - - if buffer: - buffer = string.replace (buffer, esc_from, esc_to) - i = self.find_prefix_at_end (buffer, esc_from) - if i: - # we found a prefix - self.buffer = buffer[-i:] - return buffer[:-i] - else: - # no prefix, return it all - self.buffer = '' - return buffer - else: - return buffer diff --git a/demo/medusa/put_handler.py b/demo/medusa/put_handler.py deleted file mode 100644 index 488fb42..0000000 --- a/demo/medusa/put_handler.py +++ /dev/null @@ -1,113 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- -# -# Author: Sam Rushing -# Copyright 1996-2000 by Sam Rushing -# All Rights Reserved. -# - -import re -import string - -import default_handler -unquote = default_handler.unquote -get_header = default_handler.get_header - -last_request = None - -class put_handler: - def __init__ (self, filesystem, uri_regex): - self.filesystem = filesystem - if type (uri_regex) == type(''): - self.uri_regex = re.compile (uri_regex) - else: - self.uri_regex = uri_regex - - def match (self, request): - uri = request.uri - if request.command == 'put': - m = self.uri_regex.match (uri) - if m and m.end() == len(uri): - return 1 - return 0 - - def handle_request (self, request): - - path, params, query, fragment = request.split_uri() - - # strip off leading slashes - while path and path[0] == '/': - path = path[1:] - - if '%' in path: - path = unquote (path) - - # make sure there's a content-length header - cl = get_header (CONTENT_LENGTH, request.header) - if not cl: - request.error (411) - return - else: - cl = string.atoi (cl) - - # don't let the try to overwrite a directory - if self.filesystem.isdir (path): - request.error (405) - return - - is_update = self.filesystem.isfile (path) - - try: - output_file = self.filesystem.open (path, 'wb') - except: - request.error (405) - return - - request.collector = put_collector (output_file, cl, request, is_update) - - # no terminator while receiving PUT data - request.channel.set_terminator (None) - - # don't respond yet, wait until we've received the data... - -class put_collector: - def __init__ (self, file, length, request, is_update): - self.file = file - self.length = length - self.request = request - self.is_update = is_update - self.bytes_in = 0 - - def collect_incoming_data (self, data): - ld = len(data) - bi = self.bytes_in - if (bi + ld) >= self.length: - # last bit of data - chunk = self.length - bi - self.file.write (data[:chunk]) - self.file.close() - - if chunk != ld: - print 'orphaned %d bytes: <%s>' % (ld - chunk, repr(data[chunk:])) - - # do some housekeeping - r = self.request - ch = r.channel - ch.current_request = None - # set the terminator back to the default - ch.set_terminator ('\r\n\r\n') - if self.is_update: - r.reply_code = 204 # No content - r.done() - else: - r.reply_now (201) # Created - # avoid circular reference - del self.request - else: - self.file.write (data) - self.bytes_in = self.bytes_in + ld - - def found_terminator (self): - # shouldn't be called - pass - -CONTENT_LENGTH = re.compile ('Content-Length: ([0-9]+)', re.IGNORECASE) diff --git a/demo/medusa/redirecting_handler.py b/demo/medusa/redirecting_handler.py deleted file mode 100644 index e6a1e90..0000000 --- a/demo/medusa/redirecting_handler.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- -# -# Author: Sam Rushing -# Copyright 1996-2000 by Sam Rushing -# All Rights Reserved. -# - -import re -import counter - -class redirecting_handler: - - def __init__ (self, pattern, redirect, regex_flag=re.IGNORECASE): - self.pattern = pattern - self.redirect = redirect - self.patreg = re.compile (pattern, regex_flag) - self.hits = counter.counter() - - def match (self, request): - m = self.patref.match (request.uri) - return (m and (m.end() == len(request.uri))) - - def handle_request (self, request): - self.hits.increment() - m = self.patreg.match (request.uri) - part = m.group(1) - - request['Location'] = self.redirect % part - request.error (302) # moved temporarily - - def __repr__ (self): - return ' %s]>' % ( - id(self), - repr(self.pattern), - repr(self.redirect) - ) - - def status (self): - import producers - return producers.simple_producer ( - '
  • Redirecting Handler %s => %s Hits: %s' % ( - self.pattern, self.redirect, self.hits - ) - ) diff --git a/demo/medusa/server.pem b/demo/medusa/server.pem deleted file mode 100644 index 1ee9282..0000000 --- a/demo/medusa/server.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx -NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls -b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c -kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 -KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp -/y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 -QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB -H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 -du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv -MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm -aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t -ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy -lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW -iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 -0QkPQNdP ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu -6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe -I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB -AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ -u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 -xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 -1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp -IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx -luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I -lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS -38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy -v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z -DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= ------END RSA PRIVATE KEY----- diff --git a/demo/medusa/status_handler.py b/demo/medusa/status_handler.py deleted file mode 100644 index 2e6223e..0000000 --- a/demo/medusa/status_handler.py +++ /dev/null @@ -1,282 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- - -VERSION_STRING = "$Id: status_handler.py 299 2005-06-09 17:32:28Z heikki $" - -# -# medusa status extension -# - -import string -import time -import re - -import asyncore -import http_server -import medusa_gif -import producers -from counter import counter - -START_TIME = long(time.time()) - -class status_extension: - hit_counter = counter() - - def __init__ (self, objects, statusdir='/status', allow_emergency_debug=0): - self.objects = objects - self.statusdir = statusdir - self.allow_emergency_debug = allow_emergency_debug - # We use /status instead of statusdir here because it's too - # hard to pass statusdir to the logger, who makes the HREF - # to the object dir. We don't need the security-through- - # obscurity here in any case, because the id is obscurity enough - self.hyper_regex = re.compile('/status/object/([0-9]+)/.*') - self.hyper_objects = [] - for object in objects: - self.register_hyper_object (object) - - def __repr__ (self): - return '' % ( - self.hit_counter, - id(self) - ) - - def match (self, request): - path, params, query, fragment = request.split_uri() - # For reasons explained above, we don't use statusdir for /object - return (path[:len(self.statusdir)] == self.statusdir or - path[:len("/status/object/")] == '/status/object/') - - # Possible Targets: - # /status - # /status/channel_list - # /status/medusa.gif - - # can we have 'clickable' objects? - # [yes, we can use id(x) and do a linear search] - - # Dynamic producers: - # HTTP/1.0: we must close the channel, because it's dynamic output - # HTTP/1.1: we can use the chunked transfer-encoding, and leave - # it open. - - def handle_request (self, request): - [path, params, query, fragment] = request.split_uri() - self.hit_counter.increment() - if path == self.statusdir: # and not a subdirectory - up_time = string.join (english_time (long(time.time()) - START_TIME)) - request['Content-Type'] = 'text/html' - request.push ( - '' - 'Medusa Status Reports' - '' - '

    Medusa Status Reports

    ' - 'Up: %s' % up_time - ) - for i in range(len(self.objects)): - request.push (self.objects[i].status()) - request.push ('
    \r\n') - request.push ( - '

    Channel List' - '


    ' - '' - '' % ( - self.statusdir, - self.statusdir, - medusa_gif.width, - medusa_gif.height - ) - ) - request.done() - elif path == self.statusdir + '/channel_list': - request['Content-Type'] = 'text/html' - request.push ('') - request.push(channel_list_producer(self.statusdir)) - request.push ( - '
    ' - '' % ( - self.statusdir, - medusa_gif.width, - medusa_gif.height - ) + - '' - ) - request.done() - - elif path == self.statusdir + '/medusa.gif': - request['Content-Type'] = 'image/gif' - request['Content-Length'] = len(medusa_gif.data) - request.push (medusa_gif.data) - request.done() - - elif path == self.statusdir + '/close_zombies': - message = ( - '

    Closing all zombie http client connections...

    ' - '

    Back to the status page' % self.statusdir - ) - request['Content-Type'] = 'text/html' - request['Content-Length'] = len (message) - request.push (message) - now = int (time.time()) - for channel in asyncore.socket_map.keys(): - if channel.__class__ == http_server.http_channel: - if channel != request.channel: - if (now - channel.creation_time) > channel.zombie_timeout: - channel.close() - request.done() - - # Emergency Debug Mode - # If a server is running away from you, don't KILL it! - # Move all the AF_INET server ports and perform an autopsy... - # [disabled by default to protect the innocent] - elif self.allow_emergency_debug and path == self.statusdir + '/emergency_debug': - request.push ('Moving All Servers...') - request.done() - for channel in asyncore.socket_map.keys(): - if channel.accepting: - if type(channel.addr) is type(()): - ip, port = channel.addr - channel.socket.close() - channel.del_channel() - channel.addr = (ip, port+10000) - fam, typ = channel.family_and_type - channel.create_socket (fam, typ) - channel.set_reuse_addr() - channel.bind (channel.addr) - channel.listen(5) - - else: - m = self.hyper_regex.match (path) - if m: - oid = string.atoi (m.group (1)) - for object in self.hyper_objects: - if id (object) == oid: - if hasattr (object, 'hyper_respond'): - object.hyper_respond (self, path, request) - else: - request.error (404) - return - - def status (self): - return producers.simple_producer ( - '

  • Status Extension Hits : %s' % self.hit_counter - ) - - def register_hyper_object (self, object): - if not object in self.hyper_objects: - self.hyper_objects.append (object) - -import logger - -class logger_for_status (logger.tail_logger): - - def status (self): - return 'Last %d log entries for: %s' % ( - len (self.messages), - html_repr (self) - ) - - def hyper_respond (self, sh, path, request): - request['Content-Type'] = 'text/plain' - messages = self.messages[:] - messages.reverse() - request.push (lines_producer (messages)) - request.done() - -class lines_producer: - def __init__ (self, lines): - self.lines = lines - - def ready (self): - return len(self.lines) - - def more (self): - if self.lines: - chunk = self.lines[:50] - self.lines = self.lines[50:] - return string.join (chunk, '\r\n') + '\r\n' - else: - return '' - -class channel_list_producer (lines_producer): - def __init__ (self, statusdir): - channel_reprs = map ( - lambda x: '<' + repr(x)[1:-1] + '>', - asyncore.socket_map.values() - ) - channel_reprs.sort() - lines_producer.__init__ ( - self, - ['

    Active Channel List

    ', - '
    '
    -			 ] + channel_reprs + [
    -				 '
    ', - '

    Status Report' % statusdir - ] - ) - - -# this really needs a full-blown quoter... -def sanitize (s): - if '<' in s: - s = string.join (string.split (s, '<'), '<') - if '>' in s: - s = string.join (string.split (s, '>'), '>') - return s - -def html_repr (object): - so = sanitize (repr (object)) - if hasattr (object, 'hyper_respond'): - return '%s' % (id (object), so) - else: - return so - -def html_reprs (list, front='', back=''): - reprs = map ( - lambda x,f=front,b=back: '%s%s%s' % (f,x,b), - map (lambda x: sanitize (html_repr(x)), list) - ) - reprs.sort() - return reprs - -# for example, tera, giga, mega, kilo -# p_d (n, (1024, 1024, 1024, 1024)) -# smallest divider goes first - for example -# minutes, hours, days -# p_d (n, (60, 60, 24)) - -def progressive_divide (n, parts): - result = [] - for part in parts: - n, rem = divmod (n, part) - result.append (rem) - result.append (n) - return result - -# b,k,m,g,t -def split_by_units (n, units, dividers, format_string): - divs = progressive_divide (n, dividers) - result = [] - for i in range(len(units)): - if divs[i]: - result.append (format_string % (divs[i], units[i])) - result.reverse() - if not result: - return [format_string % (0, units[0])] - else: - return result - -def english_bytes (n): - return split_by_units ( - n, - ('','K','M','G','T'), - (1024, 1024, 1024, 1024, 1024), - '%d %sB' - ) - -def english_time (n): - return split_by_units ( - n, - ('secs', 'mins', 'hours', 'days', 'weeks', 'years'), - ( 60, 60, 24, 7, 52), - '%d %s' - ) diff --git a/demo/medusa/virtual_handler.py b/demo/medusa/virtual_handler.py deleted file mode 100644 index 96f19df..0000000 --- a/demo/medusa/virtual_handler.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- - -import socket -import default_handler -import re - -HOST = re.compile ('Host: ([^:/]+).*', re.IGNORECASE) - -get_header = default_handler.get_header - -class virtual_handler: - - """HTTP request handler for an HTTP/1.0-style virtual host. Each - Virtual host must have a different IP""" - - def __init__ (self, handler, hostname): - self.handler = handler - self.hostname = hostname - try: - self.ip = socket.gethostbyname (hostname) - except socket.error: - raise ValueError, "Virtual Hostname %s does not appear to be registered in the DNS" % hostname - - def match (self, request): - if (request.channel.addr[0] == self.ip): - return 1 - else: - return 0 - - def handle_request (self, request): - return self.handler.handle_request (request) - - def __repr__ (self): - return '' % self.hostname - - -class virtual_handler_with_host: - - """HTTP request handler for HTTP/1.1-style virtual hosts. This - matches by checking the value of the 'Host' header in the request. - You actually don't _have_ to support HTTP/1.1 to use this, since - many browsers now send the 'Host' header. This is a Good Thing.""" - - def __init__ (self, handler, hostname): - self.handler = handler - self.hostname = hostname - - def match (self, request): - host = get_header (HOST, request.header) - if host == self.hostname: - return 1 - else: - return 0 - - def handle_request (self, request): - return self.handler.handle_request (request) - - def __repr__ (self): - return '' % self.hostname - diff --git a/demo/medusa/xmlrpc_handler.py b/demo/medusa/xmlrpc_handler.py deleted file mode 100644 index d56baf2..0000000 --- a/demo/medusa/xmlrpc_handler.py +++ /dev/null @@ -1,104 +0,0 @@ -# -*- Mode: Python; tab-width: 4 -*- - -# See http://www.xml-rpc.com/ -# http://www.pythonware.com/products/xmlrpc/ - -# Based on "xmlrpcserver.py" by Fredrik Lundh (fredrik@pythonware.com) - -VERSION = "$Id: xmlrpc_handler.py 299 2005-06-09 17:32:28Z heikki $" - -import http_server -import xmlrpclib - -import string -import sys - -class xmlrpc_handler: - - def match (self, request): - # Note: /RPC2 is not required by the spec, so you may override this method. - if request.uri[:5] == '/RPC2': - return 1 - else: - return 0 - - def handle_request (self, request): - [path, params, query, fragment] = request.split_uri() - - if request.command in ('post', 'put'): - request.collector = collector (self, request) - else: - request.error (400) - - def continue_request (self, data, request): - params, method = xmlrpclib.loads (data) - try: - # generate response - try: - response = self.call (method, params) - if type(response) != type(()): - response = (response,) - except: - # report exception back to server - response = xmlrpclib.dumps ( - xmlrpclib.Fault (1, "%s:%s" % (sys.exc_type, sys.exc_value)) - ) - else: - response = xmlrpclib.dumps (response, methodresponse=1) - except: - # internal error, report as HTTP server error - request.error (500) - else: - # got a valid XML RPC response - request['Content-Type'] = 'text/xml' - request.push (response) - request.done() - - def call (self, method, params): - # override this method to implement RPC methods - raise "NotYetImplemented" - -class collector: - - "gathers input for POST and PUT requests" - - def __init__ (self, handler, request): - - self.handler = handler - self.request = request - self.data = '' - - # make sure there's a content-length header - cl = request.get_header ('content-length') - - if not cl: - request.error (411) - else: - cl = string.atoi (cl) - # using a 'numeric' terminator - self.request.channel.set_terminator (cl) - - def collect_incoming_data (self, data): - self.data = self.data + data - - def found_terminator (self): - # set the terminator back to the default - self.request.channel.set_terminator ('\r\n\r\n') - self.handler.continue_request (self.data, self.request) - -if __name__ == '__main__': - - class rpc_demo (xmlrpc_handler): - - def call (self, method, params): - print 'method="%s" params=%s' % (method, params) - return "Sure, that works" - - import asyncore - import http_server - - hs = http_server.http_server ('', 8000) - rpc = rpc_demo() - hs.install_handler (rpc) - - asyncore.loop() diff --git a/demo/medusa054/00_README b/demo/medusa054/00_README deleted file mode 100644 index 5701364..0000000 --- a/demo/medusa054/00_README +++ /dev/null @@ -1,30 +0,0 @@ - - 21 Mar 2004 -------------- - -M2Crypto HTTPS and FTP/TLS servers - -All the files in this directory are from Medusa 0.54, except for the -following: - -- 00_README (this file) -- server.pem, the server's certificate -- ca.pem, my CA certificate -- https_server.py -- ftps_server.py -- START.py -- START_xmlrpc.py -- index.html, a sample HTML file -- poison_handler.py, a webpoison clone - -By default, http_server listens on port 39080 and https_server port -39443. Document root is current directory, and serves up index.html. - -The xmlrpc server is accessible below '/RPC2'. - -The FTP/TLS server listens on port 39021 by default. I've only tested it with -the 'anonymous' authentication handler. - -Medusa files are copyright Sam Rushing. Recent versions are maintained -by Andrew Kuchling. My files are copyright me. - diff --git a/demo/medusa054/START.py b/demo/medusa054/START.py deleted file mode 100644 index fb08ab3..0000000 --- a/demo/medusa054/START.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python - -# Standard Python library -import os -import os.path -import sys - -# Medusa -import asyncore -import default_handler -import filesys -import ftp_server -import http_server -import status_handler - -# M2Crypto -import https_server -import poison_handler -import ftps_server -from M2Crypto import Rand, SSL, threading - -HTTP_PORT=39080 -HTTPS_PORT=39443 -FTP_PORT = 39021 - -hs=http_server.http_server('', HTTP_PORT) - -Rand.load_file('../randpool.dat', -1) -ssl_ctx=SSL.Context('sslv23') -ssl_ctx.load_cert('server.pem') -ssl_ctx.load_verify_locations('ca.pem', '') -ssl_ctx.load_client_CA('ca.pem') -#ssl_ctx.set_verify(SSL.verify_peer, 10) -#ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) -#ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_client_once, 10) -ssl_ctx.set_verify(SSL.verify_none, 10) -ssl_ctx.set_session_id_ctx('127.0.0.1:39443') -ssl_ctx.set_tmp_dh('dh1024.pem') -ssl_ctx.set_info_callback() - -hss=https_server.https_server('', HTTPS_PORT, ssl_ctx) - -fs=filesys.os_filesystem(os.path.abspath(os.curdir)) -#fs=filesys.os_filesystem('/usr/local/pkg/apache/htdocs') -#fs=filesys.os_filesystem('c:/pkg/jdk130/docs') -dh=default_handler.default_handler(fs) -hs.install_handler(dh) -hss.install_handler(dh) - -#class rpc_demo (xmlrpc_handler.xmlrpc_handler): -# def call (self, method, params): -# print 'method="%s" params=%s' % (method, params) -# return "Sure, that works" -#rpch = rpc_demo() -#hs.install_handler(rpch) -#hss.install_handler(rpch) - -ph=poison_handler.poison_handler(10) -hs.install_handler(ph) -hss.install_handler(ph) - -fauthz = ftp_server.anon_authorizer('/usr/local/pkg/apache/htdocs') -ftps = ftps_server.ftp_tls_server(fauthz, ssl_ctx, port=FTP_PORT) - -sh=status_handler.status_extension([hs, hss, ftps]) -hs.install_handler(sh) -hss.install_handler(sh) - -asyncore.loop() -Rand.save_file('../randpool.dat') - diff --git a/demo/medusa054/START_xmlrpc.py b/demo/medusa054/START_xmlrpc.py deleted file mode 100644 index 65b6d67..0000000 --- a/demo/medusa054/START_xmlrpc.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python - -# Standard Python library -import os -import os.path -import sys - -# Medusa -import asyncore -import default_handler -import filesys -import http_server -import status_handler - -# M2Crypto -import https_server -import poison_handler -from M2Crypto import Rand, SSL - -# XMLrpc -import xmlrpc_handler - - -HTTP_PORT=39080 -HTTPS_PORT=39443 - -hs=http_server.http_server('', HTTP_PORT) - -Rand.load_file('../randpool.dat', -1) -ssl_ctx=SSL.Context('sslv23') -ssl_ctx.load_cert('server.pem') -#ssl_ctx.load_verify_location('ca.pem') -#ssl_ctx.load_client_CA('ca.pem') -#ssl_ctx.set_verify(SSL.verify_peer, 10) -#ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) -#ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_client_once, 10) -ssl_ctx.set_verify(SSL.verify_none, 10) -ssl_ctx.set_session_id_ctx('127.0.0.1:9443') -ssl_ctx.set_tmp_dh('dh1024.pem') -#ssl_ctx.set_info_callback() - -hss=https_server.https_server('', HTTPS_PORT, ssl_ctx) - -fs=filesys.os_filesystem(os.path.abspath(os.curdir)) -#fs=filesys.os_filesystem('/usr/local/pkg/apache/htdocs') -#fs=filesys.os_filesystem('c:/pkg/jdk118/docs') -dh=default_handler.default_handler(fs) -hs.install_handler(dh) -hss.install_handler(dh) - -# Cribbed from xmlrpc_handler.py. -# This is where you implement your RPC functionality. -class rpc_demo (xmlrpc_handler.xmlrpc_handler): - def call (self, method, params): - print 'method="%s" params=%s' % (method, params) - return "Sure, that works" - -rpch = rpc_demo() -hs.install_handler(rpch) -hss.install_handler(rpch) - -ph=poison_handler.poison_handler(10) -hs.install_handler(ph) -hss.install_handler(ph) - -sh=status_handler.status_extension([hss]) -hs.install_handler(sh) -hss.install_handler(sh) - -asyncore.loop() -Rand.save_file('../randpool.dat') - diff --git a/demo/medusa054/ca.pem b/demo/medusa054/ca.pem deleted file mode 100644 index b7c84a1..0000000 --- a/demo/medusa054/ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 -NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML -TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl -cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK -q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N -e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf -q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G -A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV -BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex -JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 -DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG -SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ -dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J -vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf ------END CERTIFICATE----- diff --git a/demo/medusa054/counter.py b/demo/medusa054/counter.py deleted file mode 100644 index 9dae67c..0000000 --- a/demo/medusa054/counter.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- Mode: Python -*- - -# It is tempting to add an __int__ method to this class, but it's not -# a good idea. This class tries to gracefully handle integer -# overflow, and to hide this detail from both the programmer and the -# user. Note that the __str__ method can be relied on for printing out -# the value of a counter: -# -# >>> print 'Total Client: %s' % self.total_clients -# -# If you need to do arithmetic with the value, then use the 'as_long' -# method, the use of long arithmetic is a reminder that the counter -# will overflow. - -class counter: - "general-purpose counter" - - def __init__ (self, initial_value=0): - self.value = initial_value - - def increment (self, delta=1): - result = self.value - try: - self.value = self.value + delta - except OverflowError: - self.value = long(self.value) + delta - return result - - def decrement (self, delta=1): - result = self.value - try: - self.value = self.value - delta - except OverflowError: - self.value = long(self.value) - delta - return result - - def as_long (self): - return long(self.value) - - def __nonzero__ (self): - return self.value != 0 - - def __repr__ (self): - return '' % (self.value, id(self)) - - def __str__ (self): - s = str(long(self.value)) - if s[-1:] == 'L': - s = s[:-1] - return s - diff --git a/demo/medusa054/default_handler.py b/demo/medusa054/default_handler.py deleted file mode 100644 index 9d5e9d7..0000000 --- a/demo/medusa054/default_handler.py +++ /dev/null @@ -1,213 +0,0 @@ -# -*- Mode: Python -*- -# -# Author: Sam Rushing -# Copyright 1997 by Sam Rushing -# All Rights Reserved. -# - -# standard python modules -import mimetypes -import re -import stat -import string - -# medusa modules -import http_date -import http_server -import status_handler -import producers - -unquote = http_server.unquote - -# This is the 'default' handler. it implements the base set of -# features expected of a simple file-delivering HTTP server. file -# services are provided through a 'filesystem' object, the very same -# one used by the FTP server. -# -# You can replace or modify this handler if you want a non-standard -# HTTP server. You can also derive your own handler classes from -# it. -# -# support for handling POST requests is available in the derived -# class , defined below. -# - -from counter import counter - -class default_handler: - - valid_commands = ['GET', 'HEAD'] - - IDENT = 'Default HTTP Request Handler' - - # Pathnames that are tried when a URI resolves to a directory name - directory_defaults = [ - 'index.html', - 'default.html' - ] - - default_file_producer = producers.file_producer - - def __init__ (self, filesystem): - self.filesystem = filesystem - # count total hits - self.hit_counter = counter() - # count file deliveries - self.file_counter = counter() - # count cache hits - self.cache_counter = counter() - - hit_counter = 0 - - def __repr__ (self): - return '<%s (%s hits) at %x>' % ( - self.IDENT, - self.hit_counter, - id (self) - ) - - # always match, since this is a default - def match (self, request): - return 1 - - # handle a file request, with caching. - - def handle_request (self, request): - - if request.command not in self.valid_commands: - request.error (400) # bad request - return - - self.hit_counter.increment() - - path, params, query, fragment = request.split_uri() - - if '%' in path: - path = unquote (path) - - # strip off all leading slashes - while path and path[0] == '/': - path = path[1:] - - if self.filesystem.isdir (path): - if path and path[-1] != '/': - request['Location'] = 'http://%s/%s/' % ( - request.channel.server.server_name, - path - ) - request.error (301) - return - - # we could also generate a directory listing here, - # may want to move this into another method for that - # purpose - found = 0 - if path and path[-1] != '/': - path = path + '/' - for default in self.directory_defaults: - p = path + default - if self.filesystem.isfile (p): - path = p - found = 1 - break - if not found: - request.error (404) # Not Found - return - - elif not self.filesystem.isfile (path): - request.error (404) # Not Found - return - - file_length = self.filesystem.stat (path)[stat.ST_SIZE] - - ims = get_header_match (IF_MODIFIED_SINCE, request.header) - - length_match = 1 - if ims: - length = ims.group (4) - if length: - try: - length = string.atoi (length) - if length != file_length: - length_match = 0 - except: - pass - - ims_date = 0 - - if ims: - ims_date = http_date.parse_http_date (ims.group (1)) - - try: - mtime = self.filesystem.stat (path)[stat.ST_MTIME] - except: - request.error (404) - return - - if length_match and ims_date: - if mtime <= ims_date: - request.reply_code = 304 - request.done() - self.cache_counter.increment() - return - try: - file = self.filesystem.open (path, 'rb') - except IOError: - request.error (404) - return - - request['Last-Modified'] = http_date.build_http_date (mtime) - request['Content-Length'] = file_length - self.set_content_type (path, request) - - if request.command == 'GET': - request.push (self.default_file_producer (file)) - - self.file_counter.increment() - request.done() - - def set_content_type (self, path, request): - ext = string.lower (get_extension (path)) - typ, encoding = mimetypes.guess_type(path) - if typ is not None: - request['Content-Type'] = typ - else: - # TODO: test a chunk off the front of the file for 8-bit - # characters, and use application/octet-stream instead. - request['Content-Type'] = 'text/plain' - - def status (self): - return producers.simple_producer ( - '

  • %s' % status_handler.html_repr (self) - + '
      ' - + '
    • Total Hits: %s' % self.hit_counter - + '
    • Files Delivered: %s' % self.file_counter - + '
    • Cache Hits: %s' % self.cache_counter - + '
    ' - ) - -# HTTP/1.0 doesn't say anything about the "; length=nnnn" addition -# to this header. I suppose its purpose is to avoid the overhead -# of parsing dates... -IF_MODIFIED_SINCE = re.compile ( - 'If-Modified-Since: ([^;]+)((; length=([0-9]+)$)|$)', - re.IGNORECASE - ) - -USER_AGENT = re.compile ('User-Agent: (.*)', re.IGNORECASE) - -CONTENT_TYPE = re.compile ( - r'Content-Type: ([^;]+)((; boundary=([A-Za-z0-9\'\(\)+_,./:=?-]+)$)|$)', - re.IGNORECASE - ) - -get_header = http_server.get_header -get_header_match = http_server.get_header_match - -def get_extension (path): - dirsep = string.rfind (path, '/') - dotsep = string.rfind (path, '.') - if dotsep > dirsep: - return path[dotsep+1:] - else: - return '' diff --git a/demo/medusa054/dh1024.pem b/demo/medusa054/dh1024.pem deleted file mode 100644 index 81d43f6..0000000 --- a/demo/medusa054/dh1024.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq -/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx -/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC ------END DH PARAMETERS----- diff --git a/demo/medusa054/filesys.py b/demo/medusa054/filesys.py deleted file mode 100644 index 1affd8f..0000000 --- a/demo/medusa054/filesys.py +++ /dev/null @@ -1,394 +0,0 @@ -# -*- Mode: Python -*- -# $Id: filesys.py 299 2005-06-09 17:32:28Z heikki $ -# Author: Sam Rushing -# -# Generic filesystem interface. -# - -# We want to provide a complete wrapper around any and all -# filesystem operations. - -# this class is really just for documentation, -# identifying the API for a filesystem object. - -# opening files for reading, and listing directories, should -# return a producer. - -class abstract_filesystem: - def __init__ (self): - pass - - def current_directory (self): - "Return a string representing the current directory." - pass - - def listdir (self, path, long=0): - """Return a listing of the directory at 'path' The empty string - indicates the current directory. If 'long' is set, instead - return a list of (name, stat_info) tuples - """ - pass - - def open (self, path, mode): - "Return an open file object" - pass - - def stat (self, path): - "Return the equivalent of os.stat() on the given path." - pass - - def isdir (self, path): - "Does the path represent a directory?" - pass - - def isfile (self, path): - "Does the path represent a plain file?" - pass - - def cwd (self, path): - "Change the working directory." - pass - - def cdup (self): - "Change to the parent of the current directory." - pass - - - def longify (self, path): - """Return a 'long' representation of the filename - [for the output of the LIST command]""" - pass - -# standard wrapper around a unix-like filesystem, with a 'false root' -# capability. - -# security considerations: can symbolic links be used to 'escape' the -# root? should we allow it? if not, then we could scan the -# filesystem on startup, but that would not help if they were added -# later. We will probably need to check for symlinks in the cwd method. - -# what to do if wd is an invalid directory? - -import os -import stat -import re -import string - -def safe_stat (path): - try: - return (path, os.stat (path)) - except: - return None - -import glob - -class os_filesystem: - path_module = os.path - - # set this to zero if you want to disable pathname globbing. - # [we currently don't glob, anyway] - do_globbing = 1 - - def __init__ (self, root, wd='/'): - self.root = root - self.wd = wd - - def current_directory (self): - return self.wd - - def isfile (self, path): - p = self.normalize (self.path_module.join (self.wd, path)) - return self.path_module.isfile (self.translate(p)) - - def isdir (self, path): - p = self.normalize (self.path_module.join (self.wd, path)) - return self.path_module.isdir (self.translate(p)) - - def cwd (self, path): - p = self.normalize (self.path_module.join (self.wd, path)) - translated_path = self.translate(p) - if not self.path_module.isdir (translated_path): - return 0 - else: - old_dir = os.getcwd() - # temporarily change to that directory, in order - # to see if we have permission to do so. - try: - can = 0 - try: - os.chdir (translated_path) - can = 1 - self.wd = p - except: - pass - finally: - if can: - os.chdir (old_dir) - return can - - def cdup (self): - return self.cwd ('..') - - def listdir (self, path, long=0): - p = self.translate (path) - # I think we should glob, but limit it to the current - # directory only. - ld = os.listdir (p) - if not long: - return list_producer (ld, None) - else: - old_dir = os.getcwd() - try: - os.chdir (p) - # if os.stat fails we ignore that file. - result = filter (None, map (safe_stat, ld)) - finally: - os.chdir (old_dir) - return list_producer (result, self.longify) - - # TODO: implement a cache w/timeout for stat() - def stat (self, path): - p = self.translate (path) - return os.stat (p) - - def open (self, path, mode): - p = self.translate (path) - return open (p, mode) - - def unlink (self, path): - p = self.translate (path) - return os.unlink (p) - - def mkdir (self, path): - p = self.translate (path) - return os.mkdir (p) - - def rmdir (self, path): - p = self.translate (path) - return os.rmdir (p) - - # utility methods - def normalize (self, path): - # watch for the ever-sneaky '/+' path element - path = re.sub('/+', '/', path) - p = self.path_module.normpath (path) - # remove 'dangling' cdup's. - if len(p) > 2 and p[:3] == '/..': - p = '/' - return p - - def translate (self, path): - # we need to join together three separate - # path components, and do it safely. - # // - # use the operating system's path separator. - path = string.join (string.split (path, '/'), os.sep) - p = self.normalize (self.path_module.join (self.wd, path)) - p = self.normalize (self.path_module.join (self.root, p[1:])) - return p - - def longify (self, (path, stat_info)): - return unix_longify (path, stat_info) - - def __repr__ (self): - return '' % ( - self.root, - self.wd - ) - -if os.name == 'posix': - - class unix_filesystem (os_filesystem): - pass - - class schizophrenic_unix_filesystem (os_filesystem): - PROCESS_UID = os.getuid() - PROCESS_EUID = os.geteuid() - PROCESS_GID = os.getgid() - PROCESS_EGID = os.getegid() - - def __init__ (self, root, wd='/', persona=(None, None)): - os_filesystem.__init__ (self, root, wd) - self.persona = persona - - def become_persona (self): - if self.persona is not (None, None): - uid, gid = self.persona - # the order of these is important! - os.setegid (gid) - os.seteuid (uid) - - def become_nobody (self): - if self.persona is not (None, None): - os.seteuid (self.PROCESS_UID) - os.setegid (self.PROCESS_GID) - - # cwd, cdup, open, listdir - def cwd (self, path): - try: - self.become_persona() - return os_filesystem.cwd (self, path) - finally: - self.become_nobody() - - def cdup (self, path): - try: - self.become_persona() - return os_filesystem.cdup (self) - finally: - self.become_nobody() - - def open (self, filename, mode): - try: - self.become_persona() - return os_filesystem.open (self, filename, mode) - finally: - self.become_nobody() - - def listdir (self, path, long=0): - try: - self.become_persona() - return os_filesystem.listdir (self, path, long) - finally: - self.become_nobody() - -# For the 'real' root, we could obtain a list of drives, and then -# use that. Doesn't win32 provide such a 'real' filesystem? -# [yes, I think something like this "\\.\c\windows"] - -class msdos_filesystem (os_filesystem): - def longify (self, (path, stat_info)): - return msdos_longify (path, stat_info) - -# A merged filesystem will let you plug other filesystems together. -# We really need the equivalent of a 'mount' capability - this seems -# to be the most general idea. So you'd use a 'mount' method to place -# another filesystem somewhere in the hierarchy. - -# Note: this is most likely how I will handle ~user directories -# with the http server. - -class merged_filesystem: - def __init__ (self, *fsys): - pass - -# this matches the output of NT's ftp server (when in -# MSDOS mode) exactly. - -def msdos_longify (file, stat_info): - if stat.S_ISDIR (stat_info[stat.ST_MODE]): - dir = '' - else: - dir = ' ' - date = msdos_date (stat_info[stat.ST_MTIME]) - return '%s %s %8d %s' % ( - date, - dir, - stat_info[stat.ST_SIZE], - file - ) - -def msdos_date (t): - try: - info = time.gmtime (t) - except: - info = time.gmtime (0) - # year, month, day, hour, minute, second, ... - if info[3] > 11: - merid = 'PM' - info[3] = info[3] - 12 - else: - merid = 'AM' - return '%02d-%02d-%02d %02d:%02d%s' % ( - info[1], - info[2], - info[0]%100, - info[3], - info[4], - merid - ) - -months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - -mode_table = { - '0':'---', - '1':'--x', - '2':'-w-', - '3':'-wx', - '4':'r--', - '5':'r-x', - '6':'rw-', - '7':'rwx' - } - -import time - -def unix_longify (file, stat_info): - # for now, only pay attention to the lower bits - mode = ('%o' % stat_info[stat.ST_MODE])[-3:] - mode = string.join (map (lambda x: mode_table[x], mode), '') - if stat.S_ISDIR (stat_info[stat.ST_MODE]): - dirchar = 'd' - else: - dirchar = '-' - date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) - return '%s%s %3d %-8d %-8d %8d %s %s' % ( - dirchar, - mode, - stat_info[stat.ST_NLINK], - stat_info[stat.ST_UID], - stat_info[stat.ST_GID], - stat_info[stat.ST_SIZE], - date, - file - ) - -# Emulate the unix 'ls' command's date field. -# it has two formats - if the date is more than 180 -# days in the past, then it's like this: -# Oct 19 1995 -# otherwise, it looks like this: -# Oct 19 17:33 - -def ls_date (now, t): - try: - info = time.gmtime (t) - except: - info = time.gmtime (0) - # 15,600,000 == 86,400 * 180 - if (now - t) > 15600000: - return '%s %2d %d' % ( - months[info[1]-1], - info[2], - info[0] - ) - else: - return '%s %2d %02d:%02d' % ( - months[info[1]-1], - info[2], - info[3], - info[4] - ) - -# =========================================================================== -# Producers -# =========================================================================== - -class list_producer: - def __init__ (self, list, func=None): - self.list = list - self.func = func - - # this should do a pushd/popd - def more (self): - if not self.list: - return '' - else: - # do a few at a time - bunch = self.list[:50] - if self.func is not None: - bunch = map (self.func, bunch) - self.list = self.list[50:] - return string.joinfields (bunch, '\r\n') + '\r\n' - diff --git a/demo/medusa054/ftp_server.py b/demo/medusa054/ftp_server.py deleted file mode 100644 index 859cd65..0000000 --- a/demo/medusa054/ftp_server.py +++ /dev/null @@ -1,1111 +0,0 @@ -# -*- Mode: Python -*- - -# Author: Sam Rushing -# Copyright 1996-2000 by Sam Rushing -# All Rights Reserved. -# - -# An extensible, configurable, asynchronous FTP server. -# -# All socket I/O is non-blocking, however file I/O is currently -# blocking. Eventually file I/O may be made non-blocking, too, if it -# seems necessary. Currently the only CPU-intensive operation is -# getting and formatting a directory listing. [this could be moved -# into another process/directory server, or another thread?] -# -# Only a subset of RFC 959 is implemented, but much of that RFC is -# vestigial anyway. I've attempted to include the most commonly-used -# commands, using the feature set of wu-ftpd as a guide. - -import asyncore -import asynchat - -import os -import socket -import stat -import string -import sys -import time - -#from medusa.producers import file_producer -from producers import file_producer - -# TODO: implement a directory listing cache. On very-high-load -# servers this could save a lot of disk abuse, and possibly the -# work of computing emulated unix ls output. - -# Potential security problem with the FTP protocol? I don't think -# there's any verification of the origin of a data connection. Not -# really a problem for the server (since it doesn't send the port -# command, except when in PASV mode) But I think a data connection -# could be spoofed by a program with access to a sniffer - it could -# watch for a PORT command to go over a command channel, and then -# connect to that port before the server does. - -# Unix user id's: -# In order to support assuming the id of a particular user, -# it seems there are two options: -# 1) fork, and seteuid in the child -# 2) carefully control the effective uid around filesystem accessing -# methods, using try/finally. [this seems to work] - -VERSION = '1.1' - -from counter import counter -import producers -import status_handler -import logger - -class ftp_channel (asynchat.async_chat): - - # defaults for a reliable __repr__ - addr = ('unknown','0') - - # unset this in a derived class in order - # to enable the commands in 'self.write_commands' - read_only = 1 - write_commands = ['appe','dele','mkd','rmd','rnfr','rnto','stor','stou'] - - restart_position = 0 - - # comply with (possibly troublesome) RFC959 requirements - # This is necessary to correctly run an active data connection - # through a firewall that triggers on the source port (expected - # to be 'L-1', or 20 in the normal case). - bind_local_minus_one = 0 - - def __init__ (self, server, conn, addr): - self.server = server - self.current_mode = 'a' - self.addr = addr - asynchat.async_chat.__init__ (self, conn) - self.set_terminator ('\r\n') - - # client data port. Defaults to 'the same as the control connection'. - self.client_addr = (addr[0], 21) - - self.client_dc = None - self.in_buffer = '' - self.closing = 0 - self.passive_acceptor = None - self.passive_connection = None - self.filesystem = None - self.authorized = 0 - # send the greeting - self.respond ( - '220 %s FTP server (Medusa Async V%s [experimental]) ready.' % ( - self.server.hostname, - VERSION - ) - ) - -# def __del__ (self): -# print 'ftp_channel.__del__()' - - # -------------------------------------------------- - # async-library methods - # -------------------------------------------------- - - def handle_expt (self): - # this is handled below. not sure what I could - # do here to make that code less kludgish. - pass - - def collect_incoming_data (self, data): - self.in_buffer = self.in_buffer + data - if len(self.in_buffer) > 4096: - # silently truncate really long lines - # (possible denial-of-service attack) - self.in_buffer = '' - - def found_terminator (self): - - line = self.in_buffer - - if not len(line): - return - - sp = string.find (line, ' ') - if sp != -1: - line = [line[:sp], line[sp+1:]] - else: - line = [line] - - command = string.lower (line[0]) - # watch especially for 'urgent' abort commands. - if string.find (command, 'abor') != -1: - # strip off telnet sync chars and the like... - while command and command[0] not in string.letters: - command = command[1:] - fun_name = 'cmd_%s' % command - if command != 'pass': - self.log ('<== %s' % repr(self.in_buffer)[1:-1]) - else: - self.log ('<== %s' % line[0]+' ') - self.in_buffer = '' - if not hasattr (self, fun_name): - self.command_not_understood (line[0]) - return - fun = getattr (self, fun_name) - if (not self.authorized) and (command not in ('user', 'pass', 'help', 'quit')): - self.respond ('530 Please log in with USER and PASS') - elif (not self.check_command_authorization (command)): - self.command_not_authorized (command) - else: - try: - result = apply (fun, (line,)) - except: - self.server.total_exceptions.increment() - (file, fun, line), t,v, tbinfo = asyncore.compact_traceback() - if self.client_dc: - try: - self.client_dc.close() - except: - pass - self.respond ( - '451 Server Error: %s, %s: file: %s line: %s' % ( - t,v,file,line, - ) - ) - - closed = 0 - def close (self): - if not self.closed: - self.closed = 1 - if self.passive_acceptor: - self.passive_acceptor.close() - if self.client_dc: - self.client_dc.close() - self.server.closed_sessions.increment() - asynchat.async_chat.close (self) - - # -------------------------------------------------- - # filesystem interface functions. - # override these to provide access control or perform - # other functions. - # -------------------------------------------------- - - def cwd (self, line): - return self.filesystem.cwd (line[1]) - - def cdup (self, line): - return self.filesystem.cdup() - - def open (self, path, mode): - return self.filesystem.open (path, mode) - - # returns a producer - def listdir (self, path, long=0): - return self.filesystem.listdir (path, long) - - def get_dir_list (self, line, long=0): - # we need to scan the command line for arguments to '/bin/ls'... - args = line[1:] - path_args = [] - for arg in args: - if arg[0] != '-': - path_args.append (arg) - else: - # ignore arguments - pass - if len(path_args) < 1: - dir = '.' - else: - dir = path_args[0] - return self.listdir (dir, long) - - # -------------------------------------------------- - # authorization methods - # -------------------------------------------------- - - def check_command_authorization (self, command): - if command in self.write_commands and self.read_only: - return 0 - else: - return 1 - - # -------------------------------------------------- - # utility methods - # -------------------------------------------------- - - def log (self, message): - self.server.logger.log ( - self.addr[0], - '%d %s' % ( - self.addr[1], message - ) - ) - - def respond (self, resp): - self.log ('==> %s' % resp) - self.push (resp + '\r\n') - - def command_not_understood (self, command): - self.respond ("500 '%s': command not understood." % command) - - def command_not_authorized (self, command): - self.respond ( - "530 You are not authorized to perform the '%s' command" % ( - command - ) - ) - - def make_xmit_channel (self): - # In PASV mode, the connection may or may _not_ have been made - # yet. [although in most cases it is... FTP Explorer being - # the only exception I've yet seen]. This gets somewhat confusing - # because things may happen in any order... - pa = self.passive_acceptor - if pa: - if pa.ready: - # a connection has already been made. - conn, addr = self.passive_acceptor.ready - cdc = xmit_channel (self, addr) - cdc.set_socket (conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - # we're still waiting for a connect to the PASV port. - cdc = xmit_channel (self) - else: - # not in PASV mode. - ip, port = self.client_addr - cdc = xmit_channel (self, self.client_addr) - cdc.create_socket (socket.AF_INET, socket.SOCK_STREAM) - if self.bind_local_minus_one: - cdc.bind (('', self.server.port - 1)) - try: - cdc.connect ((ip, port)) - except socket.error, why: - self.respond ("425 Can't build data connection") - self.client_dc = cdc - - # pretty much the same as xmit, but only right on the verge of - # being worth a merge. - def make_recv_channel (self, fd): - pa = self.passive_acceptor - if pa: - if pa.ready: - # a connection has already been made. - conn, addr = pa.ready - cdc = recv_channel (self, addr, fd) - cdc.set_socket (conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - # we're still waiting for a connect to the PASV port. - cdc = recv_channel (self, None, fd) - else: - # not in PASV mode. - ip, port = self.client_addr - cdc = recv_channel (self, self.client_addr, fd) - cdc.create_socket (socket.AF_INET, socket.SOCK_STREAM) - try: - cdc.connect ((ip, port)) - except socket.error, why: - self.respond ("425 Can't build data connection") - self.client_dc = cdc - - type_map = { - 'a':'ASCII', - 'i':'Binary', - 'e':'EBCDIC', - 'l':'Binary' - } - - type_mode_map = { - 'a':'t', - 'i':'b', - 'e':'b', - 'l':'b' - } - - # -------------------------------------------------- - # command methods - # -------------------------------------------------- - - def cmd_type (self, line): - 'specify data transfer type' - # ascii, ebcdic, image, local - t = string.lower (line[1]) - # no support for EBCDIC - # if t not in ['a','e','i','l']: - if t not in ['a','i','l']: - self.command_not_understood (string.join (line)) - elif t == 'l' and (len(line) > 2 and line[2] != '8'): - self.respond ('504 Byte size must be 8') - else: - self.current_mode = t - self.respond ('200 Type set to %s.' % self.type_map[t]) - - - def cmd_quit (self, line): - 'terminate session' - self.respond ('221 Goodbye.') - self.close_when_done() - - def cmd_port (self, line): - 'specify data connection port' - info = string.split (line[1], ',') - ip = string.join (info[:4], '.') - port = string.atoi(info[4])*256 + string.atoi(info[5]) - # how many data connections at a time? - # I'm assuming one for now... - # TODO: we should (optionally) verify that the - # ip number belongs to the client. [wu-ftpd does this?] - self.client_addr = (ip, port) - self.respond ('200 PORT command successful.') - - def new_passive_acceptor (self): - # ensure that only one of these exists at a time. - if self.passive_acceptor is not None: - self.passive_acceptor.close() - self.passive_acceptor = None - self.passive_acceptor = passive_acceptor (self) - return self.passive_acceptor - - def cmd_pasv (self, line): - 'prepare for server-to-server transfer' - pc = self.new_passive_acceptor() - port = pc.addr[1] - ip_addr = pc.control_channel.getsockname()[0] - self.respond ( - '227 Entering Passive Mode (%s,%d,%d)' % ( - string.replace(ip_addr, '.', ','), - port/256, - port%256 - ) - ) - self.client_dc = None - - def cmd_nlst (self, line): - 'give name list of files in directory' - # ncftp adds the -FC argument for the user-visible 'nlist' - # command. We could try to emulate ls flags, but not just yet. - if '-FC' in line: - line.remove ('-FC') - try: - dir_list_producer = self.get_dir_list (line, 0) - except os.error, why: - self.respond ('550 Could not list directory: %s' % why) - return - self.respond ( - '150 Opening %s mode data connection for file list' % ( - self.type_map[self.current_mode] - ) - ) - self.make_xmit_channel() - self.client_dc.push_with_producer (dir_list_producer) - self.client_dc.close_when_done() - - def cmd_list (self, line): - 'give a list of files in a directory' - try: - dir_list_producer = self.get_dir_list (line, 1) - except os.error, why: - self.respond ('550 Could not list directory: %s' % why) - return - self.respond ( - '150 Opening %s mode data connection for file list' % ( - self.type_map[self.current_mode] - ) - ) - self.make_xmit_channel() - self.client_dc.push_with_producer (dir_list_producer) - self.client_dc.close_when_done() - - def cmd_cwd (self, line): - 'change working directory' - if self.cwd (line): - self.respond ('250 CWD command successful.') - else: - self.respond ('550 No such directory.') - - def cmd_cdup (self, line): - 'change to parent of current working directory' - if self.cdup(line): - self.respond ('250 CDUP command successful.') - else: - self.respond ('550 No such directory.') - - def cmd_pwd (self, line): - 'print the current working directory' - self.respond ( - '257 "%s" is the current directory.' % ( - self.filesystem.current_directory() - ) - ) - - # modification time - # example output: - # 213 19960301204320 - def cmd_mdtm (self, line): - 'show last modification time of file' - filename = line[1] - if not self.filesystem.isfile (filename): - self.respond ('550 "%s" is not a file' % filename) - else: - mtime = time.gmtime(self.filesystem.stat(filename)[stat.ST_MTIME]) - self.respond ( - '213 %4d%02d%02d%02d%02d%02d' % ( - mtime[0], - mtime[1], - mtime[2], - mtime[3], - mtime[4], - mtime[5] - ) - ) - - def cmd_noop (self, line): - 'do nothing' - self.respond ('200 NOOP command successful.') - - def cmd_size (self, line): - 'return size of file' - filename = line[1] - if not self.filesystem.isfile (filename): - self.respond ('550 "%s" is not a file' % filename) - else: - self.respond ( - '213 %d' % (self.filesystem.stat(filename)[stat.ST_SIZE]) - ) - - def cmd_retr (self, line): - 'retrieve a file' - if len(line) < 2: - self.command_not_understood (string.join (line)) - else: - file = line[1] - if not self.filesystem.isfile (file): - self.log_info ('checking %s' % file) - self.respond ('550 No such file') - else: - try: - # FIXME: for some reason, 'rt' isn't working on win95 - mode = 'r'+self.type_mode_map[self.current_mode] - fd = self.open (file, mode) - except IOError, why: - self.respond ('553 could not open file for reading: %s' % (repr(why))) - return - self.respond ( - "150 Opening %s mode data connection for file '%s'" % ( - self.type_map[self.current_mode], - file - ) - ) - self.make_xmit_channel() - - if self.restart_position: - # try to position the file as requested, but - # give up silently on failure (the 'file object' - # may not support seek()) - try: - fd.seek (self.restart_position) - except: - pass - self.restart_position = 0 - - self.client_dc.push_with_producer ( - file_producer (fd) - ) - self.client_dc.close_when_done() - - def cmd_stor (self, line, mode='wb'): - 'store a file' - if len (line) < 2: - self.command_not_understood (string.join (line)) - else: - if self.restart_position: - restart_position = 0 - self.respond ('553 restart on STOR not yet supported') - return - file = line[1] - # todo: handle that type flag - try: - fd = self.open (file, mode) - except IOError, why: - self.respond ('553 could not open file for writing: %s' % (repr(why))) - return - self.respond ( - '150 Opening %s connection for %s' % ( - self.type_map[self.current_mode], - file - ) - ) - self.make_recv_channel (fd) - - def cmd_abor (self, line): - 'abort operation' - if self.client_dc: - self.client_dc.close() - self.respond ('226 ABOR command successful.') - - def cmd_appe (self, line): - 'append to a file' - return self.cmd_stor (line, 'ab') - - def cmd_dele (self, line): - if len (line) != 2: - self.command_not_understood (string.join (line)) - else: - file = line[1] - if self.filesystem.isfile (file): - try: - self.filesystem.unlink (file) - self.respond ('250 DELE command successful.') - except: - self.respond ('550 error deleting file.') - else: - self.respond ('550 %s: No such file.' % file) - - def cmd_mkd (self, line): - if len (line) != 2: - self.command_not_understood (string.join (line)) - else: - path = line[1] - try: - self.filesystem.mkdir (path) - self.respond ('257 MKD command successful.') - except: - self.respond ('550 error creating directory.') - - def cmd_rmd (self, line): - if len (line) != 2: - self.command_not_understood (string.join (line)) - else: - path = line[1] - try: - self.filesystem.rmdir (path) - self.respond ('250 RMD command successful.') - except: - self.respond ('550 error removing directory.') - - def cmd_user (self, line): - 'specify user name' - if len(line) > 1: - self.user = line[1] - self.respond ('331 Password required.') - else: - self.command_not_understood (string.join (line)) - - def cmd_pass (self, line): - 'specify password' - if len(line) < 2: - pw = '' - else: - pw = line[1] - result, message, fs = self.server.authorizer.authorize (self, self.user, pw) - if result: - self.respond ('230 %s' % message) - self.filesystem = fs - self.authorized = 1 - self.log_info('Successful login: Filesystem=%s' % repr(fs)) - else: - self.respond ('530 %s' % message) - - def cmd_rest (self, line): - 'restart incomplete transfer' - try: - pos = string.atoi (line[1]) - except ValueError: - self.command_not_understood (string.join (line)) - self.restart_position = pos - self.respond ( - '350 Restarting at %d. Send STORE or RETRIEVE to initiate transfer.' % pos - ) - - def cmd_stru (self, line): - 'obsolete - set file transfer structure' - if line[1] in 'fF': - # f == 'file' - self.respond ('200 STRU F Ok') - else: - self.respond ('504 Unimplemented STRU type') - - def cmd_mode (self, line): - 'obsolete - set file transfer mode' - if line[1] in 'sS': - # f == 'file' - self.respond ('200 MODE S Ok') - else: - self.respond ('502 Unimplemented MODE type') - -# The stat command has two personalities. Normally it returns status -# information about the current connection. But if given an argument, -# it is equivalent to the LIST command, with the data sent over the -# control connection. Strange. But wuftpd, ftpd, and nt's ftp server -# all support it. -# -## def cmd_stat (self, line): -## 'return status of server' -## pass - - def cmd_syst (self, line): - 'show operating system type of server system' - # Replying to this command is of questionable utility, because - # this server does not behave in a predictable way w.r.t. the - # output of the LIST command. We emulate Unix ls output, but - # on win32 the pathname can contain drive information at the front - # Currently, the combination of ensuring that os.sep == '/' - # and removing the leading slash when necessary seems to work. - # [cd'ing to another drive also works] - # - # This is how wuftpd responds, and is probably - # the most expected. The main purpose of this reply is so that - # the client knows to expect Unix ls-style LIST output. - self.respond ('215 UNIX Type: L8') - # one disadvantage to this is that some client programs - # assume they can pass args to /bin/ls. - # a few typical responses: - # 215 UNIX Type: L8 (wuftpd) - # 215 Windows_NT version 3.51 - # 215 VMS MultiNet V3.3 - # 500 'SYST': command not understood. (SVR4) - - def cmd_help (self, line): - 'give help information' - # find all the methods that match 'cmd_xxxx', - # use their docstrings for the help response. - attrs = dir(self.__class__) - help_lines = [] - for attr in attrs: - if attr[:4] == 'cmd_': - x = getattr (self, attr) - if type(x) == type(self.cmd_help): - if x.__doc__: - help_lines.append ('\t%s\t%s' % (attr[4:], x.__doc__)) - if help_lines: - self.push ('214-The following commands are recognized\r\n') - self.push_with_producer (producers.lines_producer (help_lines)) - self.push ('214\r\n') - else: - self.push ('214-\r\n\tHelp Unavailable\r\n214\r\n') - -class ftp_server (asyncore.dispatcher): - # override this to spawn a different FTP channel class. - ftp_channel_class = ftp_channel - - SERVER_IDENT = 'FTP Server (V%s)' % VERSION - - def __init__ ( - self, - authorizer, - hostname =None, - ip ='', - port =21, - resolver =None, - logger_object=logger.file_logger (sys.stdout) - ): - self.ip = ip - self.port = port - self.authorizer = authorizer - - if hostname is None: - self.hostname = socket.gethostname() - else: - self.hostname = hostname - - # statistics - self.total_sessions = counter() - self.closed_sessions = counter() - self.total_files_out = counter() - self.total_files_in = counter() - self.total_bytes_out = counter() - self.total_bytes_in = counter() - self.total_exceptions = counter() - # - asyncore.dispatcher.__init__ (self) - self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - - self.set_reuse_addr() - self.bind ((self.ip, self.port)) - self.listen (5) - - if not logger_object: - logger_object = sys.stdout - - if resolver: - self.logger = logger.resolving_logger (resolver, logger_object) - else: - self.logger = logger.unresolving_logger (logger_object) - - self.log_info('FTP server started at %s\n\tAuthorizer:%s\n\tHostname: %s\n\tPort: %d' % ( - time.ctime(time.time()), - repr (self.authorizer), - self.hostname, - self.port) - ) - - def writable (self): - return 0 - - def handle_read (self): - pass - - def handle_connect (self): - pass - - def handle_accept (self): - conn, addr = self.accept() - self.total_sessions.increment() - self.log_info('Incoming connection from %s:%d' % (addr[0], addr[1])) - self.ftp_channel_class (self, conn, addr) - - # return a producer describing the state of the server - def status (self): - - def nice_bytes (n): - return string.join (status_handler.english_bytes (n)) - - return producers.lines_producer ( - ['

    %s

    ' % self.SERVER_IDENT, - '
    Listening on Host: %s' % self.hostname, - 'Port: %d' % self.port, - '
    Sessions', - 'Total: %s' % self.total_sessions, - 'Current: %d' % (self.total_sessions.as_long() - self.closed_sessions.as_long()), - '
    Files', - 'Sent: %s' % self.total_files_out, - 'Received: %s' % self.total_files_in, - '
    Bytes', - 'Sent: %s' % nice_bytes (self.total_bytes_out.as_long()), - 'Received: %s' % nice_bytes (self.total_bytes_in.as_long()), - '
    Exceptions: %s' % self.total_exceptions, - ] - ) - -# ====================================================================== -# Data Channel Classes -# ====================================================================== - -# This socket accepts a data connection, used when the server has been -# placed in passive mode. Although the RFC implies that we ought to -# be able to use the same acceptor over and over again, this presents -# a problem: how do we shut it off, so that we are accepting -# connections only when we expect them? [we can't] -# -# wuftpd, and probably all the other servers, solve this by allowing -# only one connection to hit this acceptor. They then close it. Any -# subsequent data-connection command will then try for the default -# port on the client side [which is of course never there]. So the -# 'always-send-PORT/PASV' behavior seems required. -# -# Another note: wuftpd will also be listening on the channel as soon -# as the PASV command is sent. It does not wait for a data command -# first. - -# --- we need to queue up a particular behavior: -# 1) xmit : queue up producer[s] -# 2) recv : the file object -# -# It would be nice if we could make both channels the same. Hmmm.. -# - -class passive_acceptor (asyncore.dispatcher): - ready = None - - def __init__ (self, control_channel): - # connect_fun (conn, addr) - asyncore.dispatcher.__init__ (self) - self.control_channel = control_channel - self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - # bind to an address on the interface that the - # control connection is coming from. - self.bind (( - self.control_channel.getsockname()[0], - 0 - )) - self.addr = self.getsockname() - self.listen (1) - -# def __del__ (self): -# print 'passive_acceptor.__del__()' - - def log (self, *ignore): - pass - - def handle_accept (self): - conn, addr = self.accept() - dc = self.control_channel.client_dc - if dc is not None: - dc.set_socket (conn) - dc.addr = addr - dc.connected = 1 - self.control_channel.passive_acceptor = None - else: - self.ready = conn, addr - self.close() - - -class xmit_channel (asynchat.async_chat): - - # for an ethernet, you want this to be fairly large, in fact, it - # _must_ be large for performance comparable to an ftpd. [64k] we - # ought to investigate automatically-sized buffers... - - ac_out_buffer_size = 16384 - bytes_out = 0 - - def __init__ (self, channel, client_addr=None): - self.channel = channel - self.client_addr = client_addr - asynchat.async_chat.__init__ (self) - -# def __del__ (self): -# print 'xmit_channel.__del__()' - - def log (self, *args): - pass - - def readable (self): - return not self.connected - - def writable (self): - return 1 - - def send (self, data): - result = asynchat.async_chat.send (self, data) - self.bytes_out = self.bytes_out + result - return result - - def handle_error (self): - # usually this is to catch an unexpected disconnect. - self.log_info ('unexpected disconnect on data xmit channel', 'error') - try: - self.close() - except: - pass - - # TODO: there's a better way to do this. we need to be able to - # put 'events' in the producer fifo. to do this cleanly we need - # to reposition the 'producer' fifo as an 'event' fifo. - - def close (self): - c = self.channel - s = c.server - c.client_dc = None - s.total_files_out.increment() - s.total_bytes_out.increment (self.bytes_out) - if not len(self.producer_fifo): - c.respond ('226 Transfer complete') - elif not c.closed: - c.respond ('426 Connection closed; transfer aborted') - del c - del s - del self.channel - asynchat.async_chat.close (self) - -class recv_channel (asyncore.dispatcher): - def __init__ (self, channel, client_addr, fd): - self.channel = channel - self.client_addr = client_addr - self.fd = fd - asyncore.dispatcher.__init__ (self) - self.bytes_in = counter() - - def log (self, *ignore): - pass - - def handle_connect (self): - pass - - def writable (self): - return 0 - - def recv (*args): - result = apply (asyncore.dispatcher.recv, args) - self = args[0] - self.bytes_in.increment(len(result)) - return result - - buffer_size = 8192 - - def handle_read (self): - block = self.recv (self.buffer_size) - if block: - try: - self.fd.write (block) - except IOError: - self.log_info ('got exception writing block...', 'error') - - def handle_close (self): - s = self.channel.server - s.total_files_in.increment() - s.total_bytes_in.increment(self.bytes_in.as_long()) - self.fd.close() - self.channel.respond ('226 Transfer complete.') - self.close() - -import filesys - -# not much of a doorman! 8^) -class dummy_authorizer: - def __init__ (self, root='/'): - self.root = root - def authorize (self, channel, username, password): - channel.persona = -1, -1 - channel.read_only = 1 - return 1, 'Ok.', filesys.os_filesystem (self.root) - -class anon_authorizer: - def __init__ (self, root='/'): - self.root = root - - def authorize (self, channel, username, password): - if username in ('ftp', 'anonymous'): - channel.persona = -1, -1 - channel.read_only = 1 - return 1, 'Ok.', filesys.os_filesystem (self.root) - else: - return 0, 'Password invalid.', None - -# =========================================================================== -# Unix-specific improvements -# =========================================================================== - -if os.name == 'posix': - - class unix_authorizer: - # return a trio of (success, reply_string, filesystem) - def authorize (self, channel, username, password): - import crypt - import pwd - try: - info = pwd.getpwnam (username) - except KeyError: - return 0, 'No such user.', None - mangled = info[1] - if crypt.crypt (password, mangled[:2]) == mangled: - channel.read_only = 0 - fs = filesys.schizophrenic_unix_filesystem ( - '/', - info[5], - persona = (info[2], info[3]) - ) - return 1, 'Login successful.', fs - else: - return 0, 'Password invalid.', None - - def __repr__ (self): - return '' - - # simple anonymous ftp support - class unix_authorizer_with_anonymous (unix_authorizer): - def __init__ (self, root=None, real_users=0): - self.root = root - self.real_users = real_users - - def authorize (self, channel, username, password): - if string.lower(username) in ['anonymous', 'ftp']: - import pwd - try: - # ok, here we run into lots of confusion. - # on some os', anon runs under user 'nobody', - # on others as 'ftp'. ownership is also critical. - # need to investigate. - # linux: new linuxen seem to have nobody's UID=-1, - # which is an illegal value. Use ftp. - ftp_user_info = pwd.getpwnam ('ftp') - if string.lower(os.uname()[0]) == 'linux': - nobody_user_info = pwd.getpwnam ('ftp') - else: - nobody_user_info = pwd.getpwnam ('nobody') - channel.read_only = 1 - if self.root is None: - self.root = ftp_user_info[5] - fs = filesys.unix_filesystem (self.root, '/') - return 1, 'Anonymous Login Successful', fs - except KeyError: - return 0, 'Anonymous account not set up', None - elif self.real_users: - return unix_authorizer.authorize ( - self, - channel, - username, - password - ) - else: - return 0, 'User logins not allowed', None - -# usage: ftp_server /PATH/TO/FTP/ROOT PORT -# for example: -# $ ftp_server /home/users/ftp 8021 - -if os.name == 'posix': - def test (port='8021'): - fs = ftp_server ( - unix_authorizer(), - port=string.atoi (port) - ) - try: - asyncore.loop() - except KeyboardInterrupt: - fs.log_info('FTP server shutting down. (received SIGINT)', 'warning') - # close everything down on SIGINT. - # of course this should be a cleaner shutdown. - asyncore.close_all() - - if __name__ == '__main__': - test (sys.argv[1]) -# not unix -else: - def test (): - fs = ftp_server (dummy_authorizer()) - if __name__ == '__main__': - test () - -# this is the command list from the wuftpd man page -# '*' means we've implemented it. -# '!' requires write access -# -command_documentation = { - 'abor': 'abort previous command', #* - 'acct': 'specify account (ignored)', - 'allo': 'allocate storage (vacuously)', - 'appe': 'append to a file', #*! - 'cdup': 'change to parent of current working directory', #* - 'cwd': 'change working directory', #* - 'dele': 'delete a file', #! - 'help': 'give help information', #* - 'list': 'give list files in a directory', #* - 'mkd': 'make a directory', #! - 'mdtm': 'show last modification time of file', #* - 'mode': 'specify data transfer mode', - 'nlst': 'give name list of files in directory', #* - 'noop': 'do nothing', #* - 'pass': 'specify password', #* - 'pasv': 'prepare for server-to-server transfer', #* - 'port': 'specify data connection port', #* - 'pwd': 'print the current working directory', #* - 'quit': 'terminate session', #* - 'rest': 'restart incomplete transfer', #* - 'retr': 'retrieve a file', #* - 'rmd': 'remove a directory', #! - 'rnfr': 'specify rename-from file name', #! - 'rnto': 'specify rename-to file name', #! - 'site': 'non-standard commands (see next section)', - 'size': 'return size of file', #* - 'stat': 'return status of server', #* - 'stor': 'store a file', #*! - 'stou': 'store a file with a unique name', #! - 'stru': 'specify data transfer structure', - 'syst': 'show operating system type of server system', #* - 'type': 'specify data transfer type', #* - 'user': 'specify user name', #* - 'xcup': 'change to parent of current working directory (deprecated)', - 'xcwd': 'change working directory (deprecated)', - 'xmkd': 'make a directory (deprecated)', #! - 'xpwd': 'print the current working directory (deprecated)', - 'xrmd': 'remove a directory (deprecated)', #! -} - - -# debugging aid (linux) -def get_vm_size (): - return string.atoi (string.split(open ('/proc/self/stat').readline())[22]) - -def print_vm(): - print 'vm: %8dk' % (get_vm_size()/1024) diff --git a/demo/medusa054/ftps_server.py b/demo/medusa054/ftps_server.py deleted file mode 100644 index bf2f5a9..0000000 --- a/demo/medusa054/ftps_server.py +++ /dev/null @@ -1,438 +0,0 @@ -"""An FTP/TLS server built on Medusa's ftp_server. - -Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" - -# Python -import socket, string, sys, time - -# Medusa -from counter import counter -import asynchat, asyncore, ftp_server, logger - -# M2Crypto -from M2Crypto import SSL, version - -VERSION_STRING=version - -class ftp_tls_channel(ftp_server.ftp_channel): - - """FTP/TLS server channel for Medusa.""" - - def __init__(self, server, ssl_ctx, conn, addr): - """Initialise the channel.""" - self.ssl_ctx = ssl_ctx - self.server = server - self.current_mode = 'a' - self.addr = addr - asynchat.async_chat.__init__(self, conn) - self.set_terminator('\r\n') - self.client_addr = (addr[0], 21) - self.client_dc = None - self.in_buffer = '' - self.closing = 0 - self.passive_acceptor = None - self.passive_connection = None - self.filesystem = None - self.authorized = 0 - self._ssl_accepting = 0 - self._ssl_accepted = 0 - self._pbsz = None - self._prot = None - resp = '220 %s M2Crypto (Medusa) FTP/TLS server v%s ready.' - self.respond(resp % (self.server.hostname, VERSION_STRING)) - - def writable(self): - return self._ssl_accepting or self._ssl_accepted - - def handle_read(self): - """Handle a read event.""" - if self._ssl_accepting: - self._ssl_accepted = self.socket.accept_ssl() - if self._ssl_accepted: - self._ssl_accepting = 0 - else: - try: - ftp_server.ftp_channel.handle_read(self) - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - self.close() - else: - raise - - def handle_write(self): - """Handle a write event.""" - if self._ssl_accepting: - self._ssl_accepted = self.socket.accept_ssl() - if self._ssl_accepted: - self._ssl_accepting = 0 - else: - try: - ftp_server.ftp_channel.handle_write(self) - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - self.close() - else: - raise - - def send(self, data): - """Send data over SSL.""" - try: - result = self.socket.send(data) - if result <= 0: - return 0 - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), what)) - return 0 - - def recv(self, buffer_size): - """Receive data over SSL.""" - try: - result = self.socket.recv(buffer_size) - if not result: - return '' - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), what)) - return '' - - def found_terminator(self): - """Dispatch the FTP command.""" - line = self.in_buffer - if not len(line): - return - - sp = string.find(line, ' ') - if sp != -1: - line = [line[:sp], line[sp+1:]] - else: - line = [line] - - command = string.lower(line[0]) - if string.find(command, 'stor') != -1: - while command and command[0] not in string.letters: - command = command[1:] - - func_name = 'cmd_%s' % command - if command != 'pass': - self.log('<== %s' % repr(self.in_buffer)[1:-1]) - else: - self.log('<== %s' % line[0]+' ') - - self.in_buffer = '' - if not hasattr(self, func_name): - self.command_not_understood(line[0]) - return - - func = getattr(self, func_name) - if not self.check_command_authorization(command): - self.command_not_authorized(command) - else: - try: - result = apply(func, (line,)) - except: - self.server.total_exceptions.increment() - (file, func, line), t, v, tbinfo = asyncore.compact_traceback() - if self.client_dc: - try: - self.client_dc_close() - except: - pass - resp = '451 Server error: %s, %s: file %s line: %s' - self.respond(resp % (t, v, file, line)) - - def make_xmit_channel(self): - """Create a connection for sending data.""" - pa = self.passive_acceptor - if pa: - if pa.ready: - conn, addr = pa.ready - if self._prot: - cdc = tls_xmit_channel(self, conn, self.ssl_ctx, addr) - else: - cdc = ftp_server.xmit_channel(self, addr) - cdc.set_socket(conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - if self._prot: - cdc = tls_xmit_channel(self, None, self.ssl_ctx, None) - else: - cdc = ftp_server.xmit_channel(self) - else: - if self._prot: - cdc = tls_xmit_channel(self, None, self.ssl_ctx, self.client_addr) - else: - cdc = ftp_server.xmit_channel(self, self.client_addr) - cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) - if self.bind_local_minus_one: - cdc.bind(('', self.server.port - 1)) - try: - cdc.connect(self.client_addr) - except socket.error, what: - self.respond('425 Cannot build data connection') - self.client_dc = cdc - - def make_recv_channel(self, fd): - """Create a connection for receiving data.""" - pa = self.passive_acceptor - if pa: - if pa.ready: - conn, addr = pa.ready - if self._prot: - cdc = tls_recv_channel(self, conn, self.ssl_ctx, addr, fd) - else: - cdc = ftp_server.recv_channel(self, addr, fd) - cdc.set_socket(conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - if self._prot: - cdc = tls_recv_channel(self, None, self.ssl_ctx, None, fd) - else: - cdc = ftp_server.recv_channel(self, None, fd) - else: - if self._prot: - cdc = tls_recv_channel(self, None, self.ssl_ctx, self._prot, self.client_addr, fd) - else: - cdc = ftp_server.recv_channel(self, self.client_addr, fd) - cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) - try: - cdc.connect(self.client_addr) - except socket.error, what: - self.respond('425 Cannot build data connection') - self.client_dc = cdc - - def cmd_auth(self, line): - """Prepare for TLS operation.""" - # XXX Handle variations. - if line[1] != 'TLS': - self.command_not_understood (string.join(line)) - else: - self.respond('234 AUTH TLS successful') - self._ssl_accepting = 1 - self.socket = SSL.Connection(self.ssl_ctx, self.socket) - self.socket.setup_addr(self.addr) - self.socket.setup_ssl() - self.socket.set_accept_state() - self._ssl_accepted = self.socket.accept_ssl() - if self._ssl_accepted: - self._ssl_accepting = 0 - - def cmd_pbsz(self, line): - """Negotiate size of buffer for secure data transfer. For - FTP/TLS the only valid value for the parameter is '0'; any - other value is accepted but ignored.""" - if not (self._ssl_accepting or self._ssl_accepted): - return self.respond('503 AUTH TLS must be issued prior to PBSZ') - self._pbsz = 1 - self.respond('200 PBSZ=0 successful.') - - def cmd_prot(self, line): - """Negotiate the security level of the data connection.""" - if self._pbsz is None: - return self.respond('503 PBSZ must be issued prior to PROT') - if line[1] == 'C': - self.respond('200 Protection set to Clear') - self._pbsz = None - self._prot = None - elif line[1] == 'P': - self.respond('200 Protection set to Private') - self._prot = 1 - elif line[1] in ('S', 'E'): - self.respond('536 PROT %s unsupported' % line[1]) - else: - self.respond('504 PROT %s unsupported' % line[1]) - - -class ftp_tls_server(ftp_server.ftp_server): - - """FTP/TLS server for Medusa.""" - - SERVER_IDENT = 'M2Crypto FTP/TLS Server (v%s)' % VERSION_STRING - - ftp_channel_class = ftp_tls_channel - - def __init__(self, authz, ssl_ctx, host=None, ip='', port=21, resolver=None, log_obj=None): - """Initialise the server.""" - self.ssl_ctx = ssl_ctx - self.ip = ip - self.port = port - self.authorizer = authz - - if host is None: - self.hostname = socket.gethostname() - else: - self.hostname = host - - self.total_sessions = counter() - self.closed_sessions = counter() - self.total_files_out = counter() - self.total_files_in = counter() - self.total_bytes_out = counter() - self.total_bytes_in = counter() - self.total_exceptions = counter() - - asyncore.dispatcher.__init__(self) - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.set_reuse_addr() - self.bind((self.ip, self.port)) - self.listen(5) - - if log_obj is None: - log_obj = sys.stdout - - if resolver: - self.logger = logger.resolving_logger(resolver, log_obj) - else: - self.logger = logger.unresolving_logger(logger.file_logger(sys.stdout)) - - l = 'M2Crypto (Medusa) FTP/TLS server started at %s\n\tAuthz: %s\n\tHostname: %s\n\tPort: %d' - self.log_info(l % (time.ctime(time.time()), repr(self.authorizer), self.hostname, self.port)) - - def handle_accept(self): - """Accept a socket and dispatch a channel to handle it.""" - conn, addr = self.accept() - self.total_sessions.increment() - self.log_info('Connection from %s:%d' % addr) - self.ftp_channel_class(self, self.ssl_ctx, conn, addr) - - -class nbio_ftp_tls_actor: - - """TLS protocol negotiation mixin for FTP/TLS.""" - - def tls_init(self, sock, ssl_ctx, client_addr): - """Perform TLS protocol negotiation.""" - self.ssl_ctx = ssl_ctx - self.client_addr = client_addr - self._ssl_handshaking = 1 - self._ssl_handshake_ok = 0 - if sock: - self.socket = SSL.Connection(self.ssl_ctx, sock) - self.socket.setup_addr(self.client_addr) - self.socket.setup_ssl() - self._ssl_handshake_ok = self.socket.accept_ssl() - if self._ssl_handshake_ok: - self._ssl_handshaking = 0 - self.add_channel() - # else the client hasn't connected yet; when that happens, - # handle_connect() will be triggered. - - def tls_neg_ok(self): - """Return status of TLS protocol negotiation.""" - if self._ssl_handshaking: - self._ssl_handshake_ok = self.socket.accept_ssl() - if self._ssl_handshake_ok: - self._ssl_handshaking = 0 - return self._ssl_handshake_ok - - def handle_connect(self): - """Handle a data connection that occurs after this instance came - into being. When this handler is triggered, self.socket has been - created and refers to the underlying connected socket.""" - self.socket = SSL.Connection(self.ssl_ctx, self.socket) - self.socket.setup_addr(self.client_addr) - self.socket.setup_ssl() - self._ssl_handshake_ok = self.socket.accept_ssl() - if self._ssl_handshake_ok: - self._ssl_handshaking = 0 - self.add_channel() - - def send(self, data): - """Send data over SSL.""" - try: - result = self.socket.send(data) - if result <= 0: - return 0 - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), what)) - return 0 - - def recv(self, buffer_size): - """Receive data over SSL.""" - try: - result = self.socket.recv(buffer_size) - if not result: - return '' - else: - return result - except SSL.SSLError, what: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), what)) - return '' - - -class tls_xmit_channel(nbio_ftp_tls_actor, ftp_server.xmit_channel): - - """TLS driver for a send-only data connection.""" - - def __init__(self, channel, conn, ssl_ctx, client_addr=None): - """Initialise the driver.""" - ftp_server.xmit_channel.__init__(self, channel, client_addr) - self.tls_init(conn, ssl_ctx, client_addr) - - def readable(self): - """This channel is readable iff TLS negotiation is in progress. - (Which implies a connected channel, of course.)""" - if not self.connected: - return 0 - else: - return self._ssl_handshaking - - def writable(self): - """This channel is writable iff TLS negotiation is in progress - or the application has data to send.""" - if self._ssl_handshaking: - return 1 - else: - return ftp_server.xmit_channel.writable(self) - - def handle_read(self): - """Handle a read event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.xmit_channel.handle_read(self) - - def handle_write(self): - """Handle a write event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.xmit_channel.handle_write(self) - - -class tls_recv_channel(nbio_ftp_tls_actor, ftp_server.recv_channel): - - """TLS driver for a receive-only data connection.""" - - def __init__(self, channel, conn, ssl_ctx, client_addr, fd): - """Initialise the driver.""" - ftp_server.recv_channel.__init__(self, channel, client_addr, fd) - self.tls_init(conn, ssl_ctx, client_addr) - - def writable(self): - """This channel is writable iff TLS negotiation is in progress.""" - return self._ssl_handshaking - - def handle_read(self): - """Handle a read event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.recv_channel.handle_read(self) - - def handle_write(self): - """Handle a write event: either continue with TLS negotiation - or let the application handle this event.""" - if self.tls_neg_ok(): - ftp_server.recv_channel.handle_write(self) - - diff --git a/demo/medusa054/http_date.py b/demo/medusa054/http_date.py deleted file mode 100644 index d2f90b8..0000000 --- a/demo/medusa054/http_date.py +++ /dev/null @@ -1,126 +0,0 @@ -# -*- Mode: Python -*- - -import re -import string -import time - -def concat (*args): - return ''.join (args) - -def join (seq, field=' '): - return field.join (seq) - -def group (s): - return '(' + s + ')' - -short_days = ['sun','mon','tue','wed','thu','fri','sat'] -long_days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday'] - -short_day_reg = group (join (short_days, '|')) -long_day_reg = group (join (long_days, '|')) - -daymap = {} -for i in range(7): - daymap[short_days[i]] = i - daymap[long_days[i]] = i - -hms_reg = join (3 * [group('[0-9][0-9]')], ':') - -months = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'] - -monmap = {} -for i in range(12): - monmap[months[i]] = i+1 - -months_reg = group (join (months, '|')) - -# From draft-ietf-http-v11-spec-07.txt/3.3.1 -# Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 -# Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 -# Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format - -# rfc822 format -rfc822_date = join ( - [concat (short_day_reg,','), # day - group('[0-9][0-9]?'), # date - months_reg, # month - group('[0-9]+'), # year - hms_reg, # hour minute second - 'gmt' - ], - ' ' - ) - -rfc822_reg = re.compile (rfc822_date) - -def unpack_rfc822 (m): - g = m.group - a = string.atoi - return ( - a(g(4)), # year - monmap[g(3)], # month - a(g(2)), # day - a(g(5)), # hour - a(g(6)), # minute - a(g(7)), # second - 0, - 0, - 0 - ) - -# rfc850 format -rfc850_date = join ( - [concat (long_day_reg,','), - join ( - [group ('[0-9][0-9]?'), - months_reg, - group ('[0-9]+') - ], - '-' - ), - hms_reg, - 'gmt' - ], - ' ' - ) - -rfc850_reg = re.compile (rfc850_date) -# they actually unpack the same way -def unpack_rfc850 (m): - g = m.group - a = string.atoi - return ( - a(g(4)), # year - monmap[g(3)], # month - a(g(2)), # day - a(g(5)), # hour - a(g(6)), # minute - a(g(7)), # second - 0, - 0, - 0 - ) - -# parsdate.parsedate - ~700/sec. -# parse_http_date - ~1333/sec. - -def build_http_date (when): - return time.strftime ('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(when)) - -def parse_http_date (d): - d = string.lower (d) - tz = time.timezone - m = rfc850_reg.match (d) - if m and m.end() == len(d): - retval = int (time.mktime (unpack_rfc850(m)) - tz) - else: - m = rfc822_reg.match (d) - if m and m.end() == len(d): - retval = int (time.mktime (unpack_rfc822(m)) - tz) - else: - return 0 - # Thanks to Craig Silverstein for pointing - # out the DST discrepancy - if time.daylight and time.localtime(retval)[-1] == 1: # DST correction - retval = retval + (tz - time.altzone) - return retval diff --git a/demo/medusa054/http_server.py b/demo/medusa054/http_server.py deleted file mode 100644 index 8502add..0000000 --- a/demo/medusa054/http_server.py +++ /dev/null @@ -1,749 +0,0 @@ -#! /usr/local/bin/python -# -*- Mode: Python -*- -# -# Author: Sam Rushing -# Copyright 1996-2000 by Sam Rushing -# All Rights Reserved. -# - -# python modules -import os -import re -import socket -import string -import sys -import time - -# async modules -import asyncore -import asynchat - -# medusa modules -import http_date -import producers -import status_handler -import logger - -VERSION_STRING = '1.1' - -from counter import counter -from urllib import unquote, splitquery - -# =========================================================================== -# Request Object -# =========================================================================== - -class http_request: - - # default reply code - reply_code = 200 - - request_counter = counter() - - # Whether to automatically use chunked encoding when - # - # HTTP version is 1.1 - # Content-Length is not set - # Chunked encoding is not already in effect - # - # If your clients are having trouble, you might want to disable this. - use_chunked = 1 - - # by default, this request object ignores user data. - collector = None - - def __init__ (self, *args): - # unpack information about the request - (self.channel, self.request, - self.command, self.uri, self.version, - self.header) = args - - self.outgoing = [] - self.reply_headers = { - 'Server' : 'Medusa/%s' % VERSION_STRING, - 'Date' : http_date.build_http_date (time.time()) - } - self.request_number = http_request.request_counter.increment() - self._split_uri = None - self._header_cache = {} - - # -------------------------------------------------- - # reply header management - # -------------------------------------------------- - def __setitem__ (self, key, value): - self.reply_headers[key] = value - - def __getitem__ (self, key): - return self.reply_headers[key] - - def has_key (self, key): - return self.reply_headers.has_key (key) - - def build_reply_header (self): - return string.join ( - [self.response(self.reply_code)] + map ( - lambda x: '%s: %s' % x, - self.reply_headers.items() - ), - '\r\n' - ) + '\r\n\r\n' - - # -------------------------------------------------- - # split a uri - # -------------------------------------------------- - - # ;?# - path_regex = re.compile ( - # path params query fragment - r'([^;?#]*)(;[^?#]*)?(\?[^#]*)?(#.*)?' - ) - - def split_uri (self): - if self._split_uri is None: - m = self.path_regex.match (self.uri) - if m.end() != len(self.uri): - raise ValueError, "Broken URI" - else: - self._split_uri = m.groups() - return self._split_uri - - def get_header_with_regex (self, head_reg, group): - for line in self.header: - m = head_reg.match (line) - if m.end() == len(line): - return m.group (group) - return '' - - def get_header (self, header): - header = string.lower (header) - hc = self._header_cache - if not hc.has_key (header): - h = header + ': ' - hl = len(h) - for line in self.header: - if string.lower (line[:hl]) == h: - r = line[hl:] - hc[header] = r - return r - hc[header] = None - return None - else: - return hc[header] - - # -------------------------------------------------- - # user data - # -------------------------------------------------- - - def collect_incoming_data (self, data): - if self.collector: - self.collector.collect_incoming_data (data) - else: - self.log_info( - 'Dropping %d bytes of incoming request data' % len(data), - 'warning' - ) - - def found_terminator (self): - if self.collector: - self.collector.found_terminator() - else: - self.log_info ( - 'Unexpected end-of-record for incoming request', - 'warning' - ) - - def push (self, thing): - if type(thing) == type(''): - self.outgoing.append(producers.simple_producer (thing)) - else: - self.outgoing.append(thing) - - def response (self, code=200): - message = self.responses[code] - self.reply_code = code - return 'HTTP/%s %d %s' % (self.version, code, message) - - def error (self, code): - self.reply_code = code - message = self.responses[code] - s = self.DEFAULT_ERROR_MESSAGE % { - 'code': code, - 'message': message, - } - self['Content-Length'] = len(s) - self['Content-Type'] = 'text/html' - # make an error reply - self.push (s) - self.done() - - # can also be used for empty replies - reply_now = error - - def done (self): - "finalize this transaction - send output to the http channel" - - # ---------------------------------------- - # persistent connection management - # ---------------------------------------- - - # --- BUCKLE UP! ---- - - connection = string.lower (get_header (CONNECTION, self.header)) - - close_it = 0 - wrap_in_chunking = 0 - - if self.version == '1.0': - if connection == 'keep-alive': - if not self.has_key ('Content-Length'): - close_it = 1 - else: - self['Connection'] = 'Keep-Alive' - else: - close_it = 1 - elif self.version == '1.1': - if connection == 'close': - close_it = 1 - elif not self.has_key ('Content-Length'): - if self.has_key ('Transfer-Encoding'): - if not self['Transfer-Encoding'] == 'chunked': - close_it = 1 - elif self.use_chunked: - self['Transfer-Encoding'] = 'chunked' - wrap_in_chunking = 1 - else: - close_it = 1 - elif self.version is None: - # Although we don't *really* support http/0.9 (because we'd have to - # use \r\n as a terminator, and it would just yuck up a lot of stuff) - # it's very common for developers to not want to type a version number - # when using telnet to debug a server. - close_it = 1 - - outgoing_header = producers.simple_producer (self.build_reply_header()) - - if close_it: - self['Connection'] = 'close' - - if wrap_in_chunking: - outgoing_producer = producers.chunked_producer ( - producers.composite_producer (self.outgoing) - ) - # prepend the header - outgoing_producer = producers.composite_producer( - [outgoing_header, outgoing_producer] - ) - else: - # prepend the header - self.outgoing.insert(0, outgoing_header) - outgoing_producer = producers.composite_producer (self.outgoing) - - # apply a few final transformations to the output - self.channel.push_with_producer ( - # globbing gives us large packets - producers.globbing_producer ( - # hooking lets us log the number of bytes sent - producers.hooked_producer ( - outgoing_producer, - self.log - ) - ) - ) - - self.channel.current_request = None - - if close_it: - self.channel.close_when_done() - - def log_date_string (self, when): - gmt = time.gmtime(when) - if time.daylight and gmt[8]: - tz = time.altzone - else: - tz = time.timezone - if tz > 0: - neg = 1 - else: - neg = 0 - tz = -tz - h, rem = divmod (tz, 3600) - m, rem = divmod (rem, 60) - if neg: - offset = '-%02d%02d' % (h, m) - else: - offset = '+%02d%02d' % (h, m) - - return time.strftime ( '%d/%b/%Y:%H:%M:%S ', gmt) + offset - - def log (self, bytes): - self.channel.server.logger.log ( - self.channel.addr[0], - '%d - - [%s] "%s" %d %d\n' % ( - self.channel.addr[1], - self.log_date_string (time.time()), - self.request, - self.reply_code, - bytes - ) - ) - - responses = { - 100: "Continue", - 101: "Switching Protocols", - 200: "OK", - 201: "Created", - 202: "Accepted", - 203: "Non-Authoritative Information", - 204: "No Content", - 205: "Reset Content", - 206: "Partial Content", - 300: "Multiple Choices", - 301: "Moved Permanently", - 302: "Moved Temporarily", - 303: "See Other", - 304: "Not Modified", - 305: "Use Proxy", - 400: "Bad Request", - 401: "Unauthorized", - 402: "Payment Required", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 406: "Not Acceptable", - 407: "Proxy Authentication Required", - 408: "Request Time-out", - 409: "Conflict", - 410: "Gone", - 411: "Length Required", - 412: "Precondition Failed", - 413: "Request Entity Too Large", - 414: "Request-URI Too Large", - 415: "Unsupported Media Type", - 500: "Internal Server Error", - 501: "Not Implemented", - 502: "Bad Gateway", - 503: "Service Unavailable", - 504: "Gateway Time-out", - 505: "HTTP Version not supported" - } - - # Default error message - DEFAULT_ERROR_MESSAGE = string.join ( - ['', - 'Error response', - '', - '', - '

    Error response

    ', - '

    Error code %(code)d.', - '

    Message: %(message)s.', - '', - '' - ], - '\r\n' - ) - - -# =========================================================================== -# HTTP Channel Object -# =========================================================================== - -class http_channel (asynchat.async_chat): - - # use a larger default output buffer - ac_out_buffer_size = 1<<16 - - current_request = None - channel_counter = counter() - - def __init__ (self, server, conn, addr): - self.channel_number = http_channel.channel_counter.increment() - self.request_counter = counter() - asynchat.async_chat.__init__ (self, conn) - self.server = server - self.addr = addr - self.set_terminator ('\r\n\r\n') - self.in_buffer = '' - self.creation_time = int (time.time()) - self.check_maintenance() - - def __repr__ (self): - ar = asynchat.async_chat.__repr__(self)[1:-1] - return '<%s channel#: %s requests:%s>' % ( - ar, - self.channel_number, - self.request_counter - ) - - # Channel Counter, Maintenance Interval... - maintenance_interval = 500 - - def check_maintenance (self): - if not self.channel_number % self.maintenance_interval: - self.maintenance() - - def maintenance (self): - self.kill_zombies() - - # 30-minute zombie timeout. status_handler also knows how to kill zombies. - zombie_timeout = 30 * 60 - - def kill_zombies (self): - now = int (time.time()) - for channel in asyncore.socket_map.values(): - if channel.__class__ == self.__class__: - if (now - channel.creation_time) > channel.zombie_timeout: - channel.close() - - # -------------------------------------------------- - # send/recv overrides, good place for instrumentation. - # -------------------------------------------------- - - # this information needs to get into the request object, - # so that it may log correctly. - def send (self, data): - result = asynchat.async_chat.send (self, data) - self.server.bytes_out.increment (len(data)) - return result - - def recv (self, buffer_size): - try: - result = asynchat.async_chat.recv (self, buffer_size) - self.server.bytes_in.increment (len(result)) - return result - except MemoryError: - # --- Save a Trip to Your Service Provider --- - # It's possible for a process to eat up all the memory of - # the machine, and put it in an extremely wedged state, - # where medusa keeps running and can't be shut down. This - # is where MemoryError tends to get thrown, though of - # course it could get thrown elsewhere. - sys.exit ("Out of Memory!") - - def handle_error (self): - t, v = sys.exc_info()[:2] - if t is SystemExit: - raise t, v - else: - asynchat.async_chat.handle_error (self) - - def log (self, *args): - pass - - # -------------------------------------------------- - # async_chat methods - # -------------------------------------------------- - - def collect_incoming_data (self, data): - if self.current_request: - # we are receiving data (probably POST data) for a request - self.current_request.collect_incoming_data (data) - else: - # we are receiving header (request) data - self.in_buffer = self.in_buffer + data - - def found_terminator (self): - if self.current_request: - self.current_request.found_terminator() - else: - header = self.in_buffer - self.in_buffer = '' - lines = string.split (header, '\r\n') - - # -------------------------------------------------- - # crack the request header - # -------------------------------------------------- - - while lines and not lines[0]: - # as per the suggestion of http-1.1 section 4.1, (and - # Eric Parker ), ignore a leading - # blank lines (buggy browsers tack it onto the end of - # POST requests) - lines = lines[1:] - - if not lines: - self.close_when_done() - return - - request = lines[0] - - command, uri, version = crack_request (request) - header = join_headers (lines[1:]) - - # unquote path if necessary (thanks to Skip Montanaro for pointing - # out that we must unquote in piecemeal fashion). - rpath, rquery = splitquery(uri) - if '%' in rpath: - if rquery: - uri = unquote (rpath) + '?' + rquery - else: - uri = unquote (rpath) - - r = http_request (self, request, command, uri, version, header) - self.request_counter.increment() - self.server.total_requests.increment() - - if command is None: - self.log_info ('Bad HTTP request: %s' % repr(request), 'error') - r.error (400) - return - - # -------------------------------------------------- - # handler selection and dispatch - # -------------------------------------------------- - for h in self.server.handlers: - if h.match (r): - try: - self.current_request = r - # This isn't used anywhere. - # r.handler = h # CYCLE - h.handle_request (r) - except: - self.server.exceptions.increment() - (file, fun, line), t, v, tbinfo = asyncore.compact_traceback() - self.log_info( - 'Server Error: %s, %s: file: %s line: %s' % (t,v,file,line), - 'error') - try: - r.error (500) - except: - pass - return - - # no handlers, so complain - r.error (404) - - def writable_for_proxy (self): - # this version of writable supports the idea of a 'stalled' producer - # [i.e., it's not ready to produce any output yet] This is needed by - # the proxy, which will be waiting for the magic combination of - # 1) hostname resolved - # 2) connection made - # 3) data available. - if self.ac_out_buffer: - return 1 - elif len(self.producer_fifo): - p = self.producer_fifo.first() - if hasattr (p, 'stalled'): - return not p.stalled() - else: - return 1 - -# =========================================================================== -# HTTP Server Object -# =========================================================================== - -class http_server (asyncore.dispatcher): - - SERVER_IDENT = 'HTTP Server (V%s)' % VERSION_STRING - - channel_class = http_channel - - def __init__ (self, ip, port, resolver=None, logger_object=None): - self.ip = ip - self.port = port - asyncore.dispatcher.__init__ (self) - self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - - self.handlers = [] - - if not logger_object: - logger_object = logger.file_logger (sys.stdout) - - self.set_reuse_addr() - self.bind ((ip, port)) - - # lower this to 5 if your OS complains - self.listen (1024) - - host, port = self.socket.getsockname() - if not ip: - self.log_info('Computing default hostname', 'warning') - ip = socket.gethostbyname (socket.gethostname()) - try: - self.server_name = socket.gethostbyaddr (ip)[0] - except socket.error: - self.log_info('Cannot do reverse lookup', 'warning') - self.server_name = ip # use the IP address as the "hostname" - - self.server_port = port - self.total_clients = counter() - self.total_requests = counter() - self.exceptions = counter() - self.bytes_out = counter() - self.bytes_in = counter() - - if not logger_object: - logger_object = logger.file_logger (sys.stdout) - - if resolver: - self.logger = logger.resolving_logger (resolver, logger_object) - else: - self.logger = logger.unresolving_logger (logger_object) - - self.log_info ( - 'Medusa (V%s) started at %s' - '\n\tHostname: %s' - '\n\tPort:%d' - '\n' % ( - VERSION_STRING, - time.ctime(time.time()), - self.server_name, - port, - ) - ) - - def writable (self): - return 0 - - def handle_read (self): - pass - - def readable (self): - return self.accepting - - def handle_connect (self): - pass - - def handle_accept (self): - self.total_clients.increment() - try: - conn, addr = self.accept() - except socket.error: - # linux: on rare occasions we get a bogus socket back from - # accept. socketmodule.c:makesockaddr complains that the - # address family is unknown. We don't want the whole server - # to shut down because of this. - self.log_info ('warning: server accept() threw an exception', 'warning') - return - except TypeError: - # unpack non-sequence. this can happen when a read event - # fires on a listening socket, but when we call accept() - # we get EWOULDBLOCK, so dispatcher.accept() returns None. - # Seen on FreeBSD3. - self.log_info ('warning: server accept() threw EWOULDBLOCK', 'warning') - return - - self.channel_class (self, conn, addr) - - def install_handler (self, handler, back=0): - if back: - self.handlers.append (handler) - else: - self.handlers.insert (0, handler) - - def remove_handler (self, handler): - self.handlers.remove (handler) - - def status (self): - def nice_bytes (n): - return string.join (status_handler.english_bytes (n)) - - handler_stats = filter (None, map (maybe_status, self.handlers)) - - if self.total_clients: - ratio = self.total_requests.as_long() / float(self.total_clients.as_long()) - else: - ratio = 0.0 - - return producers.composite_producer ( - [producers.lines_producer ( - ['

    %s

    ' % self.SERVER_IDENT, - '
    Listening on: Host: %s' % self.server_name, - 'Port: %d' % self.port, - '

      ' - '
    • Total Clients: %s' % self.total_clients, - 'Requests: %s' % self.total_requests, - 'Requests/Client: %.1f' % (ratio), - '
    • Total Bytes In: %s' % (nice_bytes (self.bytes_in.as_long())), - 'Bytes Out: %s' % (nice_bytes (self.bytes_out.as_long())), - '
    • Total Exceptions: %s' % self.exceptions, - '

    ' - 'Extension List

      ', - ])] + handler_stats + [producers.simple_producer('
    ')] - ) - -def maybe_status (thing): - if hasattr (thing, 'status'): - return thing.status() - else: - return None - -CONNECTION = re.compile ('Connection: (.*)', re.IGNORECASE) - -# merge multi-line headers -# [486dx2: ~500/sec] -def join_headers (headers): - r = [] - for i in range(len(headers)): - if headers[i][0] in ' \t': - r[-1] = r[-1] + headers[i][1:] - else: - r.append (headers[i]) - return r - -def get_header (head_reg, lines, group=1): - for line in lines: - m = head_reg.match (line) - if m and m.end() == len(line): - return m.group (group) - return '' - -def get_header_match (head_reg, lines): - for line in lines: - m = head_reg.match (line) - if m and m.end() == len(line): - return m - return '' - -REQUEST = re.compile ('([^ ]+) ([^ ]+)(( HTTP/([0-9.]+))$|$)') - -def crack_request (r): - m = REQUEST.match (r) - if m and m.end() == len(r): - if m.group(3): - version = m.group(5) - else: - version = None - return m.group(1), m.group(2), version - else: - return None, None, None - -if __name__ == '__main__': - import sys - if len(sys.argv) < 2: - print 'usage: %s ' % (sys.argv[0]) - else: - import monitor - import filesys - import default_handler - import status_handler - import ftp_server - import chat_server - import resolver - import logger - rs = resolver.caching_resolver ('127.0.0.1') - lg = logger.file_logger (sys.stdout) - ms = monitor.secure_monitor_server ('fnord', '127.0.0.1', 9999) - fs = filesys.os_filesystem (sys.argv[1]) - dh = default_handler.default_handler (fs) - hs = http_server ('', string.atoi (sys.argv[2]), rs, lg) - hs.install_handler (dh) - ftp = ftp_server.ftp_server ( - ftp_server.dummy_authorizer(sys.argv[1]), - port=8021, - resolver=rs, - logger_object=lg - ) - cs = chat_server.chat_server ('', 7777) - sh = status_handler.status_extension([hs,ms,ftp,cs,rs]) - hs.install_handler (sh) - if ('-p' in sys.argv): - def profile_loop (): - try: - asyncore.loop() - except KeyboardInterrupt: - pass - import profile - profile.run ('profile_loop()', 'profile.out') - else: - asyncore.loop() diff --git a/demo/medusa054/https_server.py b/demo/medusa054/https_server.py deleted file mode 100644 index f30bc86..0000000 --- a/demo/medusa054/https_server.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python - -"""A https server built on Medusa's http_server. - -Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" - -import asynchat, asyncore, http_server, socket, sys -from M2Crypto import SSL, version - -VERSION_STRING=version - -class https_channel(http_server.http_channel): - - ac_in_buffer_size = 1 << 16 - - def __init__(self, server, conn, addr): - http_server.http_channel.__init__(self, server, conn, addr) - - def send(self, data): - try: - result = self.socket._write_nbio(data) - if result <= 0: - return 0 - else: - self.server.bytes_out.increment(result) - return result - except SSL.SSLError, why: - self.close() - self.log_info('send: closing channel %s %s' % (repr(self), why)) - return 0 - - def recv(self, buffer_size): - try: - result = self.socket._read_nbio(buffer_size) - if result is None: - return '' - elif result == '': - self.close() - return '' - else: - self.server.bytes_in.increment(len(result)) - return result - except SSL.SSLError, why: - self.close() - self.log_info('recv: closing channel %s %s' % (repr(self), why)) - return '' - - -class https_server(http_server.http_server): - - SERVER_IDENT='M2Crypto HTTPS Server (v%s)' % VERSION_STRING - - channel_class=https_channel - - def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): - http_server.http_server.__init__(self, ip, port, resolver, logger_object) - sys.stdout.write(self.SERVER_IDENT + '\n\n') - sys.stdout.flush() - self.ssl_ctx=ssl_ctx - - def handle_accept(self): - # Cribbed from http_server. - self.total_clients.increment() - try: - conn, addr = self.accept() - except socket.error: - # linux: on rare occasions we get a bogus socket back from - # accept. socketmodule.c:makesockaddr complains that the - # address family is unknown. We don't want the whole server - # to shut down because of this. - sys.stderr.write ('warning: server accept() threw an exception\n') - return - - # Turn the vanilla socket into an SSL connection. - try: - ssl_conn=SSL.Connection(self.ssl_ctx, conn) - ssl_conn._setup_ssl(addr) - ssl_conn.accept_ssl() - self.channel_class(self, ssl_conn, addr) - except SSL.SSLError: - pass - - def writeable(self): - return 0 - diff --git a/demo/medusa054/index.html b/demo/medusa054/index.html deleted file mode 100644 index 0f7de19..0000000 --- a/demo/medusa054/index.html +++ /dev/null @@ -1,6 +0,0 @@ - -M2Crypto HTTPS Server - -

    M2Crypto HTTPS Server - It works!

    - - diff --git a/demo/medusa054/logger.py b/demo/medusa054/logger.py deleted file mode 100644 index d131ab5..0000000 --- a/demo/medusa054/logger.py +++ /dev/null @@ -1,261 +0,0 @@ -# -*- Mode: Python -*- - -import asynchat -import socket -import time # these three are for the rotating logger -import os # | -import stat # v - -# -# three types of log: -# 1) file -# with optional flushing. Also, one that rotates the log. -# 2) socket -# dump output directly to a socket connection. [how do we -# keep it open?] -# 3) syslog -# log to syslog via tcp. this is a per-line protocol. -# - -# -# The 'standard' interface to a logging object is simply -# log_object.log (message) -# - -# a file-like object that captures output, and -# makes sure to flush it always... this could -# be connected to: -# o stdio file -# o low-level file -# o socket channel -# o syslog output... - -class file_logger: - - # pass this either a path or a file object. - def __init__ (self, file, flush=1, mode='a'): - if type(file) == type(''): - if (file == '-'): - import sys - self.file = sys.stdout - else: - self.file = open (file, mode) - else: - self.file = file - self.do_flush = flush - - def __repr__ (self): - return '' % self.file - - def write (self, data): - self.file.write (data) - self.maybe_flush() - - def writeline (self, line): - self.file.writeline (line) - self.maybe_flush() - - def writelines (self, lines): - self.file.writelines (lines) - self.maybe_flush() - - def maybe_flush (self): - if self.do_flush: - self.file.flush() - - def flush (self): - self.file.flush() - - def softspace (self, *args): - pass - - def log (self, message): - if message[-1] not in ('\r', '\n'): - self.write (message + '\n') - else: - self.write (message) - -# like a file_logger, but it must be attached to a filename. -# When the log gets too full, or a certain time has passed, -# it backs up the log and starts a new one. Note that backing -# up the log is done via "mv" because anything else (cp, gzip) -# would take time, during which medusa would do nothing else. - -class rotating_file_logger (file_logger): - - # If freq is non-None we back up "daily", "weekly", or "monthly". - # Else if maxsize is non-None we back up whenever the log gets - # to big. If both are None we never back up. - def __init__ (self, file, freq=None, maxsize=None, flush=1, mode='a'): - self.filename = file - self.mode = mode - self.file = open (file, mode) - self.freq = freq - self.maxsize = maxsize - self.rotate_when = self.next_backup(self.freq) - self.do_flush = flush - - def __repr__ (self): - return '' % self.file - - # We back up at midnight every 1) day, 2) monday, or 3) 1st of month - def next_backup (self, freq): - (yr, mo, day, hr, min, sec, wd, jday, dst) = time.localtime(time.time()) - if freq == 'daily': - return time.mktime((yr,mo,day+1, 0,0,0, 0,0,-1)) - elif freq == 'weekly': - return time.mktime((yr,mo,day-wd+7, 0,0,0, 0,0,-1)) # wd(monday)==0 - elif freq == 'monthly': - return time.mktime((yr,mo+1,1, 0,0,0, 0,0,-1)) - else: - return None # not a date-based backup - - def maybe_flush (self): # rotate first if necessary - self.maybe_rotate() - if self.do_flush: # from file_logger() - self.file.flush() - - def maybe_rotate (self): - if self.freq and time.time() > self.rotate_when: - self.rotate() - self.rotate_when = self.next_backup(self.freq) - elif self.maxsize: # rotate when we get too big - try: - if os.stat(self.filename)[stat.ST_SIZE] > self.maxsize: - self.rotate() - except os.error: # file not found, probably - self.rotate() # will create a new file - - def rotate (self): - (yr, mo, day, hr, min, sec, wd, jday, dst) = time.localtime(time.time()) - try: - self.file.close() - newname = '%s.ends%04d%02d%02d' % (self.filename, yr, mo, day) - try: - open(newname, "r").close() # check if file exists - newname = newname + "-%02d%02d%02d" % (hr, min, sec) - except: # YEARMODY is unique - pass - os.rename(self.filename, newname) - self.file = open(self.filename, self.mode) - except: - pass - -# syslog is a line-oriented log protocol - this class would be -# appropriate for FTP or HTTP logs, but not for dumping stderr to. - -# TODO: a simple safety wrapper that will ensure that the line sent -# to syslog is reasonable. - -# TODO: async version of syslog_client: now, log entries use blocking -# send() - -import m_syslog -syslog_logger = m_syslog.syslog_client - -class syslog_logger (m_syslog.syslog_client): - def __init__ (self, address, facility='user'): - m_syslog.syslog_client.__init__ (self, address) - self.facility = m_syslog.facility_names[facility] - self.address=address - - def __repr__ (self): - return '' % (repr(self.address)) - - def log (self, message): - m_syslog.syslog_client.log ( - self, - message, - facility=self.facility, - priority=m_syslog.LOG_INFO - ) - -# log to a stream socket, asynchronously - -class socket_logger (asynchat.async_chat): - - def __init__ (self, address): - - if type(address) == type(''): - self.create_socket (socket.AF_UNIX, socket.SOCK_STREAM) - else: - self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - - self.connect (address) - self.address = address - - def __repr__ (self): - return '' % (self.address) - - def log (self, message): - if message[-2:] != '\r\n': - self.socket.push (message + '\r\n') - else: - self.socket.push (message) - -# log to multiple places -class multi_logger: - def __init__ (self, loggers): - self.loggers = loggers - - def __repr__ (self): - return '' % (repr(self.loggers)) - - def log (self, message): - for logger in self.loggers: - logger.log (message) - -class resolving_logger: - """Feed (ip, message) combinations into this logger to get a - resolved hostname in front of the message. The message will not - be logged until the PTR request finishes (or fails).""" - - def __init__ (self, resolver, logger): - self.resolver = resolver - self.logger = logger - - class logger_thunk: - def __init__ (self, message, logger): - self.message = message - self.logger = logger - - def __call__ (self, host, ttl, answer): - if not answer: - answer = host - self.logger.log ('%s:%s' % (answer, self.message)) - - def log (self, ip, message): - self.resolver.resolve_ptr ( - ip, - self.logger_thunk ( - message, - self.logger - ) - ) - -class unresolving_logger: - "Just in case you don't want to resolve" - def __init__ (self, logger): - self.logger = logger - - def log (self, ip, message): - self.logger.log ('%s:%s' % (ip, message)) - - -def strip_eol (line): - while line and line[-1] in '\r\n': - line = line[:-1] - return line - -class tail_logger: - "Keep track of the last log messages" - def __init__ (self, logger, size=500): - self.size = size - self.logger = logger - self.messages = [] - - def log (self, message): - self.messages.append (strip_eol (message)) - if len (self.messages) > self.size: - del self.messages[0] - self.logger.log (message) diff --git a/demo/medusa054/m_syslog.py b/demo/medusa054/m_syslog.py deleted file mode 100644 index e212766..0000000 --- a/demo/medusa054/m_syslog.py +++ /dev/null @@ -1,182 +0,0 @@ -# -*- Mode: Python -*- - -# ====================================================================== -# Copyright 1997 by Sam Rushing -# -# All Rights Reserved -# -# Permission to use, copy, modify, and distribute this software and -# its documentation for any purpose and without fee is hereby -# granted, provided that the above copyright notice appear in all -# copies and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of Sam -# Rushing not be used in advertising or publicity pertaining to -# distribution of the software without specific, written prior -# permission. -# -# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN -# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# ====================================================================== - -"""socket interface to unix syslog. -On Unix, there are usually two ways of getting to syslog: via a -local unix-domain socket, or via the TCP service. - -Usually "/dev/log" is the unix domain socket. This may be different -for other systems. - ->>> my_client = syslog_client ('/dev/log') - -Otherwise, just use the UDP version, port 514. - ->>> my_client = syslog_client (('my_log_host', 514)) - -On win32, you will have to use the UDP version. Note that -you can use this to log to other hosts (and indeed, multiple -hosts). - -This module is not a drop-in replacement for the python - extension module - the interface is different. - -Usage: - ->>> c = syslog_client() ->>> c = syslog_client ('/strange/non_standard_log_location') ->>> c = syslog_client (('other_host.com', 514)) ->>> c.log ('testing', facility='local0', priority='debug') - -""" - -# TODO: support named-pipe syslog. -# [see ftp://sunsite.unc.edu/pub/Linux/system/Daemons/syslog-fifo.tar.z] - -# from : -# =========================================================================== -# priorities/facilities are encoded into a single 32-bit quantity, where the -# bottom 3 bits are the priority (0-7) and the top 28 bits are the facility -# (0-big number). Both the priorities and the facilities map roughly -# one-to-one to strings in the syslogd(8) source code. This mapping is -# included in this file. -# -# priorities (these are ordered) - -LOG_EMERG = 0 # system is unusable -LOG_ALERT = 1 # action must be taken immediately -LOG_CRIT = 2 # critical conditions -LOG_ERR = 3 # error conditions -LOG_WARNING = 4 # warning conditions -LOG_NOTICE = 5 # normal but significant condition -LOG_INFO = 6 # informational -LOG_DEBUG = 7 # debug-level messages - -# facility codes -LOG_KERN = 0 # kernel messages -LOG_USER = 1 # random user-level messages -LOG_MAIL = 2 # mail system -LOG_DAEMON = 3 # system daemons -LOG_AUTH = 4 # security/authorization messages -LOG_SYSLOG = 5 # messages generated internally by syslogd -LOG_LPR = 6 # line printer subsystem -LOG_NEWS = 7 # network news subsystem -LOG_UUCP = 8 # UUCP subsystem -LOG_CRON = 9 # clock daemon -LOG_AUTHPRIV = 10 # security/authorization messages (private) - -# other codes through 15 reserved for system use -LOG_LOCAL0 = 16 # reserved for local use -LOG_LOCAL1 = 17 # reserved for local use -LOG_LOCAL2 = 18 # reserved for local use -LOG_LOCAL3 = 19 # reserved for local use -LOG_LOCAL4 = 20 # reserved for local use -LOG_LOCAL5 = 21 # reserved for local use -LOG_LOCAL6 = 22 # reserved for local use -LOG_LOCAL7 = 23 # reserved for local use - -priority_names = { - "alert": LOG_ALERT, - "crit": LOG_CRIT, - "debug": LOG_DEBUG, - "emerg": LOG_EMERG, - "err": LOG_ERR, - "error": LOG_ERR, # DEPRECATED - "info": LOG_INFO, - "notice": LOG_NOTICE, - "panic": LOG_EMERG, # DEPRECATED - "warn": LOG_WARNING, # DEPRECATED - "warning": LOG_WARNING, - } - -facility_names = { - "auth": LOG_AUTH, - "authpriv": LOG_AUTHPRIV, - "cron": LOG_CRON, - "daemon": LOG_DAEMON, - "kern": LOG_KERN, - "lpr": LOG_LPR, - "mail": LOG_MAIL, - "news": LOG_NEWS, - "security": LOG_AUTH, # DEPRECATED - "syslog": LOG_SYSLOG, - "user": LOG_USER, - "uucp": LOG_UUCP, - "local0": LOG_LOCAL0, - "local1": LOG_LOCAL1, - "local2": LOG_LOCAL2, - "local3": LOG_LOCAL3, - "local4": LOG_LOCAL4, - "local5": LOG_LOCAL5, - "local6": LOG_LOCAL6, - "local7": LOG_LOCAL7, - } - -import socket - -class syslog_client: - def __init__ (self, address='/dev/log'): - self.address = address - self.stream = 0 - if isinstance(address, type('')): - try: - self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) - self.socket.connect(address) - except socket.error: - # Some Linux installations have /dev/log - # a stream socket instead of a datagram socket. - self.socket = socket.socket (socket.AF_UNIX, - socket.SOCK_STREAM) - self.stream = 1 - else: - self.socket = socket.socket (socket.AF_INET, socket.SOCK_DGRAM) - - # curious: when talking to the unix-domain '/dev/log' socket, a - # zero-terminator seems to be required. this string is placed - # into a class variable so that it can be overridden if - # necessary. - - log_format_string = '<%d>%s\000' - - def log (self, message, facility=LOG_USER, priority=LOG_INFO): - message = self.log_format_string % ( - self.encode_priority (facility, priority), - message - ) - if self.stream: - self.socket.send (message) - else: - self.socket.sendto (message, self.address) - - def encode_priority (self, facility, priority): - if type(facility) == type(''): - facility = facility_names[facility] - if type(priority) == type(''): - priority = priority_names[priority] - return (facility<<3) | priority - - def close (self): - if self.stream: - self.socket.close() diff --git a/demo/medusa054/medusa_gif.py b/demo/medusa054/medusa_gif.py deleted file mode 100644 index 005644a..0000000 --- a/demo/medusa054/medusa_gif.py +++ /dev/null @@ -1,8 +0,0 @@ -# -*- Mode: Python -*- - -# the medusa icon as a python source file. - -width = 97 -height = 61 - -data = 'GIF89aa\000=\000\204\000\000\000\000\000\255\255\255\245\245\245ssskkkccc111)))\326\326\326!!!\316\316\316\300\300\300\204\204\000\224\224\224\214\214\214\200\200\200RRR\377\377\377JJJ\367\367\367BBB\347\347\347\000\204\000\020\020\020\265\265\265\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000!\371\004\001\000\000\021\000,\000\000\000\000a\000=\000\000\005\376`$\216di\236h\252\256l\353\276p,\317tm\337x\256\357|m\001@\240E\305\000\364\2164\206R)$\005\201\214\007r\012{X\255\312a\004\260\\>\026\3240\353)\224n\001W+X\334\373\231~\344.\303b\216\024\027x<\273\307\255G,rJiWN\014{S}k"?ti\013EdPQ\207G@_%\000\026yy\\\201\202\227\224<\221Fs$pOjWz\241\272\002\325\307g\012(\007\205\312#j\317(\012A\200\224.\241\003\346GS\247\033\245\344\264\366\015L\'PXQl]\266\263\243\232\260?\245\316\371\362\225\035\332\243J\273\332Q\263\357-D\241T\327\270\265\013W&\330\010u\371b\322IW0\214\261]\003\033Va\365Z#\207\213a\030k\2647\262\014p\354\024[n\321N\363\346\317\003\037P\000\235C\302\000\3228(\244\363YaA\005\022\255_\237@\260\000A\212\326\256qbp\321\332\266\011\334=T\023\010"!B\005\003A\010\224\020\220 H\002\337#\020 O\276E\357h\221\327\003\\\000b@v\004\351A.h\365\354\342B\002\011\257\025\\ \220\340\301\353\006\000\024\214\200pA\300\353\012\364\241k/\340\033C\202\003\000\310fZ\011\003V\240R\005\007\354\376\026A\000\000\360\'\202\177\024\004\210\003\000\305\215\360\000\000\015\220\240\332\203\027@\'\202\004\025VpA\000%\210x\321\206\032J\341\316\010\262\211H"l\333\341\200\200>"]P\002\212\011\010`\002\0066FP\200\001\'\024p]\004\027(8B\221\306]\000\201w>\002iB\001\007\340\260"v7J1\343(\257\020\251\243\011\242i\263\017\215\337\035\220\200\221\365m4d\015\016D\251\341iN\354\346Ng\253\200I\240\031\35609\245\2057\311I\302\2007t\231"&`\314\310\244\011e\226(\236\010w\212\300\234\011\012HX(\214\253\311@\001\233^\222pg{% \340\035\224&H\000\246\201\362\215`@\001"L\340\004\030\234\022\250\'\015(V:\302\235\030\240q\337\205\224\212h@\177\006\000\250\210\004\007\310\207\337\005\257-P\346\257\367]p\353\203\271\256:\203\236\211F\340\247\010\3329g\244\010\307*=A\000\203\260y\012\304s#\014\007D\207,N\007\304\265\027\021C\233\207%B\366[m\353\006\006\034j\360\306+\357\274a\204\000\000;' diff --git a/demo/medusa054/poison_handler.py b/demo/medusa054/poison_handler.py deleted file mode 100644 index acc78ab..0000000 --- a/demo/medusa054/poison_handler.py +++ /dev/null @@ -1,69 +0,0 @@ - -import string -import whrandom - -RESP_HEAD="""\ - -""" - -RESP_MIDDLE=""" -

    M2Crypto https server demonstration

    - -This web page is generated by the "poison" http request handler. -
    -The links just go on and on and on... -

    -""" - -RESP_TAIL=""" - -""" - -charset='012345678/90ABCDEFGHIJKLM/NOPQRSTUVWXYZabcd/efghijklmnopqrs/tuvwxyz' -numchar=len(charset) - -def makepage(numlinks): - - title='' - for u in range(whrandom.randint(3, 15)): - pick=whrandom.randint(0, numchar-1) - title=title+charset[pick] - title=title+'' - - url='\r\n' - numlinks=whrandom.randint(2, numlinks) - for i in range(numlinks): - url=url+'' - for u in range(whrandom.randint(3, 15)): - pick=whrandom.randint(0, numchar-1) - url=url+charset[pick] - url=url+'
    \r\n' - - url=RESP_HEAD+title+RESP_MIDDLE+url+RESP_TAIL - return url - - -class poison_handler: - """This is a clone of webpoison - every URL returns a page of URLs, each of which - returns a page of URLs, each of _which_ returns a page of URLs, ad infinitum. - The objective is to sucker address-harvesting bots run by spammers.""" - - def __init__(self, numlinks=10): - self.numlinks = numlinks - self.poison_level = 0 - - def match(self, request): - return (request.uri[:7] == '/poison') - - def handle_request(self, request): - if request.command == 'get': - request.push(makepage(self.numlinks)) - request.done() - diff --git a/demo/medusa054/producers.py b/demo/medusa054/producers.py deleted file mode 100644 index a04906e..0000000 --- a/demo/medusa054/producers.py +++ /dev/null @@ -1,323 +0,0 @@ -# -*- Mode: Python -*- - -""" -A collection of producers. -Each producer implements a particular feature: They can be combined -in various ways to get interesting and useful behaviors. - -For example, you can feed dynamically-produced output into the compressing -producer, then wrap this with the 'chunked' transfer-encoding producer. -""" - -import string -from asynchat import find_prefix_at_end - -class simple_producer: - "producer for a string" - def __init__ (self, data, buffer_size=1024): - self.data = data - self.buffer_size = buffer_size - - def more (self): - if len (self.data) > self.buffer_size: - result = self.data[:self.buffer_size] - self.data = self.data[self.buffer_size:] - return result - else: - result = self.data - self.data = '' - return result - -class scanning_producer: - "like simple_producer, but more efficient for large strings" - def __init__ (self, data, buffer_size=1024): - self.data = data - self.buffer_size = buffer_size - self.pos = 0 - - def more (self): - if self.pos < len(self.data): - lp = self.pos - rp = min ( - len(self.data), - self.pos + self.buffer_size - ) - result = self.data[lp:rp] - self.pos = self.pos + len(result) - return result - else: - return '' - -class lines_producer: - "producer for a list of lines" - - def __init__ (self, lines): - self.lines = lines - - def more (self): - if self.lines: - chunk = self.lines[:50] - self.lines = self.lines[50:] - return string.join (chunk, '\r\n') + '\r\n' - else: - return '' - -class buffer_list_producer: - "producer for a list of strings" - - # i.e., data == string.join (buffers, '') - - def __init__ (self, buffers): - - self.index = 0 - self.buffers = buffers - - def more (self): - if self.index >= len(self.buffers): - return '' - else: - data = self.buffers[self.index] - self.index = self.index + 1 - return data - -class file_producer: - "producer wrapper for file[-like] objects" - - # match http_channel's outgoing buffer size - out_buffer_size = 1<<16 - - def __init__ (self, file): - self.done = 0 - self.file = file - - def more (self): - if self.done: - return '' - else: - data = self.file.read (self.out_buffer_size) - if not data: - self.file.close() - del self.file - self.done = 1 - return '' - else: - return data - -# A simple output producer. This one does not [yet] have -# the safety feature builtin to the monitor channel: runaway -# output will not be caught. - -# don't try to print from within any of the methods -# of this object. - -class output_producer: - "Acts like an output file; suitable for capturing sys.stdout" - def __init__ (self): - self.data = '' - - def write (self, data): - lines = string.splitfields (data, '\n') - data = string.join (lines, '\r\n') - self.data = self.data + data - - def writeline (self, line): - self.data = self.data + line + '\r\n' - - def writelines (self, lines): - self.data = self.data + string.joinfields ( - lines, - '\r\n' - ) + '\r\n' - - def flush (self): - pass - - def softspace (self, *args): - pass - - def more (self): - if self.data: - result = self.data[:512] - self.data = self.data[512:] - return result - else: - return '' - -class composite_producer: - "combine a fifo of producers into one" - def __init__ (self, producers): - self.producers = producers - - def more (self): - while len(self.producers): - p = self.producers[0] - d = p.more() - if d: - return d - else: - self.producers.pop(0) - else: - return '' - - -class globbing_producer: - """ - 'glob' the output from a producer into a particular buffer size. - helps reduce the number of calls to send(). [this appears to - gain about 30% performance on requests to a single channel] - """ - - def __init__ (self, producer, buffer_size=1<<16): - self.producer = producer - self.buffer = '' - self.buffer_size = buffer_size - - def more (self): - while len(self.buffer) < self.buffer_size: - data = self.producer.more() - if data: - self.buffer = self.buffer + data - else: - break - r = self.buffer - self.buffer = '' - return r - - -class hooked_producer: - """ - A producer that will call when it empties,. - with an argument of the number of bytes produced. Useful - for logging/instrumentation purposes. - """ - - def __init__ (self, producer, function): - self.producer = producer - self.function = function - self.bytes = 0 - - def more (self): - if self.producer: - result = self.producer.more() - if not result: - self.producer = None - self.function (self.bytes) - else: - self.bytes = self.bytes + len(result) - return result - else: - return '' - -# HTTP 1.1 emphasizes that an advertised Content-Length header MUST be -# correct. In the face of Strange Files, it is conceivable that -# reading a 'file' may produce an amount of data not matching that -# reported by os.stat() [text/binary mode issues, perhaps the file is -# being appended to, etc..] This makes the chunked encoding a True -# Blessing, and it really ought to be used even with normal files. -# How beautifully it blends with the concept of the producer. - -class chunked_producer: - """A producer that implements the 'chunked' transfer coding for HTTP/1.1. - Here is a sample usage: - request['Transfer-Encoding'] = 'chunked' - request.push ( - producers.chunked_producer (your_producer) - ) - request.done() - """ - - def __init__ (self, producer, footers=None): - self.producer = producer - self.footers = footers - - def more (self): - if self.producer: - data = self.producer.more() - if data: - return '%x\r\n%s\r\n' % (len(data), data) - else: - self.producer = None - if self.footers: - return string.join ( - ['0'] + self.footers, - '\r\n' - ) + '\r\n\r\n' - else: - return '0\r\n\r\n' - else: - return '' - -# Unfortunately this isn't very useful right now (Aug 97), because -# apparently the browsers don't do on-the-fly decompression. Which -# is sad, because this could _really_ speed things up, especially for -# low-bandwidth clients (i.e., most everyone). - -try: - import zlib -except ImportError: - zlib = None - -class compressed_producer: - """ - Compress another producer on-the-fly, using ZLIB - [Unfortunately, none of the current browsers seem to support this] - """ - - # Note: It's not very efficient to have the server repeatedly - # compressing your outgoing files: compress them ahead of time, or - # use a compress-once-and-store scheme. However, if you have low - # bandwidth and low traffic, this may make more sense than - # maintaining your source files compressed. - # - # Can also be used for compressing dynamically-produced output. - - def __init__ (self, producer, level=5): - self.producer = producer - self.compressor = zlib.compressobj (level) - - def more (self): - if self.producer: - cdata = '' - # feed until we get some output - while not cdata: - data = self.producer.more() - if not data: - self.producer = None - return self.compressor.flush() - else: - cdata = self.compressor.compress (data) - return cdata - else: - return '' - -class escaping_producer: - - "A producer that escapes a sequence of characters" - " Common usage: escaping the CRLF.CRLF sequence in SMTP, NNTP, etc..." - - def __init__ (self, producer, esc_from='\r\n.', esc_to='\r\n..'): - self.producer = producer - self.esc_from = esc_from - self.esc_to = esc_to - self.buffer = '' - self.find_prefix_at_end = find_prefix_at_end - - def more (self): - esc_from = self.esc_from - esc_to = self.esc_to - - buffer = self.buffer + self.producer.more() - - if buffer: - buffer = string.replace (buffer, esc_from, esc_to) - i = self.find_prefix_at_end (buffer, esc_from) - if i: - # we found a prefix - self.buffer = buffer[-i:] - return buffer[:-i] - else: - # no prefix, return it all - self.buffer = '' - return buffer - else: - return buffer diff --git a/demo/medusa054/server.pem b/demo/medusa054/server.pem deleted file mode 100644 index 1ee9282..0000000 --- a/demo/medusa054/server.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx -NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls -b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c -kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 -KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp -/y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 -QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB -H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 -du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv -MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm -aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t -ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy -lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW -iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 -0QkPQNdP ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu -6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe -I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB -AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ -u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 -xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 -1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp -IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx -luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I -lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS -38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy -v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z -DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= ------END RSA PRIVATE KEY----- diff --git a/demo/medusa054/status_handler.py b/demo/medusa054/status_handler.py deleted file mode 100644 index 8d2583e..0000000 --- a/demo/medusa054/status_handler.py +++ /dev/null @@ -1,272 +0,0 @@ -# -*- Mode: Python -*- - -VERSION_STRING = "$Id: status_handler.py 299 2005-06-09 17:32:28Z heikki $" - -# -# medusa status extension -# - -import string -import time -import re -from cgi import escape - -import asyncore -import http_server -import medusa_gif -import producers -from counter import counter - -START_TIME = long(time.time()) - -class status_extension: - hit_counter = counter() - - def __init__ (self, objects, statusdir='/status', allow_emergency_debug=0): - self.objects = objects - self.statusdir = statusdir - self.allow_emergency_debug = allow_emergency_debug - # We use /status instead of statusdir here because it's too - # hard to pass statusdir to the logger, who makes the HREF - # to the object dir. We don't need the security-through- - # obscurity here in any case, because the id is obscurity enough - self.hyper_regex = re.compile('/status/object/([0-9]+)/.*') - self.hyper_objects = [] - for object in objects: - self.register_hyper_object (object) - - def __repr__ (self): - return '' % ( - self.hit_counter, - id(self) - ) - - def match (self, request): - path, params, query, fragment = request.split_uri() - # For reasons explained above, we don't use statusdir for /object - return (path[:len(self.statusdir)] == self.statusdir or - path[:len("/status/object/")] == '/status/object/') - - # Possible Targets: - # /status - # /status/channel_list - # /status/medusa.gif - - # can we have 'clickable' objects? - # [yes, we can use id(x) and do a linear search] - - # Dynamic producers: - # HTTP/1.0: we must close the channel, because it's dynamic output - # HTTP/1.1: we can use the chunked transfer-encoding, and leave - # it open. - - def handle_request (self, request): - [path, params, query, fragment] = request.split_uri() - self.hit_counter.increment() - if path == self.statusdir: # and not a subdirectory - up_time = string.join (english_time (long(time.time()) - START_TIME)) - request['Content-Type'] = 'text/html' - request.push ( - '' - 'Medusa Status Reports' - '' - '

    Medusa Status Reports

    ' - 'Up: %s' % up_time - ) - for i in range(len(self.objects)): - request.push (self.objects[i].status()) - request.push ('
    \r\n') - request.push ( - '

    Channel List' - '


    ' - '' - '' % ( - self.statusdir, - self.statusdir, - medusa_gif.width, - medusa_gif.height - ) - ) - request.done() - elif path == self.statusdir + '/channel_list': - request['Content-Type'] = 'text/html' - request.push ('') - request.push(channel_list_producer(self.statusdir)) - request.push ( - '
    ' - '' % ( - self.statusdir, - medusa_gif.width, - medusa_gif.height - ) + - '' - ) - request.done() - - elif path == self.statusdir + '/medusa.gif': - request['Content-Type'] = 'image/gif' - request['Content-Length'] = len(medusa_gif.data) - request.push (medusa_gif.data) - request.done() - - elif path == self.statusdir + '/close_zombies': - message = ( - '

    Closing all zombie http client connections...

    ' - '

    Back to the status page' % self.statusdir - ) - request['Content-Type'] = 'text/html' - request['Content-Length'] = len (message) - request.push (message) - now = int (time.time()) - for channel in asyncore.socket_map.keys(): - if channel.__class__ == http_server.http_channel: - if channel != request.channel: - if (now - channel.creation_time) > channel.zombie_timeout: - channel.close() - request.done() - - # Emergency Debug Mode - # If a server is running away from you, don't KILL it! - # Move all the AF_INET server ports and perform an autopsy... - # [disabled by default to protect the innocent] - elif self.allow_emergency_debug and path == self.statusdir + '/emergency_debug': - request.push ('Moving All Servers...') - request.done() - for channel in asyncore.socket_map.keys(): - if channel.accepting: - if type(channel.addr) is type(()): - ip, port = channel.addr - channel.socket.close() - channel.del_channel() - channel.addr = (ip, port+10000) - fam, typ = channel.family_and_type - channel.create_socket (fam, typ) - channel.set_reuse_addr() - channel.bind (channel.addr) - channel.listen(5) - - else: - m = self.hyper_regex.match (path) - if m: - oid = string.atoi (m.group (1)) - for object in self.hyper_objects: - if id (object) == oid: - if hasattr (object, 'hyper_respond'): - object.hyper_respond (self, path, request) - else: - request.error (404) - return - - def status (self): - return producers.simple_producer ( - '

  • Status Extension Hits : %s' % self.hit_counter - ) - - def register_hyper_object (self, object): - if not object in self.hyper_objects: - self.hyper_objects.append (object) - -import logger - -class logger_for_status (logger.tail_logger): - - def status (self): - return 'Last %d log entries for: %s' % ( - len (self.messages), - html_repr (self) - ) - - def hyper_respond (self, sh, path, request): - request['Content-Type'] = 'text/plain' - messages = self.messages[:] - messages.reverse() - request.push (lines_producer (messages)) - request.done() - -class lines_producer: - def __init__ (self, lines): - self.lines = lines - - def more (self): - if self.lines: - chunk = self.lines[:50] - self.lines = self.lines[50:] - return string.join (chunk, '\r\n') + '\r\n' - else: - return '' - -class channel_list_producer (lines_producer): - def __init__ (self, statusdir): - channel_reprs = map ( - lambda x: '<' + repr(x)[1:-1] + '>', - asyncore.socket_map.values() - ) - channel_reprs.sort() - lines_producer.__init__ ( - self, - ['

    Active Channel List

    ', - '
    '
    -                 ] + channel_reprs + [
    -                         '
    ', - '

    Status Report' % statusdir - ] - ) - - -def html_repr (object): - so = escape (repr (object)) - if hasattr (object, 'hyper_respond'): - return '%s' % (id (object), so) - else: - return so - -def html_reprs (list, front='', back=''): - reprs = map ( - lambda x,f=front,b=back: '%s%s%s' % (f,x,b), - map (lambda x: escape (html_repr(x)), list) - ) - reprs.sort() - return reprs - -# for example, tera, giga, mega, kilo -# p_d (n, (1024, 1024, 1024, 1024)) -# smallest divider goes first - for example -# minutes, hours, days -# p_d (n, (60, 60, 24)) - -def progressive_divide (n, parts): - result = [] - for part in parts: - n, rem = divmod (n, part) - result.append (rem) - result.append (n) - return result - -# b,k,m,g,t -def split_by_units (n, units, dividers, format_string): - divs = progressive_divide (n, dividers) - result = [] - for i in range(len(units)): - if divs[i]: - result.append (format_string % (divs[i], units[i])) - result.reverse() - if not result: - return [format_string % (0, units[0])] - else: - return result - -def english_bytes (n): - return split_by_units ( - n, - ('','K','M','G','T'), - (1024, 1024, 1024, 1024, 1024), - '%d %sB' - ) - -def english_time (n): - return split_by_units ( - n, - ('secs', 'mins', 'hours', 'days', 'weeks', 'years'), - ( 60, 60, 24, 7, 52), - '%d %s' - ) diff --git a/demo/medusa054/xmlrpc_handler.py b/demo/medusa054/xmlrpc_handler.py deleted file mode 100644 index 15057cf..0000000 --- a/demo/medusa054/xmlrpc_handler.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- Mode: Python -*- - -# See http://www.xml-rpc.com/ -# http://www.pythonware.com/products/xmlrpc/ - -# Based on "xmlrpcserver.py" by Fredrik Lundh (fredrik@pythonware.com) - -VERSION = "$Id: xmlrpc_handler.py 299 2005-06-09 17:32:28Z heikki $" - -import http_server -import xmlrpclib - -import string -import sys - -class xmlrpc_handler: - - def match (self, request): - # Note: /RPC2 is not required by the spec, so you may override this method. - if request.uri[:5] == '/RPC2': - return 1 - else: - return 0 - - def handle_request (self, request): - [path, params, query, fragment] = request.split_uri() - - if request.command == 'POST': - request.collector = collector (self, request) - else: - request.error (400) - - def continue_request (self, data, request): - params, method = xmlrpclib.loads (data) - try: - # generate response - try: - response = self.call (method, params) - if type(response) != type(()): - response = (response,) - except: - # report exception back to server - response = xmlrpclib.dumps ( - xmlrpclib.Fault (1, "%s:%s" % (sys.exc_type, sys.exc_value)) - ) - else: - response = xmlrpclib.dumps (response, methodresponse=1) - except: - # internal error, report as HTTP server error - request.error (500) - else: - # got a valid XML RPC response - request['Content-Type'] = 'text/xml' - request.push (response) - request.done() - - def call (self, method, params): - # override this method to implement RPC methods - raise "NotYetImplemented" - -class collector: - - "gathers input for POST and PUT requests" - - def __init__ (self, handler, request): - - self.handler = handler - self.request = request - self.data = '' - - # make sure there's a content-length header - cl = request.get_header ('content-length') - - if not cl: - request.error (411) - else: - cl = string.atoi (cl) - # using a 'numeric' terminator - self.request.channel.set_terminator (cl) - - def collect_incoming_data (self, data): - self.data = self.data + data - - def found_terminator (self): - # set the terminator back to the default - self.request.channel.set_terminator ('\r\n\r\n') - self.handler.continue_request (self.data, self.request) - -if __name__ == '__main__': - - class rpc_demo (xmlrpc_handler): - - def call (self, method, params): - print 'method="%s" params=%s' % (method, params) - return "Sure, that works" - - import asyncore - - hs = http_server.http_server ('', 8000) - rpc = rpc_demo() - hs.install_handler (rpc) - - asyncore.loop() diff --git a/demo/perf/memio.py b/demo/perf/memio.py deleted file mode 100644 index 238d85c..0000000 --- a/demo/perf/memio.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python2.0 - -"""A comparison of Python's cStringIO and M2Crypto's MemoryBuffer, -the outcome of which is that MemoryBuffer suffers from doing too much -in Python. - -Two way to optimise MemoryBuffer: -1. Create MemoryBufferIn and MemoryBufferOut a la StringI and StringO. -2. Have MemoryBuffer do all internal work with cStringIO. ;-) -""" - -from cStringIO import StringIO -from M2Crypto.BIO import MemoryBuffer -from M2Crypto import m2 -import profile - -txt = 'Python, Smalltalk, Haskell, Scheme, Lisp, Self, Erlang, ML, ...' - -def stringi(iter, txt=txt): - buf = StringIO() - for i in range(iter): - buf.write(txt) - out = buf.getvalue() - -def membufi(iter, txt=txt): - buf = MemoryBuffer() - for i in range(iter): - buf.write(txt) - out = buf.getvalue() - -def membuf2i(iter, txt=txt): - buf = MemoryBuffer() - buf.write(txt * iter) - out = buf.getvalue() - -def cmembufi(iter, txt=txt): - buf = m2.bio_new(m2.bio_s_mem()) - for i in range(iter): - m2.bio_write(buf, txt) - m2.bio_set_mem_eof_return(buf, 0) - out = m2.bio_read(buf, m2.bio_ctrl_pending(buf)) - -if __name__ == '__main__': - profile.run('stringi(10000)') - profile.run('cmembufi(10000)') - profile.run('membufi(10000)') - profile.run('membuf2i(10000)') - - diff --git a/demo/perf/sha1.py b/demo/perf/sha1.py deleted file mode 100644 index 6d85289..0000000 --- a/demo/perf/sha1.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python2.0 - -"""A comparison of Python's sha and M2Crypto.EVP.MessageDigest, -the outcome of which is that EVP.MessageDigest suffers from doing -too much in Python.""" - -import profile - -from sha import sha -import M2Crypto -from M2Crypto import m2 -from M2Crypto.EVP import MessageDigest - -txt = 'Python, Smalltalk, Haskell, Scheme, Lisp, Self, Erlang, ML, ...' - -def py_sha(iter, txt=txt): - s = sha() - for i in range(iter): - s.update(txt) - out = s.digest() - -def m2_sha(iter, txt=txt): - s = MessageDigest('sha1') - for i in range(iter): - s.update(txt) - out = s.digest() - -def m2_sha_2(iter, txt=txt): - s = MessageDigest('sha1') - s.update(txt * iter) - out = s.digest() - -def m2c_sha(iter, txt=txt): - ctx = m2.md_ctx_new() - m2.digest_init(ctx, m2.sha1()) - for i in range(iter): - m2.digest_update(ctx, txt) - out = m2.digest_final(ctx) - -if __name__ == '__main__': - profile.run('py_sha(10000)') - profile.run('m2_sha(10000)') - profile.run('m2_sha_2(10000)') - profile.run('m2c_sha(10000)') - - diff --git a/demo/pgp/pgpstep.py b/demo/pgp/pgpstep.py deleted file mode 100644 index ff5b135..0000000 --- a/demo/pgp/pgpstep.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python - -"""pgpstep - steps through a pgp2 packet stream. - -Copyright (c) 1999 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import PGP, util -import time - -def desc_public_key(pkt): - print 'packet = public_key' - print 'version =', pkt.version() - print 'created = ', time.asctime(time.gmtime(pkt.timestamp())) - print 'validity code =', pkt.validity() - print 'pkc type =', `pkt.pkc()` - #e, n = pkt.pubkey() - print 'e =', `pkt._e` - print 'n =', `pkt._n` - print - -def desc_trust(pkt): - print 'packet = trust' - print 'trustworthiness = ' - print - -def desc_userid(pkt): - print 'packet = user_id' - print 'user_id =', pkt.userid() - print - -def desc_signature(pkt): - print 'packet = signature' - print 'version =', pkt.version() - print 'classification =', `pkt._classification` - print 'created = ', time.asctime(time.gmtime(pkt.timestamp())) - print 'keyid =', `pkt._keyid` - print 'pkc type =', `pkt.pkc()` - print 'md_algo =', `pkt._md_algo` - print 'md_chksum =', `pkt._md_chksum` - print 'sig =', `pkt._sig` - print - -def desc_private_key(pkt): - print 'packet = private key' - print 'version =', pkt.version() - print 'created = ', time.asctime(time.gmtime(pkt.timestamp())) - print 'validity code =', pkt.validity() - print 'pkc type =', `pkt.pkc()` - print 'e =', `pkt._e` - print 'n =', `pkt._n` - print 'cipher =', `pkt._cipher` - if pkt._cipher == '\001': - print 'following attributes are encrypted' - print 'iv =', `pkt._iv` - print 'd =', `pkt._d` - print 'p =', `pkt._p` - print 'q =', `pkt._q` - print 'u =', `pkt._u` - print 'checksum =', `pkt._cksum` - print - -def desc_cke(pkt): - print 'packet = cke' - print 'iv =', `pkt.iv` - print 'checksum =', `pkt.cksum` - print 'ciphertext =', `pkt.ctxt` - print - -def desc_pke(pkt): - print 'packet = pke' - print 'version =', pkt.version - print 'keyid =', `pkt.keyid` - print 'pkc type =', pkt.pkc_type - print 'dek =', hex(pkt.dek)[:-1] - print - -def desc_literal(pkt): - print 'packet = literal data' - print 'mode =', `pkt.fmode` - print 'filename =', pkt.fname - print 'time = ', time.asctime(time.gmtime(pkt.ftime)) - print 'data = <%d octets of literal data>' % (len(pkt.data),) - print - -DESC = { - PGP.public_key_packet: desc_public_key, - PGP.trust_packet: desc_trust, - PGP.userid_packet: desc_userid, - PGP.signature_packet: desc_signature, - PGP.private_key_packet: desc_private_key, - PGP.cke_packet: desc_cke, - PGP.pke_packet: desc_pke, - PGP.literal_packet: desc_literal, -} - -if __name__ == '__main__': - import sys - count = 0 - for arg in sys.argv[1:]: - f = open(arg, 'rb') - ps = PGP.packet_stream(f) - while 1: - pkt = ps.read() - if pkt is None: - break - elif pkt: - print '-'*70 - DESC[pkt.__class__](pkt) - count = count + ps.count() - ps.close() - print '-'*70 - print 'Total octets processed =', count - diff --git a/demo/pgp/pubring.pgp b/demo/pgp/pubring.pgp deleted file mode 100644 index fbe4863b400236e092ba68d4e0da71d284c6edf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1088 zcmbQq(8XlLKYtGc10(Y@i=UZI0Uoc+mOi;GB;|K&a`duq8)g|9p7%~{+HRX9ule-N zR@1Kj!{&>`1tSd7EV~246!!){f74rf!}aL;&^La@!M{x1x9pz0H}qjcnS=5!*_1zS zJ=@|vwzB@ZX34(Mg}v@mv|prXN2~e9Ug1enW`_kbzUDj2`-Q1QxSeKT72Lqcw1q7t zF|9d)8>5zI*obXKc>{Z0+A0U1SYkChHsBt=S~O z^WdXyMm2B3T+>w_T}~|#Z+B^EPP3A=WZuCrkGcC32iuRw3V+gGC0g3WtaMoVM;Yom zPN&SAoJxhH{7SF`eSi*}6%KSD;};&e;>4WYk;%96bDaevD)|fKMO0eSo2Gm3OBU6c z?R$0oo}Gqe*AMXqiI+U}Q#Dw!#i%Oc%|DH=XPbf_-dtS@HD9P0Y<@{ zW--_zTcAbL{6H2pJb%q{V40hN&|SvG)=#$@dVHL(wdVirb&9EHY^&~m4`0#IYZiL? zN2&Iwh$UJvO&JdvScO61s_33rRH@*RU!Iegm!e>k4&*r$R~DC~=4K`r>m}#s+QEG^ z{W!!&#hZfymMQqY{J8Ip<$3jkPCFh~Z!g+lqs!p;%x%e=-N$&%*=B|n|2V*OTYz<#)QabaA~o3PVwm+ts#&#|Gs(dp@d z8xQ_6Ppw(_B`tpHuC}vH3iA_|?QmcC+utTqy_j@A%$NrD125wW*6ED5_ZDR?-p9W* z=q#^s*#l*sJ^cQgpZ+%c*1Ye72iMX=@{@mGXER&~O^jIQrj00&CB=_*d_KEt&SKw`f-U<;N4lb(S-FHmPXO+CNP)$unlt<mA8F!v&xsS_OZ@S z&ps!+DsA~gbGa@yUX%5U({#Pdd_N!AE~PRx?9>HOS*lfIk@zf!P4ah ze4M|^1&*GbKY=m*osYJ?ZSJYMl9+fyDf!)NXZ%(F;Hnc_$9>QI<`WNR?pEf)eCIEp er(YJ@F+WRA^U0T&?Dsmt?4eP?0?MYqXaxWnw8%yP diff --git a/demo/pgp/secring.pgp b/demo/pgp/secring.pgp deleted file mode 100644 index 7eca123606f2c001ed40481883ee96ba954d7821..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1969 zcmV;i2Tu5v0oMXD51+gM009H$IQeOUP)O=FrR38R8cy1iTc-A~nldrZOJRbyJz^gz zy;b3Wc0eP#9c27Q zjJ97$wFUatIR~*s2Y&KfPFWR*g*UN{6OtM>!w_ioZ$lqWRwP(P%K!xt0TxVxb0fO2 z3IpY^H0k}bYto`~c^m!*0J&8ZB*B>%6176WyuhZ?afUXFpCU<_2VKdpaJt1*ZHn17~PV?Z31E3 z?XHACgb1#fl18P2i+5X$o&ttJ4VeS4!d{!0u&vZ!@hBp#_HR1*HEk0=51 zB=vvey;$0skgA$Mc~VsiTK|7+9rEb6zqOtMY$9$of~9FbJ7D=QnP!ZV;3pDS;5K#L z!E~*qzq2KeJ3 z{ATK5IX+yeK&AX600j{N8NoeI-u!3n1OEcik@XSqcHL>yF>-<>g zQkmjgtfl4rN$CXy%2~QDvj^b$9_1&d7wEzGfZ5^M=|{NZ3UzMh!8N2N^sdHHj%2HR zWHIl%RWKG_;?}eTYuDnVpAJ}~*U3!Im>*UAsAvUK;Z@8;v3i{;Av#`3R{2B7D`o-! z`A4qH zAYyNMumJ;=0pJ2M51wxT009I5mK%vX!X)6W4!kdx%>ox0MV6FdzKslnxZPCt#w{+5 z!**moYh-Qq_p)XtZo5^fo|yk$%bGy-3>88}8p+xe2Rt|fQ94N>O&dv=oT?w+Y=S)m zv8Y^)n!7Wo-O2qo>fTI~+zmvN1%XRG=ArSYt`eFPlz|wyy^2;hgic^_00j{NfQS$7 zeuW|L1OADiZ$H1FIR`;j;uPs!?2;fXE+2WTgDe^{{79;Kvj^MsNj3;y5oI@Z9Tjgb zHgCP$O&9GgW4D+3_P{>8k#+S|^hm!v+17AzO_u@y6FwtME4nY=KUL>bo-KYOM4GVh z`cbmu+7=GLCpwW3WQ2Zy%4(XEHO{h--pWVxHrzydO%~RzubG+L1IgJM0sx6!6jm7P zj){Iytu^QpeF_CUcSqs*%VifG4$QLZbUcbK5=Y-qX4vn#Zag-jpl7nDxx10vv);?? zc#JFW0m%XU6!j9Qx6b9Y=eV5MCA8wb2S5{U&&ja>J7h3%{!HMP;k7a;QhMlT!2r7@O6_R(b#OsK4V7=Aw41rd;`@_ zhnCuM@h^`MHOj4wEdw=-P$2qzrUad#zRa-J9NrK7d>IIEbg4qW%It1)v+4r*0s!(i zoqU^P7D9I!c3Y`}Tq}Kpx5zSM9l|v?uAvmJyzj+F7A*&qkveAq$qiwnO?rgyL-a(X zM=DIPI$$T8G8X~>f0+%MQ?_Wzy_X0jo=MP<+{4%S6@eW#qaglOW<{7v`GVU|!*~)m0se!DL;{)#-62j8FX1*WHB*u1@81+}EpA$e zRX&~2z|$`21DlKj6DDO^wx)FE`$&suTL&CsjGkDu(^Mw3((9S6umJ+J1Y}`mbg%&f Dru39l diff --git a/demo/pkcs7/pkcs7-thawte.pem b/demo/pkcs7/pkcs7-thawte.pem deleted file mode 100644 index a444627..0000000 --- a/demo/pkcs7/pkcs7-thawte.pem +++ /dev/null @@ -1,45 +0,0 @@ ------BEGIN PKCS7----- -MIAGCSqGSIb3DQEHAqCAMIIH1wIBATELMAkGBSsOAwIaBQAwgAYJKoZIhvcNAQcB -AACgggXgMIICxDCCAi2gAwIBAgIDAphPMA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD -VQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtEdXJiYW52 -aWxsZTEPMA0GA1UEChMGVGhhd3RlMR0wGwYDVQQLExRDZXJ0aWZpY2F0ZSBTZXJ2 -aWNlczEoMCYGA1UEAxMfUGVyc29uYWwgRnJlZW1haWwgUlNBIDE5OTkuOS4xNjAe -Fw0wMDA1MTgxMTA4MTJaFw0wMTA1MTgxMTA4MTJaMGUxETAPBgNVBAQTCFN0cm9l -ZGVyMRAwDgYDVQQqEwdNaWNoYWVsMRkwFwYDVQQDExBNaWNoYWVsIFN0cm9lZGVy -MSMwIQYJKoZIhvcNAQkBFhRtaWNoYWVsQHN0cm9lZGVyLmNvbTCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAqzxf+ZpWoELOD7sXes/G9O6dSCkGeNL/G5l0k/b4 -C9QnZyEh2S0vWI+g43G1uGhu6sgI5Y1SfrG08xGIUEcmexxnl6krTR/QlHr+t9If -UXFTmEPAnuIpfPRUqhOQlNFB1DfwKVLb4J3b2947ulv4vpb4owVMC+WjDM5fo765 -RXMCAwEAAaNSMFAwHwYDVR0RBBgwFoEUbWljaGFlbEBzdHJvZWRlci5jb20wDAYD -VR0TAQH/BAIwADAfBgNVHSMEGDAWgBSIq/Fgg2ZV9ORYx0YdwGG9I9fDjDANBgkq -hkiG9w0BAQQFAAOBgQCxx7Uvsnq1F/yOIPiUmlaTXLFAvvTj2trHAF4UFhkQGe6V -IBHmDk62H1xJhA4AHNVz3Pe250S8Fu75OgOh2pRJ8KfB6cJU0gxz9ahRt48Qy6+m -XUHk9135ru2u8I505nj4i37T6zK3+O/lZU+P79qdPHYwO6dNsYyaRFYLxGyXTjCC -AxQwggJ9oAMCAQICAQswDQYJKoZIhvcNAQEEBQAwgdExCzAJBgNVBAYTAlpBMRUw -EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE -ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy -dmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFp -bCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNv -bTAeFw05OTA5MTYxNDAxNDBaFw0wMTA5MTUxNDAxNDBaMIGUMQswCQYDVQQGEwJa -QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtEdXJiYW52aWxsZTEP -MA0GA1UEChMGVGhhd3RlMR0wGwYDVQQLExRDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEo -MCYGA1UEAxMfUGVyc29uYWwgRnJlZW1haWwgUlNBIDE5OTkuOS4xNjCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEAs2lal9TQFgt6tcVd6SGcI3LNEkxL937Px/vK -ciT0QlKsV5Xje2F6F4Tn/XI5OJS06u1lp5IGXr3gZfYZu5R5dkw+uWhwdYQc9BF0 -ALwFLE8JAxcxzPRB1HLGpl3iiESwiy7ETfHw1oU+bPOVlHiRfkDpnNGNFVeOwnPl -MN5G9U8CAwEAAaM3MDUwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRy -ScJzNMZV9At2coF+d/SH58ayDjANBgkqhkiG9w0BAQQFAAOBgQBrxlnpMfrptuyx -A9jfcnL+kWBI6sZV3XvwZ47GYXDnbcKlN9idtxcoVgWL3Vx1b8aRkMZsZnET0BB8 -a5FvhuAhNi3B1+qyCa3PLW3Gg1Kb+7v+nIed/LfpdJLkXJeu/H6syg1vcnpnLGtz -9Yb5nfUAbvQdB86dnoJjKe+TCX5V3jGCAdAwggHMAgEBMIGcMIGUMQswCQYDVQQG -EwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtEdXJiYW52aWxs -ZTEPMA0GA1UEChMGVGhhd3RlMR0wGwYDVQQLExRDZXJ0aWZpY2F0ZSBTZXJ2aWNl -czEoMCYGA1UEAxMfUGVyc29uYWwgRnJlZW1haWwgUlNBIDE5OTkuOS4xNgIDAphP -MAkGBSsOAwIaBQCggYowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG -9w0BCQUxDxcNMDAwNzE2MTQ0MzQ0WjAjBgkqhkiG9w0BCQQxFgQU2jmj7l5rSw0y -Vb/vlWAYkK/YBwkwKwYJKoZIhvcNAQkPMR4wHDAKBggqhkiG9w0DBzAOBggqhkiG -9w0DAgICAIAwDQYJKoZIhvcNAQEBBQAEgYBagl1y4nRwW+GLhZ5tElkh9Z/yFirz -ZXI0jMywML/ADxsAf1yV2JIYCCk0V33QdrYy8MVqgErGXxGdA5aKnm5545Wf4Noz -CLWF4FJc6RDSFp7dv2631TrswdFRRCHNds+dvP5v5EAiADvmEOYaDiWM07jp73jx -TkkzxW9cevZDaQAAAAA= ------END PKCS7----- diff --git a/demo/pkcs7/test.py b/demo/pkcs7/test.py deleted file mode 100644 index afa7477..0000000 --- a/demo/pkcs7/test.py +++ /dev/null @@ -1,6 +0,0 @@ -from M2Crypto import BIO, SMIME - -pf = BIO.openfile('pkcs7-thawte.pem') -p7 = SMIME.load_pkcs7_bio(pf) -print p7.type(1) - diff --git a/demo/rsa.priv.pem b/demo/rsa.priv.pem deleted file mode 100644 index ed34db6..0000000 --- a/demo/rsa.priv.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBANQNY7RD9BarYRsmMazM1hd7a+u3QeMPFZQ7Ic+BmmeWHvvVP4Yj -yu1t6vAut7mKkaDeKbT3yiGVUgAEUaWMXqECAwEAAQJAIHCz8h37N4ScZHThYJgt -oIYHKpZsg/oIyRaKw54GKxZq5f7YivcWoZ8j7IQ65lHVH3gmaqKOvqdAVVt5imKZ -KQIhAPPsr9i3FxU+Mac0pvQKhFVJUzAFfKiG3ulVUdHgAaw/AiEA3ozHKzfZWKxH -gs8v8ZQ/FnfI7DwYYhJC0YsXb6NSvR8CIHymwLo73mTxsogjBQqDcVrwLL3GoAyz -V6jf+/8HvXMbAiEAj1b3FVQEboOQD6WoyJ1mQO9n/xf50HjYhqRitOnp6ZsCIQDS -AvkvYKc6LG8IANmVv93g1dyKZvU/OQkAZepqHZB2MQ== ------END RSA PRIVATE KEY----- diff --git a/demo/rsa.priv0.pem b/demo/rsa.priv0.pem deleted file mode 100644 index e2b93a1..0000000 --- a/demo/rsa.priv0.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-CBC,244DDAFE6F991A53 - -h1/NnMxq2ku9UkBG2tfM7hCFWmOvwMbVQBYgS4jLm3ENvWRgkm7pCqjCug99Uo5o -r+NhzqyvSBH+eX3ojVAfpMxkL0TIjMrogRq2TD75v6hTGu/fd4Yrw7vZaKRbLzoh -rG6m7zdbiQwNyh0bTbbo3WmQ07FXkXrDqihLaZTJOvHNLS1lKwRjIS0MqtyhOfPj -NNwuNEs6AFz4k6UxNMRXhyU2SXn5SOgZZB12SCIsYA034rwKFKqNRoneaLSlhtut -1z/BlJaLiZDHJmtxtgz5h3Ss9fQ9J0pLnybx+EM70TPM3hz47/8cQiEYIVg7+QFW -jNYaGIA6IOcyB7fwX5e/zFy5yXAsmuIw/iP0sYa29hdUG++T8Mp2knrBBwQO77OS -WRz219dMQQRyyn2jpN5x23AZyz4gHj4YKMm3KO06Y2k= ------END RSA PRIVATE KEY----- - -This is the same key as rsa.priv.pem. Passphrase is 'qwerty'. - diff --git a/demo/rsa.pub.pem b/demo/rsa.pub.pem deleted file mode 100644 index 42379aa..0000000 --- a/demo/rsa.pub.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANQNY7RD9BarYRsmMazM1hd7a+u3QeMP -FZQ7Ic+BmmeWHvvVP4Yjyu1t6vAut7mKkaDeKbT3yiGVUgAEUaWMXqECAwEAAQ== ------END PUBLIC KEY----- diff --git a/demo/rsa1024pvtkey.pem b/demo/rsa1024pvtkey.pem deleted file mode 100644 index 481f191..0000000 --- a/demo/rsa1024pvtkey.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDE3rnXDvA4lrIUj7ZXQM2ODLw0NnjKXh7+O3GPttvoFoacK1qk -BRO+aO4hPhvQumySTz+N2RkIsT9PTx6yfyWWwYC1zbbv2cxlCBisGAvrUSL6IfHX -ND2/vVN+QmOd/b4hfC/ekRo2ylrnX0pOXv/JxiblV9WumiZsBEuhUvxCnQIDAQAB -AoGBALdaLEDkM8ywZQiLVCptO0RaDgqe1N68zCbBXCGaD7NXD2VxZ0itRdcnyOiC -/MroZWfakPleQVd8JNeLe66IhosAJd7Zbjf/npYnD4zD1x54zRrSuBquXhz+ev7U -tZONPxU5QCf/aow4z1s/M+knLyy+0lAUlWwTgOrd5VCQ8suBAkEA5/v48HZW8pQC -2zxQUFfsnRu6DxJuQ1UvWp51FNUYZM2LjpwgGyCNkCw+nuxPgM1HnOTAMVXkZdwL -7XG0Gm5ZoQJBANlAKKUc7ItOfN5TeD154Qz9FLtZUgWnWfawvEqiHJ0cPrzyv9v6 -wu19QxP6ORZBWyr8c20/p2fNrk+7YOZAH30CQQDZ9p1HEWlQMlEcu+aaFoJyewKt -9pszGG6NriRDlpR84cMmEvr3gfaAZ5HOsCli031dpHAP6qvWKJHsXtDhpJ0BAkBs -fANP4A+myLzF8Hx8hl4BNGej3kh9FkJwU3TS9/y935rck4OG/8NTAFf8o9jZ6izy -XDnvdffMeALxQapzj9WpAkBQt2yjU3V3bKkNl0XwTk/VK8WGEWTBF1byZv/6VZOb -q/vOPSexrQmu+T8+lljraJISfIpMSWZhR4oarmnGVRPX ------END RSA PRIVATE KEY----- diff --git a/demo/rsa_bench.py b/demo/rsa_bench.py deleted file mode 100644 index b0adacc..0000000 --- a/demo/rsa_bench.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python - -""" - RSA signing demo and benchmark. - - Usage: python -O rsa_bench.py [option option option ...] - where options may include: - makenewkey showdigest showprofile - md5 sha1 sha256 sha512 - - - Larry Bugbee - November 2006 - - - Some portions are Copyright (c) 1999-2003 Ng Pheng Siong. - All rights reserved. - - Portions created by Open Source Applications Foundation - (OSAF) are Copyright (C) 2004 OSAF. All Rights Reserved. - -""" - -from M2Crypto import RSA, EVP, Rand -from M2Crypto.EVP import MessageDigest -import sys, base64 - -# -------------------------------------------------------------- -# program parameters - -makenewkey = 0 # 1 = make/save new key, 0 = use existing -showpubkey = 0 # 1 = show the public key value -showdigest = 0 # 1 = show the digest value -showprofile = 0 # 1 = use the python profiler - -hashalgs = ['md5', 'ripemd160', 'sha1', - 'sha224', 'sha256', 'sha384', 'sha512'] - -# default hashing algorithm -hashalg = 'sha1' - -# default key parameters -keylen = 1024 -exponent = 65537 -''' - There is some temptation to use an RSA exponent of 3 - because 1) it is easy to remember and 2) it minimizes the - effort of signature verification. Unfortunately there - a couple of attacks based on the use of 3. From a draft - RFC (Easklake, Dec 2000): - A public exponent of 3 minimizes the effort needed to - verify a signature. Use of 3 as the public exponent is - weak for confidentiality uses since, if the same data - can be collected encrypted under three different keys - with an exponent of 3 then, using the Chinese Remainder - Theorem [NETSEC], the original plain text can be easily - recovered. - This applies to confidentiality so it is not of major - concern here. The second attack is a protocol implementation - weakness and can be patched, but has the patch been applied? - ...correctly? It is arguably better to get into the habit - of using a stronger exponent and avoiding these and possible - future attacks based on 3. I suggest getting in the habit - of using something stronger. Some suggest using 65537. -''' - -# number of speed test loops -N1 = N2 = 100 - -# -------------------------------------------------------------- -# functions - -def test(rsa, dgst): - print ' testing signing and verification...', - try: - sig = rsa.sign(dgst) - except Exception, e: - print '\n\n *** %s *** \n' % e - sys.exit() - if not rsa.verify(dgst, sig): - print 'not ok' - else: - print 'ok' - -def test_asn1(rsa, dgst): - print ' testing asn1 signing and verification...', - blob = rsa.sign_asn1(dgst) - if not rsa.verify_asn1(dgst, blob): - print 'not ok' - else: - print 'ok' - -def speed(): - from time import time - t1 = time() - for i in range(N1): - sig = rsa.sign(dgst) - print ' %d signings: %8.2fs' % (N1, (time() - t1)) - t1 = time() - for i in range(N2): - rsa.verify(dgst, sig) - print ' %d verifications: %8.2fs' % (N2, (time() - t1)) - -def test_speed(rsa, dgst): - print ' measuring speed...' - if showprofile: - import profile - profile.run('speed()') - else: - speed() - print - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def main(keylen, hashalg): - global rsa, dgst # this exists ONLY for speed testing - - Rand.load_file('randpool.dat', -1) - - pvtkeyfilename = 'rsa%dpvtkey.pem' % (keylen) - pubkeyfilename = 'rsa%dpubkey.pem' % (keylen) - - if makenewkey: - print ' making and saving a new key' - rsa = RSA.gen_key(keylen, exponent) - rsa.save_key(pvtkeyfilename, None ) # no pswd callback - rsa.save_pub_key(pubkeyfilename) - else: - print ' loading an existing key' - rsa = RSA.load_key(pvtkeyfilename) - print ' rsa key length:', len(rsa) - - if not rsa.check_key(): - raise 'key is not initialised' - - # since we are testing signing and verification, let's not - # be fussy about the digest. Just make one. - md = EVP.MessageDigest(hashalg) - md.update('can you spell subliminal channel?') - dgst = md.digest() - print ' hash algorithm: %s' % hashalg - if showdigest: - print ' %s digest: \n%s' % (hashalg, base64.encodestring(dgst)) - - test(rsa, dgst) -# test_asn1(rsa, dgst) - test_speed(rsa, dgst) - Rand.save_file('randpool.dat') - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def print_usage(): - print """ - Usage: python -O %s [option option option ...] - where options may include: - makenewkey showdigest showprofile - md5 sha1 sha256 sha512 - -""" % sys.argv[0] - sys.exit() - -# -------------------------------------------------------------- -# -------------------------------------------------------------- - -if __name__=='__main__': - for arg in sys.argv[1:]: - if arg in hashalgs: hashalg = arg; continue - if arg == 'makenewkey': makenewkey = 1; continue - if arg == 'showpubkey': showpubkey = 1; continue - if arg == 'showdigest': showdigest = 1; continue - if arg == 'showprofile': showprofile = 1; continue - try: - keylen = int(arg) - except: - print '\n *** argument "%s" not understood ***' % arg - print_usage() - - main(keylen, hashalg) - - -# -------------------------------------------------------------- -# -------------------------------------------------------------- -# -------------------------------------------------------------- diff --git a/demo/rsatest.py b/demo/rsatest.py deleted file mode 100644 index 4277c4d..0000000 --- a/demo/rsatest.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python - -"""RSA demonstration. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import RSA, EVP, Rand - -msg="The magic words are squeamish ossifrage." -sha1=EVP.MessageDigest('sha1') -sha1.update(msg) -dgst=sha1.digest() - -priv=RSA.load_key('rsa.priv.pem') -pub=RSA.load_pub_key('rsa.pub.pem') - -def test_encrypt(padding): - print 'testing public-key encryption:', padding - padding=eval('RSA.'+padding) - ctxt=pub.public_encrypt(dgst, padding) - ptxt=priv.private_decrypt(ctxt, padding) - if ptxt!=dgst: - print 'public_encrypt -> private_decrypt: not ok' - -def test_sign(padding): - print 'testing private-key signing:', padding - padding=eval('RSA.'+padding) - ctxt=priv.private_encrypt(dgst, padding) - ptxt=pub.public_decrypt(ctxt, padding) - if ptxt!=dgst: - print 'private_decrypt -> public_encrypt: not ok' - -def test0(): - print 'testing misc.' - print `pub.e`, `pub.n` - print `priv.e`, `priv.n` - -if __name__=='__main__': - Rand.load_file('randpool.dat', -1) - test_encrypt('pkcs1_padding') - test_encrypt('pkcs1_oaep_padding') - #test_encrypt('sslv23_padding') - test_sign('pkcs1_padding') - Rand.save_file('randpool.dat') - diff --git a/demo/smime.howto/README b/demo/smime.howto/README deleted file mode 100644 index 2b494d7..0000000 --- a/demo/smime.howto/README +++ /dev/null @@ -1,5 +0,0 @@ - 01 Apr 2001 -------------- - -These are the example programs from the HOWTO. - diff --git a/demo/smime.howto/decrypt.py b/demo/smime.howto/decrypt.py deleted file mode 100644 index 617f4ab..0000000 --- a/demo/smime.howto/decrypt.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME HOWTO demo program. - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import BIO, SMIME, X509 - -# Instantiate an SMIME object. -s = SMIME.SMIME() - -# Load private key and cert. -s.load_key('recipient_key.pem', 'recipient.pem') - -# Load the encrypted data. -p7, data = SMIME.smime_load_pkcs7('encrypt.p7') - -# Decrypt p7. -out = s.decrypt(p7) - -print out - diff --git a/demo/smime.howto/dv.py b/demo/smime.howto/dv.py deleted file mode 100644 index 94223a8..0000000 --- a/demo/smime.howto/dv.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME HOWTO demo program. - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import BIO, SMIME, X509 - -# Instantiate an SMIME object. -s = SMIME.SMIME() - -# Load private key and cert. -s.load_key('recipient_key.pem', 'recipient.pem') - -# Load the signed/encrypted data. -p7, data = SMIME.smime_load_pkcs7('se.p7') - -# After the above step, 'data' == None. -# Decrypt p7. 'out' now contains a PKCS #7 signed blob. -out = s.decrypt(p7) - -# Load the signer's cert. -x509 = X509.load_cert('signer.pem') -sk = X509.X509_Stack() -sk.push(x509) -s.set_x509_stack(sk) - -# Load the signer's CA cert. In this case, because the signer's -# cert is self-signed, it is the signer's cert itself. -st = X509.X509_Store() -st.load_info('signer.pem') -s.set_x509_store(st) - -# Recall 'out' contains a PKCS #7 blob. -# Transform 'out'; verify the resulting PKCS #7 blob. -p7_bio = BIO.MemoryBuffer(out) -p7, data = SMIME.smime_load_pkcs7_bio(p7_bio) -v = s.verify(p7) - -print v - diff --git a/demo/smime.howto/encrypt.p7 b/demo/smime.howto/encrypt.p7 deleted file mode 100644 index eb8b8a5..0000000 --- a/demo/smime.howto/encrypt.p7 +++ /dev/null @@ -1,17 +0,0 @@ -From: sender@example.dom -To: recipient@example.dom -MIME-Version: 1.0 -Content-Disposition: attachment; filename="smime.p7m" -Content-Type: application/x-pkcs7-mime; name="smime.p7m" -Content-Transfer-Encoding: base64 - -MIIBVwYJKoZIhvcNAQcDoIIBSDCCAUQCAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE -BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp -ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ -KoZIhvcNAQEBBQAEgYCdBULuQ/kfjgk17dMwBHdY+vXfqR/B+vJnF0gXhK6gc5d4 -gCkRefEyVu7lGAD2MOdD0cOLFvHdmGHFJqyJ8T+A1mmqrxMAiJImtqN586YnoTUb -Cw5FaMEd20d6hpGeEVBFHkam0vQKdR1GLG1VPiFn+ytB06g7NNphsI5/uFGyLDA7 -BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECPfuW3hoPVr0gBiA4CiFG4m74CT4wHPu -q1fhEkG3zjraxn4= - - diff --git a/demo/smime.howto/encrypt.py b/demo/smime.howto/encrypt.py deleted file mode 100644 index ae37526..0000000 --- a/demo/smime.howto/encrypt.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME HOWTO demo program. - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import BIO, Rand, SMIME, X509 - -def makebuf(text): - return BIO.MemoryBuffer(text) - -# Make a MemoryBuffer of the message. -buf = makebuf('a sign of our times') - -# Seed the PRNG. -Rand.load_file('randpool.dat', -1) - -# Instantiate an SMIME object. -s = SMIME.SMIME() - -# Load target cert to encrypt to. -x509 = X509.load_cert('recipient.pem') -sk = X509.X509_Stack() -sk.push(x509) -s.set_x509_stack(sk) - -# Set cipher: 3-key triple-DES in CBC mode. -s.set_cipher(SMIME.Cipher('des_ede3_cbc')) - -# Encrypt the buffer. -p7 = s.encrypt(buf) - -# Output p7 in mail-friendly format. -out = BIO.MemoryBuffer() -out.write('From: sender@example.dom\n') -out.write('To: recipient@example.dom\n') -out.write('Subject: M2Crypto S/MIME testing\n') -s.write(out, p7) - -print out.read() - -# Save the PRNG's state. -Rand.save_file('randpool.dat') - diff --git a/demo/smime.howto/recipient.pem b/demo/smime.howto/recipient.pem deleted file mode 100644 index 78b6c14..0000000 --- a/demo/smime.howto/recipient.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC9zCCAmCgAwIBAgIBADANBgkqhkiG9w0BAQQFADBhMQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xGTAXBgNVBAMTEFMvTUlNRSBSZWNpcGllbnQxJDAi -BgkqhkiG9w0BCQEWFXJlY2lwaWVudEBleGFtcGxlLmRvbTAeFw0wMTAzMzExMTQy -MTVaFw0wMjAzMzExMTQyMTVaMGExCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNy -eXB0bzEZMBcGA1UEAxMQUy9NSU1FIFJlY2lwaWVudDEkMCIGCSqGSIb3DQEJARYV -cmVjaXBpZW50QGV4YW1wbGUuZG9tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDQwLwQSshbTn/GUZXnZUQEUDc61OUd+qcPpHfi76Y7ar+2NwsalQ3bu2i7edEK -IZZWMFRnrOwE9PhmJHJIzfYDswgpHWtRy0P/Oyzt5kLBjvJYuMIqu8gZtWFz0G28 -Q8tGvIuPdWba+9TT3LOv4CXNF1V0k0KgAPd1Uq2FUcBa2QIDAQABo4G+MIG7MB0G -A1UdDgQWBBQe7b4CDEBuMJyiscil27YBdZBr9zCBiwYDVR0jBIGDMIGAgBQe7b4C -DEBuMJyiscil27YBdZBr96FlpGMwYTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0y -Q3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBpZW50MSQwIgYJKoZIhvcNAQkB -FhVyZWNpcGllbnRAZXhhbXBsZS5kb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG -9w0BAQQFAAOBgQAJbQXzP7AK9u2kyvl8oeZAeJQDRsip4PVMkYd64HW3Hq/9ud3g -hj/laeUyfcga+c1c1yPUug5Ab+loeHhEEKsL9LqYFXzpFU1lXaID02zcqG7g3PWe -r9RKsUqrn4ZbRQ+clidnIx4nYLuG6CPQ6ME/uFrYHMsmQEO/+KoJONf/cg== ------END CERTIFICATE----- diff --git a/demo/smime.howto/recipient_key.pem b/demo/smime.howto/recipient_key.pem deleted file mode 100644 index 0cb61f6..0000000 --- a/demo/smime.howto/recipient_key.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDQwLwQSshbTn/GUZXnZUQEUDc61OUd+qcPpHfi76Y7ar+2Nwsa -lQ3bu2i7edEKIZZWMFRnrOwE9PhmJHJIzfYDswgpHWtRy0P/Oyzt5kLBjvJYuMIq -u8gZtWFz0G28Q8tGvIuPdWba+9TT3LOv4CXNF1V0k0KgAPd1Uq2FUcBa2QIDAQAB -AoGAVOMrFozycH65YtHmXVRGlmJwMxJDoS8+JBRDVBsTw/Gix9wWPdcC7amF60ac -BLynv6Cjkg01ZMahBBgqCQUH1rii6Kg20MJJtpqvt1X+CAZkytVsQqwutSQXHj+g -TzZVDxQiuPKMyVhKTSVqutqs2EyFgSKcYuodfms5xDk2EyECQQD6vnEAl2PHBoia -5wrauujbWTM6H5oioWvJgLaUNgUhJ86/Y+ewKoGxLdYaxx99KhKxN/04i2chIHk0 -c53THOt9AkEA1SD1Rdm93FUMEor+BYEQgiN/4pWnSIsgUjyqV7lPv9QegdDTbVfm -WuPNev6Z+qo9mpDWbvhCZhH159q7uGfzjQJAe88dLRWThuqK+TGsAmTYJbbdvI1u -JjteZZjQjk4+KijlxUsnU60pbLsdRQudWMg1gpwKxKjQu2K1dljATUWyYQJARI83 -l2K1+py5J3XixS6BevukdeUiTOnEWe/98/4+szyvG59rg+8UwQQq43fnXIVLD9+r -u0LNSTxZ2F26qVV3OQJBAIBG0Gv9C44UlCPiJhmMqcpzexX20erOEGu+UiCUhHAC -ZdWdFaD2dlmk0O/E82LxPPivkGv5DtkNpzCl+3Vo+kI= ------END RSA PRIVATE KEY----- diff --git a/demo/smime.howto/se.p7 b/demo/smime.howto/se.p7 deleted file mode 100644 index df4af0f..0000000 --- a/demo/smime.howto/se.p7 +++ /dev/null @@ -1,56 +0,0 @@ -From: sender@example.dom -To: recipient@example.dom -MIME-Version: 1.0 -Content-Disposition: attachment; filename="smime.p7m" -Content-Type: application/x-pkcs7-mime; name="smime.p7m" -Content-Transfer-Encoding: base64 - -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 - - diff --git a/demo/smime.howto/se.py b/demo/smime.howto/se.py deleted file mode 100644 index cd4df60..0000000 --- a/demo/smime.howto/se.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME HOWTO demo program. - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import BIO, Rand, SMIME, X509 - -def makebuf(text): - return BIO.MemoryBuffer(text) - -# Make a MemoryBuffer of the message. -buf = makebuf('a sign of our times') - -# Seed the PRNG. -Rand.load_file('randpool.dat', -1) - -# Instantiate an SMIME object. -s = SMIME.SMIME() - -# Load signer's key and cert. Sign the buffer. -s.load_key('signer_key.pem', 'signer.pem') -p7 = s.sign(buf) - -# Load target cert to encrypt the signed message to. -x509 = X509.load_cert('recipient.pem') -sk = X509.X509_Stack() -sk.push(x509) -s.set_x509_stack(sk) - -# Set cipher: 3-key triple-DES in CBC mode. -s.set_cipher(SMIME.Cipher('des_ede3_cbc')) - -# Create a temporary buffer. -tmp = BIO.MemoryBuffer() - -# Write the signed message into the temporary buffer. -s.write(tmp, p7) - -# Encrypt the temporary buffer. -p7 = s.encrypt(tmp) - -# Output p7 in mail-friendly format. -out = BIO.MemoryBuffer() -out.write('From: sender@example.dom\n') -out.write('To: recipient@example.dom\n') -out.write('Subject: M2Crypto S/MIME testing\n') -s.write(out, p7) - -print out.read() - -# Save the PRNG's state. -Rand.save_file('randpool.dat') - diff --git a/demo/smime.howto/sendsmime.py b/demo/smime.howto/sendsmime.py deleted file mode 100644 index 6df9a89..0000000 --- a/demo/smime.howto/sendsmime.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME sender. - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import BIO, Rand, SMIME, X509 -import smtplib, string, sys - -def sendsmime(from_addr, to_addrs, subject, msg, from_key, from_cert=None, to_certs=None, smtpd='localhost'): - - msg_bio = BIO.MemoryBuffer(msg) - sign = from_key - encrypt = to_certs - - s = SMIME.SMIME() - if sign: - s.load_key(from_key, from_cert) - p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT) - msg_bio = BIO.MemoryBuffer(msg) # Recreate coz sign() has consumed it. - - if encrypt: - sk = X509.X509_Stack() - for x in to_certs: - sk.push(X509.load_cert(x)) - s.set_x509_stack(sk) - s.set_cipher(SMIME.Cipher('rc2_40_cbc')) - tmp_bio = BIO.MemoryBuffer() - if sign: - s.write(tmp_bio, p7) - else: - tmp_bio.write(msg) - p7 = s.encrypt(tmp_bio) - - out = BIO.MemoryBuffer() - out.write('From: %s\r\n' % from_addr) - out.write('To: %s\r\n' % string.join(to_addrs, ", ")) - out.write('Subject: %s\r\n' % subject) - if encrypt: - s.write(out, p7) - else: - if sign: - s.write(out, p7, msg_bio, SMIME.PKCS7_TEXT) - else: - out.write('\r\n') - out.write(msg) - out.close() - - smtp = smtplib.SMTP() - smtp.connect(smtpd) - smtp.sendmail(from_addr, to_addrs, out.read()) - smtp.quit() - - # XXX Cleanup the stack and store. - - -msg = """ -S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC 2312] - -provides a consistent way to send and receive secure MIME data. Based on the -popular Internet MIME standard, S/MIME provides the following cryptographic -security services for electronic messaging applications - authentication, -message integrity and non-repudiation of origin (using digital signatures) -and privacy and data security (using encryption). - -S/MIME is built on the PKCS #7 standard. [PKCS7] - -S/MIME is implemented in Netscape Messenger and Microsoft Outlook. -""" - - -if __name__ == '__main__': - Rand.load_file('../randpool.dat', -1) - sendsmime(from_addr = 'ngps@post1.com', - to_addrs = ['popuser@nova.dyndns.org'], - subject = 'S/MIME testing', - msg = msg, - #from_key = 'signer.pem', - from_key = None, - #to_certs = None) - to_certs = ['recipient.pem']) - Rand.save_file('../randpool.dat') - diff --git a/demo/smime.howto/sign.p7 b/demo/smime.howto/sign.p7 deleted file mode 100644 index 7a39eaa..0000000 --- a/demo/smime.howto/sign.p7 +++ /dev/null @@ -1,46 +0,0 @@ -From: sender@example.dom -To: recipient@example.dom -Subject: M2Crypto S/MIME testing -MIME-Version: 1.0 -Content-Type: multipart/signed ; protocol="application/x-pkcs7-signature" ; micalg=sha1 ; boundary="----2221986D060512556B8AC18AAA106F39" - -This is an S/MIME signed message - -------2221986D060512556B8AC18AAA106F39 -a sign of our times -------2221986D060512556B8AC18AAA106F39 -Content-Type: application/x-pkcs7-signature; name="smime.p7s" -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename="smime.p7s" - -MIIE8AYJKoZIhvcNAQcCoIIE4TCCBN0CAQExCzAJBgUrDgMCGgUAMCIGCSqGSIb3 -DQEHAaAVBBNhIHNpZ24gb2Ygb3VyIHRpbWVzoIIC5zCCAuMwggJMoAMCAQICAQAw -DQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv -MRYwFAYDVQQDEw1TL01JTUUgU2VuZGVyMSEwHwYJKoZIhvcNAQkBFhJzZW5kZXJA -ZXhhbXBsZS5kb20wHhcNMDEwMzMxMTE0MDMzWhcNMDIwMzMxMTE0MDMzWjBbMQsw -CQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBT -ZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEA5c5Tj1CHTSOxa1q2q0FYiwMWYHptJpJcvtZm -UwrgU5sHrA8OnCM0cDXEj0KPf3cfNjHffB8HWMzI4UEgNmFXQNsxoGZ+iqwxLlNj -y9Mh7eFW/Bjq5hNXbouSlQ0rWBRkoxV64y+t6lQehb32WfYXQbKFxFJSXzSxOx3R -8YhSPd0CAwEAAaOBtjCBszAdBgNVHQ4EFgQUXOyolL1t4jaBwZFRM7MS8nBLzUow -gYMGA1UdIwR8MHqAFFzsqJS9beI2gcGRUTOzEvJwS81KoV+kXTBbMQswCQYDVQQG -EwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIx -ITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbYIBADAMBgNVHRMEBTAD -AQH/MA0GCSqGSIb3DQEBBAUAA4GBAHo3DrCHR86fSTVAvfiXdSswWqKtCEhUHRdC -TLFGl4hDk2GyZxaFuqZwiURz/H7nMicymI2wkz8H/wyHFg8G3BIehURpj2v/ZWXY -eovbgS7EZALVVkDj4hNl/IIHWd6Gtv1UODf7URbxtl3hQ9/eTWITrefT1heuPnar -8czydsOLMYIBujCCAbYCAQEwYDBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJD -cnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNl -bmRlckBleGFtcGxlLmRvbQIBADAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzEL -BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAxMDMzMTE0NTgyMVowIwYJKoZI -hvcNAQkEMRYEFOoeRUd8ExIYXfQq8BTFuKWrSP3iMFIGCSqGSIb3DQEJDzFFMEMw -CgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO -AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIGAKMjEdSteeZg9ji1C -Y2r6zuxDVVftpSLy9ZhYOblGYY2b3PhzI0XytdUoLdb+GlPImqE/F5FJCPvTAovq -uLElbx/FuijA2ly7PQF2ekyFJ0EhvNWT1gcLhi1m0W+Hk/jgCQx7YRojT53Pa9fj -zuHk7ZkSKe5rZlOJvPJtYREnvD8= - -------2221986D060512556B8AC18AAA106F39-- - - diff --git a/demo/smime.howto/sign.py b/demo/smime.howto/sign.py deleted file mode 100644 index 38c4bab..0000000 --- a/demo/smime.howto/sign.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME HOWTO demo program. - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import BIO, Rand, SMIME - -def makebuf(text): - return BIO.MemoryBuffer(text) - -# Make a MemoryBuffer of the message. -buf = makebuf('a sign of our times') - -# Seed the PRNG. -Rand.load_file('randpool.dat', -1) - -# Instantiate an SMIME object; set it up; sign the buffer. -s = SMIME.SMIME() -s.load_key('signer_key.pem', 'signer.pem') -p7 = s.sign(buf) - -# Recreate buf. -buf = makebuf('a sign of our times') - -# Output p7 in mail-friendly format. -out = BIO.MemoryBuffer() -out.write('From: sender@example.dom\n') -out.write('To: recipient@example.dom\n') -out.write('Subject: M2Crypto S/MIME testing\n') -s.write(out, p7, buf) - -print out.read() - -# Save the PRNG's state. -Rand.save_file('randpool.dat') - diff --git a/demo/smime.howto/signer.pem b/demo/smime.howto/signer.pem deleted file mode 100644 index 9189aaa..0000000 --- a/demo/smime.howto/signer.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC4zCCAkygAwIBAgIBADANBgkqhkiG9w0BAQQFADBbMQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkq -hkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTAeFw0wMTAzMzExMTQwMzNaFw0w -MjAzMzExMTQwMzNaMFsxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEW -MBQGA1UEAxMNUy9NSU1FIFNlbmRlcjEhMB8GCSqGSIb3DQEJARYSc2VuZGVyQGV4 -YW1wbGUuZG9tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlzlOPUIdNI7Fr -WrarQViLAxZgem0mkly+1mZTCuBTmwesDw6cIzRwNcSPQo9/dx82Md98HwdYzMjh -QSA2YVdA2zGgZn6KrDEuU2PL0yHt4Vb8GOrmE1dui5KVDStYFGSjFXrjL63qVB6F -vfZZ9hdBsoXEUlJfNLE7HdHxiFI93QIDAQABo4G2MIGzMB0GA1UdDgQWBBRc7KiU -vW3iNoHBkVEzsxLycEvNSjCBgwYDVR0jBHwweoAUXOyolL1t4jaBwZFRM7MS8nBL -zUqhX6RdMFsxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEWMBQGA1UE -AxMNUy9NSU1FIFNlbmRlcjEhMB8GCSqGSIb3DQEJARYSc2VuZGVyQGV4YW1wbGUu -ZG9tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAejcOsIdHzp9J -NUC9+Jd1KzBaoq0ISFQdF0JMsUaXiEOTYbJnFoW6pnCJRHP8fucyJzKYjbCTPwf/ -DIcWDwbcEh6FRGmPa/9lZdh6i9uBLsRkAtVWQOPiE2X8ggdZ3oa2/VQ4N/tRFvG2 -XeFD395NYhOt59PWF64+dqvxzPJ2w4s= ------END CERTIFICATE----- diff --git a/demo/smime.howto/signer_key.pem b/demo/smime.howto/signer_key.pem deleted file mode 100644 index ad15a87..0000000 --- a/demo/smime.howto/signer_key.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDlzlOPUIdNI7FrWrarQViLAxZgem0mkly+1mZTCuBTmwesDw6c -IzRwNcSPQo9/dx82Md98HwdYzMjhQSA2YVdA2zGgZn6KrDEuU2PL0yHt4Vb8GOrm -E1dui5KVDStYFGSjFXrjL63qVB6FvfZZ9hdBsoXEUlJfNLE7HdHxiFI93QIDAQAB -AoGBALqc4OgZSbYPjQyTfpD1IJTKLgqsgCR5aE0kR7WZuG7MDt/e3ktWn0ebsgFv -2J12u2bD+yqM++dVbK7WtvTR+QpMhb/0XMhXNsvmn5gOLdKlJjS0RXDDs2DzIS6p -JNzAmn5zqTVteZAMDLk7ygkO++iGzwRz713ZgxRaKr5YWiLVAkEA+3ev1TTXNEOk -wQ9fbukMrfUXesqwgrx9VZ1z1X5we42RIIMTYI1edpcujXYvgS3/jdzAWDS1Nqta -9QB3uy91ywJBAOnysIIQhHn+4zvaOA5vh85WczPhN9C+yRmV70eyL9h+aThUFS4c -kg2jQOLp8MaxAkmk4xRbZBgehjmDr45b5fcCQQDpIGNlYFBmhpN129+YffugRgjX -cJNFEKONPKRHd6mmEW9K2dmb+FNr0+p3gOq3csJpbQ7wdyTMov13B1D4ux4TAkAR -URB1oCleKlrBjGaH0wOXZ1jBp1MNVYHnLez3Pp5CBSFetQKYVi8NaV8dLLnQyztj -Hhxc3mLrUh8XVMMC45SDAkEAxRCKmkneLceIdwixLIUF0zr0OzJtgyhxMxvHu3ET -gJcZqNN0y3EgPwcNihpBw7rjpp5e5sjlRNVqLqn8a5/Fog== ------END RSA PRIVATE KEY----- diff --git a/demo/smime.howto/verify.py b/demo/smime.howto/verify.py deleted file mode 100644 index 9430add..0000000 --- a/demo/smime.howto/verify.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME HOWTO demo program. - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import SMIME, X509 - -# Instantiate an SMIME object. -s = SMIME.SMIME() - -# Load the signer's cert. -x509 = X509.load_cert('signer.pem') -sk = X509.X509_Stack() -sk.push(x509) -s.set_x509_stack(sk) - -# Load the signer's CA cert. In this case, because the signer's -# cert is self-signed, it is the signer's cert itself. -st = X509.X509_Store() -st.load_info('signer.pem') -s.set_x509_store(st) - -# Load the data, verify it. -p7, data = SMIME.smime_load_pkcs7('sign.p7') -v = s.verify(p7) -print v -print data -print data.read() - diff --git a/demo/smime/README b/demo/smime/README deleted file mode 100644 index 736e632..0000000 --- a/demo/smime/README +++ /dev/null @@ -1,54 +0,0 @@ - 29 Nov 2000 -------------- -- test.py works. - -- makesmime.py is sendsmime.py modified to not send - SMTP, because I do not now have an SMTP server handy. - -- sendsmime.py should still work, because makesmime.py - does. - -- unsmime.py doesn't work, possibly because the certificates - used to generate the tested PKCS7 objects are no longer - available. - - - - 20 Nov 2000 -------------- - -This directory contains various programs and supporting files -demonstrating M2Crypto's S/MIME functionality. - -- test.py exercises the various S/MIME functionality. -- sendsmime.py (optionally) signs and/or encrypts a message, - then sends the output via SMTP. -- makesmime.py is exactly like sendsmime.py, except it writes - its output to sys.stdout. -- unsmime.py decrypts and verifies an S/MIME SignedAndEnveloped - message. It handles the S/MIME output of Netscape Messenger - successfully. - -- ca.pem is M2Crypto's test CA certificate. -- client.pem and client2.pem contain user certificates and their - corresponding private keys. - -- clear.p7 is a clear-signed S/MIME message. -- opaque.p7 is a signed S/MIME message. -- ns.p7 is a clear-signed S/MIME message produced by Messenger. -- ns.se.p7 is a signed-then-encrypted S/MIME message produced - by Messenger. -- m2.se.p7 is a signed-then-encrypted S/MIME message produced - by sendsmime.py. - - -I tested with export and strong versions of Netscape Communicator -4.7x. - -I have also done some interoperability testing with Sampo Kellomaki's -smime tool. - -I am interested in interoperability testing with Outlook and other -S/MIME tools. Write me if you want to collaborate. - - diff --git a/demo/smime/ca.pem b/demo/smime/ca.pem deleted file mode 100644 index b7c84a1..0000000 --- a/demo/smime/ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 -NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML -TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl -cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK -q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N -e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf -q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G -A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV -BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex -JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 -DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG -SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ -dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J -vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf ------END CERTIFICATE----- diff --git a/demo/smime/clear.p7 b/demo/smime/clear.p7 deleted file mode 100644 index c878407..0000000 --- a/demo/smime/clear.p7 +++ /dev/null @@ -1,67 +0,0 @@ -To: ngps@post1.com -From: ngps@post1.com -Subject: testing -MIME-Version: 1.0 -Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg=sha1; boundary="----F0DD27AD8CDFF9AB55B87EE3A626E6D7" - -This is an S/MIME signed message - -------F0DD27AD8CDFF9AB55B87EE3A626E6D7 - -S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC 2312] - -provides a consistent way to send and receive secure MIME data. Based on the -popular Internet MIME standard, S/MIME provides the following cryptographic -security services for electronic messaging applications - authentication, -message integrity and non-repudiation of origin (using digital signatures) -and privacy and data security (using encryption). - -S/MIME is built on the PKCS #7 standard. [PKCS7] - -S/MIME is implemented in Netscape Messenger and Microsoft Outlook. - -------F0DD27AD8CDFF9AB55B87EE3A626E6D7 -Content-Type: application/x-pkcs7-signature; name="smime.p7s" -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename="smime.p7s" - -MIIHHAYJKoZIhvcNAQcCoIIHDTCCBwkCAQExCzAJBgUrDgMCGgUAMIICQwYJKoZI -hvcNAQcBoIICNASCAjANClMvTUlNRSAtIFNlY3VyZSBNdWx0aXB1cnBvc2UgSW50 -ZXJuZXQgTWFpbCBFeHRlbnNpb25zIFtSRkMgMjMxMSwgUkZDIDIzMTJdIC0gDQpw -cm92aWRlcyBhIGNvbnNpc3RlbnQgd2F5IHRvIHNlbmQgYW5kIHJlY2VpdmUgc2Vj -dXJlIE1JTUUgZGF0YS4gQmFzZWQgb24gdGhlDQpwb3B1bGFyIEludGVybmV0IE1J -TUUgc3RhbmRhcmQsIFMvTUlNRSBwcm92aWRlcyB0aGUgZm9sbG93aW5nIGNyeXB0 -b2dyYXBoaWMNCnNlY3VyaXR5IHNlcnZpY2VzIGZvciBlbGVjdHJvbmljIG1lc3Nh -Z2luZyBhcHBsaWNhdGlvbnMgLSBhdXRoZW50aWNhdGlvbiwNCm1lc3NhZ2UgaW50 -ZWdyaXR5IGFuZCBub24tcmVwdWRpYXRpb24gb2Ygb3JpZ2luICh1c2luZyBkaWdp -dGFsIHNpZ25hdHVyZXMpDQphbmQgcHJpdmFjeSBhbmQgZGF0YSBzZWN1cml0eSAo -dXNpbmcgZW5jcnlwdGlvbikuDQoNClMvTUlNRSBpcyBidWlsdCBvbiB0aGUgUEtD -UyAjNyBzdGFuZGFyZC4gW1BLQ1M3XQ0KDQpTL01JTUUgaXMgaW1wbGVtZW50ZWQg -aW4gTmV0c2NhcGUgTWVzc2VuZ2VyIGFuZCBNaWNyb3NvZnQgT3V0bG9vay4NCqCC -AxAwggMMMIICdaADAgECAgECMA0GCSqGSIb3DQEBBAUAMHsxCzAJBgNVBAYTAlNH -MREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0ExJDAiBgNV -BAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEdMBsGCSqGSIb3DQEJARYO -bmdwc0Bwb3N0MS5jb20wHhcNMDAwOTEwMDk1ODIwWhcNMDIwOTEwMDk1ODIwWjBZ -MQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xGDAWBgNVBAMTD00yQ3J5 -cHRvIENsaWVudDEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20wXDANBgkq -hkiG9w0BAQEFAANLADBIAkEAoz3zUF0dmxSU+1fso+eTdmjDY71gWNeXWX28qsBJ -0UFmq4JCtw7Gv4fJ0TZgQHVIrXgKrUvzsquu8eiVjuP/NwIDAQABo4IBBDCCAQAw -CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy -dGlmaWNhdGUwHQYDVR0OBBYEFMcQhEeJ1x9d+8Rzag9yjCiutYKOMIGlBgNVHSME -gZ0wgZqAFPuHI2nrnDqTFeXFvylRT/7tKDgBoX+kfTB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBAKy2cWa2BF6cbBPE4ici -//wOqkLDbsI3YZyUSj7ZPnefghx9EwRJfLB3/sXEf78OHL7yV6IMrvEVEAJCYs+3 -w/lspCMJC0hOomxnt0vjyCCd0JeaEwihQGbOo9V0reXzrUy8yNkwo1w8mMSbIvqh -+D5uTB0jKL/ml1EVLw3NJf68MYIBmjCCAZYCAQEwgYAwezELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5u -Z3BzQHBvc3QxLmNvbQIBAjAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzELBgkq -hkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAyMTIwODE3NTIyMVowIwYJKoZIhvcN -AQkEMRYEFI/KcwJXhIg0bRzYLfAtDhxRMzghMFIGCSqGSIb3DQEJDzFFMEMwCgYI -KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH -MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABEBrhZ8JVqGZ+S7dh+xKDwbF -yRXiOQWEa2uxD1O5fD02VfGEzDSrV1sPdQ8AcM3o+ny5AyC11E4Fns2cIkXwZEwz - -------F0DD27AD8CDFF9AB55B87EE3A626E6D7-- - diff --git a/demo/smime/client.p12 b/demo/smime/client.p12 deleted file mode 100644 index b7b985a5801359fd42baace2b52bea774106252b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1604 zcmY+Dc{tPw7{`Be{br01k7E*(vWgu0LlmV@gqoNcM;47^WXM$^a^+X193_*phG|WX z$dy^gu*9IlWRprEk=)TpH6&~GJiFWOAMf)%@Avz@??2z?1Hqs<5`ltX5CkQ*Gi{h+ zDFhaA6UK1X*BM0-utsX zQ3oI-5(k`vQ8~tE6C)cC)!_~Lfrp0N%8pYr-i7#D1?{%_xN%85LKDA|xX7Yhln8jP zfc>cOwXh-+iBUSQ&C+<_k|3hJsQM(F`{ig@waj6DU&y}V+=cSH%{Y}{#X{>Y11YD8 zGIq`cG0w=WKlh2&#yY5jH2+k*)-yBZUdEQ2?#jINKF zoOD_I z$6gCdh&f^1Uk9g0J}tK-{;CDU?z6@fq#&jRL094ZaBFHA3oTog6sDxHgStOok6e z%+`KN(gW4KY^GYy@Yp0XsT1^K!{%&3DT)$tXa9BD+xC#QI+n_48U}uzJmuJ!<2d%s z+u=8rB$k%rRH~1CK4(bsu^_fqvV62d{k26Z3QLE^G|0k-1#(y zqz>lNz>&e}w%5&yxet$JY|c?N|Go2O8=9}t`Xw|=%XtU!s?IGBV{i7^t@UGR?Dfh4 z;P@)6p|59BA(f0*agP)+k=-s$0}ZdX&SGhMdNnDVpzmZfSbFm$t`K>o~TKX^d~TN@%`c zwqnvWETT?B!TqkCS~O$Z%`HR?kXgMadE!F>`AdIO-xXq!6WI4?-YSJ^Q*^Z1p_4ob zSmVpWY=P_P2d)Xh7coNdW6Xw{@q%2TdnCO`kY&|C*vJjo6+s}CHaZ7y8KlX(&jlRy za0o9{>v8C3gl|hZ*cfl=S1wHwWdNPU_L=ew@T9b*&^bT9*py1rG04ae%+ z^kvoQ(H}eEB&L(FF`dmj3&GnSGI9!HcBT--HoM zXc+Msf)Vp;H494qgEbz3Tr-(#BK$wvQQv82oF2@!S43U@PW#%q=SjikmVC~l0@K^l zvuliEXOI|OGTf^eNEQ~K$hym0Jy{oVC+no?0e5RXIvE$?nIk!kQGI9NxT~aA;h=Z+ z*3cL{rOqzFJxV1}kr>!0&Px`~@0fC93>6j|Rn~|8T<#;gCEIbQ*hM?D)gC8y#JA1^ zc#hRGNqI_7Nu><7_PXIm<*UVq{6!5huhJ=};z$v#h=Zyx+a|yRc4Wx z%>GZ}q+jf3ste)!;+n6NE z=sx``x5hBwyi-!*Fk!swz(QPvc=(m@Vh=M``T2>=_&6Ei*32tgld5=RvE;&Q0;3o zUh%1erEhlJ56(?er7YdzOFO2SuX4c!!iBIFeMd0=sy|F96{rF(I)#%?-(5W9`;|_A=$D3 diff --git a/demo/smime/client.pem b/demo/smime/client.pem deleted file mode 100644 index 0eeeefb..0000000 --- a/demo/smime/client.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDDDCCAnWgAwIBAgIBAjANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tMB4XDTAwMDkxMDA5NTgyMFoXDTAyMDkxMDA5NTgyMFowWTEL -MAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRgwFgYDVQQDEw9NMkNyeXB0 -byBDbGllbnQxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tMFwwDQYJKoZI -hvcNAQEBBQADSwAwSAJBAKM981BdHZsUlPtX7KPnk3Zow2O9YFjXl1l9vKrASdFB -ZquCQrcOxr+HydE2YEB1SK14Cq1L87KrrvHolY7j/zcCAwEAAaOCAQQwggEAMAkG -A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp -ZmljYXRlMB0GA1UdDgQWBBTHEIRHidcfXfvEc2oPcoworrWCjjCBpQYDVR0jBIGd -MIGagBT7hyNp65w6kxXlxb8pUU/+7Sg4AaF/pH0wezELMAkGA1UEBhMCU0cxETAP -BgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMb -TTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3Bz -QHBvc3QxLmNvbYIBADANBgkqhkiG9w0BAQQFAAOBgQCstnFmtgRenGwTxOInIv/8 -DqpCw27CN2GclEo+2T53n4IcfRMESXywd/7FxH+/Dhy+8leiDK7xFRACQmLPt8P5 -bKQjCQtITqJsZ7dL48ggndCXmhMIoUBmzqPVdK3l861MvMjZMKNcPJjEmyL6ofg+ -bkwdIyi/5pdRFS8NzSX+vA== ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIIBOgIBAAJBAKM981BdHZsUlPtX7KPnk3Zow2O9YFjXl1l9vKrASdFBZquCQrcO -xr+HydE2YEB1SK14Cq1L87KrrvHolY7j/zcCAwEAAQJAUkHlWZmSUZMNf5nOpMkM -hZ5E1v2Wjy4UFgRGDcTXbZm401Avwrc8006qQxQjoH94pVkwPYjEyAMubhusMFt4 -AQIhANeB4qzW/YsABYpt66x1ByiuUJE1p+QMLngeESJbc989AiEAweoMtXsNRJi4 -1xBzlKB9zljQfESYIt59SctURPfX/4MCICS9kwyOdplM/qTUCprTNM49saSf9iiN -3xpBXgBygPWtAiEAmoIeDEB26vBxX1OJdKSIeXFE9a9GNYpn8/OiOq3smncCIGIg -Hj9MtdZ/1uPk7jx5oZVfzN1DM7GYZHAeYeYhVR13 ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE REQUEST----- -MIIBEzCBvgIBADBZMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xGDAW -BgNVBAMTD00yQ3J5cHRvIENsaWVudDEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0 -MS5jb20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEAoz3zUF0dmxSU+1fso+eTdmjD -Y71gWNeXWX28qsBJ0UFmq4JCtw7Gv4fJ0TZgQHVIrXgKrUvzsquu8eiVjuP/NwID -AQABoAAwDQYJKoZIhvcNAQEEBQADQQAQho0UsOhmuUUhJrx7uXIEbo984OrOVpa6 -giAU7socmyjCzJvihmr/Nnqub+Md7rkSfDytGDN6CianGL5MROjr ------END CERTIFICATE REQUEST----- diff --git a/demo/smime/client2.pem b/demo/smime/client2.pem deleted file mode 100644 index 166919a..0000000 --- a/demo/smime/client2.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDDjCCAnegAwIBAgIBAzANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tMB4XDTAwMTEyMDEzMDMwNVoXDTAyMTEyMDEzMDMwNVowWzEL -MAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRowGAYDVQQDExFNMkNyeXB0 -byBDbGllbnQgMjEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20wXDANBgkq -hkiG9w0BAQEFAANLADBIAkEAn9qneRYTKPokme3obiJa2NTz1Z2kcF3NHVh60Qod -/TV/q4olPrZdFR2TDWt63Lgnygcsgf3u9pnhcEGk6IvntwIDAQABo4IBBDCCAQAw -CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy -dGlmaWNhdGUwHQYDVR0OBBYEFDKWFe6VWMhtRTE3/78+hAnSGxmvMIGlBgNVHSME -gZ0wgZqAFPuHI2nrnDqTFeXFvylRT/7tKDgBoX+kfTB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBABpE9xt1Hlq2dQZUXHuX -HI57vc2mlWnhhM0wnNhsNZFwfXRHCZOo/JJBhEIT3Rgyz0ErrbOr1SN96HNDKXOD -z6bh4NxB5DZ9sRPKEBj66zDsWJVMlom+Lkeal+GkVy36vpAyP1r+cTXyc9M2Gw/o -FBMinMHH/BXvF5GJ+UleheZe ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIIBOgIBAAJBAJ/ap3kWEyj6JJnt6G4iWtjU89WdpHBdzR1YetEKHf01f6uKJT62 -XRUdkw1rety4J8oHLIH97vaZ4XBBpOiL57cCAwEAAQJANXfspprUo9MvpPEn2pbR -Lk/kk2IcW510e0laI0uwBj50djfHqvsU5ccuVLrxowngLGrFmM3G4lnMknR2NvH8 -0QIhAMsK0AwStUNM/KyvIMikHHBOE9PrK7ARgKvlKl+0ieWPAiEAyYwonIVAtr1f -M8vmrc6TM2YxzSq4+jyYktaaNhYw11kCIA5pmhMBUPSSBm2LkNwtKgeewzGLw/If -i+6nubZJbnBpAiEAvJQvy4PCsTkvQr+d7zJB+O2920IGId1gxMOXNtQ8jsECIGvn -Uz54oonshmTg+Kj2DxnUKQEzFAmQLbtFslp1m47v ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE REQUEST----- -MIIBFTCBwAIBADBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xGjAY -BgNVBAMTEU0yQ3J5cHRvIENsaWVudCAyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBv -c3QxLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCf2qd5FhMo+iSZ7ehuIlrY -1PPVnaRwXc0dWHrRCh39NX+riiU+tl0VHZMNa3rcuCfKByyB/e72meFwQaToi+e3 -AgMBAAGgADANBgkqhkiG9w0BAQQFAANBAHI5KXfL6kIRoNjR8G9/uKiPUt4uVBKF -ecGp87M5t2a92Z0KpWOMXSHZ0LLQKqwWzALvWcPPIj6S8F6ENdwpfMk= ------END CERTIFICATE REQUEST----- diff --git a/demo/smime/m2.se.p7 b/demo/smime/m2.se.p7 deleted file mode 100644 index 3a5bb1b..0000000 --- a/demo/smime/m2.se.p7 +++ /dev/null @@ -1,84 +0,0 @@ -MIME-Version: 1.0 -Content-Disposition: attachment; filename="smime.p7m" -Content-Type: application/x-pkcs7-mime; name="smime.p7m" -Content-Transfer-Encoding: base64 - -MIAGCSqGSIb3DQEHA6CAMIIOBwIBADGCAVkwggFVAgEAMIG9MIG3MQswCQYDVQQG -EwJTRzEvMC0GA1UEChMmRmFzdCBTZWN1cmUgQ2hlYXAgQ2VydGlmaWNhdGVzIFB0 -ZSBMdGQxMjAwBgNVBAsTKUZhc3QgU2VjdXJlIENoZWFwIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MSQwIgYDVQQDExtGYXN0IFNlY3VyZSBDaGVhcCBLZXlNYXN0ZXIx -HTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tAgEDMA0GCSqGSIb3DQEBAQUA -BIGAaH1UOF0vZjCfEDbzWAy+kni/T0AVVbTdWeCZAaADIgNrUqVJKkV8BIrAFRUO -jNdz23gra1TRgoe+sq4qn9WBi61+f+8JUV4UHZYl4DdcIkcGvdEI7utPLFNFif2m -oqd+kr39wuGWMonoBpzFdycSN/FRpFTrwoyXEIHj9VPCwvUwggyjBgkqhkiG9w0B -BwEwGgYIKoZIhvcNAwIwDgICAKAECCZMYhSx21tlgIIMeGyY4Sgm4uv0a0Zu5gnx -x1bA6wPY2W8oOqFC3jEAc6j0aP9TzxFW33W5fT/wCWCuIaS8Bm2nCozt7yhBofV2 -9mEtlahbEV1KeqwgI/RteTHD2WUvz6277O9lsB/xsreKM63WzxkpTWi0BUQBDjC1 -ncwy/74ujmZhdAD28HJie5cqhxKQd8if5/Ild3B786sxpGaSBKbJAtJYG30imbHL -B7JTqDciCKQZzFeQBc1TOcld9VqFP2dRexmcPMxcyJN1iJe8R0g6PYpfAmLfmN6B -fAImcgJYBpq8PYzmTi7cpJCMmzlPn7urm8Nx4DUQtzzMArmSuMfWGhu2wWLM+2Mn -TB1cAVuO0bGgsHnr0BKW5gfQEJEIZY41Kq179RKAzI6OdJYvnKXoadEtzYI07Tup -D+HJXLdAuU/B6E+09IS8mg2RydNyRP+lp+sOVve6L4LAH8h5pt7hoES5/qgiew09 -FPpx5xmhcGCTHJ9Ad2Xec6zAuYkVWAUfLpiy2A2NDTZnQ6EWaeWHtoAizMjHlqQY -ZJYeXINzE4/u9ph5DTvXV2Sd57eOoaaaHmWwoV/887cdW33cQQ8LXciuzduI/b4V -LWFm3X9eVdGEeQFoNDP5D7xwEK67flhufYClB99lt3tCfRLvvcclsd39heOex5/M -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 -0GNMrEghOH1w+QAAAAA= - - - diff --git a/demo/smime/ns.p7 b/demo/smime/ns.p7 deleted file mode 100644 index d2ab1ac..0000000 --- a/demo/smime/ns.p7 +++ /dev/null @@ -1,53 +0,0 @@ -From: Ng Pheng Siong -X-Mailer: Mozilla 4.5 [en] (WinNT; I) -X-Accept-Language: en -MIME-Version: 1.0 -To: ngps@post1.com -Subject: S/MIME signing -Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg=sha1; boundary="------------msD996346BF03A805B450DC20D" - -This is a cryptographically signed message in MIME format. - ---------------msD996346BF03A805B450DC20D -Content-Type: text/plain; charset=us-ascii -Content-Transfer-Encoding: 7bit - -smime -vs- pgp -war over? ---------------msD996346BF03A805B450DC20D -Content-Type: application/x-pkcs7-signature; name="smime.p7s" -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename="smime.p7s" -Content-Description: S/MIME Cryptographic Signature - -MIIF8gYJKoZIhvcNAQcCoIIF4zCCBd8CAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCC -A9cwggPTMIIDPKADAgECAgEDMA0GCSqGSIb3DQEBBAUAMIG3MQswCQYDVQQGEwJTRzEvMC0G -A1UEChMmRmFzdCBTZWN1cmUgQ2hlYXAgQ2VydGlmaWNhdGVzIFB0ZSBMdGQxMjAwBgNVBAsT -KUZhc3QgU2VjdXJlIENoZWFwIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtG -YXN0IFNlY3VyZSBDaGVhcCBLZXlNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEu -Y29tMB4XDTk5MDkxNzA1NTAzOFoXDTAwMDkxNjA1NTAzOFowYDELMAkGA1UEBhMCU0cxGDAW -BgNVBAoTD00yQ3J5cHRvIENsaWVudDEYMBYGA1UEAxMPTTJDcnlwdG8gQ2xpZW50MR0wGwYJ -KoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA -vp8eCa+KpzNCv0MWyicUImP+WHxlrxm5EummI1Qe77U4w0k8IQuue7QIURWKDjdZI97izzeQ -SozHvgSsjCvuJlqifMoV0v7U4iUQoZkrXO3hzwM5VNr875M95SYeBjqWDUc0v3R6tka3xhg3 -dMoEL3QR6gsiardPEwygdL7/FN0CAwEAAaOCAUMwggE/MAkGA1UdEwQCMAAwLAYJYIZIAYb4 -QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTEHU/WosFL -yRo8NT9ViQ8APbKBXTCB5AYDVR0jBIHcMIHZgBQOTokwY/jsgXmHJoyQ5DmTVN0c8KGBvaSB -ujCBtzELMAkGA1UEBhMCU0cxLzAtBgNVBAoTJkZhc3QgU2VjdXJlIENoZWFwIENlcnRpZmlj -YXRlcyBQdGUgTHRkMTIwMAYDVQQLEylGYXN0IFNlY3VyZSBDaGVhcCBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTEkMCIGA1UEAxMbRmFzdCBTZWN1cmUgQ2hlYXAgS2V5TWFzdGVyMR0wGwYJ -KoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNvbYIBADANBgkqhkiG9w0BAQQFAAOBgQBN4w1l4IXm -DJke8XVyo3SFlre1nL/bjDB+hpYCgTQnceHAmSi6L8FljGs2KYGFePWLSCsOxA99q8lVtl7a -sdoOtYkTluccWGqnWloyusOzlO2xgpoQxZ2iue3PT4Y4u8czMTs2AyanZyd6NdQoaYGfI2g0 -tpgiDhSqcX8r/JYYVzGCAeMwggHfAgEBMIG9MIG3MQswCQYDVQQGEwJTRzEvMC0GA1UEChMm -RmFzdCBTZWN1cmUgQ2hlYXAgQ2VydGlmaWNhdGVzIFB0ZSBMdGQxMjAwBgNVBAsTKUZhc3Qg -U2VjdXJlIENoZWFwIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtGYXN0IFNl -Y3VyZSBDaGVhcCBLZXlNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tAgED -MAkGBSsOAwIaBQCgfTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP -Fw0wMDAzMzEwNTExNTJaMB4GCSqGSIb3DQEJDzERMA8wDQYIKoZIhvcNAwICASgwIwYJKoZI -hvcNAQkEMRYEFDIu42hsp6w5K/x7ejaVgiqgPYk4MA0GCSqGSIb3DQEBAQUABIGAkipjxn6+ -NhIyRPGgrqY9zpDC8AGdt7sGFMKfxhJ+UoSb+lBH0imHSBhA/BnlfysyyDXCpit1Gxy/W/jn -vHpI0lMLvvcKOtSQp9HUPAtawdeF6Zau8SovSBroUnxxY7DILJoKnaHheHF7G2MbYusyZCmi -r3xZ4P0Ps3fhNEAmrH0= ---------------msD996346BF03A805B450DC20D-- - diff --git a/demo/smime/ns.se.p7 b/demo/smime/ns.se.p7 deleted file mode 100644 index a7a75f5..0000000 --- a/demo/smime/ns.se.p7 +++ /dev/null @@ -1,75 +0,0 @@ -MIME-Version: 1.0 -Content-Type: application/x-pkcs7-mime; name="smime.p7m" -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename="smime.p7m" -Content-Description: S/MIME Encrypted Message - -MIAGCSqGSIb3DQEHA6CAMIACAQAxggKyMIIBVQIBADCBvTCBtzELMAkGA1UEBhMCU0cxLzAt -BgNVBAoTJkZhc3QgU2VjdXJlIENoZWFwIENlcnRpZmljYXRlcyBQdGUgTHRkMTIwMAYDVQQL -EylGYXN0IFNlY3VyZSBDaGVhcCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMb -RmFzdCBTZWN1cmUgQ2hlYXAgS2V5TWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3Qx -LmNvbQIBAzANBgkqhkiG9w0BAQEFAASBgERIsZhX2nmvB4kOtcfqUpuWjK9njs8YixtPSS4w -ugmAx3LhBMTgY1OlsbKi7etVPwEU2jSqgkwCHPeYeOQt6M9aQ66tcue7/fWjfMBfZ+tetwOb -kpqlw//GyjhkJx2QBGPuw3Ye84ll1KA7x/CGxmk8g0YBHoLo9Xy1W1XHVUanMIIBVQIBADCB -vTCBtzELMAkGA1UEBhMCU0cxLzAtBgNVBAoTJkZhc3QgU2VjdXJlIENoZWFwIENlcnRpZmlj -YXRlcyBQdGUgTHRkMTIwMAYDVQQLEylGYXN0IFNlY3VyZSBDaGVhcCBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTEkMCIGA1UEAxMbRmFzdCBTZWN1cmUgQ2hlYXAgS2V5TWFzdGVyMR0wGwYJ -KoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNvbQIBBzANBgkqhkiG9w0BAQEFAASBgKFEdyFcaj2z -7LBp/rdEiDRNkyvjZtpEc3F1tvml2jmOuRZq/Gd0Ib4ELmAuC2qZ7AG+MNwlMeCQp1PKGjCk -3Af9hjcOX27c+qF3pSK35WOPrdQTaVLjqdNwejInEoBjGlHa83V1L/MTiD5ABOXGIZKOFS8m -G0tPxoc3AhlYbHspMIAGCSqGSIb3DQEHATARBgUrDgMCBwQIvFFOv2EOARiggASBsBBa97DM -xPCX8mZ2K/jjVl2LKtBP0uwG+nd48IiaoBERbJohEdzxTlIU3pj+QZ4ktmSSYo/4Os0eSCfK -v2mG3d5SPxcE6HztA4FttvQ4IiByTQUU61vJhMoirV5Nvfkxk8i8xPMKMlJSruFBnIOteXQv -vwVwBCIAkMhxBE9Sj+OfW5966d+LmB3yGEZa9GEW//4VbR6DNs1frEz7riUod0om5CA66bou -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 - diff --git a/demo/smime/opaque.p7 b/demo/smime/opaque.p7 deleted file mode 100644 index a242446..0000000 --- a/demo/smime/opaque.p7 +++ /dev/null @@ -1,47 +0,0 @@ -To: ngps@post1.com -From: ngps@mpost1.com -Subject: testing -MIME-Version: 1.0 -Content-Disposition: attachment; filename="smime.p7m" -Content-Type: application/x-pkcs7-mime; name="smime.p7m" -Content-Transfer-Encoding: base64 - -MIIHHAYJKoZIhvcNAQcCoIIHDTCCBwkCAQExCzAJBgUrDgMCGgUAMIICQwYJKoZI -hvcNAQcBoIICNASCAjANClMvTUlNRSAtIFNlY3VyZSBNdWx0aXB1cnBvc2UgSW50 -ZXJuZXQgTWFpbCBFeHRlbnNpb25zIFtSRkMgMjMxMSwgUkZDIDIzMTJdIC0gDQpw -cm92aWRlcyBhIGNvbnNpc3RlbnQgd2F5IHRvIHNlbmQgYW5kIHJlY2VpdmUgc2Vj -dXJlIE1JTUUgZGF0YS4gQmFzZWQgb24gdGhlDQpwb3B1bGFyIEludGVybmV0IE1J -TUUgc3RhbmRhcmQsIFMvTUlNRSBwcm92aWRlcyB0aGUgZm9sbG93aW5nIGNyeXB0 -b2dyYXBoaWMNCnNlY3VyaXR5IHNlcnZpY2VzIGZvciBlbGVjdHJvbmljIG1lc3Nh -Z2luZyBhcHBsaWNhdGlvbnMgLSBhdXRoZW50aWNhdGlvbiwNCm1lc3NhZ2UgaW50 -ZWdyaXR5IGFuZCBub24tcmVwdWRpYXRpb24gb2Ygb3JpZ2luICh1c2luZyBkaWdp -dGFsIHNpZ25hdHVyZXMpDQphbmQgcHJpdmFjeSBhbmQgZGF0YSBzZWN1cml0eSAo -dXNpbmcgZW5jcnlwdGlvbikuDQoNClMvTUlNRSBpcyBidWlsdCBvbiB0aGUgUEtD -UyAjNyBzdGFuZGFyZC4gW1BLQ1M3XQ0KDQpTL01JTUUgaXMgaW1wbGVtZW50ZWQg -aW4gTmV0c2NhcGUgTWVzc2VuZ2VyIGFuZCBNaWNyb3NvZnQgT3V0bG9vay4NCqCC -AxAwggMMMIICdaADAgECAgECMA0GCSqGSIb3DQEBBAUAMHsxCzAJBgNVBAYTAlNH -MREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0ExJDAiBgNV -BAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEdMBsGCSqGSIb3DQEJARYO -bmdwc0Bwb3N0MS5jb20wHhcNMDAwOTEwMDk1ODIwWhcNMDIwOTEwMDk1ODIwWjBZ -MQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xGDAWBgNVBAMTD00yQ3J5 -cHRvIENsaWVudDEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20wXDANBgkq -hkiG9w0BAQEFAANLADBIAkEAoz3zUF0dmxSU+1fso+eTdmjDY71gWNeXWX28qsBJ -0UFmq4JCtw7Gv4fJ0TZgQHVIrXgKrUvzsquu8eiVjuP/NwIDAQABo4IBBDCCAQAw -CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy -dGlmaWNhdGUwHQYDVR0OBBYEFMcQhEeJ1x9d+8Rzag9yjCiutYKOMIGlBgNVHSME -gZ0wgZqAFPuHI2nrnDqTFeXFvylRT/7tKDgBoX+kfTB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBAKy2cWa2BF6cbBPE4ici -//wOqkLDbsI3YZyUSj7ZPnefghx9EwRJfLB3/sXEf78OHL7yV6IMrvEVEAJCYs+3 -w/lspCMJC0hOomxnt0vjyCCd0JeaEwihQGbOo9V0reXzrUy8yNkwo1w8mMSbIvqh -+D5uTB0jKL/ml1EVLw3NJf68MYIBmjCCAZYCAQEwgYAwezELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5u -Z3BzQHBvc3QxLmNvbQIBAjAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzELBgkq -hkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAyMTIwODE3NTIyMVowIwYJKoZIhvcN -AQkEMRYEFI/KcwJXhIg0bRzYLfAtDhxRMzghMFIGCSqGSIb3DQEJDzFFMEMwCgYI -KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH -MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABEBrhZ8JVqGZ+S7dh+xKDwbF -yRXiOQWEa2uxD1O5fD02VfGEzDSrV1sPdQ8AcM3o+ny5AyC11E4Fns2cIkXwZEwz - diff --git a/demo/smime/sendsmime.py b/demo/smime/sendsmime.py deleted file mode 100644 index 9cc446b..0000000 --- a/demo/smime/sendsmime.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME sender. - -Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import BIO, Rand, SMIME, X509 -import smtplib, string, sys - -def sendsmime(from_addr, to_addrs, subject, msg, from_key, from_cert=None, to_certs=None, smtpd='localhost'): - - msg_bio = BIO.MemoryBuffer(msg) - sign = from_key - encrypt = to_certs - - s = SMIME.SMIME() - if sign: - s.load_key(from_key, from_cert) - p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT) - msg_bio = BIO.MemoryBuffer(msg) # Recreate coz sign() has consumed it. - - if encrypt: - sk = X509.X509_Stack() - for x in to_certs: - sk.push(X509.load_cert(x)) - s.set_x509_stack(sk) - s.set_cipher(SMIME.Cipher('rc2_40_cbc')) - tmp_bio = BIO.MemoryBuffer() - if sign: - s.write(tmp_bio, p7) - else: - tmp_bio.write(msg) - p7 = s.encrypt(tmp_bio) - - out = BIO.MemoryBuffer() - out.write('From: %s\r\n' % from_addr) - out.write('To: %s\r\n' % string.join(to_addrs, ", ")) - out.write('Subject: %s\r\n' % subject) - if encrypt: - s.write(out, p7) - else: - if sign: - s.write(out, p7, msg_bio, SMIME.PKCS7_TEXT) - else: - out.write('\r\n') - out.write(msg) - out.close() - - smtp = smtplib.SMTP() - smtp.connect(smtpd) - smtp.sendmail(from_addr, to_addrs, out.read()) - smtp.quit() - - # XXX Cleanup the stack and store. - - -msg = """ -S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC 2312] - -provides a consistent way to send and receive secure MIME data. Based on the -popular Internet MIME standard, S/MIME provides the following cryptographic -security services for electronic messaging applications - authentication, -message integrity and non-repudiation of origin (using digital signatures) -and privacy and data security (using encryption). - -S/MIME is built on the PKCS #7 standard. [PKCS7] - -S/MIME is implemented in Netscape Messenger and Microsoft Outlook. -""" - - -if __name__ == '__main__': - Rand.load_file('../randpool.dat', -1) - sendsmime(from_addr = 'ngps@post1.com', - to_addrs = ['jerry','ngps@post1.com'], - subject = 'S/MIME testing', - msg = msg, - from_key = 'client2.pem', - #from_key = None, - #to_certs = None) - to_certs = ['client.pem']) - Rand.save_file('../randpool.dat') - diff --git a/demo/smime/test.py b/demo/smime/test.py deleted file mode 100644 index a59cf9f..0000000 --- a/demo/smime/test.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME demo. - -Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import BIO, Rand, SMIME, X509 - -ptxt = """ -S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC 2312] - -provides a consistent way to send and receive secure MIME data. Based on the -popular Internet MIME standard, S/MIME provides the following cryptographic -security services for electronic messaging applications - authentication, -message integrity and non-repudiation of origin (using digital signatures) -and privacy and data security (using encryption). - -S/MIME is built on the PKCS #7 standard. [PKCS7] - -S/MIME is implemented in Netscape Messenger and Microsoft Outlook. -""" - -def makebuf(): - buf = BIO.MemoryBuffer(ptxt) - return buf - -def sign(): - print 'test sign & save...', - buf = makebuf() - s = SMIME.SMIME() - s.load_key('client.pem') - p7 = s.sign(buf) - out = BIO.openfile('clear.p7', 'w') - out.write('To: ngps@post1.com\n') - out.write('From: ngps@post1.com\n') - out.write('Subject: testing\n') - buf = makebuf() # Recreate buf, because sign() has consumed it. - s.write(out, p7, buf) - out.close() - - buf = makebuf() - p7 = s.sign(buf) - out = BIO.openfile('opaque.p7', 'w') - out.write('To: ngps@post1.com\n') - out.write('From: ngps@mpost1.com\n') - out.write('Subject: testing\n') - s.write(out, p7) - out.close() - print 'ok' - -def verify_clear(): - print 'test load & verify clear...', - s = SMIME.SMIME() - x509 = X509.load_cert('client.pem') - sk = X509.X509_Stack() - sk.push(x509) - s.set_x509_stack(sk) - st = X509.X509_Store() - st.load_info('ca.pem') - s.set_x509_store(st) - p7, data = SMIME.smime_load_pkcs7('clear.p7') - v = s.verify(p7) - if v: - print 'ok' - else: - print 'not ok' - -def verify_opaque(): - print 'test load & verify opaque...', - s = SMIME.SMIME() - x509 = X509.load_cert('client.pem') - sk = X509.X509_Stack() - sk.push(x509) - s.set_x509_stack(sk) - st = X509.X509_Store() - st.load_info('ca.pem') - s.set_x509_store(st) - p7, data = SMIME.smime_load_pkcs7('opaque.p7') - v = s.verify(p7, data) - if v: - print 'ok' - else: - print 'not ok' - -def verify_netscape(): - print 'test load & verify netscape messager output...', - s = SMIME.SMIME() - #x509 = X509.load_cert('client.pem') - sk = X509.X509_Stack() - #sk.push(x509) - s.set_x509_stack(sk) - st = X509.X509_Store() - st.load_info('ca.pem') - s.set_x509_store(st) - p7, data = SMIME.smime_load_pkcs7('ns.p7') - v = s.verify(p7, data) - print '\n', v, '\n...ok' - - -def sv(): - print 'test sign/verify...', - buf = makebuf() - s = SMIME.SMIME() - - # Load a private key. - s.load_key('client.pem') - - # Sign. - p7 = s.sign(buf) - - # Output the stuff. - bio = BIO.MemoryBuffer() - s.write(bio, p7, buf) - - # Plumbing for verification: CA's cert. - st = X509.X509_Store() - st.load_info('ca.pem') - s.set_x509_store(st) - - # Plumbing for verification: Signer's cert. - x509 = X509.load_cert('client.pem') - sk = X509.X509_Stack() - sk.push(x509) - s.set_x509_stack(sk) - - # Verify. - p7, buf = SMIME.smime_load_pkcs7_bio(bio) - v = s.verify(p7, flags=SMIME.PKCS7_DETACHED) - - if v: - print 'ok' - else: - print 'not ok' - -def ed(): - print 'test encrypt/decrypt...', - buf = makebuf() - s = SMIME.SMIME() - - # Load target cert to encrypt to. - x509 = X509.load_cert('client.pem') - sk = X509.X509_Stack() - sk.push(x509) - s.set_x509_stack(sk) - - # Add a cipher. - s.set_cipher(SMIME.Cipher('bf_cbc')) - - # Encrypt. - p7 = s.encrypt(buf) - - # Load target's private key. - s.load_key('client.pem') - - # Decrypt. - data = s.decrypt(p7) - - if data: - print 'ok' - else: - print 'not ok' - - -def zope_test(): - print 'test zophistry...' - f = open('client.pem') - cert_str = f.read() - key_bio = BIO.MemoryBuffer(cert_str) - cert_bio = BIO.MemoryBuffer(cert_str) # XXX Kludge. - s = SMIME.SMIME() - s.load_key_bio(key_bio, cert_bio) - # XXX unfinished... - - -def leak_test(): - # Seems ok, not leaking. - while 1: - ed() - #sv() - - -if __name__ == '__main__': - Rand.load_file('../randpool.dat', -1) - ed() - sign() - verify_opaque() - verify_clear() - #verify_netscape() - sv() - #zope_test() - #leak_test() - Rand.save_file('../randpool.dat') - diff --git a/demo/smime/unsmime.py b/demo/smime/unsmime.py deleted file mode 100644 index ffc40ad..0000000 --- a/demo/smime/unsmime.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python - -"""S/MIME demo. - -Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import BIO, Rand, SMIME, X509 -import sys - -def decrypt_verify(p7file, recip_key, signer_cert, ca_cert): - s = SMIME.SMIME() - - # Load decryption private key. - s.load_key(recip_key) - - # Extract PKCS#7 blob from input. - p7, bio = SMIME.smime_load_pkcs7_bio(p7file) - - # Decrypt. - data = s.decrypt(p7) - - # Because we passed in a SignAndEnveloped blob, the output - # of our decryption is a Signed blob. We now verify it. - - # Load the signer's cert. - sk = X509.X509_Stack() - s.set_x509_stack(sk) - - # Load the CA cert. - st = X509.X509_Store() - st.load_info(ca_cert) - s.set_x509_store(st) - - # Verify. - p7, bio = SMIME.smime_load_pkcs7_bio(BIO.MemoryBuffer(data)) - if bio is not None: - # Netscape Messenger clear-signs, when also encrypting. - data = s.verify(p7, bio) - else: - # M2Crypto's sendsmime.py opaque-signs, when also encrypting. - data = s.verify(p7) - - print data - - -if __name__ == '__main__': - Rand.load_file('../randpool.dat', -1) - decrypt_verify(BIO.File(sys.stdin), 'client.pem', 'client2.pem','ca.pem') - Rand.save_file('../randpool.dat') - diff --git a/demo/ssl/README b/demo/ssl/README deleted file mode 100644 index 07e43b8..0000000 --- a/demo/ssl/README +++ /dev/null @@ -1,25 +0,0 @@ - 29 Nov 00 ------------ - -This directory contains SSL clients and servers written as demos -and testbeds. - -The oldest ones are s_server.py and s_client.py: these are modeled -after the eponymous demo programs in OpenSSL. Once I got them going, -I moved on to Medusa and other "real-world" servers. The pair has been -in a state of neglect and quite likely no longer work with the current -M2Crypto. - -My current testbeds are the echod-* servers and echo.py. These should -always work. Note that Python on the three platforms that I test on -are built --with-threads. - - -Python 2.0's httplib introduces HTTP/1.1 functionality and an interface -substantially different from Python 1.5.2's HTTP/1.0 interface. - -M2Crypto.httpslib provides both interfaces. The demo programs are -https_cli.py and urllib_cli.py; these have been tested with -Apache/1.3.14 (Unix) mod_ssl/2.7.1 OpenSSL/0.9.6. - - diff --git a/demo/ssl/c.py b/demo/ssl/c.py deleted file mode 100644 index bd03e6e..0000000 --- a/demo/ssl/c.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python - -"""C programming in Python. Have SWIG sweat the pointers. ;-) - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from socket import * -import sys - -from M2Crypto import SSL, m2 - -HOST = '127.0.0.1' -PORT = 9443 -req_10 = 'GET / HTTP/1.0\r\n\r\n' -req_11 = 'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' - - -def c_10(): - c_style(HOST, PORT, req_10) - - -def c_11(): - c_style(HOST, PORT, req_11) - - -def c_style(HOST, PORT, req): - - # Set up SSL context. - ctx = m2.ssl_ctx_new(m2.sslv3_method()) - m2.ssl_ctx_use_cert(ctx, 'client.pem') - m2.ssl_ctx_use_privkey(ctx, 'client.pem') - - # Make the socket connection. - s = socket(AF_INET, SOCK_STREAM) - s.connect((HOST, PORT)) - - # Set up the SSL connection. - sbio = m2.bio_new_socket(s.fileno(), 0) - ssl = m2.ssl_new(ctx) - m2.ssl_set_bio(ssl, sbio, sbio) - m2.ssl_connect(ssl) - sslbio = m2.bio_new(m2.bio_f_ssl()) - m2.bio_set_ssl(sslbio, ssl, 0) - - # Push a buffering BIO over the SSL BIO. - iobuf = m2.bio_new(m2.bio_f_buffer()) - topbio = m2.bio_push(iobuf, sslbio) - - # Send the request. - m2.bio_write(sslbio, req) - - # Receive the response. - while 1: - data = m2.bio_gets(topbio, 4096) - if not data: break - sys.stdout.write(data) - - # Cleanup. May be missing some necessary steps. ;-| - m2.bio_pop(topbio) - m2.bio_free(iobuf) - m2.ssl_shutdown(ssl) - m2.ssl_free(ssl) - m2.ssl_ctx_free(ctx) - s.close() - - -if __name__ == '__main__': - c_10() - c_11() - diff --git a/demo/ssl/c_bio.py b/demo/ssl/c_bio.py deleted file mode 100644 index 1c20e91..0000000 --- a/demo/ssl/c_bio.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python - -"""C programming in Python. Have SWIG sweat the pointers. ;-) - -Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved.""" - -from socket import * -import sys - -from M2Crypto import SSL, m2 - -HOST = '127.0.0.1' -PORT = 9443 -req_10 = 'GET / HTTP/1.0\r\n\r\n' -req_11 = 'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' - - -def c_10(): - c_style(HOST, PORT, req_10) - - -def c_11(): - c_style(HOST, PORT, req_11) - - -def c_style(HOST, PORT, req): - - # Set up SSL context. - ctx = m2.ssl_ctx_new(m2.sslv3_method()) - m2.ssl_ctx_use_cert(ctx, 'client.pem') - m2.ssl_ctx_use_privkey(ctx, 'client.pem') - - # Make the socket connection. - s = socket(AF_INET, SOCK_STREAM) - s.connect((HOST, PORT)) - - # Set up the SSL connection. - sbio = m2.bio_new_socket(s.fileno(), 0) - ssl = m2.ssl_new(ctx) - m2.ssl_set_bio(ssl, sbio, sbio) - m2.ssl_connect(ssl) - sslbio = m2.bio_new(m2.bio_f_ssl()) - m2.bio_set_ssl(sslbio, ssl, 0) - - # Push a buffering BIO over the SSL BIO. - iobuf = m2.bio_new(m2.bio_f_buffer()) - topbio = m2.bio_push(iobuf, sslbio) - - # Send the request. - m2.bio_write(sslbio, req) - - # Receive the response. - while 1: - data = m2.bio_gets(topbio, 4096) - if not data: break - sys.stdout.write(data) - - # Cleanup. May be missing some necessary steps. ;-| - m2.bio_pop(topbio) - m2.bio_free(iobuf) - m2.ssl_shutdown(ssl) - m2.ssl_free(ssl) - m2.ssl_ctx_free(ctx) - s.close() - - -if __name__ == '__main__': - #c_10() - c_11() - diff --git a/demo/ssl/ca.der b/demo/ssl/ca.der deleted file mode 100644 index 8f4ed808100d9f3ad635aed4c165c61c5b5a3c20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 841 zcmXqLVso^(3`0~;ViX95_i%SgklJj#7( zaXxZbF|sl+H}*0ZGcd#cNNdP-0fl`;DIWUVeJI>Y@GRqu=&@RkSY= zUvXMJW|f_fwTqUY%~|6zc7MIsmO7r^f{x10_Rh1;d+1kP4Ju8W?$s1>%+cze?LV#~ zU2_&QC8#NQ|ITnavGzfOTGt-)g$|6xcK@Aj`z*W0F1cLjcG$&T%IBu<_S*W5k%^g+ zfpKx;4THw32C~3-kmX|$V-fk?uAKRLj@4w*r$_f|2KxVdt6{-t(6|&Nuguao*PwA$ z16DN)>zC9HXjnG^(p_rDcCCVY;ZQ0I5mQT_MKJD1o0zt6dH>nQ^>o6mbA8T?nOI__LOb>AbG SiH`z>YE6HiWH6O5PXhq1Ru+8# diff --git a/demo/ssl/ca.pem b/demo/ssl/ca.pem deleted file mode 100644 index b7c84a1..0000000 --- a/demo/ssl/ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 -NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML -TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl -cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK -q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N -e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf -q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G -A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV -BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex -JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 -DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG -SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ -dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J -vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf ------END CERTIFICATE----- diff --git a/demo/ssl/client.p12 b/demo/ssl/client.p12 deleted file mode 100644 index 9c7a64096793efa541e1565c9a1b4ec48bda7e18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1604 zcmY+Dc{r2{6vn?<&CoERQ7Md2naO;XC=tR9Nrcj#Jt@Z6yISs-kfx}{MT&`GG?jHI z%(awdvP5JVOC?!`%4EngE?3WU@9o|{&U2pgzUQ2O-scBGXmdCW0YYdr8mk>+6Elm0 zNx_&9Y8DBh#2|#41R=!xpB9=4A=*}?W;hI3X>~sx7`Oo~{r87eFf=HO#NwP-aNf2Cxvqu2zt>Qk<0gg*+c&nIhkWE+Z?&!^Qj<@ z7QSYm^>-?3%v_ZwN^wgt45n&6=xQ?%hU#fy5-Qas){vQzeYC|MIdAD{{C~13S0udp^5Tn{n}S1DhiZv}j)x<&R}1?=B{^ zv}~7me{MvY{IkHz&PF@+bM1s3j4fEWN=9Mrzd3}p75DBg3XBZG#(^ic9^cg}ulB@1 zEU({igj%t$eo`&xCWbL}_%rb}c?)6&Wu4ks?Uzn-8I{^tA>i(1?C213{xD9(kUSVM zruV>K?b**T%W9Z>X^LL$gmK))B?G%dqP?Eu(#1g{{W)1vCnLH|dwf_k20j{@Hje51l)67)4 zva^vB)96}mMHDiBxsmpz^EWxIaFZQoFYHXh@|DxveEs7L$LC|0TVx(JM5pJicRf}U zjE8qIhKhJsx%-lu@vE4zYd=(H?cL}@&Cp;L_zBKSGvMN$8#tE%okhA;Qp82mvMpjm zNAWMa&3PR%fhqLu7>*664wl9YH5z+2dpDrR;DRjPx&7KI-!w`y#v$+E!}r-!ao=21 zdlQq1M2fzElc(bCc=BGU2{`_M!Dx0)Rp67id)+&pIa)#K9QW>qF{gvzh>Ko?2M-kLo2 zYJKC?TXWL9{3-j6m0tpsXVfAw?|X7ecUxanLSo0ff^sNhA`87d<1|ihZLQ&`n>U^f zYQiUoCj*z7%&LmDn2j9m?4xAjQeWZX^twH|%Zy!?hZ_SSY?umcv+t36x_e4 z@2Y?U&)zsQ)<2t-Khl>-N6Z@`za>Iq4mykLu2_I4Zw`T9s1h^}~(G4I3$NUFmCIp*DLa-SS zf_+=5FKC&6u$G3wSIn3d5&9qPh#$0PDAn!^Cw4^qpnc{1v_^^jmz01)#{i;DklWLi z-sX|2;>>ZsdtZIZxVi=Mu|C2oGTPW?(>c`E{VEA-RoB&gj1_Xq1`z38z);IcsOwSB zUI(3&_cg3*-#AlAo~1RM%fm&z;WJ+Ie!>sGSD(J+K3jT2@2u*A zmus2Gpu`7sSkN^F1J10M0e6JHd7mY4)pIIi?`f@I^z1YU&1)nVzLN|cwAXi*o=;HD z#6>E|RivFL9AQTgN$aoM(JpYw`%MviT^DfEzo}u@=n{~M@e^aWj?+eu|}Xd z@p2RkZu_~UsH>);0_+F$084-dL;_SG1PBDwR;F`+AK(oH03o0*NCdHH6iF5VUylNi liWb^R(JT@Hn`wnMiY^YEE 0) - - def handle_write(self): - if self._ssl_accepting: - s = self.socket.accept_ssl() - if s: - self._ssl_accepting = 0 - else: - try: - n = self.send(self.buffer) - if n == -1: - pass - elif n == 0: - self.handle_close() - else: - self.buffer = self.buffer[n:] - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - self.handle_close() - return - else: - raise - - def readable(self): - return 1 - - def handle_read(self): - if self._ssl_accepting: - s = self.socket.accept_ssl() - if s: - self._ssl_accepting = 0 - else: - try: - blob = self.recv(4096) - if blob is None: - pass - elif blob == '': - self.handle_close() - else: - self.buffer = self.buffer + blob - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - self.handle_close() - return - else: - raise - - -class ssl_echo_server(SSL.ssl_dispatcher): - - channel_class=ssl_echo_channel - - def __init__(self, addr, port, ssl_context): - SSL.ssl_dispatcher.__init__(self) - self.create_socket(ssl_context) - self.set_reuse_addr() - self.socket.setblocking(0) - self.bind((addr, port)) - self.listen(5) - self.ssl_ctx=ssl_context - - def handle_accept(self): - try: - sock, addr = self.socket.accept() - self.channel_class(sock) - except: - print '-'*40 - import traceback - traceback.print_exc() - print '-'*40 - return - - def writable(self): - return 0 - - -if __name__=='__main__': - Rand.load_file('../randpool.dat', -1) - ctx = echod_lib.init_context('sslv23', 'server.pem', 'ca.pem', \ - #SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) - SSL.verify_none) - ctx.set_tmp_dh('dh1024.pem') - ssl_echo_server('', 9999, ctx) - asyncore.loop() - Rand.save_file('../randpool.dat') - diff --git a/demo/ssl/echod-eg1.py b/demo/ssl/echod-eg1.py deleted file mode 100644 index 87358b7..0000000 --- a/demo/ssl/echod-eg1.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -"""Demo SSL server #1 for the HOWTO. - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" - -import SocketServer -from M2Crypto import Err, Rand, SSL, threading - -def init_context(protocol, dhpfile, certfile, cafile, verify, verify_depth=10): - ctx = SSL.Context(protocol) - ctx.set_tmp_dh(dhpfile) - ctx.load_cert(certfile) - #ctx.load_verify_info(cafile) - ctx.set_verify(verify, verify_depth) - ctx.set_session_id_ctx('echod') - ctx.set_info_callback() - return ctx - -class ssl_echo_handler(SocketServer.BaseRequestHandler): - - buffer = 'Ye Olde Echo Servre\r\n' - - def handle(self): - peer = self.request.get_peer_cert() - if peer is not None: - print 'Client CA =', peer.get_issuer().O - print 'Client Subject =', peer.get_subject().CN - self.request.write(self.buffer) - while 1: - buf = self.request.read() - if not buf: - break - self.request.write(buf) - - def finish(self): - self.request.set_shutdown(SSL.SSL_SENT_SHUTDOWN|SSL.SSL_RECEIVED_SHUTDOWN) - self.request.close() - -if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) - threading.init() - ctx = init_context('sslv23', 'dh1024.pem', 'server.pem', 'ca.pem', SSL.verify_peer) - s = SSL.SSLServer(('', 9999), ssl_echo_handler, ctx) - s.serve_forever() - threading.cleanup() - Rand.save_file('randpool.dat') - - diff --git a/demo/ssl/echod-forking.py b/demo/ssl/echod-forking.py deleted file mode 100644 index 43faab3..0000000 --- a/demo/ssl/echod-forking.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -"""A forking SSL 'echo' server. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import DH, Rand, SSL -import echod_lib - -class ssl_echo_handler(echod_lib.ssl_echo_handler): - buffer = 'Ye Olde Forking Echo Servre\r\n' - - -if __name__ == '__main__': - Rand.load_file('../randpool.dat', -1) - ctx = echod_lib.init_context('sslv23', 'server.pem', 'ca.pem', - SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) - ctx.set_tmp_dh('dh1024.pem') - s = SSL.ForkingSSLServer(('', 9999), ssl_echo_handler, ctx) - s.serve_forever() - Rand.save_file('../randpool.dat') - diff --git a/demo/ssl/echod-iterative.py b/demo/ssl/echod-iterative.py deleted file mode 100644 index 2e68699..0000000 --- a/demo/ssl/echod-iterative.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -"""A simple iterative SSL 'echo' server. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import Rand, SSL -import echod_lib - -class ssl_echo_handler(echod_lib.ssl_echo_handler): - buffer='Ye Olde One-At-A-Time Echo Servre\r\n' - - -if __name__=='__main__': - Rand.load_file('../randpool.dat', -1) - ctx=echod_lib.init_context('sslv23', 'server.pem', 'ca.pem', \ - SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) - #SSL.verify_none) - ctx.set_tmp_dh('dh1024.pem') - s=SSL.SSLServer(('', 9999), ssl_echo_handler, ctx) - s.serve_forever() - Rand.save_file('../randpool.dat') - diff --git a/demo/ssl/echod-thread.py b/demo/ssl/echod-thread.py deleted file mode 100644 index 65db811..0000000 --- a/demo/ssl/echod-thread.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python - -"""Another multi-threading SSL 'echo' server. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import Rand, SSL, threading -import echod_lib - -import thread -from socket import * - -buffer='Ye Newe Threading Echo Servre\r\n' - -def echo_handler(sslctx, sock, addr): - sslconn = SSL.Connection(sslctx, sock) - sslconn.setup_addr(addr) - sslconn.setup_ssl() - sslconn.set_accept_state() - sslconn.accept_ssl() - sslconn.write(buffer) - while 1: - try: - buf = sslconn.read() - if not buf: - break - sslconn.write(buf) - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - break - else: - raise - except: - break - # Threading servers need this. - sslconn.set_shutdown(SSL.SSL_RECEIVED_SHUTDOWN|SSL.SSL_SENT_SHUTDOWN) - sslconn.close() - - -if __name__=='__main__': - threading.init() - Rand.load_file('../randpool.dat', -1) - ctx=echod_lib.init_context('sslv23', 'server.pem', 'ca.pem', - SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) - ctx.set_tmp_dh('dh1024.pem') - sock = socket(AF_INET, SOCK_STREAM) - sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) - sock.bind(('', 9999)) - sock.listen(5) - while 1: - conn, addr = sock.accept() - thread.start_new_thread(echo_handler, (ctx, conn, addr)) - Rand.save_file('../randpool.dat') - threading.cleanup() - diff --git a/demo/ssl/echod-threading.py b/demo/ssl/echod-threading.py deleted file mode 100644 index 81eaef3..0000000 --- a/demo/ssl/echod-threading.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -"""A multi-threading SSL 'echo' server. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import DH, Rand, SSL, threading -import echod_lib - -class ssl_echo_handler(echod_lib.ssl_echo_handler): - - buffer='Ye Olde Threading Echo Servre\r\n' - - def finish(self): - # Threading servers need this. - self.request.set_shutdown(SSL.SSL_SENT_SHUTDOWN|SSL.SSL_RECEIVED_SHUTDOWN) - self.request.close() - - -if __name__=='__main__': - try: - threading.init() - Rand.load_file('../randpool.dat', -1) - ctx=echod_lib.init_context('sslv23', 'server.pem', 'ca.pem', - SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) - ctx.set_tmp_dh('dh1024.pem') - s=SSL.ThreadingSSLServer(('', 9999), ssl_echo_handler, ctx) - s.serve_forever() - Rand.save_file('../randpool.dat') - except: - threading.cleanup() - diff --git a/demo/ssl/echod_lib.py b/demo/ssl/echod_lib.py deleted file mode 100644 index 7bea683..0000000 --- a/demo/ssl/echod_lib.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Support routines for the various SSL 'echo' servers. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -import SocketServer -from M2Crypto import SSL - -def init_context(protocol, certfile, cafile, verify, verify_depth=10): - ctx = SSL.Context(protocol) - ctx.load_cert_chain(certfile) - ctx.load_verify_locations(cafile) - ctx.set_client_CA_list_from_file(cafile) - ctx.set_verify(verify, verify_depth) - #ctx.set_allow_unknown_ca(1) - ctx.set_session_id_ctx('echod') - ctx.set_info_callback() - return ctx - - -class ssl_echo_handler(SocketServer.BaseRequestHandler): - - buffer = 'Ye Olde Echo Servre\r\n' - - def handle(self): - peer = self.request.get_peer_cert() - if peer is not None: - print 'Client CA =', peer.get_issuer().O - print 'Client Subject =', peer.get_subject().CN - x = self.request.write(self.buffer) - while 1: - try: - buf = self.request.read() - if not buf: - break - self.request.write(buf) - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - break - else: - raise - - def finish(self): - self.request.close() - - diff --git a/demo/ssl/ftp_tls.py b/demo/ssl/ftp_tls.py deleted file mode 100644 index 163d87c..0000000 --- a/demo/ssl/ftp_tls.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python - -"""Demo for M2Crypto.ftpslib's FTP/TLS client. - -This client interoperates with M2Crypto's Medusa-based FTP/TLS -server as well as Peter Runestig's patched-for-TLS OpenBSD FTP -server. - -Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import SSL, ftpslib, threading - -def passive(): - ctx = SSL.Context('sslv23') - f = ftpslib.FTP_TLS(ssl_ctx=ctx) - f.connect('127.0.0.1', 39021) - f.auth_tls() - f.set_pasv(1) - f.login('ftp', 'ngps@') - f.prot_p() - f.retrlines('LIST') - f.quit() - -def active(): - ctx = SSL.Context('sslv23') - f = ftpslib.FTP_TLS(ssl_ctx=ctx) - f.connect('127.0.0.1', 39021) - f.auth_tls() - f.set_pasv(0) - f.login('ftp', 'ngps@') - f.prot_p() - f.retrlines('LIST') - f.quit() - - -if __name__ == '__main__': - threading.init() - active() - passive() - threading.cleanup() - diff --git a/demo/ssl/http_cli_20.py b/demo/ssl/http_cli_20.py deleted file mode 100644 index 0ce4cef..0000000 --- a/demo/ssl/http_cli_20.py +++ /dev/null @@ -1,22 +0,0 @@ -import httplib, sys - -def test_httplib(): - h = httplib.HTTPConnection('127.0.0.1', 80) - h.set_debuglevel(1) - h.putrequest('GET', '/') - h.putheader('Accept', 'text/html') - h.putheader('Accept', 'text/plain') - h.putheader('Connection', 'close') - h.endheaders() - resp = h.getresponse() - f = resp.fp - while 1: - data = f.readline() - if not data: - break - sys.stdout.write(data) - f.close() - h.close() - -if __name__=='__main__': - test_httplib() diff --git a/demo/ssl/https_cli.py b/demo/ssl/https_cli.py deleted file mode 100644 index 543ba8f..0000000 --- a/demo/ssl/https_cli.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python - -"""Demonstrations of M2Crypto.httpslib. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -import sys -from M2Crypto import Rand, SSL, httpslib, threading - - -def test_httpslib(): - ctx = SSL.Context('sslv23') - ctx.load_cert_chain('client.pem') - ctx.load_verify_locations('ca.pem', '') - ctx.set_verify(SSL.verify_peer, 10) - ctx.set_info_callback() - h = httpslib.HTTPSConnection('localhost', 19443, ssl_context=ctx) - h.set_debuglevel(1) - h.putrequest('GET', '/') - h.putheader('Accept', 'text/html') - h.putheader('Accept', 'text/plain') - h.putheader('Connection', 'close') - h.endheaders() - resp = h.getresponse() - f = resp.fp - c = 0 - while 1: - # Either of following two works. - #data = f.readline(4096) - data = resp.read(4096) - if not data: break - c = c + len(data) - #print data - sys.stdout.write(data) - sys.stdout.flush() - f.close() - h.close() - -if __name__=='__main__': - Rand.load_file('../randpool.dat', -1) - #threading.init() - test_httpslib() - #threading.cleanup() - Rand.save_file('../randpool.dat') - diff --git a/demo/ssl/https_cli_async.py b/demo/ssl/https_cli_async.py deleted file mode 100644 index 9e7a5d0..0000000 --- a/demo/ssl/https_cli_async.py +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python - -"""Demo for client-side ssl_dispatcher usage. Note that connect() -is blocking. (Need fix?) - -This isn't really a HTTPS client; it's just a toy. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -import asyncore, sys, time -from M2Crypto import Rand, SSL - -class https_client(SSL.ssl_dispatcher): - - def __init__(self, host, path, ssl_ctx): - SSL.ssl_dispatcher.__init__(self) - self.path = path - self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % self.path - self.create_socket(ssl_ctx) - self.socket.connect((host, 19443)) - self._can_read = 1 - self._count = 0 - - def handle_connect(self): - pass - - def readable(self): - return self._can_read - - def handle_read(self): - try: - result = self.recv() - if result is None: - return - elif result == '': - self._can_read = 0 - sys.stdout.write('%s: total: %5d\n' % (self.path, self._count,)) - sys.stdout.flush() - self.close() - else: - #print result - l = len(result) - self._count = self._count + l - display = (time.time(), l, self.path) - sys.stdout.write('%14.3f: read %5d from %s\n' % display) - sys.stdout.flush() - except SSL.SSLError, why: - print 'handle_read:', why - self.close() - raise - - def writable(self): - return (len(self.buffer) > 0) - - def handle_write(self): - try: - sent = self.send(self.buffer) - self.buffer = self.buffer[sent:] - except SSL.SSLError, why: - print 'handle_write:', why - self.close() - - -if __name__ == '__main__': - Rand.load_file('../randpool.dat', -1) - ctx = SSL.Context() - url = ('/jdk118/api/u-names.html', - '/postgresql/xfunc-c.html', - '/python2.1/modindex.html') - for u in url: - https_client('localhost', u, ctx) - asyncore.loop() - Rand.save_file('../randpool.dat') - - -# Here's a sample output. Server is Apache+mod_ssl on localhost. -# $ python https_cli_async.py -# 991501090.682: read 278 from /python2.1/modindex.html -# 991501090.684: read 278 from /postgresql/xfunc-c.html -# 991501090.742: read 4096 from /postgresql/xfunc-c.html -# 991501090.743: read 4096 from /postgresql/xfunc-c.html -# 991501090.744: read 4096 from /postgresql/xfunc-c.html -# 991501090.744: read 4096 from /postgresql/xfunc-c.html -# 991501090.755: read 4096 from /postgresql/xfunc-c.html -# 991501090.756: read 278 from /jdk118/api/u-names.html -# 991501090.777: read 4096 from /postgresql/xfunc-c.html -# 991501090.778: read 4096 from /postgresql/xfunc-c.html -# 991501090.778: read 4096 from /postgresql/xfunc-c.html -# 991501090.782: read 4096 from /postgresql/xfunc-c.html -# 991501090.813: read 4096 from /python2.1/modindex.html -# 991501090.839: read 4096 from /jdk118/api/u-names.html -# 991501090.849: read 4096 from /python2.1/modindex.html -# 991501090.873: read 3484 from /postgresql/xfunc-c.html -# 991501090.874: read 4096 from /jdk118/api/u-names.html -# 991501090.874: read 4096 from /python2.1/modindex.html -#/postgresql/xfunc-c.html: total: 40626 -# 991501090.886: read 4096 from /jdk118/api/u-names.html -# 991501090.886: read 2958 from /python2.1/modindex.html -# 991501090.887: read 4096 from /jdk118/api/u-names.html -#/python2.1/modindex.html: total: 15524 -# 991501090.893: read 4096 from /jdk118/api/u-names.html -# 991501090.894: read 2484 from /jdk118/api/u-names.html -#/jdk118/api/u-names.html: total: 23242 -# $ - - diff --git a/demo/ssl/https_srv.py b/demo/ssl/https_srv.py deleted file mode 100644 index 6d12d80..0000000 --- a/demo/ssl/https_srv.py +++ /dev/null @@ -1,150 +0,0 @@ -"""This server extends BaseHTTPServer and SimpleHTTPServer thusly: -1. One thread per connection. -2. Generates directory listings. - -In addition, it has the following properties: -1. Works over HTTPS only. -2. Displays SSL handshaking and SSL session info. -3. Performs SSL renegotiation when a magic url is requested. - -TODO: -1. Cache stat() of directory entries. -2. Fancy directory indexing. -3. Interface ZPublisher. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. -""" - -import os, sys -from SimpleHTTPServer import SimpleHTTPRequestHandler - -from M2Crypto import Rand, SSL -from M2Crypto.SSL.SSLServer import ThreadingSSLServer - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - - -def mkdirlist(path, url): - dirlist = os.listdir(path) - dirlist.sort() - f = StringIO() - f.write('Index listing for %s\r\n' % (url,)) - f.write('

    Index listing for %s

    \r\n' % (url,)) - f.write('
    \r\n')
    -    for d in dirlist:
    -        if os.path.isdir(os.path.join(path, d)):
    -            d2 = d + '/'
    -        else:
    -            d2 = d
    -        if url == '/':
    -            f.write('%s
    \r\n' % (d, d2)) - else: - f.write('%s
    \r\n' % (url, d, d2)) - f.write('
    \r\n\r\n') - f.reset() - return f - - -class HTTP_Handler(SimpleHTTPRequestHandler): - - server_version = "https_srv/0.1" - reneg = 0 - - # Cribbed from SimpleHTTPRequestHander to add the ".der" entry, - # which facilitates installing your own certificates into browsers. - extensions_map = { - '': 'text/plain', # Default, *must* be present - '.html': 'text/html', - '.htm': 'text/html', - '.gif': 'image/gif', - '.jpg': 'image/jpeg', - '.jpeg': 'image/jpeg', - '.der': 'application/x-x509-ca-cert' - } - - def send_head(self): - if self.path[1:8] == '_reneg_': - self.reneg = 1 - self.path = self.path[8:] - path = self.translate_path(self.path) - if os.path.isdir(path): - f = mkdirlist(path, self.path) - filetype = 'text/html' - else: - try: - f = open(path, 'rb') - filetype = self.guess_type(path) - except IOError: - self.send_error(404, "File not found") - return None - self.send_response(200) - self.send_header("Content-type", filetype) - self.end_headers() - return f - - def do_GET(self): - #sess = self.request.get_session() - #self.log_message('\n%s', sess.as_text()) - f = self.send_head() - if self.reneg: - self.reneg = 0 - self.request.renegotiate() - sess = self.request.get_session() - self.log_message('\n%s', sess.as_text()) - if f: - self.copyfile(f, self.wfile) - f.close() - - def do_HEAD(self): - #sess = self.request.get_session() - #self.log_message('\n%s', sess.as_text()) - f = self.send_head() - if f: - f.close() - - -class HTTPS_Server(ThreadingSSLServer): - def __init__(self, server_addr, handler, ssl_ctx): - ThreadingSSLServer.__init__(self, server_addr, handler, ssl_ctx) - self.server_name = server_addr[0] - self.server_port = server_addr[1] - - def finish(self): - self.request.set_shutdown(SSL.SSL_RECEIVED_SHUTDOWN | SSL.SSL_SENT_SHUTDOWN) - self.request.close() - - -def init_context(protocol, certfile, cafile, verify, verify_depth=10): - ctx=SSL.Context(protocol) - ctx.load_cert(certfile) - ctx.load_client_ca(cafile) - ctx.load_verify_info(cafile) - ctx.set_verify(verify, verify_depth) - ctx.set_allow_unknown_ca(1) - ctx.set_session_id_ctx('https_srv') - ctx.set_info_callback() - return ctx - - -if __name__ == '__main__': - from M2Crypto import threading as m2threading - m2threading.init() - if len(sys.argv) < 2: - wdir = '.' - else: - wdir = sys.argv[1] - Rand.load_file('../randpool.dat', -1) - ctx = init_context('sslv23', 'server.pem', 'ca.pem', \ - SSL.verify_none) - #SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) - ctx.set_tmp_dh('dh1024.pem') - os.chdir(wdir) - httpsd = HTTPS_Server(('', 19443), HTTP_Handler, ctx) - httpsd.serve_forever() - Rand.save_file('../randpool.dat') - m2threading.cleanup() - - diff --git a/demo/ssl/myapp.py b/demo/ssl/myapp.py deleted file mode 100644 index bb024d8..0000000 --- a/demo/ssl/myapp.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Sample application for socklib and somelib. - -Copyright (c) 2007 Open Source Applications Foundation. -All rights reserved. -""" - -# Sample application that uses socklib to override socket.ssl in order -# to make the 3rd party library use M2Crypto for SSL, instead of python -# stdlib SSL. - -import socklib # sets M2Crypto.SSL.Connection as socket.ssl - -# Set up the secure context for socklib -from M2Crypto import SSL - -def getContext(): - ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) - ctx.load_verify_locations('ca.pem') - return ctx - -socklib.setSSLContextFactory(getContext) - -# Import and use 3rd party lib -import somelib - -if __name__ == '__main__': - c = somelib.HttpsGetSlash() - c.get('verisign.com', 443) diff --git a/demo/ssl/s_client.py b/demo/ssl/s_client.py deleted file mode 100644 index 021e3db..0000000 --- a/demo/ssl/s_client.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python - -"""An M2Crypto implementation of OpenSSL's s_client. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from socket import * -import getopt -import string -import sys - -from M2Crypto import SSL - -# s_server -www -HOST='127.0.0.1' -PORT=4433 -REQ='GET / HTTP/1.0\r\n\r\n' - -class Config: - pass - -def config(args): - options=['connect=', 'verify=', 'cert=', 'key=', 'CApath=', 'CAfile=', \ - 'reconnect', 'pause', 'showcerts', 'debug', 'nbio_test', 'state', \ - 'nbio', 'crlf', 'sslv2', 'sslv3', 'tlsv1', 'no_sslv2', 'no_sslv3', \ - 'no_tlsv1', 'bugs', 'cipher=', 'Verify='] - optlist, optarg=getopt.getopt(args, '', options) - - cfg=Config() - for opt in optlist: - setattr(cfg, opt[0][2:], opt[1]) - for x in (('tlsv1','no_tlsv1'),('sslv3','no_sslv3'),('sslv2','no_sslv2')): - if hasattr(cfg, x[0]) and hasattr(cfg, x[1]): - raise ValueError, 'mutually exclusive: %s and %s' % x - - if hasattr(cfg, 'connect'): - (host, port)=string.split(cfg.connect, ':') - cfg.connect=(host, int(port)) - else: - cfg.connect=(HOST, PORT) - - cfg.protocol=[] - # First protocol found will be used. - # Permutate the following tuple for preference. - for p in ('tlsv1', 'sslv3', 'sslv2'): - if hasattr(cfg, p): - cfg.protocol.append(p) - cfg.protocol.append('sslv23') - - return cfg - -def make_context(config): - ctx=SSL.Context(config.protocol[0]) - if hasattr(config, 'cert'): - cert=config.cert - else: - cert='client.pem' - if hasattr(config, 'key'): - key=config.key - else: - key='client.pem' - #ctx.load_cert(cert, key) - - if hasattr(config, 'verify'): - verify=SSL.verify_peer - depth=int(config.verify) - elif hasattr(config, 'Verify'): - verify=SSL.verify_peer | SSL.verify_fail_if_no_peer_cert - depth=int(config.Verify) - else: - verify=SSL.verify_none - depth=10 - config.verify=verify - config.verify_depth=depth - ctx.set_verify(verify, depth) - - if hasattr(config, 'CAfile'): - cafile=config.CAfile - else: - cafile='ca.pem' - ctx.load_verify_location(cafile) - - return ctx - -def s_client(config): - ctx=make_context(config) - s=SSL.Connection(ctx) - s.connect(config.connect) - if config.verify != SSL.verify_none and not s.verify_ok(): - print 'peer verification failed' - peer=s.get_peer_cert() - if peer is None: - print 'unable to get peer certificate' - else: - print 'peer.as_text()' - raise SystemExit - s.send(REQ) - while 1: - data=s.recv() - if not data: - break - print data - s.close() - -if __name__=='__main__': - cfg=config(sys.argv[1:]) - s_client(cfg) - diff --git a/demo/ssl/s_server.py b/demo/ssl/s_server.py deleted file mode 100644 index 84789a1..0000000 --- a/demo/ssl/s_server.py +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/env python - -"""An M2Crypto implementation of OpenSSL's s_server. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from socket import * -import asyncore -import cStringIO -import getopt -import string -import sys - -from M2Crypto import SSL, BIO, DH, Err - -# s_server -www -HOST='' -PORT=4433 - -class Config: - pass - -def config(args): - options=['accept=', 'context=', 'verify=', 'Verify=', 'cert=', 'key=', \ - 'dcert=', 'dkey=', 'nocert', 'crlf', 'debug', 'CApath=', 'CAfile=', \ - 'quiet', 'no_tmp_rsa', 'state', 'sslv2', 'sslv3', 'tlsv1', \ - 'no_sslv2', 'no_sslv3', 'no_tlsv1', 'bugs', 'cipher='] - optlist, optarg=getopt.getopt(args, '', options) - - cfg=Config() - for opt in optlist: - setattr(cfg, opt[0][2:], opt[1]) - for x in (('tlsv1','no_tlsv1'),('sslv3','no_sslv3'),('sslv2','no_sslv2')): - if hasattr(cfg, x[0]) and hasattr(cfg, x[1]): - raise ValueError, 'mutually exclusive: %s and %s' % x - - if hasattr(cfg, 'accept'): - cfg.accept=string.split(cfg.connect, ':') - else: - cfg.accept=(HOST, PORT) - - cfg.protocol=[] - # First protocol found will be used. - # Permutate the following tuple for preference. - for p in ('tlsv1', 'sslv3', 'sslv2'): - if hasattr(cfg, p): - cfg.protocol.append(p) - cfg.protocol.append('sslv23') - - return cfg - -RESP_HEAD="""\ -HTTP/1.0 200 ok -Content-type: text/html - - -
    -
    -Emulating s_server -www
    -Ciphers supported in s_server.py
    -"""
    -
    -RESP_TAIL="""\
    -
    - -""" - -class channel(SSL.ssl_dispatcher): - - def __init__(self, conn, debug): - SSL.ssl_dispatcher.__init__(self, conn) - self.socket.setblocking(0) - self.buffer=self.fixup_buffer() - self.debug=debug - - def fixup_buffer(self): - even=0 - buffer=cStringIO.StringIO() - buffer.write(RESP_HEAD) - for c in self.get_ciphers(): - # This formatting works for around 80 columns. - buffer.write('%-11s:%-28s' % (c.version(), c.name())) - if even: - buffer.write('\r\n') - even=1-even - buffer.write('\r\n%s' % RESP_TAIL) - return buffer.getvalue() - - def handle_connect(self): - pass - - def handle_close(self): - self.close() - - def handle_error(self, exc_type, exc_value, exc_traceback): - if self.debug: - print 'handle_error()' - #print exc_type, exc_value, exc_traceback - print Err.get_error() - self.handle_close() - - - def writeable(self): - return len(self.buffer) - - def handle_write(self): - n=self.send(self.buffer) - if n==-1: - pass - elif n==0: - self.handle_close() - else: - self.buffer=self.buffer[n:] - if self.debug: - print 'handle_write():', n - - def readable(self): - return 1 - - def handle_read(self): - blob=self.recv() - if blob is None: - pass - elif blob=='': - self.handle_close() - else: - pass - if self.debug: - print 'handle_read():', blob - - -class server(SSL.ssl_dispatcher): - - channel_class=channel - - def __init__(self, addr, port, config, ssl_context): - asyncore.dispatcher.__init__(self) - self.create_socket(ssl_context) - self.set_reuse_addr() - self.socket.setblocking(0) - self.bind((addr, port)) - self.listen(5) - self.config=config - self.debug=config.debug - self.ssl_ctx=ssl_context - - def handle_accept(self): - sock, addr=self.accept() - print self.ssl_ctx.get_verify_mode() - if (self.ssl_ctx.get_verify_mode() is SSL.verify_none) or sock.verify_ok(): - self.channel_class(sock, self.debug) - else: - print 'client verification failed' - sock.close() - - def writeable(self): - return 0 - -def s_server(config): - ctx=SSL.Context(config.protocol[0]) - - if hasattr(config, 'debug'): - config.debug=1 - else: - config.debug=0 - - if hasattr(config, 'cert'): - cert=config.cert - else: - cert='server.pem' - if hasattr(config, 'key'): - cert=config.key - else: - cert='server.pem' - ctx.load_cert(cert) - - if hasattr(config, 'CAfile'): - cafile=config.CAfile - else: - cafile='ca.pem' - ctx.load_verify_location(cafile) - - if hasattr(config, 'verify'): - verify=SSL.verify_peer - depth=int(config.verify) - elif hasattr(config, 'Verify'): - verify=SSL.verify_peer | SSL.verify_fail_if_no_peer_cert - depth=int(config.Verify) - else: - verify=SSL.verify_none - depth=0 - ctx.set_verify(verify, depth) - - ctx.set_tmp_dh('dh1024.pem') - #ctx.set_info_callback() - - server(cfg.accept[0], cfg.accept[1], cfg, ctx) - asyncore.loop() - -if __name__=='__main__': - cfg=config(sys.argv[1:]) - s_server(cfg) - diff --git a/demo/ssl/server.pem b/demo/ssl/server.pem deleted file mode 100644 index 1ee9282..0000000 --- a/demo/ssl/server.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx -NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls -b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c -kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 -KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp -/y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 -QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB -H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 -du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv -MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm -aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t -ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy -lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW -iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 -0QkPQNdP ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu -6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe -I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB -AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ -u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 -xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 -1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp -IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx -luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I -lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS -38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy -v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z -DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= ------END RSA PRIVATE KEY----- diff --git a/demo/ssl/server3.py b/demo/ssl/server3.py deleted file mode 100644 index 99fbe97..0000000 --- a/demo/ssl/server3.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python -""" -server3 from the book 'Network Security with OpenSSL', but modified to -Python/M2Crypto from the original C implementation. - -Copyright (c) 2004-2005 Open Source Applications Foundation. -Author: Heikki Toivonen -""" -from M2Crypto import SSL, Rand, threading, DH -import thread -from socket import * - -verbose_debug = 1 - -def verify_callback(ok, store): - if not ok: - print "***Verify Not ok" - return ok - -dh1024 = None - -def init_dhparams(): - global dh1024 - dh1024 = DH.load_params('dh1024.pem') - -def tmp_dh_callback(ssl, is_export, keylength): - global dh1024 - if not dh1024: - init_dhparams() - return dh1024._ptr() - -def setup_server_ctx(): - ctx = SSL.Context('sslv23') - if ctx.load_verify_locations('ca.pem') != 1: - print "***No CA file" - #if ctx.set_default_verify_paths() != 1: - # print "***No default verify paths" - ctx.load_cert_chain('server.pem') - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, - 10, verify_callback) - ctx.set_options(SSL.op_all | SSL.op_no_sslv2) - ctx.set_tmp_dh_callback(tmp_dh_callback) - #ctx.set_tmp_dh('dh1024.pem') - if ctx.set_cipher_list('ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH') != 1: - print "***No valid ciphers" - if verbose_debug: - ctx.set_info_callback() - return ctx - -def post_connection_check(peerX509, expectedHost): - if peerX509 is None: - print "***No peer certificate" - # Not sure if we can do any other checks - return 1 - -def do_server_loop(conn): - while 1: - try: - buf = conn.read() - if not buf: - break - print buf - except SSL.SSLError, what: - if str(what) == 'unexpected eof': - break - else: - raise - except: - break - - if conn.get_shutdown(): - return 1 - return 0 - -# How about something like: -#def server_thread(ctx, ssl, addr): -# conn = SSL.Connection(ctx, None) -# conn.ssl = ssl -# conn.setup_addr(addr) -def server_thread(ctx, sock, addr): - conn = SSL.Connection(ctx, sock) - conn.set_post_connection_check_callback(post_connection_check) - conn.setup_addr(addr) - conn.set_accept_state() - conn.setup_ssl() - conn.accept_ssl() - - post_connection_check(conn) - - print 'SSL Connection opened' - if do_server_loop(conn): - conn.close() - else: - conn.clear() - print 'SSL Connection closed' - - -if __name__=='__main__': - threading.init() - Rand.load_file('../randpool.dat', -1) - - ctx = setup_server_ctx() - - # How about something like this? - #conn_root = SSL.Connection(ctx) - #conn_root.bind(('127.0.0.1', 9999)) - #conn_root.listen(5) - #while 1: - # ssl, addr = conn_root.accept() - # thread.start_new_thread(server_thread, (ctx, ssl, addr)) - - sock = socket(AF_INET, SOCK_STREAM) - sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) - sock.bind(('', 9999)) - sock.listen(5) - while 1: - conn, addr = sock.accept() - thread.start_new_thread(server_thread, (ctx, conn, addr)) - - Rand.save_file('../randpool.dat') - threading.cleanup() diff --git a/demo/ssl/sess.py b/demo/ssl/sess.py deleted file mode 100644 index 23428fc..0000000 --- a/demo/ssl/sess.py +++ /dev/null @@ -1,89 +0,0 @@ -"""M2Crypto.SSL.Session client demo: This program requests a URL from -a HTTPS server, saves the negotiated SSL session id, parses the HTML -returned by the server, then requests each HREF in a separate thread -using the saved SSL session id. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import Err, Rand, SSL, X509, threading -m2_threading = threading; del threading - -import formatter, getopt, htmllib, sys -from threading import Thread -from socket import gethostname - - -def handler(sslctx, host, port, href, recurs=0, sslsess=None): - - s = SSL.Connection(sslctx) - if sslsess: - s.set_session(sslsess) - s.connect((host, port)) - else: - s.connect((host, port)) - sslsess = s.get_session() - #print sslsess.as_text() - - if recurs: - p = htmllib.HTMLParser(formatter.NullFormatter()) - - f = s.makefile("rw") - f.write(href) - f.flush() - - while 1: - data = f.read() - if not data: - break - if recurs: - p.feed(data) - - if recurs: - p.close() - - f.close() - - if recurs: - for a in p.anchorlist: - req = 'GET %s HTTP/1.0\r\n\r\n' % a - thr = Thread(target=handler, - args=(sslctx, host, port, req, recurs-1, sslsess)) - print "Thread =", thr.getName() - thr.start() - - -if __name__ == '__main__': - - m2_threading.init() - Rand.load_file('../randpool.dat', -1) - - host = '127.0.0.1' - port = 9443 - req = '/' - - optlist, optarg = getopt.getopt(sys.argv[1:], 'h:p:r:') - for opt in optlist: - if '-h' in opt: - host = opt[1] - elif '-p' in opt: - port = int(opt[1]) - elif '-r' in opt: - req = opt[1] - - ctx = SSL.Context('sslv3') - ctx.load_cert('client.pem') - ctx.load_verify_info('ca.pem') - ctx.load_client_ca('ca.pem') - ctx.set_verify(SSL.verify_none, 10) - - req = 'GET %s HTTP/1.0\r\n\r\n' % req - - start = Thread(target=handler, args=(ctx, host, port, req, 1)) - print "Thread =", start.getName() - start.start() - start.join() - - m2_threading.cleanup() - Rand.save_file('../randpool.dat') - - diff --git a/demo/ssl/sess2.py b/demo/ssl/sess2.py deleted file mode 100644 index a3c2bf4..0000000 --- a/demo/ssl/sess2.py +++ /dev/null @@ -1,78 +0,0 @@ -"""M2Crypto.SSL.Session client demo2: This program creates two sockets, each -bound to a different local address. The first creates an SSL connection, the -second then creates another SSL connection using the first's SSL session id. - -(This program only works if you've ifconfig'ed your interfaces correctly, -of course.) - -Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import Err, Rand, SSL, X509, threading -m2_threading = threading; del threading - -import formatter, getopt, htmllib, sys -from threading import Thread -from socket import gethostname - -ADDR1 = '127.0.0.1', 9999 -ADDR2 = '127.0.0.2', 9999 - -def handler(addr, sslctx, host, port, req, sslsess=None): - - s = SSL.Connection(sslctx) - s.bind(addr) - if sslsess: - s.set_session(sslsess) - s.connect((host, port)) - else: - s.connect((host, port)) - sslsess = s.get_session() - s.write(req) - while 1: - data = s.read(4096) - if not data: - break - - if addr != ADDR2: - thr = Thread(target=handler, - args=(ADDR2, sslctx, host, port, req, sslsess)) - print "Thread =", thr.getName() - thr.start() - - s.close() - - -if __name__ == '__main__': - - m2_threading.init() - Rand.load_file('../randpool.dat', -1) - - host = '127.0.0.1' - port = 443 - req = '/' - - optlist, optarg = getopt.getopt(sys.argv[1:], 'h:p:r:') - for opt in optlist: - if '-h' in opt: - host = opt[1] - elif '-p' in opt: - port = int(opt[1]) - elif '-r' in opt: - req = opt[1] - - ctx = SSL.Context('sslv3') - ctx.load_cert('client.pem') - ctx.load_verify_info('ca.pem') - ctx.set_verify(SSL.verify_none, 10) - - req = 'GET %s HTTP/1.0\r\n\r\n' % req - - start = Thread(target=handler, args=(ADDR1, ctx, host, port, req)) - print "Thread =", start.getName() - start.start() - start.join() - - m2_threading.cleanup() - Rand.save_file('../randpool.dat') - - diff --git a/demo/ssl/sess2.ssldump.out b/demo/ssl/sess2.ssldump.out deleted file mode 100644 index 9b383ee..0000000 --- a/demo/ssl/sess2.ssldump.out +++ /dev/null @@ -1,112 +0,0 @@ -New TCP connection #1: localhost(9999) <-> localhost(443) -1 1 0.0061 (0.0061) C>S Handshake - ClientHello - Version 3.0 - cipher suites - SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA - SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA - SSL_RSA_WITH_3DES_EDE_CBC_SHA - SSL_DHE_DSS_WITH_RC4_128_SHA - SSL_RSA_WITH_IDEA_CBC_SHA - SSL_RSA_WITH_RC4_128_SHA - SSL_RSA_WITH_RC4_128_MD5 - SSL_DHE_DSS_WITH_RC2_56_CBC_SHA - SSL_RSA_EXPORT1024_WITH_RC4_56_SHA - SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA - SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA - SSL_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 - SSL_RSA_EXPORT1024_WITH_RC4_56_MD5 - SSL_DHE_RSA_WITH_DES_CBC_SHA - SSL_DHE_DSS_WITH_DES_CBC_SHA - SSL_RSA_WITH_DES_CBC_SHA - SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA - SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA - SSL_RSA_EXPORT_WITH_DES40_CBC_SHA - SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 - SSL_RSA_EXPORT_WITH_RC4_40_MD5 - compression methods - NULL -1 2 0.0068 (0.0006) S>C Handshake - ServerHello - Version 3.0 - session_id[32]= - f2 6e ab c1 e6 db fa 55 4d 77 97 be 0d 28 23 fe - 53 8a d5 3b 31 58 1d 93 35 65 10 a9 06 6b a2 a6 - cipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA - compressionMethod NULL -1 3 0.0846 (0.0778) S>C Handshake - Certificate -1 4 0.0848 (0.0001) S>C Handshake - ServerKeyExchange -1 5 0.0848 (0.0000) S>C Handshake - ServerHelloDone -1 6 0.2475 (0.1627) C>S Handshake - ClientKeyExchange - DiffieHellmanClientPublicValue[128]= - 3c 8f 0f 93 8a 3a 1e 5c 07 cf 40 2f 7d bf 25 7a - e8 2b ba 54 46 d5 54 40 22 90 38 f2 88 c3 62 8a - ec b1 b7 f1 06 6d fa ba 46 dd f1 92 5f 44 18 44 - 8e df 33 30 64 79 e0 77 07 1f bc 10 dc 0d 6e 4b - 4d 68 01 af 4a bf 83 62 de 87 d7 98 6c e3 9b af - a2 a6 60 67 18 46 89 29 fa 1a 72 df 92 2d 9e 4f - 2c b2 02 b3 ef b7 03 07 49 69 c5 b2 37 ae a1 0e - 10 e1 79 25 a4 70 02 15 69 d9 47 2c c8 48 23 67 -1 7 0.2475 (0.0000) C>S ChangeCipherSpec -1 8 0.2475 (0.0000) C>S Handshake -1 9 0.3239 (0.0763) S>C ChangeCipherSpec -1 10 0.3239 (0.0000) S>C Handshake -1 11 0.3266 (0.0027) C>S application_data -1 12 0.3566 (0.0299) S>C application_data -1 13 0.3571 (0.0005) S>C Alert -1 0.3574 (0.0003) S>C TCP FIN -New TCP connection #2: 127.0.0.2(9999) <-> localhost(443) -2 1 0.0039 (0.0039) C>S Handshake - ClientHello - Version 3.0 - resume [32]= - f2 6e ab c1 e6 db fa 55 4d 77 97 be 0d 28 23 fe - 53 8a d5 3b 31 58 1d 93 35 65 10 a9 06 6b a2 a6 - cipher suites - SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA - SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA - SSL_RSA_WITH_3DES_EDE_CBC_SHA - SSL_DHE_DSS_WITH_RC4_128_SHA - SSL_RSA_WITH_IDEA_CBC_SHA - SSL_RSA_WITH_RC4_128_SHA - SSL_RSA_WITH_RC4_128_MD5 - SSL_DHE_DSS_WITH_RC2_56_CBC_SHA - SSL_RSA_EXPORT1024_WITH_RC4_56_SHA - SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA - SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA - SSL_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 - SSL_RSA_EXPORT1024_WITH_RC4_56_MD5 - SSL_DHE_RSA_WITH_DES_CBC_SHA - SSL_DHE_DSS_WITH_DES_CBC_SHA - SSL_RSA_WITH_DES_CBC_SHA - SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA - SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA - SSL_RSA_EXPORT_WITH_DES40_CBC_SHA - SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 - SSL_RSA_EXPORT_WITH_RC4_40_MD5 - compression methods - NULL -2 2 0.0055 (0.0016) S>C Handshake - ServerHello - Version 3.0 - session_id[32]= - f2 6e ab c1 e6 db fa 55 4d 77 97 be 0d 28 23 fe - 53 8a d5 3b 31 58 1d 93 35 65 10 a9 06 6b a2 a6 - cipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA - compressionMethod NULL -2 3 0.0055 (0.0000) S>C ChangeCipherSpec -2 4 0.0055 (0.0000) S>C Handshake -2 5 0.0066 (0.0010) C>S ChangeCipherSpec -2 6 0.0066 (0.0000) C>S Handshake -1 14 0.3698 (0.0124) C>S Alert -1 0.3702 (0.0004) C>S TCP FIN -2 7 0.0996 (0.0930) C>S application_data -2 8 0.1224 (0.0227) S>C application_data -2 9 0.1244 (0.0019) S>C Alert -2 10 0.1248 (0.0004) C>S Alert -2 0.1254 (0.0005) C>S TCP FIN -2 0.1300 (0.0046) S>C TCP FIN diff --git a/demo/ssl/socklib.py b/demo/ssl/socklib.py deleted file mode 100644 index ebaf6d3..0000000 --- a/demo/ssl/socklib.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -socklib provides a way to transparently replace socket.ssl with -M2Crypto.SSL.Connection. - -Usage: Import socklib before the 3rd party module that uses socket.ssl. Also, - call socketlib.setSSLContextFactory() to set it up with a way to get - secure SSL contexts. - -Copyright (c) 2007 Open Source Applications Foundation. -All rights reserved. -""" - -sslContextFactory = None - -def setSSLContextFactory(factory): - global sslContextFactory - sslContextFactory = factory - -from M2Crypto.SSL import Connection, Checker -import socket - -class ssl_socket(socket.socket): - def connect(self, addr, *args): - self.addr = addr - return super(ssl_socket, self).connect(addr, *args) - - def close(self): - if hasattr(self, 'conn'): - self.conn.close() - socket.socket.close(self) - -def ssl(sock): - sock.conn = Connection(ctx=sslContextFactory(), sock=sock) - sock.conn.addr = sock.addr - sock.conn.setup_ssl() - sock.conn.set_connect_state() - sock.conn.connect_ssl() - check = getattr(sock.conn, 'postConnectionCheck', sock.conn.clientPostConnectionCheck) - if check is not None: - if not check(sock.conn.get_peer_cert(), sock.conn.addr[0]): - raise Checker.SSLVerificationError, 'post connection check failed' - return sock.conn - -socket.socket = ssl_socket -socket.ssl = ssl - diff --git a/demo/ssl/somelib.py b/demo/ssl/somelib.py deleted file mode 100644 index 21b3491..0000000 --- a/demo/ssl/somelib.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Sample 3rd party lib to use with socklib and myapp. - -Copyright (c) 2007 Open Source Applications Foundation. -All rights reserved. -""" -# This represents some 3rd party library we don't want to modify - -import socket - -class HttpsGetSlash(object): - def __init__(self): - self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - def get(self, host, port): - self.socket.connect((host, port)) - ssl_sock = socket.ssl(self.socket) - ssl_sock.write('GET / HTTP/1.0\n\n') - print ssl_sock.read() - self.socket.close() \ No newline at end of file diff --git a/demo/ssl/ss.py b/demo/ssl/ss.py deleted file mode 100644 index 3db6752..0000000 --- a/demo/ssl/ss.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python - -import os, popen2, time -from socket import * - -def main0(): - cin, cout = popen2.popen2('openssl s_server') - cout.write('Q\n') - cout.flush() - s = socket(AF_INET, SOCK_STREAM) - s.connect(('', 4433)) - s.close() - -def main(): - pid = os.fork() - if pid: - time.sleep(1) - os.kill(pid, 1) - os.waitpid(pid, 0) - else: - os.execvp('openssl', ('s_server',)) - -if __name__ == '__main__': - main() - diff --git a/demo/ssl/twistedsslclient.py b/demo/ssl/twistedsslclient.py deleted file mode 100755 index e4b79c0..0000000 --- a/demo/ssl/twistedsslclient.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -""" -Demonstrates M2Crypto.SSL.TwistedProtocolWrapper - -Copyright (c) 2005 Open Source Applications Foundation. All rights reserved. -""" - -import twisted.internet.protocol as protocol -import twisted.protocols.basic as basic -import twisted.internet.reactor as reactor -import M2Crypto.SSL.TwistedProtocolWrapper as wrapper -import M2Crypto.SSL as SSL - -class EchoClient(basic.LineReceiver): - def connectionMade(self): - self.sendLine('Hello World!') - - def lineReceived(self, line): - print 'received: "%s"' % line - self.transport.loseConnection() - - -class EchoClientFactory(protocol.ClientFactory): - protocol = EchoClient - - def clientConnectionFailed(self, connector, reason): - print 'connection failed' - reactor.stop() - - def clientConnectionLost(self, connector, reason): - print 'connection lost' - reactor.stop() - - -class ContextFactory: - def getContext(self): - return SSL.Context() - - -if __name__ == '__main__': - factory = EchoClientFactory() - wrapper.connectSSL('localhost', 8000, factory, ContextFactory()) - reactor.run() # This will block until reactor.stop() is called diff --git a/demo/ssl/twistedsslserver.py b/demo/ssl/twistedsslserver.py deleted file mode 100755 index 04897a0..0000000 --- a/demo/ssl/twistedsslserver.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python -""" -Demonstrates M2Crypto.SSL.TwistedProtocolWrapper - -Copyright (c) 2005 Open Source Applications Foundation. All rights reserved. -""" - -import sys -import M2Crypto.SSL as SSL -import M2Crypto.SSL.TwistedProtocolWrapper as wrapper -import twisted.internet.protocol as protocol -import twisted.internet.reactor as reactor -import twisted.python.log as log - - -class Echo(protocol.Protocol): - def dataReceived(self, data): - print 'received: "%s"' % data - self.transport.write(data) - - def connectionMade(self): - print 'connection made' - - -class ContextFactory: - def getContext(self): - ctx = SSL.Context() - ctx.load_cert('server.pem') - return ctx - - -if __name__ == '__main__': - log.startLogging(sys.stdout) - factory = protocol.Factory() - factory.protocol = Echo - wrapper.listenSSL(8000, factory, ContextFactory()) - reactor.run() diff --git a/demo/ssl/xmlrpc_cli.py b/demo/ssl/xmlrpc_cli.py deleted file mode 100644 index 69647d7..0000000 --- a/demo/ssl/xmlrpc_cli.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -"""Demonstration of M2Crypto.xmlrpclib2. - -Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" - -from M2Crypto import Rand -from M2Crypto.m2xmlrpclib import Server, SSL_Transport - -def ZServerSSL(): - # Server is Zope-2.6.4 on ZServerSSL/0.12. - zs = Server('https://127.0.0.1:8443/', SSL_Transport()) - print zs.propertyMap() - -def xmlrpc_srv(): - # Server is ../https/START_xmlrpc.py or ./xmlrpc_srv.py. - zs = Server('https://127.0.0.1:39443', SSL_Transport()) - print zs.Testing(1, 2, 3) - print zs.BringOn('SOAP') - -if __name__ == '__main__': - Rand.load_file('../randpool.dat', -1) - #ZServerSSL() - xmlrpc_srv() - Rand.save_file('../randpool.dat') - diff --git a/demo/ssl/xmlrpc_srv.py b/demo/ssl/xmlrpc_srv.py deleted file mode 100644 index 3811992..0000000 --- a/demo/ssl/xmlrpc_srv.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Server demonstration of M2Crypto.xmlrpclib2. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -# M2Crypto -from M2Crypto import DH, SSL -from echod_lib import init_context - -# /F's xmlrpcserver.py. -from xmlrpcserver import RequestHandler - -class xmlrpc_handler(RequestHandler): - def call(self, method, params): - print "XMLRPC call:", method, params - return params - - def finish(self): - self.request.set_shutdown(SSL.SSL_RECEIVED_SHUTDOWN | SSL.SSL_SENT_SHUTDOWN) - self.request.close() - -if __name__ == '__main__': - ctx = init_context('sslv23', 'server.pem', 'ca.pem', SSL.verify_none) - ctx.set_tmp_dh('dh1024.pem') - s = SSL.ThreadingSSLServer(('', 9443), xmlrpc_handler, ctx) - s.serve_forever() - diff --git a/demo/tinderbox/build_lib.py b/demo/tinderbox/build_lib.py deleted file mode 100644 index 2babb14..0000000 --- a/demo/tinderbox/build_lib.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright (c) 2006-2007 Open Source Applications Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Trimmed down for M2Crypto build purposes - -import os, sys -import glob -import fnmatch -import shutil -import fileinput -import errno -import subprocess -import killableprocess -import tempfile - - -_logFilename = 'tbox.log' -_logPrefix = '' -_logFile = None -_logEcho = True -_logEchoErrors = False - - -def initLog(filename, prefix='', echo=True, echoErrors=False): - """ - Initialize log file and store log parameters - - Note: initLog assumes it is called only once per program - """ - global _logFilename, _logPrefix, _logFile, _logEcho, _logEchoErrors - - _logFilename = filename or _logFilename - _logEcho = echo - _logEchoErrors = echoErrors - _logPrefix = prefix - - try: - _logFile = open(_logFilename, 'w+') - result = True - except: - result = False - - return result - - -def closeLog(): - """Need to close log to flush all data.""" - _logFile.close() - - -def log(msg, error=False, newline='\n'): - """ - Output log message to an open log file or to StdOut - """ - echo = _logEcho - - if _logFile is None: - if error or _logEcho: - echo = True - else: - _logFile.write('%s%s%s' % (_logPrefix, msg, newline)) - - if error and _logEchoErrors: - sys.stderr.write('%s%s%s' % (_logPrefix, msg, newline)) - - if echo: - sys.stdout.write('%s%s%s' % (_logPrefix, msg, newline)) - sys.stdout.flush() - - -def setpgid_preexec_fn(): - os.setpgid(0, 0) - - -def runCommand(cmd, env=None, timeout=-1, logger=log, ignorepreexec=False): - """ - Execute the given command and log all output - - Success and failure codes: - - >>> runCommand(['true']) - 0 - >>> runCommand(['false']) - 1 - - Interleaved stdout and stderr messages: - - >>> runCommand(['python', '-c', r'print 1;import sys;sys.stdout.flush();print >>sys.stderr, 2;print 3']) - 1 - 2 - 3 - 0 - - Now with timeout: - - >>> runCommand(['python', '-c', r'print 1;import sys;sys.stdout.flush();print >>sys.stderr, 2;print 3'], timeout=5) - 1 - 2 - 3 - 0 - - Setting environment variable: - - >>> runCommand(['python', '-c', 'import os;print os.getenv("ENVTEST")'], env={'ENVTEST': '42'}) - 42 - 0 - - Timeout: - >>> runCommand(['sleep', '60'], timeout=5) - -9 - """ - redirect = True - - if logger == log and _logFile is None: - redirect = False - else: - if timeout == -1: - output = subprocess.PIPE - else: - output = tempfile.TemporaryFile() - - if ignorepreexec: - preexec_fn = None - else: - preexec_fn = setpgid_preexec_fn - - if redirect: - p = killableprocess.Popen(cmd, env=env, stdin=subprocess.PIPE, stdout=output, stderr=subprocess.STDOUT, preexec_fn=preexec_fn) - else: - p = killableprocess.Popen(cmd, env=env, stdin=subprocess.PIPE, preexec_fn=preexec_fn) - - try: - if timeout == -1 and redirect: - for line in p.stdout: - logger(line[:-1]) - - p.wait(timeout=timeout, group=True) - - except KeyboardInterrupt: - try: - p.kill(group=True) - - except OSError: - p.wait(30) - - if timeout != -1 and redirect: - output.seek(0) - for line in output: - logger(line[:-1]) - - return p.returncode diff --git a/demo/tinderbox/killableprocess.py b/demo/tinderbox/killableprocess.py deleted file mode 100644 index 9c4fdb0..0000000 --- a/demo/tinderbox/killableprocess.py +++ /dev/null @@ -1,212 +0,0 @@ -# killableprocess - subprocesses which can be reliably killed -# -# Parts of this module are copied from the subprocess.py file contained -# in the Python distribution. -# -# Copyright (c) 2003-2004 by Peter Astrand -# -# Additions and modifications written by Benjamin Smedberg -# are Copyright (c) 2006 by the Mozilla Foundation -# -# -# By obtaining, using, and/or copying this software and/or its -# associated documentation, you agree that you have read, understood, -# and will comply with the following terms and conditions: -# -# Permission to use, copy, modify, and distribute this software and -# its associated documentation for any purpose and without fee is -# hereby granted, provided that the above copyright notice appears in -# all copies, and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of the -# author not be used in advertising or publicity pertaining to -# distribution of the software without specific, written prior -# permission. -# -# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION -# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -r"""killableprocess - Subprocesses which can be reliably killed - -This module is a subclass of the builtin "subprocess" module. It allows -processes that launch subprocesses to be reliably killed on Windows (via the Popen.kill() method. - -It also adds a timeout argument to Wait() for a limited period of time before -forcefully killing the process. - -Note: On Windows, this module requires Windows 2000 or higher (no support for -Windows 95, 98, or NT 4.0). It also requires ctypes, which is bundled with -Python 2.5+ or available from http://python.net/crew/theller/ctypes/ -""" - -import subprocess -import sys -import os -import time -import types - -try: - from subprocess import CalledProcessError -except ImportError: - # Python 2.4 doesn't implement CalledProcessError - class CalledProcessError(Exception): - """This exception is raised when a process run by check_call() returns - a non-zero exit status. The exit status will be stored in the - returncode attribute.""" - def __init__(self, returncode, cmd): - self.returncode = returncode - self.cmd = cmd - def __str__(self): - return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) - -mswindows = (sys.platform == "win32") - -if mswindows: - import winprocess -else: - import signal - -def call(*args, **kwargs): - waitargs = {} - if "timeout" in kwargs: - waitargs["timeout"] = kwargs.pop("timeout") - - return Popen(*args, **kwargs).wait(**waitargs) - -def check_call(*args, **kwargs): - """Call a program with an optional timeout. If the program has a non-zero - exit status, raises a CalledProcessError.""" - - retcode = call(*args, **kwargs) - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = args[0] - raise CalledProcessError(retcode, cmd) - -if not mswindows: - def DoNothing(*args): - pass - -class Popen(subprocess.Popen): - if mswindows: - def _execute_child(self, args, executable, preexec_fn, close_fds, - cwd, env, universal_newlines, startupinfo, - creationflags, shell, - p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite): - if not isinstance(args, types.StringTypes): - args = subprocess.list2cmdline(args) - - if startupinfo is None: - startupinfo = winprocess.STARTUPINFO() - - if None not in (p2cread, c2pwrite, errwrite): - startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES - - startupinfo.hStdInput = int(p2cread) - startupinfo.hStdOutput = int(c2pwrite) - startupinfo.hStdError = int(errwrite) - if shell: - startupinfo.dwFlags |= winprocess.STARTF_USESHOWWINDOW - startupinfo.wShowWindow = winprocess.SW_HIDE - comspec = os.environ.get("COMSPEC", "cmd.exe") - args = comspec + " /c " + args - - # We create a new job for this process, so that we can kill - # the process and any sub-processes - self._job = winprocess.CreateJobObject() - - creationflags |= winprocess.CREATE_SUSPENDED - creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT - - hp, ht, pid, tid = winprocess.CreateProcess( - executable, args, - None, None, # No special security - 1, # Must inherit handles! - creationflags, - winprocess.EnvironmentBlock(env), - cwd, startupinfo) - - self._child_created = True - self._handle = hp - self._thread = ht - self.pid = pid - - winprocess.AssignProcessToJobObject(self._job, hp) - winprocess.ResumeThread(ht) - - if p2cread is not None: - p2cread.Close() - if c2pwrite is not None: - c2pwrite.Close() - if errwrite is not None: - errwrite.Close() - - def kill(self, group=True): - """Kill the process. If group=True, all sub-processes will also be killed.""" - if mswindows: - if group: - winprocess.TerminateJobObject(self._job, 127) - else: - winprocess.TerminateProcess(self._handle, 127) - self.returncode = 127 - else: - if sys.platform == 'cygwin': - cmd = "taskkill /f /pid " + str(self.pid) - if group: - cmd += " /t" - os.system(cmd) - elif group: - os.killpg(self.pid, signal.SIGKILL) - else: - os.kill(self.pid, signal.SIGKILL) - self.returncode = -9 - - def wait(self, timeout=-1, group=True): - """Wait for the process to terminate. Returns returncode attribute. - If timeout seconds are reached and the process has not terminated, - it will be forcefully killed. If timeout is -1, wait will not - time out.""" - - if self.returncode is not None: - return self.returncode - - if mswindows: - if timeout != -1: - timeout = timeout * 1000 - rc = winprocess.WaitForSingleObject(self._handle, timeout) - if rc == winprocess.WAIT_TIMEOUT: - self.kill(group) - else: - self.returncode = winprocess.GetExitCodeProcess(self._handle) - else: - if timeout == -1: - subprocess.Popen.wait(self) - return self.returncode - - starttime = time.time() - - # Make sure there is a signal handler for SIGCHLD installed - oldsignal = signal.signal(signal.SIGCHLD, DoNothing) - - while time.time() < starttime + timeout - 0.01: - pid, sts = os.waitpid(self.pid, os.WNOHANG) - if pid != 0: - self._handle_exitstatus(sts) - signal.signal(signal.SIGCHLD, oldsignal) - return self.returncode - - # time.sleep is interrupted by signals (good!) - newtimeout = timeout - time.time() + starttime - time.sleep(newtimeout) - self.kill(group) - signal.signal(signal.SIGCHLD, oldsignal) - subprocess.Popen.wait(self) - - return self.returncode diff --git a/demo/tinderbox/slave.py b/demo/tinderbox/slave.py deleted file mode 100755 index eaa64c0..0000000 --- a/demo/tinderbox/slave.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python -# -""" -This is a sample Tinderbox2 buildslave script. - -NOTE: WAIT at least 6 minutes after the last build before starting - the next build! - -Create config.ini file with the following contents: - -[build] -name = identify your build slave, for example Ubuntu 8.04 32-bit -;;optional fields: -;;uname = uname -a -;;swig = swig -version -;;cc = gcc --version -;;openssl = openssl version -;;python = python --version -;;clean = rm -fr m2crypto -;;svn = svn co http://svn.osafoundation.org/m2crypto/trunk m2crypto -;;patch = -;;build = python setup.py clean --all build -;; OR another way to do tests without setuptools: -;;build = PYTHONPATH=build/lib-something python tests/alltests.py -;;test = python setup.py test -;;wait = 3600 -;;timeout = 180 - -[email] -from = your email -to = Email Heikki Toivonen to get the address -user = smtp username -password = smtp password -server = smtp server -port = smtp port -""" - -import time, smtplib, os, ConfigParser, tempfile -import build_lib as bl - -# Change to True when you are troubleshooting this build script -debug_script = False - -# These commands assume we are running on a unix-like system where default -# build options work and all prerequisites are installed and in PATH etc. -DEFAULT_COMMANDS = { - 'uname': ['uname', '-a'], - 'swig': ['swig', '-version'], - 'cc': ['gcc', '--version'], - 'openssl': ['openssl', 'version'], - 'python': ['python', '--version'], - 'clean': ['rm', '-rf', 'm2crypto'], - 'svn': ['svn', 'co', 'http://svn.osafoundation.org/m2crypto/trunk', 'm2crypto'], - 'patch': [], - 'build': ['python', 'setup.py', 'clean', '--all', 'build'], - 'test': ['python', 'setup.py', 'test'] -} - -def load_config(cfg='config.ini'): - config = {} - cp = ConfigParser.ConfigParser() - cp.read(cfg) - for section in cp.sections(): - for option in cp.options(section): - config[option] = cp.get(section, option).strip() - return config - -# XXX copied from test_ssl -def zap_servers(): - s = 's_server' - fn = tempfile.mktemp() - cmd = 'ps | egrep %s > %s' % (s, fn) - os.system(cmd) - f = open(fn) - while 1: - ps = f.readline() - if not ps: - break - chunk = string.split(ps) - pid, cmd = chunk[0], chunk[4] - if cmd == s: - os.kill(int(pid), 1) - f.close() - os.unlink(fn) - -def build(commands, config): - status = 'success' - - cwd = os.getcwd() - timeout = int(config.get('timeout') or 180) - - bl.initLog('tbox.log', echo=debug_script) - - starttime = int(time.time()) - - for command in commands: - cmd = config.get(command) - if not cmd: - cmd = DEFAULT_COMMANDS[command] - if not cmd: - continue - else: - cmd = cmd.split() - - bl.log('*** %s, timeout=%ds' % (' '.join(cmd), timeout)) - - exit_code = bl.runCommand(cmd, timeout=timeout) - if exit_code: - bl.log('*** error exit code = %d' % exit_code) - if command == 'test': - status = 'test_failed' - if os.name != 'nt': - try: - # If tests were killed due to timeout, we may have left - # openssl processes running, so try killing - zap_servers() - except Exception, e: - bl.log('*** error: tried to zap_servers: ' + str(e)) - else: - status = 'build_failed' - break - if command == 'svn': - os.chdir('m2crypto') - - timenow = int(time.time()) - - bl.closeLog() - - os.chdir(cwd) - - return 'tbox.log', starttime, timenow, status - - -def email(logpath, starttime, timenow, status, config): - msg = """From: %(from)s -To: %(to)s -Subject: tree: M2Crypto - - -tinderbox: tree: M2Crypto -tinderbox: starttime: %(starttime)d -tinderbox: timenow: %(timenow)d -tinderbox: status: %(status)s -tinderbox: buildname: %(buildname)s -tinderbox: errorparser: unix -tinderbox: END - -""" % {'from': config['from'], 'to': config['to'], - 'starttime': starttime, 'timenow': timenow, - 'status': status, - 'buildname': config['name']} - - msg += open(logpath).read() - - server = smtplib.SMTP(host=config['server'], port=int(config['port'])) - if debug_script: - server.set_debuglevel(1) - server.starttls() # if your server supports STARTTLS - if config.get('user'): - server.login(config['user'], config['password']) - server.sendmail(config['from'], config['to'], msg) - server.quit() - - -if __name__ == '__main__': - config = load_config() - - commands = ['uname', 'swig', 'cc', 'openssl', 'python', 'clean', 'svn', - 'patch', 'build', 'test'] - - logpath, starttime, timenow, status = build(commands, config) - email(logpath, starttime, timenow, status, config) diff --git a/demo/tinderbox/winprocess.py b/demo/tinderbox/winprocess.py deleted file mode 100644 index 4d867fe..0000000 --- a/demo/tinderbox/winprocess.py +++ /dev/null @@ -1,262 +0,0 @@ -# A module to expose various thread/process/job related structures and -# methods from kernel32 -# -# The MIT License -# -# Copyright (c) 2006 the Mozilla Foundation -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE -from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD - -LPVOID = c_void_p -LPBYTE = POINTER(BYTE) -LPDWORD = POINTER(DWORD) - -def ErrCheckBool(result, func, args): - """errcheck function for Windows functions that return a BOOL True - on success""" - if not result: - raise WinError() - return args - -# CloseHandle() - -CloseHandleProto = WINFUNCTYPE(BOOL, HANDLE) -CloseHandle = CloseHandleProto(("CloseHandle", windll.kernel32)) -CloseHandle.errcheck = ErrCheckBool - -# AutoHANDLE - -class AutoHANDLE(HANDLE): - """Subclass of HANDLE which will call CloseHandle() on deletion.""" - def Close(self): - if self.value: - CloseHandle(self) - self.value = 0 - - def __del__(self): - self.Close() - - def __int__(self): - return self.value - -def ErrCheckHandle(result, func, args): - """errcheck function for Windows functions that return a HANDLE.""" - if not result: - raise WinError() - return AutoHANDLE(result) - -# PROCESS_INFORMATION structure - -class PROCESS_INFORMATION(Structure): - _fields_ = [("hProcess", HANDLE), - ("hThread", HANDLE), - ("dwProcessID", DWORD), - ("dwThreadID", DWORD)] - - def __init__(self): - Structure.__init__(self) - - self.cb = sizeof(self) - -LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION) - -# STARTUPINFO structure - -class STARTUPINFO(Structure): - _fields_ = [("cb", DWORD), - ("lpReserved", LPWSTR), - ("lpDesktop", LPWSTR), - ("lpTitle", LPWSTR), - ("dwX", DWORD), - ("dwY", DWORD), - ("dwXSize", DWORD), - ("dwYSize", DWORD), - ("dwXCountChars", DWORD), - ("dwYCountChars", DWORD), - ("dwFillAttribute", DWORD), - ("dwFlags", DWORD), - ("wShowWindow", WORD), - ("cbReserved2", WORD), - ("lpReserved2", LPBYTE), - ("hStdInput", HANDLE), - ("hStdOutput", HANDLE), - ("hStdError", HANDLE) - ] -LPSTARTUPINFO = POINTER(STARTUPINFO) - -STARTF_USESHOWWINDOW = 0x01 -STARTF_USESIZE = 0x02 -STARTF_USEPOSITION = 0x04 -STARTF_USECOUNTCHARS = 0x08 -STARTF_USEFILLATTRIBUTE = 0x10 -STARTF_RUNFULLSCREEN = 0x20 -STARTF_FORCEONFEEDBACK = 0x40 -STARTF_FORCEOFFFEEDBACK = 0x80 -STARTF_USESTDHANDLES = 0x100 - -# EnvironmentBlock - -class EnvironmentBlock: - """An object which can be passed as the lpEnv parameter of CreateProcess. - It is initialized with a dictionary.""" - - def __init__(self, dict): - if not dict: - self._as_parameter_ = None - else: - values = ["%s=%s" % (key, value) - for (key, value) in dict.iteritems()] - values.append("") - self._as_parameter_ = LPCWSTR("\0".join(values)) - -# CreateProcess() - -CreateProcessProto = WINFUNCTYPE(BOOL, # Return type - LPCWSTR, # lpApplicationName - LPWSTR, # lpCommandLine - LPVOID, # lpProcessAttributes - LPVOID, # lpThreadAttributes - BOOL, # bInheritHandles - DWORD, # dwCreationFlags - LPVOID, # lpEnvironment - LPCWSTR, # lpCurrentDirectory - LPSTARTUPINFO, # lpStartupInfo - LPPROCESS_INFORMATION # lpProcessInformation - ) - -CreateProcessFlags = ((1, "lpApplicationName", None), - (1, "lpCommandLine"), - (1, "lpProcessAttributes", None), - (1, "lpThreadAttributes", None), - (1, "bInheritHandles", True), - (1, "dwCreationFlags", 0), - (1, "lpEnvironment", None), - (1, "lpCurrentDirectory", None), - (1, "lpStartupInfo"), - (2, "lpProcessInformation")) - -def ErrCheckCreateProcess(result, func, args): - ErrCheckBool(result, func, args) - # return a tuple (hProcess, hThread, dwProcessID, dwThreadID) - pi = args[9] - return AutoHANDLE(pi.hProcess), AutoHANDLE(pi.hThread), pi.dwProcessID, pi.dwThreadID - -CreateProcess = CreateProcessProto(("CreateProcessW", windll.kernel32), - CreateProcessFlags) -CreateProcess.errcheck = ErrCheckCreateProcess - -CREATE_BREAKAWAY_FROM_JOB = 0x01000000 -CREATE_DEFAULT_ERROR_MODE = 0x04000000 -CREATE_NEW_CONSOLE = 0x00000010 -CREATE_NEW_PROCESS_GROUP = 0x00000200 -CREATE_NO_WINDOW = 0x08000000 -CREATE_SUSPENDED = 0x00000004 -CREATE_UNICODE_ENVIRONMENT = 0x00000400 -DEBUG_ONLY_THIS_PROCESS = 0x00000002 -DEBUG_PROCESS = 0x00000001 -DETACHED_PROCESS = 0x00000008 - -# CreateJobObject() - -CreateJobObjectProto = WINFUNCTYPE(HANDLE, # Return type - LPVOID, # lpJobAttributes - LPCWSTR # lpName - ) - -CreateJobObjectFlags = ((1, "lpJobAttributes", None), - (1, "lpName", None)) - -CreateJobObject = CreateJobObjectProto(("CreateJobObjectW", windll.kernel32), - CreateJobObjectFlags) -CreateJobObject.errcheck = ErrCheckHandle - -# AssignProcessToJobObject() - -AssignProcessToJobObjectProto = WINFUNCTYPE(BOOL, # Return type - HANDLE, # hJob - HANDLE # hProcess - ) -AssignProcessToJobObjectFlags = ((1, "hJob"), - (1, "hProcess")) -AssignProcessToJobObject = AssignProcessToJobObjectProto( - ("AssignProcessToJobObject", windll.kernel32), - AssignProcessToJobObjectFlags) -AssignProcessToJobObject.errcheck = ErrCheckBool - -# ResumeThread() - -def ErrCheckResumeThread(result, func, args): - if result == -1: - raise WinError() - - return args - -ResumeThreadProto = WINFUNCTYPE(DWORD, # Return type - HANDLE # hThread - ) -ResumeThreadFlags = ((1, "hThread"),) -ResumeThread = ResumeThreadProto(("ResumeThread", windll.kernel32), - ResumeThreadFlags) -ResumeThread.errcheck = ErrCheckResumeThread - -# TerminateJobObject() - -TerminateJobObjectProto = WINFUNCTYPE(BOOL, # Return type - HANDLE, # hJob - UINT # uExitCode - ) -TerminateJobObjectFlags = ((1, "hJob"), - (1, "uExitCode", 127)) -TerminateJobObject = TerminateJobObjectProto( - ("TerminateJobObject", windll.kernel32), - TerminateJobObjectFlags) -TerminateJobObject.errcheck = ErrCheckBool - -# WaitForSingleObject() - -WaitForSingleObjectProto = WINFUNCTYPE(DWORD, # Return type - HANDLE, # hHandle - DWORD, # dwMilliseconds - ) -WaitForSingleObjectFlags = ((1, "hHandle"), - (1, "dwMilliseconds", -1)) -WaitForSingleObject = WaitForSingleObjectProto( - ("WaitForSingleObject", windll.kernel32), - WaitForSingleObjectFlags) - -INFINITE = -1 -WAIT_TIMEOUT = 0x0102 -WAIT_OBJECT_0 = 0x0 -WAIT_ABANDONED = 0x0080 - -# GetExitCodeProcess() - -GetExitCodeProcessProto = WINFUNCTYPE(BOOL, # Return type - HANDLE, # hProcess - LPDWORD, # lpExitCode - ) -GetExitCodeProcessFlags = ((1, "hProcess"), - (2, "lpExitCode")) -GetExitCodeProcess = GetExitCodeProcessProto( - ("GetExitCodeProcess", windll.kernel32), - GetExitCodeProcessFlags) -GetExitCodeProcess.errcheck = ErrCheckBool diff --git a/demo/x509/ca.py b/demo/x509/ca.py deleted file mode 100644 index 446998b..0000000 --- a/demo/x509/ca.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python - -""" -How to create a CA certificate with Python. - -WARNING: This sample only demonstrates how to use the objects and methods, - not how to create a safe and correct certificate. - -Copyright (c) 2004 Open Source Applications Foundation. -Author: Heikki Toivonen -""" - -from M2Crypto import RSA, X509, EVP, m2, Rand, Err - -# XXX Do I actually need more keys? -# XXX Check return values from functions - -def generateRSAKey(): - return RSA.gen_key(2048, m2.RSA_F4) - -def makePKey(key): - pkey = EVP.PKey() - pkey.assign_rsa(key) - return pkey - -def makeRequest(pkey): - req = X509.Request() - req.set_version(2) - req.set_pubkey(pkey) - name = X509.X509_Name() - name.CN = 'My CA, Inc.' - req.set_subject_name(name) - ext1 = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') - ext2 = X509.new_extension('nsComment', 'Hello there') - extstack = X509.X509_Extension_Stack() - extstack.push(ext1) - extstack.push(ext2) - - assert(extstack[1].get_name() == 'nsComment') - - req.add_extensions(extstack) - req.sign(pkey, 'sha1') - return req - -def makeCert(req, caPkey): - pkey = req.get_pubkey() - #woop = makePKey(generateRSAKey()) - #if not req.verify(woop.pkey): - if not req.verify(pkey): - # XXX What error object should I use? - raise ValueError, 'Error verifying request' - sub = req.get_subject() - # If this were a real certificate request, you would display - # all the relevant data from the request and ask a human operator - # if you were sure. Now we just create the certificate blindly based - # on the request. - cert = X509.X509() - # We know we are making CA cert now... - # Serial defaults to 0. - cert.set_serial_number(1) - cert.set_version(2) - cert.set_subject(sub) - issuer = X509.X509_Name() - issuer.CN = 'The Issuer Monkey' - issuer.O = 'The Organization Otherwise Known as My CA, Inc.' - cert.set_issuer(issuer) - cert.set_pubkey(pkey) - notBefore = m2.x509_get_not_before(cert.x509) - notAfter = m2.x509_get_not_after(cert.x509) - m2.x509_gmtime_adj(notBefore, 0) - days = 30 - m2.x509_gmtime_adj(notAfter, 60*60*24*days) - cert.add_ext( - X509.new_extension('subjectAltName', 'DNS:foobar.example.com')) - ext = X509.new_extension('nsComment', 'M2Crypto generated certificate') - ext.set_critical(0)# Defaults to non-critical, but we can also set it - cert.add_ext(ext) - cert.sign(caPkey, 'sha1') - - assert(cert.get_ext('subjectAltName').get_name() == 'subjectAltName') - assert(cert.get_ext_at(0).get_name() == 'subjectAltName') - assert(cert.get_ext_at(0).get_value() == 'DNS:foobar.example.com') - - return cert - -def ca(): - key = generateRSAKey() - pkey = makePKey(key) - req = makeRequest(pkey) - cert = makeCert(req, pkey) - return (cert, pkey) - -if __name__ == '__main__': - Rand.load_file('../randpool.dat', -1) - rsa = generateRSAKey() - pkey = makePKey(rsa) - req = makeRequest(pkey) - print req.as_text() - cert = makeCert(req, pkey) - print cert.as_text() - print cert.as_pem() - cert.save_pem('my_ca_cert.pem') - rsa.save_key('my_key.pem', 'aes_256_cbc') - Rand.save_file('../randpool.dat') diff --git a/demo/x509/certdata2pem.py b/demo/x509/certdata2pem.py deleted file mode 100755 index 9fd6d32..0000000 --- a/demo/x509/certdata2pem.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -""" -Small utility to convert the Mozilla-format certificates -(/mozilla/security/nss/lib/ckfw/builtins/certdata.txt in the Mozilla CVS) -into PEM. Got the idea from http://curl.haxx.se/docs/parse-certs.txt. - -Copyright (c) 2007 Open Source Applications Foundation. -""" - -import array -from M2Crypto import X509 - -counter = 0 -value = None -name = None - -out = open('cacert.pem', 'wb') - -for line in open('certdata.txt'): - line = line.strip() - if line.startswith('CKA_LABEL'): - assert value is None - - label_encoding, name, dummy = line.split('"') - label, encoding = label_encoding.split() - - assert encoding == 'UTF8' - - elif line == 'CKA_VALUE MULTILINE_OCTAL': - assert name is not None - - value = array.array('c') - - elif value is not None and line == 'END': - assert name is not None - - print 'Writing ' + name - x509 = X509.load_cert_string(value.tostring(), X509.FORMAT_DER) - if not x509.verify(): - print ' Skipping ' + name + ' since it does not verify' - name = None - value = None - continue - counter += 1 - - out.write(name + '\n' + '=' * len(name) + '\n\n') - out.write('SHA1 Fingerprint=' + x509.get_fingerprint('sha1') + '\n') - out.write(x509.as_text()) - out.write(x509.as_pem()) - out.write('\n') - - name = None - value = None - - elif value is not None: - assert name is not None - - for number in line.split('\\'): - if not number: - continue - - value.append(chr(int(number, 8))) - -print 'Wrote %d certificates' % counter diff --git a/demo/x509/client2.pem b/demo/x509/client2.pem deleted file mode 100644 index 166919a..0000000 --- a/demo/x509/client2.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDDjCCAnegAwIBAgIBAzANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tMB4XDTAwMTEyMDEzMDMwNVoXDTAyMTEyMDEzMDMwNVowWzEL -MAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRowGAYDVQQDExFNMkNyeXB0 -byBDbGllbnQgMjEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20wXDANBgkq -hkiG9w0BAQEFAANLADBIAkEAn9qneRYTKPokme3obiJa2NTz1Z2kcF3NHVh60Qod -/TV/q4olPrZdFR2TDWt63Lgnygcsgf3u9pnhcEGk6IvntwIDAQABo4IBBDCCAQAw -CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy -dGlmaWNhdGUwHQYDVR0OBBYEFDKWFe6VWMhtRTE3/78+hAnSGxmvMIGlBgNVHSME -gZ0wgZqAFPuHI2nrnDqTFeXFvylRT/7tKDgBoX+kfTB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBABpE9xt1Hlq2dQZUXHuX -HI57vc2mlWnhhM0wnNhsNZFwfXRHCZOo/JJBhEIT3Rgyz0ErrbOr1SN96HNDKXOD -z6bh4NxB5DZ9sRPKEBj66zDsWJVMlom+Lkeal+GkVy36vpAyP1r+cTXyc9M2Gw/o -FBMinMHH/BXvF5GJ+UleheZe ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIIBOgIBAAJBAJ/ap3kWEyj6JJnt6G4iWtjU89WdpHBdzR1YetEKHf01f6uKJT62 -XRUdkw1rety4J8oHLIH97vaZ4XBBpOiL57cCAwEAAQJANXfspprUo9MvpPEn2pbR -Lk/kk2IcW510e0laI0uwBj50djfHqvsU5ccuVLrxowngLGrFmM3G4lnMknR2NvH8 -0QIhAMsK0AwStUNM/KyvIMikHHBOE9PrK7ARgKvlKl+0ieWPAiEAyYwonIVAtr1f -M8vmrc6TM2YxzSq4+jyYktaaNhYw11kCIA5pmhMBUPSSBm2LkNwtKgeewzGLw/If -i+6nubZJbnBpAiEAvJQvy4PCsTkvQr+d7zJB+O2920IGId1gxMOXNtQ8jsECIGvn -Uz54oonshmTg+Kj2DxnUKQEzFAmQLbtFslp1m47v ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE REQUEST----- -MIIBFTCBwAIBADBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xGjAY -BgNVBAMTEU0yQ3J5cHRvIENsaWVudCAyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBv -c3QxLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCf2qd5FhMo+iSZ7ehuIlrY -1PPVnaRwXc0dWHrRCh39NX+riiU+tl0VHZMNa3rcuCfKByyB/e72meFwQaToi+e3 -AgMBAAGgADANBgkqhkiG9w0BAQQFAANBAHI5KXfL6kIRoNjR8G9/uKiPUt4uVBKF -ecGp87M5t2a92Z0KpWOMXSHZ0LLQKqwWzALvWcPPIj6S8F6ENdwpfMk= ------END CERTIFICATE REQUEST----- diff --git a/demo/x509/demo1.py b/demo/x509/demo1.py deleted file mode 100644 index f0aa282..0000000 --- a/demo/x509/demo1.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python - -"""X.509 certificate manipulation and such. - -Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" - -import os - -from M2Crypto import X509 -from M2Crypto.EVP import MessageDigest - -def demo1(): - print 'Test 1: As DER...' - cert1 = X509.load_cert('server.pem') - der1 = cert1.as_der() - dgst1 = MessageDigest('sha1') - dgst1.update(der1) - print 'Using M2Crypto:\n', `dgst1.final()`, '\n' - - cert2 = os.popen('openssl x509 -inform pem -outform der -in server.pem') - der2 = cert2.read() - dgst2 = MessageDigest('sha1') - dgst2.update(der2) - print 'Openssl command line:\n', `dgst2.final()`, '\n' - - -def demo2(): - print 'Test 2: As text...' - cert = X509.load_cert('client2.pem') - print 'version ', cert.get_version() - print 'serial# ', cert.get_serial_number() - print 'not before ', cert.get_not_before() - print 'not after ', cert.get_not_after() - issuer = cert.get_issuer() - #print 'issuer ', issuer - print 'issuer.C ', `issuer.C` - print 'issuer.SP ', `issuer.SP` - print 'issuer.L ', `issuer.L` - print 'issuer.O ', `issuer.O` - print 'issuer.OU ', `issuer.OU` - print 'issuer.CN ', `issuer.CN` - print 'issuer.Email', `issuer.Email` - print 'subject ', cert.get_subject() - #print cert.as_text(), '\n' - -def demo3(): - cert = X509.load_cert('server.pem') - while 1: - x = cert.get_subject() - -if __name__ == "__main__": - #demo1() - demo2() - #demo3() diff --git a/demo/x509/proxy_destroy.py b/demo/x509/proxy_destroy.py deleted file mode 100644 index c79bd2f..0000000 --- a/demo/x509/proxy_destroy.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -############################################################################ -# Matt Rodriguez, LBNL MKRodriguez@lbl.gov -############################################################################ -""" -Script that destroys a proxy certificate file by overwriting its contents -before the file is removed -""" - -import proxylib -import optparse, os - -USAGEHELP = "proxy_destroy.py file1 file2 Destroys files listed" -JUNK = "LalalAlalaLalalALalalAlalaLalalALalalAlalaLalalALalalAlalaLalalA" - -def scrub_file(filename): - """ - Overwrite the file with junk, before removing it - """ - s = os.stat(filename) - proxy_file = file(filename, "w") - size = s.st_size - while size > 64: - proxy_file.write(JUNK) - size -= 64 - - proxy_file.flush() - proxy_file.close() - os.remove(filename) - - -def main(): - parser = optparse.OptionParser() - parser.set_usage(USAGEHELP) - opts, args = parser.parse_args() - if len(args) is 0: - proxy_file = proxylib.get_proxy_filename() - scrub_file(proxy_file) - - for proxy_file in args: - scrub_file(proxy_file) - -if __name__ == "__main__": main() diff --git a/demo/x509/proxy_info.py b/demo/x509/proxy_info.py deleted file mode 100644 index ce9cdc3..0000000 --- a/demo/x509/proxy_info.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -############################################################################ -# Matt Rodriguez, LBNL MKRodriguez@lbl.gov -############################################################################ -""" -script that displays information about a proxy certificate -""" - - -import proxylib -import time, datetime, calendar -import sys, optparse - -FILEHELP = "Location of the proxy." - -def print_info(proxy_cert): - """ - Print information about the proxy cert - """ - cert = proxy_cert.getcert() - print "Subject: ", cert.get_subject().as_text() - print "Issuer: ", cert.get_issuer().as_text() - pubkey = cert.get_pubkey() - size = pubkey.size() - print "Strength: ", size * 8 - after = cert.get_not_after() - after_tuple = time.strptime(str(after),"%b %d %H:%M:%S %Y %Z") - expires = calendar.timegm(after_tuple) - now = datetime.timedelta(seconds=time.time()) - expires = datetime.timedelta(seconds=expires) - td = expires - now - if td.days < 0: - print "Time left: Proxy has expired." - else: - hours = td.seconds / 3600 - hours += td.days * 24 - minutes = (td.seconds % 3600) / 60 - seconds = (td.seconds % 3600) % 60 - print "Time left: %d:%d:%d" % (hours, minutes, seconds) - fraction = round((float(td.seconds) / float(3600 * 24)), 1) - print "Days left: ", str(td.days) + str(fraction)[1:] - - -def main(): - parser = optparse.OptionParser() - parser.add_option("-f", "--file", dest="filename", help=FILEHELP) - (opts, args) = parser.parse_args() - filename = opts.filename - if filename is None: - proxyfile = proxylib.get_proxy_filename() - else: - proxyfile = filename - proxy_cert = proxylib.Proxy() - try: - proxy_cert.read(proxyfile) - except IOError: - print "The file: " + proxyfile + " does not exist." - sys.exit(0) - print_info(proxy_cert) - -if __name__ == "__main__": main() diff --git a/demo/x509/proxy_init.py b/demo/x509/proxy_init.py deleted file mode 100644 index 1ca5cbb..0000000 --- a/demo/x509/proxy_init.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -############################################################################ -# Matt Rodriguez, LBNL MKRodriguez@lbl.gov -############################################################################ -""" -script that generates a proxy certificate -""" - -import proxylib -import optparse -import sys - -OUTHELP = "Location of the new proxy cert." -CERTHELP = "Location of user certificate." -KEYHELP = "Location of the user key." -VALIDHELP = "h:m Proxy certificate is valid for h hours and m minutes." -FULLPROXY = "Creates a limited proxy" -def main(): - parser = optparse.OptionParser() - parser.add_option('-o', '--output', dest='output', help=OUTHELP) - parser.add_option('-c', '--cert' , dest='cert', help=CERTHELP) - parser.add_option('-k', '--key', dest='key', help=KEYHELP) - parser.add_option('-v', '--valid', dest='valid', help=VALIDHELP) - parser.add_option('-l', '--limited', action="store_true", - default=False, dest='limited', help=VALIDHELP) - (opts, args) = parser.parse_args() - kw = {} - kw['cert'] = opts.cert - kw['key'] = opts.key - if opts.valid is None: - valid_tuple = (12, 0) - else: - valid = opts.valid.split(':') - valid_tuple = tuple(map(int, valid)) - kw['valid'] = valid_tuple - kw['full'] = not opts.limited - try: - proxy_factory = proxylib.ProxyFactory(kw) - except IOError: - print "Can't find usercert or userkey. Use the -c or -k arguments" - sys.exit(0) - proxy_factory.generate() - proxy_cert = proxy_factory.getproxy() - if opts.output is None: - proxy_cert.write(proxylib.get_proxy_filename()) - else: - proxy_cert.write(opts.output) - -if __name__ == "__main__": main() diff --git a/demo/x509/proxylib.py b/demo/x509/proxylib.py deleted file mode 100644 index e0f3395..0000000 --- a/demo/x509/proxylib.py +++ /dev/null @@ -1,327 +0,0 @@ -############################################################################ -# Matt Rodriguez, LBNL -#Copyright (c) 2003, The Regents of the University of California, -#through Lawrence Berkeley National Laboratory -#(subject to receipt of any required approvals from the U.S. Dept. of Energy). -#All rights reserved. -############################################################################ -""" -API to generated proxy certificates -""" -import os, sys -import struct -import re -import time, calendar, datetime - -import_regex = re.compile(r"\s*libssl.so.0.9.8\s*") -errstr = "You must have the openssl 0.9.8 libraries in your LD_LIBRARY_PATH""" - -try: - from M2Crypto import BIO, X509, RSA, EVP, ASN1 -except ImportError, ex: - if import_regex.match(str(ex)): - print errstr - sys.exit(-1) - else: - raise ex - -MBSTRING_FLAG = 0x1000 -MBSTRING_ASC = MBSTRING_FLAG | 1 -KEY_USAGE_VALUE = "Digital Signature, Key Encipherment, Data Encipherment" -PCI_VALUE_FULL = "critical, language:Inherit all" -PCI_VALUE_LIMITED = "critical, language:1.3.6.1.4.1.3536.1.1.1.9" - -def create_write_file(fname, perm=0600): - """ - Creates a file to write to while avoiding a possible race condition. - This is essential for writing out the proxy file. Need to make sure - there is no pre-existing file. - """ - if os.path.exists(fname): - os.remove(fname) - # Make sure the file doesn't exist. Will throw an exception if - # it does. This would only happen if the code is attacked. - fd = os.open(fname, os.O_CREAT|os.O_EXCL|os.O_WRONLY, perm) - f = os.fdopen(fd, 'w') - return f - - -class ProxyFactoryException(Exception): - """ - Base class for exceptions in the ProxyFactory class - """ - -class Proxy: - """ - class that holds proxy certificate information, - consisting of an issuer cert a user cert and - a key for the user cert - """ - def __init__(self): - self._key = None - self._cert = None - self._issuer = None - - def read(self, proxypath=None): - """ - reads in a proxy certificate information - """ - if proxypath is None: - proxypath = get_proxy_filename() - - proxyfile = open(proxypath) - bio = BIO.File(proxyfile) - self._cert = X509.load_cert_bio(bio) - self._key = RSA.load_key_bio(bio) - self._issuer = X509.load_cert_bio(bio) - - def getcert(self): - """ - Returns a X509 instance - """ - return self._cert - - def getkey(self): - """ - Returns a RSA instance - """ - return self._key - - def getissuer(self): - """ - Returns a X509 instance - """ - return self._issuer - - def setcert(self, cert): - """ - Sets the user cert should be a X509 instance - """ - self._cert = cert - - def setkey(self, key): - """ - Sets the user key should be a RSA instance - """ - self._key = key - - def setissuer(self, issuer): - """ - Sets the issuer cert should be a X509 instance - """ - self._issuer = issuer - - def write(self, proxypath=None): - """ - Writes the proxy information to a file - """ - proxyfile = create_write_file(proxypath) - bio = BIO.File(proxyfile) - bio.write(self._cert.as_pem()) - self._key.save_key_bio(bio, cipher=None) - bio.write(self._issuer.as_pem()) - bio.close() - os.chmod(proxypath, 0600) - - -class ProxyFactory: - """ - Creates proxies - """ - def __init__(self, kw={'cert':None,'key':None,'valid':(12,0),'full':True}): - - self._usercert = get_usercert(kw['cert']) - self._userkey = get_userkey(kw['key']) - self._proxycert = None - self._proxykey = None - self._valid = kw['valid'] - self._full = kw['full'] - - def generate(self): - """ - generates a new proxy like grid-proxy-init - """ - if not self._check_valid(): - raise ProxyFactoryException("The issuer cert is expired") - if self._proxycert is None: - self._proxycert = X509.X509() - key = EVP.PKey() - self._proxykey = RSA.gen_key(512, 65537) - key.assign_rsa(self._proxykey, capture=0) - self._proxycert.set_pubkey(key) - self._proxycert.set_version(2) - self._set_times() - issuer_name = self._usercert.get_subject() - self._proxycert.set_issuer_name(issuer_name) - serial_number = self._make_serial_number(self._proxycert) - self._proxycert.set_serial_number(serial_number) - self._set_subject() - sign_pk = EVP.PKey() - sign_pk.assign_rsa(self._userkey) - self._add_extensions() - self._proxycert.sign(sign_pk, 'md5') - - def set_proxycert(self, proxycert): - """ - This method is useful if you don't - want to pay the costs associated with - generating a new key pair. - """ - self._proxycert = proxycert - - def getproxy(self): - """ - Return a proxy instance - """ - proxy = Proxy() - proxy.setissuer(self._usercert) - proxy.setcert(self._proxycert) - proxy.setkey(self._proxykey) - return proxy - - def _set_subject(self): - """ - Internal method that sets the subject name - """ - subject_name = X509.X509_Name() - serial_number = self._make_serial_number(self._proxycert) - issuer_name = self._usercert.get_subject() - issuer_name_txt = issuer_name.as_text() - seq = issuer_name_txt.split(",") - for entry in seq: - name_component = entry.split("=") - subject_name.add_entry_by_txt(field=name_component[0].strip(), - type=MBSTRING_ASC, - entry=name_component[1],len=-1, - loc=-1, set=0) - - - subject_name.add_entry_by_txt(field="CN", - type=MBSTRING_ASC, - entry=str(serial_number), - len=-1, loc=-1, set=0) - - self._proxycert.set_subject_name(subject_name) - - def _set_times(self): - """ - Internal function that sets the time on the proxy - certificate - """ - not_before = ASN1.ASN1_UTCTIME() - not_after = ASN1.ASN1_UTCTIME() - not_before.set_time(int(time.time())) - offset = (self._valid[0] * 3600) + (self._valid[1] * 60) - not_after.set_time(int(time.time()) + offset ) - self._proxycert.set_not_before(not_before) - self._proxycert.set_not_after(not_after) - - def _make_serial_number(self, cert): - """ - Lifted from the globus code - """ - message_digest = EVP.MessageDigest('sha1') - pubkey = cert.get_pubkey() - der_encoding = pubkey.as_der() - message_digest.update(der_encoding) - digest = message_digest.final() - digest_tuple = struct.unpack('BBBB', digest[:4]) - sub_hash = long(digest_tuple[0] + (digest_tuple[1] + ( digest_tuple[2] + - ( digest_tuple[3] >> 1) * 256 ) * 256) * 256) - return sub_hash - - def _add_extensions(self): - """ - Internal method that adds the extensions to the certificate - """ - key_usage_ext = X509.new_extension("keyUsage", KEY_USAGE_VALUE, 1) - self._proxycert.add_ext(key_usage_ext) - if self._full: - pci_ext = X509.new_extension("proxyCertInfo", - PCI_VALUE_FULL, 1, 0) - else: - pci_ext = X509.new_extension("proxyCertInfo", - PCI_VALUE_LIMITED, 1, 0) - self._proxycert.add_ext(pci_ext) - - def _check_valid(self): - """ - Internal method that ensures the issuer cert has - valid, not_before and not_after fields - """ - before_time = self._usercert.get_not_before() - after_time = self._usercert.get_not_after() - before_tuple = time.strptime(str(before_time), "%b %d %H:%M:%S %Y %Z") - after_tuple = time.strptime(str(after_time), "%b %d %H:%M:%S %Y %Z") - starts = datetime.timedelta(seconds=calendar.timegm(before_tuple)) - expires = datetime.timedelta(seconds=calendar.timegm(after_tuple)) - now = datetime.timedelta(seconds=time.time()) - time_delta = expires - now - #cert has expired - if time_delta.days < 0: - return False - #cert is not yet valid, not likely but should still return False - time_delta = now - starts - if time_delta.days < 0: - return False - - return True - -#Utility Functions -def get_proxy_filename(): - """ - function that returns the default proxy path - which is /tmp/x509up_uuid - """ - if os.name == 'posix': - proxy_filename = "x509up_u" + (str(os.getuid())) - proxypath = os.path.join("/tmp", proxy_filename) - elif os.name == 'nt': - username = os.getenv("USERNAME") - if username is None: - raise RuntimeError("""USERNAME is not set in environment. Can't - determine proxy file location""") - - proxy_filename = "x509up_u" + username - drive = os.path.splitdrive(os.getcwd())[0] - proxydir = drive + os.sep + "temp" - proxypath = os.path.join(proxydir, proxy_filename) - else: - except_string = """get_proxy_filename is not supported on this platform - Try explicitly specifying the location of the - proxyfile""" - raise RuntimeError(except_string) - return proxypath - -def get_usercert(certfile=None): - """ - function that returns a X509 instance which - is the user cert that is expected to be a ~/.globus/usercert.pem - - A check is performed to ensure the certificate has valid - before and after times. - """ - if certfile is None: - certfile = open(os.path.join(os.getenv("HOME"), - ".globus","usercert.pem")) - else: - certfile = open(certfile) - bio = BIO.File(certfile) - cert = X509.load_cert_bio(bio) - return cert - -def get_userkey(keyfile=None): - """ - function that returns a X509 instance which - is the user cert that is expected to be a ~/.globus/userkey.pem - """ - if keyfile is None: - keyfile = open(os.path.join(os.getenv("HOME"), - ".globus","userkey.pem")) - else: - keyfile = open(keyfile) - bio = BIO.File(keyfile) - key = RSA.load_key_bio(bio) - return key - - diff --git a/demo/x509/server-expired.pem b/demo/x509/server-expired.pem deleted file mode 100644 index 80ef9dc..0000000 --- a/demo/x509/server-expired.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDBjCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzER -MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD -ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n -cHNAcG9zdDEuY29tMB4XDTAwMDkxMDA5NTEzMFoXDTAyMDkxMDA5NTEzMFowUzEL -MAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlsb2NhbGhv -c3QxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tMFwwDQYJKoZIhvcNAQEB -BQADSwAwSAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh -5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAaOCAQQwggEAMAkGA1UdEwQC -MAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl -MB0GA1UdDgQWBBTPhIKSvnsmYsBVNWjj0m3M2z0qVTCBpQYDVR0jBIGdMIGagBT7 -hyNp65w6kxXlxb8pUU/+7Sg4AaF/pH0wezELMAkGA1UEBhMCU0cxETAPBgNVBAoT -CE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlw -dG8gQ2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3Qx -LmNvbYIBADANBgkqhkiG9w0BAQQFAAOBgQA7/CqT6PoHycTdhEStWNZde7M/2Yc6 -BoJuVwnW8YxGO8Sn6UJ4FeffZNcYZddSDKosw8LtPOeWoK3JINjAk5jiPQ2cww++ -7QGG/g5NDjxFZNDJP1dGiLAxPW6JXwov4v0FmdzfLOZ01jDcgQQZqEpYlgpuI5JE -WUQ9Ho4EzbYCOQ== ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIIBPAIBAAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh -5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAQJBAIqm/bz4NA1H++Vx5Ewx -OcKp3w19QSaZAwlGRtsUxrP7436QjnREM3Bm8ygU11BjkPVmtrKm6AayQfCHqJoT -ZIECIQDW0BoMoL0HOYM/mrTLhaykYAVqgIeJsPjvkEhTFXWBuQIhAM3deFAvWNu4 -nklUQ37XsCT2c9tmNt1LAT+slG2JOTTRAiAuXDtC/m3NYVwyHfFm+zKHRzHkClk2 -HjubeEgjpj32AQIhAJqMGTaZVOwevTXvvHwNEH+vRWsAYU/gbx+OQB+7VOcBAiEA -oolb6NMg/R3enNPvS1O4UU1H8wpaF77L4yiSWlE0p4w= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE REQUEST----- -MIIBDTCBuAIBADBTMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xEjAQ -BgNVBAMTCWxvY2FsaG9zdDEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20w -XDANBgkqhkiG9w0BAQEFAANLADBIAkEArL57d26W9fNXvOhNlZzlPOACmvwOZ5Ad -NgLzJ1/MfsQQJ7hHVeHmTAjM664V+fXvwUGJLziCeBo1ysWLRnl8CQIDAQABoAAw -DQYJKoZIhvcNAQEEBQADQQA7uqbrNTjVWpF6By5ZNPvhZ4YdFgkeXFVWi5ao/TaP -Vq4BG021fJ9nlHRtr4rotpgHDX1rr+iWeHKsx4+5DRSy ------END CERTIFICATE REQUEST----- diff --git a/demo/x509/server.pem b/demo/x509/server.pem deleted file mode 100644 index 1ee9282..0000000 --- a/demo/x509/server.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx -ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE -AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu -Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx -NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls -b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c -kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 -KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp -/y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 -QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB -H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 -du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv -MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm -aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t -ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy -lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW -iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 -0QkPQNdP ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu -6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe -I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB -AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ -u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 -xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 -1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp -IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx -luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I -lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS -38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy -v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z -DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= ------END RSA PRIVATE KEY----- diff --git a/demo/x509/x509auth.py b/demo/x509/x509auth.py deleted file mode 100644 index a1f6e4b..0000000 --- a/demo/x509/x509auth.py +++ /dev/null @@ -1,675 +0,0 @@ -#!/usr/bin/env python2 -# -# vim: ts=4 sw=4 nowrap -# -# ChannelHandler -# ReceiveChannel -# SendChannel -# -# SocketDispatcher -# Loop -# Poll -# ReadEvent -# WriteEvent -# -import sys, re, time, thread, os -import getopt -import exceptions -import select -import string -import socket -import StringIO -import traceback - - -from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN, EINTR, EISCONN - -STDOUT = sys.stdout - -IDstdin = 0 -IDstdout = 1 -IDstderr = 2 - - - - -class ExitNow (exceptions.Exception): - pass - - -class AuthError(exceptions.Exception): - def __init__ (self, msg): - self.msg = msg - def __str__ (self): - return repr( self.msg ) - -#---------------------------------------------------------------- -# -# Class Security Certification -# -#---------------------------------------------------------------- -import M2Crypto -import random -import base64 -import sha - -class CertHandler: - - def __init__ ( self ): - self.Nonce = None - self.CurrentObj = {} - #self.ServerName = socket.gethostbyaddr(socket.gethostname())[2][0] - self.ServerName = 'AuthInstance' - - self.ObjNames = { 'C' : 'countryName', 'ST' : 'stateOrProvinceName', 'L' : 'localityName', 'O' : 'organizationName', 'OU' : 'organizationalUnitName', 'CN' : 'commonName', 'email' : 'emailAddress' } - self.ObjMap = {} - - self.Params = { 'Digest' : 'sha1', - 'Version' : 1, - 'Serial' : 1, - 'NotBefore' : ( 60 * 60 * 24 * 365 ), - 'NotAfter' : ( 60 * 60 * 24 * 365 * 5 ), - 'Issuer' : { 'countryName' : 'US', 'stateOrProvinceName' : 'florida', 'localityName' : 'tampas', 'organizationName' : 'watersprings', 'organizationalUnitName' : 'security', 'commonName' : 'Certificate Authority', 'emailAddress' : 'admin@security' }, - 'Subject' : { 'countryName' : 'US', 'stateOrProvinceName' : 'florida', 'localityName' : 'miami', 'organizationName' : 'watersprings', 'organizationalUnitName' : 'security', 'commonName' : 'Certificate Authority', 'emailAddress' : 'admin@security' } - } - self.KeyEnv = { 'RsaPubKey' : [ '-----BEGIN PUBLIC KEY-----', '-----END PUBLIC KEY-----' ], - 'RsaPKey' : [ '-----BEGIN RSA PRIVATE KEY-----', '-----END RSA PRIVATE KEY-----' ], - 'X509Cert' : [ '-----BEGIN CERTIFICATE-----', '-----END CERTIFICATE-----' ] - } - self.CertContainer () - - self.ObjFromContainer ( ObjName='CA' ) - self.ObjFromContainer ( ObjName=self.ServerName ) - self.ServerObj = self.ObjMap[ self.ServerName ] - - - - - - def CertContainer (self): - self.PemMap = { 'CA' : { 'Subject' : {'organizationalUnitName': 'security', 'organizationName': 'watersprings', 'commonName': 'Certificate Authority', 'stateOrProvinceName': 'florida', 'countryName': 'US', 'emailAddress': 'admin@security', 'localityName': 'miami'}, - 'RsaPKey' : ['MIICXQIBAAKBgQDmAl+4+XdF34D3kBN58An29mA8/D+NUHVJW+XeE96uDJ9mw8f1', 'xguVYgfpMaiVihW/qDWZRu/NhWOfheKBVNstx5OcqIjY10vBvGAG17CQZhcon8eN', 'Kufg7XzON7e5WXXD8qyklhuesHtTEGGpZ1FfA+n+D/0JF3YfTBDeYyY2VQIDAQAB', 'AoGBAI53L/Uxx7fmzUoJ2pZvoKxwRIHhuDd+e3c5zbJ1WjsyJFWRtLw9tBUOCFpf', 'YM1nHzt8I97RulzxXxiC5B45ghu3S0s+B06oEOUxNLbjsai08DKBRFqM+IZIx11r', 'IM/tZsTdJg1KtKojRu63NDtOzR6a7ggTeMge5CDKpXVWpvVtAkEA+QF/q2NnsdmL', 'ak6ALl8QwMbvwujJcjLwvecHQJmB0jO9KF60Hh4VY8mTRIMZ/r9Wf+REsQcZtmhG', 'WRr12si5qwJBAOx4R0Wd/inoXOpvKheIoKgTg01FnLhT8uiLY59CuZRr6AcTELjC', 'Kvk6LyfhspYBkUwWAEwKxJ3kMeqXG+k8z/8CQQCy+GDKzqe5LKMHxWRb7/galuG9', 'NZOUgQiHdYXA6JRmgMl0Op07CGRXVIqEs7X7Y4rIYUj99ByG/muRn88VcTABAkBQ', 'Z6V0WoBtp4DQhfP+BIr8G4Zt49miI4lY4OyC3qFTgk1m+miZKgyKqeoW2Xtr3iSV', 'hnWbZZ3tQgZnCfKHoBHpAkAmf2OvfhLxaW1PwdjBdm9tFGVbzkLFDqdqww2aHRUx', 'sXonHyVG2EDm37qW7nzmAqUgQCueMhHREZQYceDrtLLO'], - 'X509Cert' : ['MIICpzCCAhCgAwIBAQIBATANBgkqhkiG9w0BAQUFADCBmTERMA8GA1UECxMIc2Vj', 'dXJpdHkxFTATBgNVBAoTDHdhdGVyc3ByaW5nczEeMBwGA1UEAxMVQ2VydGlmaWNh', 'dGUgQXV0aG9yaXR5MRAwDgYDVQQIEwdmbG9yaWRhMQswCQYDVQQGEwJVUzEdMBsG', 'CSqGSIb3DQEJARYOYWRtaW5Ac2VjdXJpdHkxDzANBgNVBAcTBnRhbXBhczAeFw0w', 'MzAzMzExMDQ2MDVaFw0wOTAzMjkxMDQ2MDVaMIGYMREwDwYDVQQLEwhzZWN1cml0', 'eTEVMBMGA1UEChMMd2F0ZXJzcHJpbmdzMR4wHAYDVQQDExVDZXJ0aWZpY2F0ZSBB', 'dXRob3JpdHkxEDAOBgNVBAgTB2Zsb3JpZGExCzAJBgNVBAYTAlVTMR0wGwYJKoZI', 'hvcNAQkBFg5hZG1pbkBzZWN1cml0eTEOMAwGA1UEBxMFbWlhbWkwgZ8wDQYJKoZI', 'hvcNAQEBBQADgY0AMIGJAoGBAOYCX7j5d0XfgPeQE3nwCfb2YDz8P41QdUlb5d4T', '3q4Mn2bDx/XGC5ViB+kxqJWKFb+oNZlG782FY5+F4oFU2y3Hk5yoiNjXS8G8YAbX', 'sJBmFyifx40q5+DtfM43t7lZdcPyrKSWG56we1MQYalnUV8D6f4P/QkXdh9MEN5j', 'JjZVAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAK7f4YodUnT7Ygp7BWBBDHSq/r+tY', 'H69ly3W23U5VupaIglNiNQoMqnZpVVfcuIYltajrux5TSH4gPbenCg163Ua8RvF6', 'E2JElccprbKiCf9tf8l6Rxpsall4EF+CazP56DiUD1NfGLhWp9V2ga9SoynEo1P1', 'eztMBfk01atBJ/s='] - }, - 'AuthInstance' : { 'Subject' : {'commonName': 'AuthInstance', 'organizationalUnitName': 'security', 'emailAddress': 'ioclient@AuthInstance'}, - 'RsaPKey' : ['MIICXQIBAAKBgQCwfB6CoOQTJTd6D4ua1G/H9hwqpdVUMMjG3O8Y93vYGesZdwtT', '1iEQX/6TWACBxa7jOC8hHUHe2lsPu7imHv8dDiD59Rzets7BM88HsJTemYrxSv5G', 'uh8FloB1KEtSHeCZSlDT/tzSX4M0JfVPmtx+0FsyDOVZ6jXjRIyIKgqDlwIDAQAB', 'AoGAYc8YFatXW6j3mwU8iL2NidPC/nvTxAoZa+UL+dlG4JhUrFNGitsUjf+1ljFi', 'bomBiFod/Is7c2euqgSOrDpnheYlogv2QpnP80YUpiv9OruaB9I1zqJ7QM7PrkrH', 'm1C36DzyzVY+4DMvTV29do4Mf6CKT8xf6hXlLK/NbqwO9NkCQQDYwxwCTWxrkX08', '+0c5KaTYxfqCByxOqoiKl97p6wHxNtlzdLeFoSZD0n3Q1c2v0DIXhcBPRPPaZBWC', 'yTayMkRzAkEA0G6I5mHQVNIx18Xmc75urC0QWrum9cj5VcyRvl3KCzB2kQoXkx6v', 'y0JN6YS37rSp8vmvIFNO/oHWSuEJlFYfTQJAajWv07D8Hvj61JaLH4c4Lr9TL8M0', 'Apesr7wajaOJIBgwFFJsWh3MEg9hdqJMVok9AimXQUAX/DpuD9dn5Yib4QJBAIdt', 'Kno2V7ylDkmahk/yDcrFRPkPMD5GpOrAjnnYSqzWglNe8U5gA+zXWfQ+jZwFut7q', 'qIUiXBM1nVzttuGwy4kCQQC3MHppypSWoFqd+TaxK3MX/HoZqaoRELXdeiniOt3Z', 'gFMJ4m6D9lL4segWDoDpequjDYxv2cl+wS1+qDOyeG3J'], - 'X509Cert' : ['MIIBxDCCAS2gAwIBAQIBATANBgkqhkiG9w0BAQUFADAAMB4XDTAzMDMzMTEwNTE1', 'N1oXDTA5MDMyOTEwNTE1N1owUDEkMCIGCSqGSIb3DQEJARYVaW9jbGllbnRAQXV0', 'aEluc3RhbmNlMREwDwYDVQQLEwhzZWN1cml0eTEVMBMGA1UEAxMMQXV0aEluc3Rh', 'bmNlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwfB6CoOQTJTd6D4ua1G/H', '9hwqpdVUMMjG3O8Y93vYGesZdwtT1iEQX/6TWACBxa7jOC8hHUHe2lsPu7imHv8d', 'DiD59Rzets7BM88HsJTemYrxSv5Guh8FloB1KEtSHeCZSlDT/tzSX4M0JfVPmtx+', '0FsyDOVZ6jXjRIyIKgqDlwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFsXewlXnKpH', 'uSwxavmLPUqRk7o1D5E3ByTddBe3BY5NqEXk7Y2SJFtumiuUY5/sWB/aO8Xbqj/b', '/7Cwg9+bc9QqxeeIe/YvtFOmv1ELh2BC1Nof7zSa5rLa/+gPYCoogS4mLRMuUfRk', 'tVHhpoxL1B+UXp4jNeKeTgquOjpUiyBR'] - }, - '192.168.1.20' : { 'Subject' : {'commonName': '192.168.1.20', 'organizationalUnitName': 'security', 'emailAddress': 'ioclient@192.168.1.20'}, - 'RsaPKey' : ['MIICWwIBAAKBgQDD285BGY+FHhfpRvcqupN8X2lPwUNq4G7k5kit5cyuQLfN0+eQ', 'I+VFZdtfJhCZC54dEIvNgA4I7563pRUD0S9rmN6kh/M0GgrKZjYNO+CvvG2dts26', 'MGK0eUQaSsvDf9phEA+0mSv9dsUrdyBTJBn4mXvApekYHt+mNLfCVLkM1QIDAQAB', 'AoGAMqcFB3cJ0/59Zpowz/8ip3axcKvluJ1EcLRRtY+JyML6BiQ4beGqqLD38/qP', 'LlV/1bpyvXnRp2P5IztxXORbo77IzDVzl62YesQATnecSCMLTaeOusy2EZZsjE0k', 'V2cR1rZvzyJPY+Fi8X54hiB+5IcKkPRX9LVw7+yBbBh4sKECQQD0Yi0/DGa3IetR', '9F+/jgN/VIcTd5KwMBW3Bw/+Bh78ZlZGaucpRiR1IQuD7sLTnhNS6RMJUxv10jnS', 'BGW9pjX5AkEAzSslOGFyJ5Aoy48rgC2kKwq6nFKJ/PmY92cnm0nqmwb2npbOtDxz', 'sPUdb7oYmUU/nVCJh3yb+KJIw2g9XxnUvQJAG8ybNwPTH1vlZ+Izjhe6gB5+axF8', 'BzzBC5vrDstldPKzN7lraD+JYCWNKMndMbNWoWTP/IyOrqzmVOSZKjShCQJAbzuE', 'C2QxaqeqpmnxkKWuCrPfZl8NdryvpPolK/jQG8qTrHlgibD4nCjYE7nWGkrD6Xs/', 'hNgXC56YSnDaTRQJFQJAD5GFACv9QgcMZhy1hza0yGDMSQ0WR8/y3CJhi3DPOuAf', 'MetGM1kLQR8bDFrl7yEs+Nufk8QTsE5ngZ7dGFgmuA=='], - 'X509Cert' : ['MIIBxDCCAS2gAwIBAQIBATANBgkqhkiG9w0BAQUFADAAMB4XDTAzMDMzMTEwNTMw', 'NVoXDTA5MDMyOTEwNTMwNVowUDEkMCIGCSqGSIb3DQEJARYVaW9jbGllbnRAMTky', 'LjE2OC4xLjIwMREwDwYDVQQLEwhzZWN1cml0eTEVMBMGA1UEAxMMMTkyLjE2OC4x', 'LjIwMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDD285BGY+FHhfpRvcqupN8', 'X2lPwUNq4G7k5kit5cyuQLfN0+eQI+VFZdtfJhCZC54dEIvNgA4I7563pRUD0S9r', 'mN6kh/M0GgrKZjYNO+CvvG2dts26MGK0eUQaSsvDf9phEA+0mSv9dsUrdyBTJBn4', 'mXvApekYHt+mNLfCVLkM1QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAA5pWiXJOHCJ', 'P6kHcBITJuwv94zZ0dbHby1ljUfG/8z3Fmr8JRUcTuTtgVYH9M0O9QujIR8YLWSV', '0GeD3nkLRn0+ezam0CW0dF/Ph5vNXFP4a0DSEVv7T0G21VFmbUV3xrVeaXARFuLa', 'AtqRoSyBMajd3g0WNXDCgGEH7LvzJ5EP'] - }, - '192.168.1.26' : { 'Subject' : {'commonName': '192.168.1.26', 'organizationalUnitName': 'security', 'emailAddress': 'ioclient@192.168.1.26'}, - 'RsaPKey' : ['MIICXQIBAAKBgQC5ILRHC3wFoqG9Egb96N3iGEnVrgvQikHyXYc/jFMUgB79rVJp', 'hY1MziGkSjSyc3RFMshkjHlMlARMPCNtomIikqAQaO4Eke2SYWyaOBoTdkeOy+yZ', 't/POpoGp3nRmKGed6NNcdMd5BO01GiatUb7X/Se3Yyvmj5UcEmv/hZQGFwIDAQAB', 'AoGBALdR5FMp0zE9X437iQLsErQuOwcmpzplfnJDHYfXK/nz+TxY4m/tuQNiZ7vp', 'Y4+Gdo+Dfx7aX89uD2dycd7B2wwTziBGIEjhusD8gtralVjhBDjCowSOkezWTeY+', '2h40NB4e1uypOZb0PXWvAL/l9xN7NBGioq9zmShT5c+FFO8RAkEA4k3QSaT1ScGI', '5II5JolvPnv6yS+0dCQTn1SC2ABWbH75NDUHMGAdNIf1sqhaLSQnY9GuXhb8XqX6', 'UUhoypUHzwJBANFrqnuEuTNKR0HVD31/2trPYLfZL6/9RUsR4mlvxPb0tX+T5LVL', '5he43zbura/lZqNxt0ZVeD03LanPN7bvZzkCQQCMAToIJa6+x6YKQOpchhA1pvwb', 'NZE9fQhKvT0JpwPQsak4/EmLSxsmYarGsdLANKrN3W4ztaLCZ4r6eIKkOhkPAkBz', 'ke4wYitucbRnUTRONuvJSx599x6JCcVey0zekO7qtlsfP7e8kVk2iDCu+QLjCj8d', 'Pdk9uFc1uSi7CH8ftniJAkBLNYF0kfGC+CaTuyfnIwiBZ/tjmm4UvHfwtlaZHJYc', 'QIjimBxVA7mujrv3xIBTiDMdxUhq9YIaKIEdlveaTwPK'], - 'X509Cert' : ['MIIBxDCCAS2gAwIBAQIBATANBgkqhkiG9w0BAQUFADAAMB4XDTAzMDMzMTEwNTQx', 'NloXDTA5MDMyOTEwNTQxNlowUDEkMCIGCSqGSIb3DQEJARYVaW9jbGllbnRAMTky', 'LjE2OC4xLjI2MREwDwYDVQQLEwhzZWN1cml0eTEVMBMGA1UEAxMMMTkyLjE2OC4x', 'LjI2MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5ILRHC3wFoqG9Egb96N3i', 'GEnVrgvQikHyXYc/jFMUgB79rVJphY1MziGkSjSyc3RFMshkjHlMlARMPCNtomIi', 'kqAQaO4Eke2SYWyaOBoTdkeOy+yZt/POpoGp3nRmKGed6NNcdMd5BO01GiatUb7X', '/Se3Yyvmj5UcEmv/hZQGFwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAMPd5SXzpwZ+', '40SdOv/PeQ5cjieDm6QjndWE/T8nG2I5h6YRWbZPohsCClQjrTyZCMXwcUiCimuJ', 'BaMigI/YqP5THVv58Gu8DpoVZppz7uhUNS5hsuV9lxZUh1bRkUtL6n0qSTEdM34I', 'NJBJKGlf0skULg9BT4LJYTPGWJ0KosUl'] - } - } - - def CreateObj ( self, ObjName='CA' ): - self.ObjMap[ObjName] = { 'RsaPKey' : None, - 'PsaPubKey' : None, - 'EvpPKey' : None, - 'EvpPubKey' : None, - 'X509Req' : None, - 'X509Cert' : None, - } - self.CurrentObj = self.ObjMap[ObjName] - - def ObjFromContainer (self, ObjName='CA' ): - if not self.ObjMap.has_key( ObjName ): - self.CreateObj ( ObjName=ObjName ) - self.PKeyFromPemRepr ( ObjName=ObjName ) - self.CertFromPemRepr ( ObjName=ObjName ) - - def PKeyFromPemRepr ( self, ObjName=None, PemPKey=None ): - def callback (): return '' - if self.PemMap.has_key( ObjName ): - UsedPemPKey = self.KeyEnv['RsaPKey'][0] + '\n' + string.join( self.PemMap[ObjName]['RsaPKey'], '\n' ) + '\n' + self.KeyEnv['RsaPKey'][1] + '\n' - else: - if not PemPKey: - raise AuthError( 'no such Object "%s" in container - abort!' % ObjName ) - else: - UsedPemPKey = PemPKey - self.CurrentObj['RsaPKey'] = M2Crypto.RSA.load_key_string( UsedPemPKey, callback ) - self.CurrentObj['EvpPKey'] = M2Crypto.EVP.PKey ( md='sha1' ) - self.CurrentObj['EvpPKey'].assign_rsa ( self.CurrentObj['RsaPKey'] ) - self.CurrentObj['RsaPubKey'] = M2Crypto.RSA.new_pub_key( self.CurrentObj['RsaPKey'].pub () ) - - def CertFromPemRepr ( self, ObjName=None, PemCert=None ): - if self.PemMap.has_key( ObjName ): - UsedPemCert = self.KeyEnv['X509Cert'][0] + '\n' + string.join( self.PemMap[ObjName]['X509Cert'], '\n' ) + '\n' + self.KeyEnv['X509Cert'][1] + '\n' - else: - UsedPemCert = PemCert - self.CurrentObj['X509Cert'] = M2Crypto.X509.load_cert_string( PemCert ) - self.CurrentObj['EvpPubKey'] = self.CurrentObj['X509Cert'].get_pubkey () - #self.CurrentObj['RsaPubKey'] = M2Crypto.RSA.rsa_from_pkey( self.CurrentObj['EvpPubKey'] ) - - def ObjNameFromPemCert ( self, PemCert=None ): - """ - generate objmap structure and fill it with values from PemCert - return ObjName string - """ - X509Cert = M2Crypto.X509.load_cert_string( PemCert ) - Subject = X509Cert.get_subject () - SubjectTxt = Subject.print_ex () - SubjectTxtList = re.split('[\n\r]', SubjectTxt ) - SubjectMap = {} - for Entry in SubjectTxtList: - ( Key, Value ) = re.split('=', Entry) - if self.ObjNames.has_key( Key ): - SubjectMap[ self.ObjNames[Key] ] = Value - else: - SubjectMap[ Key ] = Value - if not SubjectMap.has_key( 'commonName' ): - return False - ObjName = SubjectMap['commonName'] - if not self.ObjMap.has_key( ObjName ): - self.CreateObj( ObjName=ObjName ) - self.CurrentObj = self.ObjMap[ObjName] - self.CurrentObj['X509Cert'] = X509Cert - self.CurrentObj['EvpPubKey'] = self.CurrentObj['X509Cert'].get_pubkey () - self.CurrentObj['RsaPubKey'] = M2Crypto.RSA.rsa_from_pkey( self.CurrentObj['EvpPubKey'] ) - else: - self.CurrentObj = self.ObjMap[ ObjName ] - return ObjName - - - - def ServerCert ( self ): - self.ObjFromContainer( ObjName='X509Auth' ) - - - def CreatePKey ( self ): - def PassPhraseFkt (): return '' - RsaKeyParams = { 'KeyLength' : 1024, - 'PubExponent' : 0x10001, # -> 65537 - 'keygen_callback' : PassPhraseFkt - } - self.CurrentObj['RsaPKey'] = M2Crypto.RSA.gen_key( RsaKeyParams['KeyLength'], RsaKeyParams['PubExponent'], RsaKeyParams['keygen_callback'] ) - self.CurrentObj['EvpPKey'] = M2Crypto.EVP.PKey ( md=self.Params['Digest'] ) - self.CurrentObj['EvpPKey'].assign_rsa ( self.CurrentObj['RsaPKey'] ) - #print self.EvpPKey - - - def CreateCert ( self, SignEvpPKey=None ): - """ - generate new x509 certificate - SignEvpKey pkey to sign x509 certification, if None this x509 cert will be self signed - """ - self.CurrentObj = self.ObjMap['CA'] - self.CreatePKey () - X509Cert = M2Crypto.X509.X509 () - X509Cert.set_version ( self.Params['Version'] ) - X509Cert.set_serial_number ( self.Params['Serial'] ) - X509Cert.set_not_before ( int( time.time() - self.Params['NotBefore'] )) # 1 year in the past - X509Cert.set_not_after ( int( time.time() + self.Params['NotAfter'] )) # 5 years in the future - X509Cert.set_issuer ( self.Params['Issuer'] ) - X509Cert.set_subject ( self.Params['Subject'] ) - X509Cert.set_pubkey ( self.CurrentObj['EvpPKey'] ) - if SignEvpPKey: - X509Cert.sign ( SignEvpPKey, self.Params['Digest'] ) - else: - X509Cert.sign ( self.CurrentObj['EvpPKey'], self.Params['Digest'] ) - self.CurrentObj['X509Cert'] = X509Cert - self.DumpOutInternalPemRepr( ObjName='CA' ) - - - def CreateObjCert (self, ObjName): - """ - generate Obj with new PKey and Request, signed by 'CA' - ObjName the primary key to identify key-pair - """ - # new obj - if not self.ObjMap.has_key( ObjName ): - self.ObjMap[ObjName] = {} - self.CurrentObj = self.ObjMap[ObjName] - if not self.CurrentObj.has_key( 'Subject' ): - self.CurrentObj['Subject'] = { 'organizationalUnitName' : 'security', 'commonName' : ObjName, 'emailAddress' : 'ioclient@' + ObjName } - # new pkey - self.CreatePKey () - # new request - self.CreateReq ( SignEvpPKey=self.ObjMap['CA']['EvpPKey'] ) - # new certification - if not self.Req2Cert ( SignEvpPKey=self.ObjMap['CA']['EvpPKey'] ): - print "300 error occured while verifying - abort!" - # shipout x509 certification - self.DumpOutInternalPemRepr( ObjName=ObjName ) - - - def CreateReq ( self, SignEvpPKey=None ): - X509Req = M2Crypto.X509.Request () - if self.Params['Version']: - X509Req.set_version ( self.Params['Version'] ) - X509Req.set_subject ( self.CurrentObj['Subject'] ) - X509Req.set_pubkey ( self.CurrentObj['EvpPKey'] ) - if SignEvpPKey: - X509Req.sign ( SignEvpPKey, self.Params['Digest'] ) - else: - X509Req.sign ( self.CurrentObj['EvpPKey'], self.Params['Digest'] ) - self.CurrentObj['X509Req'] = X509Req - - - def Req2Cert ( self, SignEvpPKey=None ): - X509Cert = M2Crypto.X509.X509 () - Version = self.CurrentObj['X509Req'].get_version () - X509Cert.set_version ( Version ) - X509Cert.set_serial ( self.Params['Serial'] ) - X509Cert.set_not_before ( int( time.time() - self.Params['NotBefore'] )) # 1 year in the past - X509Cert.set_not_after ( int( time.time() + self.Params['NotAfter'] )) # 5 years in the future - Issuer = self.ObjMap['CA']['X509Cert'].get_issuer () - X509Cert.set_issuer_name ( Issuer ) - X509Name_Subject = self.CurrentObj['X509Req'].get_subject () - X509Cert.set_subject_name ( X509Name_Subject ) - PKey = self.CurrentObj['X509Req'].get_pubkey () - EvpPKey = M2Crypto.EVP.PKey( PKey ) - X509Cert.set_pubkey ( EvpPKey ) - if SignEvpPKey: - X509Cert.sign ( SignEvpPKey, self.Params['Digest'] ) - else: - X509Cert.sign ( self.CurrentObj['EvpPKey'], self.Params['Digest'] ) - self.CurrentObj['X509Cert'] = X509Cert - if self.VerifyCert ( SignEvpPKey ): - return True - else: - return False - - - - - #-------------------------------- - # CertHandler Verifying - #-------------------------------- - def ExtractPublicKeyFromCert ( self ): - self.CurrentObj['EvpPubKey'] = self.CurrentObj['X509Cert'].get_pubkey () - - def VerifyCert ( self, EvpPKey ): - if dir(EvpPKey).count('_ptr'): - Result = self.CurrentObj['X509Cert'].verify ( EvpPKey._ptr() ) - else: - Result = self.CurrentObj['X509Cert'].verify ( EvpPKey ) - if Result: - return True - return False - - - - #-------------------------------- - # CertHandler DumpOut - #-------------------------------- - def DumpOutInternalPemRepr( self, ObjName='unknown', File='PyReprPem.txt' ): - if File: - open( File, 'w').write("\t\t\t\t'%s' : { " % ( ObjName )) - else: - sys.stdout.write("\t\t\t\t'%s' : { " % ( ObjName )) - self.ShowX509CertSubject ( File ) - self.RsaPKey2PemRepr ( File, Cipher=None ) # unprotectd pkey representation - self.X509Cert2PemRepr ( File ) - if File: - open( File, 'a').write("\t\t\t\t\t }\n") - else: - sys.stdout.write("\t\t\t\t\t }\n") - - def ShowX509CertIssuer ( self, File=None ): - IssuerName = self.CurrentObj['X509Cert'].get_issuer () - print IssuerName.print_ex () - - def ShowX509CertSubject ( self, File=None ): - Subject = self.CurrentObj['X509Cert'].get_subject () - SubjectTxt = Subject.print_ex () - SubjectTxtList = re.split('[\n\r]', SubjectTxt ) - SubjectMap = {} - for Entry in SubjectTxtList: - ( Key, Value ) = re.split('=', Entry) - if self.ObjNames.has_key( Key ): - SubjectMap[ self.ObjNames[Key] ] = Value - else: - SubjectMap[ Key ] = Value - if File: - open( File, 'a').write("'Subject' : %s,\n" % ( repr( SubjectMap ) )) - else: - sys.stdout.write("Subject: %s\n" % ( repr( SubjectMap ) )) - - def RsaPKey2PemRepr ( self, File=None, Cipher=None ): - """ - converting pkey to PEM representation - Cipher if set to None, the pkey will be unprotected!!!!! possible other value: 'des_ede3_cbc' - """ - PemRsaPKey = self.CurrentObj['RsaPKey'].repr_key_pem ( cipher=Cipher ) - PemRsaPKeyList = re.split('[\n\r]', PemRsaPKey) - if File: - open( File, 'a').write("\t\t\t\t\t\t\t\t'RsaPKey' : %s,\n" % ( repr(PemRsaPKeyList[1:-2]) )) - else: - sys.stdout.write("\t\t\t\t\t\t\t\t'RsaPKey' : %s,\n" % ( repr(PemRsaPKeyList[1:-2]) )) - - def X509Cert2PemRepr ( self, File=None ): - PemCert = self.CurrentObj['X509Cert'].repr_cert_pem () - #print PemCert - PemCertList = re.split('[\n\r]', PemCert) - if File: - open( File, 'a').write("\t\t\t\t\t\t\t\t'X509Cert' : %s\n" % ( repr(PemCertList[1:-2]) )) - else: - sys.stdout.write("\t\t\t\t\t\t\t\t'X509Cert' : %s\n" % ( repr(PemCertList[1:-2]) )) - - - - #-------------------------------- - # CertHandler encryption / decryption - #-------------------------------- - def CreateNonce ( self ): - """ - creating some randomised data - return new Nonce string - """ - random.seed () - RawNonce = "%s_%f_%f" % ( os.getpid(), time.time(), random.random() ) - sha1=M2Crypto.EVP.MessageDigest('sha1') - sha1.update( RawNonce ) - NonceDecrypted = sha1.digest() - return NonceDecrypted - - def NonceEncryptPrivate ( self, NonceDecrypted, RsaPKey=None ): - """ - creating private encrypted string from NonceDecrypted - """ - padding = M2Crypto.RSA.pkcs1_padding - if not RsaPKey: - UsedRsaPKey = self.ServerObj['RsaPKey'] - else: - UsedRsaPKey = RsaPKey - NoncePrivEncrypted = UsedRsaPKey.private_encrypt ( NonceDecrypted, padding ) - return NoncePrivEncrypted - - def NonceEncryptPublic ( self, NonceDecrypted, RsaPubKey=None ): - """ - creating public encrypted string from NonceDecrypted - """ - padding = M2Crypto.RSA.pkcs1_padding - if not RsaPubKey: - UsedRsaPubKey = self.ServerObj['RsaPubKey'] - else: - UsedRsaPubKey = RsaPubKey - NoncePubEncrypted = UsedRsaPubKey.public_encrypt ( NonceDecrypted, padding ) - return NoncePubEncrypted - - def NonceDecryptPublic ( self, NoncePrivEncrypted, RsaPubKey=None ): - """ - creating decrypted string from NoncePrivEncrypted - """ - padding = M2Crypto.RSA.pkcs1_padding - if not RsaPubKey: - UsedRsaPubKey = self.ServerObj['RsaPubKey'] - else: - UsedRsaPubKey = RsaPubKey - try: - NonceDecrypted = UsedRsaPubKey.public_decrypt ( NoncePrivEncrypted, padding ) - except: - raise AuthError('decrypting of public key failed - abort!') - return NonceDecrypted - - def NonceDecryptPrivate ( self, NoncePubEncrypted, RsaPKey=None ): - padding = M2Crypto.RSA.pkcs1_padding - if not RsaPKey: - UsedRsaPKey = self.ServerObj['RsaPKey'] - else: - UsedRsaPKey = RsaPKey - NonceDecrypted = UsedRsaPKey.private_decrypt ( NoncePubEncrypted, padding ) - return NonceDecrypted - - def NonceVerify ( self, DecryptedNonce=None ): - if self.CurrentObj['Nonce']['Decrypted'] == DecryptNonce: - return True - return False - - #-------------------------------- - # CertHandler authentication request - #-------------------------------- - def ClientInit ( self, ObjName=None ): - """ - generating AuthString - Nonce messagedigest 'sha1', encrypted with own instance private key - Cert own instance X509 cert, PEM encoded - any linefeed charaters stripped out of the base64 code - return generated Nonce and AuthString - """ - if ObjName: - if self.PemMap.has_key( ObjName ): - UsedObjName = ObjName - else: - UsedObjName = self.ServerName - else: - UsedObjName = self.ServerName - - NonceDecrypted = self.CreateNonce () - NoncePrivEncrypted = re.sub('\012', '', base64.encodestring( self.NonceEncryptPrivate ( NonceDecrypted, RsaPKey=self.ServerObj['RsaPKey'] )) ) - PemCert = re.sub('\012', '', base64.encodestring( self.KeyEnv['X509Cert'][0] + '\n' + string.join( self.PemMap[UsedObjName]['X509Cert'], '\n' ) + '\n' + self.KeyEnv['X509Cert'][1] + '\n' )) - InitString = re.sub('\012', '', base64.encodestring('%s:%s' % ( NoncePrivEncrypted, PemCert ))) - return ( NonceDecrypted, InitString ) - - - def ClientInitVerify ( self, InitString ): - """ - return decrypted Nonce from AuthString and ObjName from AuthString X509 Cert - """ - try: - PemBaseString = base64.decodestring( InitString ) - except base64.binascii.Error, msg: - raise base64.binascii.Error( msg ) - try: - ( Base64Nonce, Base64Cert ) = re.split(':', PemBaseString ) - except: - raise AuthError( 'cannot split PemBaseString into parts - abort!' ) - try: - NoncePrivEncrypted = base64.decodestring( Base64Nonce ) - except base64.binascii.Error, msg: - raise base64.binascii.Error( msg ) - try: - PemCert = base64.decodestring( Base64Cert ) - except base64.binascii.Error, msg: - raise base64.binascii.Error( msg ) - try: - X509Cert = M2Crypto.X509.load_cert_string( PemCert ) - except: - raise AuthError( 'cannot extract X509 cert from PEM representation - abort!' ) - EvpPKey = self.ObjMap['CA']['EvpPKey'] - if dir(EvpPKey).count('_ptr'): - Result = X509Cert.verify ( EvpPKey._ptr() ) - else: - Result = X509Cert.verify ( EvpPKey ) - if Result != 1: - raise AuthError( 'verification of X509 cert with Certification Authority "CA" failed with code %d - abort!' % ( Result )) - ClientObjName = self.ObjNameFromPemCert( PemCert=PemCert ) - try: - NonceDecrypted = self.NonceDecryptPublic( NoncePrivEncrypted, RsaPubKey=self.CurrentObj['RsaPubKey'] ) - except: - raise AuthError( 'wrong public key for encoding nonce - abort!' ) - - return ( NonceDecrypted, ClientObjName ) - - - - - def ServerInit ( self, ClientObjName, ClientNonce ): - """ - NonceServer new Nonce from server encrypted with client publickey and base64 encoded - NonceBounce the authrequest nonce encrypted with server privatekey and base64 encoded - PemServerCert server X509 certification PEM encoded and base64 encoded - """ - if not self.ObjMap.has_key( ClientObjName ): - if not self.PemMap.has_key( ClientObjName ): - raise AuthError( 'cannot find ClientObjName - abort!' ) - else: - self.ObjFromContainer( ObjName=ClientObjName ) - else: - self.CurrentObj = self.ObjMap[ClientObjName] - - NonceDecrypted = self.CreateNonce () - NonceServer = re.sub('\012', '', base64.encodestring( self.NonceEncryptPublic ( NonceDecrypted, RsaPubKey=self.CurrentObj['RsaPubKey'] )) ) - NonceBounce = re.sub('\012', '', base64.encodestring( self.NonceEncryptPublic ( ClientNonce, RsaPubKey=self.CurrentObj['RsaPubKey'] )) ) - PemServerCert = re.sub('\012', '', base64.encodestring( self.KeyEnv['X509Cert'][0] + '\n' + string.join( self.PemMap[self.ServerName]['X509Cert'], '\n' ) + '\n' + self.KeyEnv['X509Cert'][1] + '\n' ) ) - - InitString = re.sub('\012', '', base64.encodestring('%s:%s:%s' % ( NonceServer, NonceBounce, PemServerCert )) ) - return ( NonceDecrypted, InitString ) - - - def ServerInitVerify ( self, InitString, ObjName=None ): - NonceDecrypted = '' - ObjName = '' - try: - PemBaseString = base64.decodestring( InitString ) - except: - return False - - ( NonceServer, NonceBounce, ServerCert ) = re.split(':', PemBaseString ) - NoncePubServer = base64.decodestring( NonceServer ) # NonceServer - NoncePubBounce = base64.decodestring( NonceBounce ) # NonceBounce - PemServerCert = base64.decodestring( ServerCert ) # PemServerCert - - try: - X509Cert = M2Crypto.X509.load_cert_string( PemServerCert ) - except: - return False - - # verify X509 cert - EvpPKey = self.ObjMap['CA']['EvpPKey'] - if dir(EvpPKey).count('_ptr'): - Result = X509Cert.verify ( EvpPKey._ptr() ) - else: - Result = X509Cert.verify ( EvpPKey ) - if not Result: - return False - - # verify Nonce from Server encrypted with my own publickey - try: - NonceDecrypted = self.NonceDecryptPrivate( NoncePubServer, RsaPKey=self.ServerObj['RsaPKey'] ) - except: - return False - - ServerObjName = self.ObjNameFromPemCert( PemCert=PemServerCert ) - - # verify Nonce bounced from Server encrypted with server privatekey - try: - NonceBounceDecrypted = self.NonceDecryptPrivate( NoncePubBounce, RsaPKey=self.CurrentObj['RsaPKey'] ) - except: - return False - - return ( NonceDecrypted, NonceBounceDecrypted, ServerObjName ) - - - - def ReplyInit ( self, ReplyObjName, ReplyBounce ): - NonceDecrypted = self.CreateNonce () - NoncePubInit = re.sub('\012', '', base64.encodestring( self.NonceEncryptPublic ( NonceDecrypted, RsaPubKey=self.ObjMap[ ReplyObjName ]['RsaPubKey'] )) ) - NoncePubBounce = re.sub('\012', '', base64.encodestring( self.NonceEncryptPublic ( ReplyBounce, RsaPubKey=self.ObjMap[ ReplyObjName ]['RsaPubKey'] )) ) - ReplyString = re.sub('\012', '', base64.encodestring('%s:%s' % ( NoncePubInit, NoncePubBounce )) ) - return ( NonceDecrypted, ReplyString ) - - - def ReplyVerify ( self, ReplyString ): - try: - PemBaseString = base64.decodestring( ReplyString ) - except base64.binascii.Error, msg: - raise base64.binascii.Error( msg ) - ( NoncePubInit, NoncePubBounce ) = re.split(':', PemBaseString ) - - try: - NoncePubInit = base64.decodestring( NoncePubInit ) # new Nonce from Remote, encrypted with own publickey - except base64.binascii.Error, msg: - raise base64.binascii.Error( msg ) - try: - NoncePubBounce = base64.decodestring( NoncePubBounce ) # bounced Nonce from Remote, encrypted with Remote privatekey - except base64.binascii.Error, msg: - raise base64.binascii.Error( msg ) - - # verify Nonce from Remote encrypted with my own publickey - try: - NonceRemote = self.NonceDecryptPrivate( NoncePubInit, RsaPKey=self.ServerObj['RsaPKey'] ) - except: - raise AuthError( 'cannot encode nonce with own private key - abort!' ) - - # verify Nonce bounced from Remote encrypted with Remote privatekey - try: - NonceBounced = self.NonceDecryptPrivate( NoncePubBounce, RsaPKey=self.ServerObj['RsaPKey'] ) - except: - raise AuthError( 'wrong public key for encoding nonce - abort!' ) - - return ( NonceRemote, NonceBounced ) - - - - - #------------------------------------------------------------------------------------------- - # TEST - #------------------------------------------------------------------------------------------- - def CreateCAForContainer ( self ): - self.CreateCert () - - def CreateForContainer ( self, ObjName ): - """ - create new pkey pair and x509 cert for specified objname - result will be written in file "PyReprPem.txt" - """ - self.ObjFromContainer ( ObjName='AuthInstance' ) - self.CreateObjCert ( ObjName=ObjName ) - - - def Test ( self ): - #self.CreateCert () - #self.ExtractPublicKeyFromCert () - #self.VerifyCert () - - ( ClientInitNonce, ClientInitString ) = self.ClientInit () - ( ClientSendNonce, ClientObjName ) = self.ClientInitVerify ( InitString=ClientInitString ) - ( ServerInitNonce, ServerInitString ) = self.ServerInit ( ClientObjName=ClientObjName, ClientNonce=ClientSendNonce ) - ( ServerSendNonce, ClientBounceNonce, ServerObjName ) = self.ServerInitVerify ( InitString=ServerInitString ) - if ClientInitNonce == ClientBounceNonce : - print '100 Test Nonce bounced True' - else: - print '100 Test Nonce bounced False - abort!' - - ( ReplyInitNonce, ReplyInitString ) = self.ReplyInit ( ReplyObjName=ClientObjName, ReplyBounce=ServerSendNonce ) - ( ReplySendNonce, NonceBounced ) = self.ReplyVerify ( ReplyString=ReplyInitString ) - if ServerInitNonce == NonceBounced : - print '100 Test Nonce bounced True' - else: - print '100 Test Nonce bounced False - abort!' - - ( Reply2InitNonce, Reply2InitString ) = self.ReplyInit ( ReplyObjName=ClientObjName, ReplyBounce=ServerSendNonce ) - ( Reply2SendNonce, Nonce2Bounced ) = self.ReplyVerify ( ReplyString=Reply2InitString ) - if ServerInitNonce == Nonce2Bounced : - print '100 Test Nonce bounced True' - else: - print '100 Test Nonce bounced False - abort!' - - #self.NonceEncryptPrivate () - #self.NonceDecryptPublic () - #self.NonceVerify () - - -#----------------------------------------------------------------------------------------------- -# MAIN -# -# x509auth.py --ca -# will create a file "PyReprPem.txt" in the current directory -# append the contents of the file to the CertContainer in this script -# -# x509auth.py --cert -# creates a file "PyReprPem.txt" in the current directory -# append the contents of the file to the CertContainer in this script -# -# x509auth.py --test -# running authentification tests with bounced nonce -# -#----------------------------------------------------------------------------------------------- -if __name__ == '__main__': - run = CertHandler () - - if len( sys.argv ) > 1: - if sys.argv[1] == '--test': - run.Test () - elif sys.argv[1] == '--ca': - run.CreateCert() - elif sys.argv[1] == '--cert': - run.CreateForContainer( sys.argv[2] ) - - sys.exit( 0 ) - diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..6c4932c --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1,2 @@ +wheel +twine diff --git a/doc/M2Crypto.SSL.rst b/doc/M2Crypto.SSL.rst new file mode 100644 index 0000000..233c1eb --- /dev/null +++ b/doc/M2Crypto.SSL.rst @@ -0,0 +1,91 @@ +SSL Package +=========== + +:mod:`SSL` Package +------------------ + +.. automodule:: M2Crypto.SSL + :members: + :undoc-members: + :show-inheritance: + +:mod:`Checker` Module +--------------------- + +.. automodule:: M2Crypto.SSL.Checker + :members: + :undoc-members: + :show-inheritance: + +:mod:`Cipher` Module +-------------------- + +.. automodule:: M2Crypto.SSL.Cipher + :members: + :undoc-members: + :show-inheritance: + +:mod:`Connection` Module +------------------------ + +.. automodule:: M2Crypto.SSL.Connection + :members: + :undoc-members: + :show-inheritance: + +:mod:`Context` Module +--------------------- + +.. automodule:: M2Crypto.SSL.Context + :members: + :undoc-members: + :show-inheritance: + +:mod:`SSLServer` Module +----------------------- + +.. automodule:: M2Crypto.SSL.SSLServer + :members: + :undoc-members: + :show-inheritance: + +:mod:`Session` Module +--------------------- + +.. automodule:: M2Crypto.SSL.Session + :members: + :undoc-members: + :show-inheritance: + +:mod:`TwistedProtocolWrapper` Module +------------------------------------ + +.. automodule:: M2Crypto.SSL.TwistedProtocolWrapper + :members: + :undoc-members: + :show-inheritance: + +:mod:`cb` Module +---------------- + +.. automodule:: M2Crypto.SSL.cb + :members: + :undoc-members: + :show-inheritance: + +:mod:`ssl_dispatcher` Module +---------------------------- + +.. automodule:: M2Crypto.SSL.ssl_dispatcher + :members: + :undoc-members: + :show-inheritance: + +:mod:`timeout` Module +--------------------- + +.. automodule:: M2Crypto.SSL.timeout + :members: + :undoc-members: + :show-inheritance: + diff --git a/doc/M2Crypto.rst b/doc/M2Crypto.rst new file mode 100644 index 0000000..dc6c706 --- /dev/null +++ b/doc/M2Crypto.rst @@ -0,0 +1,218 @@ +M2Crypto Package +================ + +:mod:`M2Crypto` Package +----------------------- + +.. automodule:: M2Crypto.__init__ + :members: + :undoc-members: + :show-inheritance: + +:mod:`ASN1` Module +------------------ + +.. automodule:: M2Crypto.ASN1 + :members: + :undoc-members: + :show-inheritance: + +:mod:`AuthCookie` Module +------------------------ + +.. automodule:: M2Crypto.AuthCookie + :members: + :undoc-members: + :show-inheritance: + +:mod:`BIO` Module +----------------- + +.. automodule:: M2Crypto.BIO + :members: + :undoc-members: + :show-inheritance: + +:mod:`BN` Module +---------------- + +.. automodule:: M2Crypto.BN + :members: + :undoc-members: + :show-inheritance: + +:mod:`DH` Module +---------------- + +.. automodule:: M2Crypto.DH + :members: + :undoc-members: + :show-inheritance: + +:mod:`DSA` Module +----------------- + +.. automodule:: M2Crypto.DSA + :members: + :undoc-members: + :show-inheritance: + +:mod:`EC` Module +---------------- + +.. automodule:: M2Crypto.EC + :members: + :undoc-members: + :show-inheritance: + +:mod:`EVP` Module +----------------- + +.. automodule:: M2Crypto.EVP + :members: + :undoc-members: + :show-inheritance: + +:mod:`Engine` Module +-------------------- + +.. automodule:: M2Crypto.Engine + :members: + :undoc-members: + :show-inheritance: + +:mod:`Err` Module +----------------- + +.. automodule:: M2Crypto.Err + :members: + :undoc-members: + :show-inheritance: + +:mod:`RC4` Module +----------------- + +.. automodule:: M2Crypto.RC4 + :members: + :undoc-members: + :show-inheritance: + +:mod:`RSA` Module +----------------- + +.. automodule:: M2Crypto.RSA + :members: + :undoc-members: + :show-inheritance: + +:mod:`Rand` Module +------------------ + +.. automodule:: M2Crypto.Rand + :members: + :undoc-members: + :show-inheritance: + +:mod:`SMIME` Module +------------------- + +.. automodule:: M2Crypto.SMIME + :members: + :undoc-members: + :show-inheritance: + +:mod:`X509` Module +------------------ + +.. automodule:: M2Crypto.X509 + :members: + :undoc-members: + :show-inheritance: + +:mod:`callback` Module +---------------------- + +.. automodule:: M2Crypto.callback + :members: + :undoc-members: + :show-inheritance: + +:mod:`ftpslib` Module +--------------------- + +.. automodule:: M2Crypto.ftpslib + :members: + :undoc-members: + :show-inheritance: + +:mod:`httpslib` Module +---------------------- + +.. automodule:: M2Crypto.httpslib + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2` Module +---------------- + +.. automodule:: M2Crypto.m2 + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2crypto` Module +---------------------- + +.. automodule:: M2Crypto.m2crypto + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2urllib` Module +---------------------- + +.. automodule:: M2Crypto.m2urllib + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2urllib2` Module +----------------------- + +.. automodule:: M2Crypto.m2urllib2 + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2xmlrpclib` Module +------------------------- + +.. automodule:: M2Crypto.m2xmlrpclib + :members: + :undoc-members: + :show-inheritance: + +:mod:`threading` Module +----------------------- + +.. automodule:: M2Crypto.threading + :members: + :undoc-members: + :show-inheritance: + +:mod:`util` Module +------------------ + +.. automodule:: M2Crypto.util + :members: + :undoc-members: + :show-inheritance: + +Subpackages +----------- + +.. toctree:: + + M2Crypto.SSL + diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..cbe8480 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = . + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/{doctrees,html} + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/M2Crypto.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/M2Crypto.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/M2Crypto" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/M2Crypto" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/ZServerSSL-HOWTO.html b/doc/ZServerSSL-HOWTO.html deleted file mode 100644 index 78c15a9..0000000 --- a/doc/ZServerSSL-HOWTO.html +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - - - -ZServerSSL HOWTO - - - - - -
    -

    ZServerSSL HOWTO

    - --- - - - - - - - - - -
    Author:Ng Pheng Siong
    Id:ZServerSSL-HOWTO,v 1.1 2003/06/22 17:40:13 ngps Exp
    Date:2003-06-22
    Web-Site:http://chandlerproject.org/Projects/MeTooCrypto
    - -
    -

    Introduction

    -

    ZServerSSL adds to Zope's ZServer the following:

    -
      -
    • HTTPS server
    • -
    • WebDAV-source-over-HTTPS server
    • -
    -

    With the HTTPS server, ZServerSSL also provides WebDAV-over-HTTPS -and XMLRPC-over-HTTPS access to Zope.

    -

    These instructions apply to both Un*x and Windows installations of -Zope 2.6.1. To avoid cluttering the presentation, Windows pathnames -are shown in Un*x fashion.

    -
    -
    -

    Preparation

    -
      -
    1. Download M2Crypto 0.11, contained in the file m2crypto-0.11.zip.
    2. -
    3. Unpack m2crypto-0.11.zip. This will create a directory -m2crypto-0.11. Henceforth, we refer to this directory as $M2.
    4. -
    5. Install M2Crypto per the instructions in $M2/INSTALL.
    6. -
    -

    The ZServerSSL distribution is in $M2/demo/Zope. We shall refer to -this directory as $ZSSL.

    -
    -
    -

    Installation

    -

    Below, we refer to your Zope top-level directory as $ZOPE.

    -
      -
    1. Copy $ZSSL/z2s.py into $ZOPE.

      -
    2. -
    3. Depending on your operating system, modify $ZOPE/start or -$ZOPE/start.bat to invoke $ZOPE/z2s.py, instead of -$ZOPE/z2.py. The files $ZSSL/starts and -$ZSSL/starts.bat serve as examples.

      -
    4. -
    5. Copy $ZSSL/dh1024.pem into $ZOPE. This file contains -Diffie-Hellman parameters for use by the SSL protocol.

      -
    6. -
    7. Copy $ZSSL/randpool.dat into $ZOPE. This file contains seed -material for the OpenSSL PRNG. Alternatively, create -$ZOPE/randpool.dat thusly:

      -
      -$ dd if=/dev/urandom of=randpool.dat bs=1024 count=1
      -
      -
    8. -
    9. Copy $ZSSL/ca.pem to $ZOPE. This file contains an example -Certification Authority (CA) certificate. For information on -operating your own CA, see -howto.ca.html or one of numerous -similar documents available on the web.

      -
    10. -
    11. Copy $ZSSL/server.pem to $ZOPE. This file contains an RSA -key pair and its X.509v3 certificate issued by the above CA. You -may also create your own key/certificate bundle.

      -
    12. -
    13. Copy $ZSSL/ZServer/HTTPS_Server.py to $ZOPE/ZServer.

      -
    14. -
    15. Copy $ZSSL/ZServer/__init__.py to $ZOPE/ZServer. This -overwrites the existing $ZOPE/ZServer/__init__.py. Alternatively, -apply the following patch to $ZOPE/ZServer/__init__.py:

      -
      ---- __init__.py.org     Sat Jun 21 23:20:41 2003
      -+++ __init__.py Tue Jan  7 23:30:53 2003
      -@@ -84,6 +84,7 @@
      - import asyncore
      - from medusa import resolver, logger
      - from HTTPServer import zhttp_server, zhttp_handler
      -+from HTTPS_Server import zhttps_server, zhttps_handler
      - from PCGIServer import PCGIServer
      - from FCGIServer import FCGIServer
      - from FTPServer import FTPServer
      -
      -
    16. -
    17. Copy $ZSSL/ZServer/medusa/https_server.py to -$ZOPE/ZServer/medusa.

      -
    18. -
    19. Stop Zope, if it is running.

      -
    20. -
    21. Start Zope with ZServerSSL thusly:

      -
      -./starts -X -f 9021 -w 9080 -W 9081 -y 9443 -Y 9444
      -
      -

      This starts the following:

      -
        -
      • an FTP server on port 9021
      • -
      • a HTTP server on port 9080
      • -
      • a WebDAV-source server on port 9081
      • -
      • a HTTPS server on port 9443
      • -
      • a WebDAV-source-over-HTTPS server on port 9444
      • -
      -
    22. -
    -
    -
    -

    Testing

    -

    Below, we assume your Zope server is running on localhost.

    -
    -

    HTTPS

    -

    This testing is done with Mozilla 1.1 on FreeBSD.

    -
      -
    1. With a browser, connect to https://localhost:9443/. Browse -around. Check out your browser's HTTPS informational screens.
    2. -
    3. Connect to https://localhost:9443/manage. Verify that you can -access Zope's management functionality.
    4. -
    -
    -
    -

    WebDAV-over-HTTPS

    -

    This testing is done with Cadaver 0.21.0 on FreeBSD.

    -
    -$ cadaver https://localhost:9443/
    -WARNING: Untrusted server certificate presented:
    -Issued to: M2Crypto, SG
    -Issued by: M2Crypto, SG
    -Do you wish to accept the certificate? (y/n) y
    -dav:/> ls
    -Listing collection `/': succeeded.
    -Coll:   Channels                               0  Jun 19 00:04
    -Coll:   Control_Panel                          0  Jun  6 00:13
    -Coll:   Examples                               0  Jun  6 00:12
    -Coll:   catalog                                0  Jun 12 11:53
    -Coll:   ngps                                   0  Jun 16 15:34
    -Coll:   portal                                 0  Jun 21 15:21
    -Coll:   skunk                                  0  Jun 18 21:18
    -Coll:   temp_folder                            0  Jun 22 17:57
    -Coll:   zope                                   0  Jun 20 15:27
    -        acl_users                              0  Dec 30  1998
    -        browser_id_manager                     0  Jun  6 00:12
    -        default.css                         3037  Jun 21 16:38
    -        error_log                              0  Jun  6 00:12
    -        index_html                           313  Jun 12 13:36
    -        portal0                                0  Jun 21 15:21
    -        session_data_manager                   0  Jun  6 00:12
    -        standard_error_message              1365  Jan 21  2001
    -        standard_html_footer                  50  Jun 12 12:30
    -        standard_html_header                  80  Jan 21  2001
    -        standard_template.pt                 282  Jun  6 00:12
    -        zsyncer                                0  Jun 17 15:28
    -dav:/> quit
    -Connection to `localhost' closed.
    -$ 
    -
    -
    -
    -

    WebDAV-Source-over-HTTPS

    -

    This testing is done with Mozilla 1.1 on FreeBSD.

    -
      -
    1. Open the Mozilla Composer window.
    2. -
    3. Click "File", "Open Web Location". A dialog box appears.
    4. -
    5. Enter https://localhost:9444/index_html for the URL.
    6. -
    7. Select "Open in new Composer window."
    8. -
    9. Click "Open". A new Composer window will open with index_html -loaded.
    10. -
    -
    -
    -

    Python with M2Crypto

    -

    This testing is done with M2Crypto 0.11 and Python 2.2.2 on FreeBSD.

    -
    -

    HTTPS

    -
    ->>> from M2Crypto import Rand, SSL, m2urllib
    ->>> url = m2urllib.FancyURLopener()
    ->>> url.addheader('Connection', 'close')
    ->>> u = url.open('https://127.0.0.1:9443/')
    -send: 'GET / HTTP/1.1\r\nHost: 127.0.0.1:9443\r\nAccept-Encoding: identity\r\nUser-agent: Python-urllib/1.15\r\nConnection: close\r\n\r\n'
    -reply: 'HTTP/1.1 200 OK\r\n'
    -header: Server: ZServerSSL/0.11
    -header: Date: Sun, 22 Jun 2003 13:42:34 GMT
    -header: Connection: close
    -header: Content-Type: text/html
    -header: Etag: 
    -header: Content-Length: 535
    ->>> while 1:
    -...     data = u.read()
    -...     if not data: break
    -...     print data
    -... 
    -
    -
    -<html><head>
    -<base href="https://127.0.0.1:9443/" />
    -<title>Zope</title></head><body bgcolor="#FFFFFF">
    -
    -<h1>NgPS Desktop Portal</h1>
    -
    -&nbsp;&nbsp;So many hacks.<br>
    -&nbsp;&nbsp;So little time.<br>
    -
    -<h2>Link Farm</h2>
    -<ul>
    -<li><a href="http://localhost:8080/portal">Portal</a></li>
    -<li><a href="http://localhost/">Local Apache Home Page</a></li>
    -</ul>
    -
    -<hr><a href="http://www.zope.org/Credits" target="_top"><img src="https://127.0.0.1:9443/p_/ZopeButton" width="115" height="50" border="0" alt="Powered by Zope" /></a></body></html>
    -
    -
    ->>> u.close()
    ->>> 
    -
    -
    -
    -

    XMLRPC-over-HTTPS

    -
    ->>> from M2Crypto.m2xmlrpclib import Server, SSL_Transport
    ->>> zs = Server('https://127.0.0.1:9443/', SSL_Transport())
    ->>> print zs.propertyMap()
    -[{'type': 'string', 'id': 'title', 'mode': 'w'}]
    ->>> 
    -
    -
    -
    -
    -
    -

    Conclusion

    -

    Well, it works! ;-)

    -
    -
    - - diff --git a/doc/ZServerSSL-HOWTO.rst b/doc/ZServerSSL-HOWTO.rst new file mode 100644 index 0000000..91ef5af --- /dev/null +++ b/doc/ZServerSSL-HOWTO.rst @@ -0,0 +1,239 @@ +:orphan: + +.. _zserverssl-howto: + +ZServerSSL-HOWTO +################ + +:author: Pheng Siong Ng +:copyright: © 2000, 2001 by Ng Pheng Siong. +:date: 2003-06-22 + +.. contents:: + :backlinks: entry + +.. sectnum:: + :suffix: . + +Introduction +============ + +ZServerSSL adds to Zope's ZServer the following: + +- HTTPS server +- WebDAV-source-over-HTTPS server + +With the HTTPS server, ZServerSSL also provides WebDAV-over-HTTPS and +XMLRPC-over-HTTPS access to Zope. + +These instructions apply to both Un\*x and Windows installations of Zope +2.6.1. To avoid cluttering the presentation, Windows pathnames are shown +in Un\*x fashion. + +Preparation +=========== + +#. Download M2Crypto 0.11, contained in the file ``m2crypto-0.11.zip``. +#. Unpack ``m2crypto-0.11.zip``. This will create a directory + ``m2crypto-0.11``. Henceforth, we refer to this directory as ``$M2``. +#. Install M2Crypto per the instructions in ``$M2/INSTALL``. + +The ZServerSSL distribution is in ``$M2/demo/Zope``. We shall refer to +this directory as ``$ZSSL``. + +Installation +============ + +Below, we refer to your Zope top-level directory as ``$ZOPE``. + +#. Copy ``$ZSSL/z2s.py`` into ``$ZOPE``. + +#. Depending on your operating system, modify ``$ZOPE/start`` or + ``$ZOPE/start.bat`` to invoke ``$ZOPE/z2s.py``, instead of + ``$ZOPE/z2.py``. The files ``$ZSSL/starts`` and ``$ZSSL/starts.bat`` + serve as examples. + +#. Copy ``$ZSSL/dh1024.pem`` into ``$ZOPE``. This file contains + Diffie-Hellman parameters for use by the SSL protocol. + +#. Copy ``$ZSSL/randpool.dat`` into ``$ZOPE``. This file contains seed + material for the OpenSSL PRNG. Alternatively, create + ``$ZOPE/randpool.dat`` thusly:: + + $ dd if=/dev/urandom of=randpool.dat bs=1024 count=1 + +#. Copy ``$ZSSL/ca.pem`` to ``$ZOPE``. This file contains an + example Certification Authority (CA) certificate. For + information on operating your own CA, see :ref:`howto-ca` or + one of numerous similar documents available on the web. + +#. Copy ``$ZSSL/server.pem`` to ``$ZOPE``. This file contains an RSA key + pair and its X.509v3 certificate issued by the above CA. You may also + create your own key/certificate bundle. + +#. Copy ``$ZSSL/ZServer/HTTPS_Server.py`` to ``$ZOPE/ZServer``. + +#. Copy ``$ZSSL/ZServer/__init__.py`` to ``$ZOPE/ZServer``. This + overwrites the existing ``$ZOPE/ZServer/__init__.py``. Alternatively, + apply the following patch to ``$ZOPE/ZServer/__init__.py``:: + + --- __init__.py.org Sat Jun 21 23:20:41 2003 + +++ __init__.py Tue Jan 7 23:30:53 2003 + @@ -84,6 +84,7 @@ + import asyncore + from medusa import resolver, logger + from HTTPServer import zhttp_server, zhttp_handler + +from HTTPS_Server import zhttps_server, zhttps_handler + from PCGIServer import PCGIServer + from FCGIServer import FCGIServer + from FTPServer import FTPServer + +#. Copy ``$ZSSL/ZServer/medusa/https_server.py`` to + ``$ZOPE/ZServer/medusa``. + +#. Stop Zope, if it is running. + +#. Start Zope with ZServerSSL thusly:: + + ./starts -X -f 9021 -w 9080 -W 9081 -y 9443 -Y 9444 + + This starts the following: + + - an FTP server on port 9021 + - a HTTP server on port 9080 + - a WebDAV-source server on port 9081 + - a HTTPS server on port 9443 + - a WebDAV-source-over-HTTPS server on port 9444 + +Testing +======= + +Below, we assume your Zope server is running on ``localhost``. + +HTTPS +===== + +This testing is done with Mozilla 1.1 on FreeBSD. + +#. With a browser, connect to https://localhost:9443/. Browse around. + Check out your browser's HTTPS informational screens. +#. Connect to https://localhost:9443/manage. Verify that you can access + Zope's management functionality. + +WebDAV-over-HTTPS +================= + +This testing is done with Cadaver 0.21.0 on FreeBSD.:: + + $ cadaver https://localhost:9443/ + WARNING: Untrusted server certificate presented: + Issued to: M2Crypto, SG + Issued by: M2Crypto, SG + Do you wish to accept the certificate? (y/n) y + dav:/> ls + Listing collection `/': succeeded. + Coll: Channels 0 Jun 19 00:04 + Coll: Control_Panel 0 Jun 6 00:13 + Coll: Examples 0 Jun 6 00:12 + Coll: catalog 0 Jun 12 11:53 + Coll: ngps 0 Jun 16 15:34 + Coll: portal 0 Jun 21 15:21 + Coll: skunk 0 Jun 18 21:18 + Coll: temp_folder 0 Jun 22 17:57 + Coll: zope 0 Jun 20 15:27 + acl_users 0 Dec 30 1998 + browser_id_manager 0 Jun 6 00:12 + default.css 3037 Jun 21 16:38 + error_log 0 Jun 6 00:12 + index_html 313 Jun 12 13:36 + portal0 0 Jun 21 15:21 + session_data_manager 0 Jun 6 00:12 + standard_error_message 1365 Jan 21 2001 + standard_html_footer 50 Jun 12 12:30 + standard_html_header 80 Jan 21 2001 + standard_template.pt 282 Jun 6 00:12 + zsyncer 0 Jun 17 15:28 + dav:/> quit + Connection to `localhost' closed. + $ + + +WebDAV-Source-over-HTTPS +======================== + +This testing is done with Mozilla 1.1 on FreeBSD. + +#. Open the Mozilla Composer window. +#. Click "File", "Open Web Location". A dialog box appears. +#. Enter ``https://localhost:9444/index_html`` for the URL. +#. Select "Open in new Composer window." +#. Click "Open". A new Composer window will open with ``index_html`` + loaded. + +Python with M2Crypto +==================== + +This testing is done with M2Crypto 0.11 and Python 2.2.2 on FreeBSD. + +HTTPS +===== + +:: + + >>> from M2Crypto import Rand, SSL, m2urllib + >>> url = m2urllib.FancyURLopener() + >>> url.addheader('Connection', 'close') + >>> u = url.open('https://127.0.0.1:9443/') + send: 'GET / HTTP/1.1\r\nHost: 127.0.0.1:9443\r\nAccept-Encoding: identity\r\nUser-agent: Python-urllib/1.15\r\nConnection: close\r\n\r\n' + reply: 'HTTP/1.1 200 OK\r\n' + header: Server: ZServerSSL/0.11 + header: Date: Sun, 22 Jun 2003 13:42:34 GMT + header: Connection: close + header: Content-Type: text/html + header: Etag: + header: Content-Length: 535 + >>> while 1: + ... data = u.read() + ... if not data: break + ... print(data) + ... + +:: + + + + Zope + +

    NgPS Desktop Portal

    + +   So many hacks.
    +   So little time.
    + +

    Link Farm

    + + +
    Powered by Zope + +:: + + >>> u.close() + >>> + +XMLRPC-over-HTTPS +================= + +:: + + >>> from M2Crypto.m2xmlrpclib import Server, SSL_Transport + >>> zs = Server('https://127.0.0.1:9443/', SSL_Transport()) + >>> print(zs.propertyMap()) + [{'type': 'string', 'id': 'title', 'mode': 'w'}] + >>> + +Conclusion +========== + +Well, it works! ;-) diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..8530a00 --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,285 @@ +# -*- coding: utf-8 -*- +# +# M2Crypto documentation build configuration file, created by +# sphinx-quickstart on Thu Apr 20 11:15:12 2017. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath(os.path.join('..'))) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'M2Crypto' +copyright = u'2017, Matej Cepl ' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '' +# The full version, including alpha/beta/rc tags. +release = '' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'M2Cryptodoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'M2Crypto.tex', u'M2Crypto Documentation', + u'Matej Cepl \\textless{}mcepl@cepl.eu\\textgreater{}', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'm2crypto', u'M2Crypto Documentation', + [u'Matej Cepl '], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'M2Crypto', u'M2Crypto Documentation', + u'Matej Cepl ', 'M2Crypto', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# -- Options for Epub output --------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'M2Crypto' +epub_author = u'Matej Cepl ' +epub_publisher = u'Matej Cepl ' +epub_copyright = u'2017, Matej Cepl ' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +#epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True diff --git a/doc/doctrees/M2Crypto.SSL.doctree b/doc/doctrees/M2Crypto.SSL.doctree new file mode 100644 index 0000000000000000000000000000000000000000..7ea180d702c3051507d2c73564d3c87667228632 GIT binary patch literal 349315 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

    %D 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 {3lrP7cI#MStxWd`X%Q(~ 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 z z)o(AB=U_#S%CIDtF}uiIuo0QRk*E-ND~MgIg=DwpQt008#{Kl&+l`H4s^#-#%5 zv^OIDo#-}PyjpwVq$x)7CX z5&9oQiA8%py+pf#=Wbh~oxr90*2jIt9q2!>RIkDozOWpxPA*;@uEybHHRPB+G|w&o M-Z0OVtIrny0b`Kqs{jB1 literal 0 HcmV?d00001 diff --git a/doc/doctrees/ZServerSSL-HOWTO.doctree b/doc/doctrees/ZServerSSL-HOWTO.doctree new file mode 100644 index 0000000000000000000000000000000000000000..040bc3f041276112f2f24a2b38fe87f5bca80dc8 GIT binary patch literal 43570 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 literal 0 HcmV?d00001 diff --git a/doc/doctrees/environment.pickle b/doc/doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..9a85a4ee7a6760a194b7c16eef72193e574a9c87 GIT binary patch literal 535122 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 peO^iDUdC7$6uL?3 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

    HZ3%o<2JX0pb531-VSdse*ofaHW1wl~T zNw*n7WhL9NbNNZeV+?%1%=S_Vj062C4#l`#wm&e7fc`Xt?nbCu2OK8y&ob~%x5@c+ z{doqQB*(;~Z^V)LEEV-L`2{Z%SW~+IxvV>hb_KOTlxuPf+?mde# zFhT#8L1_|3Kx<;uG7$dv41TB97`CFc#iy&0I{za>(~$ynVW;fChnxJL8H?R;e)9Ra zHvbv}Yu7qAb-?If9M^)^mTTQY^lr}rkHIbelNED^n+^eC7I}o-$Te_rlQ|K$y;V5i zh9L)b9fOVFd;;{4e{VH7;hshW}9az z11Ph|B(&ZZ28!4Q;NZ4094_d?F*P2;^Ac}n$U9XBRt)IUN4o+z`qn5keB|6(WT$RB zQs2(dw?n@-xV&u)v0L_(v4q_b0gff>7z6t^J~%4g$zb7nu`^h6pxH<$pDA#l`xsO& zH3M{b$p;u*=*njroKg=mSoDqw2YQG>2k)40;D;I9-T2@@UdAAIsyPvu@ya#Z_Ed#~ zo?>X<_6G;_00ZIuK6qt2G}KsyKE&`Vp@ieO#?h~wWUp?ASG2m~Srvj;5T4F3M8qZt zsRZ!~qtrQuorn=LY!0uC;xM2s+8iEb9Kwd>3m`W1aR$|`gD*6Bwf`mt-)3yN@?;Fc z+<6At4SgHp)JY2{btJgRz{AGvqR0h?iZgB($O=Qo9CizEje+BAix9{rL&n_}A<%7x z-if!a%cYxv*1f=h+p*&ul)#Dd78y)`qJ9qcvKmR4^NBjXx3aJuxce2(&J*7@`rH8C zLz{gqD^hH>g`;Sr^b@exGnm+IIbaJh3JAr$k>hBhaX9YH47Zcin_KKeu8Yb7zl8zE z3D|50UD#?J1OIIdznkzVa5$w9ZQQpp@F;=t$apbt9gTdBA@%jQGjt)N-fn#Z-)>C= zmM>(Y7yXDB>gBswdAFaPo|-x6%S098yBPupOM7$Jx$?dmZdEA(d>bdQ2MNu#&qpJ#Ad z6&6d&!^{2!2F~ITkOtMz2>GEX*s!up_>T=>&}jJ_jxqQp#=zZT>DBsE47R6RN73Wz z{mTr#OThWy*IV?jGVES~O=7j*7|0@)-F}O)*eMd*;Z^<_28?XstfGFO;nvW5)k^=6 zy_FdV1}qfG6UYe;k@b%mQf43&>SS&>0R3kSEexh zx;{8ZO_-z@qW#}6{63CXL12Ief5&+2#D&mYp;et9QutRGaCZodQR+W2u+GIEy=(8i zgK{x^Z}q>oPMw1bf87}|Bm@un8Y^kL?|dAj%_5&Ln17wYum`;aRA?Eu6Ls-d-DJu|tc%Qh{IH^FzG8B3_;{Y26ln;kfa(?7050XzG_>pTF zaxBumj<_2bl%{lH0KfyOzu?UbP4mg^E}hsE!&W!=;1CAU)-m8WF*t6?x`h4#XAnpD zhok>3j0f!}h*9=!3@7#z#H+457?uthif!}l47~@t&G19vm}9Wo5KMG>R0@!!jE80dHgO)bfW-RFUM zUCD;Ml)-jHHhUX)l;Py(n(U$pkDSLD@J{)iXSW4cd)cX?2YrH}X-_pjl-h%vW;n6l z1s!DG-bLeqo@P+7V1<2aqgx+}eg#A0x86Be&4F|6=p)c!-Z0DXBzU>q?y`O49>E`B zP!hb}0G;PM!_kj1G=*hE&js^5H}w?$B!iROQSk}!y32kwgVIrQa4%swU(Lbw^mD^y zFE9?Ysu~&I?9%6b*vPnKW6KP?TXiPRjy8|Qstin@j|_8<1_Oyb|1sKqivh7u4YhE|{Iqb=ajG zS_)zt+TiCHmtBK0%bbn3C`np84tSDMI5vo5sA@)oXck!mzP=9 zA)F*S?=sC6D)%|YlE$?OmHQLML)<_XF`L0FFqGua8J7{F92P!5&rsM%BZrPWx_yCx z_ZzWyfE|TQq2OO)Tt=hgEJJ>oA;$(pR|fqD236LAams);@l}S}g9CKjiX7pDGacj? zYWlA}_$6qO@!5s zSNOQN1tDdqd${a2F?OQ&Q6EU#lVl!+L$R)BeCTFY+AIN0yxFmjULC6Bjf~q-yW+iH zqYh>IBF0o~cTg?Lvvz?TA-j1o!-+4Y=|0@(wI7MiFs%4eny?W0jIS`FiyvVu#L_FV z&>wL`!*??Hc52A5ynt~a8n%nU#9A@TI^*iXVCWtO6#`4>fJGZ=vIz#?PXa4=T&qno zE@I71afxHNyBLRExNj)T@&}vX9)`^#wvD3;2wHF$i|qBH&Hoa{VBaMSHX`h)>r6%9 ziso@Yuoq)6h54?de2A}rx}ag zO}Jn#XP+=134VnaY@aq837%zOUFoHcQ)N!2D;lfL_MDiVJv*Z>@AB210z&1zib*i( z9<-{cvz&8Sg-MY!0cm(`>Y$w+_8Il9M^UnPbf8x^Uwv!r|OP^#aa{ zX4=GckCul;3Kp^|F;@HF?z~Hj+_0X7YsDI>>^$Rf??7vN3kc<@GhX)v^`f}y!ES!4 z`0QYIPce2cfwMCOJHMRo=^&;BWrNMcdQ(^rQ)L8WhJczx|yZSqpB+G-Z;dUdWHGsrB%j>Fl(xmoPQMBHiYU?QtD-2eQ#> z9FGf$EW(# zTyI6Oio4z0{Yvh3xHWIxvBt$Z4yzE+7G%B6jaC_sA%InEVxQ}_%Kgjz-l|RjSKH$( zBmT9f70jz+Oz`hbxeMjsB7O@jj&cERm-}PA@XKVn2CqN%=yNZ=>M9)hWOBLrZl?=V zCb>+xM$srg*KSntKy2~%>ebt}ZCkCnlgveVBQq@OXU;%uhe(sb3%fE$&OVe~y?UzA zTm-R8IQ6nCv+v$}?;W4qyZ1om^g`xr3BGmD%)maYg>2?XwVENiHr&kuK?tt71@u|S z0&&kz53MAnb~s>oqjO)z{w*IW)5feUfQ>J?_T}*$jlTxwW(f{*{2DPo;vFxm|VSj zwdifI($sB>V`4Ua*P+!UHcaj~7b*g;+9X^G&+b_i0LbFOkuU(~aPo!Trra*qVa@<=1tvaw$nlj84X&tSD_?F0 znORViI*7558NS5-woSpg^Z8a8K4EWX+TA9$y`Y$B)T@h`xuA0~2R z9!ngne6aJd^3AG<&=@9fc@d_Y&xqR?{a!BSo@nygaB}0R=}eA~16>>+7ZMC}abPB0 z9DWNu#4L*eVt&Crz(!odf zWX#Crc)2tWt$5kyAWKpsLu=tXqlGD*3%j@Chx0TBvC)=+e&6 z)rFZn1P~1Jq9e%w5!^To=F8*@g+>bxfXs9n8Hk8bj~!7A^ueeh{&$FyQ1SRsrWn8; zz#1Nkg!It)*YcfAW1jvJHzi_U-GvCb5ONTFGEKM&QlX0(n90Bx+QBX}fF4~7C|nF? zbjS8rhxWEDdg}#$b3TBgKi*UL&ycm;5uSnghx@phd{4 z)5@qyXO3()6mVlRbe$1P!T!)Cp7PLTJk>ts>7IcuPUt#A5)2Dnz)XfN_$@T6Xrm$n z@Q1Dx4b@~ip#K3m0=Qw@Zkh1Vj1w_hCaR-qBnS8Ej;TB`+j$z7UuC1lhA!{270tHT zF`9eWp{jiE@sNx9U{OLy4@g+i8!o{ELwZM)B>1XUj0Q4ZGc9X^QC7Q8U1fYIv!i|gw#*LETgf`Y6cbw-*cSZ~>vfmTOY!fp(yeQR zBWfQ)36bHLfv!)c%wHKY1L3QiuV!hqq3Y3UkUm#&b1&ie?M_kLcnpH85_DyPZ$OAG zwhxb^Ec6@&(m@CkIC@jeFII6lt}!ftM~`6* zJd{=a@jE>(>XX_DU{88F`^_~P z)llgUjx?dFvx`9<(tG%&1{+FB^c%FBJs}}F0EFdE7VbxtgylNSoe-sHi5_AY+nonC zW4j=?+>;sKryD1vMztoCO&ZtEw>*ZY{ zd3m==@45@yxT?rFvu!45BEgwL2Y;MyT)-d4g2J{Z$&6~ah`R7hCVXa8ush9=L$bpd z(T#LQ%s}KID1>i)K{o7QEKvk9-ARWGHC`wAe z&JAOf8p@%kfcBZrk|MoKHx4A(>|B%VXCzKJ++LJq;0v?(gX++>lT(qyD>3$O~VM86Hj~XK{wfag%H3laYwDZsw05NfdmWJ^v{o#uuG_^u8!JMmtbZ-U* z)@VF26O75GU_z;&vegyR(`rRbIWe(|l7?#9hQL>H*nz+LjG!hX!YCO=0ml$BM}{{%^1gsc9O76xQZ|_<+kVv{pd0K4XwGxRyX11WIrMffQWP5wH*% zIUKg9zoEkzh5ym~bDi>iJI;%F=7;muuAFGz_D~(Z4uWq4uq+(=;Lrzu*C~QbW?!PEq% z_|!X)48?~D!D9Pj8Md>IW*$5>J8Dz~QW{3Z5uF0#PpLfqc>K`#0g;Q~3p99k6xJe$ z#MZE=?1hZ8XgK->suPxRpn)JaNN#o%GdoTk+Hva8j+yL^`OJ=2!JIv^#{b;zE;&=1 zqri6{6K+=Xur@)aI?SsoTdo&jx=PqFb0@21WhkGznzNYjI1HxL`p6(!?C1u9u|?TN z#tia5%{-hAQDmVlBiapRyWp$#SX@g1m4>Y3l#D;ILIUOP%2rY%Vz0TGl=-%@4eYpu zlv`7o-3O{n9sogX41dYWa1cqyiT>Naa@*Bc;eWVl zdjq|A2)44r=iga1VbJd_gC4U#ee3k?Z|?W5XEe0h)vt75S$X=7=}`{_r9_fq*Yq9_ z1t^irNs8?BUZ7ZOmeTKCM@xwP>6_@K5MhRTM=hlg;o$TkfD1)J3b|Y%OSo_PWk9lp zN(f1yNrfUDoj&Fgm|8qA{SXjrv^c=bp5#A0eUiiF1iK_SJ^d;mSYyEZmCI83RARTx)h402()OG>GNU9;;k(C3Go8wp}?nc4}p}mG5r)ER?-U? z=*p+<=`K87Pfx>X5c%%n^dh`lNAJ{}nSAxk^lRYNwfIVwTc;;mt!Bn`{^sc(pl-Bj zc&Xn${TvW&vWc|7Z=e3J@cMfDwWa90rr+&Si1DnH{yoz_3>51u9#W0}La#Pcjba<) zD!gy{Lnxj3-mJ6_Pk)rZHvREq)1QLZ>kYK7(N9nR3cM38LnZ4(ON#w#)4v52hHNT! z$oIc9{aJXwRdYA<4N3Ed(_gV^%#bT-{&D(iK(i|3BTe&OeB8z8Vz=qa%r&qPMKl8C zipC?+F#CeaYO7&eB5JcddJw4ye`~8iZzIe|@4N=2H{2uWq0bXV8J7Qqjg8(#`#8St z@?A9@s8+R8B%2Gjg+ANc5gOUwN!)y4vBI$BVhU|>g$e1W}M#CDi-F!SNr53?tO`=IO{G+A85 ztu^50#VqdYgsn?xjJDbxGXsTH1ECa7$2Vb)y5521$8sC@%N(vZ#xWRbw+Eox-S#zf*kGyjBL~c~Ca6#qkDd8|Ey*%I2)526oc(ns;VgxRedo>!`q)zu$UOIRz zOf?{eKyu~~Sp#1T9$DB5U6cn0i-C(M7F-S?G(kj{W{HUycqzQz8198$PRS+BVvxU~ zqN-Tw3>cMQ7fZN37bZrCIk7c%nE*+?wTJ`IJo?#Wwq45a!xUaiRm-23(Mk?<%r@zh zPWnsO_CnK#LSish0-pl*nLO;7z#u6~#aD7`hA8V$hJK2TkQk&hV^j!^VC6iE9I`iv`1lTLzJdfq`(Az#UrGqkZz#Wv%(yBmI!Ua z5kt4jqQAlS_(Pc>|5cOp!89Jvflbn|37>09wcXW-G^~Z zisWM7yL{;B9$N>=bn4+x#ym9uB-rG)6h59S+IhQ^XFavmU6swr-0QBdth9T zg6`td(r`^#ypb0d#m|~n)!ql!_W=x-6s^>Fn$}{it`3r_dE6dtbl1mQ=P$N#gB>Bz zPoK`$hDZv+XK*{j*_%9>M0G6KMAsJ`d1()C+H-*uhGbHWgPZQJlg=n)garY2Znjje zF$YTJHQuL2$Dz;L=nY|u9U9J(15Bw&^{8a~W9OE(`o@C98Vc1xY_4$j{wjj2R1WeD z`*t6rqd<}%J7w!&ww!#|kFV8PLSmU{eXY+a2myQ3;e) zMnh=8EojmiT90@LOzJZT%m@x8sX;dE^rF`B6fSwsV${gKB54xQ#k$JIqj~w2lE*?Y&39_iX9sG#i1#n)a|oeQ?^0hZ+w?X>VT+^ zvl|>kXzmRI%r7DSFi#3QJ(xu%v=Zn>+xMB)yv*;~rRBvF>u~kiXvibcFv`@W%&DVX z1t$;i179~rn{IJBH6UL7;!A3-@@xUUl%w>Ee@p3#ajwXBNBm=`^N0n^eo7yX8=jr%xx8#P)Z|2OOyvILIEfV^c}@>NP53Yd6xF6;=4ti?2i`E1C&+fFBUJO z%(DS;Qii7^YvgS485HAM#tD}uW`uzvB!Q1|IjcR{xcYx;+ZA3^q$Q8xLjW&UXK$_)7UcZ;7a zwX00Ws{T~*Gsu1_sw$IcxnC>(G;%)_<@!Z#CH{=ukHm11rY!T%6@MPpKN3}sNX*Lo zO7S0~%&}0$5Vpf~xgbdLL?Iq`r)ZGm9P%Wi76Qqw8J^@-a4M;B|2kYrj{A2=mW&K~ zCA~~3k~onlrNk8EDCH(B0?F4EDqr2&lplUo^4BR}SlfH&%jCEc>86Az-#1`73N1iP{yrSZ`1@fo(~sA4JrXteh<4WiNmLWdB@(X!Hr_@UNF%b?dIR_0((!6zX~a(-x$}2J(Y)K&tBdU{S6YJX<*M zXB=4}+QcBGM}NtQFfDs8=QffA#nX`mBjm+9IR`I5Jm0tgca$zqcJO5993qRgIZFHq z6GzAY{$TP(PX#;M;K#Z%BH(TC=0*-w`dV@cOl~=m0MdD9;IBee!YE4Xs@5_T5H7LUs$7#0+XFKgatFUyWKjORspuC}v znzj1wBXt|wzq<|mHx^S;V1}Hv{9^M%Cqc|NPMol;?$F{j7&|2kj5 zR91w8DmLZVBU^_EeIg8A5s*t57Q2Ho5g{Iija%YP^oE>>0VW7+3qqdedn!?6ckmChmsZ|-E z@<|x_GN{em?0A3kOw^>!x~*yHFj~}t{}M5%$RUNI?mP>UNvVoD(y~^iToU=1Y$E*2 z_92=BZZEQm=v+X;2xB?QP4c2l<7nLJAPgbAnV`*uHf9KSG0E6$_jX_o|#N ztKHLOeV67+Sn$a0t0R`L-UF{dj4==gY!hxrCIT@zq}Z&$TtcePH_>m}A*~56pdu4l z4Q4rjm+SBI1jPef1B>;Q2PLfP!^0wVOTf5k&%zQqD*>|)-Cuc*F|-@eHGu~GhT?D& z>no=(wT0=MDs_Q?7`LShaP!TWme9`{^4xK8wAbzQHhUxzi`8{-pT2GOsqF_kZt;B! zL;}<>NfDL}MI`N{^t~w3(+ln4)+nmuS?LSd<|=!fEGAvJSV(r}ZgxQ~_g@iaIEPKo zTEno_6g53Dqd;ra+U@Qd*I9*?-H`9{G;r?N=cYFr!)R^Ilc2uRv&|d2}$00Og!zWQd7SlxCC;?AnWgbTfEJ|6Nt^;YP zTK4+={p~@2p>cDYp~AS{aZ()YqOlE3;vRJaJ!k_^5zG}Gr|<~BhoRkgr#)=Iuk^NT z2DnB33%-npf`jb$V=Qesj5u%~C3$zh2Er}2z> z*_q8uFGsR;B=Z4NJVmD1Nr&OVRBk6{QV&S&vDPqLs%)uw%oygMZ@hw7@^{Ms1-h)S-tt%*PM7s|XVdE`s_WCt&Rhier3#YZ~DsC^Fk{nq=iv$MR>JBz3y&!Iq zpKQjvQmBMW1J0-=&#@V(a#~Iebs&Q~lF)AkRtyPKm7t@BvPbeh7g2I^+y_f!WIW;E zxRF69A2|-;B2X{O5w8;}-<<~4X$-K^+XH`;dvY*mZ4n0OVB-26xA%wJL)^Nw``F-l3{Vyxl` z9GfNXPcI|4KPy{p|2B6xY`d_-=#4y-&o{PUCK>iRO!jvB4m9An&87T`4Ox2O<~RbA zm04P7ypEP|&AX0kov10A(3r3##L0+e*vCHKxB_=QrPuieHhg?X$i~k%Rz+gMs=E)) zL6_s}_fJL5@yeS=8Vr!i9h}HWP>46i-F~3~(JSzp=c9TJ2~B#D z!5;ZrTXHrTya*en9(iQ%q1_3`4XbbzlOqz0k-Nj4`#c^pX7y;$xecWjk5f>;k#_yz z$F2nN5*<)z^M)T%D7r2TnG-K&rC;9W`boXJ4vSnn0-RsWtp$u1DQu#>pTf+(bQmsxLfWuMXa8YJ~*cKl}6nx`HK(C}k1gS-m>ucq~ESMv+Du9>^ ztH3X*PncRH~jQR$_QsKI1*)|Ri_Y+VtLG%Tv?#md@?EtjUO#9?bW;{qPNW%d2&ybKrFzss&^A)7 z>SD6y4Sr130fE%GAC<^W+XnlI*^XZtN-fb|cUba?De^EhTP16cglN4*EAg}=EX%$y3J6mAZ;_cPD16Ao>j*5gkr<-vNx7Kxl`E+wZxmf$43>elkrp(Gx z>aIj|t9r?e`?q143LghqX_!^E8rrKeG$V>ge{0=dKJtT|pISXP~XASpXEQNGbf_B2fhZ0**5!kNXtI_6EQY&fO3J5DP5Q8vvkv zT!caFgXV^%388jp>g*sN#2pDMGMoWJ!H_H>F*j_b5;nYmqt^R(thFH75?z^2y@6P=yVN+-b$C|byRgta8gYP5?T zBtPksl~^pZU+lR$q7AU*VR6qT%i+|L-!6X0B@2C7@(&k3hUBN%gTL9uIni=|y!a{P zO8-9B)HS8H|6a_{SV6Pse50{^#OfA?uiA#q;^Ei+|(OqnT^IXQufrGd?Gp z>gES#nvXN*G3zE;7R@JTnol$DeathU{s&F^pwlzxD4HLdX?{D4KJ8ADC5W4IGtDIy zcq%Fo_jP)vd4~B<`1~0Db2H7)GWUZnSD|VCQA_{uN_40wcm3*2^9n0}s8lHK{_0Hg zi!Ad@QYHprZKnA;OMEOTQJK%?_s%qLvD`oa^fSdgqF7L9vF zPKC(KqjAnlgMN+rJe=r_>D@iIj+-moxDEEspTM=``e1*5u$x2b(K zA9O8DDV{}CXtz25o>dx`H(}kV_A$EyT;7df91S}sxBwvd3$7FKg_lq#7g!Rut~?H~ zpcg>dh<(a+A-tk#T2TV))`@tMmO9F{MSyXWh)a9)zL~ebo*jZ!?@x=JADJ9|=7A=rFBDgO6Y__X2AxT@# zdede@T0htL63niLjh)^u5YOvhNw%>o*fM90#&We?4qeKNNwR{QkXU8h$;hG+%RT5E z1UL{=-H4%zNgBVQM;|}lO-Mq#K&8Q!o-RRIuzH5auLW*UOD?ES^qQ97cedL!%Yt#P zIvMk=Or~SwZrp00czgN8_nka(_KlSI70z=J@w>ix*407hQ0Oq|OJhj5s7OYof$n&< z%XhEz@aBFj@Jo1N5a&W(#?$!Wm8%k4OVJ3`3Dam{%AULzHJ>%aM!yg};NYB@aH@Y@ zd*p=#Y+QD_ce*?0E!G;2k%A!vZ)mS~K&4yTy*F>~?DhwHZw*KL<2!fn-G6)em6Z#t z7hk<}`Fn~h&8ye0fAPlJ%`d(7`j@}=`%W${ojU#EOD~@}ds1CktUd4!9NB?POuTfU z$8dKie(Q}8iEO85%bz5AkK9G5Eu|Q;1g#9On_JfAEgn;K(HZfD-j5@Kn;_rlbar;( zO(-blq!Dwoejhq=r^P44&-xfsv@I3d5Tf^!5ZNAKx>U8~Sq8-wnavuJ-7u*xDRD*J zAd~$t*&i=l!v6Tfj~;4&ben6|6ZFER?5^mZbUihFWXbF%2w97_@U{~sMdbNh=O9{n zmX|Rer`t81cGkHuM!Tn4gI>6#7o4kd8wyf44x^5qppT7hb@Q}>WW}y##mO^gsY-@% z0k7%wx+gB-j0~d^(W&D073vr~X9s1<{-86km;xd(kXCUIf}Vr(r~Qbp1CnOXXQyqTh)v(uA72 zFh1s0r^78*9R`9IulHLPaYwetNRQ5X4}%WYHoNAMiW#&Ejn7?yqYsY=$^w=;$dk_q;`Z1MjkBnl7C^X#n5!E)-3|?24-Av z6QK}($mQi|vt%?L%E~iAZiLK@u;ckkB5-o}4?{DKUS#>`D@AVQ1+W}8CPI`jm4^XI zm$I80nT9GzwD;w6>6|3yV)Dl8_>n`HUW--9@nL{W@m2x`tjNO?uqaRY#FLAKQhQmx zfUWu+n`m7^?sZ{rL!x(K0N$N`IPbRH;I4?9rY&64Kwe*mNO~TblGk!6hI&t@;q>cI zy-p}lm)Z-LblccwCvXpu>m6Z{G&08IO8b1tYcyBsUspd$!=@NDFI<|#cWK8zrebrX zW$bvv@NsTT6vxXzM@GU19v?apBWS0{6@xMOrNXwkSB;h&bwKkRXbQZ=SuRVp4<2Wj zbwBggzl{O|)P+IqV2l}b;B0_oh}gq7jv!p{QlH5JLWx03g60m~q5 zGGv*%036e4Absq4v7MkCFfA1|K3N#M~7mr9D^;#-UFLJ}z;ZG+pEvJ3D+* z-t>4v%6mz|@{Y@M9Gd4hOUqj-&Y~Yc72lS9ruZxppG0EJ?ybh>ie-b$n69O-6c>@s zULwwCd6$a98jM+tWj2fJ$owNXsp#_>&&uy(VQE{rwc>S@do-d^%lN+H4YnR-kghHB zE5$l8j|FP8^ezKH$ze-+mV;Gw#FAVYlcaJEJO+IAbbOK=rd;dA1Cx|=NZM3oFj_Yr z22;k7DijFB(Jw>+y0Es4v)?~`dD^p|NEdkG#o1XNJLYsnlMjSz%XT8<>RB1=-5>J( zSj1O7-Z;8aLqZJiNoeEON$5PMhwanI1?V_>ei@xXG7(s%Oo$<%15JqqdzktteTT9XHpO z!+BGA&63HTKDHfbem znk|jt3G-k)OuExOcTVSy6p+Q@>TB2Wl)~Dwo$I|^yh}GjoOq!rDtbG^0V4BZ*P>a$ zCqnd+U7k|V!a`F^Uy#QU=4KgpJ(96^Hx|ZwaNfgHS6VKJ-};;ax$*|?|NCv2zyyFd zMhHGl;AA<=jy{@OJh^l_sy}MGwQf5OM>+(GP!sj>e8pCOPJ0Qp#Ir^76@69$&m*8_ zD97_HoM2L05n&{FzO3=W3z#+WW5L&GxYdJFTtzzMV<1ppG#C^B3&~ecGzuWENTp!E zf=uY_E=-2SU>`!M;K-BM`w~=+^xni(0QDh=dxeKf?t3e5m;()r1%Lpd!GoF+w!*3= zWqngi1E6yda~P5zM@xiS8o@b7hmDrWIB+v6#7-rKC%hPvNXo|WV_nCH5&m(yAGPzx zdzJcyeo)3YF3G{j=LHaNF}`jD-*%j5sE~ygKC&_LF9pcNIzFSt z+(nPaRormxL^wQ8o(&WAD8OOp01aK{2k#{$qiPK@c zCy}H)HAa#Y5~a;KRo#GG@3ecVPWgM|TI{${f3L7&-o_6E(363YTz}I_QC+K;P zT~J%o`|8j-om8PEQ6OWG7VIXK<5ZWb=y@qc{#oxE(TJ> zG}m5{OH*9HW7FR3-2)y(kl!U)z9UV7YTgV#)}v;7&(F630V9c4?m*Riqhn)(&MHu8D6s zX1}yeW8&KCS{}{?MqIAPbBzg=C6)|J21ErZ$jD%^F}Dv3kmIy8F^PV292~%7#O5`6 zavK9THUt-_==RtL_B9@HRQyqEMm^1ln$PWzqSJNyxG-AV6!9mJQG|Zq#GzHf@wfzo zIn?8n?P=dHADaN^at!y?nu7Q8qKPqo2&6l);PCk4wW8n(yu`LGM>SAKi#hB0*>-o- zT3kAVsJornc|S&@4fqB)t+ifaV`=Se5Al3QS$WM0eg||{+2VENRM!=yd}Rj6{)kHo zrd-`*MTaE+xN460m0|1HDQe2y7bM)#eS|l{O%Zn?Z8-{XN_98&;YK1-I@B&VAU0iVu9*WVh=_V1Dl(NmcELD!_Q7OS zC7}bCF+i;00r{1jlF`Ew(F2gsA@~Q_y3#vs{kXXXk(E=EV=p$@t^Oc(HRL9k;Sg+O z;wRj*#3bjcR8KX8wsZp10n7{dK|#ePY;^gtu|WAi(jRb_+cuoYgHw%9*{`(eDr9WW zpyQuN=O#U={vp}u;$gHrm7kZZa z!sCZvy0Y(0Xlf$U%yDO>MKja{N)JKh4o55&(F^xCML&U$~Y^pj9ApB23zrJdhEcyyu1-^W92qOBTd`U zI|PMJT+?(kr(04U<=%C$P2!rmPQOJcNa1g31w8vmSN?+opd;QE{G*DLhQ^WOF?f} z!MfZWerDog+rs%!c?D-p3hB&?x&7j{WeTd^k$5xh*F(8gTo>K_T z5j42%m2Um=g0#->0hkoEIZ!6@alaJ`RvbJ;GGZ$zMtM&Eyg)&=m4|v z>$8lm2V(~!|8TEWG0E6~*Pqe#?j~~W4#IBSL1>622^kbT#`TS>#><(jj9I$6%{D&U zcySR%;?R^sPJtepm64)?j`ik{bq)?-7QoddIYO7wn(v#ZERu{+CD88}pSo);w3Wb>r=ofy zk&~NiB#>81EV%yicfx?LBt%R9Hqp3@@g;HnFrg%_XM9Q6=VnVjz*MB>pSTQmHzR^@ zhg<=J*=NDr-OZf6@Tct(t}Q-sYU1;*@&4Ib6z!nVEv=q%Y%g1P*Nw)jD5 zX*WU#Y$!rd)FE)W2l|_ul-?2kB?5^W#DUB3;s$p+8^S`U=FltUcsF^M_*dxsU7#x0 z8Dx<k2o|UaJHI=b%LM)P{P#sM|?`AdoBUE12>?%%1+O@jdj@!XFXIs`!(J5D|iE}2)!{6VC1CDB7} zbwH(4Mv?bDfKXMt-M#z7E#|6$ypNKyk8U>&#M_82%134b`c6pyUtdxNtHqFmT1n3U z#!sg?1UR0IR>Z4S!>3}KjKilsT|5Kd$H$Obb}wCGs2TX3N>1!w`q|?1Ap`otR?GY) zmy65Dcv5S4{|U=1iti1X*iJMagJs?l56mZ6Q+65zP}&_?-bQi9bw{-;gbmBMSNt*8 zqH2rdT0d0$1TvqM7K4Q-7rE8`NeNLZ19z%t%lUbUEBchLiXNkSzf$~7G#qk`5m?>d zEdCyHKjiCLZdCvGBmn3Kr3Cc!R_`Ad{|o9JW2)X1S^7UM{tu)-?n=vrm1X^3#s7mW z!FF`HWSRe>_?NDp*Z*7A|JR&hG|2a&P4lMxsHPAX!clpDpoI}E6k$P8`e~O}YOVR~ zO!H$b@Bu4e(IwwE)BFx5S6p$?B(_q?aMGSggRR^EZP z`Pxi#gV`T+2VH}HYo>XZ>5sYeFb~bQXPQ6Gyl34MMPjH`|B0FAp9$5IiEjSFO!KcW z@2ObKiJJelndWaHU&Ct(s>M53W-`K|B+44|v@J;`x|Fm)bDkn4T}U8V0g{}j{ZdPQ zP?BClw~|*`oRS*RvHUJmsw5_4Eh$y1^{vHWGy_pdc8&-oqeQuqmQbFy?x^5vZ)z>~ zTc=IZQreTGD$PZ;Q~YI!LCWT7OtKQMbEd?hEJ-&>sIJu&xNC2GZd!M3bxooVi z)s+jEK8=5%xLv+}8B*yNhTXTuJ@`nT^PZ6>7tSu6!L=t%Il9AR$0EP!2XNpH&fAF} zIAdm>z&|fFUK{q_>^AU%J=od^Z<^yGXL%Q4=7t+>yxY1A*AMX?r+r+LB)Ip0UwTwQ4u&|;mp z;6d&#dv)aiSMF{{J-MwQRK(9WR>tr^Z{Uuqzt6XOhvHKNSJ(Z~v8$Ia;7+5nx45`8 zTvS;hP4b4|ba#leEJj6|lrOz>rqZ?~)s`-|jnYfOBt3!TrIWYIa7$9Y?UzngAd#fn z(q%|cx(<@FOBF~YDckna(&=((O{yzhh8v}klrR0_OO>`IDO>u~88#%Bk8UnCDO>u* zrNwe-P0E$tUtBy@Ds4%%rBi%M={&yo7f+QTv7~(4C|zz_lJccrI#t5p{-Pw+m9C8P zB@Vo{bQuzqt{dgqDh4Gf-!`(!ZA(&8T4K|*$2%Ha6{~-10WU{3ZeCfFSFCaC4t6ng zi+z9TR0SEDlr(Cz!_sABXi`n-vt>jtonlhH^qDFol2li^0?C=$X*qqe0*NMN+eTKo zZB5FSe(~kS@+dW_u5`I=ltxlgTBb+LEAWEmooE4n`E2W@B}TQ{?P^X^jnm}wB2p>U z%21=Pbt*86Qms=dh`ujOX$^#$lZTLbc?dP9zE&PW)~bc@#h2QMD}#BTR~c87Q`6VWnQ>_?$;s5($GFZe=Emi7>T6}jWwo;7vb@Z=d`_k> zV1DW3nY$I5mvL!MrWRUMYV%v2Qg3I;=hWBAkE@0beT(^V)zG0r|MF7ZxFjb7A+T}k z3p83=;!BQ1Ya8e~huca!S-K0u}xkObQ@%bv6kc^ypr78(v zH3V0xk^ojiZE+RjeF3mM%hM{JLqyp|%&0 zrek(m#U~t8C5*+Y)Dny=DfSY^VpS%O#ql^lmKxUP<^_$$H0HTbNpN6ur7Fo-CeoO1 zG#Sf88k1>QGQJkZl4oZQu!yPoDmA>!Rl)EbN7E`kp>`@Gb{2XO{#IKBjXGZDd&#jd zX5MY@weF6#TD^_kR=3mJXx-i48AZERO@5{CY&lKM7 zJNJuZAd`p@1rnIJ!{a7=bFi~BxJwIcK8MnwmI_AB?M`Pf+>q3PQz6d78wDz?HYz^% z#WDPBs5@g2D+C-SNW_v8KXAc(E42bux#ji@8-uLxBK@SyNvrdk9ymK zyLhkynnNip(DJ1S3ot;C5o#Q*!YrSzHfR==*1LFs0=D-wE=Bx0DC~An1mP3V9U^)3 z;eSXN*d_|0(cWkq-dZ|1yed)|xP%d+p*qfk91Ry}Zx4t5h=J(uI5Xl3l6l%Y)2y!4 zgoC`c{w8cyG)WVKrBg zBm+JGQ)Y}D>f^2nAY?$Z3#;itb4FP-{&>|pvT#wO53%=D+jTyf6wIy`7zHv89?I&d zAVEnG^K&H*$tgT2jT~S_qu89D0AQ4(0c62+s+7)tVvrvevjL?s<}gjsbmKZ{GCpyw zfHHmr&o}hF9=t!(*t?I%8o);pv)bp|Y-%kxhwu%Jx)jGT*cwQ#bA!y0+Cw;YZ{aGZ z@BDtnz7FWdmD2*k>%yhFPgf;%sh%6okFb(S6xdVzIP`*wptk9P9g~MIlbI`B;r_Z+ z;&#%H`nlOUMiG-gkb<{3%;g>Patgl-Yo_yLAX@+cyIDVHQbPoe1xk{Tx+Hcf10+CDl6n%=LHK## z5@^pi5%mp2ON+%QF3;=Z%}uD6EaVsB)HDk8Z~;pd!Tcz36zq#8C9rCL1)$al|}(?!bNGgEE8}wiXj$9IYbtBY$Vq> zOR?K(R4L9RP6=_uVV&HEhFSnlXM2zfdcBI=6B=;xCB?_f1Zbc-4PB zIEAQ-jKLlutH@jXBTmw!_@_8;z(itaQ$tLE70VVIZLale$ad;9H zm5pp8d$+brvOj)e&RfHB03WcF<2q#?WB4(7g$po;9OVuVgqyIaonOwwu>!?GiiHOz zs&K%!z`E1mtvzb(b$1P8x(}41cpgfQi>K3_txe*XqgXC}>i+HG5)vIYF5{s{$N@N5 z-GwHX+c3XFRBgK+dK#Z$^EfkihKn3PIwb8{Q=QuI#mHqUF^RQSrzu76pj*GJ%-o;=86uY)?; zlz9*6ih(-sv^XF3-{=nl!6j3VJ+s%ZKZ%m+qtjt;pNi`8} zfTY2A@de!R#B*WwhI=3&b6oYSDQ+xQafE4wBJ03_fDoqr&@o3PT zQ6Tigf$?Ls=IRE07%RHH;^>g3XbR7aSmrwC7~mQoH2yj6!yL z6tj755xKZf0+&6I0PmC2vR44a=QmUe-m?EOrWK{)t76~ot z%84NP_&tu;yj(HBi(V8yr+DKO>o^kseKZw~^5&+v1r-?Xv*+|rI366NSo15n8Z^B$ z(O2-GD<%JU%(5_@sFu#H0s`HZz$Fn6F`2w_j~ggSclp^$BCs7=t2CWPY24o#FjQrv zz4dg(FPMa~GReGiz&}b)95_TM&&ESMODl}`KUe@S#^9ByrA)}vMIvu14y#h9Z3ces z!LL&XZyb6g24H=Osp-NiTNCYSi8k{5emW)q;3E{FJID1!XLw+wuaqhLe&7K%dkHfa z$7!3!sxq+5(rqtS-cj0-qmyfN5$pI*w1^{#PnNOMMLFt~4O$Mf=Ne?uiN4CF#g=o_ zlrHEhZ`MbfT-*7TL3wWS>No_~G#ok3Sy>Ufw%DbJPr{{+gl%3gy7y)LWt_)sfQ4KX zya;Enm299d3cuUoxe0U15mvb<|-O-b1ZBu|^6Kr;F~u1p^?BPpO0ofe585 z$2T0-M9E@LUwGEXX_(`Q+6NR3B})jm^M&}N%DU3{!`@4EIE3BIzIM~v)!_MaIL_-1 z=w_2FP7aDVFWafli$1|>Br~Ba7&V?((;Qv0I31_EcRH+qFzFN!0AarGXvhg{vd%{; z!{bhfkLzXOba}iGpAK9-*@#?C<=6mGC2_$c4Day6$blIRDR)N7&8NP*KsV)EfW$nL zZ{ajKPsrYQLofFYuZqxI)Aks>(Sn7F_)zg-1U+~((z;kwiJvHb3K_>FBMuhwCyTH7 z^f*??&lUfkrJFUBwe#;6e*x+5M?087OZ(O0KS3Hhb;e4T@t2EVN5VqZxz3d+-H)CasKZVzl;2*k?(Ho)ttf_|GULMK=zYt+>`;_3N7;=75^NW z0t^HJk65X?}n)C49qHMC&&nnQ1=F>_^aos*NoJF*v@R85~bZ z!D%JFbEf%mmUs*$yaLJcJ~7k$B=i0Vf(yL)gNU|K{D>w146+ihU$gQjEP%%omQC8h z!nfR|ndUjR7UyD#TJC3Ony)Yy^UJ0!Sjg;5^CDA|kPQ;|3%~>~_GtGTw=i+|cooW7X$V)N&qchE)X5L5quBOe}#%8VmshQ?4u~a77g8==@ zGtFOP{s$e~wR*ok)BFvoXPs)`yMVgCG1L4nnV*jqAx;17nda}Z$TQUiYn}YPnda}I zgv1?@8I>p#G08|mi4Y_$NA8lrRqa=)r1$t+2dW3^J^lsZFXW7 zwx>!td9vBS^{iONR%w|j7P?A^hQLjM?#B*!f5$j)GE3+K0Ea`^LO ztHdO^v9|m$F-hFrMX=7|y+(iVR{Pj7Kmg^l!9gMJ3P8ej#w>((z8TTkfo_FCQ8XS& zuu(C=h&O)6j!`7+}`cZ=*8Ba%u8!~x7}&MNOE!V z40*?pX8bf(@DX9RZbqyKBH-|;oCJv7rPl67tFwO(n_9OE$^+#@3E_sQbXmvAGb&+E z{@8$hSI#E9u#%3LySssgLCOpr2W356jZoVRvqD|BDsDNYS}P8e?)CV9l`FBhf&+YGo@oj+TI_^jP48uw;SU0?LE+bv|=3{4b z*3L$e=b?{8tDYfTYA%<3#jwhStpKEGohL~F#?nd$bJGQTewJKmwswx>lzO=sdtNX@?UcuOaZm5_ez~W#CEZpa_!>SHws-NCN@` zxPTgfmG=8mVl5}Y8nboKyEESyAmlrc2ki@P+@Y8|e-b2des*``#oQC$mdqJmBy?vsZxsQgY#5Fi zvZ7fzqkg8emhzzTZY|RQHl$^u%^bbO$P3Ge6n(owPIwoRg9^>F7~7~5iTQ*QK_^FBOVlk)PE1Q)H$r_bX(cU!8PM3&oajzHgyr)0qS75H9ogzJyg+VRAI_~7m z>5Ln9LyCaSZlp4zuou?iJ!PM9Pd9W!V?z=VAqHHRx>8G2fWYz-H)CAE!5u(~=0drZ zOku1$kOUnl7=VmOe@TY4*R5YmyFZgb4BL@39yeti!`4~^qVx08G zmsl`3NQ+IMp4zdm;0XXK?x=c4haMu2eEZ@~`Mce=Y)xYHI_NXD6>7#!LVl@ve-TaL zsMm$E)ZVm)XWS0%7;(=tYHy+?@p^EecneDpQ$$^Q1c{Zz;!vl0;)(iUh=>kDzG03L zG^B?F5(qRX30a7!j7T)2_5%J7;t?yNLDWs9cxe!YgK&P*cUBe4)2<=WEP8sZ>)0qB zf5Kh>#QSkL`5qM4^g~}-O$aDlZs24?r`Tm1rbNS7^{nraF?zREQWhe-;!EV zgD5~|+lWkyx-}~nk!m1WM;Hh6rD2;g)o_WT5$toA1~wojT`a+mL&^wuw*1ZY?Tm^< zhMyNRVJz=I4F3AUAz(EneCL}{JxG#&K%#nhCyd0*{GD^vCqsnYku4#7n|cLt6+TeZ z3-8V0bt^avK2+!&vMOgi5*sSdVmz}na*($uYh2(_Cfb-|-;Zxb&M`^C?F)ZE))>VE zy(!3FJ?J*+lxP;Dpu1a+n?qp&7be~aJ+|fN;^3z$5YRP&{;shqNTI2@bI=M|NZCVG z`2)%8u%UBAF7gA_E6?ii1QOmtxMd$*i5_u$2Cqz;#3K$o_G5z5)z4ogS3%;?`KSm{ zyc40YzVekM7}i(5k_(6BB`ty!eZbvRhL_=dGaOc4>cl$4s^Z>~xGx5IUXEo>WOOcB zZnukR+M(V=PA+iqI>AK=w4`481jR#!F6)my;fh2)Ermw04k8Nm1Q84Ih}suP))5eL zoCw3M!3U~`G6#%s)O%aaA8Jn=2dE;rFS8LUBlz9cqhKXJiw2S7y&eJ^oJT&-Lt;EO z9!;JB&p)KoVB!{|^hP)rS)1e&+ueISgYLG?jFDs!*D8TphR8vj_`n{i6Fd**f)EFl zbFB2D5FO9t_%3FlbgnctkTE=_q>h!bk90I+75T|=O!EXk*Z9Ww>T|eInMTRaVXju{ z9?n)hpF8Q{Rz1=Xn~018|HrIErpE|{6EVlSk*kukYLD2FVe}z=qYq0PCBMK_KVy@P zvE>Ej$RF?z5zR~@1G!mD1SN8hDG9;6Xi{(bcbgs>P$I#uUs$$y1be0uPDm*;`6hWJ z%(#X;qRFlL*h>REosh#+Bz~3jy(zDR3K$QPBPnxR_7cjIfY$lC0t;ndbWKgQkg8k@^x^+fkqX3Om)*+~tVozRX+{ zo|K;V$@5r_*n5g z(mrAiEf>TCqvYpW%oi`A%!kWm#PH9WIa7QFMLv`k(feU5alW{K63?b3h9zp~bK@+Al^(d2&Vc3uPGJF8&>4KH)QCD1V~(6Uckq@)CG{y7(Dn zJ!V-kL|-d@4mrSJ{ze#nAn=;y**q zBbtLP%i8}N#ea_Er!_e;nzHQwLVe05TQKjehAjVgir+)^CnR4k>SzFAdH+rE50Up& z$V*W2-xdEOa-R&jF;@Pk;-C4dcI_TD{LhR39l6g)Rm)A9{y&R*o9D zZmeC0`$dJi`Tm*aw=!FC$b%woxGeA6&8u8d@6;2P`CT*3Gpwlnx=i&G7C+~6GtDou zz@q}V>fo&Inz?@aEOF13THTrE4r}Sm@r-SC`ZLWDGZewmiPrMRGtIY||2}qSl=F+4 zRQ5do!I|byvS`k={HJG{f0lXA`rQeP%6OLb^h@R&UiImf5x_GL+2kR~z&1au^&wHM4-0AI}gXBFrf4VWci+^BaAiAMeYjaGim{yDNX$M1ui(DTK zcHq0&(%;9#Z`(DScR#=S>gB7e=7D}4x6?a~we4YhcW~#}qESk z0uvZ|IIb#sO#MX7lbn2D_6)~n%u!_R9wh{QbIDJzx8W_>_lN%LeOgcFO`A%Z(0~|w z%0^7v2BYnZKkqd=4R4pF@PzxMhPtCJR8AB~d)pB4$n2Y$vk>3}d?%hi^6xdx3+k z?QP(}-kvy&E;tT0JT0mJuj%x+{bQ3b+a7lD#t`0u6bmqF2esGO98uL`=imqoJ4{() z^PrIaiMPAM0h7#Acp;{!pnSJccwj}V5{&}8Fy4-wjLOnDZorVO4O8u8Af#IyNyqS* z8BQ42L?9zr%3yZ(hdZqfjP3QN#F4h000OSe0TxRk8*zicymY$ix89t0I99wswPpUtBskJ7Lb^iuo~!qsa^L8`mGi$TBC-4S`hz05|zf-q15y4}4$ibpr@=>|9MwP;K> z8u9v?_~fUv&V?P;9Aly^F1BbmFK%OiJ`_fHj&xDqrh*!Q5CBHJI(6XV9@go4#3Iz4_P+B1ZZ1G=qv2YGTVFd zK3@D#)WP#Dvs#h3WR@xIF7O`@HsPwY)h-rhHHGD@ugOE z;Io!v)w*z&rJU!8=!b)Aln3@hk<7ipJhE`ByHl-E1viV5wPzuMseF z#jY*02n9whV~Fi$rf;r1TQWiZ0OY2}#%Ocma9)d|=!VSik4mMUD)RkU>B;^0CT%<& zoGJR_y@Q7WrhR`fmR%jB z&liixc-$%}w5kCvPRX^>M=YyEu2$wu@%acKCum#dvRo;-wpGx!tc%5E)O*I-j)XqT zFNzz;|EL>FSJsf<0l2*WSeoQW%G{-2_a=t17ia%h~V2MA&D<##VI|x)uX(*~p zkK{VsyLn9#-GoS@qp2{3lAKbEB)LfuR3>PuW=E2m>9}hrLMmqoA_l}3gCqqE$)B^CrEB#wgELT`k7_oiGZBEaR4R*mJIHYp!1#J^Bzu?ExXzRLUGmcP-vCr z*kPqfPNLq0tgT&H&0eZd=T^GK05DJ%;6-_?I7E|j)J4(O3t^xzWg82KJUP61f3KU0 zWh^XbRWzoHQV7u}N6jNU`V|iLE$THbOi(0%dk~~UH!o}$OI;36kuVP(;zHDTy;v`R z0TO{Zs$_(a+!$833@EWQhQPlakaCd)lud^d8R4!O2eEqkFjiR=$EyRx#Z$f@E*w%}Gl zSx!D%e3sou*+P0&`E$i8azE&DP0%|dsgEZpwyaAOWkoV8XN#N>wIsh|>`Oug@8wj* zoTQdfEr~f)Nk#_4l3s^A$*fK_lam{6h(U>5bYtZ-2qs@yMMTYt0Lu^>sC?QqEklIpg1otGnO%6U)s zXX_a(!~qfWK_1S0yflC^SwC09h&$?CsXe4Y$iO(!YLJh}Z3u^rTvbV0U&0V#TVWC1 zIv)O3R9kj>hZGE9Y7QqcAQ22Pm2u3;@Puj`OLy}uQkZo%WPlpp6jG@7hIt=$KW^M`RMS*aomA&#eg|$0=C7i~oKFM|L@)Ql8!zF3IjY#{|=PIw^eh@MT zqp&piV7uohaZAu?Lq*S7Ao$U{?)V8Y^0`_3ot5fp#qpePMLFw;5fD)(O%7pnzD{N^ z989o*;aK8X+3EHVIv2Qux$t*M zZBu^Fa|qwXJb%71+no)2Q3Q*@Arh_bYBENa;HSG2x6wbajefR`QOW8%mfT1d6 zY|o(MAGvAqf9c;cj+QN%+o?>D4%a%AkiuuX)y>|5fU0s6u96w-!0x<)WV%Jji|_g;7_ zYQ)C@S57iQRCx%}kb=3Fx9RZ#n_8+V(YZDRw=ta6hV=eOt=|RL2s@98+8AS#!&}Lm z%o>AEXFMD=?rvkHE9CT|uybFgsmoCiJ2|EZEU=(TTO4*_WXx9dUfDAYH}wdywt@ao z2^QGuF$uu*ozvADH(H{o6Z?r%kvV_NZc-+j&L|mdygDoZ{s@}Ly^+SsgEm0|c_c6J z!3+RT#$r4Kb8_S%6b!ZvlD>RI|zxuA`&Ibgr!}pSZrZrduU3 zWoKut%4Fk6+rraVs`Awst+U-8ZHE^y zU3ovJ@s}&zEjS38Z_-ZhcDJF=OU?7o($Z-fM)TW?FXdkDV@tEc9z?K>#g|T^EEkJB z^OsvCE|@8)xU)@CCq5W9LmvC^#1~JD3?)4sa-7Z<+t$+?Bc3S-0k3*e0LlEk}$td=LqAi_A8{-1LHz7P@shE zKslbC`Q;mZ(^25% z))+(;YbIx}UcS(pZG5+E5^fW6W5XU4*PO5wK{6e8)xu!Hi`9N%ru6CQDcx+Mt}DBQ zBfkk-!vs1kk>eqEfgnqHhsP>Sz7yL4$uN@NDxFq{7<^ycl|*WDa+=!rlcE8mpAk3Z z@^`%pwvMM}bob!&;O(vqmFH{M%Uj=Q96zG4Z@^`tY&$wqa>5cpD1sj=#0lQ(I1CuWYhA`ra_$sQx7Z5q)PHwy}KqpomY5D5LX2$8rDI(&vh-gIv zZjW;ZL44ag-*`76aQaf?wR(|50N@Sz!V9Kx#yzD|)h0d{|D{Sd&j4bK&)f!$pR82Hb7y+4(h?KRVIt=ku$vZ{)bzP!#2m&EEa?88hkVlc7KzXzU!!CE( zH@Am1ix@lO{qwM)To~6*fNNzqIy4KQo#n^?z}bbLGEmWz(=D!L@xwoh_tQxH53{5cLtr?Jo490 zGXz!AI2a9|<|Jil>_Xq9XFLx?1o``d>N^!iEaEARd3St1@CV00>PsAC1>u>a-?=7o zl6vX@$vE#O-aAEiPYy*>Tu?^uP>^~sX5mwI4P2QnoG|2ZmzXBqDt=hD^ZSLCu)Sgn zG94_ht7V%C_p>pvkO4t-W|hi0JlduOoe`r#R)!1tICt_GLFi^`igR+_gA&{!-yg^j z6nFOD4+Qj1@*+?Q=!Yvdd36h?FYLNWT$g$#ldvHt2Z}(gXEM)ZbjqEK!lReanv+vv z?h@@BqHTC5cAvVPn}B6^?+0Prh7ZTQbGY((C3G1deIR_j6Z|-u6Wz@Z;K+x@Z7*`$X zwpcG!Q`9B9_7{afy?Oi0jvCGDm#^L|O@nf^#)-!16V#tThTl5DD-Qqw`SL_(Fz)Yz z_3i8o?&>{kRTM%bqTvAQ0}iJ@-d$&O;LXfo0PoL}Igz(^1_(Pn>Y)NkqAHGT6G1Nl zEdw!z{0@VDXtK0vL%5JuU%*c2G`PpwE=>2xZl8}}%VEyKFoq2^p+s@1{~!=3n(wc@ z`8d3#izkXF;UoDNQiFTuSKkY9^lL?vZeQKup0xNyg6>-|dgf^PVEJlP&hv`H%PtP>Z zGM`hH1V^o!_j^ADe0Zl=S3x@4-RD zDKWASWL&>-_0@&OjjrgJMotWCoLo4&@S>P`wbuuCDB0x$0!$Z-tyFpGW6Igt? z(S$ViW@Dwhx3kb#M)3DxZ)+P`P`=hOyo1}-W5?Fuo_^)>%IejXRnb~QuxnuZM(Aj$ zNBb%l;@)dPUh$A))fCT$NI8!di&T(?ghP0FKJam15IA?_F9#TCwV=Mn%O%vM4>29s ze7YOdq{|Ojl<~Vz3Xg&OA=`!fA*JN1Ftx|i>U*Q^cw^AAd~1_cC3L*+1tDGc$0I22 z{Us;>QFDY~nP3Wd|G0?stRW9vX?MVLpwF%E4AvnC_V*!C-!E(M1*-YRCI+X0*!_Ko zI}|s2_h3ZEMlglYN^wp}hfsfj9@0|;OPy-~Uy$ql)x6W&D*)#jb3zr6{fCWp90g#| zve$2?h30X2*>o>T;p6HtuQXy*>-!5QC~h z@whO?6P|n+1-Hh$ES^(bP%A08Ks$)1fWhq!c)5&Ma=MIqKO!h!g&B%{L}!6Js8XBR00JbmD*%-in!N=GF~g<=_zRm}O{S;jhGR0yVxi(fY|7%U3U4ynJOGT5$o$-*9_+he}> zZ6~Lcu&e5QkS-}hcJ$ne1PgV@k8pW>nhEe*o?Q764d6EId%BmEmz>*NL5;HT%2as+ zmjlouMd}=~>2S9v(;;RxP4!fkiCNF6!aWC2Sa3dL0aL?1Tu`@K5=5HYP;We}Ai z|Kr`nXSiu0pg!(%NysuME^>_sQL)uP(A z=Nq$BM`s*T85Poq2giUmsH47Eh_I zE|Dr4bMTJA%T4<`_Zy2Rmrft&oDfHbwVS|zAQPzQJ9ifBWE(6;nWhK#n71{Kg76}E zZ18rCvlkF?97Saw+l?Iv4@0ajyzN36Q&MdfN>k$|LI3KmUY-ovP3(7J)In;b6Of7! zGBmfC8<5haR0GmX7e=XS=b&tof5b?^n^F#pMPQMU=G(BB#cE zEZ|R?f<&K>c~Kjk@^p-Mb9e`pb9CcPn}F+bsEDV=BWe`UA(o81o@5r`?&X$ozXzlW z`jxC9$bx<$|Bc3*cx{BybiEbMI_Vg>oYQ_6aw3G|-j2$ki2yC;EL@}Fm?kS3M?Tc+ zpGZi|SD*m6nYk(0EYksLay85N&E2}pepF7_;d2jLL;z@p#|8o~|4J`1>-0V$^8|Ss|aOXbJ;5JU9EiWm; z5?_YJ7Shiwd|!rLzGVYb>@VTWasvdQX8>83n1#_kx7G9*9W`>n8o=bfuA{?om-(et zTv?Kn7qi9{CNy>n@`E48jmERZhp1K+{t9u#;zxd~JVo({q>`mu@`>U!m7ba`GOlI3 zEKf{4AsO6;3bH|nt1vZ z>alNo{^$Z{u6>$~PK=#7ovMtyd&0W~xff{<9XfN3&a%!%C4{3QLF;3**Nc_4ms>Yi zzkE{-aiZTooE6yHF-^aEZDsYw&9%6wOUjmByZmaYu%u+mu3TEae6`fFBxOtE;&}B& zsko(O%Y$cKzWBXq^Olw=e_{3J^2(*v3vqd$mMQfAtYieR12ZC?vQYl95gu(z-9@q&}9$)+~*? zLq9cEVH0Kvb)h6`F;!C5H{`RcVNjXHPmTYG_9^rtU**-tG_sfane4e|h8N?>c=%A- z1~D|?@w^dY={F$@ne+vL({_9z2|lXA!glImU6TX?$^y`w2csT&Ese^C{ByYAmx&I8 z4O3F)8*8kUPEQa%6p<3yc4Q$y4Q95$Pjxb~wfpYH)$)+loS&mRbl9JAN79toeg$Mn zqZTSILbMiz=x6A|g=d6vZ?O~`jB(4+A^SOj0ICS`J%_M9l2Ow;j7Cn1OEDDl1^`bB zI0tO*w6{k2DfG|#wbu4wYaaqmlrqXdma=IkuRvFz&~&eubAz4kuM7Z=A_AHWqhe|= z-Ola3OsTPatdF!Zfw5H01GO?QvN9pQ_Fkq%n=*eLA{9{17?6(^rNXuHZmm@|$kqBJ zkRyUO7n7_WV4))b{2)N18i3}o%SevNIbgXS3TwtMA5wxXx`T0t{$&(L14`7?A;1~! z;(V&l)E%1m0KbwF2SVEqlC4pL5}-2TJ1XnLYJk{F2-5=bADopSKSxMj$pjkn7Zr{6pi30|bG$%<&TEmOy34Pq_ zbmczN*rJ#5mA=L5ASzE8|M|wn%U{OHTBp*SgPq*ou;@yfDK*n+<|K#$0-8MA=JAbe z1l}Fk@A*vyem{JoKt9x4)1~ep?++ICQ|WH3{0Tu5a71wD?dnWpfjC&I%!RG{-1F2( z5@rvriCOR}(#OaBV8bwN7(on|I(#V#bwo6gO6+9L^%Tizu0=1^$rCeRQHnu)sY9TE z{vb#+J{U9;w=88EGyE+Q zGKLA7yo^<5hMpNzF@h7WJ9(SQ4Ht<|<=m7z2=nzI{e;>z?Ejw@A{v~QS3B567`DS2p4EP5BN}2^-8ZA%h(X4U2+lEf z7$$PRWuuK_Yvel#6ER&!xYX$F$)yTL`sGx(f(( z3BDzcKKqf?sUvok^tc>>kqWoeFR2*I2DuxXA+O8KtF!^4vcpeug++5hxq%3 zu*zu`>rqXq#}Al6`CWoo%J$_j_fm9%kX>dL@*sg!Vv8{A*xtqKr_zr$L@$;323krK0>{`UNh zhf%7}!N}Z9<&O|$UaWI{5-KSKAcHuX*=Bv?4t=@5aa|1Dub|S(sV<8=K#T7bKvNCI zp|EZg*?lFxgMijW1-(PB9=~jC8TnOX8PQE$e3x(lZTV3jNFO#dh+wMF&`Sv!#+;4H zV?|Q^uLEa#Les5XM0Dv*?!b>BM}F0`x;fO~PI70}8SZS(@teub{?sFqnJ_K+COuQ%*z@l|fqYWvFn=6w(7C(C;zJ-tq4C-hEM)_WB-?>9VS_tBO{$gatY7>j=xZFuD_L*!OpTtkUD52Ppq%J88-4Cle9-8sns%muK0NrenK)9+(F2?|Fgv}Bk!3sF9Po`6n_c% zAJY6tp9GDUweVMpU(1%j#%Cq|)8aQ!;;GPvo;fY|uNQw4xld}YSHf84Z;I>rN8-#N z3|X1qE`A3M~HrAkhQz9hYdc5Cv4WF#+{R!PZ{kK|OTSCVryDGR4IH*{a39;u;g z+p*6mDZzKb`=n6J^@Q_CYL=%}$_uBH)C`Z4^cwCac`@ZmLYZQjIIb9TCf?6q#?b=i zoxk}jM`zy2CMOzqPWLeSv18W<&;Sh(%-sc1hdDiMx*BWZFxgn%+kTi0B7Irq zdt>g}+VVxXVL}%kIbyFIZ}3rezRdn|gC*39`i6Q@-|$}4%VXSS4$n0%b$hpO_Zl|` zy*mtVDL&K3%(R>DaF05@p8LHs*xG_kc8xLW^4e8+F+rr6Z-_~1#d+ErlR|2n+KJl9 z>%Q`_i`Q;6mv6TCG!_iX-A_hcJl}xr7=XkV1C>|LR{%9EMp|N0)oMX8X;y-qLA|67 zSD_}Y`CCZYDdZB;mqr7xwXPND1fnNXTk_Li`0*H_;-FNPvn)1y39{Jgtj`T#CDhr! zSC$J=O>aT;0;IJvfLAU=XqiGOShCvPg^0mT(1PG8|^;nvjTiosV z^!I4I{wB1UMfd*Y4Y)w?<&fd5_-A~-^x;k&G6t9}!PRwc_T=KysnajM^zxar?ez}u zxcth>h1HAaU}^-t8_)K$(PQ8$s)zZUo0YcU<~^dX5WG9O^syWBZ62!OOsk6d(D~$) z-8sduFfHg_`SlBQx3Ij*odz%YFF-|~|_=W^8U#Aqn3v>^8# zMrm`7@s%s@#bx|(^p$H>PM`MJf;UV$lCtqN&>DpAf7rUG=dtpIHM$l6`3jw=l zaE)+yB?Di#PDqaa4C@%tExl$4YlSoKu^iMkpbP*N_mUQ>TGC2B^@WJJ-bJ7Y0n{*) zfFe90=@yI3*@O@RsJ>#eSD}govS4w-h9xVH*Pu=%UhPsxV9c0&cwCi^`s~BVA%P;y zO+rUH0!K}rYq1sI12|&B8JX#*hu@p+A%ovyr2%ZE6VDPG>MrIwSZKU*-+OVl)y(uS2VsH-{kOYA39(Oy&!m4uv3CWPMY5O5hejdl|Aorlqs|PEhFfEa zz5r9CogGh4l{SFRa_4Y7t9I`F78k|04VM#iyo05*{MBJ7`DBKof zWhQ-ruqQ=i1gdR0xF*xP+XFe+7?K<6VCvpD(szq=^gv+Sk2=h!ImEFcj{rY$SV=N% zwRKsIpBRQ(Y*dElu~EVSIr!x9V>iss#H%vba4Gb3uKN$26~lW|y74aW>|aGkvw{3F zqllcoDS*&4xirTdl?T{oVngv9j3s0nk}>IZASIC=9Q*qFc~fc;fZV#CezejJdWeU6 z;p*DCyLay{*!UN)Os$5Ky+$+8lD6mQqDvhT znJ_Lo60WM)cDUBfn5{St+`G4cwTgw^lIdkrVg(DnL;K8FIu84^nzyHxbZ!h^PIl|Y z8cmKA+2_o+6YsqZL{!@yZ1gtiEu8i7RMR8E8a`dI4@8ZjgcZ@X$#^w*<^%#4W}Q|L z#J~B$_<7PcoD(j&F{X6`teJlQ8wj7yYxM;{MsABlaa#uA61q|&&c#Lm6w=@bKo#9# zpRxJxYlis!f^n$rAym$#X6X5Rzu%dM({o$iW+ScK2W#(x(eLuj7G&H8|J6aufzSMw zBZMHrj;qx{;P>tB=o8Wpr$fGACm-Fe7n1UMVeOXWBpF&sK#DzS{FXeOfCT=k$O4`y z)l!VfNF!RtS)+x~o3K(9p5h{K+gEw8I#gt-NFyDD#lh-iAwA40V+U+?BOm*?ZCPqI z;R^`7fRM9uTmWII%#~(cYhw*pp$RO~`DpZx=RG}az~}9+3GZw=)#5WnKy(Pq_RDi) zf6Vos!218Q_wKQgX4!q%_G2NN+LhL;U1=p*(zm3?tnO`AceAJG!CkJF!|vH>ajLtQ z6Smj_X#B;K)n#k;cVWI)Nl5ud@obxYh-!k9bycaD=3}hx;3y-41d! zbVIOSan)t!0P^t?aSg>yTs0ZJNc$?IOZM60_iS*80Fa$1*3U;yl}rky8KQWnp)!{^ zQ^v=u1rpf6#*j2+&vXdv1zoo{kU+wc_1!in-~h7k7(B){Fdm>KB#&b&iUo8ttg0$j zlP?v0VHC0Ib0`o(+!2ZcUNb}Dy%O}TI<+Yu<+19+eY9B8hy5}t2nm|QL4c@A6;H_w zAU7>csE^vTL!bi?aJez!m7gG&u4A78&$86iLB>PSfhIvSAhcF4l-6-72QH(gNxU+k z)tQsm_LI~=C`Q|u^;3~9$|aLGI5>V0<}!P?e*jx)Qwf7tsuMlvM}YtnPe<#>&bjQm+M&IAB{}nGL|6Wz$Y@N+KN< zfc9-jx<|)Ib1YOyA?Y?1Eo2y!{*f*ljg+k~r8jY&OJYT-nP{Y}l`W!;vTFNC34ypV z`MlJ@0>nBXeS`p>U0ll@!=~TidcC{Ux{dJmb;Rb==sncDGi;3?YteSbxOb#I3))M4 zy8S2OBut_dk6W#MOR;s}d=?2{r^B+(&3NP)nfk z@y=-fIv&*Z!E=Tt|7mNu*0GFyt%uyPT>mgNW8T>}H8g8p@tsVuJ&#iy7%?&r?&E4j zv53HZnZL|j66Q1|2V0D;xy3PyX*n6Hs?YI#z4#|&Soeh7RFFxBc}DaS3gp_vzmyX@w$>8OeOrAxkK*OqO97MhfNkxtdTzD5Z|e;FirTVO*zxa82&LnGB)6 zKNW|b+3KiSKq^-JAUrn0XMqB+KaSqeRk1nMdV2kuAX6LpMizmZHb za;=CS`mzOBm8WL|HfCjS)Re%}Dbm%%6UwC$Z?#xe-gOQ0WIV z-&;{y(nRD!bRtgR%9(ME!6cYuY9#1rISTk_CsS7H>PnIOQk*!8b=xeAvN(j)6REhh zX2XDZl3jGpAIat&287|tnD94H1W1*|#aKw=5_ZQZa+4;WZ^&%n#9_0L4Smvym#`2B zEg?-(z`q^2;Kc(DWC=CW$48%2lXdhWt4oM=R0F1KpX|rljk_w z|2WadeG-yVgF-`W{VAQuy3MB^>{E)R6APKRYF`bjt1@|Yt62>-B5$g3D$sFxMW5Md ze3!dyG!zjfm~0;GTr0k`NV{|KCEX)ZAQC>o8cOGPa5nr@X?&W8t512+IVnw!W2U1m z&4&1n7;ZxU;hb7lEtMzfu{2;cg=fRAw_ukJgJiO@A(X~&B=!Xsd(ck}BcxFsE#jpoS??>XlzQi{Qa=ISU2qur6*ht4-uv%BbRNY>42at^CWmZKrhL@0%s zXU3@sgy+cN_gm|)zY?}8(kDI*6oB>w-`iogpenBd(Qf}yulPEQD6mG|S-PnUH>>Q2}nPRQqu56rckdqTLkqld}2O zftb$j-T>~Ea3EkR`sl2TUOi7YI;Gvs#$dnfrWOSggF(~u*a^L}28W9?R-#7c7EV;S zBNRvWxF11yWwh0=_K=$&I>fC$?)cf?KJ4>|2lyr%^`Pwy{f3V*%GRE~yIOj)NGd)BEqnOH|8PR^?0nD=yO zV{|DCQ(>Jeo-i;W198etc3&%m7Km#!3BWK@0Xn%n$8@1c&7J+8~}^w1dt^e**iE7M(kl}ZVVo@yujJp#7#n>)QBBo&}bZi zE^wrQVF;I}NCpIjz6?zuxF?+>x#@(ILL{YpLHXbU#!Oyr##++RStOUb?G&?9<)BeY zK9ih))B5O-10>^u42&Mi7fIpyT9O5fmcT3$E*>`md9PL|*(5UtZ>;^p6EA#2?)OHi zxCL+NzF(_E8VQ1p?;LMpF+V76^?IcNi>F%ls^-qut2~5`buHtzugx9$_@JkhKJ+>j zilWtBqiBH7sGaUI{ldulap#pHj~xfOco*=Is7fGW;r908ZDJ{$ASuXs58@zpJEJi! z6~@Ck%YDlpp6np0SFt`kEV;+T(wP`b{K|M!>?TCX(Vvl?2n9aYVcgaD5DYH>Lb!9~ zh9x$@lFSW^Kl#DP-DO4uC2Qf`1h2N<@Fx-~?zk0CHP)eAp)Q2#<~CXc7T&qre*Mj* zueO)(weByi*U_;^Cr(nSCYnx+^J znvYs?hGoRW)!$Zw5Ro3q2<+sH)`e3$Hxkq8-3afA$qtSz=0sp55Gm8BCt<1eE{?=G zO+%P*#HJn3{Y0h>nET$y?%8B;WjmC~Ol0eWp)AJ_BbC6v4}%B*W+O-fu_m0RG@<0- zGSHACNhX5iD_`8!8&kTA!gHd9_cX@c)44OIE6LUWoh!0rOtZ6?0X7}uNiy8+8~(1E}qHGi`D|!|6p2obHi?GL#R>mgCHX! z)Uiw?nS#J=PnZX1bk3YJW)L>Zx}8wKNq4}>^l(~WPR-(v_g()!vhio10g!BezAMhw z(bANV26mW(p1K@QoQ<3~PK`~=B!kvbr8XL%f>9QXzW$MD)YjnZ!88(yI21(clEOATML1G5C%umWp>R*?vb>X7*(!3jlOR-cyjQ|2 zl8GhCWX2=9@J)ohMT<~INb+P1ih-=6UZvZ~8hRKN@5m0AWC7<4T&*_%|}U;(~x{_%PpiuL?CSvNx-)^1QDA7-<9Bq&=jM?6^Lem3&8rkRk>4q zow3nkVz$Ez&3hdX7pm)*d=x1nm2xV!g^!L@v8@|4@CA+Nsj6MiK-1}{aqL&q6R>$) zPtE~7>(L3!i2YR$eEC!l0^%&?9!M;~&-7cCt(+uF*4->x7T&G5*d_?d=?8}hGS}{M z2y>G}&U2^3VVVA_TeGe@rc!jaR-w~dbze`(l1(W`7mt-)D88`-_&X0Xage7&jAez0 zA*Gr^p$;uni`v|^e&^6iWpsuV3Rsyk%$4qpsXrPWBCdvIY#s6I?-GoZ2X_)eXaGqW zP#qd7^zfmx!7>yAb+VuEy}HXGw2lEgGI0}OjSKt^!bp*zCUCFkhg=vDwkkH8sMYll z+Bj^VNo3-*l{V_aBo0UD-lrFJuMQt$@W5RSb1 z`f_n|{*`ORi_PoJ`Q}YIWJU}>kAGBCL->B=CtekOSFAD^LKLDoqX&l@NZWt>{=rM8 z?jw;_7~O|PYTj}-KM6=WIWb`GdO~a53zDMDcHTQm<|kN1y^|9;KYcLJBAiNi5rbfv zj}q-laYqE(Zoobliu<8bQs8vkK)`9b4Si_%b#qe*SH_Fv!Un-wP7^9L9ZwTMIt~N) z(0~q2XH-!u$+?eXF3Wx>V(gmuvQRV@n_^Y3rj*Q-E^zmdykd9pTiwdivOj24P>V)Y zf`lqW4@g!Sd4vt{2aF)tAqw$I3ek0NzYv`dsGqk&B5T&;eiObxvaoGJ5HuKl}sFvmtQ~=8_1Be(W@MR;Cd}5O^N1WXWK?aeU zOdKdpK#5vpvntUXBeUzavIjR!r1bTE+%>%(?Jk8{663yh0C{ao=J0o*+&I6JaLOpCbFxt=8kG;~cG%kzuVd)*FL8VHsA z6|yw(TXTCai^1ws4d1MskcF#z_cGMr3SUfIn2-_~gh@7n4oU}WbtDTQX_yi`46n%8 zXZs$@iSJY$)dq(trwzTqEyd;Y;|~l#NF|JnaF#}wfLtD5#7Ol3^2AnTBO;G64fj%$ zpd@QYJSN+lnscKLMaM4e<(=Ni z<-y?)9?*W)0Z(NZX6g_KVmjGzViF=@GPQn?uoFJvF!d1CozWw>IM|zX?8foiP>3iM9*}d+~^y;^;!TFwn zzX8k?6z*}Hnxs{iBaYQQxJjI_MWj>YD+K2T;@mA6U^~bMfM9`g_b@l^K-5svUj1GR zCtVj;&9OMLn?0ugAY(M}ZpjALNO|;Lw|RI#3uFTg#hSL&!8@|s1U@=x(necoi5#r{ z&USA@6A;6nzpikbL zaOq0%;e&Aka&xj=2O%Y$dD01 zD?KxwJtCvyRZQ?>_Z=^K+8|d2-IibX<_c=9h;@2k;%{eldAh{O}NZiiLl|YShf_ zgg3v1X+m@o%3-ze(3f7&FuMhW%NGw%(kq~F$51&RRsJGM)OER1L)p0LK2xgHz}sx= z5_TIJ4}nX}>&JNw#dTwFEl^RkesA@5dwKmGiB=9Jo#0qQbY{I>DeowhmJ-#7A$dA_!JGYt+B2nQ8z+szHVO9oC_( zDOAvtb6NtwB0C6(V}VBBn$;l8hKXu5)i6T zUPt6HlyF%K$C9qzNm7d|1P%gD26^qUAM7M29&g-Gr=UQ6p;w=vj2sIR-zCr~ZbG4|nJfsp?FkVZNM1k1azc@I?@H}lr-(9& z#088zwM^n_bssxv|B~Sl1o@IPr&4gOE{$VDY^BIY8e=OxRQ9T1qpaDT>PZ!9i8M7i zTvm9jmf>wA*z2>YPuV==J=@1ZkzCKm@lQ+r4vv51)k`GWKsR^6v%U=Y?hfH32>cJW66 z$t$8=dBE}Od!mG{2<*!+!mo80AyrpS5bQ{$kEA+GQnJ~zGioVZhAO8wb{m8Q-0=X~ z)(bR(?I%ncebw|>g*TXzhH0VS-Q56#JNZC}B|96tJv|Vbm?o93Jl-hNpCF%xWEO&v zgO4FtAT5($dm)~dBR!tVw)VG&yp?BI3;=H(L&%3xlNHKAkR$A61D(be<~`!=Re}h+ zk+&GYe**TD$X=YGr+?R(*U1jT**uZq*XHEHVOopd8*<{o$;=fJr-S4By|bl9h~PSE zP!B200@#5>79fkkCd-6kAm}-9wZ$pV@Ni$h%eEhPFN}hdUp$ff6mUX>bWWiy8wGZ{ zJ=|V{6GUd0vIe?`)L%0sUa{H67OZzO>>$fpxiL(@c!)c{(p_9ZzOPqkC6{K2L8r@| z)+ZBL&h!SdgW=$yv&|c9$CZ>?c5sLjHH@t!7}+v+Wa%Kfv& z#MKU^9`p>U$S(;t_DVdWX(}d8HVyA5;SemQHY^g#ZIM2wBb_%cVOo8@EH8vNm#8hq zxpE#6Tk(bOjKW(qP@S28!#O)E%ON0_W91OMSDyHL*T!*1!v~DxdwgwN6#4vyn-k!sIEIp?pRf3W&oOd0n+GREj+N#b#+! z2>epX!O?~XE-L`CC?&8Gj4P>k8j6;dGz$s*2At>4;v%OTws#@{5lJ_6P^&%1VuRI> z`zhI9nJyd=dclbztfD-D1M=(dpj+iYTCkSX8GCRXUz!P-1!zT%aju30;i)jpJf3IC z*Bf18yzvsvoa#m`bgJ;w+_Od###!_FhS|4GAtl3)_6oSPLtV}S3&rGcADK$2$s7f< z7MF&LMqv!;M$I;Gu%)iIiCPZh5(Nw~E`hMq&0h~kxJ~P2Vc}>ubP%iww1Q#!?6x)n zV}+5ZRjqPr*h>2GWtIYYI+;G56K4&CGA>=RL@UV+ ziOEO3C{3r35vjo)IB;DbsiHC>9egEJsCD5p^j4PabKmmD`4e^W%vtTy(XOhb8c3Ah z2^~5;APp~Vl3nbwl;CS85wrk@CHfM8=`d>@5~ZRNibKQ&#pO&>PVTvD$UB%A279bS z{}(&vGBOJ5TLgwcM~MN@N3bl3Z~-uyRX43QF~SKgaS#f;t?#gKNtHFNML;NARL=Y2 zYn^@_MsTOt>pbd}hK4}t_YP@pOvfmgG|WXna0m>9k?vsA%glPKY-2P&MwVVqOrKU- zNt-z{(phN~k@HMCb6Z0Xb&1vh2l*^be;;YWHSfobogDFpnsY5I zYoaIlSjWxclxf!{wF5g_^o?|95YM_6vw2Yx>+DZzL{qWhj!p3Z=r0r_XD8YqsQYhCmONuYBgh`tE!NwRzg1|GP?ryKHYBU=yXR!sBDcI7pkv;}& z!#T#0lg&rDDe&@yKTTRAtm&Uq_{DkA*jbgwoUW@;T^QSmPM+*PI@7_(d|d9fT31iD zK%PM1GD$NqaeMGclt6Rolz!E0;x*X?d|{{v#9o7>$R9DafciI6Rt{BIfS`!CuaJb^B*UM8pHjGH|41;Sq4w0I!f7PQ8T94tJ$G3 zf@AF*YxN^hTZRGtQDh&SFn#H)==|A}L`Wri(#!x8XHRq_#+C;1v|huD$^xrK({q_6 zofG+$Lf_xq1Wr{c>p5Xb1%%WvpOg}7N2~KfX-;Ca(xekfc`CvsTtyP*$q!tzG%kH) zQX8X@MVGCcP?@sZUPV>#V+nhyl9oWC)+H~&M7|Y3pmQ^{YM#YLI7PtgCf6ebjDJYz zu0e|;JHS;vamV_|<1Xv4=Nn2b#sV?q%zFh{bRf~!>7QNgO~XWQ7VR zkXbSY9d8}e4zZ}ZpFMlPae!*lc-d1rT4jce8IvT%8cd9Pwf165&x4R3j8I>!iFQD7 zX%=F%Z;YX_HT0|zVXLY$2?m`yDvsyY$MXk=c|-jgt)ddN<%)^GW;CMG`2rGYfA}$C zMdOh7l+iH|><`xmc`yxhr9ffM#YSBS((a?D5b*D2MG*sh1c#Q#If9DkP6=%ygyGqu+r*cW3Wqpt z8MQr6gqbyehUM{W!Da?3JYXu6mPJ!$L1;we8PUYgj1JFcWAS+5}P0D(#XS1 z48yex<-{cr$+SxTA4(vaP<^$fl;Dpi_NYIfJy4SKTTABd0Z>owdSdeIF=@|2^Z6;w z*}~JDE^BB%5~GmT$&5svlzA|`Qk@}o5S7m z5urbdnqTRN5CzV3L@4JtlMV?f=Y)O5Rwz0M?*GFcZZI7ofq1%PRT+;Z^J~!cx ztu~OA?G-HVf)&4G&p=-%oKUjFBFkkxKidhVw&mJ7e$|{%mRkP)95@oRc;JX%i82_$5dnPLjl<(oDU9|1?K(A{21glTSPa4TOpx z+iXuf@r-;D)kX6FI(XKeiXG*nEgB@u-AT{4zSbQLvRTYa4#OYL!l6XZ- z)@v66f?*F`Mrr)Jzw*z2>0|Qw;Jc0Q{C--G#NGM3-}>O^KK8MdpIrH=U;gfQJ}dK7 zcB%gEx5g~;`IQ+I`6Rtgf(6K4{o$3D@aiYnXiUV{bk1glzOu56LO)(9)a~uI+g9fG z${Q&2W92e%<*)+3u<|Af{B)@R?P|zWGUgrLR`Bl1H);yfQd%nbU}XaZ%doQ`4SLpE zccqU)pDT4MW@%oGWThUh9HP{Zl|P5l6M;osLYT2Xzw#GQ^e5|qjq~;wSAKP3 zG5Xe7$A4+%uc258&ju#k#;nw@t^DUG^_jXp4ckwpgtkL_cl$Q3dOa#5`oCHEb+n^X zpOs2+{2MF(D0G$Ni*Zd0lIy zwXC&&vGT9#T4TASwST?x|Dcr4WCGi!ID7HJAu>K!NOC*SF&7Esqs}z7p>!j40Ki7JR1wNa$fbr1NI23y2TgN5=jC&b@+aIW<(OX!j(e#IQE2yL~`wKn)R zQbtqk*(Ajb^{wu?*1uH(C%I$Xn)|oUwSJj}lrczWoNN}1SA$#GKX$J5AF*sQ875d* zf&chi>o2pwry{P^8OPrLr{`LKrP=`RqO}5l^<3-MSU`3XxmZXErFFqxe3C7fiRAB` zYyExJ`h>kq>Ej=qYyEm?F~#F=oNN7~SScUJKR(y`pZV^GrNL|n|MXnzf6HFMC(3~T z-_N!FPrgzZ-Mzq^}^-})L$>B!kvW#n(4Z~Y>R z=*YcDI`VIxZ}nJ07?1#@NA?EE_W9Pg;%h>Zz1}_FdK_P~eMO1YetN$3etgZ^+3OF^ zw|<$gBeD$ZR{f8iZ+$1e7c^*^e0%@L&$s>*-z#0)sg=F^)8|`%KE5Ml5TESbe{#O{ z*ZD4vnFm`PfBiSlxBg4Mj!5HciMO`~{;Tt?|BfY$SaD8cFaF{A)<5M7T^M?vWUv0$ z^R3_HE2VzVF=;P<>wN3~id|+oCauK3I^Vi*0o9fGIG!Zgpq2Ufh1RE8<|3D+F^0c! zPM`gLF$pt*zzTo%LhCXMe=@wFMZ{jtU1%-w<)`9HHG|muTNheu0!@4$or|r^*Dtg- zSVqOhHHjFsv@>M}wR@p8W>MwY<)SIOdVHbvM_5wDhf>KP9JGGvLhIjPu^D0lk_@92 zy>H?!&5&W>{+kzC|1PU2qpwyGmn+q=%AQhO_e|@3#_gO?GFl~lQSr-SQG_9$B zaG~{^EH@Q#YJ>d?7h1oSc7g-(@?ihp3$3Y(sO%WiBI#g1ak2HI)e@<6@&_)qKEo2K zE6KS#x&gJMLVD}RFSb6%Qa)k>CY4Wq>SF7sS;X-wMIv5*=3?t-%dev_-YPD(=J;Br z8wDc>;jOC|TVLc`6*2T}w*M|(Y`w+;jz)BDX#DL9`sUNs2nL&i+ZS7RS@%+SvIu{zYFSZ`>^^bUMypF=b-o@5?<+ord2HEIh>j~cm$V$?~ z(Z$vu;rmZ`+lc`2OBY+e!grtccVqzBF7_ucw*E|3qO#BZ*^8}TWr-h4+sJqJzjU$n zSF$2TcQT)}5t-qNSAtd>h_qQ&#{x*wz&O1tWy+k!`{hf=gzsGVv?&Wfy4eRi~ zz1aE5CiAF}q1hQ4NxKOu}@sE6m)*>7KLUHmwz z=$>Kkl0D^zKHmCizW=ebuEot*6F>X$)*OrcL{_A-vt0XlYk|c+0b5I%MsIz*b)WBk zSl^}ex%%HsF-%bR-bpwyPLLwP(= zH<7nB!g}d>PDQCgCk4yupFGrIkp!|~O;EL@icSKn)DPL;==IJvow1*qA+ttF(MpCU zZ(aY8=aaO>Ql(maM2gOJ1*t1IGefaFs8~1UY1tr4T8eg7DKgo@Dz8g6KhggrJm1h& z?twTc^`PS6?c62Os+XEiO^VWey#Z5&At@k;Fgu4lIM%8oC4@eu3NGPHSZQvQQJacX z$X_H&Ke32qb|I;Cf;~ve2(bw$Y6&&0oMac2x)p;ZCs$33@;)NMtgL+Rrpo#jIC;ml z!1q}TnG7jy)`^|+q9U!zQ$>KuuwrkP$KLK>2qTX?acLS)gmbI@Ag?B+AQguD`j4(28|j2+Zocy*<3ub9-i+RIIt`_ahlryaJiFg5k%FMnB&KSQ?$n!&FHa71sv zn}DPZNRVz%sy5-Hx!>CyH)e5f&a2nv;RrQ5KYtAwzxw<8h~geLyGQ$7WceBlw?kUv zqS3-tX`{|19~T_shuE8n$Jd(IUdG{Xr+d_#wGKFf_IP&`dL(l|8rjDU#1bnEyMt|H zy_^Mz0AhB3`(X4H+!Z@Jf8$zl?@?$7r=r7M1g?!5vv1y6TStkx;S>39ZVpGz*AWh9 zpX;x_;$Mqm{>J=E#V;K07R3z|diB+piq1g?0$2NBqq*JRn(7XpJmr6LPf_RP35{I8 zdE=$x-sZTtj!x#UUAu-WNA?dpyLs*T3AKxx*XO17jq6@}&^N31O!ZWqN(t9~Hq z&aO9a>dep04Q=Kp!0t0Y|7vmV#sdD8>&u!uR{#*K?}J-9ckeJPKVezB(9mH;#Hr$nXtY9vmDE``bI?qOp02 zB>CzbNa{v$ce}WcG=JO08WjEQX0f!pTS&PPmXxfpZj){YQ!~ZeJtX|tmjGQ`?@x9H z$gDRScfqu{*!f4d;L#O?JZyHD&vkG(q{sgdoCdYg4m?=-9Bx8;%_()G(5lwzWd;@R z58msrQ)e++(0@5ETw8lHq&;&cgTL_SaHkE+R(J0n<^fi&Eu^#~0Cjv)hRGSA3$ptm zSX9jpNZ4Ggz!cj^NL8_%*kj;Y2!q zJm_~f_qvT)uaeyEJpx2FDDEw2Tn5mzAtMhqKx>W$X}+W%hP?xczQv_I^XDwdM~{= zWxvSxnK(_v4If@2MIajTX#VAc-9rd2a3IagHR)2ihYZJ~=HYM`U_zA`Vw1PF@oWU( zaaAI|9q!Bbi4Aa|ZIwQ}ew24+3f0u~fODIpj$X9GbVnk$9hakPvSwoIISrMT7K#MtPuensxD9^h8ID59Ac zymYm!dnWf@{*FHrflM|$8K&O;f^G&+kg#vCw|BVjX`Xp+7Pd3Ui3HE*D>}jYt|_{; zP}5?O4Ax)QNpYBIP@l_kaD&?PAD1s<;U%0rL`lGRAddV2&L(~Jok zu|pYi0jd({WFKB-p^o|RbJzD6HIW(eU4F8I-ft=7=vJq2=LQZOG(#!}m%bP}UtqT@W7YXkswb8MgNQjlI z*PC($_4Vd;=AHG{qIbEC5>vQ<`--78%c=o&VVB-B2X&&QOH;uvJI4=b1egqgu@;D} z!+n_`+(Rna$muJ*i$(JAA^PF2NPFwUhZNI$Pf=o=1Uv^+;EM+B_4hY-51G;L zEqsx90-Dhb4g+c-F+&o1o<-M>=Wonvw>SfPM$Po@f(glyFHp%=)4nt zBBmkUc z0RUOViC$qGqbxfI=2qod;{Icl62>6vKTdsM)RYyiLKe>7wSltU zjQ_Rf*6uB@wAa>GZ!fiy&47hipo|wjuTWT0ILC&}LR3k0q>K8;=8Sdy!>hH%#oFCF z_$zw?85rafUZC@&S3KGuJR#daCRRzvaWF_T?RX=ETHHM$K7!Y@i5>C9P+<78rfY5j z)H9rMC~K;@BE8a$3;b#IxEizKPMZ-DTS45bJYS60;9qT1r-9?DC5gHzVr3=StctBn zn|URCBw(${w>4AT!(PnG>^I>TN7F?ID*+0_285&|a)CMAqXkm|)I!ldF)5o6K`~ER zj|2q7zd>Hg6a?JhW1GM-mH@8#;x2(rLzGx-IWUP=TJdF?w=Z`V@0K_oJLQBDai^Qe z&0XFPp3nuVYlo=MEhJ}R%A%J>AXDPzw%&WTzHF#>B1Zfzw+lv!<2iK7!6woj8T*=AJp6Cy$SfFvTjhq3*cnfy z($2{J#D-GWYfXpMy*p*Plx?)RU?aaj96UV|MQJ(Et*B~i@wfHuBIJ^4C2PEM)An@G z61W>|_)Jv|7Wniiu(IWQckkX_<^_b3%+r*VxBVg^Op3PwlEc;Su$K$V^m=%@)gOXk zFu>S3pmx#d?1Jb7$12+6jBhaPe_M|;cX0j(8pJvPpEDc#C9%Da4mUS}hONV0SV#BC zsgp%(%|T0mLIO$xGw+W?@!`=T7r5>X_zGUKy(5p3AuEd>LjZ+!fvcI@sg3$|ULQ|E zhRs0H!_l4Ng$qtbm@0V*Sj8Ai3&~z=yp_(CdO1bXX`A~c z*+tcEfrZElAFe@4@}`zQmnI%GbG2lox_WqW3T@p|n{)02O{G;6*mxL>DWD{PL<=|V z(w2#eapfu%&HOZ#ephJgP8X6BOeh2vhh&W@zIb63wp8+z{&0eZEu=(36%pC8&O%Ke z4N?YYpqPIgEQ1R}Dq;D--=0*Pe9HhEhIEcbwnee$q~goq*)rfq`a-u!z;oe4&r z5;r>8B0vizj2wwXFQP)*ClK3#e{Jf`6OGx!@zyJ|mr9B^_SfY0L$3qL1vYZ>B-}m0 zM8l&?at0k54TPZG26}`&$w>1o-Flsg-Fks?w-i>|JR-t)b4wUtuPyx6Qf*Nw%YE?R zaBRYkXt7B0*MnRFEf9wR0Pj)%Ks4?}Y{>FMmqxg#qyDBYH^Td0==GHFH3==@4xmy7 zaF!E6;TjaF912$t8fDN^00f*LAO@ka-ViJia@=rN#5b2<*qWF~xszSx-el%W%(W<` zJiRVlV6(Bah=@f2m<%u+RzgMD?~QS%C!~bVc;`w10g=pbYuMSQ?T!R!2PqAFi53G8 z93_3UJ|5I*oiXEiW7@NtzlFpZq(T}5r;8WZazgntR6*7J^oMhEX2p`@^iAh6kx;Hk zJrTG7v5u%IM?Q^NI*|EXm}MaXmxE5+=8dQ%$LbXzSXgDNHif)U*ZW;a`eg$$XN#QT z2EVowW9TWsN_z;yVY5(pvF%`@i9P8<&X8ncvVxTXBtY5nr@Z<=YUb8fgRkCH%4RCY z;4tUX+9upfK=1YQu6>iXWl7pVWne-pRTdy+4W05Q7|wy*FlM>|pfM1co&Gh%vytA7 zwWOXHyvuw%F5wb4VIK)QIc8%emh@A{Z)_PD=Tfc7y3!xWgU#$DbsDI1BmG-dK4*~b z*X_f?W3@%9WL!Sf&=VO2PxXBh2Y|SS=n`*a(kTkshrh}fkI|6ua$(N`ahQ%{8cy_| zlbg0}B5%CvSXDEH$DlPT|GoXLmh;Tbm!U;MfxUeB5zHvtqq-U3A>+ieMw;kp7a8K- zTwJ1#V-cveV)E)4rbo@ zE{drL5at3FY*WTD_fp8l9A!M?@9CtnzsXZ>^P&}0R*@||HCL7=EQ-20 zsM0+{%axz9G7>tZtqIeuh&tlBLmKL0xh+meSIQjXZDFhuH?aM`Meu7_`UGAAO_h!)- z5@=?5@6adaZ`v!qFj{z_E7OT{@9W@SE-Z0%^hBED1uw+qq_c2?j>REc|U9{_LMaw zfCln&t8L}tIn+tEO?reH1szKzWicH-@sOM4pe`;57y-<{$P=Uv?dLgR28cMYYS{gjtZ%7KqXNHEN4`pJNIE}+}{ z!e89hAx50aHUweZcM;hGOnk@|lIN$zN>pvq_slBmf}7@yVu~ zF9_WRu-P_uNv>P2Em1T|{RT=j?IF^k*iSIs;vm;V`hC4(bXf$1zrLxH3k;A1$?L-khJ6mp^l#8+xfku*XKAN73>v?H*h$1AFDH|qygr_)>WgIbBt<5`FYiv67b#OuLFq(Gu@hS$jh86)^AsoWY!!Gv`?(Oe%;N&89AqY*uO;|e;odg9Cc7y{m zJLaPLJv+kD+v|7UY2Ahwqqx(_DJ1wJJy~gI2Rnzo9cRbzM$)}_u-ly*jgRo!4xw?h z3Aww;_Asca28~bpeI9;DJhe1<5ZmXz%;KCYH}~%LwmX|g#nSyd0HxlS`3yl<=9ruN zGW&LLoHw%^{Q-PzK>eq%MZyE1RJ`ic?83jh1H-9`K2;byy@%OE^E58RYpJ(v^b>~q z<6hLkyTQ>%iOPB%u`iaq|BV~E3yP6RCx92K$Q_Y}m&@L~Pz3Il#^mZO$}L4&O19Fp zk<5Af*_sgj!|`;wCZgdWfu+)fWpSsQM_cAl1PU`IGnm93m!rR;JTZwOxW>Q$dJk>% z;JEBoo09mIxGm zt3YN2K#OrA{h0_=Vzt7Gzwrp>ygErsI%XenO2{V2HspkXVr+6^k`&9GN2AOqf+|7` zAz3D+rJqPe97R$vK??MGzNAQ}(ryHxU$?a@kn&fxa&xvBkV} z<8NlfwQAw&)q|t%V3VQSSLd5Io7b<}(v<*MFU-Gc)y5FuvxMo#SQ$jYr@8%~WdSr_ zM7a2npJb3~nfG@1qQN>*e$^V{@KFqOUyyX;svYP$qJ%wZys$&ezveA3W@hEn)m`VnuYhTeK6g`y4>sF6rn>;{bp`rAW#YVfh;d(%Fd*Y z?RB;Dw6%#aR5U5Vkx)?pV!R^&ONB^GD2o!< zG9!7U;3o@?@B!`CxSO2|n9|HyC-l#f3GIa?%jfwp_~i6Ulcl}gd~ifZgM)|zV_|*( zve&836bmH7Wusxq$O7O?G^`J+javsv6ZL(toZ}work;KE>I);&wUhbMj&yK&ch9kC z*}IYx`bKB+eFC~pvG&;9N$Zbg&bS6yB|#)WwI#rZ6$Zf42@n(4V!74RuSeR0dGt7a zAeL^1a#505fHfgseL7D7hFc|HMH*0J@11+XW*f3j)TGQn5-?do(RTlFZ{LnS(Mp1Y z*bts)!X$^qkJyhEi_8=vW+}0R*tU5|cEtnRPg$+H3hNq5Y$~-a<*ir?VYTxV4F*OW z*$jK17v4Z;1sCX>B};>BUyFv=D1j_u)oe8(LnxB5{m=%8bTk`>+q*a%+HD}|3P&Vo zb_Ypkz?g_+i3k(Xxzmj5VPlrk8YaXSXk2$vOzjknSy(J_Md^5sjFi*YVFCoTR$YBM z_vFcwIqouZSYN95caziX+J;aL*G96b7rL`Bi{p2LAlsQpj@=yMuimZ#i~(~BN`rLh zm+&eaeX&osb+KpG(@|4^<)Iz5LqR=6Xl)`1W=cmRhkci10$5iCf*S~&0vU^!1^yyw z%)#!Fk^szg-k{Or2@}Nw2SE!?0A^|EHnh$ZZ-B6h&NgD=l)R|-k;3Su>^h+JvBejB z*4#P}ILrnZ6@Ed60 z?zE;0F;z@?Be1R>XRDY$-dM4WBPz|M1av_VoTuuLn+4GNRQk4^tGgJgm z9|-Q8_AI6o*>PQ&$4mkOxHXB|uCJg~;xTpu2+|WHxRnHOoTrDd-d?1LK=ozk$@p7=_9NR|Z?MX{mGnyGKGy*G1@Il&>1`%=(Q3w3Q4v-}f zRU>+)OhR13jUjz_rJ8Oh@YYve!=YJkeCJ*Wt3c}mMye;RHqxq>L{pTMM%;5jk5w?R zE?{|t%ya-oIYwxO?%*1SqB_> zs0)THjv3)nx(O9GBJ!3HTs%bR0+*YuHb+;~f(26`Eciz6ARtjdcp~vfbQIIM!JdZ5 zFE0HsR}!Wpb?uRozuWlaO-=up!@OX#rcjuflutBj3Yy(ad;r>vM`^ds;+9xmQVSdB zFId?Uqf6B*q^7rUEF^s-t_c)VqwtoRkD^$@o50*DDt;!MW*h0PPLDs#Ji_yi~)Y8J&E9zBd=OaYCN>Q0Ob zFeCE5B4JUKGnq>OJjYUXTCJ_0a~hRE(M}Mj&i^hXE@ls76;M zZ3wFuD=le?%NMdRT!)fKCdh5&iag3+uv`|Js)0`e4U*#stoY{`yI8Yg8ME0F+t^Hr z2^f7yq#d=P&_ghj%rJo!m3Ht+#oBtf*yR*BLSrk32)YP!i!R(llb|cH2O_CmV~spuf;X#l|2TM`CnH zc0A)bm`)~Zfl=+frael`2pZGbJUoCJ(~~lX`v~Ad5EwJ9w0FA0#I-$3P$@AAro_;N z&L={HugJ(EZw~O!Ksut7*q6|29REOES7p2lOQt21Vamc0LfRR!0IkLpqqs(9$i<)Z z;d%=?;hKaMR9$gn9vU&Q2;(3mDyv10ZVyM7Mm7*J@dzi^*erAt)kF|aI(?{ev>dR7 zeX3SQYAGaZ1Eh?_1_LEqYe#_T#E%#eN`ruIi(zPNsWI5!J&H3hQ*G5|>A`edOw;dT z8mFbL$k~GcPQv47$0a+NNOB0>+8Rikk}MPX(IkdoFH{1E@UR^o71h})_|Dk0NxynZ zi#-%yL;`2{_!ElR^5*Bm#7nc{lp0tsN+i@eQ`|>LJd^k`8U}dc;(;P9vHdP&V6HJL zd0k6fy3J#M)-0jl2I9$hd&6CrKLRWu<6#FI)r3xHG7{<{l);Vk|B%wjf@4ESz$cLncdq&{50RFGf5@3vg8;GSw8xUNc^!muS^8_$T z>M*!UFnt%nRe=MevVkVSk=W*O2?t7a=(7R;LiGc-pGXw$dL^U)=5NZFF%=9n7<&6@G?H z<07QU;`|ZX*4OPZTcYBU+O=zjLpF;mi&u1Qr}jACaeVJBJC4Iy9R?_ZK*!I-D&S5u-+( z>eC&-up!Agx=VmZjl+gTdyq#? z1l=KcJ|x-;Q?@Ccib`>h-U-87va<|y6+uk37;x+(v_yeL8f6RX?r3Hc23T0Xwu;xW z7OcFma9VOlu(=PhhhP}YSr@7>s?P*@cP0`vle3e@$T~q1No)EJY}NZ>u;YUBesSO< z(KX<75WOT57Qd12Z^(`Y!vMfU6=}N)0~;$p)jf=2Dx5cHl-8vw<^mEpC!{};<{Lmu zqO+Oek$4&4J+dIc{(lMj1Hc|pkzp+ujN5G0ODlhzZ&Lnlb^iU8zit_GOZCKqb#jOD zy40Y0v(}ydjFAI4w8u)_c3t0rF}@1koFnzhTKM$e1S8>q4BH&G9#?}Vo+kn zN?fdrtXJT-5bnkU1f(Ln5Vr(%-iJZy33B^m-{-ayug=~eVjM^4y3h=Ol!X0F< zOhF0Q+_BUOG$83QvzXK@zhy_g^KcZ2Qy%q{v>mGf<1lVM+Q6~TMh_Aj#X0CH>_LS$ z48mkG?(Htnjj>D-|`xST&^$ez8{KqrFN}WB_Bsj>~l5X4W^h67-F|jQF^RzT=k5 zyDeav;<$h^s>kr!B^G^cX}<&vf^2s%<#@8hI!qmfG2O;38=*?D+_6=P?)}ZfU3i-M z#9%YRc_KR!;kE*jnCW;=3XJ=ZjSZCo0P;=^9*MoZH)RmQ9qYa!Up4Y^iD+fa=O(W!jFfw9i5J|=9;6LK2? zq%?;NYCT`d5xGUs5YJOnM%VOSyCR+jYF#gItA-w}z}p zKvQQCJQ1jLCP5ZRjY6MNEGAw&!oOw+;2g*Zrl_Y?EwFG0fh1oP_mHI)GAOdez$3vx z0nr@|4#l2L6RmVV6_;6mAM&#l#uun7q+FfxRqB-_K>QRb0AYM4mZ8wpy)}7w>5HPw z%S_080@Y#+Xszs3j|Fd4@ADlK=80KkmEN20(kJ@rvyEvB_&rFdb+cvo#;`tw@ZovPmHJ);xIs`cC>j} zb3sT}5f|dE4Gl=-H=91vmQ@GYS`pJeh{-#g@?9)MMIM(t28CHjDw-aE`p&*U7f|#- zS+sFZm3SapU87lshHCWw77lv~$-Cvv>X9FPWv~c=-#kI-p zN+QpUF9CS0XD1g%Px!t8P_Xl*EDvj;bASy2#Aa)gp@JmzjSj9TKdyBL8Z+)#;iY`*K(JtuHyZ(hOd{IMR z;1apl*@5D_@XEDU=dW_Fnp2Z09gQb90F*AyKEm17#3BM)cX4*Rx6|wI{UIO|_x;fJ zfE^ThbUb{cGHxh32#M1r*LYuif~JcFbq)fwot;j1Zl}}PTexw3{*~zu(BOB|C~^ zNjX0b61j}Ak*U)Ss+N#U5m$sc5GJfYlC_NS_1Kws%s<*09PX+tpv_||qIbzQlOFcE zKd&dC#-b$oGkcSi#loa0b7)1Hpujm^V^*{+w87WLucbV>4K@Ql#?(Oy--8GZD99Sf z&~>Be_Pb1Z$_}IrJcT$4d3kr6K1cXzlOSAPS_3}-sPKD&6$U$vj0YTR8&_umR$ zW2;tI9HJguRQQS0@us56AN2?RZGf0BtwllmDO2Y7gJI9VsZBQgl0;+S*HLJJHdlW< z?(H4WMDD-A`00a|faOs@Fi0l;L`@}2gUQ7;PQ!Ct#vvA^#O29HR*O8sOmu*ODDBSRHUy>^ImN029|Rr^hwX9&#P0cQC+cKhB` zG~%c4=-f0l)oydkZ=>u3Gwdv@F-?BWnw&$A-dqUdlSGQ(PtkR%=0V#w<@KtaO4_F9 zwU#mHeh=HB+Wq(#Kf>Oaws7C%fY$cVYbTH1hRA$NL0F}nFrg-k-5>S`!zFBLY{o6| zWho@BUwvm#*1hlsE4p9WV$Dlyvi1$}8xW_{lNeArjJUz_S831Xqg&AUN=@X3U>0IO zLQlzr7;U&(q$zJ^ZS!TNe9PvORG9EllW8&5f}zkXgFo~BjK8698e6s+GsT-4DJ;S( zuO-xhqav(x*qk4Wvpjyv#&IaOl!6y2LuQk&L*G0~o=m~10zNK0&xMp51!g-%g#=4M zxNWIRWo5vDzNtR+qoYyN-*B&curQD2T-&i|CTK%s0V0;*Z=$|~b?9N&qVnlx`>Su> zdu{2>_O08mFTM5VdVBp&>-N33)^i!_GLGgtflD=H?B%9v24fl6PE^`eyMaPM5$`gM2A9?4i)u?yenxWh%MoQw@->P8 zJjgK<1Bw!{lo!|vMFKElpz;c}TAmuxA%}5+htS)l78F&r6hY`&gTs!oBJQ`+Mi=*4 zK+H0@FeVy2OnC7ibxgCGiNv{q@~|mUR7aDe`Gw?EUUe!G2Ym;)7+fUszSaS~n^B6( zHl>%TM1i#FBA~dSZ~^;@9dDvNhylp9E{An80&!X(!ayoR5nFiok7U1r#1xz+=+A~d znnI5{M0xYbo(V)sQ`@_^VIiKId8bgv#;VN1B7r#|*~6wOC)9LduvGHgW;jr#JAPXe zjh9M8gu{mq+4-_j*=3p&5^x|NiZdW7gHBRSY+lRe(=Hr>wjZ-|0s}9ez!`dxK zV|!vD!XXOPgXW%kptdP)BP$Hk1*5;Pg5U$(E53F}Uz=4XgBJU17>Tf~H(;LQ8NY)J zR8fH}LoH?1rvZq8k3&S9IPHM@8zdwA`j#eFR2KpdvN`;)Kx(A_= zl%*q^6^Mz_qM^>DTI~d(Zz6(HTC+_`z8NIZbHEhTU^3vE;m03nCXs1vje;#@Sphw4 zFosIcD*`nis|@0rK%%Xs|4wgW^B(NUy2k$Di>_Il@eMJ6(M=MQXmSjZN)r&tF^+}3 zsH^$cnd?_{A~jNE{eMFbykNu&Z{1sDvHVOxPlu&aRZ@RFR=lb~@i^LOW z@Osr4-pu)IN1qgZ`3Og z2$g!b?;q}MP+_KUilcMhiLP7(eMjIn<^& z$M0c^OohOePlz)UhGmKsTa--%wfG%1A>t?xQ-5d~urv%|>q!r)aFFr{2o+?m-aPCp z`f+k@gmNY6jdW#Mm?Y^9UYV3FN5;k|XpEpyfs#8)iZjuC%9nR3&8&OgkInTho5K(*WZxmrIItH=3R`UyYB1w zb&LxxVY?9P)Vvm3Vtwxg+#k&}iGk1)-{<_!9YejA5e*9p;h>2!{$!beBn-U~XRPF( z4RX@!*XCcm{7TllumC#MXHSK7EEc(+z3>;X7c`W=0IsKnpplq_M}XsFt1ZTN4TloJNzg0VRjDZr|KYhtwH;-lvb>0b z#zqnnMKJgQD5Pd7T5W+PHc+>Eo2uXxnSX#G1u`cSRwR8q8N%gYQUM=afp+p4WAzh| z#3H9b6q=D4`ZDHO7Oz15C3zSJtRn9+rM}YHT`v4i+ola3534Ht|F}*Ta4yWtw!ng4 z=p*_~>}&WY2WGiQi%jk8-=>lQO{905Q)3?bOyv(SAT#oN=4b5t%RDa@Pat2kvRuGj zxu>9t0ZB(2cp)`iRG@;!RWC6xr0IOIMr>39v<9Ol_+)?oQ6tok^KFN6=B^f7;S5oD zP;Lj7QtI!)g1WcY$WfRy6QyEvQMRI7DCdPqoXDmer*Q{5ID${lpyBu?j4 zk+BV@7rxp3!XJX3gojIO%XjWv5^>DfzeJ`o2#u*kP0R!KR>hcyD)M}eQK*nYL??yu zOspWQuP+z#ufBBC_U^A!zZI7NnG?MAsB09L!&Qm`G_VbM6)*^blLNK`|08;C3I8I{ zXa^n^)~Zh=rdWn0;50peN9x4TS~-m6J}g1CoD5)9Ut=?yj)=7?HaZP)7E4+~t_J|F znCe?vXV4$r>*bCgvj`w(jKOOSrPy!6>#i{!@_SikDI;{2_oR1IQyO5osyMdLb&BAg z5!{jhU_jaFlJVTd_dlpn%G5WM(M5XG7Ac2E=wkL21B4wRW%~tjWp=ex;^tEcTXlqE z4ggK4D(?&&yn6qG{7of3wWds4#I{m~Kxx-r@K4@sTkiw)m}*%Ygp?oB6mGn?dwY^y ztO>5XhuFGE1S~Ec!G6`&K{R63xY$8MC8Uy&b4`tHl?!nd3c2bMV^^_J>9|^>^duj5 zI*FW!WKKgt0ITNFnsMq2)YLCZ-(P`k2bpw0^vk%&Z*K0(#ccV7n#MSu92P-0ol=Cm1Z?MpO2b1PaV&u| zNeK^e;M#!lEn_%e2?JJHKL|jCL2C1&z!Vr_!Mf9;mY2l z#K-~(EK***t{|&1idRV+>uMrx`)FCMo?}+5uHpJRtY*Kma5!DOV0^>aNJOfD#Z_%f z55Jv~1wOulY?Eemb*T8NhRFCBqw{pgp#xi-#1PKdJXoKv6D&o!DY#f54ChT$-C`QiF;VEYRS7V8t|ik0 z1zCAMTxIeuO5<|gQ>K@6rF$8rIbsBySr0v|Go2C6dx9Jvf{+7@3+k>t8>|b0>U3+b znVs}CX^^`KI}3}os`*P9_6hAB|Avypw!FhXfo5cPGAautLoeu2Ity!s>sXFfjzd>$ z-vF-SFA+f48KO^3f=SRP&P=E(OopDwbhF=9N0QuExdgb#wW9}U5*OH$O=6ct!Y4iS7E&E zd{tLlrU^NT=Vf8fg_FV^AvA>VB0Wt*N}C3NiB!ewUUq7%?1l)-)UO0Sb=h{GK|ng4 zMIa#+H@B+9sW1?l0EiW0^Ny+yaLoc-2s(Og-LTJ_LO# zW(ka;tnS%caTuw24NghN-pjxIw?*Rs1&k}%|VZTr+ZJ~?L4RpgX#(fheDo}2Cc>`=mxAgfu$Wj2`6d1A!m@YBY#7PH zZOf>I;X87#UWpbn5{?>?X9c^UZ6c9zo&r#>@^BTnqwp$@-DN2pX(4$)(R&IBKs|hYpM(o;x>3ec$JBTaL4bz|8YpX;jReg? zKF5;3BK%KeOk_{OL3^4m26^Ru!`AHurx(f*7&8aFzz064Zyr3T8S-?nVPZ4_(Bx=w zqc^!m)IYQYwG!vx9Y)t7Uo+Gx%^7VtOWN6FNFO{s@1e%<38K~L<%hb~9@SG{hY=yx z3<*-kE(}PApJvbE{$)kQ=4yk_C!X%1XvY;(E1%#orzrqK{{bB4pnv|cV)EO^q2#v z)9N-9+V^b%)ubS`?eLQKp!DX9J@Y+}o5EX45~{7?z7`W5zAzmmn@~;-Y!*KjRJF+T zrPb0N34WOmQADUnhE|(_i~)>@+&Bw-$#b$qmhrtD6`LjQYdVm$1cR3CiWWh}d7Aw3!crI7mQ14;4{RjIQ4QN*4aaIq<=&EUBd3OA z;rDiU^{2_oUkJ184Oaioeh5Rbk(~y~hnhd`6iA-6q8WTLAga_Nyc)Na@m9A?OoP1P zver0%Oq3Z3ODkBz{OOwcVDxUlpE_qtm{MnVPR^J!gfg|RuTwhr+E|scpytTaY`K(a7u%#dEv;D$|SLR3)S$X!t zA^xP zTq+3!#MzSx8Q`4Al;aGdqZ>b3fja@tmf+aPTzL>1;KvOo2?l6$F>G}nLzsYH|1$$=%=oZHJR)1Ws|;KXvNXRGTd|!umRX98o}Gx!gIu(<9m|d z^NQpzf$XRlLSP2(#$u*9al20ZQ@{UdKe;pvPrsX!bLLiP4%$AqAQ`@)V!oPoxES5) z786{+5+!rD9D+Mj!;LLL&tK{)rqr;;RTPtj!F_dXCSb}zA6|k`H|}}%Pa5w^dk%+< zA@ZbI*Pxd@Ia6r&!%GvIHC;5wQp-Q!PS~+KI8z>X%sm`OFMqZz)+B+Bop_i*`hL zPv8N`rS@!jjWv~xGF?$5Q`~8xrUa;55~e7|eO&F1@H=D;K|%}-Eq=@cL=US<(t)rI ze&9WUeQ8KbxaPz+qN3$uR5TdV%M5ogv5*F=A$UpT2W)na0BTsuPB_;-DWWBea}GBNT|nfj(yNx>sh@Bu0fxP zj-`3W^vu3?jTloz!EB_UP&lAL5}1xuBr=PuNJfazNT?AfN>!9-7_kfKYP1dWm>!XN zWl2~b>v)!PQv$0221rYYb-`(eup$1NFI~rldDHVxpH9OhhQMGLw&<^b*%En$Mj<_# znvD`?xCcQpCn4sUBcv6BwxrD-E+U0-3{mI^OhzIoeCLj?#*tF60qLND%lwKj(QuFM zzl1!S*AnvQocmy1cGpFzd5QAVQ;R zv@9>^6_%a@2%pq#)PXC)qR~zhAOa4yaqKDKEa(m(T>_5-H&QQXo4=u zSu!mEx3ndI4_olLYds*N8`qwSE;m5N5sg3&+l)6ylXF-^Xv-HVY{7S^Rix$A79E-x z^TL#aT_oh;iW1w7CiwKRfR6w&WWXzd6w(yHVxl?qWE1kPax-*^veiC5hg~MXK_%B? z*l;FCbSVc`;sef^!axCZ!?}_x87P?FYex3 z2eHyuGAAq^-7-!D=U!WVOCA_7Z5M}ex1s!ii+3atElKqQ&wHlQkd-jPZH*vZgtqZE z#y)5>X$V^p&WHLSN@RY)HmtiB0vG7+X~{m)rr~MwjzaSAs|e)oGiqd;x&m! z+=OcdQw2&e*ITQ1c$Ac6e;FNMtpGY-x5)DW0V!!3K=2}3Z-G5YrW+neF|tM@GPy-} zc|ZhEvz0ZEJ8F{FNYR>C;!zK&gG3HXPqq|Hk&2XsFq4OmQ<)WrT)!ZzlC1Q`Y(Y!O z3-i~Q+|&y%-@Chh`|f(1^m}`C4YeBOm@!Z{aRKzp_0|cMql4)B^8TZR;<12=8#o^; zRfYSm+)Y39>;3Crthz@YKOs^i@Kb^;#vmBOGFH{lQAX_LEqk=vVuW>K(UO<`BAG<# z*~Gf3*S_97syIfn(k!(lM~5)0b@12617xullGN+2K;R<7A(N8EKJN>*D6Yfj0bWkB z#mVU&`4`0?x8;P?qrAwJH)$a`2X;-y%UT<9HBkrgRGlu z14S4t=RY6?8!5zV5ybTCsAuaYVFfdixF2cG00b^~0I48eizGyrg=1(H2%Ote`k<7s ze*_u==?F6l9g^3YaUI$XC2sCENF1B6Uf|l{YL1XG6LZg<7fZi;LVLg^AP|K`*RYjs1c>6LQ?r){z14cJ0_Vz6$$y^t_M!w>9>Se%0?W@ zg;7c>*?jta>ZNax=;Aa25N!-_r5km&dW)K!t9if+0}dt3G2%D04YV23G;wf1F-eBtDdqVCi;a#iVL(9%2X1yXPZF0B4izZSa$`WUK^%A; z3J|LMTyGwx1Jpc*F9vK} z8EwhRH+$0lu-Ig3>X765;#d(|JZ>H$^`8~`=Edmh;_+0NyF#PvQ9 zTt*5tMl6G3gNZbQz<-KNiGw<`6iqQ;>?UCZb%pj#5GGA%c-#MRyETAt^*m_ zgB#@sFP9(8D;9jJ!2j35QK&YW5M@#m4ZZkkT9TSRg{NpX`03)C0TYUmX@uo7J3Lr; zE_^n>xnEP7y~55shBo=s(%oAMM6SsN)Pb>K;5*Eog*!yhgy%O^ zSvaXx$W6%$+B!8hu&RBt9#m|rH(q@OwpAM3DKMw4gqpD2bdoElm{e6TEFF)Z;6NDY z+Tp$$?xfXWE8)4Z!cj47n|K7?!G!4IgRbb4X31kAV0f|2srqVqiU5_~5fx@UG)?{- zo`!OuIq6B>YY~o=0fvP_{PGo$$bRH51)ofVzVd_#1JN11+#*-)P=w!Z0Gz8OR3NC3wRb(gBN$x^jrw ztI>%9+8U4(kgjg&S0PyBIqIYs6S?GjpVpp;b8q&+`~pgdoB#5&bWr)IRaPMqCp1+ZX(NNhl4M?&#^%9D|6t_bA zk?aM)0M60C3p6Ul3P4SPWHOosF$qjh=RKA8a7Z}ZKx5}6-k*3UP9ri z99b`JQOU^)C+TT)=nEtD+k)yMZG={R=i^_!{kI@7a6T3xOX-pBqV`LdqQwB^k+hii znzp8Xgw~cF4cmUld66!piPSbAPpxoln)*bWFo48l_r%vQ0&U1JlaX?^K5Dj{(1gwY zk@it5qQ+hTLx3krA83M*adQ$TqUAS^xHv>#;G2@1W{X4?O$v*wD{>-VSrHRNFkfRd zU|k5ZePOhqu4WAnY3A!1l{B3i`|dTo8w3@mrI33KXAVfLh$yL-UTki>^r9+n!V?65 zraicH2|?*p5F68-(PqD&SO(c35yO*tHIg*+QiwTYQ{NV4iz+=1Yx|qUEF?|oIRZn} z8JBaA{ZTB$PGX$0zc=!eiH&73Sz!v92Q8UgEVAsC95;?;^BI^yjwqPiptc3Cc<5L> zO4+2G3FCGmQz{0;XcgEapXI!iPiCNDKtzMMC0k8F%^F#C1r@MapUAm}y%F!`Rk zsMsxNEXIR3+;Kv--p_W*Zqgp2!-sv$5HF$H;L%Gsq`gDY1iy(wq~#BY!PF)(2-0>n z{(y}lToiwztx-4`01{CW+e|W)oCJ~=4`c|`)Dkt0vxyN)z5`jlXpD{?@B-w0HhE*< zH8?Lugt|Z^*&%Zy4i|{@s3lpjaTtQJ+w96>KcP!PE^N)@ zAjJEH38OsM4m?*bugj*5e2m@2@pN(VC_HP>W`ZJ#TCkZ;!}^{HOV+3Nkf6lgln@iB zf~a7R02tOu7N#Icj2Y1N(nM0tu!}pm_^|u|@yM9_Bixs_A#+5kc2rk!Rc^r6s6!Sy zN%l&ORF4ysj9w=O-R9%hbC?J*^eSj`JWyjl;P)!v<4{2MZls?U)0((Gk?qD(x+^0r z)>SjY55CPz=%R0nW`VOv>S4xLNjrk&pcaNvfeX1UUgUQeW)r#vGNr(S>!k=^DqMF$ zBLpERZ(8A6T+VzO;it5YF41CEU349P2MaPNB-3yz%N4Hllyp#ze??)=8VvAcTV5F! zj5e!fV5D8Mc`V9A$Km&~j>Cq5t&H2qRI#4Pb27CC7annf2wbEJHqy18>>9^~;+1O? zPWt4Y$IMkv%_(_`wKhyf7w@=g!uhJcT+h&s8%T4X@3d>T{k;G&gY68iNTq!I}S z2-+FSh-bSkdvct;sAZ>12OSX-3SsOpfhqaMuT8rStw5MB@u?vC(W>0{t{u86roxnK_C06gV~-bK(6wV zTO=~Y+ps&{(#>*};y|PH9^HhwJo}DB7Gzr+Y-qqjsdb6+KW3B5Rw;*hmJi9e%-0AI zsjGe!8p3j@0}S@|)I;DZ*S$`lIA#LEWpZWgmuDxPjVzmpg+1ZVWhU&%Vuod7Br;%9 z6dz0z4IP&f6@uG(LW2^9k~9@5;0!_}tevBF)~n?}j*CVB(>rwYlH87}^&``nDVDl4 zDI4Dv$>M+)@(Jt0S`e}R|7Y*rgCo7N`!Eh?IOJftPcE0s<*v4g;cPdCKo5Z76HAZ_ zVn7ar`DR9gnO!m%Zl?h>FwFtFvE7XsU{{P?mKE9Z#_?m7$ZSRZ>Y@PMoS#QdY&O%I|m1xv%g08jm5lD>>?24!XbZ-gD1A_uO;O zJ@=e*g9!r@Ni?A0BkyRCbWjISaEVwV%E?e#%XF=hYJMV>_Bqla4yD`=K`r-ee=J2& zbUahl!azGtbLtpqQ=&rVwQ7%nt6pT}ye^$5T;SaN8#Dem84++jR(D;83`|L<>`kf{ z22N(zgl3=!mbqdN17eN}U}ho^$Q!Oc@LxatrmCpVClYT@RtoV!4OEu1-Q zz(y|qpfWz)T?B7UsAh$YJ-*BFJM)6EuB1rR=}&JQDWR9XYAk0HXR}?TR;0g$c@x7} zuc-3Yo+j1^xnPTk+kEfsVRWPP$JN>!GxhW1W9L^Yw+HW?udRHWf1e+dpU(#?y&E?E z#epx-o2{*k-mbp)#u)1G%lWa}x2Iu<0`NuK|0#iW+s*iPo(15{3ACe+mP$EM?VUrF z^MbF`%=`Xj)eX;z2?TxQ9m4GHw7NXFpHp?XUv9%&2Pu{bUeAL@X$a$Lf&H@Di5X^3 z&uYSOHyT0urYWt$O5fPt?3J0i&6dH}l*L6o*qH>SL_uAMEZ@Sxy06B##MQjmP$rl3 zOltOU(^IP@_reE35gmb&kLh&KT92fK7;RJ))~|Xn9jRlsN3mXTW6X;>p`EX#?8;j$WXug|i9*DE*AeF)O!S z+&Jrvdzklz7>tFmR>OfR!MhYt*|w=@GG*26F6cW9_j+#+X5nUU?T+jjF&L@PCjiiG zJ7?bHV}2A1e^a%JHRMR>)?sJe-GOUVX-@!A1fl4+5Me9T(dzhUbu_nA(Khto+|61d z@hfxSANW{NmeQ%ktl#USLpGc-Jo$bL?ES5#7+sU&$hcsUYp}r?$~CTLynx|*Z@(cE zR+vqcNI6NTFokVZ$QGH@$}3P#=#foQEzAW|{=7qy$&ZrlkTj^U!T_P8JK}&eWYf_k zVA*F&o=zCz%IzaBwXB=!yX z5GDx=l>BMd97qR~i=AUd__I#DUjf&|_>{1%ZgkiHqwRQ=MLH&tIsjnR?@fL%^S!B% zj6H5_%yVGE6*A~J2S9aWTO2hZT%ot#2t8~txq6IWMs1l^9k&S6lGC(}y zrQ6MTw8!OqBy^GhinHkfz>4W9!1ct7v-og6G8|Hm;>-ulehLq{0$K?iWHZ{qUItHksjUcJAPE%F>izroTghXbb{@vHzKEK!D9)Vv%OJ1l&3^L4sp ze57O*h`D3=i}Z#tb&WxF4m{( zQ)6C-HTHKgBZ#93!C(=36ujI;1RFPdt>;S0W!$Lv3T|u<;V?N+e{df2D3~^N1Wr2( zT~oLZfq@lnZ#Fi8Eh@UoLJVhE3!b@7I8d3u9QjHSx3X!}7yRWrHYDJ5_K#!Z1UU+4+AmmwIPY%4I ze4xdFg9ecS#B8$p?Y^&1jKe|3gMjEH*nc6O-PJ{hj|Ehl8fgKAA^FV z7kzE2h=+yLkgyX!Kq~MA0Nq3&z~Ev8XP0{A@^-y)OYe%r1gcy&t579tc96E5mZ2OF zz@`BV+j(05Scg*2f_>|idEB4FyGg-k?LOu5CiY=L>?tA|(F(t$Rk`j5P+*xMC<}n0 zagMnH%yl2J?7O`_L`4pjb)4Sck(8^jkgemEi5(!JMAKS8PdEK*% zN@6$#E@j^&i18z_F6lxr7gmTM)ajuQ)6tR4Ok|m%<|VV+l$#vl4(kl}-Hv3%pnJE~ zLD~%`qcN#T7_+@e2(?}PM)I&2N?@amu(`Xf@7!xhtRAlXM3`2Mlb+&PV(Oq~>q`$h z-q)}V0FpssUIPC1yGw3a6{RpZ#zZLxu~q}tcR;Ety({V^$`{GpKy?6hmuHB)lC}kc z@_5b!LAYsaBmkr;6N8FC=5O~Q@L@Z}VnYt^&^^MTzT{|fJX3_$_6l`aIZ4{J4&|n4 zw(>n1e&kr9Op?bFa*n~}6QZiS)5H$R)9|bs`f!gk7BdJ&EectLdln#>EuV*JFVLx| z>dIriUmo!&Nz5NhI1R!@hOc4GL6{3-_ZjrJ2dAaM0Kwfj(t&bfEx`nhu*IziEs`=Q zMS9v0mFEpJh)(JEA?YE-2dz!bayxJ1Tgf6Q|lT$mSjt z5@*w>Ie{aVf!dMI3$a211D0FSGpA~5v6t@p67nlo0?MGhm$_NR@8}|A@^^Dbi@8e3ztdfBC>=!pa=F$sEyv>Hl@_C`cuum3{BLvyLLtv#Y#RG0 zN^Ej8SPN=%7urF$6Y(KS>5NIR(?>w{RQUn%2P8)7>~u}@ygOAfEG@Y z!E)4SP+9NSJRJgCK;&KKWMl zNUqtS!Qbj&TeFZ9ImVcR^PU!*&F_EYbD2 z{|@Vypey;9a7rxlsWwWS;tUa{z#`b3+>N)UfwHbKu$maCy+W1Y$v*N>(`3R8k>&;x zY1(}wOt4k)kgQZWt9T*WEP99VLYZFnT{>ys;nic`s)c}F?yl5cD@Di}cFtv!)u-LGx0+_5f=+h7WWw&4TEp+Na0C7AnqAXlZWwiu4LZ8#T9A z*O}=+O`qCxuHd_{2S{i;RtV@~;2dn6$y)<3<`&lPpb?^n9yrCACJdl(JeH&OMddDSG9u*E>C&z zFt$x#Xu!aHft@tn!$3f4;yDYhb6zQMM@NwTHr6CDIl{qNoXI)4&iS zF{0@oQG?PS$mV?ozMhR@bxBuV=J0ImZX?&wQyy401Wzm0n@fcyUOaHhb z&K)_dw^n!I_KAgNHcsm++=2|a?j_hZ{0P9vO~T3HrI}*{WV8mB0Mz9zASNaqO;6b1 zsS0lMQIUx;qK`=g&3KhfyM$Nl`n=C!UvHE^^J7dIVL;^`rBp$3Z{lrDWQfESj#k2@ z1TW$jn2U&~42E@_f}Taf0w5Trx@i@OGX#z#Nr^K(0)oS_uydrE%3PmGU!|0sV+uO_ znY;(UDAZI}sA8-sabzMPY#bz;s6Y)TZgRFrGZjn?I4|R+5I7>Ur^Q?|gvQS(gAI`T zj>T8s$KJ4B!9gCbOCyn>QPZuMi35O7y|}cif^ZWBRG|lcL81}7QQOfg_WJ?1_*9tr zoKdXm>I}1fCM0A9eyR!7l(Dn~%GkXbTx>7wP0$g6hcFXZLNp$KJ!kAeC&ZD;VN})& zoiVwJu0?LFNzXC>H@Wz3;HFz?8z#_d-j|9{aOy;2*~E0KSlKMIHqv1r2=pQc1-n6F zb+ur}VR3#OzQ-B@tr`u5kp}r>aNBx{LZrsIYDF#7z4>t16zL4Z-r619%7o*uXqyR{ z*D(3PKc34#K8FCuU)G>nBom3H^L7Oc4v|kW&CXxm~qr7{tq5Dw)J zm`|5cI6seE!@~x!DwVWhHWnJ<0VVg!$Uw^*TIm7+M10&o0NMdwDnwZYUFVvD<3I`aHf+VNS)FVYG8eZc+ zw8~6|qW7o1y0{7=@UxY6H==)-9LvJMcSUq!Rv2JhH0*nU1D|V`uGQYZv%fV!n8{3K z*%_@Maj~W{D5c-tWa=RYt1MK5k@%xTnDGKw@B_>PPl0$=BtwV#=*n#*P=J z>QjODc&a=(JQfse*5NGg0+>n>2?jl6WVVPXZmiG~n808_ z0gK==9h|k1^F>J!#w8|wIQX;%VO0i4-D$(;K=^7EnOm80nW~5sR!5-w%{FX%Zen$K ze&@tN)Scz7UGKFEpE%YIl;ar`{LZ%Im?h+it1&x4;18cJH1y9#c4c(lkHV-VhZR^s z848T}J&}7j9N5CS8ku;8Exi@~G2!tOf z$wkbZ`V~j;49x zyt43s7~MhMOId)ViFi{Z>y1B3(O;_k8yUkyaa{|4Ra3>?%c8(YhV@u2EowVCRm+YF zuPuw>&b-8}9!`Z2$*6gJH2q|O>Z*KA+a`@a@8H512l9E zP`DL~<>{ha;|vW%d;`7VN)B9clHL@(-z4RX&h@JCKp-OSoK7~WW)5a{UniOz3qnY5 zwKm{nh>QN}^yh+aKypjLcC)8hqEw`jPf^E&j9fD!4v&rsPCtA2Vl=`~${p$vf$ zA^P%!;j>ceXmJplihH0^4?d;NDVuEOj!>f!Fi(UnSQQ~eLZczi9ztMhmX`L)nG+yp=ax@3Tz_Pl?or$TZmhUV}@Ggvl|ADyz1Xuw06%Zkg? zv`JS8P}c|^xzxd9)FX^_6%K9ib%UQMmLP1mKmm@cq*lkd51?;!k%v19aXDLYeF%fm z6GA|HVzOEw<$LXPNpG1WZJep6#QX!LQR;f%NQwQS1}*bE(kTtHDA!IirF!I)yp(6P zw!#)A%7hEJp#+P1WGopOA*YpHKv-oH%VCk@CPI)8$-9=1&{Z<@Ar>y2`*0t-HxM6N z9+)FpitM(yaONFv39zhFLrrL@C=!a|1X&scee9bbQi8WK2^uV#JP1?Fjix4p4Cb+D zI0^MALmJUr#x#g2Lg2@dD(OdoW@SBy)+q8w9F$T<&xA?Xa-#uh*J!xgCY3*o1GrTV zd@lScUkip8CLsLNFuBTvKjGF-n{OQDrY6gYo^n^L^ z7u#dQ`aI&cT+5bt3rx?BFmI;T2uOQsdJMFLqLAm7Si(q6S3oO)WLClfQO>xfmts4a zfdikGeK*v}6!CS~p{G&b#O$aW*(Cj9P6cuIYV!n0OqED-EO$q<5}1{3$(A*8D|KFH z*f(F7-7K9=Y3f9}*;%!Bs5_!u8HODN)6mK}F?G}RUAcCbDe>LLTN;Sc(NODeZNc%V zQ;B>%WY1*RKtcQb1;j0qbH z#x9w+s69d}h(eP3l$O|YLKT#jr7V0gTs{p2q2;j(-fOuu8mNM%1;loH9iA(wd9?+1 zK)9L-B-%)OuC&HfV3_b8NhZJ#cYUsFQV+qM@lJ@spid6m1F<1?89wZm zDaSvUs2H&o9Y_)rzp7Q8l-dFwXhi(1W`7in$!2ixC!0n21c9E`N%=*463hcHE{E#r9Czr|4zjT$buc#)lmXRx&Y-OGQ!?eZl`Ks81lkTYzpXP}j=nLGg5`)XY(=i|m3}C|kuWw4|PHn@L>`#_B$s zYqa)i@c{8ErsoU8c~I>XDq+I?9bnSwYo-rZxY>pkBkwHDR?51BE754eOc7789uJM# zAQs@LT$ik;bkb}0Bq0(lmvY}6m%^U+Ok{fjj*S7=@ zFZFW64M=bohISNQ3_CQ~07sCFSbaD%&|Er6h2dBT1u!$Gd3YsccNGIM3S7fjPOf?g zhUM3qhZX9`Shv4R=u#R58-4svm;!Em?G25CjQU)sFlr89PeX(XTVma98n+}z^yc=! zE*E4Q?z3$=rzcQ-6RLM#vY*#{m-1(M2CMW>1xgO41YGU#6OpU|l-YRdh zaJF5CaG+?3Np>&iQk&cRz{VD;=iUhwWKDC6ju3W1;Mj%vQG;m5DwQSaCQ^ ztQr(GTAI!gY-r`1MC7F(t~{7DLmAi|{eT=>#zjn=PK5$N2RmvNp8;8wvz%{`V;WN9 z(3yh{u z4VKNPf|e3IV8^?unNYbv)D0irg>4WIVjAFJmjO&hTbWEJhoU2jOWn?!0wG9wTZg3^ zM6kM8l~KPGhMmQ@|0PMeeh8h@!C?_Tc0Me&n2CX>#usU$EDoyhg--y;tp}0OjYe^S zLly5IQ>!+ywU|alHM+F9a6L8`l87NtRnRp;M>6!-a*x&_< zgC6N3`UpZ;#mdE!?i19J=&E+UJW#u#dgo4z$`T_=LLeii^5~ep%ipvxP?6g}bjA8ZXsl1)ntug0%j4n!+cv4R#4(ipJXtM#| zeZ-R?oVnKDM{Muj8m{Z&Ntf(;1ShWc@ubu}LoB_^rly;g0bL^oFuadE739<-!YCeX zupjyfE+&>$+nFQgk&B{*<Cg)C(dP;)A*^Lb)E*bLN9j6!H z^t<4CS$1>jTj0L{8|ZB1rQCDgbjpF`GBNd1I5dD4!%aQ3H#>Ulsx3%3h`29~WG6?U zQr6tVl0bwG~7_Z}cIIq<{&`R=7c=Ye{l_{y=R z5G7hgY~JR26pd$8i-jUK;HBui++EH?Wwq@h=@;47_mpa5L|^|LBPA_5E`JTh(vjlg zEhi!vO+AO;JhBmY*XTsZIC=u|J!A{aL33~8ZoXIQKH*BzO(-etad##7*OxNHaJJ&h zB^^XkTik42?1(JwupUB3^A#muc*n>}b5CN_KnJm^$*fedB3EWeV}440grtOu6L%zq z>`39sAlwxb!Ie0SSaG>k2v^OV?w-aNfTNB^N?F+$q1I5ICy0e& zHexF{m3DcS!~hYT+Oe7NHhin}_i%s`c6MWh&6L534%RELgPc@Muv zzrKpI+?QS$#jnxv(H#7!Fkq~xZaaE`8Q4}0#Q7RvjPmdT#u$XDRD$TUP76bz`gtIO zY#iaJ3Ypt|Exf0euFguMv!kkm`~ImJDAs7h)N?NS>>-z+-j?mQMrTIHqoY{gaqLyJ zDF3*!<5Jc)i0t%C^`XS^LFiIX22rn^hl7|L`#`Pex?Qg9Tsr#*xQV0b9daEh-xzco z630{H^FT4k36CY>i`V;92y1?fqM1OV8cfB}uA3}_%Ca6Tr=sHkY$RW{%q}d0)~P7@ z*MXVx5JrPZ^6MN@s2;PomM7+x=NA_(rj%8VqNSJYF`&W}tftrq_^~1An#XcnM61v- z7RW_Kzum3BxsRlSi`SIuk=hTQfh-?6Tbaj=oiMKAFxh)JbA7~nI>Kpq`N&8%_YRcT z`MLSa3n1qdLSgj-XS`l}n>N`N>R|VxHhE@1p*h$6W(91;&00T=$0I=pqF9X!)?B%W zqi}G2ZF#~Z(;CGrk~T8UoRWfQKF-cbKbj%MBly(b1(@qImUl-yl;)ZW68TB`E$@0kV%qRI%aO-7C^_yCyZS)=5mQ8jAom(+FMWp?GMDe| z1NBE{f4~+z2S!mok?n-rD}lr`Hai0y#%3Pp#qjKe^E94w2+ZHW5>e4hLP}s;L`Mh7 zAt=cmC#mVUk3~V&J!#`(Cj0%V-7qs1_cbaKj?utbbVI+CqXkbe1aG<%vQad%d%W*dS z>Gy#jrl8F53!1Z~(XaxIhVmN)LkC+n}%er6g$LC)D2rmm4^$y!dIdR8GaCms=TjP!7@-VW^s+x!k%!{Sh+|zvV5I_g$ zE43TR2}B%Z%;zB-oMf~1UVUPK%vfz!Yh2AC>$(GK$t z>-V$p;?ndEon0h`_v0!xI1QYbNi6j60zp>eHKdQmnhTMPG^04Ro}n(V-`%A@Jrqzx zrBL#CAi?~DM8a|b>SAVV5=h3+kGcdJyK5Tp8m(`iIH zi+>s>8L!HXt4c;|wCMu|aQp0CSxKOWbT&DQTzC4C;kvRIRi`OQvapIhh~6)okUZ#` zZiiu+YeRl=%`?>{s*5aRxL$~3z>oAHlHKmBFEEU-q$*;ux!^%m;+z|S!k~RrFH#-g zkR}7bZgBvx2Gw0l(9^b8TfMJGHL>lc)+r+=QdauMI0q=D>eqv&bp4jqC2acDfEJH~ z+RJDz!vMY6MA|}WNd+G^j|~mhk0hMXL;@zje!j3i;Jaec7Q!&dt5IQnlq+sg4!lnt znl|Jc%s+j2RKRd%kr|9RP=`-hhfGt`vEsQI+~g6*MhoCR7D23_=mEAX>zJ9i>sP|# zu{6n`KzG-bFQyLGF;lpj9jq7_kiZL=E7J97(x$32S3%J>oRw>6Ng`Z0iE+KKMs&W* zVL_PXu8f(gEeI$@!zwI5V37|kqsK6eWw zw3|7(G*KrVIUO4-5h<1|l;I3uVQeoqU>k?IDvI2ZTibW(qOH|q(b|Wr=K2L}kZ|48 znDfkJj|F94#XANHVs6P_*h72B+!z}6JrYL%!oay4vg=_9);(oD-T_VC!hH1F9E6=z zB{PfxE;N3aq@nQmr&teqRn=gKCqLE#g#B)ZcKVv%JldP+tT2>SP19q?d5qj#7iMO^ z_Qt<(_W5U@8~=Ls8#P=J_ufxNUTcMc7H!J`b=>QRI%NZPN_Qb)-p6 z&XL7*oD={b`V>W00v8$zZYde;q3V(Q?ns+Q%!0N63f&{&)XWYNiwBqMB%ju#G{2=a z&<2WGAh#m~q~kIcc`&+c{_s~85zImkO5=Q_ON1RI+vmsiFHtIV^IEA&efsQJ-#qn{ zEvVg#y@nn1@2oQaKuM5@wpw+9ic%xexNOi|^pnm-)`=Dw;)imAVmc~(V+LV{XQh~qIiXMH_eIbgN*TLtYpNT}{G=O!0*O+W6n&uv_X_P!;qaQV{fkSH{SptnBmVGJK zJ2?Esb)3iqi2wm0Ldh?)vIw)LTWS28R5-*E%@^Tf6BZiJv`kPOve^&;-#xVNdgeCs zf`NE`5&->nE3GOldU??2U1X_4VaaA!`ADl26>5r}!VUN3} zTqCe;_4dW~d8}%($O*DT8tcQ~1NL*Vg|M8S=)h-M+8T=!Mmqdz8`$_cCdXN*b5D2^YZGoVq5KASVe`M`RH1AS(#oFsV>7*{0q;b<;qgtgF8SUJi8 zhxavyG!i7h(}OJ*`9qW4OqIjZd^jT0NSWGdl+B3fxDU|c&`I%fNGw@Aa(DHG?C{^C z&w&6b;>n`m%=&%Ylh8V-kn3~>@QMRWFh?LFiyecI@Y|x%s@Qd6>VT6nL|YADjokz{NVM6xc7=Cz!(xDMa@LzB{~UPX1eqU`WJ7C(vt%TL4#R>yT8}C(7#@}+v(o#W5ao$#u>igVG(@l zL>tiXK!GFHL8&MQd+jwzW@^ef2xtUjp9nv7gvBx= z>K|X^0wJ`9k0Ede&PCe^=F}FS0v7*xVidR7e2v)`>@vXI7iW8C?YsfDYdfsP)dylI zqRin9ijwEsCvyfXV~luA8s)DcpqSc6>M0`>@8eoL)?CBkujYkw?1bko2VHlScqCY( z7o6`RP<&_!pKyAM2`U{Pln1RKWdf~;b2K=3o!E`|8iQ&Ld5?WY`EnNK0=ii`8k7R0 z;=sf;(r$3bAT{&$GFAXWu9YIEu|U)z0`*)HIL0`j7>gDhqbwMqr%)fv`YP(t_ z8WC+(J5}0@vdZc{r!Ch9;pN=qBS!ofo4ZnB;)51cO!$7rR#R`;;0OiNMn0U%a}q$r zT$^?|euM71$rwLQJEw1$?;XX>5h~o;9oKW$HH`WDyQ^|tRmQh=ebFwk)QlqqlegFwR9X_vlUoWNt)I5uC z%1r^vzJa(gQ4fGR7bmzEc$Lu@Agjip9RChM@-nzspty2@&(BtPAT{sxl^IbwX~Kkv zR4*1w15gR!4iP>3ypt*{o_2hB2VP%t4+EjekuH{Tvw1Qks(G*5mc$D;S~$4st+mYQ zBH-l-98gob3VzWF%_Ut6yGSW#I|_$h5j@!D$ugJ>r}X!GU4Dh@ zgs6LR1j?{?Bu8YnKhNkC*t*4VR{7ef$YRVdy>vwE%`*^>ypquafZ4{w0Kc!T;g%5d zGq5YCU&1A@(|dcPU~HVb!-Ig=nc&=ARe$iVCI+kq3z|>43O$0EGS-+xj5hdvER1U{ zI1gf5f+JZt77maFP_JNYqSOwK;=_Cat4&W%RuEv|$XYkVUxPbXE{x1}GvI4#NmvrO zj>{OyYAD~B0}!1dS>OXL=TX6jg#;{q91v^yAPzGOz?&O&;Wi<7adQXUB9w4^>FMv9 z&ovsAhKxe;!svnYNW5Nk7`gKb+ZW;zZLUfz;kUrU!c&e-lEaO-OXAgz7=L&py8Rq` ziH$hZLe>c+h@+@c<1Zo>Q6<8R2e=>=xl6uCmuwCWJ+V2M^w zLUFT!D=!at=-k+b(FS4>{pCfZdf2()91p>fel)mATaR#VT)K3LekO2{Ho ziJd@zx*`YVRO3ALr|)0P)`2IHj9mQ8j?xnWm9n(2eni%ely2;*FKOGxM&bkuuU~L5 zoo2Z);|gQe4=M@Cd1AtGkWmEzsn95*%pSMz?t`U6vS`h^?m$6U@=`(ZX}# zU8ng2w#kaP3pKhH-1Q|zBo*|6+1c# z^&;e;p-hMB0dqs?`4^U#cJ?DJqiC8>%4JFdN*^Yd)Pb26IHqw5DbrzmlV#Zn5}D^y zM{&!PrjF9Xt0Sk5I(FJ9o9bfHNpM1^WWMU@WAX}h_zD+;TPDBU+~Uj))kP>+@+MYG zK$$>{w0Fui%^XIqp+97rWXS-B;V0@i&So%_aWlW?Oc_AgXReA7;F4OJ08W-O9y`_) z8UDs)%nUcDs-{2l_d1167drY8(o8aG>Ht_O#d==4aRiDIE?NzMDH5>nb3+Ka$u9E( zmk5HLsUs+WCq6iDK`|UQ(aKA<9EI|UM}hXzP9denv4=1>;WcHTE?c&ka5=*HkM@AX zhuu!b(XZ6-i$7>3}`HL~dX<{bokkSj*GlpTlXk1|42zyz(B6tv&~FkzgzjBiXZ>6-^i z|3xVLs8i&*Bc)1)k=xwIGw zeYEUCflG}@L`Bvk^EPDCEkCL(Bc=rZaxr}=r`nh+92S`~#a{5Svya<^l2j7EUowf+ zXmx=G#Z+SSVk?dc4CsgC7CTU}9mU`|gK47SlKMf*&1EG6CmkcVSWtPXT}Z`bkO9rQ zNXr{}f=h&RqL3_VN6#%5YtwAbASVrmetopL#S&ur7Hu;GLW`z@v@$$qDr6PQYe*<> zCZmv4?AX5Yv}FXHX{gEd7A#ScKV+1i@agXJK@A0Rlw`Uc^d!W{xC1rLTX}md^$CHf zk|^bfc~YpK?glB$=5k3JjQI_LEN|7Mg`>pLZ3bRffITJhUwd&W?Mx=yy z%B#*+-HOIKD||ciUfLUXORvF|GSA1UF(WJm$PA$bpZcOfJAxQxHO27;nuub#@xZwc zS1;jYjXSLBImWiq;IY9kwd%R%IMPN}&aGC?y<0hVdFEU;b8flvc6PIRESslh^g@no z0+lA@8**5MWjDqLCpvP5%MJ@(5SIKNN@GAnKQVsleUY;SsA483COqEg;H(E{j2G6C z1w?I-ci%{uK^Vt-a!9dONNMA|Ae`q$aOGfTlFr0b#0texG1zV^z@MQvWql8e1rJ@Q zLrR_UN>S4htU@E?^xGXviHCv#*in|9q{0SZA*anUqU<}HNNSV3JiDQWvMvhAdPydR z_ZNJ=aJD77kv}l?BY@Q~pB&R4v5OHJdv15P1UwV>Aw0R&hfkgVW_C+C*oe>K#KK^w z8+yBeE_ZaOU^u+Ks?@Lw-f8aiqZ}S`=71EK?SVy{GIOqyGUBG=`Oor4?P}8 zaB*N2-)GU8=sBVp$3U*g*F|13ivc%W!BJfvBXOI1Gc_4(5hce;EN(XZ1CPmqSSmjk z;^{mRt*HNr%3x5=yE7*XbIDLbS2P~WABDRE#mJ-*bpr`lVkP0AE(}#67I^$5sa((j zpUg$WsJgnLN`syw$|sKJg*6RgC>;*5=)q z*keUr|8hk)?+4Qu1Wmr=kJgO}TNq5=sGkBBfe^KKlinW4EQiwSMS=RbWgCuUJfOv# zWUec6&&B#hU0X;Qu!AE`U9%oK<+i2{(onwzed^)Bo`3SOnYwOxyp6KK5yvCR2J;`x zU}zabuJCb%N4;Dzssrarm65-;f0v=*ReR8?bYPDpbzqpp-54G}6NSQ6a^R5g2(^Yt zC|{hM`pDL>DK5gzE#!@f7Bc89+s%#~XQvBUjAnw+^l-uGq=E^TQsv^}rED4NbrVAk8W)b4>I&{##OsGteq zCTP^kGZME&KVGN>k&mZHK$o-58GrgnG=*F}68#d@X6RdfV5;};-=Cn~Zsl;FgPE>N z7u>Khh$f+bp^j6=V9mUhp_s)-vLdHuYp-pftDIqYz0I?H4Dk9(rg(vxfIaYPStiFky zlshnYdU6AAUDOf>9+(x7yy^EuKa8+40Uj73x7YIScfS8In;8!W;+Q8+RT^(Fr%tR+ zRU1O42IoUCmK{ZWB{^WkO-E&mj8$lUsDL`K{z2>43zH8b+>a@WMCz+~IT96AOFjmH zB<=h@6iFp`|AA0)lkpFPlB0w_@C#BQ6-vTKzi&m83Rdlds0cx##wwG@#d0&3I?+HZ zODrrcLrmVrrxd9X)!g1+_G;;^hOV|>6a*o{qD6~8V2fPQ&0d(K08iUIoFsUX=Db;k zrH=E3th{S8!PplHc=O=JKZbRghcDl#(jhM7h4Am=vMV@p@f}j14)2&F{lX&B;B$)` z583NXXBe-vBQ#XK5icT%=MWd8G4Jx9I1t77FnIP{{~H!NtN9TX8%d6copQRm1jdiQ zxeVU)Yl7;7s}7|s_?atLqA)>w3~ zANeAhS8TXusSCBAhH}xAo;}Y_MkkHx0jnmH=POXOpl7jr&NveHjb(9GAS+@x%1%ub zm>W@3={sr*J_mRJAot|?c37yWPVgyI1-cF7nonz&seO?1+dHY|#~vDKf(!uatR9p- zyUikpDTG9Fe`Nq*2*x-Bn|cWrg<*=u1%^&bs;V)?Bz&{-_N_&Dx7=$ZW}i1HJd0AE zaON5gUZB?N9~VxtrH^pw=I=#|6BQUyba@a@r?65AvgT*>&VV5dQ9G|*wIdHyL?m@9r1^$ik z8|)&QvsTvCMr$wkoV3PeigLZJa*XF02cX%O!9^;npohvE_&GL zW2bAj<+zXjVX=?&FoKlc*XYSghUtRzvH9G_j(B@g#44f zuwW$qNna3Ga0LIPFX$%9l#_6})o#)A z8{KnL5Fb*BK6}w3pi4(O?WLTgM~DiNlrs0ix-OttI9j~RXOci%-R(2vDAx(F5gyv? z!gP+Blv;RGw*(Dh6seQslBNjOI$;7SW~2+No3G3pdMq|c8A;ygn1NKH{ZR!P?@WK9djS3;z_U+iYl3uqlQaZp>!CGa&95@nKKKm)$m`S zgsB`hZb2%Bj*?-7UOA5Q&xgY1aHA)QnGsZApptkE$tg6un>NO~A@`$%ohZy)Fs$Zh z6dNz}ln;%ZHx_Q*sE|yBT2cszQFoSbAYka(q2tD_Kqpp9X(j7egWfE}4+#>!Yi|;X>t@`4Nlev>x7UoC2j&T0GAbCjQm{g5lF;MvsmV`74O8>>Z zjdfrS7pskKE!7=>9LIp;lw!^s(%|)BOw8Lnp~817a%*V_7bJX7I>%j(lLL#fn2srL z@uC+c^4UuKAKY~7m2V;w(FVqwS#rbc)*hsw-J3`N{21?~sPe_mea<0|3VufOjs^HB zWtRhA@TCVzNkL{x`^6&sJP2!O&7+UF-Y%-cUl{FDA5Pao(g{$f*aw?7R~F&oQ#x(R z_p?#8aG1_k$x_FhVS=QsEmOgH4bla-LtuEZ1Ch0iS69>sAHE-VTO5*_B|gw@;sNe% zL{6a4OL^hf-^5E=0Oi+6gtcN1h%|6(cPp!KfMh1B-Sz-?pX_7zkMwWibEubAh$N%8 zCw*lR6Upd@%_zH~>0&kQho?!j+QiERF^yK?m?n`AuHsu(HdZCxg6Cb3m=r_+jxa}4 zLy$8rmmkjFH@B32m_x#5)Z|EJds^0P+=XFepNQAAQf&O9Ac**`r1Sj%Br!D{>PJVi zAQq$nu4#F$2y!Q5;2N~E1Mn`V+cHB#xRZ+Di_zj9Vz7B>4+285dt9%) zrZ8XEJ96|+L~iT=8+R&G%CBlXH}YL{)?tO1 z!V?(k77Q7<=v6M|^8J zh&L8qghu@JdNewbzAi?ZsA1VvJ69bS2W-QCD=@McO=hJ=nUzvPt93R2=E}rNGnzd{ z$1JBf7-3cj6W5f#^d3)%1cHzl7xI2{VPbl6>ZOUP$;rtn+`&D;QH1+9U9=It-(j>2 zRG9g<7r}77_72o?^oLqBou3=mZ(MulU4wH7eoT=9&fzBCUkHA` zwdzY)N*!r#KZ@ zm1@TvX0$7#a_|5i#0-=zfFi>gkn|EqWy-Ljcg4!r?zpF(chq>Oowb$A%8iI1lM!iX zZtO&q>2A)-#z{0We{b@>QS`#zx@`YcJ>Bq;un-mqW@xYNZZ(mT7rR4~0P}ZRYaCjP zt28gNL}VKu>0E)V>~wW{AhO|38#grQ{RJ}qXayHkL7}8f<*n*i&#~p!W&G0BWvuSJ z7^kIaFRSOP0v&8FXgCq;BvI6pg1fWpVtjjZLMJ6HqNnA8ZzUvnI-n13=e@g@`O+>O zPZlZHQA~4dZl&7k+KIj`QZOOQ{vq&;jizoC&*Cm+2{K6TF_b~rf)t19BiYa0vBGlKL%9ys>sU=9SF&Mu$u>=5mn%fD*QrG2~o^z(7Kd z5`=7czzLSjUTv~khp!K|JQioa1u;hvyWSlHi&0b+Ud*ljS`)Ve5LQs1SOn>37#jwX z^{Tb{^SA3`Z=CBt#~@plmEN-$Kfn&#Omm2~dTM1;(&OD?3S8?|cv@6mk=iOMMGKd! zk{fsl61oqAE=+k5V+($s@u(Z!q^7~pHryk{>)WBUTw8v}ar>GE5vT@$%e5u;02NqP zE*^wCDrP0%;IhjBMr^w;Qb{Mi6HD98wQhf}fqgHQ?hVbGsSMD->V)WL9|!AZ^bOU% zXjKFm^{7A@P=yF5BxQ&sX~trsaZRe+?5mP29dqX_T#{5^Wz9AAZ=;9NlKZ!p_jzm9 zJP>Pd?&=NNLM5m$8!g_Y6U1C}m4!({;bPwjO0t%&o{j#R@;s6c4~!bFuN+>k<=Z?> zL8O%N@AoQI$cnAqbtEo@EeluEA@6m!yX8E)_!h~gq4o9gW~I8(?bcVDJ=(3#^9zi5 z+x#&#{c?R0|C^E@;qT;ysh3P9eIPw_#1`#fqa(_cPX?twm6V4{3js&9y1g@vo3U!` zojIINMO^BF;`D`^>X?;MlRWH7NERZf(ls2ZK{_#*E;=E^lwvHqKBnE~g>>#aC|Uy6 zrj^O@iv9mR7<*m_&U`itv?MYhR$hCpGX26>9{6}WYfV@Zlz4H934O%Vo1z85NIT6KppQ=PFl&cLN4!vAA z(%lPyz$*Z|O&yf5sR{*a}r!Qa*}l-g7@KUiwJ*}scY?)7wv0cpnqLuq5xU#Xn0)Etbd zF$fo&l+4{_hGN0H6ddUE`AIUom_!A5~_BZpdq z7S@y-AJ%fh5&N*KH(?yMg0l=iZXM)zM<=&xqqnrW1uDctq`Gq8q0o5>X4yng2)OMP z6c!y?#u9oNX`3m5%gwr|L%4qw;uS%MVJ{w;kp!~ek2w86)JDJ4KZ>3cVG+~7Mj1R6 z4SCdj#8#LQRyt52B4bRfWYa~msNXpV9Hc@~kl1)6fO6bNSdn2g;2hg`3{H5NpfhGF znf0Z>-xz-pA+S&A?gA6PGq6dYGbi?1o7mUlw%CthR(z}7fwc6xtZRy#j{O`KXzReC z0~_UuDXfKdjtZ#;_?}H|)moHPueqHpM;r%KgLR%u?QVhd5nvu}D{LZK5*E7&**wr1 z*=aE=1GDs|M_18cQ!ElJKSc~BJx6P>>}Ja>wxqvq;&>vjA1bsKbE$EA_C=QYhc4#b#XK|>7U31!VZBKe0#D*&Z+?h1Zsk>UXNCg(hp+KuQfiCDZLr(4%I?1wPuE;@kTNq?; zD{p`m9eCUoWX^gp5V@MO*q-I|DAsWw9{6(a>#HKq4{T<1GJq#JK;xiouM}NEuu=57 zb@khbxxO%iKy139dwdSSolpYSNP&Th%!2{v%|f?|Bf;AIkVi0;Y5x&I(-Lk_3%D1B zzrx^P-Gbr^Mc=KD-WurO24Ugq@Gq!91oo8?R%TvQqdlG7XCj+fT!r5q(iW-)lp`nw zv{_>~>gDiU7?l$AFz5vsxww-DfP&LBja|VPKd{5_$P2CdJP>Ex^`>nr&&uD=O~j zE-_xY367QZBFAjFwijkZtOI@(qboSKbhrr%%LQyNa_12@prWjE1~$`cJqylJ@x8l4sRngSy#ujWp;@`T43F2l$q>sKB0=$! zTcD(1y8M3}tG>!?o(FzN<&dOw)E=TDSPze=CplnLkx8Gz9>y0CB`rwG;*zc@oxCR z)-BcW;~X|BFmWDZ<%2b}Fd?~0gU_88JCgPR{^~xls9EiF**8^%Mp=8G_SZG<(#EoZ z0O25dCnC6j=*D-}c^VTC<%6LpO6jAb$ifeR;#pX$WCW2r1~y?`yuv`nQW)oH>=2|f zj7n=_Q}x0RM}n`3Y4!E08D3#NPKTUHlRV6@E|%3Bj$AJl%@mz!RklT_3Jc zQa-Rv!k$jgar4V5s&SHHy@Ol(g#m}lf}R>sH^WJ8(lzOK{_#QmziJ_VJNl~&xDVh8p zfbEGX-3}3pr3tb?Eidg#SNPw9Ca{ZJLimT zWE_tNws56t6OB(U73SH>oAh{;468H*B`#Fn!%DCZT^rg@DHnIa$$*j`jr`niR8Bm^ z&ksKMLGAmGB1-||O@8qH;HwWkwDc#I{)eCW!S_GahO-!5*7>H@vv>bs>38t%6Q}^9 z(I>NIFaD=&^aS3F;0@zDJG(pjB75#cc7bmmw>y*@q^7;Qcp{tQyU*Ov`;~pRWP87G zBDDaMD|_2`;>c!tRB6-p_~2WiR_Q??dRNEP`IHf zFs=R{J(2wkOME^qk!$~tpU8feWj^c5K&@A^yaDSo=%4VnQNlPg{;Fv%hg7`-g%{uB14b8ZQ6nME1XzK|{Qz;yy)4zQ} z-#)&&+umAFCSvx+!&#Fxzwjmw5-%$?>ZA;~9GZc_-*`CNWU0@_rDCeIAI|Qwz~|xu zjm8#|oEwPkhqFFQd?G4g_^sJ1@njUc!1Z32&Y;L&Dak2RgYlE@yANkSC5`#CufDuN zy!UYS(=2hGB`&FG6u_>B0#+#KuDdlf|JcLXA7{;{hSanMe#VMD$6_~Z4msd%PBnTe zjtumleK`Af33{}wPJ|E=l3I$F(}%OCPU78@ zAkW^u!_LL~SsPzDnVn;yr;5L3q~wsx*N=HDXC9NasKI(+0U|p zuO0%y8vH3Mey*hW^%a){S zguK9x0(Li}^S^d7`%45caUcK?otY2vmH+a|>{nPh&nzUa@2k<}U$U~#&aL9ip}97I zjA^ft7(!vEx+s{ra0Hv;XGc+Ei-x<>KQg&6H8)@1D&50c)Q- zxb0MS{Labje`BSu9af23JufK#@yYD}Vy!O@t7Y{2wUgODVY#y$r~>UGQXm_y_2QvZ z*{M^g^7*nV2KJwx)H2VB%s3eC%Lexor?MvqS7lbdjsbqu3XQscU21P)Cv(7npF5R} z6YTTDYhaOq0;3}*o-Kw^{Zw{=RWA&$8d0dgEK{elc~+ksUOnQLb?Jyq2y1@fRCbN^ zpBrAEiq{&p^J`8k{fSfAKX*uPS%hTG!%hZ|GiV$UnlS< z$*hGs2KZO4&^h7OLMhcmRAoT2S3~3{4wW9Rw^nyIx3Fz;TbTd+RQ6vCttNgz^dAG|8yfm%`2Sa@vcJP>UoC5Gz3Vg> zr^NmCsqA-I{Fx!eW7YOl_Vq_l^of$9MwY*2MPyhUIi!0LoNqjm%@NKgBAQwK*B{B| z`AX_9I{-QTX7Q2i3JZxs=L@lweyrbIeI&ciVvn;KSIpXZ`;qJh-^o%mkI2S$3&U*+ zYOc9&J(8`ktmv}&veLIyu)p_6)?oQ(+3t|?iA--klC80V=!CfnhVM5Y$u?Nz8N2q_ zQD#?fL5{oKek8lgqMu5O8lXG&_S3TEZQN~r=bm`m8}n>GlI^mxy_Vk5rfIM5Ka%|- zUqAU4;u0MW5~COm?_Yi-`>TaQ6i(tMYmk2Zk?c2E=$RN2foMLN27y}9-+CnbJ1qK% zsHpYkFWIXn8ccJ^IYASG+OMtlZ$Fa#cdY#cawB+*2Rkvv{{AD`r%$8E7osAVS{)oX zGXI7F`t0fK36>fOr3{Pz{tFhF#emaM% z5$8#J{p2MWVB7%E7!!}c(&=o2Fg_6#vid)6uO5eOXPUPHlZyFjT?$frV)XeRy5)7kIv?HAIwu<^*<=SGG9@pSe-v(%T%OC|fq z|MhhCk61RMN@}gk{_*K-{LvJej1(pp3^MICS*#qFJevJ1%SIiPDNM0pMZW)N_9t27 z^8q;#DzfTYnLqVt_OIuf3}teg`CoiA`z4lrCcqPn`VHgvp!fXpquHCj@iochg2v%kxN5pAVl5F!8VquFO3D`}0>!D#Wh$Ff&h z3ff59~@fPsdRtnvFwi?QaEUq|KelWUpTa| zgZvARWq*x@&ld>7-QtdzT!i$i+`h(}fZu#9`&+E}{2?{te4Wfw6i8CmjXFX6MmqgJjoII0# zk`+Fcf;WbL?J<3O#wW?MYEPWWzQ}5i!I=l{r(QXE=1g{$&(C1OiFk37{A*{jae3kM zav7uxXR;Ug;tABSTwMA2^xB#1$64glQ4uEOF$h=AWXpL76sVE>xOFD`!z}WJ2tt&% z!2tb{GucnE)Muhn@nZASXR<%W_fJOe*@z~GFd#pBCi|25LLoVW75Y+oDi?g%Xf7oyndU zLD^>#n5hT26@7Xndxk}yj*u)Z_?40DEDJs!!!#g&aU}aSz8eWZ?9IkVw#_$Bgg4kR zsjs&cd37XPXOSmk!1+Smk?a>xX!irG2if#|Z+~adt#4C5K^DB}9}KV}MvwQlw|YAW z!(aVD?VYP<9(qV4Od1=zaN}(?8ZO49x!Uh;?ZPyt&f6m+@aK0>a71_qNgZ&F4N{%K z!Oerj;plvKXTR6pyfdiO*2XGRufF;!5)({btX$o!T!)ozv$Bj;6Dfh_5P2=-m{$q& z`yQ`AL!QtPa~6jXYrXV>|LK|@84-NlPlxUD@)g9va#x0qjaOXf;lS12!@Y$_BfwA_ z{;luqPrtmgwQDhS8r`tZG#d`q9CJe8pXC934d-zzL+|VH$~6g;gvSGp&^z7lG;^5L z(Ndk~Q~kP<1GA+~`dELio4@LU`7ko?5~HIL=;~|2F`%W9;k!E$MUA7+o&o4ftPt9` z{_aIRHx|^jE#xtY+dA)Y49C1tX^_Za6-tgY8gS31Q#yEHw&Dm38RZ`%W zP1k{%{|0wVIsO%KjkJi82hTH2{H}nSQAMj&@ReAKByPq@1V6cIQ8U4*((DLEAN4K3q~>uZ zy*c1r(jPQdyX%+>V1QM)=Ozi6J)w#dMQ*4@Kv8EPB+?X0o=9gax-p}x0WM)hbTd8B z=#a%@pWsLot@#?^-mts^Zf>hH5sRtEh;KoT_7M+PTAmN3yu1#h!Mkgn{HTi&2ZPRC zIVMESAfiV#t#(9ajR-#*k4b12OkmVaeL?QjX{!rnI)r3~_%7VN$wX=!U0&*m_zHOO zOJHpf!+{ekwFQas7Dp;tY`~EwUdjw22EuAffOQb$@4@yXcQoh;iWbenYTYpd8w=I`rj)I*_)e=@63z zvX*q7_)uqi~tcMRdfzc_>h{eO7lhXF9Kfn)I3aF#_I4 z#FOa@$pV>E^Ot^X={ah2X&EE6s(njeTe^lKpG=CV;=J@UUqRKY6<#kt{Ln)~!Sdzq z5It}Z>y3jujA{T+LOuMC;hiOVL*q#5;fPZjAZ!eXyUJ3R6cHcvFx=kV!WoVfV&K>g zQpMop7owJVcs{fSdDd$$<;vprG&C6o7HGCpWk$cCrR%zjVqL^O47b0wze|tWT<260 zxRTq`bzcGrIVFRyHfI()7tnD?iwjs5xing>V>RnrQhq!Yc9BbuFMSrQ^=M)}T>AXd z)5cWcg|L&=RPG6z3*SL*Em^Ze&_$FeN}TKzs8C|b3(J1aYu1ceVb zVA!}r)k~NZ3OjZY2Vj>+Np`pHpA;jV6w3S9tnJ+CfySZ3_rxH?Cy+XSqyuLC?t>iUAEh5(!0v8UQ)LW7s7vbra*hE!pLNHDr_Ps!Z3sG1ps`)&(3tAUM^D(OHrhv0Ym^#7eTPVDwd7A zf+~OU6O1_eTmMbVS+vt3*UA`6d#i>0-a#&A8CfR9^8*kDSL_%0(eO49C)EsCwW>B{Z-C3rjaq;0xt+vNGRVde@Yxm;|CuCEbxHW%$aA zp>4?9wEyy`9BX+M(>y#dYRiM+bm8mWyp9L0?{TNH)v-%~()X*Uj;!=0rexHHLeRU{ zhC|Fy<^O2Q`2r!O zcN@9uE_Aw+w??R3&^RR9gHQqAVo(s{VJky2r|9!ZeZIZJh<7tG>n~WX1G7L#e+cUr(KU;6sO!j00>8%?UC8)ySpQo!D{ zhIA^0+HcJ*UTG}8g*F=m)Ry5c9SJGag4CsR4y~kzP z=#PS+16s$!1f-a09>WWns6OamR{QSVcI9TbeGklw1n{M`M7TCM4st%UQbh+uXEV!< z5Ryvj)$V-g5g&XD*8pxN&tmOHU(;mFvPLJUxo*3P?XU?G6{kb?uJ61!`6|!-Fj3u! zA4gmc>L6#hlRMJM-!ipJr&W3gZqHcO=ONoiTOAT=)XM6cUZv}T)yk9Xcoj*^gKBX9 znmeI#DNk4xxqQ|JyUi{AzR_-NtzX4C&1{ufwYwdDk5d#mu~rks+#LtuN4kHY(n=n3 zDy*dAQ>~R20!jCd{3)^rMF!gqIk1T5hN_opPeHtg2PBi|K2JbsFVI^Yc?r!1?h4=$ z#aq3Q!x?L>8Ijn>8QBry(iqJpLt@Tg5k%g4o_SehyWj@2Tq!ol2qml$?7#1$ zBUtPT;ixv;V z>nPez?ea-K`6Hx$Yr$XysTngPN1}?ztM@UWb6W#p&_I!x>A+SVNjaoJmuoR7h@c!G zo1PA%f{mmwMpg5L4lO|@-EmxH=!dDqt9Xhq(4#ya;W(vCiugkYInWK;RXNsh>_sNT z;u!z*O-sSRHYgT;q=f!dL-7b(TrVa>ETBjLinglP^GhMz1n3PR zqof%jI9YJ!#q)Bre<$}ygG^?t{X5O6Qi<%=F|m$>Wo<=_YHBbo3TYt~5kL?4 z$CDP5Cq`!YIcHJ|c~k-+X-7jI%eX+GyNwxAT=eAnTeKe+^ms_Qb%}I}iYPIHmPZbY z$SdL1%9OBF8BNu(Ail|h%!y4b&*ha{K5KYK!#-K*>Zl=LN`1i3{IZRDWYg7rY{e&MMesbK{{@)zZkO`Ve(TD zi`8A&X2ppKqTU8;6kb0(p^h4`DWE{4o6$?jhAa)III^^x%Zx_?7rYRX9?4r6Y2#)D z5>Y=C&_z9La0r!~-ip1w6_UnTXTLZ3LA8#vPRK5mM*2K6R<+X^psAl+y1`KeWSx(-<*j%zQ3Djy-d8UG%-VWWz-Az;YJ-lvr zRS&H&YTujwpgNWiDFQs)W*qk{e2=Mh+`6ShkRK}FK!hYZ5s5cBh$swYG9s?`2s#S% z4}y;8Rq?CZ_PTlw8TTZxz&oYjV%CY8`B+&fU8@foe@8}+|Ktbb2NiX_W6`OIRUC+z zQpX)~2RnulkGK;c6uT+q_ymV!Z9TWW4tpL%+$_Qr;;Z<`m%<6~3|dZ9(`&dS#}`k= z6DOld$ywZjGt zB^q+0Pudw3T*MCwRnl%wZ+5_j5Kpe1aAn+INsv99i0P=fN|9K+476&FSNKDxl3<&V z(bdiW4cg&s+PR}Ko7X>~q9wGkLsZwCo!wkPXz1>a*injIQ}ckU!M{l4<@e*W2XYAp zkn4CE>5B~^QO~@G>-jWpnBPOwOnHSPpL_v&`C#{r^n*|z5(YF<)W(z@QHH+%t1z9m z*Nbjn4lWFOR~IkAhu4`PhVfSp{ZhtCdw>oIrh*U8+<_Xh6^Sqp+Nnc?e~q948FMC& z%ee1RAv6?z6)46EV zIWCL`sK|Z<5KUq3e9Smn!v$zjZyjI7_S0BnCLn%XvzY#Qp?zrUlo=nD014#oA6t5a zx^WL}#~@=N)Rv9pFd?mbodcw_-}X2Yp8hRvc4C9d>$o;WjMiWZw<`{F#=otXt{r5q z+3NN_Hs(#2IRDU_-~N%e9|kORKGlE% z@k>=8FCTtLBes3sql{Bw+7M}oop~+Vr@kJo%ftHeku!3PR*tiAKkM%?j5tBVc>l0Q zE)fvpl>@0X1g9T43r1x7VX)SNGx))jN^y@@g5i2PmWH$%bwipWxV&;1PX)Y75}%gmX68BKTh2Gx{i)`@4osn zz7XWF!U%;@(NfsRP#{Lq8)GduMV`l%%df|-yDWDWr!BY-4}Rd4<|@2qq@VD|$G6oM zyN{E88k`YiaW6ekFG?+IR|I={nrBxovmbJ^TYBKgdc!Mu%DAlX>dak@uSX?>s3++B zdESEDy${nOR!Bnz7d2?lFqWOW9K~?VO$bAK(ROvqWg#g?KDaA|4FMNqR+R%yCS`(TEFy3tK;TL*}?+9W~ z{Q%D5iY6J*6n=R>;VTJSEMi1GF9K=QMyPCiP{EA_WNqvQ2`W@ai` z?D+cu`o!AJ6+sQc7`htZvtd9|r-p@Zq}= zK^fK+J(?&LNa^61K#GPzS9?zbIL|-^HY714JxH;+X+S$e=vTu|<;~4=9ibfvix+a( z_c|ZoB2XMoiR13)%RHdWPxr~CFTjcSlZmT^y?T1-OL+B}{E@l6{mRmh;qB+-?PV%E z&PCF~I!2dX!TZm~@3C8P3H+93mR`r}Gyb(feO4ZS#%!Z`m6b$=d zNrhs^Wo=2kjiWFLx*R8g2QC8O!J=Yu+kH=NZG~E=*@DcqS6dIRW1NH~9$;&N+K_$n z5T`AzLmfsc$L>#Xa5&5*&xJh_A)C!ObYr}Pf|D%3$Q{zxLnK2mZUh?Bu^j)b6}SaW zSUwW%Ww=v$rIO4!L7|K|LKzhC!t?>!KqLp#ARXMsk*F0zsuu`G`}4t# zlyoHTZBiT}57xC9`7K8Lekcbb_te_mG8%`FTpveBo{5)d^FkI7Ge|f?uRrJWJU_uO z7>4O%{k`@U9n~B2i`OqN+z2aZ3`=-IAc3>xZ_INK&e(SuEaG^ZA;F=c#4!^dIlN59 zrVnDx*In!|d+p6vU+r?eAw9w6)&UWp1`|M zQKgiq8)%(iQSMlx>h7G5jy?A!%EMA<}7q*B#F3+CSXBw23 z?|??Tem++u?nZrS5`e#$E8&^bnx9^J8KnwM$tYTpSC?Kxk;h{|hUeG#MpDao{JDhZ zx+#x7rPb@6D)KZ3RM-E~Wgg4_Q|a>W0}!DCO#bu7iX|0Q!Pl=e?;>VHLNA9Y4o3?o z9U1uuQh7w0i>2|f@U7vwJR)u9xba!0LgzDn7%@uKn>QD)jaMLA#w#I&%H{lkJ-!f3 zl>lLoqtla2aYXQ`X3K-cQS*#bNQw$Hv?`#8a7z`i2aj)E#*qetid+<`{ycs*laT!J zQhN;^ZdZ_kg4mlUGd z{vf8HGtdMvJG;Fdq~S{}WC!Fsaa%1e|LPecaZJ~-wFy|spw;61gu49rWi6lZ(CIy< zS21yb21^H+sb+ztd=9y9z$a^-7MkdjB3^?~OK`$E<~A($*E|z78mqiUW9Um&8Mdbz ztL<)MqX(n8tds7SEM0g@jUc>rzua4v?sO$nZm4b#Vx5Fh-CkWl&Jj!_%s>m?*l2FI zxAx(%hj`FIeeSKs;?;$l(Zc5`4}#JKO)I0Q){tB`Mg5-&lV5*L`$EezamvX2djgy> zNy)%7vySGADZ;*>{`7?kni^UKaqzD%qKZe~;&(~ZPV2sETPRk?f4G{|bz786UlrOD zu^b+1qOgUQXq9Ds-J&mDv9Kp=O}piZ9T|s$R!WAAU@%1^TkP(@!(ULSFJD7+H0(+X zHzP=hd`2#+xl5OBAZJW~CXnELj77dn+!>){VDur=xUflnw6GJXX=&&H_9AlLCFKaw zMXQ&GrKCk>D-%=o$y}oxFJbw{##WP=m7v5$6Csp#EpkjDr*Nl`pYOQWkk=L;9K6DW zm!5fvaVK{grmTYw7oCYC`dbHrQ7@xZr`4_ve zzaT6cvK*0ryGYcv-o2j&bkcd(tqe$?h@*kZyWL%6H{^i|+#FF?$4^LK8>2S8kNjbt z0%v)L>?U#!jr(MGmHXXJb%3^b+>v6z#RS#EDGCM)Y=fZHo^+gHkNqtSE7l|SHIhf3 z`y%0KTP3Lx7`g-|X2o%VYLx`4PK_KN+8i*foLFYUyyDqhv8xC7(+Pgx&w!5NqO;w` zMyCLINguFCL_jCmFo^kt!Q2m_TjUXPNYtEXPv+^Z;L$<&&C+T(Rs@#ubcUE~GRdx7^^H9`le>CSV922hHO|Yi^q|=p^nt#A zJBcB@+KrH-Xzy%}S8zNZVL}K=wha$}JTO-ol>wvS0VzpF1GpxVI}a+1mG3h$9$h3U z=$%jZfPf^S1O}np4oB(jbx12_rGzS~2`Yu0PUB9r)3}t}B)^vLMIrM?t|xw&0_wfi zS_?<{66n7jb-*I4o9H%z?zR#@If6hMHY*$O^vCt}5`i8@pg>x2s^HTCs_sY`Y>Dvy zgn)e*1Z4XY4Vr0XWGX0As6)E(m*bW4x#46)#QRfTP}l?r5(ttmog!tEqbP_lGu}3g z)^>Z6Ho;R~P_%pnVSb1TPd?!%oxcSfa?=>*z;)>X5>4QIt_(v-*FoPjCVVWS8w+89 zCU623c#D_?RgPD_0|jgL#j;jPg+vV7;1EJAh9I)pM`0c72qF_*T{|_Vjhx*V~sO1u@_Yd(67q9#Bca*fXcC@VWp7Pcn0s z4sV59ddfu=odDXG?I{^JR}GgCVF8iFKv~9vxOrvy0;W-=1|Je8+iD@9Wgo(XR!sCd znkY8`mL(CCiVU#Oe6Swj*g@vYY6~h-8;TICt-{N-0&EZk$wgNH$9mtL#DGX&i$d1vhB}ahhCzgJSZN_zo4Av{xxQ~rniz$+ zg0u}yjT0Z)YDPM{%Ynl67!_*N+N6(;(Db~ahQlG^chV0V!VQnE&w4TzVP}GeSYcFW zgc1bJ2Y})$TRF#Ap`bN)sC)wSNHSS_^~MgAOdRJpxb`5&;g*eReok%(1ZBG0vNtle zUu$wtRL1L3luF5BFHF;1TWjqM{3kW_90Fk@>%zw4CcpGZ;&#@7jf^$*g%7`7N*#!@%EVP$&mQEf_BC zG3TG#%?kx)DsOSa$mKb1A%E2n8Nx0{{z z&h8dwEVzla{izI%fsLzk*+Ni#oiM;(op6=znyePy)TV~l_3UvaCjLPmr7`l;IggF!x@<}j&x9*eZ`N3 zkF_fitq*482cU9HEhV(9%FbGpkb4)o;h-p(ocJ&b1?$2*z&}X~dQM1vS4<$*60IR+ zBU!3c#2ohKKF|A`$bdgC%N&lJkXX>~ooId(dC|c2AIPLlL3)h@L5s9Onz}9820;-7{i8rp6#X*@f&fKP6ll{T=;Pm_2!cL- zzw?+m^L^hg$@{Qf)P#LSesgB#%$ak}oH=vm45b6F4voiLOJ!?kt%nIR6+)D+w9HN} z+JOAp-|o(AnzbRaC(#E)v4%q9ab7}$x!0m!D3FFt)iP$Bl9oi9!tWScqB1Gl3Qu^b zbyjf&2v)_Efhk~9$V>%9rtHKSJNgh2#Ih{!_RJ5L2%d~Wj5oNz29FI=da8Qw5Z9HJ z=V=@sAY_+zO`336FO*qY0@V&d01N>B>}>l5K_E0R!7kjLhWIP?6$W#Ul*qcy30NJ7 zPo{wLAq!^!LtM-iHYJ=Wc;~U?=56ALw@(1^4#?8LEvGkF0vvFdyVt!zfV^EpFbaZ< zvBX5-)8R`eqBTTcq_KulVjmFWfK>bT#9?p@)TZb0 z1}3QWO{xa`y!rZitR=NX;8+^3063#8w2Q{9XqV9OJYA^jxeS1;yMEXdCD zu<9e>ZRP!KOACqH!F}uP1s zm@pV`9?)U|Q${V9?VPnHG{x~j-6bZ#?(V&PG!6Sf{2_1$B^;df@vk^;xg3r0*b=a! z^$m0cGwd+bGHlxJgf^UBaMJB(eoDaOqMAfLK7wu#KEnhn?n);LPTI_Pqlr# z|1@7ZV%kAM1X!Ma?PH@c3^s5?_KzV?1Z+E)zzEHRX^q!0X;RfO|J(&Jz?zY$&W7F! zs5b&?77m+idAip}%|ItHV#l!cYivh295d>EJ~xQnmSr}=;2s2XG&V!byG7#5pOF#4{tO(QZ>SgBRxo5mLO z;!NfxM>47-ID>|*4qsfdJN@ApnE{EbsD12#n39qjM#^z2$tDwha?`%wq4cvV;W=ac9WsPX zI+T)YEV+71KY41%wu4+RbDII(v_Zq#hqnm;o+%+3hy5Teul0r)>((Bv6q-0WjVz4sWIR_*1RgaUuT;VR?^j#^-V zU9p!%zU1h1N@1Gm60YYnx+n$*3#S@!1xfgod$FwmW~h>l9ssswqHR0i-SRt@A~R7+ zcziESgt9oS(78a*Mdh`LcoxTF(2S+TKa}Akj*t9nRtuBV-mX{7oxyxR6W38I@5{LFH|K{gCes^-B)xDR47 z4J35F3!C51o8JNh%?u$q4~m=@3^Wt$(0Ro|O8~FWL@SlAHFgB;8zGNlPD9+Huq}hR z=wcGDqe_>zY^t8DX!}e`&J|aVaB+#X=W1zVfVZ%u9l6>!fKFySaJC#=8`92(8iO{( zeEZ}EVU80KrQY!(7Mb}4qEVz}3)LjkR^VOR)aE8JC9ZI+PucTifHzONl>y&W>E`HY zH$?GHGhXNy{vqU(_zCEU{0C!f^iPuZ+o}{W8$lh!6LsEzeB9&);G#D1OrAT~*b2p2 zTgu(wplpB?#M~K8w{I%aw36$=j=)N5{DYNlc2~?ANgj@S*yG(P2W{2vD;me-?3kFz zGnZVK5u1G%{ZjyWBTEioaLh^T10EZC_tkex*o^-abR#|$RC{tb5RSRzMYJ3VpFB7D z?m;AJsT`%Ppc>iMWb@Rz-iC`p>YQ!8;l6vRF=ZNQFmnx_Z|`q}vGV;Wu14|rN*QYNT`^ha1^vbUoWj#>?f}3ky&7z zjRD@2gojQRU>wj^MLQ>nWHb`oUyty@(4O=4-TiyG4Zba$)clsWzN<)p{&?I+AoA8= zYcxK1G#orews2RMQS#yv#U-2;OLqbdjVqo9 z_26K8K8Kyq1(>(Mnz1ElKR083C`wWP5iC+UM>NmfeE>rpO3PtGXT3?_OeQ8y59Nec z%%T20D0lQHjDr(B=3fTcfOP6vvyZ|%qfkIoRWjjZymGS5&e>6(Dv9OUPR$4%h&`(j zSi=PAmqV(AIba2q4su}l^oEfEm70QL(M;|?p`@UGa((N?n>Pa;%pO$wz#=qCh2Q}T z<&joWS5{3q^$HS}JQ;57Z&gQ64xlc|)fA~KH9&z%V9c0e+{q1au_;a|L~y){la2`+ zP9_}3l+AHmh|I*MNvVK4%@-tvr+rY#rTi1-*vdL#d|K#+6sfod&0Vs+%wW^xQ<1=l zmI3Q!FqqFIK~VAAHT~{d3Y9UmFhFf782P6ItBL6j``%oEFap7)kc~_2PbG9PcE3*| z&Wz#ia2vKgo}Cf`MkNy#K;pxJ+_|C{AstqrLTWsLDby7KoBh!z7cR^qgNi(^%2r_J zu{K7Qt@C<(I3e$76N!X*4wcTQ}ft zW7wItftS@2p0M?<(z;fld`Y`KS(t$gC5C4Jl*s+QVMds9gR zFPC+26|-ntTFRa;VAyx2WI25xs?k3vNlL}5LtQD7nzlYn_PEr3INj{ z9(0CBWKSDjuMJFc0s3yYHNY#HaI9JksX+J*1lUGra`$EBi-%Pvb2UURak8M*VF(CQ za2~nq%(RMDh)95~`w??i&B71jORI@clp_@$mqfb_;R04y7gcZ!y^t&?3E@C@y$shR zTkwze8+M`?)hd~}wn3~(7dDNKHRa5H?-hHo3SAsIM=KGcIw}K5<)B;%0)F7U<;~he zQc4@NOznOP+i9YQY|5jR8I_w&ZFxn8jl!A1GP#W-6qhp~O9h?s9|HGrrYF;|}AkhPegbtdECx)gU99 zVB#la8@$X7!#{}2r88&r)RRY*;o62X$-&m$5kiIO<)Pt*ZQR`IGOjQT_SV~H#2|(I zAyijPKlY@$W6PvAmLy|{x z++cbIB^Vl0-H|4_b#H%Lj%K-es$!^^5Ct%X;sA_XNc7ClcOy_G4SP1jhL$9-mSl5a z65m!vUWN%yoJG4EcwIgd@(@q#o@4`{v6qpI3U#Hms88cL2_PU^qhKDD139(EIKxKQ zP;WU`OB6Dk^CN_-A?u%>QByK8H{uoKXbf{0k2PsVLrHXTes_0&xVd)@_LQ=LM?rB5 z)<-}BVk*3&>Z~CA+@KM-3gd%02r-}Bbbuh{9N2{f`3RypptR8?%cL-He)AF$97m9H z)&kMYKCadf+8$v|sjeV;&rVmDWjo`vciG}N)Btz`Ym3}O0jU^27-b%EdlzAYd3$3^ zQqnrdttf=R9zVz|XI5P|kN}e?s&w}QfC;mk!Y5DvCF>w8nLd*BJ}h5V4C?k_S!Pas zqA$^`+KjJ>;z6PY+e6ARm1M3%XrC#K^q3qCPiRMl=4f0zp$TQ%l9jpW3S#8mRL>8< z#H`YwaE;aB9*Kk3*l33H;69fCSP;vRMIf+sBSQxXfVA)g?C|L21qDjOfE2E%dy6<* zX^N!Sg;>!Bz-0zs%7X^zf-i6|J6i!hvj^KnCo;A=yeovjFeX&Il+QVrI7xFJ@{7{qV6JD~A*F?f}1I5Mu^g;Gx;>> ze30q#S-g}9s-_N-c-svGaKcokk4%%eqH_3zVe;kn5kelOZAglgLv1bs^i_L&T|yLxnzJ za5%i*d+^raDNP>@(Tv4pOv5xBX^VLrl4{#W!!_X1fNVZ|pUQe<9^s%PazKzg7}XR? z;Sqmo6bs)Y-WI6bZZe+cX1-ab*5N-40#zcfqjUL$mtdU=s_q#Gy`<3~qk;xW;sggf zBSCm1ItDuH%ktDcRjc{ZGIG{dBG25qWY~~)%_WfI8<2zodUZPUCQB?esp-0k{r*Z` z)oP+AeSDU_y-8G0gD$AgFzF$-1c5qX60bb&kGG*CbuXweSUIJRo+&{^!vMomvgslj zY>UkijV&>DQm;Ni#RYFurkF3Z@d&vnmf@Y35#*K67Pf|lpdS!z$ZIR+UF1*_T6&*_ z7U*Deg07y#S7FB9Aa}tZd{hRT%w5U~bL$lizAj1Uj>uP0m)b}5I38mt! z6-H0t$v%drEoeQJq2(T~%q_g48&8@82B4#b{;=lKNXwNpa+=>7hn@+%3RX?qMCJCT zm32biQ`#olMaGxBC^*N&vDop{0Fn7b$SPHvtON|J=8MMgd{cht*qR1n3uqHQig?5+ zpC@b~;F~^gn-SWJS7*m}k;euu7zx2Scd=;*p4vanl*Ep-mFP7oYXa$4tiA{fLTVhW%_7&L$W(I?H%ncdIS9DcanZq2R1@WLl- z*Zfq#`Zn>0KGta1?3dS=SjQ2!wV5ogb?%&ajKyQqHX>1J__ivI&)cU=VVD|O+oWE6 zTCm~qYl~dQo#N$0(8_spCSr_uBJ8UjO;9=?dFUW$G@5cK?h_qzjzD4Q=}0q`xMmqK zTzuwa_W=1raCt&jTz44Tep`+pz!3#@J`t&+VjS;Bb&uZ+s* z-R`z=Oc&l&RE8@fk&Try@>K4znbOEGvRV`9XLmQC5C(2Ew3eC(X>AB8xnoKA1Z8d2 zr7#+Bb-rgvUC6S35hD}#g3B0CF;yxSTbp>#Bx-D|m3t1Jl`*e}V3?;riBK z@4-mVhRBD#2ZJXY`&&D6OtR%o(k};v9>S1dk8$DCH03?sM#wT@L^yTjRQpTVlFps_ zF}!B(15wN_3SP~^>sS1aAvZtUwszo%eIE=V}!`?k29xQ&sJMhu}%D7 zs9ID8B3$4&kQUqCPPhRd-N%%Ig*l>G?xnndc2kcR2 zBk~(stTSR0e<^wmj0D|6%~)lPk(>3~KqAD+3Aa*nG)$@zun z7I4hM5bnAJ$~-i*2Bp{VwbTTA2rzuI*W(Q-dErQijbM9hUz)T)w%iJHBkV25h_S-~ z3p5?uWIIN0CJga8al=H0r*f+dZ00fn;i1vWSt#i#7giZ*F5Y#LEl3rEl|26|D3 z_*RS#djY$hS|r5?`L_z@lF5<_X;+2H`aHz@VQ)>i2Wzh%e5CUXUO#wGW|-puXgU#N^zOOO263IKwL8WBr9hL z^cOl`1JL(}mLU2Y*1}JA{xS-m3Wb`;(29Si^Rp;^Unu5zDmxL2-k`qT`8hyEIuKXf zlCtuj@BAvtXJacU*Nci}?kl=2tkSP_ehZa8euPTvx>K=wzuoy4sP}_qJ` z^i20zLdE$tD1(@t>3)_FQB?dwq=8(W>He8&SK&^gLCw!}uT{IUtAGY^eWtrah&aFb z8kGTcX1d*KXW{OiK`qa8e}qtRa?^b~gIS&FzFg}rh0Gh!t25m%5-19~*g#g^o9V8z zJWdHVedYZugS|J?yl_quY`(oCMu5y_6GCcXS#n>g|TDn(L;mzi zy3h@B;Y9a3A)}sfXSIRcIMMAkAV*%Ig<(+3C%UgTK)IjHpzfUL4hU6K^y*16x0wOo zKhb^I(4;$M3~K8{cc%))v6_F!pvEV(`vqq$+Zyv1Czj&hi69hTk+-R{?vnoGzqWjmXc*qzh;_=r{bpJ-RlTf3nlW&~p z{w-FiGNGCIhRUy;=>969&IRn*@N{F}D*xJv?ys}*M=F)8My!E<^F;R_5j?6E^rcp; z!TggG-QOe(o?Y@NFMAK`qf#IbVikq*)>TxWzF12^l+(D`Q4x+I7AZM5Lo~k;19!qSkA!zH7ZkoTSv%ztlalKne5| z-74jW>eNPjlc-B+G|-7}HhZM_NU|)DM-xy1jT|a{>f$G5)0Zg$sZLR`<_W|h3z)!E zCn^bUQ)yPrO{H16OKF9_l9?cdkt=Y@wuboHUjc%dkKkYo{bNj=mui@W>T{f~$-$fa5A^ zX*iOU4VMyj*y=4!L@|^m(iT{XqZmqY(^4joQ49lQWeF3|8e&X66!wn-bok;UU=r z^Ef82zJ7NyOnX(WR)_UJiw6@Q5Bd+0^}}Ia#-A_orXimsgnth&>+)ek34`!^_IlVQ zDB(1V!PWK>BBDXgwmc-nJ)!x+<5}JjLkNQRUp!@q)99`K4gyZ7Vn}fQ$}f0>(B1&# zi8a2I4*=r2|9u2~qgj1=EBj(o)RxslLv+{5$sP8_=@Gpq4{F_gOXn$ui3Exy(aHcf zur@5qzdM1W2UHx0)-f<^AZyJ3+oON1cn0|4;GhXFkFx=h(6)wY=t6uo<){#4zw<&~Z`8?lA)P%cr z=4fYxS*aeZ#;^5E^?05U8KWPhS!>NcyE}_B!1N(EE7FJQ2MO(jg}lJ$E(N=oS6x7H z7Bza@+uwe;jmR_{Y@r^W0CT~KcLqnJ%^Wo>bsP7~XrS?XVkqE44Sj}8A;&oK{wC9= zu+an-u&2c&Z@2X%B*2G=Nc&5l&LhVh1uo`9lSAZ+s|=lUhfoNlBh%@}+CknAYKO#^ z#@QhbvMFr5UjuIFE#L0V-@MuS3aM&;-&*eBw?~&+Ur9)_h1yT8#^rFxXm2b`KN>A0 z1mkq!AhH++DC+W1GNlZrq9iiOvvLso@)#&k15cR7+$fWEYSvaoljmsM@t4=r z6pdW1yo*SHt7=jpE@9`v7SA4gIxchi+ckcjX*RTwRP6=A6yF9>X#052#F-we^gbjh-hFMlv zp(^5jv#3xX0^SIl;Xx<{M>>}jo!UNxnFcNrJ=0vRQ|T84!sS7GN{ zDrniPfD-YhX(1VRxd2d+1)W(jT_&3+ zcq@?NEVuMaTZEVSk((j`Ff}8y#&DU&>XiscPr2QcZ+)Cb>*d1cu~4s%H`q4e%|Dl! zpp$4|W1&Qf)uE2;_W?4h(aK2&<^GIJUh zf^WyQ16_1{%D{T@gY1K*^;22A%pr+%c9IxDZ^`+TtDTGa-|6o?n7CoC+pX0v!XQ{p z5^3FhP18SRscB#oh!U>ow z99UVl77O!4RZ>zMgt{bB8b8BVF1A80o6a^LY@A{g|%`u54HhKFW*YN|B6v_Y>49*?N?kLBf7%rpE*yF&y@H(t)c3O62{)1CtX@_^*nn&N|L!f0;LMq+OV zL~=lESwxG=8$o>Bc58V5!5-4a@O|6HSG4fhyWi2%1Uon_;gUG$qjqRfpP&PeFlSE_ zF1#J;Q;7+;DS%BVSMltsB8*N^-OaclQ!D3WAJ3r)|5zKCZtmEb?g^O5-d*Rfp2&{M z!{^b`1zG>bU47(QL=Ib|dO$vJ?3|%*nNzlDK$2Ri-_l%^ny?NRqb0{4=S9in^Gvmb zku|j=bA%caX`Sw}=DFhN&YR}+aP_8k42&__LnN4B@K@HF(cXYgfwTveQk86#j#Vg4rq0vr8rFq=m(m zwcfR*6(sn3G#rn%w_r&pMEH7;KH!bj2+9e)NWw|*Z29=D6Y*%{5yPM|l=jYGt2!D_ zL6h)FgqS*->q|Em<8W{ir^86?m`oo&99`t79KK)+?nJ`}DACa)#*58H;w>;m>YI(} z4|EptUhlyU;aa2#88qcw8_T`ro0A-nRAGbYh4m(mX{s~|xFK7YGMWuX6>m8kSK*#r zkcSPZ)toK$%|I}$v9v1WXR7iJ&MwYnY!f+p*tCJH9@8{#C0C)*C?3A3fN?ce==^x_ zC78`vL}i;8?Oru((|m;@q%weLVlwRLsBUYF;Q7^`wK3n9^zP2KuH&If`Jf#)D_}Xh zs8RtcdGs(_ThyCX5Fu0(k%TB!N~NJe_rFjQ2qOfe$r~V=!B<{=+%;-pJr#1L1_Et- zKM+1mA=mY#SGtR>OV49oU{~r+81FfbHdE7;btygcQXP6G3|9;_QjKpIdX9%@m^_VE zuX^Su?nSY5V3p>7(jL?uXAMWT5j`@Qc5DfAVGnh2eJol*G!7x`o)3xGfH8ww&?8>4 zNQGm^VtZ$3>>VUdNpbC*e4t}xrcC+$# z9h3e=pKaR(h|o|FXmPg|#G`;AiV-U>vN8Zh+D#Lhn(<$dj)KGRCb^yK4e#}~M>%po zONniIWin-49F`{q7M_3#l~Om90wbz3crqrc+R=c$G0f4`y5?vqM>~4zrAs3zL8@xn zVr<6uVRUXy?o$Zq&Ij?+g?!_YyJUN*T~qaN&s5r16?@HQ$h3N})yNWAo!5`y8{4VW z&vKMoYODv_&2tv&?o<8_=O0vKhAI)8uEC;NXX|k2wW%pxyM+9pgxrEpgmJ_sD$Lj& zreZ}h&*{#zm^LDgi5??(bq^8*1?1)!#dE>-l5sMpB43g$(2AOEZ)>Nwp-CX2(;n=I zXC^a3lV7zmjGH|59qc?9Y)NX=Yd7G=A7d{7tFXb#nk^p}J?&GEYPg4RK@)3^3oJI! z+zxZS4gRNzB2XZZ#VwNS9@aj-HV!A#HoKYgfu~0CLANX$5A<3`9@E@C&7_R!9u4K*kGih+D&f!>iU{Vq=p@TR zTTolvAasCZa}pjMiKMTn9lD|pRXxh1C5e=rj$#8%$Gd%7ukl-xNFx5TjsH*d1ZS28 z)DgoM(AAZeH4K@BgAl0~n|Tm~2uVv&@vK)2$Z}1a%vnA}r3LW}O2(dQX zYl5d1pI`$ky96fsR&*(UHiWY+yoZTg9qm)CXIs*C(tOU{_*zcPw}f{qe3--*FIf+^ z;7NlU<$S~Z@%@0ef;nqMn97~>eomy>`dwbuN4#u+2@H|+@dC_-=EMh(Hb^~8Iv0*C z@*o=)HTta)kdu;2Gpj(NAd*GfF4irN#v0*iHLOXgHq^DH);5m_{i3)Lz??nm7b=HmRJXsCi|EBA8z%)COaUJ3p$)`3^OgtR^w?1r$AT-Gp%$9}k&KGZ4?Z zn!6a@U+`>bt&7}?(O;=h*!=Eq!nWlp>85Lu4V>U0Hhg`=gZKKIFfBP~Le!J9HCE7DX!VN)ruZ(-COHOs}({= zoOMu}oHHJXpCd26*VMNsX_&BRZVtaJhi7<=0&X3v%*Q$P&Dr&JWUG^*mjNmh2c~1L z(!(D;2i>w(UXb@>)5AbzlN)@H5f%pS z>QM=4jn$op3Tf0ZN+3n~@RGX^VKG=Ay@j<`diOx|2hQ8Oc!G;l#5J3F%m+A+WzdeC znP5kKH{a%wi4A98IQQ!B!@~l?v-W|!C6mVEz0pu`Inro)aW-7`1cp?%YZ!(*>@{qU zaj?z;PElZqJR{KHJj4+{XwJQyLhbMNcZW=Ch-~`AfKu$~Jy z$nMLL8Y~;KF+(U2ZMbk_5ij9^&$$)eYalY)2#=SFpoDIwkyl2mNLaPwQ@BDgC9+U0 zpI1cos=zn#a}zVaki16fgggdeVJIJ&q;73BXo}ZMtSN(U5Pmxbv7N$br-?ojcn=!{ zRdIflLaur=#A9f~y{-Q4L#$waYQqgEhqzGNJm4~;oeJRy%$8B%PL1W@%E*OQa){vS zV>T4X&SC~Yx#BrRz4ZY;hM9Di&JW+iBm5W7!mFL6=Wj`o_)}Jfzt~yajmS+capdKP z`E*Dc_M+Z_)C_id2wTxE`Z$=r&t;Qwta)EE_mvpx2P~7zk;=p808iM#Fk@-ut6CW# zVCr)YTQIQ>&ZHG>DmBz~Fy}T!_K?*`$VXPq{Sio~nu1e^fb!vHKd;c$!B7v3`DJOUy-^1nMcCm?k5P^J|w1V)%&IkP=u1^MTJQ2RPb5(fb0YkTRia zzeG_~VWbR)=;po7iz6Y{)M!WEYIWNXY>o9awb5)9diNPAoMPgSwlFnl#bi5z(EYh$ZfD1@uDgpRE<4G zHAVV*4=(Bbd)x>R1$bMmFk8~oEtS~27zc7+37V+X=R9;oUO+^fiLPqWQ=-SyLr004 zv3sa>o#JZ51cF46v7+GtzpAsNc)3XMA!FQHUW3(l5B?xn?J&2={@5JLHCsv(br>8W zW8713jF1B(p%{yzym*w~Dq`>OK=a}mpA>~sAwR21n@ZqB2E2(vng#a-7l;ZqWnnmT z^0jZA{My^(=c}*Hef`~j4ZUZ%3pBq}=Lb6PLw2e6$%&pJS!yr`NNp zOP!l2{5~&?Nl$NeZlj1?fjbvNsgKT`ENV_0gy}?l-ksut))Nc{122TTCyd> zjH`wL{m;%H0f;GGq>%t52fGIK$DRLO?Mjc$v>Yi(yYH9*1XCO(WGV-12Kv1--KPo4 z1TzIFjyVkE2WGk-B1l0lwiZu94E7_Iob-odbA^}P0Fk5gA{$Ng5Vpx~UIV*4)BRk5 zUhqg7$mcBuDRcJ72ue?xK_Lg}OKd2Sgrs#&vYm^8zB1F@FF+&Hm7tGjx?dwGQ7}TuQsiS|6CzWW6@i(Eu#_fhPNI)MO`k~tnIcD0o|umv z6~ZXRO=_{Mm-MA8L@7Q@u?bKjL6u#lG!c=!H-U%=`UUBYuq|wk>Ion!W zxNW~C%RB5fCjYwjfX;Jl9J<3NOGx-{cW_3#%mOyrZA(DZGsu#&y*De4v0{+Ow=@mI z>!UHQmT1#Dc;=n@ zYq@=!4tDuAKo3h0AAm#jjJ~mO1G^7Aq`t6;Jq=vu%=o7Z@!7-&wdr8))*k91;Ulgw z;9Tb_!>pTjSwf(BbjctZG%xg2zG#ylN+ggk#rtLuvTV_+m(voztnTAxE(o@ zlQ%n3Wa}!lmTXCZ>S=fiqWpK2V>8K@?j+_#obx_6V8+_4WX~|6v_W|w0$Dh>H!O>o zHxP?`T4N44Y$L%Z2=0@YIi_!`i#f9z2oEei+y2Jbv0Az}J}9xbRuCSI#%G<}07>xjIi*F=$sL~{iA%#Eb-2)Xrkuu{Zq$nyxv@UY8B+kvAn{9o(_1uL_Thobq z~^t{FB!X1_o>y9tUPj6&5=)v0q) z$=BQDq)WT6(W&ut>M}{YZU{Ob=*(g}@V;DLiibg+>0AQTduvcK=LYj!=QDtLM}o1f z#rx&+(}@Pv^3QdyqT0Kw!?W7+o#%i0HQATMhQ+v=h>es^8IhDXbSU2&5oO8#M9U0D zTbTxRRRa!SvVG|7Z+n}XUVdYElJRx<=*Cx%n}A*qn&!@|b;U(j_8+$2WHQgfVDObc zXF+97KuSyr*J!^T**?&0VQIN_kuW4H85%96nqgeYy%@h{k7&&hKp4qr`)sSXbHMk> zn;$opN1Eg&PF*KJu;Ac=UX_OEWu(ipQ17DR9DwQd1T-lLDYpJGBlcTFS-fw@SY|+N zECQ0ZQMKc&HHt~T5L6;1TzYRHq^+%rYj7z`@H#7nc9Lop@(8uk=6uxuJOV1`#9u5IDP8S9JbaMlhh!;A!_BwdqzX>iAoS+wT8vDGY(ju2jjezV5r zO?ii*H%G`p-n0>VgWjhOQnL5Pbzlycpu@$UB$n61L9Q^F$Q^2w7iDCwjVrCQIo3z!QJlTVk&At<+9pqReh{X?_vg}hknuyE_oMKg zsSquiA@ae_hhsHUQ&!lLwFS*-&3uNX*7UOcdkSLubu%u*ZDjE-fk_JdGvkq@ttwXt-blqbu*lD6)|vX zLzl0K$cb9=ISnTdR=zh6q^#mYFn?L9;@@RxQl*LFQcxKfzg0bFP7fGir`-iaBc{Ff z81eLjjoTLa_VO4hL=)z;>a7K?ENJTH zwba(a&BghZHa&?a%Y^c}qX*4tg~I2;9U0s>Vv}+Xwyj9t1d)=oT4CXy#ml6XS)%!B z+cE@}+=na6%vo`0!l8oug}m*v#~X)x!~SLh-_u!dW6eOI2vQtCC()1M&3SnWh-~kS zkg8_Lqh_QbwBM&0&pcwrJH->N=e8t^LR^4hXn)EM?WMt36BfW~RoAFm-;PznT7J2Q z4QU$a5~#E`?r-mM*k!GTu~^>~vL5S!fmLeg1z1sxushpY0zLJ&Wr?#utdF}7X?@9N z@I+aYd99a`Ggm6YGXeDpR)H#Qef8>&bJgy&l$1S;Szz;pBgJmFX)6 z8@spbkHcbV8;o@_5Irf^P;LOq3gvt#@hXo5HJmIBIY%3k-s z?FixOtX~HmO!nYY~}y_Oe?{_~oi`4KAAMqMKH3 zI0h}NfJOwJwa6g*=#z5?aBzuC#Gz#!hzVebwX^KXnA}~6#EHzRusuZjWn?Yh-A8LM+oA!C)9 z08i>$-Q3tDNpi6_{=phiv|&@5>QXLa_3sQpgwhVVJ_>InMA607RjNpyemtJE@yO{g zLA$lQws@uW>S$k+rSU=oFMp2rz|nJbw^MrWk0^knB)kkgvGBJjsO&DSM~rSwGEIj3 z|5s2CkwNk9A5T!}clwSNPqpBH8kmNqQL?zN@N z*gP<~FJ#rKX$AWhN(R-*>*4)!eQD?kDW*kD>qVRxjhh}@&zD1mXbfdj!Ryax=h`Eat8y|@X1%4nn^ zVnuCc^Ml3h|FQYuxeQMQb#DBxK;rl|p#%(7=LL088UGEH4w;t{c>27s`9tRgKr#xQ z6a2+F`9koi%oU!YGd5p!R-dalgK8@SW>`#~v{lw^EN;4o+)ubqoh+c7>rX`D0J{xM z*vB(eI#lI4yYi3Uz;3r*L_yx>sYPgi1B0{j)Z<_qYmom+v&x+gyfdvCWBYdz0Hw7x z!>*)5d@vfx1-#sIb|(mu4dG;IY1Z*3k1<%HvN!kml&TpEIjZcjnRUDB(+S*_yg8Gc z8F{-Xn@agl+CV-SAeK*a$rLBmt}H3mb~V_>mPOvaSB6?EuZ~;7GJlAm5fm?*oL}J=cxg|a0NfnUq5Qk7m_?`EqIeyKv-^kX=^P*ZO zk{%TrPi8)6RK~qGfll`Y>#Y^0rL}rp9f4>KW7C^#yWA)H1xDM=>$n4v=oewgp|k&RysrMOGqz?#16dB zX41&UAM~fBTJquH-@AjscFY6Oy1UP1^d9bD!993DpXlbq^yZ-*{T01hi%D;12Su?7`=ZYO-=7}hf zr&|^Mn+`igvj<;vMK*J6#Oc;6ue<^#P?u`!Qu_ku$L@Y2j8HB@BE3D6h7&_+C_6~O za%p_0mC!hfxG2o2%*D?1um^_%M%C? zCMplyux~)-a4c*kN@E*rxSS%SvpO~|LWIOIBY3((i#(nOqsQ`G0`Sj^Dl_|6+jFvC zY+p`AVv0HCt~w3N;tC~UP*lFCalr{WT`l4>sj9!uYp5~sf@+2vKJ{_hdu>~@PLf(x z!!vg$*z?T+8lSVX?0*68Gho4ItUax2*YCL2i3gD~iKV8MLaC+di&_Dnq*=_h=O;$0 zlkowl(+rKmxLQ|)uj&I>N* zT?o(wjd-#{&%siU^{kIm+HL49GX`*{^wf-i)Kx-SK*Xn9tfD;FOG_IJR>ITr(yQM@ zD;PsjOB(+%?~`*nwrH{{sg%KQEiH z!m!H2l?_32nYhT2xM*5^97sRL)r~`9U$;}Qws4vu0oCTG`}lPPt@217 z^FUWlU9;3C5tlTCC3fH)@u&t7A1iB+Pvo!I+n2Z$T#cdJ44(Amg+z(?TJ5gg&N2kK z5w6ROm8XC`XfD}BxfTE$agOmDIf;qtaDRw_@X{EWMP6>tT1LK?QiFIhcpc=SZToeX zZkCvC*}o%h(BiZ9?}ZnwLwk&tO~jVY3h~Pxr^&tM`iFFzTed`qMdwzT3HQZow9_A| zbH~C|L}^%DYpo?ypNW!5MNJz3NV1FY*O-+|D1fh+2EG-g&KzKdPeO2?CQFKtDCg|p zDx+iuYk)CbwrxPR3i#oYyCNlqMZ@b7I#LBpmQjj&{K)z3%e0#opqr`R8vg_HIL+ zEY08Sy}Yutwm9X<_E>d(VPWz18k%`&>DCKcv-kXq*RL&Ctuc>J* zL+jbsIl;eZa9a08TbXBxhcp{k>%5TLl`V@9mq0Ua^D0*7Xxp3?OZv3{_*3- z67)+hAC2#y-x#g$o=51-?s>g#)_$GIm{{wCfZ;z0ao(1vjAV&*+-OAWpz0!Z*EmF`^lVo4lbqXrcg zTIDq}Y@QBbB@cDGBRtjcR?F*VstN+wbhW=U8g467R7N0gL}WIT=~m9HRud{xPBw8o z0<$~buPj6b?t|8~5x3xJTP8`{xCHDz*x%d0%Xu{#|CuyNRYq;ql=16T-MymBVZ z24t#jH9@D2eF@3}EQY6$#Fr)cl0-epMJeejin^n|!F^r4AwtPq8LSWRoY}@99P%bA zn@PQslk(&^Y# zoRBKov#+S&&G^4nK8U)vXe+E0lj=5+Qr!+ZyoM&gSrrPXFN1E1qI-H`Aa`{F5}CW$ zkLGKm-_^b~?VF|hCVVp{Tp${r%MCgqt>xi%O0k#=?^*h|#7R{Sn$}m=PRP+h4rYr1 zgQ(bj?@U%O3v0NmM}|0o!o#4ZC1^mqNmjDQ6FQj-JB}gCl9NX|jy2P8$WK5+>e_CW zG$>mpkhM-vcANj1;|IA@!&3io)#+-o-j2Ahd9RTcl5auVyp@hswLq(GxwDt%`dGVf zW3V{bV0qC@Byxir%ErNJVPFAQF8P>V0xM~&2P!*afYByFB>ZP?+=;y`X)p~{2J1yy5 zw=9plcyy5ad>`@ibVv?yJjS&0%*5dCuP^M3nK^Y&(|5}`H4Wg$d5cmRYcQuKhLwUAFJz6d%bmxnPP{566Jy09@6f>xp(e z_YT?kd>Mr>=;Q8HTx*&xT>MjNqTnz}zonQP@&_7IXAQD`B5kwmhxL`&{uWb5!oHFG z57;VT8v*@540Kl<&x!8sGaZqFq9gP;KFC{$=p8g<>~awI6Wp$^?~ONQ6C&I$WW`C; zU~ZF z6_c<5n^$@<=>Wmqt?`Hwfsg^XOOkpzO=V|inRbp3c97SCi65Uvp)v;MjyS22EN}XxHlTHk853s4D|T}K{Pl9%Y50Y|Jm~Gow51lYZq3m-_3^uBKAT9Z zQ(M4z#(xpl?ftF0@N7Y=5GgKwIJ!ql6&$|uEGM*M>V^IRydOyOO61YqV290SMB#X| znQFq{`Bn(14g3&CZiDoxJ_1i3bsp6*QBm`!C0!e+ivTMRcW@_+KZHTro6a@;A0`HA zd$}M{%}T_EXk+5Wbz#oL*F;RUd?B_lzYu}&XmEx~Tm*c3q)QAR%$e4Bz#;WQ{}5FN zUX>cR&Rw)49_A9pY0I{)GAKWHiR@S9ubhM2Z0PcAUpUtCM6Z+iTXR znLP%(HO_3aT8ro$Lvc{*j-%sgN`z}oieNS_nsH+%$D@>>bqqqiQM4veObjpgSI_`Z zm-AI@{yqFpwg^YcH6z4I+#M|x3uU7PmbYX@e4F$V%9POgLu{?O4*;^MS21G5(yO_N z8off0K;501sg%vnGp)}<9I3E#o5)az&P3$Hb|Yiy+XH5ckXm+X=gO{4%*wq9s{n~{ z>vK5IuD4{x$<+tXWof%K>>3jm{UMa&(z3Y3=Mss$IQ}~~dyUrd=HQ-$!ju;Bk9`$4 z-CLiS+CXcTF>uI&PE0X*c$=Zz$>Fv7Hr(boGFE!4O@br4hz5Ue-gmPkr7yzX-TW1` z+JwvVWwSu4-x*)QHG3BOkFVT5Rpo+NB8C|<@cI;SXRVW+q}pK1HrOxPL9|uQyMzGD z(<#^t0d;)F0(U(@$_?MD6h0xxo&T0%Kz1*NCm@@<4ZakXC@qckBTrE&Rc57mMoKrJ zDaHb);D2%#E9sO~OyJ$LV-O`GTf9=82!&Jg$qCG{@TcO}q?qQ}o+SA?Yt?;cMeuW< zD*bf^s7kx*^>(V-$Ox}XWlqNDdb$Ga*rRO=-IgM;SC(T)ng~7gm ztn=yc9k(Ft`)511@ckWn$0~#WNT;7aXXuU2BYb{3MTn$WV{7d%b-sr3cZKqtJ?SSq zKZUZVLYdxTv8q4a`77)(6r1Nr=PiY%%2_*&;1(j!oZ@A1ijc+9QIU+nyn^q9+v z9)G#>H>F1}wjRGOpFdE)=u++ao1Nc7{r5Eh%29$L@%x=W08~?R9?4~Zf7ty#CeUwc zPb_i;>wdpIl+bGESK$0C*x>!Kgl8Jy%Y#;{fJYO~5Rs+|`3!_-uU6p`Gu<{Te59cV z+5>*}Y2X*^DTV3n^E}5Y;8lfNZ2yNF+SlV21H3)cy)y}s=!G}%FV1uy5d3sgyOpKN zs%*}5A04R*6tGo!GSmIa#46DofYz`oKR(m_i6d3Xz5LWn_h(q8iKyzIq(0^L%=-A* zneNXYp+fHA7iPNOV1*AgQA@X@x%FS1>Hf+gz`5nWGt>Pw0)McnW#3gA+P^;2{rl5l zbG!d=ru&Zx+a!B_mSN5Q#!UBjCW4wiHqhUl>Har@K3&Jw6v(d#faI1f^sr`FkJl!YlDDQ{wjEW;{eM*vh|7r?`Xd}4c5Z6kn9lam#rfHV!#G@_Ir zK@$>g|7dyK_K+B`$oIB>7rEX3-pQjrk>F1vNUSh#P9X|;VYG7~&mFYp*3Yyqe&#cu zVY;_tWafpJiAl+J571a+`rVW^3|5vTh}k)~^eH|YtOl&qfh&scQ)>%n;b&Vn`82$z z+bWW;?QcKaM$}GE?&OS_at+e$QC4)db7+XC+`l`atjx*LSR1VruOWF$#Zx{^*(RC0 zCiOqZ0)zoG1?^cmz1H6lF$Ui;BDuz6dDaM5A0OH_=ydDa08f>!Bc4=ua%Opr9-cf| z4jdcKJ7S;VsE3E)y_b56D=WQg2t2&e`?HHH%XsJW=Jnp{(hIj1uk{udSJpHtvIKuo zgB;hEdoL`m^_EswUtC-f;NH#Uh54H|U!7j*rNxz{>#z2ZCQo}pvb~kXrYh{e_u{R! zl^2`r{e`9HFqgbPh*R*+e~6uc|h6c_Y5u= zR>vMP{El%C3Wt?*r{rqw!Ijptcu)c7s#|npZ?xO(AKgCHdR7o;y~ZCN7&4k7Ml7Ob zWVctm8CM-ELf*Y|d5yZVqr#PBMjEgNZdk40G@tPYlyQ0Dj`#I|my~1FqlXiTV8N3j zCOBC8{M95hxe9v;9rDlmrbYntu1FB6iQ-!${^%i`yL@0T397LiCj4v*Dy!fxn`~@T zSw*H(si{;v5<7$;MT|jD9H!sJnV_)jGOQ!Lpp|IxUq9orQ z0Lo-F=%vQt$e6MdM!ZilS&uQT(n#xLtse)=py%Ey0-fhqJ3g6@QIty-mT%o!Tv*GK zC86?Yg>UnCjK?Xdi-Z=4doF5g9QB0C8aVHDqmQfTL;o_MKU$dXR{6r>klSqj9(xXksM z2g31&9&9kz=a+6SUQ<DKk-Zx?=tl70Rr*0W6GMt)jZ zoWGVqND)fUEVm8$sG?2@0g_qDP<84k0>+Ib(_tL>xZuV(*R`vAL^V3z(*SZYD=coxYYR+ zYCOdng+8?6&vyQt<&B<#o7nTsSV_?l@e$Z2OmrVmv+wt?Ni1xB4gzn$<26q#sm$#> z{GMam|GEC84ZtzpMZ+!sgS`j1+icc*fA?T}9gCj-t?$-Mem>3ZEA9=F!QW_&d74%0 z2&R{PDK{QdjJMQ&v7snQDptK_a48Gsd}QrRKdhdzpzsJ)b7u5(ymF|bi|o4Ek->UP z=Nx7|is?`s@rb+oULOx|AIMu>lvF4WZMzL)d+FBV8k(0UrrN8^3mq)OP&i$|Mzk-3 zTR8x|hA6)&A{CG$zfy(B8EI4d#Pzqkc&wH--CXt3AtGt{AS9-zc#i^v;Di}z7;f7{ zlOl=e1j^XBBMu?jGotBzN^eag$7=$`K+<$#6Nc4Vj;b^+Pp({EeeS|%KG}peOeR6L zJg|~DM7dv~VIh3MjAx?qq#&n>Kf2l!)RoRdw-$s)He*(T0_K1&p`m#;rEfYY6iH2@GH1DKOX zq2E>ZV!p2TuuNQCwQ^Cy6LFK$L&hjDvKrJdZ!A)rS+qZ0pYK&4R%{6J+>(( zTwzBT4@&s({O!^`(^9RfiJR2a}Z6ex`u13;kS;|C*LTC>1X ziaBc|Y>{P^Hj#}V@q&4Sk*7Wl#HKa%;grS*=MvDfI`_sW0$a`|SP4_*b}4qJ(SsPiE#Rd2TvTY}y#AD>eB3EIx;wB+rb@3mrLYz61|u8u5Sxj|W0Dm}}$ Yrsk!fY*^Qx^3guWcJHf*?Wi;s6O?Bry!fK@cQBV#kghAaINtM z4n=PSRB2S(3pWFZc=fBl|zWLH$`^{g!W&Mor^D1W=lB};ODlh1# zZ|ppPJ*B4W>xpcC%&_F$C{z9B?&TrC`*{Kg9kH{w4Tp>G-+yWhud^~hcOLN z)$A#*O~1P1&SN0CMWfB2(x)P2jr5jxq^!!1Ji{5kTM-4UbQQbQrb=zgUVmwQ5e|8Mc zQk*TG_5hrER}?N=lJOmMWNOms_^loz$%aaw>4NMqHyPI2_=QhA!^ao=t28#b$PQ7r2ejPG%3f22um5tIxP6W6>Y?ppm- zbo~p9#z)X+>_MN}w3qk()jy&_fk5Cf`5mO#5kVTy=CAqe-VdfNs6{QD;V!P|&f@Q3 zfPZ(V&AWpXA@;ywVqL*vj#U6guSsI5IK5`1iuND+TQ+d}%sag{yox(qcvbZp%Din8)4}ZuBnjy6$4*VGv zY*r;1qYtS^A7)Y?e&F+R={0L(9{~}+wiIv=%`Mpg3-CMM1;CMTSLpRcMwfIiL;3QB z<92ZGix*7H9h1dm{$LRn{XQ8I7Itm?IqH$y*!p&EwEuOw?=O+nbH?(yOv-I(b^E`T z@Ambxdoab9@wrE52Xr|qJJfU^%`80f;?Mr4FWkCSpdg_bHrfb0FbT&t!>Xo%k0XK6 zD5kAGriM6hr~<_bZAPJns@4Un`JNU-8B3C&J`xS1uhV{i8{z@Ol0(Q9Gp6#!Cr=L# zDMsNbMG$y__qp3A=u}J9C_@w|ND34y8TuN!V>nLe8yFRNV5q9BKcsk}#h9|;(*=Ww z8#;NWJf?)T_S$301Cbgqvcv<;DYZp~V^NA{M*7!L8|2ax7{%}zB4bd!k++fln35Du zHhCh*;87;^Q1?E6Oo_}upcHlJ6OQ|mCh#u3eEk|L>7vf~T42O?JNK}sGvvij5jOHH z8|EPRU1zi1u@W@zd>;K>hUw#%EMaNvws+6~pOmeCIx34+DA4M`bkDAM|t~ckguJQk=f=~s*BYKpn6LJL~&;>8C+C0TUTM#lY z^i)MRH0vDn^)(fuaZjfn5tdZ2DH~j~IKKE|Ne}>&%t`9oL;g?*Ta*=TS zs^k^q7)PNzSME_T9{`Y7R3!4*C8FYMHDFbR>@RO>Q0Q%u|4gYn$4z^V8&{embly&G z+QL#M-|?RMU4L;&jZ?=WpNSGK|rrX!@*$6v&%EPyFyT`rOL88 zBwP_zB8#c$hR}zsq)r4qOU|=xSKudCYBODc&Y!iH_vFmJE=Pi2ot?m~@#}&D(;S$y zaEWQ=9x>V+0%>|)l=-=gsH#9|2K-lp^-9%77Bg0DV^ju)D2S|UR7#d9h^9RtGIS=a zjBqT#KnPKkptD4nKBU7bj5TUoFo*!ipdC36rcXdTgquEndR}ur`QeSlq8FmN>EFjO z*n-UY6>-UPeDrINDwGJn- z`@jmnu;v0GU#9&pN4;M|{a;w3+rNZ5sQMSkAIs=T*g348oxhBd=`2GT7?E6lZt>}- zPgR&*bzNTLl-ARyP-{T@&T5>;+TfKzOp)!j)zq^blLCzU*R3heZpo7D{oh(mm)aD& z7i`LHYv$gO*aa7i%ZCHh?oYxl*^-MW?P_hqo^nG>te7@SDh_f!rb<_8I7U^?m$_AY}w zZ3~KZSWt{Flk$rFw$p)e_5Z%0Nh(jw0Kq`gwgW)TUlZ0I`@)uqL#Jtu9H&;S z-=BW!vs-w6e?|#1j;^0O|AbV6q^%g#gCf%^= z6lQX}HR}Crs#$&T0fw^Th2r^qMS!csT4U{(1=Ry+`VsT0ef<76=1l*y*%kTBXPdVl zc`T>j{*l4FDIfjHr9<+tj|CM$q;G(<&K`wJ^4%|6O_$=kb}!(&?DwBQJ=6a|^fq0? zf9A+s7^St@X4~)HB z$X#Zc%V!gz;bw2Ae3`l;tDl}7KYDvRRdp@lFS39&j_)1!WLobtB$VWCAGSV08wkXD z-3g&7!VlIae1bS>7kDi@%L!2*-n(_nio77oFFE5OBFIwLwi;Su&6?j5YAgwWV<6|u z3QH|X7KnkKdIbLq0!jpUVH_jD2h>Ma$tP%ap#X!MHQkGYyJ}PI;wvsDac3#Rh^wQKvh=0)p!)yE%5$^DbkJ^JE*&30) zh+!Be1s?L#@=%yIBPjrbBVcvaM>SQ`vO(C+HjI|V9_n4&j%@FQq`)4HP#)s8wY*hB z36==dgY8?@`l@9t@!9%?6?WtGe`&&zDd+}-yasV};rVQLlP+`!*LV!O2QhP?cZSNs z#)4Uzk}l$ViC_ni1LY+EgLw&t6Jk6$GGT{7aSID?Ma<~14%!`Y@Dj=bah2(aMxt1m zQMx{A9Z;~ZwaF0qS_J(=tsJ%X;kZOn&5HtnI)sT3& zN_DCNVA}@&gw9%cItzl4sk#CpaUo4Yv+NFiR0g&zpoaUrS+4IoV|QRunW_6<02xCo z(180SqJ~QGh;-9+GJJwLJ?r78gk%s9#;ZM_uSN`FR!9L{v{MdaS<23v!!jut#0Y|b z3q91~p_N;!y3|&HL|()ML;$dD5g<(t{8BRrO~On;Ow43m2wx!lpwCDe!A)-iMSq`u!Xbch^SOhq4z8}IbNNEa8cb!ku$QXkDCj^FEF)(8)!L{p z&{X7cu9VqrR%*GdkILq@Rtq3p8lS4Gxoj@Hnn`CK2b0NoIF-z%)9F|sm`yp11WE!GS3J)YLbRegOE7?YXEte0(PQu8en}&0=$8WLkyr ziEbVgH>(MMq`beq9bgMSO5WRcM$3mu*Yp1xTkxR9k z2enEe)vvE~YwcR5aJ(splwu>^@lnk2%1-bk-d>3m`|W%v(8$KZ;cVn2!q?<1f3m_W z+fqOqn1f?!XsqycQ9F`~+d*R_tsKO1=?x#%sYm?WcDf-9!dkPX$^FQ2Vl&yx8bYAC zRqlq3z;LI$akMKKHNDW{jgGS3_ivctqinC1X>_pfC;oQ4Qc=r(w(UVeBhnCc9VLVD_@3aHQN7h2lvm)Amsz zuEV9*Ps-h5p~Dpd;VrhdvtM2>?Br#=*4WRVbW1J&NqT2xtE<<7#Y|`AB)wnF4CHL8 zTI9Nb&=p#tU_alkA63?ak@i-;)z}Z~dl9z71qZCQJ3NY=$oa5RG@D1e(W0@r*-Q#M zAAdYK0CJ`5e3CtH2KcE`7iww%=Fm?Uoa#XPm| zhF@Gw;k)4%u#KG6^t{yWQNIvdu&kozh491X7qe!rCksTCP8tpo%M-NmDi_F9jWtSSCng!QOa+p6q_$ zomp{IauT_*Kq+^-8-L(5Td2vC;D>p$dTXkZdsTdAf^SZAZ}*woxi!~6{|s||`!WN9 z3x9lhy$j~^_H;gTObpJnzI2gE!R_6e-QRwO+0FCc+Y7&(o2oe>(wTU%waaF8-f&`* z$t?Ol*M<3&AKA-WZ!-9)~(B}NR~`{i4o}n z8`9Dyq-$G{u5CcNw*BbZ=A&y{kFISzy0-1;+NPsxTaK=6IJ&mo=-OtZXSNzyM0%0Y zXu{X`Z)hFH`0Lt=Z)iR1yP@^A??;u^XBDB}S|EwcRfG;FvcmIo@&5;yeM?B0@Yoab zIO9*7IC{@{`%w-j(^4kgt9$1i@4IWqC7+zq%Z$13(_>@{eDI8-67Mkee0=d2L%Z?G z|9Jc47dho;9qLy!)i|#X&H`Cvty$!iM^qpqi^$b6#|zK!JxTf0iW}0_;OOo3Wx;mD zQx(KhAWqm0h5&7N-tl<|?w~ObDK`g=k3_#9PDDp_J0AKX=YkavB$CJvrES0PXvMW4 zBEX6Lp;8JWc}NTjWUEol2Iqo?J+Qkg_YW#L- zb_<97rQCKIX1hGEb+p$To^&qC^M)tQ3DNv9cJbfvq_Z;Mk19`^)w2I+fygyi%N|Z- zuj^>p7u)`kj|#7%8wl+@MJhjyVI>Y95YXR}j!(rqNVaIU$VclPO5$?+7GCVZh|XkP z_}Yx0<%OS}Fk|t~bOFYs@ZHW&z>nZf*>maJSJN=DzwYS~J>43=V!d#5cx0-EH!~mH zO;++oH*MG!eERb&2$u8ABfHyCx31)l_*^%T7U`2Dyf|r1ioA1fiR($arn`V zPN8{V9!Kgc2JdSmg2&~oaTF4`&3!J>QbLVBlN?3&vcc_IT;1&IWpg{YauA4=_ZXor zM2-Xcuo#SQ$mw3FyJz@XffOX~MeS}LrB*hY)kftcxW6a&cYA|~ugiCK%6t{09n@o?Ub)t8g;Tp6Z&oTp^Q6`~ zF3ZhwNr;vtwH!=U_BPU5LD?B{{q1hQT-(|84GIxWEtFQ+c+`&+vh_y3zNz>XmQ6FE zrW`0m^Lns0l19mcl?=CA3)NbUt#o=_&eaR+a=gg;Hj}N|UN~D=>8>zcb~hr)!BTf8 zk>jepj23S6Q-MNK3FI~k@q@ko9K|2F$4#GN3eDd7X0{hF z_ew@SAaVQoQoU7eDV?oS&Df}<+M}(!VC)t$;ck2L#LudsVLVreNx4osb+YA?qqW^$ z+3>oPp`L+tN9dSkuUWsc}bYO zKwVfb;C1U9g;%xfxoXW;hl_H+RJS4&mW z?b2R4rPeaJz-TAD8Ra&12gTjO(3eX!vwJ%`+1yap*-%Mj^WuOD?;LNQq~vtFdn9(H zd~z5_XLfRpe15&lHe_>Wqa<_6fy_x!*(c=J4K9ByZ})ZwY%P;kPEsXr!_-c0J(Vh_ zI~ZNN+0C?@xs(=En$6&jCd)z1XQut@M{;IY)1u12?DIgT@NhkTlnh3VL2gIo;t^Ic zV{D?pviaSjc*39b20M}J$$D!qmokgKqFLJzMr`FMYKZY>R;!hyldY}ea#}gcg|?dJ zesVt)N(HyXNK#ifH`m*-ZiP)2>uu>EEfwW~&tT(Q;mk&>J&ZP(c0<{g6Wi2#`|N=5Q%UuvVT?)Ib2YBZWT=#N$qOW)qf z4LjTZVO2H<>Pn+y^aqtdQ%x5)&B$JHOE{1sf#_~rO{lq{K9I}?w|q%W-|6mh$+|X3 z_IA?+9cc&iN;8)!3A@ZzbT>FU>6ejkSyJ{hF4|p$R*p(|bFkbTEH?+s&B1bWu-qIh z&*xy7s4p4no=|*lWH~6^olcb83WAVJw{e(PQ`XT}6 z-K<~r^awTds{rD>pLJf(j%5YBb4=bBC;qy5x^Y_?;Jw-zZ{9?uhQ=9vrsf{4^cewQ ziapG0L2|{Z9pcwezhl*(^@IJ-+qZ5_G5}Dp1yHL7+>}T|pppziACcGfQA)x9e7+04 zV}4WD{FeFN-|x2l6L8L7lG@Cd@x0xxCSB&NViUpgF^G!>v81&#wB zI0=HP*h8pRxV_@zYW^`*{@8K(KBh9IkEebEzvVah_(EsFB=^Mx8dWh_S>mWIVMJLk z0z18tYMy5)xve61f!L!dO=oh7bt?x(>8(!QgLa$H)FUTz!gLCgzNsQI(90&W*-mRr zXYW)Ye**!UY0=Rn%_rzsn2tv15KAXxbd;xKEX^k9V2kFWG{ex*z+3>yAk7FgE6}kx z`7NL#Plp0D-=f(#%?0SFRoIG?58kObqlob|%h3^ZoS@@j0wahKppif)S-KUV6ET`+ z>0lBGx8?!}1!<0_d5#uhG|STg00_|>M@Qo{AEko6Eijt+-tAu<;L7pLPa9g5Lh zi)PR_OUHt=z|)BUEwFTiBWuHk$@my96o3=SI4$6<^4Xu=7EI~(N z1S_KWV4+7OM8{Bq(PGk=E|xt&va(^jLf9*Jom(8i2cR_eQb^FPBmsuq#S~j%x)q^g zA+pn?9qIsiqIB3rbu3ykNhg3oJRMHb5g<83hpp`*Ekbk{s0WZNp#lspfv2(Qydz0M zJV_un`T&6?NQ)$f$J0S9b%ZQ9A0e{{VArug*l)M*1e!*WiGkn)`M}XFfyTUniwvd! z)C5hSzc?L^klhtPbP}Gs-e%z)rE9P47vNl%9iUx$flJI%SsaEN_I378kK6P^mdMZSj{6F zn(E12<<|99b95tAMi?j(Pr21>xZcWB-3he?l5EP!H8mXqT}VZ%HH;!pKfFk@LSwIf zhnd+y4HI1&iKQ?%B(j?1=?#R45)clM?7JZjP&`=@s%u@V6}0lwL44LE zK}T{ZJfza(X}yn%$UJWiYi@=tXvk!qmWn)av%5b0uP%YdjwAfR;<_HI!7{Z$tbbzx zm3y7r-$niJ%rOys6ZAOEXk$~_g{A;+GQp+k>`G)dLuFSZvgK&(DkOF#3cC)0JvaJV zL|)gRuH}g9JZ+I7Eg~&PYq`NiaAq$DciH_7E_yiq_Z1gs1*w0qfW^)gq`o)dwaW-n zlN_^u1^vuiFL7~XROb!U?Yv2TeV(+s)A<7VOfC}`-?nbKI>jZs7ly=rcWLwdZxHBL zHqZYNChs@|7MkbZv%0K z;by;WRXr1KW{<`NIumX-d5DSIZI=r-`(xDqO{=e2qy0bjO~cKch4Fb!?6i+?S<7lP zwW)`RNibxY1FOi8i(vhd*<%Hbh8#tVh4z!F2)l$4u%PQEY42F&vsRi;%O-DsoRJFc zoTd{SJsI`+Jf>i6dz0%R9m_;XHK??J{JO~BIY)d967kVnH`O9JWarkkL`}=m`P|$I zi(Cn=Prz$bo$E$e&V{gq``}uxgKN1Bu4Os8mb>6uu7Yd139e-+f@%NR-2=4)!g)y7Ytn9+DG zcv}GgJRsrnb%--gEdnkbrn50R0Z$`bgzI#g+!;l@nYj!dNYR-9aY=^Zm`u^>IGs%q zeKzgZ<(S~G2%Xit2dUW(-}IQrlTq1 zAq-@R&wV{Z{G&KC18KN#>2#D16CPxl{8}cqy0oY^OrxiMKV7ECZ1V1n@kDs zs}uQ=_>Fz8HD-ap=qT_vqU*%+c_X^ckQ%|Q8`1TOQ7$*4>y7Aoqab@vy&DC2Zam$M zf_zcz+;dlu9U%#SZ$#HW8KUc~z5fpv*oo)b`~Tm>lDmw(|Durjg@F_Q6tUa|#qx^d z4l{&L7^Zc}mHwC#*4k_2{!en1*SRE9Fm8nC80w`P*W+Kc1b|M}H zM8mSPUp=<2{^~I!xY2d%I$&gk^9gp4wB^P3z@1#@JGpX<1XMubA<)T34vDiglFVAt zeZ0U)#2!WIqH5w6F{H?9s{?W+7e0^d@ndoVZW%}BInz?B`YM9CN7ifXhNuaQ;p^cd zG5IkG6oB7X(*-MHWI~2B3i@O5+1xEram(#ss>fj{8jskK_-#^&j>~|XbY9iM1 z+fY_`+-B6Q6)Ty@L9J;F0nK~SwN7@r&EiHsxScu*7DV5Zro7P?0^lr5>5*xc$564~8oMGZ<@%>L%OnN5%K*<5LJ*kr4_)qZs=Tv-`(8;x8B zFZ*_L^_>5pa&&Zb(A}}2grvr9C8cNBTp^pNrZi?p4rlqyc2oD~+o|1Fuh)r;>KnOX zccdpb)!;^=8%guWX1mAKhb1X$Luu~#GkYi6eyW>G9hb_9KuTlt$CY|d3kLHWc|V&^ zH#@;>J>A_nsB&?>eSE+h^~`p@biAXK^tKJ9Fgyw?u})C0pH##3MvP&1609_6mdbUm zxV4!&+SyE}N;}8v%yvD(`b#@ZIlB{P)bv3=)v6@7Z75M;ogc7*u@XP&7$Gg1=}X;q zcUW$vdRcQnCmYB9#I`VK1~RhTSW$A?aq?udy{8T9I@Ty-+EC)Ljp(LyqEyn^>UwCs z)81$t?d|dHQ6r)bo8ewP9!_p=3`*&3i7WYcOUb>;C{Q&=34iA3WUDqYipY&hdjF&q z>W0_NI$!GU%Ij&eM!o*NI$}*}eK%B%rhAN^IZnppJw4#xlSHwV37#BO{QLfOdn{=! z9$yiYe8H4gLRn>0mZO0aGf?GEbR+1GGo#36HM=pA(wSnuYTb23$nWx(%+F=o+kYE= z+8aKOW8nfm?%0yP@~3Q_$kh;6I`Ld*^!`u%DO;;6$_6CC&po7sTo3@@yiQmA=mj*m zZ8ey2&5!kEMT;4c;)LxWY`b zp}zg z3UH1zazmESsEOT>W!rZ{mg~OfOqR2PNoK(TKUXl>bdKO<%yyG7-Or(;>xb!f{v{6i zt(Py1(S-o&4bmO|ZVfLfLFSc=_pCRMNPs2c86YMIk8z1R1RqjDj9O2hKAu>~kVsyW z2B=}#;Z~=1D7zM}Q?$)^0{;PCJF7{kvWhp(ZE@Ot7qeElDQtQK?i978{rX4O23ZY{N$?=xerY2TAK4GCNEAnL9sM zmK(o)**Xv*|H*WFO5!`nLo!ctbeGC2IXb0oZ7p%gVP8^b z;VkS-o7gLRC!I-Owh{DbLl&gw3wV>}@Y&JD%)XkI^0sCHt1XJlOkj}ZD6&04QXdiV=C1CPjWzk5X_ zxPu6v!pMiXZ3;Yq_#G6A7Y2f?_DP~0;&9-FzO0VOH{wn}#j3wpDCQ`p--jjN_FK3d z;PEBHu^5AQKpsr|@RD|5mou%f6n`Hm<$a%FmOFf5&P*LVef`WDxMQ#=?3b6vRWb&P zOKd#1Rdn(3`N5pCTFc=aJBxE}qw#BS1g-Wpl@oa6AvtBlFFZLF-+FRtJ-}h*KKLRY zeEG>Kc&qq8d{=zmJ#e?)!P_ap&hYUP$FF9N1Et;-W=XVJzyxaMm zGZ=C4OE+XN57FYcrY*$x#CM9V*@OBI8p6W?D1wo@@MgipshVv#&fo#V+o%Y()(xSL zV|?NiBL-072!j)gfjgNHj?aU$I;hJ@TxF=LOkPQblL&8uP2Ovr#6zx84T0h%9tSje z3RfDuV>oabe!wVLZJfY;iGyv?m_@=x$QT|D`ojVIro?z$~kT#hG`L}f+bt&1>Tfo}gNU~H;c?ponkLVj)?+*89# zI~(Ojt&E+LdXmg&M06rAK~c#4gZ~yDDS~19QLRF_Q;D?@o?A-q!>>wYLgX$c4O0Q@7p$Ah_2XQTD}NlirZ+%EP@0za|`f4#P%c-_yznv91dBk!Tow+V39@ zhiiSSXbrE{e)9D2(8gNdQ|H}9yQ+@5Z6sD^*fk)qzZbHEOV#~Anz|>#ul#tfj(aYQ ze_Uq(l>Ngq*e>!@2K!*~{yU8Kj*Thql2}LO{{`&J%<$uvh<1Qf|C8382OyR4TXV6^ zIw82pfUQIIoE+it5l%S2^n} zRNAW}M02bnk@70Xtdisns}qmQsra_w4EWLbk=2T(oMv{^2$~^`!p`~NG#lTYbikYn z-ieZNz334v?u@@I9D{`#hqz(_aWv%MJY+|Q7B+r%+KFK+#aHz47w6WJ_|wlYLR2tW zcXrNroqlm?1!l(yr{a4=oOoe;AK@+N$~c^qm&UI;C9#5i-l#;;PAK$YX?(9OC^$?ERYUuGB*6vV3GVgrA=%GEPDTzE3>iI68cYjb)r7vP8HX~_B~G_KH}>J0 zrs>z)<2P|wVy$qdnYvTy_V_k0ux1|v)4bI zA|4jjDuDe4L0Zrj0p@k91gop)Wc%HszAl)&dU)I;DD?(tMb(8vZ%YeHKxG5OfY~Ve z`XS^KhLy=gCZl}WAqerk@vE4O4id0LWdMC`Qti;PE}cSuxZfB0F4dB;yh=(){+C07 z+hfXMr?bL}A5xDWHFf{#_$|_cKqM^=4FQ)vf^bg9cTv9jwLk>Ra$jq4XSyLJZZ~f` z-B`l`%jC2Pb3kzdi6;q)sA?+tyV7|ijZD78fy|AD42$*KaZepT-=peO4#8XYaaV12j0 z9$MLffF4-Eui!p3Pzv_fCM)b1;Xj9H-8K6d%zf}41Jau?A@^?sNmNc!TG(ob{y$GR z0{Gu-y*C8BhR%Z|N3aEof?xpJTb!&i-9sy5$|1w^nqYB+Z;f9Rl))*?cH_G?CjjXI zizJ1YfY-*M!Dwx~A4W#}COQIE7+{E48(wJXV8G+g&y-qbMp6uDt?8FL-1-W)YG zn}5q{U9wu1tX3tfMadN3L>-(H?^~ephrkto!v;z$H5O1y$u!5Wd9lNq-)kHZ=*f&R z3A=<)uv5=o8E=VQ599MLjML4VKPn;>7*1k6b@t)JG)#&px@F(deUKqc17S`m+ zt?^y(mua>8eFnjrhp_+ZU|j^@Bix#FUmrm;?m5NoadsPG6v-X!=3Jt4ICRMI2EA6c zR3~7CK@G?`Xeq#8e_$5!YLKQL#2!$OCf}*p2adG%$rV6+@0-6E``$NyX$H(xJG5lH zUn5w+E>Z~J?fi=c^~Sd+$KDI$m+Wh=UMiH<%jE2Fga(i`kqYeO9{&vRAksSKJ>tU< z-`V;uY~KGIPaJ{$dg~YWtY7?D*DpS^egHGOe*a~`x)4dJiHZK_1@+FYU*|ue#g$gi za=QrQ&ri=a2O$ZbUb?K4WnLSvZGaQtrV#~+AWqzO9Hi35E|IcX^BY6CcF0k0l+m`djJ3c literal 0 HcmV?d00001 diff --git a/doc/doctrees/howto.smime.doctree b/doc/doctrees/howto.smime.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4199adb8d7de7dbd6fa83b4babf5ab0036797dd6 GIT binary patch literal 88860 zcmeIb3v_E~RvuWdd+Xj)Rky0Ty67&ts_XQv?!La)*LvELt$K9nY0I|cha_8ecj0>^ z9lfO^pL6u`q!VD61cFE=!7!5qSRs?OXdYo8!x|<`nuKHqX00qB1PBW<30WkQWCfVO z0278xnECd9o|0urcHMe(74(u|NZa1|GoFW|NVdc6W?*;kw+h)e}h{EDc@Er zb;Z$?3Zim4xIqsZVpBc+_S3uHaQem5xxr0Y=qgfM&WopmM^GYPuG9;%*gSpbbgul! z;JPZvCDAHhzBYKy;oy(TQdgB0lt!f?22RUQzH>U@1XYzQxweXqsNu&e1qF=^p3K(; zMZrUSzt$8Q+P52pcFX#a6Y@1#ENW%&rBXN@JZ0e64()hDvz3rdHItXnQqquWjw8w*vgOER|%T z(Wo>_e9D=KC!&0%$#3`7vee|e6}8MKJYm)~!yDRqA}#g^!V>^v-F!{7U%_iho)wUj9`1lN;CBn7Lv_ ztQU^z6(GSNk)dI;_hVn_RoNU_RR`CFHbyRMV|AE6Ex1|EH}g`fFIP%sus4{l?65zvaP^na^-(m+L-#y7^q6 zh{iVg4o>U+(5%5vt6_jUy`VLU{|*3t@3c`EQ*sl9zk6C?nv%h+Q$j83Q!;rDS5VL{ zHE!5@m>ak>nccEP;DWM1Ys5mOxzJ)FaDhbNf+2lR%P)(DbebEuS@i&KtItDHqdtjH zt-dBg&HBU3glLy=w*f0#7xan0K6pv&wII`vOfD@P<@!fVVtw(n{4?dJl)=Zw7QuRi z0xzQgX!bRO6pYni&Ui3*I^I-esnFKe4V`RX3C|RzZq#t_ag}cfH4z+~;>w!TWrKeXQN* zm42fkLK(^P`AVzI%0lf>gp$Y?DkV|T8(K>Q!-|8k>s+~DPU7Na@Mtjo4Py>0iOao4jyObTgkuF1C8b%af5F1ic zQDvAJ%Fv>v>-|I8z9wkEobRp?a|)^s5G3gGKK+?l?Kj5vQEPk_LIzKR*R1tRFjnR> z&uw=^!#EImEZm~p6jeTfrHYUCRIFvNAr$`eyRk6u@w(kuWMW|s-#qW|3pCrE z3T$d#;PWU3dx@5*uE5qUMZ_{iOO-6<#Y#uSlBM-X#$Z8E1qT-r6tTd=BBbT8CAHdh zLAC)w1r-%d2y($#=&U|bhbv0;y3{2jQ?p~4ErS)0bw%qZEt8czAS_BUFV>;=$Wjvp zw3QGQIic06SMmbcxC(}Jk1REeLVtAcK7Y?xHAw`QWVCvZhQ-}$O3ekB(d|No)#jxl zFF{qWH1F|qZH0ikhlRGH3Uywoz-(86Z{^ia5ZJh4$XA}r_2qp(JBjIY`Z1@+$fJ2a_rVH z?^sj7REMua^OIBun9$WP5C|G1Ooe;wK5w-$pkHI)tiFR*;M#HI!?S9fPdty z=(BoZ5dSxqfcQyWdRk2l%tuqFf+rIcI8vM@C~z-sh<(it4~w!| zDU!ATm%i@nIOnZ7)aoB-X#YL>Gqci4>fP^{HJEyL+pgXX{#sgs8YBV|NF?1aut1sz zbSz!)-RJvKn{SGEf+Fx2@HMf|w}gt!&#BPrIbDrYNSP7%RyzmXh?OBN1rJDRLHnq6 zm#HymCF@vnt?+pZ52(v2LZx7;K9K?o65)blxWz&dlCfjL){5U>nht zwL>giJAnLbz`!kuO_5w4rU2EJ11YBp@Y36fh_+KSbC9fL_+;gLMW}Q4tTHg~cx{7_ z8JD`vYTA2)_(SW|qNj)1D3JBJiG=;qxq~%`{bT1~!vdHwz}oB#KoBtoxM?^6?8=7i z;TY&=BNFF%MDn9FUwJHzLS2#IDC6;|Q9w}^#d?3i+6qvlqT0pwy@QXzLD3MJSdBGj zjB=k79VG|61#MNLJ^X^Pk#71fh_aMEoGuMsC}67{{uhuWQ4<_9aC#u#;66voIu9p@ zEYX^Q@A#d{gT3 zT}iHC5s{^KsjSbYvHzn==ZJ%0fygtzDZ)Sye4;Q#tSrDSX0%d)6IH0!G0&K*mMGWz z(o3r#`0?9)Ev4(!>Qt0=chyJ%?w8r1(yP}2Tu}UWLSSv z1;Jf>t}Zld9IYMfr(PI3Em|?gBVdcBD8SFpcZ7OdywAmptSJr3JB~Z|nR3kPnw9Ee zQPo;^=qL?KZS0F6G=zYj^8gB!(3l4m-Q_X+rTaD z@1kf5fG@Cu?*ts&CJ_+1>a}*o(tYe#t1vG=Pj9#6lF+Q2XtQK1AvIc9D^bYYve>T_ z;A>a-Z8Wv17TyUMd(cB|z!#rsf&{Im^!PTtzc3Uu(1Z2*U@Nn00FDuAp=>E^ZHO`# zrLZGDSU{wpf<2OV0<`5J%5RH3f%fbj1*xIyH&@&^%pl;hD{j2v#`m2YO>Ko)6Mq3~ z@Fa73aI@E_2b31#eGn7e0+&Da^nr#dQ1UUL$>0tGJVf56ls%`R=@>g z1vETw_xX0y^ljXyKo5i#J+Q554<5YELu4^y!rq!9){BOJZ@im`d>b|&9$U*EJYZfB zwzxld;DAyp4lQk1tw5OY-jNmsg@7Z?0AM*pvPJm5D9Dy&8o2xrZTi%^X$2GTJtL|V zMJ?-Ukxd~QJUfC^!}NU0hH48aMj+omg+PcBzK?p>fMDk4=EIyU3!cHlZFdaXs$arL z%x$z=!*pUGOY^ZY;;~?3xca-7z?JWkX*ZOr4iB5zzJ>h3GeaHI z7RoOZN!r}j!!vscKKK{2&n@-M_~5g%joCJkS!+xk;e~1UcP}x%Ycw4J8~Bf7!p32L zHo7_(qO0n+0V0zZUukrh&7<2mx^;G>|1?;0N-2|P7`JkdPhR?}-vt1w-%WV2R=Y3Q zU_7(hy`7eLM5I=V2>ziZMS_uqU?A)x4U_eKUhE+d2v!0WGXr>RwEoh$E!nU=p%9?_ zIEHsV2V9swJ~ahfwsnAdX7vB@^9E`g#Q9~$jA1r9`a0VjVN2IeN7=>=%O#*${Y{C? z;{_E*Z+Jwf583@;Yez4@@%R@(jFR?^e(fQm7;-DXd-*w6&vTa*p%*C-0TjDryO9&+ z0PmvLF57D(6p9blONf_J%Z&ivC@k&c8#W}PX2g@(U>qJZYAO6?YV|(9^`>Fi-RHx} zH-{`TC$q@jJZpxTZS9e21M|{+KoBP-l@E!~cfvP%K=dc_{BipA1JyA&b;rO7Vv5*up|b2%YhYNz_%C> zfP_T?V+EhSfFIM83;0*4!Lg$dy@5qBAP9kFPrwCa773rr{=gz!iJpLuO>w~=a2Esl zb6O}e$O}t>9D^Ap7ncJ?%UWp;#d52`st-p->k&VF2`>g> zE=F;|fF~3P`$1MiZRyvsi&{gApRii=ca@>~U+Br2Vjq;y_fP#Odb zlNZuF;Bs-}28#e*#D|2n_-~k(%31V=gMsvJCdz83E-d>&viaqJ4~&`%6hS)qzzUdf zh4>Iu>jqOT1@bFINz33vKhYxi+yoUIn*(nY0&Xx{feMJI0$K;@7Xuzoz~iSW^*}~o zCPb3?qKywx9?g=>Dq<}lUR`ztmO%8&1PQ7aT!Er5kjn+YAp%6wa$sr2>fMXCkR2;j zWyQ+`0pLMv;Nc?40?0={1O$4?2ZVgUTL}0Ut?KBDxE*y@h;0CB4w6C$2wtK}U_)36 zco;`5g7^G^LNVa7i6M*y+zyEeP;& z$xhjjVJmm1Tb4We(rh&t?iN3f?c%yfw z%%;s7M}0GI+zV!4gN0GsxW~R81N&?~xW8bdoKYX#4+5e~hvitL^S(vqoDIl1^W?nX zovX+lWD&ZG+@Z}aE1pK%@cO_acXo|46K8{WOy(LFzjMX5Myxx+;jRMit^)2<{{0NN zyD-}h>wncL8pBxq4>`5Wo&GcW->bnA&UxHFXS?5~tlb(eXwx}H-=Mo5;5>iZ@)D}j zH%uA0O;w`4nX2@teN!7h#=te38uTR_0!P%K0Y9>(Z3^GfUG3=who}0lP8sposr~^Q zq-Uo3AH}u&6na#rLJ`E;wzZj)LW>8z4=w(UvwM$kJ$P`RQ_6?{rr=`Q^w!GI*0{cV zsh`e7m{k{vCq?72N%i*;8uEsTBK!J8jq^i|o5jYoZv}4Mn|)9=lD$YRp!7=<$@$~w zVao_;_~pzCAjP>2O9!`T0F z35?yp5RI7(Ik;H8F<6*Q(EKeM`(lR8d~kzYP;Ma1o@F2+#>0*qJM65T)w7PA;hYp5 zFrm8mW(7{RZ zoP-k!giqwSP`MTkJ+;a*vi&UJY?F#;2(f_7I$BIACZ?|y1y*U6@;Kih-*fQ6W*-~D z5Q!3x93-5Orz347eU&y&vI%T9={STD6RS^-5fW<%Rc-n!>V1}>p#X;pb|Q?4Gz*y# zxYR*~BKdF#1QEa3i!RW_Yhkn;D98|^NDGYfcF3@5L)qY_i5`P3uQ7CuFya3_0~7wf zHpjoiih{yEI~&5So@TB=^uT%o^O5(;9$Toyho;FttZ^@F&9xTWbdUN+9g{)CC> zi4#-(OR$CAmz+F;{(@Bn8<7_l}eIFDk_jdrvFvr``Z7IM_o>wU^T z2W!HpDY4i@ibZF~j}atArygHt%~|h2{GfK^1#GtrW}t(SblMH+`*2p7ozDxf@KJ=l zY9XBWaqLiAYjKc7iwu4prx}|X6ljt&Yij*>Bs!nTPGjN-Ap^`_W6pApA@=@O8BuTGmEVx}<(Y48;Q z?3lT<7K}+bzy3aI8WML%(k?;Lo~2zq4YwXO3iAYOyLLRm6qlj+)`JHDh{xe4+EE={ zZVNfevcXbxQ*FpG2wYYXR*&@xcH@?o9vli69rMAlVq|n+`3c6CH>E$i8v((QK#pCx zA8I3EhfE$HxQQs4hmjeaP7*a(k%b&fsak{=X`x=JLB=vU3j4j%K=yH&tQ&10kY-Z1 zNs9<_gf~kxa$VXEORGyufghfow|>BoUmrhjl5Eo8{4$^iYRSH450B-!(U~>m+0*t3 zxB6nz?58diI=)yjZ=y*IG^(j{Qyr;)P_^66!#j_XOC+6`1c4qmZ(U>N?lmly@o z&&|kfR%e3?RC*ZW`lCyX>*bMg4M_#tP$rj~3jHg?oG>C_jJbNr&K5&uEJ)Z4K67nm zUB%?}}W}(JqFXoHdgSo(YE76BPe%AV~XRYAV$j5CiZc^yflG zSJ14%jIN)xs{(^BlWuPwGQ>Ju!0i|Ig!Q;=h1NvVhX{Y7WP~j32 z!=%VXrpAJEkh?^G7bFDY_)+Xy+&f7}{(00i7-VD*Hv6ZbCbL9NhLk6TQj&2NGQNd8 z{~&5?aFWM_v#4;-D4bxYux+vPOA~?CPtbG#h-y zp-uixv-LYjgAXY|rI7iIS8?r;a_26!m7=V*q;7BTCRZIC!RH`v+Yu?db9d}igp5WD zI4_1uaZ0MDc{Skp(1xSiZ?7|t1`gu4Tlh+SQsaOII<|vT023R$=0lmg%PCrKaA3{d zq2i)!>{X*X{RvA!b(d@TQCo3PsW~*LqtUUw5l;D!BGGg(ycUhz)fwPw9>}xwLC%A@ z2r-$XPLVldBM5MfmC0vkA_)EgqI>;VFlcYlTr>p!9?=8;nx7FLyBz`vx1`)XzKa|A zS|E0~^_a8H;7^SdH8MhTx{HjCFPl-spfHXX& zmaH}hXWs$qRMW074DVrm{5&KZP=C$%Nw9ilBl#;cj6}b?z#Pf5BlBoAIXLrb+&G5P zu^?DtJQWz@_~^LTR+nrPKQzNAbdRDriWkO^nbquI?CYtcflbH=)d2o+{IVKlu>QSE z!1^`g3EygYa9)Y25Zk!N0Q$PdPFCv-?tgL#xV@KQNK(TZh-cF%{xxb^8ig&` z;+OQDHKweT8pknSleAPGKp{_|?RuWR7geE;S5cyLfaKY-y`v^)64_jrIG#O#sU z{F~rM`|>a`2Ep9%{C7h{KAc5m4{Gyk{I0%elEUbiS%=-ys1^F*D8bUc8VJ_GQ9_nC z&#KgS>4k%`phDM;VS^gGZHyW0(SToQLRGevOG^QwYVDSQNd?UuCB`aZ>_6gG3(8l@ z8dmh~(ZPMb<-bouhmwsDpr$%Uy;9uN++9ssrwpZrvJPtpTDU6eO1px0Kr~x2^rQ5SS=zR@HWBoZvvrAs zZ(P3&2mik|C`S$7-$EXw^H_*GmuI+XOu~_^ykO=xs+5=NZ{D`uL+9)*v}$?9&s%`JLJn zH^xApwdycBCXV=ZmUQ>c+uC*XEx&TxLMBXo1xES;(iuqrQXF-0SH~rj+sQwGUVK z`iWGuyVkXLQVYe(>nDf%OSQx7dXPKJmdm+pNI6U`)p8zJcdeXHCeT#kB+*Nxqpn0G zak9^z#fP6&L%GC`(&fTCtoPMucRjs(65UM%ml^2caw48iuSfFDdbhB;+>2F%8EpuO zbYw5lNoVTG-Bc*eX`sY=@pP~lD%Fn5waV&B*A)uyME9f3WIfl|t>186^o(ewf)3Nd@&O( zB^$BqPEzSftB3QI<8E)Wo~&~Hl|hV%JnFW)k>N_rZKeStudV9Xb{=Dj| z?}+7`*Rx+d$nNAeV!haUDtnUZZS}mn-10#=wOs(kb)&(cuoY6P;gE6?ED*xhb{3V>xFoCcR8_k9E` zO8M2@OnU1i+F9?WmfaiD-h3^a)~3&xJ?^s8XUraVq3Jt_hk}t{f(>ss5e=n-5iYp1 z=1c@#CU=3kLZM(L7+hQp1=l2RL=La*F8hk9^j@%2tYix*rMrK;p@yU7%-U`t%%wMD ztM$clq~=-eANGV;`}nY1$?Tpu*Zj>yCEstvJ>A;L@|v^TUyGHNSG}RQSkCOWs-BMX za6fy%iBcz5O8KLQ!OgwBTBN#IPS&0A_}YHKx2ksBnXO3CpV`gz)VjC4v*Hxf`|&hx zQ%}3gVtczO$lP-Nq+d|BHWL_My9%Dq9gq;|9z=$*eIBy8Y0P3^`#fZGW0_@#VS7l7 zN%7Sl&~HcfdJuw#vvXjm3*j*&A8WD1&T=-A4)#bcKtA-6kxVy%yIAA8kl{2zT8lz5 zMPpl%xSJ^~M|<&uY;os!Ih2mIH}>V!wzraqS%MT(y&gG<#S+m31WM^3Zc5~Cz8e|( z4Z&Fo2N|7&H7Oj~fj}+A@GQR?N-0}hup7ta<{+e@0#Rv{xPm*GU?{#C+-YT&%dw2Q z8IJkNTOO4Y^DEJVb!WVBd|at?=R>{yUM-W^OE0_ka@B63xw4*0`{tDsHL71i4Ub!BWQW31?L(JZVCR)OEOzkV4(uW72<` z1F3q*8}@3|bs?u1olRLVYfzX}V&T!DIH`jmyOxgm?X<(2n)lAyQ6sM{ZAoKmSldZ< z(4Mw~*KQxcrVpo`@nB65UYO&`7Q=M^B3; zj}87|K`-}t%4R$zfM#5f3_@-;5tCyQfhfZnOeeV4E1-ZKGi2Kw1eFC_)7glVfgf)B2&^X2veuWMy#ivcQ)RQHR?|lr~O_RMa-R?UP-# zG*XqFYaQthd-NpuhX~KXTcpF`z%5-Wz;5iN!@OAQhBiIv=BAe?jn77slgoh)zjcHT zhmSU0_)eSCDN|`vZm4Ib+&nir12*{2zMBg3^JgZ|pyOwTX2)$LC+LsMn~}Zx&V!j z0_bCu>+80|sVQrYR{!>WzFtAf8;^&iA^$m+6njLWqiayKinjZg%ThyhHcKtVN$aDt z;c*&^iBk(=x3%qBVvTE^vL0li0&SQTJc`P)B;V)p$5DcoEz(cuvqp1z2(qm#E`Y)v zFsxj_<97L%@LzyMy7Raz9l=AQqWwJ5dc>U;GF`=zr-YK)BVMcBs`-z!?S9;?feSnK zwA;kAm!xeQo_kvhhQ4}*^Y;)E=<38Px%~2wmF0SgP6Jm8qs!{$6f+URGF>M)&8J>&1RvlKH)wdpA!}nsEnt>} z=I>+5?Ln2pstDz&v?JeG)St3FwL~~u(*N@m8nP)P)HhQ`{?7Y1sciAl0*)Wbw3-Yw z`0@8|5Lovf;tZ!VfX;QS z4w+DJ48AMhYKr=}_u!a%ht$Am)vU8g98D=CG(GNeHF#dV?Yl-Z2pReaA@a> zhpu?&GDlBLWq|3UZ()U-wDULCrYYGMxKW#C@Zoc8Z(eE{|2F$5N0;%R$FAc0d$QsJ zq5ciq5dwA|W849R1`-a8o;|QvJooGYogxVB4Tad}BMABrr6LFb&g@X2f3H-E1{3kM zl_33HJ?I{!tr&l9T9AKYx7LjzhM2|p_d-^Te`BvIWJ4{Apm!xwJKcC`G|+#qf4HA) z7AkYZ}&J4Gukn5dbv~&;-3E9K><7z7uJ?s{?{iSO0q!?6pDrz*< zPjn@3WqvcX)%7VU+&$~#V)bNXJKU_v>CSN^>)lm-Szjllro#tYjrrqB(%-Ib*S0b~ zcRuMaFBdup`G^UG25vI{b%BqaVWwbMH~$$lJm!X!5575yQNTR zOlJRN!5}q8I#iT8z<5gM?qsb1QprMSM${N6|!bQmdUP+W&Y+AmKkeje4m|U&)6C7 z!3pfYJt8M&^Y{I@9n2BV8oV$j0>+RqW8V$q?WZn-x4&Zt=dg3v-aw|D90&YW3GHgn3%Le#NZ87OyW4FJ7 zL+JlWb3z-zvh3;|+Qnpx70(Eq_C*a3?&VYE*&<=jad@K}jYf?Fd|&ZC@G#51h7D*{ zr2LCW>R=*LZL|>1OYwmA6pDz)z;eG&xnP*%d;}jXMxUnRYw=3aC+D>#*AI$AG>g>I(aRV%R*=X&R0DO`y;3;AwgKG==z94{jM z3m5Wb>={@zl@lRYDv816rQJr>7tHP?dO1!EMNXWX z>teW+_wF8N+?j4%$!#Q#+i}I6TJ%M8xyDj++rLyf*>1M0TeWphxii0+JUQOl4@MeW zb#6Y~T#X*Pk9+BUp&c(}B0*0xR0?l8OMCsj{=73AUMZ;YMkbT)slCn8ff{nPtF=&4 z*%G43t$Knhb{12s32(KwJHO%V)elyEYilQmtGVJqKe<}<9QgZ*L$|!?ZY-yoyU9i^ z+*dYM({j5YCX2pqdWBo}b+=X`C!6VtbmBd1?#bTGs*>7>BV|gwwb(8lC)b6|_P)R2 zjj4y;M6iSjT`q@m>&kNaa9Q2t_MEP2H*=htFUk4RVKleWZxr)lp(m8pNT#?}-L17E zEv0vOvbVQdONEm8+)jJNBZc}qd(GXQns~rzmt2OTkWi&yP%9>Gaa!?z~%F zuD22Axt3g6URjAJwmp0Ok}H$*`D4eie(Ru-@Z=jFPN@dtiyN(CC+%`&W64fwvyCmh z=!UYQ^jFhc{&Hn4xwDavEiT5EHV-^SW4n>>uAJ=W+D>;wUWptm*Imuv zPTAw`FU3|}`PXyZ>P~J~ZAQvSu+y%4Qj7ied}F>FiMWMb&&FcS zyBdu9H#SOJq5ZULJ`@Sp^UdWTx47Q+IS(?qs@Ho^Pi(K3nyZ!SW>c!i`mSx)a`7shRoZQa9rL>3i18i#?py<)0rynNWRVRN+PXP{jv3a;h4+i=WEei@i4V4q>laV{EE=q z_oXW?F}S_H9Nk+}yX91nqRg_uuSYBSmFN53jm^$l&9!o{>5FjLMmkcO z&!j6crMy_(*l0LI<$_qx?Jlk7kj<>R6pR=AzC=-8o{u@*r4?~|tE23%wRU8u6yHfp zTrXM^df~=Nw6yKY`SLUESJ-v^qICcJ?;&I|rQ& zw|ZDEI3t`;c9vR+?PfvgclN^3c5J)e-tR{$3D;h&yH*N&oZi-Y{2;a_^fr8p@wVF7 zR{Gu*ue^pdUyHRQ7hDtCzS{oAe1CK07)W!swml~urMu(y&^EK`O*>b;xmBgnsb_1^ z;)z+pOk8$>LIpX9!wl8`B!V*MJX9c$m!#~ z9naSKPQA00%GK-J*^{+-Ay^SQq2+zpBwI9aQ;;P!;tSos_oDfaN<;9La zRmvvBR@R>`@3^-+&T65cY&hGCRZq;j*mh-WYB#(+pOJILTGZ2!@`Y@taMH^)3Y>bF zI%#frj=QD3l(N00Ac0**5L>xswUG?PVj(%RS(Y~vR>Yq3No z-;@jcz2HG&FPctfwwhd9?(YRR{CmZ%dO&wABn{Zv35FsymQ!B z7Edq_kw*V`rJYq4J#I1S?Rd(yy|qrHzuZoHwp7mwS1&E@EFFj^yY6UJ*mpWtO6^T| zD4WY~$mwW7?TN`_cxL>m*5Otno$5wB^>S$W#J996XIEU|zRE=t4PiI6dJruXm&$IT zxam$cHntKnsHC7C{q*{ElUvG3fo?Ov4 zpE%~4$Ju&gwd!5(9{aN^&UsHLa@;AlVzKN}J=KV-8;3zDw^>k>YHZghOY6O@<6UL7 zB6x(udDnbqiQ6le3h}hsjMhu)T1XHNGfVPXMCq0a;^tmxdtP4MZ*KHj>+`KmHJPk< zmXz&--TZ!R(-)Nso~1S?W-ABFtI@bT-}cMLq5W2VWo_5Hs06on6>mG23uo$L+P}D5 z6T`WlXVD*Tgw#qTuO9aDdH2?`kDGVxRM)nBYnik^mXe&YM%pj9J+72@wcx2%daGrZ zukKu_RF@8Yjdj7l+wiB;xm2~?a%SVH=2n_ZZ0zTAad)%0w^a^zyuHY=N8A*|dBr8| zNqN_zJ1_1EC&#gbC%x%B^kuThnW*n3WUs88Gw~@`R?d}`b7kdRSvgl$&XtvOW#wF1 zIagNBm6da4<$PsYIm26FAH^=wg}1_f&%Q}?CjRR=+K^sAP|JcI`(z6QWA9i9m-TK! zL>LRYnh+885hJ>iLTI!s7e-9jxL4-Tt4`V+Ln_A$?U7Mb*gdlbiwawK48gaDcfaBE zi>GttYlCAwMG*@DnI-$9sE0GB5oBUsu8T`TamT%)%1G>?80Vbz2s(y4J=sUaxDtk9 zofj_DwJmz=f)#;-*G(LZi*~+=+)vuDjH$TBep_9#J=h2unM8QD7-#B_#W)8j_t51K zW%WLIH?52r{cO?E&c|%TGrF%@o_J>aLmM5fMN8Qt9A^%aW(1+dM+b|leh;0-FSw-+ z5mk4nsXP3eZ{kkQCeA{?W(Kz-G?>4GbU1fLueY>cKZ$^Cx&ZW?i0iA&nwQP2xr=bt63y#nQ>5Lbo>|C*5$Zmj5VMk;Vn-VYcZe z;3=s)sWu|&>Cc(mon|me#|*N+;yId(E1py7Hm?tJHruZTo--9Mw)DRbGBLzDT|Qugw}vz5l|ndjIord%8vYeY!(4e(K&qxs9zUK%9~p6q#XN?($Q?%YD}yv;-#DUQ}%Wv zxc@S|7L8bKPr)N^yQn!YoiJ?7-DQ_rzz$H_4VYY%Vc)>knL(eEG>dRS|6nZeJ(hx2 zpN-*h8uu2k`vF+Gewwnm9&%r4^)boz+W?Hq42ECMluOH~f&)6|5th~I8M>g_wzEOh zf_6U0X!h(J>K*BKLYqWO70#X+(##t+XsA2mtR)RNyd1vc`ZLNGWL!SYe@0^iV#_ln z>Be5GoW|LXs#IytS^SI4y0>+#+xjqX^tDyj7+vdR92*#DLNgYMhS4(-y?Q++Ni;m$ zDSR5|*nnqx0 zXU|DKHiSxjym+KujN8ABP8`SWiaKXnu2-^J#ZtqNb0w=s4>S_FUdif)B=*vtz8sBX3vO&v-n3m0d$` z+JsE&=8@#P(!|kvCtc5~TZHCMT_vL=;IIg}p+Yt%zF~mF-72c?(+tuI3Qo zucx%&hT4mq;ACJvcwp$!+U+6OrqS(H^O^vtcc?41L~UcMTT#ngQdE_^&=UECs9+2w zQMPh*|LG5Qh&ChggN6i_+fR-deZ!f;pSI73;W4>kOp!GbMvXr+g&J*JZ`3Q>db`FZ znKkqsk9__S_D|dM)ZfekqD3Jlh{mH45P$6wAik|TPjs?li8a8Y%q2J*;h9W3cx$+= zi<9u#37c)7@H_2HKa|v)8P+hh7nB7`t+-(D=>q&Y3#3`vw%LucyyB#?MuG>;siv2m z;Im_HuL(Z8*R-v6+QX6LN(otuaU;Npx67E}naY}ouRd~|@iO~f}5Nf#O$knSB+$gn5s|D*;z*Tf& zE1;L5v9sDF7d7T1K?th~a*WVH&-HfrhM?xl=oHT&I7QO_jiOXZg$pIuMhXfblB$s` zH?RBCFZi&e;ydr@P%J(iyvH43&Yq^pwxx+5mT5N(v>K%J1j#cCKqkvxL=%%%R+}uN z-k2==w1NCd^JMiin63QO@!*oCk*PNZ_RP?8t7kUCxl4@j?s-JTgd(|4OtLarZ*b?l zN|1g-RmO~THsSU?B-{)}#Z;JqGuc(T>4!87S!~c1I$)rDTbAjjpR5CSLfQbRKpAP_ zQXsX0YeTSiXL4aUh@YIIU4jNTykxL5E+CQlN&$^kRCpRmTfxf;-1TtU+gcWJMF~`r zGt;DXVK6ak4c)hK8JeAw9sC@LMe^w3a*u={=gYju<#O{yuzMT#nt;0vAT-G6<{lc2 zwIhxqiAr9U6sf3kHk>QCX_F)lgPB3Ev?K}nsTD*)s01~;3k5|Snwx+kg1-5~f>4W~ zKSVHr5`z=P&n4M)eRg)G{+U4fkqc88@$m;qW0utT;S0n50dvRMd7n*q{f+a4*Wka5 zYnLC%?IvAzB=b@i_c#RE%}26LzKlvPx&uj~8uuaZxIAjo<&7ksa93_uYS-Cyh&drw zM;{3`3P~wx1@R{-`CUwF#U%D7Lz)vBC*)3)%*yjO;+cOTqIvQ7vn#? zUlyS$$r>((G*1$fwshotQxpqWB+SKt6f8rr;Bz+@op00p!`sKojBKLF*}=p`N3gww<--@)9ezE_JU?_El9;tGtg%J zS;cMU*@z`LIcS4fPZJEl&&Dl-ni!5W5dN$y$Ix$QEpAR%^{;Dk<9kL(bRwmd$qf8! zW({Tr{>ZQy_#ccQXwyM&qkd}#C%#|@CfE$3W2!aTPq1sMKdjNx51Ev4k*JBkO-yMJ6?Qa#3!&OZxIfIZC*L`>teC+U@7+sEsu;L; zj}PlpOWa{jF2u(6);5@uk0*lLu=7=lgH><`qNYSuR8AJ*3=lgYC1zXXB^W_@6$$_- zA}97GvR%kUkcS(U7A+ROxVE*Q-qKWnx#}O-AROE@Au@RJ8iUYUNtliKQ^3tMEBg1* zE^zT>RunYV89zog6Yu3HO(8K*$3yU5W7)ugC7>szMgMUkpr4olzrU&B*Pu0W_?JJK zv|Gu88d-GaF%g8`h%MahX&n|Z&Wh+UI-^1kh|z@#NB54AqG_`+SqO$nssV#u8t<-8 zMh+L~)tuexZxFw}TK$*w$L1rNyaX7k<4+8;ZTXSGvtkoLDzx)ZII33^_4M0MhxvF8 zg>KTDBV>bZ*j{H}A?Jh{(SANwhm!dk7xS_lviB&OhkMQKxkp%rCm}%5OJL!qqSX0T zEw8ve`~ogOrO>Jccmcrl+QLLh>FEhgnEB91U(bI*i+)*XVq1p4Jqp=vegXb(tD2+b z_MqD+t=)W7>ueiQi*!+H;0>&TqWl)8AEP3<)zaVb3sdSaTA8y6!kveXF1-s};Cg=3 zc3L}sE-cYEcgFK+*M~)&7b4Edv}tWS%u1RD{=Z5_V@gLx zJfE0CJY#p2|GqKdqk-RJ7P0E@X)^eCOc|`NN!8!S6O&Y)PpJarmbrE~aJBKUV)Wc- z31eQ)zA%SaUBd7{oZcy;gonRui2a|Y!8xZ_m~miVABJzGMh*bdx#ox??((-0gIc@I zSD?JZVb0#<+lkq_;^Ahr~Y zhV32Vx(5$TeTNhmY?LzN8U=81lF}vxrC5OpuCNBlw`wDcGZLuy{`AYHNIQ3P&x|mU$BW8_S|9PVgz#r;XE_+-0GCACf_u}9P7S3tyicbTF5(1 z+6;4I^>@K~<~V0lX?~U{wmZXU&RgBi?`Cj=tOyl%UY-uFBN!@I$>R$)EsK@jY5Dr# zx`LoXe64zLo`SZX|4(fJ9X9F`Umo^K{kf#rLs%Vr$;?~LHYYXiz)^Z^Cn6>aRscl` zz@vfB+8zHG@OZ{bA=6wRl^V+pr`Hw>6WGi1(#) z0kX~EghIgo-va*aX4^1{;zl(4zzq82tcO-dj5zHHtz!&K z9I)UVybtqp7O&^is$DPo$HWo_5yFf0A8hIy@C#*aZdj!|Hm^U3M0e=~i^R_8!QnJK zb3=A)k2dOItFnXN%x;DG$$lW5g_*V1{A#AD{u{3~fo-=T@6HT@DRf^tw~B3=CKLja z{wbrLcS)_kK0CE){ekBmwUJWw+cjU1_Hwo<{zaPNf1*J@WXMGfL+;&7kHMi2r!iB< zXT1F%r(kQW8S~4=a4%rS{5(3+WYRb@Ci_L$*>R*@p$rEmm4h@Pc$pK&)aOaAP=GB@ z3jxAKY}<{_-U6X{AulYDYmGu-p`h^vlF_93_wlvcqytRQUr^Oz0Q7=DK0YaQDkVXM zi73{GmkO-O+nd_u@{86G}>^XWmk6)Tkt^ew_0c%;V9H|L+I1q1_nfaLMPl! z&a$eulp{s%I9mM&5AJh0XpVI(4y?_DCoK0{Dh@5ti7W=pdRKC6(=i!F5&gN7)kRyC(%pENiv@Cg9Q${Dpd`=_oZq|ASS6JpBM z8wOk0#HjTQa_8BnXw5xOYBC-&B#5!bLb4cXSR8 zUpiO38YJ@KSn+EC&ZuMO5}3`tR|4FEZSdapaSlE$`(Q@dQMd%=5Z0^P2NM=08y03O zZ;og-we43(k9lea=yhZDj1F^tH`VWlzEk}H`uIW8e6Cl2h`vuYO@DF7G|he#OYrEn z5^Y5{p$4#^2rT$U{5n5QiiLT?iN6P6?&(%9i-C>8kpAQ2+!|lw1Asb=;*t;8peQw^r z8K&jzTfjF%PKKdvxND3E3<3N&D8d>u6SseP2DZ~T->4_%RM2i)W@qRq-tQcuf{%ca z75Qb^M!{IZVy^GAq-9!1gU`RG6nqwc=gShiGvQwhI}@yJ-|Wkf7R)zIs=YqsA^y^L zKFHGr!9nO7^6d|Ka4mC7^C&3HL1sq#8$4Q}oFW3k`Yq;XMCkS{FXRwV6N#o4qLHX~ zAsh;8q5pK|2LZN_Vg;OCB6F{=>j?~c945J3~fg3d@oOxuCq7y=1KQk`m)jX`jZ?)CBB-ISG&sf?N z_0?ac$;E~0BXc~_8fF2nzhu^60k8jlNPipr=Q#PEa7Ku)k;1intdLfo;qKB^ES! z3nlGOI2J4_`?ngE{U0XHTqG3sw}@p8avM6D{F!kq+b|BYQ4kvA4Z#R88H`lWX5Oqo z*?05`6Bw3J`UHl(ewd=O&jv>tKP_ZDg4=8{qCdV6GT2dLvj$_i|7)1#ep>67^b3K1 za0u@^{|32S15RhR+jX4afkTo@Z#_6V;_tO&snE`=_n>w_E71bY6`m?_P&JGkf4W6= zeu_T_uXkz-1~oE=bCqUCsv*Q&_w16MBJf=?H*`!!b1dV0w2IAjFsiAm44$@+$67;1 zo&%9j6FzN`n&pBSA@s?~crfPZ2^zT71zVw@Z;$~t6ToP!3$%MeM|E5aF%LDv*(|jbC-JrOge5+7Vue#BM_FyuiOV^}^-^9IGK#3(HaSDE#HNYm zwf3n?MM4ZOk`l;up+!7Oh6SBWVb%<7#Bc>Ej}YdjYCGfm!Wft>dK`>>jqyi7c;~Qc z@=}nT&k35c{{JAOJ(E6!6!@mhd&)?7=ysrB-$(qE1+&(kefy=jL&i0FA+ptaZIR$`}|A8UJrcr%n%>14mhB41GmL8t(zdL0j ztoi;)Dyh%62I*|`{TR*ne?O(0+2?yz$8Ss)#V+~4H!C?=ko)`sXTw$rC+wtVC9jmE z4w7^>uv)85rC2{IV*#egKQs5ShtsY}2VZ-Bdp2U2R0?SOXQLEx{~}{F2;*XvhUw#9 zPnkH2KK_l3J~X&zqmL(uK7M6NH?z}6CLx_5G!j8JqKY$5HOu*&LRbyb$tc5=($I>t zbpX0PrL9(+Miu~Pt5$O2_|_R}Nxv7pn6&fhSz5PI(QM^`=Et958j`hwxNP(^6DACr zx_HH5x_X*HGRr!1i%RNpM}vPhx_Xl6>i>IabQRJ0IgG4COrJ>QA%U8FN`N*$yy76q z2OYC(3AogVWDgVBY{k*AXIdlGyBHe_%!Hco>XZ&_^F6gFMm|3})%N9K8ibC)jHQPs z)jRW~F4-nkgLJk@-W1{ZWs+#HV<2i!zV5 zj=&#e?J8*U6WS9TsbEiz$R<9@*Ks}-AfrdUg8ATSS)`-1M|GT}ub*x_HbB0Hy7}|k z;CZoEQI9YhwXGP1t_`jg#9X_C_HIFYAaflh5YW)Tlbb4dTckmqe)Hf~rHQ1HM@Cfi z>EI^9oEMhKJ$E{IdHCg#D9e(3q&cl+;F&zdb|Fj6TTSqC3((JdxN)}z5=6%f@kg*KAtn}i3%vIopt+!X56 z;Ir%ru&dn{W<6>tV!I$6^%_J{&(YCnMLe?CWK@z@k2*-XhIm!?ssC@KX5p~M<^ z^rXQMh6NYVlN{nkj)=Ag z%tBOjPi~7{%fhsSg4l7Qq~bgsyht^uMXGUxljOj%3asA1^M%j27J-&qaxp*B4Lz~C zd6|}8>PD3$a4FfKtQ+zup^KZUkOK=8)bi=ZjlnA*sK$}WTPFBNN{goVTLxdlps6(B z;-xJZ&@JJp078CB7P{t7Fy3=YADh{|qcTEW>J;t*w`yH#f~ucZaGpdxI&On~71Vrz z{nmaSu}e8L48D>t<5)}{OPt15m@$$+M|2vc-2yPTAbXI859ra@{aZjJQl57BE&l%q zNd(*zGFgTYTU44T-ew#l2J$)pfz{duCyoFuV>g)7z?>av2 z(8nj9#K*_!qe&k%`uHXK_yzj7gG{H@Pt(V@(Z`>sk3Xc3KcJ8Q7Dqd(-$5V004Hbl z=jh`P>EjRRqlty9TBDE8LyAx8G>Ep(KVGj{G`gz!urfg_A!Km^(ol7L1zjk4@dh~L>$@K_@!)lG(F z4?jBc&@6p(sKuK`udLEXhT6wsCabi1zBt;J{^pUv4ajG+*exXUhFH_XXtV}RF>HSf z2iq+z!ioO*sinc(n-~XR8 zmtB%8ii%XrumF*qGw1gI=fD5|ocH#A@a&e7(1^eH`DR!BHEAck;-P6;E1_(uKKR46 z2kBJ4z#vKY$7Y+l51grVujl%5aCuKU(KE5lc;M`Db~|{?fOxj%1YKF{nz8KE%neGi308fx7Rp`_)w-vxu-}V=8qk5>fTRjYs$molk|u!OA4w~A13$--v(K3zFbO03 zVmJ0==~Y_2bmfhuD`&;kFldKnx9j?CvAFoMaD8#LA3K3B*4)?;ubjTXt1`kc(cUGw zPKdqf@xL+Pqr;}Y>>PJy34BM?ormj5({v62`_7T;1Lr>cKZ^ek;Qxcy2Z{5La}wPj zQ{A0MoQE$@FtkR?m7d-3T!5dE#Sp;!e$!WaD4$I+G@URLfE_A8tNCNG@1Ms;F5YOj z7traPBY3B~$~$cacE7Zpbn&Vq3FSDkwy3wovwpi5o%3bfm0cOTR@Dl+&kNJH#U<&k zthiz+a90Cg`l8}+!?_?bTS4O6CY^dU2-~ySAx(kGOq^=ZDXr+dp@^ZH9v)qKkOR5N zI{@^H49FCyT!MPRbS1Rix5>UU9B%q9UklWE+>zrDnoeNJByDGLRZy*b3Ddgj;tQ2J;)+1M|2BbIWCiVck7jf(j36|8gul zy{Uwuf8u%pE`AFj($ENntkH265Y=ky&xpUiG=F;6!p2% z1Ai^DViD(iJ3Y4fDh<}*z?aE{4L<5bcr zk3B0&g9QeYLR5p5Ld*x3wY@AWtP|KHt9MP96X}C;y$9vo$OWj~X!aYdfZiQAKXDF3 z=>wZ~fl+}D$It;h^=L+N8BbNRhID$tkHf%DlmVdGYPhjD>wm=l{^92I?mGc*(DzkURDU{7uc7n%DNK9sDP-q0! zum3TQPt(0jgK06i(72Cp>nPbmBjx+Apb8jG>R5|CtOmii;Pu!RaGAJh$y%h5k zjGaTE!R>&VjqXfhKzft_+(2_90L_5?OY~PPoQ}R31K?xZA=?bZ{hGv!r5MJ?w+UlD zTmgB13CI$kj6nIlyM||SDVE+ndmg2X@ft2uvWGB?#co;Lrq3)n5S*DqENt0@1rvvG z8>1n`b!lno>f*2mrvwg|^p@tx51?}a6ba@#PrtV9%w^CWEubsVkxqlz3N>bCx_Lu; z$vYfXwxpfLD9Xdp?NsZ?C#p}*i8aTy9MMAGBqRlAbfNX3--yjUw@Eax z>e@7e(p>YAYfC}YAcnMDHFxYqM22u=m^?>BlQhi;J3$0M&ze)t-L&Q6_&VzNocu7h z6LrW4^^2ur96G-LdO@~b-zQXapoB~VxD(=Z6+VYLvXhaB0&7LW98ssFPDk2CB}{Cb zu8%lXf0k{KDCyBTRKbpXM^z2|SMa6_t?B}P0H>qas0qktqg z4T`?O50D}8AR=aH)H3{Zbse*k1EcvJsvJy3$JLWz7n(_RbS=Ze)M4O}0-%l47;3_5 z`N93$Z3CT|_BH^|^WHM}1xXDQNquKWB=w~&Na~uzbZ@w^qor`}4XRjBNxCmDvp6hh zX?a;l_>MuJ$Y6Q-C3vBWtO4*MXm%i(GqG$1o`*;D^C-m71Jky`pj$p`Ey#_gY>@yD zC3HUP8<2_iXU!r;#iS>emlxrG`t5})Sh1N959CB>WCjOFaI>8!$ap}Os8N^$0AwSo zFDzWCE?jwmC(L0{?6MYwE0G95ExdUIq-E&!X?#9fvx)`?zHkW8y}lyk3QW?IH%2#; zPT>@#kKcF*;6zBY^9Li;LAerm`Z6@Vp+NQ~ILWNTLnG&0?1P=NKgJ5<98iQ(JKv{W zsLjBRsHO)>lu}GL+`P%=J3qiYdE94an8vd08U^7MQ}a&$atAwY-5Js?cADO)6>o^& z=`ufM*qzK+tk^N*_J=#b?ZaC#=_tJ)+p^~tWIjwO_wAgz|9%H>-77XolLA}mW^ZqJ z77uPIj>Cy*W3*T;Wq^K6E)io%uFM#O5yQ zkZsHJ+9vYYHk8ED8hiS)ic^XB>u-9S%a6<>MI* zX;9c;Oi066Bz&`lm@z`RsQ~oL3eee`0+hlSU&=>t7~`oSTKTO7n7#l5@aCK0cAznf7+y!+} z^!;jRuDYSP0LRr1(P3fng}ONPZ!CM- z6Y?dUW&jTg(;$wdEzvb8EX+tb7G`|%FWqicyewnrqDUef6_8gNvE{5IQ9J}G5Ts+= z$f37Pw&dsNJ)KomIk1g>^l1c*74pu3E7VZ>!%ri4w{&u3W?$S9c|S8u-n-I++B9!8 zJ$Ozf1O3_&Xl^TB7tawbXRdbz(T#Y$8p*f;55#TtEA&$R+2~0Kk6-5Qx}}ALV8d-S z{D5CJEE&Qjv*Fx3&z+ey+?Jr(yuh^ebPeo6`F)j>mRaq|?#Ws4$aCU}vm!LzNQ#T= z6dFL}uX3^;hzsWhO&Oh>HKJmpn!qcV8|}!7GRap|La|}mC|!%9S>sVr55lhLQ4}{0 z;30|%JU=1VP0B}d++vnOJza>vNVMQV25Va6e~ui)EH@%2m%(iMy$%W;=cc7o>s{|` z)I+ivHHAGK3T1pLSJqh~;(qw@xe~Qfc7I49e~-d3Ef)oOg3A4LNFOeBE_^w9BdD7# zTV~=Z_n%~?-zO?HK&2c+u1KaT7TQ_cX&wA0J8Z=d)=;1)%@rS%BcoYXkzfK6+|pn} z45C|Sp-F@*X^Wt~)R||9*}G@M`8jqRI*8+)){cY?D)@3^rhIhQPC~TMu>eZ}Yz;oX zSbAPms8`?+hA#NA%N*{uIFb&n>AAWBj}F#od1f0r5DL&2W)o2n)~#{BN9q_n8)|ik zG6J${LIiga4dG+M>QrEW(=s9$Qc#g3O7uciO*RlzB9AW$wMWvn9+eT6`Wu!5TOGtl z+MNUi$YEZbAyW;69mDz}L4tgRrbKMVL-}LU#`Iy(gqEgCh```^sRSl8Q6pi=%+C58 zWzZYjMOi_4SgEq&4YME99` zaleMbpBhq@HEX4{R%<4x5e3oL%CmkArQ**$L8U~f`=xE^D66qtUtG+Wq{5@}lHdV~ z)<(rjy%m>NYlne3t?McKzlEqnFB_ zx_6ZLv(UhFnKud)vwig2*z8#QNSBKZ&!Gy9-qM9ew}E%FVkJf<)OIyJG{VXS92;Ma zKZIv)K?-Cj-2*{V?0_-(;WjbJLlpv_&mIaoe}H0RGwprepZs zRt~;$*I`YmB4TBxSH+82sTLIuP^}i?VwsBoBfvmaO|1MbR{aR8ofVw~ZDtF}N6O}F zG|nNl6KBCSczy_RqO_NvI_K3H{GnG60|f-KYpFX>VODxM*y}%(SPzXhC+@U z*VQqaj8e$iA*5tEfh=*rr76l60=SfOr{XtMVQ~Hk9!VrooC;qGY4QLQ0B@*Hiwp`c zcL|xcIuy&1)(S$BeuAETu4f&IO4A4miSjmhcQl0kt!xswI2bN?uH4c2oFYD_2u%@% z@cBdupTFCY@VUN)@Jas~WU2X2dG1*i6IB=~wg3yjF<0RPxagpMDjw2d1SV}&_({TQ zV-x|OC@{M~j(|Ioh?xa5j6@E=7vMuxi#SJ)4N16sO>m}%s1vP_i94_2HVTJOijDXc zhzWE>1e_6fjJRGeF=&}F(+?I}6#iJr2v8R)!GuCZB%i)402j z-~0U{IMsPu9m`ugI+kDA>R2Aj&<|EzLk=j0OhWD0Mf&Rc>oS6{LDne4()KzRl+;mM zc6PMoUmMzTNqgnGq%i4AO=IkNXo_N*(O6!7c@WAFa8<|dbOx>iT`ttnmkQO>>8ypq zc!PR6i3$NE$lAD6=}3Od5)xt%{ywfRnt0vx65Mr^-|lj~S9#G5R3Lbw2kA{9sLJv;|p{^QqMH0Qma{I6^d~BKC+d>u+cC;+Lyu3R-2&*Ud zlWt?3^uPcuGn8=bH7H4qp%JG1S=9pHlUo|36&f5q!j`e39zfr+alAI~yK z9~yZxGDYV@P-r@%<}LQH@3p0u=AXv;!!Je#r-uoK2#9ikB9E(G4tj_=Cb*~o7`IXV zau4p(O7By;yMgj3D(v(vSQ@~?1R|F$fC-Gab^}I3%UvHh6X^^^0UJeAdJo-+b&#y8 zMoxG@EH|*h0b_6y7froLCU($3RStR`#tj*;W*X&@OeMHjW7UmZMWTlq z5XqE(1|WKu`!j}c9!aMG3_gPNxugq|9@O0$9&zz4+< zj%*O}0p!Q?M=;*usE^N5*BcIQ=<)cL9^77r;*vo+9pM|hxbaQ`_Kh&|K7Lk@TqdV6 z_z(ivR4pPy#a1{ml0OZMUP*d`_xXl5zK=|^`}-i0z#|-rQ${4d9wNOs5(vWm@QdUdH``aV^)d8*-ODB~i0PBH@TwjF_8tRTXKJz132viYs zeFG>2x4OLxSvAy3(JgMqY_0r(E~uhQjUS28KwK_rE06-ZkJ=uN6wEsOE4ol zuhNf45i#lr`f(3O4oC$Jcpm zoyXM^=Lp@Sb__S<{MdPnmvcT*YtfhJYAs6nsI@3i!)vjFlB5UA^uwSYv{1{z^a3zd z3-Nf?PvNfILKMxdprURw@N$ym#-AB!%zIA_%{Y~<%7gA5njhjij7dKn9i2RVXUgt?$8H{+wQnW&H2=Wf(A pbcHmHx+D>jFS~+}su}-N&6gg?QNg^yej9W>1jL|DLBFI~{XbWe5)uFa literal 0 HcmV?d00001 diff --git a/doc/doctrees/index.doctree b/doc/doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..cab8fd09d91333bacc522b6cd7a35a3514c13f1a GIT binary patch literal 6360 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 Vyk3$GjB5_Hro4*jTQ}+L{||y2I&uI2 literal 0 HcmV?d00001 diff --git a/doc/howto.ca.html b/doc/howto.ca.html deleted file mode 100644 index 74142d5..0000000 --- a/doc/howto.ca.html +++ /dev/null @@ -1,891 +0,0 @@ -HOWTO: Creating your own CA with OpenSSL

    HOWTO: Creating your own CA with OpenSSL

    Pheng Siong Ng

    ngps@post1.com

    Copyright © 2000, 2001 by Ng Pheng Siong.

    Revision History
    Revision $Revision: 1.1 $$Date: 2003/06/22 16:41:18 $


    Introduction

    This is a HOWTO on creating your own certification - authority (CA) with OpenSSL. -

    I last created a CA about a year ago, when I began work on M2Crypto and needed - certificates for the SSL bits. I accepted the tools' default settings - then, e.g., certificate validity of 365 days; this meant that my - certificates, including my CA's certificate, have now expired. -

    Since I am using these certificates for M2Crypto's demonstration - programs (and I have forgotten the passphrase to the CA's private key), - I decided to discard the old CA and start afresh. I also decided to - document the process, hence this HOWTO. -


    The Procedure

    I use CA.pl, a Perl program written by - Steve Hanson and bundled with OpenSSL. -

    The following are the steps to create a CA: -

    1. Choose a directory to do your CA work. All commands are executed - within this directory. Let's call the directory demo. -

    2. Copy CA.pl and openssl.cnf - into demo. -

    3. Apply the following patch to CA.pl, which - allows it to generate a CA certificate with a validity period of 1095 days, - i.e., 3 years: -

          --- CA.pl.org   Sat Mar 31 12:40:13 2001
      -    +++ CA.pl       Sat Mar 31 12:41:15 2001
      -    @@ -97,7 +97,7 @@
      -                    } else {
      -                        print "Making CA certificate ...\n";
      -                        system ("$REQ -new -x509 -keyout " .
      -    -                       "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT $DAYS");
      -    +                       "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT -days 1095");
      -                        $RET=$?;
      -                    }
      -                }
      -    
    4. Create a new CA like this: -

          ./CA.pl -newca
      -    
      -    A certificate filename (or enter to create) <enter>
      -    
      -    Making CA certificate ...
      -    Using configuration from openssl.cnf
      -    Generating a 1024 bit RSA private key
      -    ............++++++
      -    ......................++++++
      -    writing new private key to './demoCA/private/cakey.pem'
      -    Enter PEM pass phrase: <secret passphrase here>
      -    Verifying password - Enter PEM pass phrase: <secret passphrase again>
      -    -----
      -    You are about to be asked to enter information that will be incorporated
      -    into your certificate request.
      -    What you are about to enter is what is called a Distinguished Name or a DN.
      -    There are quite a few fields but you can leave some blank
      -    For some fields there will be a default value,
      -    If you enter '.', the field will be left blank.
      -    -----
      -    Country Name (2 letter code) [AU]:SG
      -    State or Province Name (full name) [Some-State]:.
      -    Locality Name (eg, city) []:..
      -    Organization Name (eg, company) [Internet Widgits Pty Ltd]:DemoCA
      -    Organizational Unit Name (eg, section) []:.
      -    Common Name (eg, YOUR name) []:DemoCA Certificate Master
      -    Email Address []:certmaster@democa.dom
      -    

      This creates a new CA in the directory demoCA. - The CA's self-signed certificate is in - demoCA/cacert.pem and its RSA key pair is in - demoCA/private/cakey.pem. -

      demoCA/private/cakey.pem looks like this: -

          cat demoCA/private/cakey.pem
      -    
      -    -----BEGIN RSA PRIVATE KEY-----
      -    Proc-Type: 4,ENCRYPTED
      -    DEK-Info: DES-EDE3-CBC,19973A9DBBB601BA
      -
      -    eOq9WFScNiI4/UWEUaSnGTKpJv2JYuMD3HwQox2Q3Cd4zGqVjJ6gF3exa5126cKf
      -    X/bMVnwbPpuFZPiAIvaLyCjT6pYeXTBbSzs7/GQnvEOv+nYnDUFWi0Qm92qLk0uy
      -    pFi/M1aWheN3vir2ZlAw+DW0bOOZhj8tC7Co7lMYb0YE271b6/YRPZCwQ3GXAHUJ
      -    +aMYxlUDrK45aCUa/1CZDzTgk7h9cDgx2QJSIvYMYytCfI3zsuZMJS8/4OXLL0bI
      -    lKmAc1dwB3DqGJt5XK4WJesiNfdxeCNEgAcYtEAgYZTPIApU+kTgTCIxJl2nMW7j
      -    ax+Q1z7g+4MpgG20WD633D4z4dTlDdz+dnLi0rvuvxiwt+dUhrqiML1tyi+Z6EBH
      -    jU4/cLBWev3rYfrlp4x8J9mDte0YKOk3t0wQOHqRetTsIfdtjnFp/Hu3qDmTCWjD
      -    z/g7PPoO/bg/B877J9WBPbL/1hXXFYo88M+2aGlPOgDcFdiOqbLb2DCscohMbbVr
      -    A4mgiy2kwWfIE73qiyV7yyG8FlRvr1iib+jbT3LTGf743utYAAs7HNGuOUObhoyt
      -    jYvBD7ACn35P5YX7KTqvqErwdijxYCaNBCnvmRtmYSaNw9Kv1UJTxc5Vx7YLwIPk
      -    E9KyBgKI7vPOjWBZ27+zOvNycmv1ciNtpALAw4bWtXnhCDVTHaVDy34OkheMzNCg
      -    2cjcBFzOkMIjcI03KbTQXOFIQGlsTWXGzkNf/zBQ+KksT1MCj+zBXSCvlDASMckg
      -    kef21pGgUqPF14gKGfWX3sV4bjc1vbrRwq6zlG3nMuYqR5MtJJY9eQ==
      -    -----END RSA PRIVATE KEY-----
      -    
    5. Next, generate a certificate request. -

          ./CA.pl -newreq
      -    
      -    Using configuration from openssl.cnf
      -    Generating a 1024 bit RSA private key
      -    ..........++++++
      -    ..............++++++
      -    writing new private key to 'newreq.pem'
      -    Enter PEM pass phrase: <another secret passphrase here>
      -    Verifying password - Enter PEM pass phrase: <another secret passphrase again>
      -    -----
      -    You are about to be asked to enter information that will be incorporated
      -    into your certificate request.
      -    What you are about to enter is what is called a Distinguished Name or a DN.
      -    There are quite a few fields but you can leave some blank
      -    For some fields there will be a default value,
      -    If you enter '.', the field will be left blank.
      -    -----
      -    Country Name (2 letter code) [AU]:SG
      -    State or Province Name (full name) [Some-State]:..
      -    Locality Name (eg, city) []:.
      -    Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto
      -    Organizational Unit Name (eg, section) []:.
      -    Common Name (eg, YOUR name) []:localhost
      -    Email Address []:admin@server.example.dom
      -    
      -    Please enter the following 'extra' attributes
      -    to be sent with your certificate request
      -    A challenge password []:<enter>
      -    An optional company name []:<enter>
      -    Request (and private key) is in newreq.pem
      -    

      The certificate request and private key in newreq.pem looks like this: -

          cat newreq.pem
      -    
      -    -----BEGIN RSA PRIVATE KEY-----
      -    Proc-Type: 4,ENCRYPTED
      -    DEK-Info: DES-EDE3-CBC,41B2874DF3D02DD4
      -    
      -    mg611EoVkLEooSTv+qTM0Ddmm/M1jE/Jy5RD/sc3LSMhuGu9xc26OgsTJmkQuIAh
      -    J/B4lAw8G59VTG6DykeEtrG0rUBx4bggc7PKbFuiN423YjJODWcHvVgnPOzXMQt+
      -    lY4tPl5+217MRHyx2NsWGrpkQNdu3GeSPOVMl3jeQiaXupONbwQ7rj42+X/VtAJP
      -    W4D1NNwu8aGCPyShsEXHc/fI1WDpphYWke97pOjIZVQESFZOPty5HjIYZux4U+td
      -    W81xODtq2ecJXc8fn2Wpa9y5VD1LT7oJksOuL1+Z04OVaeUe4x0swM17HlBm2kVt
      -    fe/C/L6kN27MwZhE331VjtTjSGl4/gknqQDbLOtqT06f3OISsDJETm2itllyhgzv
      -    C6Fi3N03rGFmKectijC+tws5k+P+HRG6sai33usk8xPokJqA+HYSWPz1XVlpRmv4
      -    kdjQOdST7ovU62mOTgf3ARcduPPwuzTfxOlYONe5NioO1APVHBrInQwcpLkpOTQR
      -    vI4roIN+b75/nihUWGUJn/nbbBa2Yl0N5Gs1Tyiy9Z+CcRT2TfWKBBFlEUIFl7Mb
      -    J9fTV3DI+k+akbR4il1NkQ8EcSmCr3WpA0I9n0EHI7ZVpVaHxc0sqaPFl8YGdFHq
      -    1Qk53C/w6+qPpDzT3yKFmG2LZytAAM1czvb6RbNRJJP2ZrpBwn/h99sUTo/yPfxY
      -    nueYmFJDm0uVNtG0icXGNUfSfnjKNTtHPAgyKGetRIC3kgJz/bo2w7EI6iEjBAzK
      -    l5TRm4x6ZJxwuXXMiJCehMMd8TC8ybwWO4AO19B3ebFFeTVsUgxSGA==
      -    -----END RSA PRIVATE KEY-----
      -    -----BEGIN CERTIFICATE REQUEST-----
      -    MIIBnTCCAQYCAQAwXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIw
      -    EAYDVQQDEwlsb2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5l
      -    eGFtcGxlLmRvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr1nYY1Qrll1r
      -    uB/FqlCRrr5nvupdIN+3wF7q915tvEQoc74bnu6b8IbbGRMhzdzmvQ4SzFfVEAuM
      -    MuTHeybPq5th7YDrTNizKKxOBnqE2KYuX9X22A1Kh49soJJFg6kPb9MUgiZBiMlv
      -    tb7K3CHfgw5WagWnLl8Lb+ccvKZZl+8CAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GB
      -    AHpoRp5YS55CZpy+wdigQEwjL/wSluvo+WjtpvP0YoBMJu4VMKeZi405R7o8oEwi
      -    PdlrrliKNknFmHKIaCKTLRcU59ScA6ADEIWUzqmUzP5Cs6jrSRo3NKfg1bd09D1K
      -    9rsQkRc9Urv9mRBIsredGnYECNeRaK5R1yzpOowninXC
      -    -----END CERTIFICATE REQUEST-----
      -    

      Decoding the certificate request gives the following: -

          openssl req -text -noout < newreq.pem
      -    
      -    Using configuration from /usr/local/pkg/openssl/openssl.cnf
      -    Certificate Request:
      -        Data:
      -            Version: 0 (0x0)
      -            Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom
      -            Subject Public Key Info:
      -                Public Key Algorithm: rsaEncryption
      -                RSA Public Key: (1024 bit)
      -                    Modulus (1024 bit):
      -                        00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50:
      -                        91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e:
      -                        6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13:
      -                        21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4:
      -                        c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac:
      -                        4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f:
      -                        6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9:
      -                        6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f:
      -                        0b:6f:e7:1c:bc:a6:59:97:ef
      -                    Exponent: 65537 (0x10001)
      -            Attributes:
      -                a0:00
      -        Signature Algorithm: md5WithRSAEncryption
      -            7a:68:46:9e:58:4b:9e:42:66:9c:be:c1:d8:a0:40:4c:23:2f:
      -            fc:12:96:eb:e8:f9:68:ed:a6:f3:f4:62:80:4c:26:ee:15:30:
      -            a7:99:8b:8d:39:47:ba:3c:a0:4c:22:3d:d9:6b:ae:58:8a:36:
      -            49:c5:98:72:88:68:22:93:2d:17:14:e7:d4:9c:03:a0:03:10:
      -            85:94:ce:a9:94:cc:fe:42:b3:a8:eb:49:1a:37:34:a7:e0:d5:
      -            b7:74:f4:3d:4a:f6:bb:10:91:17:3d:52:bb:fd:99:10:48:b2:
      -            b7:9d:1a:76:04:08:d7:91:68:ae:51:d7:2c:e9:3a:8c:27:8a:
      -            75:c2
      -    
    6. Now, sign the certificate request: -

          ./CA.pl -sign
      -    
      -    Using configuration from openssl.cnf
      -    Enter PEM pass phrase: <CA's passphrase>
      -    Check that the request matches the signature
      -    Signature ok
      -    The Subjects Distinguished Name is as follows
      -    countryName           :PRINTABLE:'SG'
      -    organizationName      :PRINTABLE:'M2Crypto'
      -    commonName            :PRINTABLE:'localhost'
      -    emailAddress          :IA5STRING:'admin@server.example.dom'
      -    Certificate is to be certified until Mar 31 02:57:30 2002 GMT (365 days)
      -    Sign the certificate? [y/n]:y
      -    
      -    
      -    1 out of 1 certificate requests certified, commit?  [y/n]y
      -    Write out database with 1 new entries
      -    Data Base Updated
      -    Signed certificate is in newcert.pem
      -    

      newcert.pem looks like this: -

          cat newcert.pem
      -    
      -    Certificate:
      -        Data:
      -            Version: 3 (0x2)
      -            Serial Number: 1 (0x1)
      -            Signature Algorithm: md5WithRSAEncryption
      -            Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom
      -            Validity
      -                Not Before: Mar 31 02:57:30 2001 GMT
      -                Not After : Mar 31 02:57:30 2002 GMT
      -            Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom
      -            Subject Public Key Info:
      -                Public Key Algorithm: rsaEncryption
      -                RSA Public Key: (1024 bit)
      -                    Modulus (1024 bit):
      -                        00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50:
      -                        91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e:
      -                        6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13:
      -                        21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4:
      -                        c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac:
      -                        4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f:
      -                        6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9:
      -                        6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f:
      -                        0b:6f:e7:1c:bc:a6:59:97:ef
      -                    Exponent: 65537 (0x10001)
      -            X509v3 extensions:
      -                X509v3 Basic Constraints: 
      -    Certificate:
      -        Data:
      -            Version: 3 (0x2)
      -            Serial Number: 1 (0x1)
      -            Signature Algorithm: md5WithRSAEncryption
      -            Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom
      -            Validity
      -                Not Before: Mar 31 02:57:30 2001 GMT
      -                Not After : Mar 31 02:57:30 2002 GMT
      -            Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom
      -            Subject Public Key Info:
      -                Public Key Algorithm: rsaEncryption
      -                RSA Public Key: (1024 bit)
      -                    Modulus (1024 bit):
      -                        00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50:
      -                        91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e:
      -                        6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13:
      -                        21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4:
      -                        c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac:
      -                        4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f:
      -                        6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9:
      -                        6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f:
      -                        0b:6f:e7:1c:bc:a6:59:97:ef
      -                    Exponent: 65537 (0x10001)
      -            X509v3 extensions:
      -                X509v3 Basic Constraints: 
      -                    CA:FALSE
      -                Netscape Comment: 
      -                    OpenSSL Generated Certificate
      -                X509v3 Subject Key Identifier: 
      -                    B3:D6:89:88:2F:B1:15:40:EC:0A:C0:30:35:3A:B7:DA:72:73:1B:4D
      -                X509v3 Authority Key Identifier: 
      -                    keyid:F9:6A:A6:34:97:6B:BC:BB:5A:17:0D:19:FC:62:21:0B:00:B5:0E:29
      -                    DirName:/C=SG/O=DemoCA/CN=DemoCA Certificate Master/Email=certmaster@democa.dom
      -                    serial:00
      -    
      -        Signature Algorithm: md5WithRSAEncryption
      -    
    7. In certain situations, e.g., where your certificate and - private key are to be used in an unattended SSL server, you may wish to - not encrypt the private key, i.e., leave the key in the clear. This - decision should be governed by your site's security policy and threat - model, of course. -

          openssl rsa < newkey.pem > newkey2.pem
      -    
      -    read RSA key
      -    Enter PEM pass phrase:<secret passphrase here>
      -    writing RSA key
      -    

      newkey2.pem looks like this: -

          cat newkey2.pem
      -    
      -    -----BEGIN RSA PRIVATE KEY-----
      -    MIICXgIBAAKBgQCvWdhjVCuWXWu4H8WqUJGuvme+6l0g37fAXur3Xm28RChzvhue
      -    7pvwhtsZEyHN3Oa9DhLMV9UQC4wy5Md7Js+rm2HtgOtM2LMorE4GeoTYpi5f1fbY
      -    DUqHj2ygkkWDqQ9v0xSCJkGIyW+1vsrcId+DDlZqBacuXwtv5xy8plmX7wIDAQAB
      -    AoGAbAkU8w3W1Qu15Hle1bJSL7GMReoreqeblOBmMAZz4by0l6sXZXJpjWXo86f/
      -    +dASMYTMPC4ZTYtv06N07AFbjL+kDfqDMTfzQkYMHp1LAq1Ihbq1rHWSBH5n3ekq
      -    KiY8JKpv8DR5Po1iKaXJFuDByGDENJwYbSRSpSK3P+vkWWECQQDkEUE/ZPqqqZkQ
      -    2iWRPAsCbEID8SAraQl3DdCLYs/GgARfmmj4yUHEwkys9Jo1H8k4BdxugmaUwNi5
      -    YQ/CVzrXAkEAxNO80ArbGxPUmr11GHG/bGBYj1DUBkHZSc7dgxZdtUCLGNxQnNsg
      -    Iwq3n6j1sUzS3UW6abQ8bivYNOUcMKJAqQJBANQxFaLU4b/NQaODQ3aoBZpAfP9L
      -    5eFdvbet+7zjt2r5CpikgkwOfAmDuXEltx/8LevY0CllW+nErx9zJgVrwUsCQQCu
      -    76H5JiznPBDSF2FjgHWqVVdgyW4owY3mU739LHvNBLicN/RN9VPy0Suy8/CqzKT9
      -    lWPBXzf2k3FuUdNkRlFBAkEAmpXoybuiFR2S5Bma/ax96lVs0/VihhfC1zZP/X/F
      -    Br77+h9dIul+2DnyOl50zu0Sdzst1/7ay4JSDHyiBCMGSQ==
      -    -----END RSA PRIVATE KEY-----
      -    

    That's it! The certificate, newcert.pem, and - the private key - newkey.pem (encrypted) or - newkey2.pem (unencrypted) - are now ready to be used. - You may wish to rename the files to more intuitive names. -

    You should also keep the CA's certificate demo/cacert.pem - handy for use when developing and deploying SSL or S/MIME - applications. -


    Conclusion

    We've walked through the basic steps in the creation of a CA and - certificates using the tools that come with OpenSSL. We did not cover more - advanced topics such as constraining a certificate to be SSL-only or - S/MIME-only. -

    There exist several HOWTOs similar to this one on the net. This one - is written specifically to facilitate discussions in my other HOWTOs - on developing SSL and S/MIME applications in - Python using - M2Crypto. -


    $Id:howto.ca.html 583 2007-10-01 19:23:12Z heikki $ -

    \ No newline at end of file diff --git a/doc/howto.ca.rst b/doc/howto.ca.rst new file mode 100644 index 0000000..e950b59 --- /dev/null +++ b/doc/howto.ca.rst @@ -0,0 +1,370 @@ +:orphan: + +.. _howto-ca: + +HOWTO: Creating your own CA with OpenSSL +######################################## + +:author: Pheng Siong Ng +:copyright: © 2000, 2001 by Ng Pheng Siong. + +Introduction +============ + +This is a HOWTO on creating your own *certification authority* (*CA*) +with OpenSSL. + +I last created a CA about a year ago, when I began work on +`M2Crypto `__ and needed +certificates for the SSL bits. I accepted the tools' default +settings then, e.g., certificate validity of 365 days; this meant +that my certificates, including my CA's certificate, have now +expired. + +Since I am using these certificates for M2Crypto's demonstration +programs (and I have forgotten the passphrase to the CA's private +key), I decided to discard the old CA and start afresh. I also +decided to document the process, hence this HOWTO. + +The Procedure +============= + +I use ``CA.pl``, a Perl program written by Steve Hanson and bundled with +OpenSSL. + +The following are the steps to create a CA: + +1. Choose a directory to do your CA work. All commands are executed + within this directory. Let's call the directory ``demo``. + +2. Copy ``CA.pl`` and ``openssl.cnf`` into ``demo``. + +3. Apply the following patch to ``CA.pl``, which allows it to generate a + CA certificate with a validity period of 1095 days, i.e., + 3 years:: + + --- CA.pl.org Sat Mar 31 12:40:13 2001 + +++ CA.pl Sat Mar 31 12:41:15 2001 + @@ -97,7 +97,7 @@ + } else { + print "Making CA certificate ...\n"; + system ("$REQ -new -x509 -keyout " . + - "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT $DAYS"); + + "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT -days 1095"); + $RET=$?; + } + } + + +4. Create a new CA like this:: + + ./CA.pl -newca + + A certificate filename (or enter to create) + + Making CA certificate ... + Using configuration from openssl.cnf + Generating a 1024 bit RSA private key + ............++++++ + ......................++++++ + writing new private key to './demoCA/private/cakey.pem' + Enter PEM pass phrase: + Verifying password - Enter PEM pass phrase: + ----- + You are about to be asked to enter information that will be incorporated + into your certificate request. + What you are about to enter is what is called a Distinguished Name or a DN. + There are quite a few fields but you can leave some blank + For some fields there will be a default value, + If you enter '.', the field will be left blank. + ----- + Country Name (2 letter code) [AU]:SG + State or Province Name (full name) [Some-State]:. + Locality Name (eg, city) []:.. + Organization Name (eg, company) [Internet Widgits Pty Ltd]:DemoCA + Organizational Unit Name (eg, section) []:. + Common Name (eg, YOUR name) []:DemoCA Certificate Master + Email Address []:certmaster@democa.dom + + This creates a new CA in the directory ``demoCA``. The CA's + self-signed certificate is in ``demoCA/cacert.pem`` and its RSA key + pair is in ``demoCA/private/cakey.pem``. + + ``demoCA/private/cakey.pem`` looks like this:: + + cat demoCA/private/cakey.pem + + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED + DEK-Info: DES-EDE3-CBC,19973A9DBBB601BA + + eOq9WFScNiI4/UWEUaSnGTKpJv2JYuMD3HwQox2Q3Cd4zGqVjJ6gF3exa5126cKf + X/bMVnwbPpuFZPiAIvaLyCjT6pYeXTBbSzs7/GQnvEOv+nYnDUFWi0Qm92qLk0uy + pFi/M1aWheN3vir2ZlAw+DW0bOOZhj8tC7Co7lMYb0YE271b6/YRPZCwQ3GXAHUJ + +aMYxlUDrK45aCUa/1CZDzTgk7h9cDgx2QJSIvYMYytCfI3zsuZMJS8/4OXLL0bI + lKmAc1dwB3DqGJt5XK4WJesiNfdxeCNEgAcYtEAgYZTPIApU+kTgTCIxJl2nMW7j + ax+Q1z7g+4MpgG20WD633D4z4dTlDdz+dnLi0rvuvxiwt+dUhrqiML1tyi+Z6EBH + jU4/cLBWev3rYfrlp4x8J9mDte0YKOk3t0wQOHqRetTsIfdtjnFp/Hu3qDmTCWjD + z/g7PPoO/bg/B877J9WBPbL/1hXXFYo88M+2aGlPOgDcFdiOqbLb2DCscohMbbVr + A4mgiy2kwWfIE73qiyV7yyG8FlRvr1iib+jbT3LTGf743utYAAs7HNGuOUObhoyt + jYvBD7ACn35P5YX7KTqvqErwdijxYCaNBCnvmRtmYSaNw9Kv1UJTxc5Vx7YLwIPk + E9KyBgKI7vPOjWBZ27+zOvNycmv1ciNtpALAw4bWtXnhCDVTHaVDy34OkheMzNCg + 2cjcBFzOkMIjcI03KbTQXOFIQGlsTWXGzkNf/zBQ+KksT1MCj+zBXSCvlDASMckg + kef21pGgUqPF14gKGfWX3sV4bjc1vbrRwq6zlG3nMuYqR5MtJJY9eQ== + -----END RSA PRIVATE KEY----- + + +5. Next, generate a certificate request:: + + ./CA.pl -newreq + + Using configuration from openssl.cnf + Generating a 1024 bit RSA private key + ..........++++++ + ..............++++++ + writing new private key to 'newreq.pem' + Enter PEM pass phrase: + Verifying password - Enter PEM pass phrase: + ----- + You are about to be asked to enter information that will be incorporated + into your certificate request. + What you are about to enter is what is called a Distinguished Name or a DN. + There are quite a few fields but you can leave some blank + For some fields there will be a default value, + If you enter '.', the field will be left blank. + ----- + Country Name (2 letter code) [AU]:SG + State or Province Name (full name) [Some-State]:.. + Locality Name (eg, city) []:. + Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto + Organizational Unit Name (eg, section) []:. + Common Name (eg, YOUR name) []:localhost + Email Address []:admin@server.example.dom + + Please enter the following 'extra' attributes + to be sent with your certificate request + A challenge password []: + An optional company name []: + Request (and private key) is in newreq.pem + +\ + + The certificate request and private key in ``newreq.pem`` looks like + this:: + + cat newreq.pem + + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED + DEK-Info: DES-EDE3-CBC,41B2874DF3D02DD4 + + mg611EoVkLEooSTv+qTM0Ddmm/M1jE/Jy5RD/sc3LSMhuGu9xc26OgsTJmkQuIAh + J/B4lAw8G59VTG6DykeEtrG0rUBx4bggc7PKbFuiN423YjJODWcHvVgnPOzXMQt+ + lY4tPl5+217MRHyx2NsWGrpkQNdu3GeSPOVMl3jeQiaXupONbwQ7rj42+X/VtAJP + W4D1NNwu8aGCPyShsEXHc/fI1WDpphYWke97pOjIZVQESFZOPty5HjIYZux4U+td + W81xODtq2ecJXc8fn2Wpa9y5VD1LT7oJksOuL1+Z04OVaeUe4x0swM17HlBm2kVt + fe/C/L6kN27MwZhE331VjtTjSGl4/gknqQDbLOtqT06f3OISsDJETm2itllyhgzv + C6Fi3N03rGFmKectijC+tws5k+P+HRG6sai33usk8xPokJqA+HYSWPz1XVlpRmv4 + kdjQOdST7ovU62mOTgf3ARcduPPwuzTfxOlYONe5NioO1APVHBrInQwcpLkpOTQR + vI4roIN+b75/nihUWGUJn/nbbBa2Yl0N5Gs1Tyiy9Z+CcRT2TfWKBBFlEUIFl7Mb + J9fTV3DI+k+akbR4il1NkQ8EcSmCr3WpA0I9n0EHI7ZVpVaHxc0sqaPFl8YGdFHq + 1Qk53C/w6+qPpDzT3yKFmG2LZytAAM1czvb6RbNRJJP2ZrpBwn/h99sUTo/yPfxY + nueYmFJDm0uVNtG0icXGNUfSfnjKNTtHPAgyKGetRIC3kgJz/bo2w7EI6iEjBAzK + l5TRm4x6ZJxwuXXMiJCehMMd8TC8ybwWO4AO19B3ebFFeTVsUgxSGA== + -----END RSA PRIVATE KEY----- + -----BEGIN CERTIFICATE REQUEST----- + MIIBnTCCAQYCAQAwXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIw + EAYDVQQDEwlsb2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5l + eGFtcGxlLmRvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr1nYY1Qrll1r + uB/FqlCRrr5nvupdIN+3wF7q915tvEQoc74bnu6b8IbbGRMhzdzmvQ4SzFfVEAuM + MuTHeybPq5th7YDrTNizKKxOBnqE2KYuX9X22A1Kh49soJJFg6kPb9MUgiZBiMlv + tb7K3CHfgw5WagWnLl8Lb+ccvKZZl+8CAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GB + AHpoRp5YS55CZpy+wdigQEwjL/wSluvo+WjtpvP0YoBMJu4VMKeZi405R7o8oEwi + PdlrrliKNknFmHKIaCKTLRcU59ScA6ADEIWUzqmUzP5Cs6jrSRo3NKfg1bd09D1K + 9rsQkRc9Urv9mRBIsredGnYECNeRaK5R1yzpOowninXC + -----END CERTIFICATE REQUEST----- + +\ + + Decoding the certificate request gives the following:: + + openssl req -text -noout < newreq.pem + + Using configuration from /usr/local/pkg/openssl/openssl.cnf + Certificate Request: + Data: + Version: 0 (0x0) + Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50: + 91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e: + 6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13: + 21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4: + c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac: + 4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f: + 6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9: + 6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f: + 0b:6f:e7:1c:bc:a6:59:97:ef + Exponent: 65537 (0x10001) + Attributes: + a0:00 + Signature Algorithm: md5WithRSAEncryption + 7a:68:46:9e:58:4b:9e:42:66:9c:be:c1:d8:a0:40:4c:23:2f: + fc:12:96:eb:e8:f9:68:ed:a6:f3:f4:62:80:4c:26:ee:15:30: + a7:99:8b:8d:39:47:ba:3c:a0:4c:22:3d:d9:6b:ae:58:8a:36: + 49:c5:98:72:88:68:22:93:2d:17:14:e7:d4:9c:03:a0:03:10: + 85:94:ce:a9:94:cc:fe:42:b3:a8:eb:49:1a:37:34:a7:e0:d5: + b7:74:f4:3d:4a:f6:bb:10:91:17:3d:52:bb:fd:99:10:48:b2: + b7:9d:1a:76:04:08:d7:91:68:ae:51:d7:2c:e9:3a:8c:27:8a: + 75:c2 + +6. Now, sign the certificate request:: + + ./CA.pl -sign + + Using configuration from openssl.cnf + Enter PEM pass phrase: + Check that the request matches the signature + Signature ok + The Subjects Distinguished Name is as follows + countryName :PRINTABLE:'SG' + organizationName :PRINTABLE:'M2Crypto' + commonName :PRINTABLE:'localhost' + emailAddress :IA5STRING:'admin@server.example.dom' + Certificate is to be certified until Mar 31 02:57:30 2002 GMT (365 days) + Sign the certificate? [y/n]:y + + + 1 out of 1 certificate requests certified, commit? [y/n]y + Write out database with 1 new entries + Data Base Updated + Signed certificate is in newcert.pem + +\ + + ``newcert.pem`` looks like this:: + + cat newcert.pem + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom + Validity + Not Before: Mar 31 02:57:30 2001 GMT + Not After : Mar 31 02:57:30 2002 GMT + Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50: + 91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e: + 6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13: + 21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4: + c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac: + 4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f: + 6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9: + 6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f: + 0b:6f:e7:1c:bc:a6:59:97:ef + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom + Validity + Not Before: Mar 31 02:57:30 2001 GMT + Not After : Mar 31 02:57:30 2002 GMT + Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50: + 91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e: + 6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13: + 21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4: + c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac: + 4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f: + 6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9: + 6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f: + 0b:6f:e7:1c:bc:a6:59:97:ef + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + B3:D6:89:88:2F:B1:15:40:EC:0A:C0:30:35:3A:B7:DA:72:73:1B:4D + X509v3 Authority Key Identifier: + keyid:F9:6A:A6:34:97:6B:BC:BB:5A:17:0D:19:FC:62:21:0B:00:B5:0E:29 + DirName:/C=SG/O=DemoCA/CN=DemoCA Certificate Master/Email=certmaster@democa.dom + serial:00 + + Signature Algorithm: md5WithRSAEncryption + +7. In certain situations, e.g., where your certificate and private key + are to be used in an unattended SSL server, you may wish to not + encrypt the private key, i.e., leave the key in the clear. This + decision should be governed by your site's security policy and threat + model, of course:: + + openssl rsa < newkey.pem > newkey2.pem + + read RSA key + Enter PEM pass phrase: + writing RSA key + + ``newkey2.pem`` looks like this:: + + cat newkey2.pem + + -----BEGIN RSA PRIVATE KEY----- + MIICXgIBAAKBgQCvWdhjVCuWXWu4H8WqUJGuvme+6l0g37fAXur3Xm28RChzvhue + 7pvwhtsZEyHN3Oa9DhLMV9UQC4wy5Md7Js+rm2HtgOtM2LMorE4GeoTYpi5f1fbY + DUqHj2ygkkWDqQ9v0xSCJkGIyW+1vsrcId+DDlZqBacuXwtv5xy8plmX7wIDAQAB + AoGAbAkU8w3W1Qu15Hle1bJSL7GMReoreqeblOBmMAZz4by0l6sXZXJpjWXo86f/ + +dASMYTMPC4ZTYtv06N07AFbjL+kDfqDMTfzQkYMHp1LAq1Ihbq1rHWSBH5n3ekq + KiY8JKpv8DR5Po1iKaXJFuDByGDENJwYbSRSpSK3P+vkWWECQQDkEUE/ZPqqqZkQ + 2iWRPAsCbEID8SAraQl3DdCLYs/GgARfmmj4yUHEwkys9Jo1H8k4BdxugmaUwNi5 + YQ/CVzrXAkEAxNO80ArbGxPUmr11GHG/bGBYj1DUBkHZSc7dgxZdtUCLGNxQnNsg + Iwq3n6j1sUzS3UW6abQ8bivYNOUcMKJAqQJBANQxFaLU4b/NQaODQ3aoBZpAfP9L + 5eFdvbet+7zjt2r5CpikgkwOfAmDuXEltx/8LevY0CllW+nErx9zJgVrwUsCQQCu + 76H5JiznPBDSF2FjgHWqVVdgyW4owY3mU739LHvNBLicN/RN9VPy0Suy8/CqzKT9 + lWPBXzf2k3FuUdNkRlFBAkEAmpXoybuiFR2S5Bma/ax96lVs0/VihhfC1zZP/X/F + Br77+h9dIul+2DnyOl50zu0Sdzst1/7ay4JSDHyiBCMGSQ== + -----END RSA PRIVATE KEY----- + + +That's it! The certificate, ``newcert.pem``, and the private key - +``newkey.pem`` (encrypted) or ``newkey2.pem`` (unencrypted) - are now +ready to be used. You may wish to rename the files to more intuitive +names. + +You should also keep the CA's certificate ``demo/cacert.pem`` handy +for use when developing and deploying SSL or S/MIME applications. + +Conclusion +========== + +We've walked through the basic steps in the creation of a CA and +certificates using the tools that come with OpenSSL. We did not cover +more advanced topics such as constraining a certificate to be SSL-only +or S/MIME-only. + +There exist several HOWTOs similar to this one on the net. This one is +written specifically to facilitate discussions in my other HOWTOs on +developing SSL and S/MIME applications in +`Python `__ using +`M2Crypto `__. + diff --git a/doc/howto.smime.html b/doc/howto.smime.html deleted file mode 100644 index 21bc5cb..0000000 --- a/doc/howto.smime.html +++ /dev/null @@ -1,1570 +0,0 @@ -HOWTO: Programming S/MIME in Python with M2Crypto

    HOWTO: Programming S/MIME in Python with M2Crypto

    Pheng Siong Ng

    ngps@post1.com

    Copyright © 2000, 2001 by Ng Pheng Siong.

    Revision History
    Revision $Id: howto.smime.html 646 2008-10-29 03:12:56Z heikki $


    Introduction

    M2Crypto - is a Python - interface to OpenSSL. It makes - available to the Python programmer SSL functionality to implement clients - and servers, S/MIME v2, RSA, DSA, DH, symmetric ciphers, message digests and - HMACs. -

    This document demonstrates programming S/MIME with M2Crypto. -


    S/MIME

    S/MIME - Secure Multipurpose Internet Mail Extensions - [RFC 2311, RFC 2312] - provides a - consistent way to send and receive secure MIME data. Based on the popular - Internet MIME standard, S/MIME provides the following cryptographic security - services for electronic messaging applications - - authentication, message integrity - and non-repudiation of origin (using digital - signatures), and privacy and data - security (using encryption). -


    Keys and Certificates

    To create an S/MIME-signed message, you need an RSA key pair - (this consists of a public key and a private key) and an X.509 - certificate of said public key. -

    To create an S/MIME-encrypted message, you need an X.509 - certificate for each recipient. -

    To create an S/MIME-signed and -encrypted - message, first create a signed message, then encrypt the signed - message with the recipients' certificates. -

    You may generate key pairs and obtain certificates by using a - commercial certification authority service. -

    You can also do so using freely-available software. For many - purposes, e.g., automated S/MIME messaging by system administration - processes, this approach is cheap and effective. -

    We now work through using OpenSSL to generate key pairs and - certificates. This assumes you have OpenSSL installed properly on your - system. -

    First, we generate an X.509 certificate to be used for signing: -

        openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out signer.pem
    -    
    -    Using configuration from /usr/local/pkg/openssl/openssl.cnf
    -    Generating a 1024 bit RSA private key
    -    ..++++++
    -    ....................++++++
    -    writing new private key to 'privkey.pem'
    -    -----
    -    You are about to be asked to enter information that will be incorporated
    -    into your certificate request.
    -    What you are about to enter is what is called a Distinguished Name or a DN.
    -    There are quite a few fields but you can leave some blank
    -    For some fields there will be a default value,
    -    If you enter '.', the field will be left blank.
    -    -----
    -    Country Name (2 letter code) [AU]:SG
    -    State or Province Name (full name) [Some-State]:.
    -    Locality Name (eg, city) []:.
    -    Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto
    -    Organizational Unit Name (eg, section) []:.
    -    Common Name (eg, YOUR name) []:S/MIME Sender
    -    Email Address []:sender@example.dom
    -    

    This generates a 1024-bit RSA key pair, unencrypted, into - privkey.pem; it also generates a self-signed X.509 - certificate for the public key into signer.pem. The - certificate is valid for 365 days, i.e., a year. -

    Let's rename privkey.pem so that we know it is - a companion of signer.pem's: -

        mv privkey.pem signer_key.pem
    -    

    To verify the content of signer.pem, execute the - following: -

        openssl x509 -noout -text -in signer.pem
    -    
    -    Certificate:
    -        Data:
    -            Version: 3 (0x2)
    -            Serial Number: 0 (0x0)
    -            Signature Algorithm: md5WithRSAEncryption
    -            Issuer: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom
    -            Validity
    -                Not Before: Mar 24 12:56:16 2001 GMT
    -                Not After : Mar 24 12:56:16 2002 GMT
    -            Subject: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom
    -            Subject Public Key Info:
    -                Public Key Algorithm: rsaEncryption
    -                RSA Public Key: (1024 bit)
    -                    Modulus (1024 bit):
    -                        00:a9:d6:e2:b5:11:3b:ae:3c:e2:17:31:70:e1:6e:
    -                        01:f4:19:6d:bd:2a:42:36:2b:37:34:e2:83:1d:0d:
    -                        11:2e:b4:99:44:db:10:67:be:97:5f:5b:1a:26:33:
    -                        46:23:2f:95:04:7a:35:da:9d:f9:26:88:39:9e:17:
    -                        cd:3e:eb:a8:19:8d:a8:2a:f1:43:da:55:a9:2e:2c:
    -                        65:ed:04:71:42:ce:73:53:b8:ea:7e:c7:f0:23:c6:
    -                        63:c5:5e:68:96:64:a7:b4:2a:94:26:76:eb:79:ea:
    -                        e3:4e:aa:82:09:4f:44:87:4a:12:62:b5:d7:1f:ca:
    -                        f2:ce:d5:ba:7e:1f:48:fd:b9
    -                    Exponent: 65537 (0x10001)
    -            X509v3 extensions:
    -                X509v3 Subject Key Identifier: 
    -                    29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99
    -                X509v3 Authority Key Identifier: 
    -                    keyid:29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99
    -                    DirName:/C=SG/O=M2Crypto/CN=S/MIME Sender/Email=sender@example.dom
    -                    serial:00
    -    
    -                X509v3 Basic Constraints: 
    -                    CA:TRUE
    -        Signature Algorithm: md5WithRSAEncryption
    -            68:c8:6b:1b:fa:7c:9a:39:35:76:18:15:c9:fd:89:97:62:db:
    -            7a:b0:2d:13:dd:97:e8:1b:7a:9f:22:27:83:24:9d:2e:56:ec:
    -            97:89:3c:ef:16:55:80:5a:18:7c:22:d0:f6:bb:e3:a4:e8:59:
    -            30:ff:99:5a:93:3e:ea:bc:ee:7f:8d:d6:7d:37:8c:ac:3d:74:
    -            80:ce:7a:99:ba:27:b9:2a:a3:71:fa:a5:25:ba:47:17:df:07:
    -            56:96:36:fd:60:b9:6c:96:06:e8:e3:7b:9f:4b:6a:95:71:a8:
    -            34:fc:fc:b5:88:8b:c4:3f:1e:24:f6:52:47:b2:7d:44:67:d9:
    -            83:e8
    -    

    Next, we generate a self-signed X.509 certificate for the - recipient. Note that privkey.pem will be - recreated. -

        openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out recipient.pem
    -    
    -    Using configuration from /usr/local/pkg/openssl/openssl.cnf
    -    Generating a 1024 bit RSA private key
    -    .....................................++++++
    -    .................++++++
    -    writing new private key to 'privkey.pem'
    -    -----
    -    You are about to be asked to enter information that will be incorporated
    -    into your certificate request.
    -    What you are about to enter is what is called a Distinguished Name or a DN.
    -    There are quite a few fields but you can leave some blank
    -    For some fields there will be a default value,
    -    If you enter '.', the field will be left blank.
    -    -----
    -    Country Name (2 letter code) [AU]:SG
    -    State or Province Name (full name) [Some-State]:.
    -    Locality Name (eg, city) []:.
    -    Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto
    -    Organizational Unit Name (eg, section) []:.
    -    Common Name (eg, YOUR name) []:S/MIME Recipient
    -    Email Address []:recipient@example.dom
    -    

    Again, rename privkey.pem: -

        mv privkey.pem recipient_key.pem
    -    

    In the examples to follow, S/MIME Sender, - <sender@example.dom>, shall be the sender of S/MIME messages, - while S/MIME Recipient, <recipient@example.dom>, shall be the - recipient of S/MIME messages. -

    Armed with the key pairs and certificates, we are now ready to begin - programming S/MIME in Python. -

    Note: The private keys generated above are - not passphrase-protected, i.e., they are - in the clear. Anyone who has access to such a key can - generate S/MIME-signed messages with it, and decrypt S/MIME messages - encrypted to it's corresponding public key. -

    We may passphrase-protect the keys, if we so choose. M2Crypto will - prompt the user for the passphrase when such a key is being loaded. -


    M2Crypto.SMIME

    The Python programmer accesses M2Crypto's S/MIME functionality - through class SMIME in the module - M2Crypto.SMIME. Typically, an SMIME - object is instantiated; the object is then set up for the intended - operation: sign, encrypt, decrypt or verify; finally, the operation is invoked on - the object. -

    M2Crypto.SMIME makes extensive use of - M2Crypto.BIO: M2Crypto.BIO - is a Python abstraction of the BIO abstraction in - OpenSSL. A commonly used BIO abstraction in M2Crypto is - M2Crypto.BIO.MemoryBuffer, which implements a - memory-based file-like object, similar to Python's own - StringIO. -


    Sign

    The following code demonstrates how to generate an S/MIME-signed - message. randpool.dat contains random data which is - used to seed OpenSSL's pseudo-random number generator via M2Crypto. -

        from M2Crypto import BIO, Rand, SMIME
    -
    -    def makebuf(text):
    -        return BIO.MemoryBuffer(text)
    -
    -    # Make a MemoryBuffer of the message.
    -    buf = makebuf('a sign of our times')
    -
    -    # Seed the PRNG.
    -    Rand.load_file('randpool.dat', -1)
    -
    -    # Instantiate an SMIME object; set it up; sign the buffer.
    -    s = SMIME.SMIME()
    -    s.load_key('signer_key.pem', 'signer.pem')
    -    p7 = s.sign(buf)
    -    

    p7 now contains a PKCS #7 signature - blob wrapped in an M2Crypto.SMIME.PKCS7 - object. Note that buf has been consumed by - sign() and has to be recreated if it is to be used - again. -

    We may now send the signed message via SMTP. In these examples, we - shall not do so; instead, we'll render the S/MIME output in - mail-friendly format, and pretend that our messages are sent and - received correctly. -

        # Recreate buf.
    -    buf = makebuf('a sign of our times')
    -
    -    # Output p7 in mail-friendly format.
    -    out = BIO.MemoryBuffer()
    -    out.write('From: sender@example.dom\n')
    -    out.write('To: recipient@example.dom\n')
    -    out.write('Subject: M2Crypto S/MIME testing\n')
    -    s.write(out, p7, buf)
    -
    -    print out.read()
    -
    -    # Save the PRNG's state.
    -    Rand.save_file('randpool.dat')
    -    

    Here's the output: -

        From: sender@example.dom
    -    To: recipient@example.dom
    -    Subject: M2Crypto S/MIME testing
    -    MIME-Version: 1.0
    -    Content-Type: multipart/signed ; protocol="application/x-pkcs7-signature" ; micalg=sha1 ; boundary="----3C93156FC7B4EBF49FE9C7DB7F503087"
    -    
    -    This is an S/MIME signed message
    -    
    -    ------3C93156FC7B4EBF49FE9C7DB7F503087
    -    a sign of our times
    -    ------3C93156FC7B4EBF49FE9C7DB7F503087
    -    Content-Type: application/x-pkcs7-signature; name="smime.p7s"
    -    Content-Transfer-Encoding: base64
    -    Content-Disposition: attachment; filename="smime.p7s"
    -    
    -    MIIE8AYJKoZIhvcNAQcCoIIE4TCCBN0CAQExCzAJBgUrDgMCGgUAMCIGCSqGSIb3
    -    DQEHAaAVBBNhIHNpZ24gb2Ygb3VyIHRpbWVzoIIC5zCCAuMwggJMoAMCAQICAQAw
    -    DQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv
    -    MRYwFAYDVQQDEw1TL01JTUUgU2VuZGVyMSEwHwYJKoZIhvcNAQkBFhJzZW5kZXJA
    -    ZXhhbXBsZS5kb20wHhcNMDEwMzMxMTE0MDMzWhcNMDIwMzMxMTE0MDMzWjBbMQsw
    -    CQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBT
    -    ZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTCBnzANBgkq
    -    hkiG9w0BAQEFAAOBjQAwgYkCgYEA5c5Tj1CHTSOxa1q2q0FYiwMWYHptJpJcvtZm
    -    UwrgU5sHrA8OnCM0cDXEj0KPf3cfNjHffB8HWMzI4UEgNmFXQNsxoGZ+iqwxLlNj
    -    y9Mh7eFW/Bjq5hNXbouSlQ0rWBRkoxV64y+t6lQehb32WfYXQbKFxFJSXzSxOx3R
    -    8YhSPd0CAwEAAaOBtjCBszAdBgNVHQ4EFgQUXOyolL1t4jaBwZFRM7MS8nBLzUow
    -    gYMGA1UdIwR8MHqAFFzsqJS9beI2gcGRUTOzEvJwS81KoV+kXTBbMQswCQYDVQQG
    -    EwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIx
    -    ITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbYIBADAMBgNVHRMEBTAD
    -    AQH/MA0GCSqGSIb3DQEBBAUAA4GBAHo3DrCHR86fSTVAvfiXdSswWqKtCEhUHRdC
    -    TLFGl4hDk2GyZxaFuqZwiURz/H7nMicymI2wkz8H/wyHFg8G3BIehURpj2v/ZWXY
    -    eovbgS7EZALVVkDj4hNl/IIHWd6Gtv1UODf7URbxtl3hQ9/eTWITrefT1heuPnar
    -    8czydsOLMYIBujCCAbYCAQEwYDBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJD
    -    cnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNl
    -    bmRlckBleGFtcGxlLmRvbQIBADAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzEL
    -    BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAxMDMzMTExNDUwMlowIwYJKoZI
    -    hvcNAQkEMRYEFOoeRUd8ExIYXfQq8BTFuKWrSP3iMFIGCSqGSIb3DQEJDzFFMEMw
    -    CgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO
    -    AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIGAQpU8hFUtLCF6hO2t
    -    ec9EYJ/Imqqiiw+BxWxkUUVT81Vbjwdn9JST6+sztM5JRP2ZW+b4txEjZriYC8f3
    -    kv95YMTGbIsuWkJ93GrbvqoJ/CxO23r9WWRnZEm/1EZN9ZmlrYqzBTxnNRmP3Dhj
    -    cW8kzZwH+2/2zz2G7x1HxRWH95A=
    -    
    -    ------3C93156FC7B4EBF49FE9C7DB7F503087--
    -    

    Verify

    Assume the above output has been saved into sign.p7. - Let's now verify the signature: -

        from M2Crypto import SMIME, X509
    -    
    -    # Instantiate an SMIME object.
    -    s = SMIME.SMIME()
    -    
    -    # Load the signer's cert.
    -    x509 = X509.load_cert('signer.pem')
    -    sk = X509.X509_Stack()
    -    sk.push(x509)
    -    s.set_x509_stack(sk)
    -    
    -    # Load the signer's CA cert. In this case, because the signer's
    -    # cert is self-signed, it is the signer's cert itself.
    -    st = X509.X509_Store()
    -    st.load_info('signer.pem')
    -    s.set_x509_store(st)
    -    
    -    # Load the data, verify it.
    -    p7, data = SMIME.smime_load_pkcs7('sign.p7')
    -    v = s.verify(p7)
    -    print v
    -    print data
    -    print data.read()
    -    

    Here's the output of the above program: -

        a sign of our times
    -    <M2Crypto.BIO.BIO instance at 0x822012c>
    -    a sign of our times
    -    

    Suppose, instead of loading signer.pem above, - we load recipient.pem. That is, we do a global - substitution of recipient.pem for - signer.pem in the above program. Here's the modified - program's output: -

        Traceback (most recent call last):
    -      File "./verify.py", line 22, in ?
    -        v = s.verify(p7)
    -      File "/usr/local/home/ngps/prog/m2/M2Crypto/SMIME.py", line 205, in verify
    -        raise SMIME_Error, Err.get_error()
    -    M2Crypto.SMIME.SMIME_Error: 312:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:213:Verify error:self signed certificate
    -    

    As displayed, the error is generated by line 213 of OpenSSL's - pk7_smime.c (as of OpenSSL 0.9.6); if you are a - C programmer, you may wish to look up the C source to explore OpenSSL's - S/MIME implementation and understand why the error message is worded thus. -


    Encrypt

    We now demonstrate how to generate an S/MIME-encrypted message: -

        from M2Crypto import BIO, Rand, SMIME, X509
    -    
    -    def makebuf(text):
    -        return BIO.MemoryBuffer(text)
    -    
    -    # Make a MemoryBuffer of the message.
    -    buf = makebuf('a sign of our times')
    -    
    -    # Seed the PRNG.
    -    Rand.load_file('randpool.dat', -1)
    -
    -    # Instantiate an SMIME object.
    -    s = SMIME.SMIME()
    -    
    -    # Load target cert to encrypt to.
    -    x509 = X509.load_cert('recipient.pem')
    -    sk = X509.X509_Stack()
    -    sk.push(x509)
    -    s.set_x509_stack(sk)
    -    
    -    # Set cipher: 3-key triple-DES in CBC mode.
    -    s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
    -    
    -    # Encrypt the buffer.
    -    p7 = s.encrypt(buf)
    -        
    -    # Output p7 in mail-friendly format.
    -    out = BIO.MemoryBuffer()
    -    out.write('From: sender@example.dom\n')
    -    out.write('To: recipient@example.dom\n')
    -    out.write('Subject: M2Crypto S/MIME testing\n')
    -    s.write(out, p7)
    -    
    -    print out.read()
    -
    -    # Save the PRNG's state.
    -    Rand.save_file('randpool.dat')
    -    

    Here's the output of the above program: -

        From: sender@example.dom
    -    To: recipient@example.dom
    -    Subject: M2Crypto S/MIME testing
    -    MIME-Version: 1.0
    -    Content-Disposition: attachment; filename="smime.p7m"
    -    Content-Type: application/x-pkcs7-mime; name="smime.p7m"
    -    Content-Transfer-Encoding: base64
    -    
    -    MIIBVwYJKoZIhvcNAQcDoIIBSDCCAUQCAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE
    -    BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp
    -    ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ
    -    KoZIhvcNAQEBBQAEgYCBaXZ+qjpBEZwdP7gjfzfAtQitESyMwo3i+LBOw6sSDir6
    -    FlNDPCnkrTvqDX3Rt6X6vBtTCYOm+qiN7ujPkOU61cN7h8dvHR8YW9+0IPY80/W0
    -    lZ/HihSRgwTNd7LnxUUcPx8YV1id0dlmP0Hz+Lg+mHf6rqaR//JcYhX9vW4XvjA7
    -    BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECMN+qya6ADywgBgHr9Jkhwn5Gsdu7BwX
    -    nIQfYTYcdL9I5Sk=
    -    

    Decrypt

    Assume the above output has been saved into encrypt.p7. - Decrypt the message thusly: -

        from M2Crypto import BIO, SMIME, X509
    -    
    -    # Instantiate an SMIME object.
    -    s = SMIME.SMIME()
    -    
    -    # Load private key and cert.
    -    s.load_key('recipient_key.pem', 'recipient.pem')
    -    
    -    # Load the encrypted data.
    -    p7, data = SMIME.smime_load_pkcs7('encrypt.p7')
    -    
    -    # Decrypt p7.
    -    out = s.decrypt(p7)
    -        
    -    print out
    -    

    Here's the output: -

        a sign of our times
    -    

    Sign and Encrypt

    Here's how to generate an S/MIME-signed/encrypted message: -

        from M2Crypto import BIO, Rand, SMIME, X509
    -    
    -    def makebuf(text):
    -        return BIO.MemoryBuffer(text)
    -    
    -    # Make a MemoryBuffer of the message.
    -    buf = makebuf('a sign of our times')
    -    
    -    # Seed the PRNG.
    -    Rand.load_file('randpool.dat', -1)
    -    
    -    # Instantiate an SMIME object.
    -    s = SMIME.SMIME()
    -    
    -    # Load signer's key and cert. Sign the buffer.
    -    s.load_key('signer_key.pem', 'signer.pem')
    -    p7 = s.sign(buf)
    -    
    -    # Load target cert to encrypt the signed message to.
    -    x509 = X509.load_cert('recipient.pem')
    -    sk = X509.X509_Stack()
    -    sk.push(x509)
    -    s.set_x509_stack(sk)
    -    
    -    # Set cipher: 3-key triple-DES in CBC mode.
    -    s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
    -    
    -    # Create a temporary buffer.
    -    tmp = BIO.MemoryBuffer()
    -    
    -    # Write the signed message into the temporary buffer.
    -    s.write(tmp, p7, buf)
    -    
    -    # Encrypt the temporary buffer.
    -    p7 = s.encrypt(tmp)
    -        
    -    # Output p7 in mail-friendly format.
    -    out = BIO.MemoryBuffer()
    -    out.write('From: sender@example.dom\n')
    -    out.write('To: recipient@example.dom\n')
    -    out.write('Subject: M2Crypto S/MIME testing\n')
    -    s.write(out, p7)
    -    
    -    print out.read()
    -    
    -    # Save the PRNG's state.
    -    Rand.save_file('randpool.dat')
    -    

    Here's the output of the above program: -

        From: sender@example.dom
    -    To: recipient@example.dom
    -    Subject: M2Crypto S/MIME testing
    -    MIME-Version: 1.0
    -    Content-Disposition: attachment; filename="smime.p7m"
    -    Content-Type: application/x-pkcs7-mime; name="smime.p7m"
    -    Content-Transfer-Encoding: base64
    -    
    -    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
    -    

    Decrypt and Verify

    Suppose the above output has been saved into - se.p7. The following demonstrates how to decrypt and - verify it: -

        from M2Crypto import BIO, SMIME, X509
    -    
    -    # Instantiate an SMIME object.
    -    s = SMIME.SMIME()
    -    
    -    # Load private key and cert.
    -    s.load_key('recipient_key.pem', 'recipient.pem')
    -    
    -    # Load the signed/encrypted data.
    -    p7, data = SMIME.smime_load_pkcs7('se.p7')
    -    
    -    # After the above step, 'data' == None.  
    -    # Decrypt p7. 'out' now contains a PKCS #7 signed blob.
    -    out = s.decrypt(p7)
    -    
    -    # Load the signer's cert.
    -    x509 = X509.load_cert('signer.pem')
    -    sk = X509.X509_Stack()
    -    sk.push(x509)
    -    s.set_x509_stack(sk)
    -    
    -    # Load the signer's CA cert. In this case, because the signer's
    -    # cert is self-signed, it is the signer's cert itself.
    -    st = X509.X509_Store()
    -    st.load_info('signer.pem')
    -    s.set_x509_store(st)
    -    
    -    # Recall 'out' contains a PKCS #7 blob.
    -    # Transform 'out'; verify the resulting PKCS #7 blob.
    -    p7_bio = BIO.MemoryBuffer(out)
    -    p7, data = SMIME.smime_load_pkcs7_bio(p7_bio)
    -    v = s.verify(p7)
    -    
    -    print v
    -    

    The output is as follows: -

        a sign of our times
    -    

    Sending S/MIME messages via SMTP

    In the above examples, we've assumed that our S/MIME messages - are sent and received automagically. The following is a Python function that - generates S/MIME-signed/encrypted messages and sends them via SMTP: -

        from M2Crypto import BIO, SMIME, X509
    -    import smtplib, string, sys
    -    
    -    def sendsmime(from_addr, to_addrs, subject, msg, from_key, from_cert=None, to_certs=None, smtpd='localhost'):
    -    
    -        msg_bio = BIO.MemoryBuffer(msg)
    -        sign = from_key
    -        encrypt = to_certs
    -    
    -        s = SMIME.SMIME()
    -        if sign:
    -            s.load_key(from_key, from_cert)
    -            p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT)
    -            msg_bio = BIO.MemoryBuffer(msg) # Recreate coz sign() has consumed it.
    -    
    -        if encrypt:
    -            sk = X509.X509_Stack()
    -            for x in to_certs:
    -                sk.push(X509.load_cert(x))
    -            s.set_x509_stack(sk)
    -            s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
    -            tmp_bio = BIO.MemoryBuffer()
    -            if sign:
    -                s.write(tmp_bio, p7)
    -            else:
    -                tmp_bio.write(msg)
    -            p7 = s.encrypt(tmp_bio)
    -    
    -        out = BIO.MemoryBuffer()
    -        out.write('From: %s\r\n' % from_addr)
    -        out.write('To: %s\r\n' % string.join(to_addrs, ", "))
    -        out.write('Subject: %s\r\n' % subject) 
    -        if encrypt:
    -            s.write(out, p7)
    -        else:
    -            if sign:
    -                s.write(out, p7, msg_bio, SMIME.PKCS7_TEXT)
    -            else:
    -                out.write('\r\n')
    -                out.write(msg)
    -        out.close()
    -    
    -        smtp = smtplib.SMTP()
    -        smtp.connect(smtpd)
    -        smtp.sendmail(from_addr, to_addrs, out.read())
    -        smtp.quit()
    -    

    This function sends plain, S/MIME-signed, S/MIME-encrypted, - and S/MIME-signed/encrypted messages, depending on the parameters - from_key and to_certs. The - function's output interoperates with Netscape Messenger. -


    Verifying origin of S/MIME messages

    In our examples above that decrypt or verify messages, we skipped - a step: verifying that the from address of the message - matches the email address attribute in the sender's - certificate. -

    The premise of current X.509 certification practice is that the - CA is supposed to verify your identity, and to issue a certificate with - email address that matches your actual mail address. - (Verisign's March 2001 failure in identity verification resulting in - Microsoft certificates being issued to spoofers notwithstanding.) -

    If you run your own CA, your certification practice is up to you, of - course, and it would probably be part of your security policy. -

    Whether your S/MIME messaging application needs to verify the - from addresses of S/MIME messages depends on your - security policy and your system's threat model, as always. -


    Interoperating with Netscape Messenger

    Suppose S/MIME Recipient uses Netscape Messenger. To enable Messenger - to handle S/MIME messages from S/MIME Sender, S/MIME Recipient needs - to configure Messenger with his private key and certificate, as well as S/MIME - Sender's certificate. -

    Note: Configuring Messenger's POP or IMAP settings so that it retrieves - mail correctly is beyond the scope of this HOWTO. -

    The following steps demonstrate how to import S/MIME Recipient's - private key and certificate for Messenger: -

    1. Transform S/MIME Recipient's private key and certificate into - PKCS #12 format. -

          openssl pkcs12 -export -in recipient.pem -inkey recipient_key.pem -name "S/MIME Recipient" -out recipient.p12
      -    
      -    Enter Export Password:<enter>
      -    Verifying password - Enter Export Password:<enter>
      -    
    2. Start Messenger. -

    3. Click on the (open) "lock" icon at the bottom left corner of - Messenger's window. This brings up the "Security Info" dialog box. -

    4. Click on "Yours" under "Certificates". -

    5. Select "Import a certificate", then pick - recipient.p12 from the ensuing file selection dialog - box. -

    Next, you need to import signer.pem as a CA - certificate, so that Messenger will mark messages signed by S/MIME Sender as - "trusted": -

    1. Create a DER encoding of signer.pem. -

          openssl x509 -inform pem -outform der -in signer.pem -out signer.der
      -    
      -    
    2. Install signer.der into Messenger as MIME type - application/x-x509-ca-cert. You do this by downloading - signer.der via Navigator from a HTTP or HTTPS server, - with the correct MIME type mapping. (You may use - demo/ssl/https_srv.py, bundled with M2Crypto, for - this purpose.) Follow the series of dialog boxes to accept - signer.der as a CA for certifying email users. -

    S/MIME Recipient is now able to decrypt and read S/MIME Sender's - messages with Messenger. Messenger will indicate that S/MIME Sender's - messages are signed, encrypted, or encrypted and - signed, as the case may be, via the "stamp" icon on the message window's - top right corner. -

    Clicking on the "stamp" icon brings you to the Security Info dialog - box. Messenger informs you that the message is, say, encrypted with - 168-bit DES-EDE3-CBC and that it is digitally signed by the private key - corresponding to the public key contained in the certificate - signer.pem. -


    Interoperating with Microsoft Outlook

    I do not know how to do this, as I do not use Outlook. (Nor do I use - Netscape Messenger, actually. I use Mutt, top dog of MUAs. ;-) Information on - how to configure Outlook with keys and certificates so that it handles - S/MIME mail is gratefully accepted. -


    ZSmime

    ZSmime is a Zope - product that enables Zope to generate - S/MIME-signed/encrypted messages. ZSmime demonstrates how to invoke - M2Crypto in a web application server extension. -

    ZSmime has its own HOWTO - explaining its usage. (That HOWTO has some overlap in content with - this document.) -


    Resources


    $Id:howto.smime.html 583 2007-10-01 19:23:12Z heikki $ -

    \ No newline at end of file diff --git a/doc/howto.smime.rst b/doc/howto.smime.rst new file mode 100644 index 0000000..715e7c4 --- /dev/null +++ b/doc/howto.smime.rst @@ -0,0 +1,778 @@ +:orphan: + +.. _howto-smime: + +HOWTO: Programming S/MIME in Python with M2Crypto +================================================= + +:author: Pheng Siong Ng +:copyright: © 2000, 2001 by Ng Pheng Siong. + +Introduction +============ + +`M2Crypto `__ is a +`Python `__ interface to +`OpenSSL `__. It makes available to the Python +programmer SSL functionality to implement clients and servers, S/MIME +v2, RSA, DSA, DH, symmetric ciphers, message digests and HMACs. + +This document demonstrates programming S/MIME with M2Crypto. + +S/MIME +====== + +S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC +2312] - provides a consistent way to send and receive secure MIME data. +Based on the popular Internet MIME standard, S/MIME provides the +following cryptographic security services for electronic messaging +applications - *authentication*, *message integrity* and +*non-repudiation of origin* (using *digital signatures*), and *privacy* +and *data security* (using *encryption*). + +Keys and Certificates +===================== + +To create an S/MIME-signed message, you need an RSA key pair (this +consists of a public key and a private key) and an X.509 certificate of +said public key. + +To create an S/MIME-encrypted message, you need an X.509 certificate for +each recipient. + +To create an S/MIME-signed *and* -encrypted message, first create a +signed message, then encrypt the signed message with the recipients' +certificates. + +You may generate key pairs and obtain certificates by using a commercial +*certification authority* service. + +You can also do so using freely-available software. For many purposes, +e.g., automated S/MIME messaging by system administration processes, +this approach is cheap and effective. + +We now work through using OpenSSL to generate key pairs and +certificates. This assumes you have OpenSSL installed properly on your +system. + +First, we generate an X.509 certificate to be used for signing:: + + openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out signer.pem + + Using configuration from /usr/local/pkg/openssl/openssl.cnf + Generating a 1024 bit RSA private key + ..++++++ + ....................++++++ + writing new private key to 'privkey.pem' + ----- + You are about to be asked to enter information that will be incorporated + into your certificate request. + What you are about to enter is what is called a Distinguished Name or a DN. + There are quite a few fields but you can leave some blank + For some fields there will be a default value, + If you enter '.', the field will be left blank. + ----- + Country Name (2 letter code) [AU]:SG + State or Province Name (full name) [Some-State]:. + Locality Name (eg, city) []:. + Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto + Organizational Unit Name (eg, section) []:. + Common Name (eg, YOUR name) []:S/MIME Sender + Email Address []:sender@example.dom + + +This generates a 1024-bit RSA key pair, unencrypted, into +``privkey.pem``; it also generates a self-signed X.509 certificate for +the public key into ``signer.pem``. The certificate is valid for 365 +days, i.e., a year. + +Let's rename ``privkey.pem`` so that we know it is a companion of +``signer.pem``'s:: + + mv privkey.pem signer_key.pem + +To verify the content of ``signer.pem``, execute the following:: + + openssl x509 -noout -text -in signer.pem + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom + Validity + Not Before: Mar 24 12:56:16 2001 GMT + Not After : Mar 24 12:56:16 2002 GMT + Subject: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a9:d6:e2:b5:11:3b:ae:3c:e2:17:31:70:e1:6e: + 01:f4:19:6d:bd:2a:42:36:2b:37:34:e2:83:1d:0d: + 11:2e:b4:99:44:db:10:67:be:97:5f:5b:1a:26:33: + 46:23:2f:95:04:7a:35:da:9d:f9:26:88:39:9e:17: + cd:3e:eb:a8:19:8d:a8:2a:f1:43:da:55:a9:2e:2c: + 65:ed:04:71:42:ce:73:53:b8:ea:7e:c7:f0:23:c6: + 63:c5:5e:68:96:64:a7:b4:2a:94:26:76:eb:79:ea: + e3:4e:aa:82:09:4f:44:87:4a:12:62:b5:d7:1f:ca: + f2:ce:d5:ba:7e:1f:48:fd:b9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99 + X509v3 Authority Key Identifier: + keyid:29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99 + DirName:/C=SG/O=M2Crypto/CN=S/MIME Sender/Email=sender@example.dom + serial:00 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 68:c8:6b:1b:fa:7c:9a:39:35:76:18:15:c9:fd:89:97:62:db: + 7a:b0:2d:13:dd:97:e8:1b:7a:9f:22:27:83:24:9d:2e:56:ec: + 97:89:3c:ef:16:55:80:5a:18:7c:22:d0:f6:bb:e3:a4:e8:59: + 30:ff:99:5a:93:3e:ea:bc:ee:7f:8d:d6:7d:37:8c:ac:3d:74: + 80:ce:7a:99:ba:27:b9:2a:a3:71:fa:a5:25:ba:47:17:df:07: + 56:96:36:fd:60:b9:6c:96:06:e8:e3:7b:9f:4b:6a:95:71:a8: + 34:fc:fc:b5:88:8b:c4:3f:1e:24:f6:52:47:b2:7d:44:67:d9: + 83:e8 + +Next, we generate a self-signed X.509 certificate for the recipient. +Note that ``privkey.pem`` will be recreated:: + + openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out recipient.pem + + Using configuration from /usr/local/pkg/openssl/openssl.cnf + Generating a 1024 bit RSA private key + .....................................++++++ + .................++++++ + writing new private key to 'privkey.pem' + ----- + You are about to be asked to enter information that will be incorporated + into your certificate request. + What you are about to enter is what is called a Distinguished Name or a DN. + There are quite a few fields but you can leave some blank + For some fields there will be a default value, + If you enter '.', the field will be left blank. + ----- + Country Name (2 letter code) [AU]:SG + State or Province Name (full name) [Some-State]:. + Locality Name (eg, city) []:. + Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto + Organizational Unit Name (eg, section) []:. + Common Name (eg, YOUR name) []:S/MIME Recipient + Email Address []:recipient@example.dom + +Again, rename ``privkey.pem``:: + + mv privkey.pem recipient_key.pem + + +In the examples to follow, S/MIME Sender, ````, +shall be the sender of S/MIME messages, while S/MIME Recipient, +````, shall be the recipient of S/MIME messages. + +Armed with the key pairs and certificates, we are now ready to begin +programming S/MIME in Python. + + **Note:** The private keys generated above are *not + passphrase-protected*, i.e., they are *in the clear*. Anyone who has + access to such a key can generate S/MIME-signed messages with it, + and decrypt S/MIME messages encrypted to it's corresponding public + key. + + We may passphrase-protect the keys, if we so choose. M2Crypto will + prompt the user for the passphrase when such a key is being loaded. + +M2Crypto.SMIME +============== + +The Python programmer accesses M2Crypto's S/MIME functionality through +class ``SMIME`` in the module ``M2Crypto.SMIME``. Typically, an +``SMIME`` object is instantiated; the object is then set up for the +intended operation: sign, encrypt, decrypt or verify; finally, the +operation is invoked on the object. + +``M2Crypto.SMIME`` makes extensive use of ``M2Crypto.BIO``: +``M2Crypto.BIO`` is a Python abstraction of the ``BIO`` abstraction in +OpenSSL. A commonly used ``BIO`` abstraction in M2Crypto is +``M2Crypto.BIO.MemoryBuffer``, which implements a memory-based file-like +object, similar to Python's own ``StringIO``. + +Sign +==== + +The following code demonstrates how to generate an S/MIME-signed +message. ``randpool.dat`` contains random data which is used to seed +OpenSSL's pseudo-random number generator via M2Crypto:: + + from M2Crypto import BIO, Rand, SMIME + + def makebuf(text): + return BIO.MemoryBuffer(text) + + # Make a MemoryBuffer of the message. + buf = makebuf('a sign of our times') + + # Seed the PRNG. + Rand.load_file('randpool.dat', -1) + + # Instantiate an SMIME object; set it up; sign the buffer. + s = SMIME.SMIME() + s.load_key('signer_key.pem', 'signer.pem') + p7 = s.sign(buf, SMIME.PKCS7_DETACHED) + + +``p7`` now contains a *PKCS #7 signature blob* wrapped in an +``M2Crypto.SMIME.PKCS7`` object. Note that ``buf`` has been consumed by +``sign()`` and has to be recreated if it is to be used again. + +We may now send the signed message via SMTP. In these examples, we shall +not do so; instead, we'll render the S/MIME output in mail-friendly +format, and pretend that our messages are sent and received +correctly:: + + # Recreate buf. + buf = makebuf('a sign of our times') + + # Output p7 in mail-friendly format. + out = BIO.MemoryBuffer() + out.write('From: sender@example.dom\n') + out.write('To: recipient@example.dom\n') + out.write('Subject: M2Crypto S/MIME testing\n') + s.write(out, p7, buf) + + print(out.read()) + + # Save the PRNG's state. + Rand.save_file('randpool.dat') + +Here's the output:: + + From: sender@example.dom + To: recipient@example.dom + Subject: M2Crypto S/MIME testing + MIME-Version: 1.0 + Content-Type: multipart/signed ; protocol="application/x-pkcs7-signature" ; micalg=sha1 ; boundary="----3C93156FC7B4EBF49FE9C7DB7F503087" + + This is an S/MIME signed message + + ------3C93156FC7B4EBF49FE9C7DB7F503087 + a sign of our times + ------3C93156FC7B4EBF49FE9C7DB7F503087 + Content-Type: application/x-pkcs7-signature; name="smime.p7s" + Content-Transfer-Encoding: base64 + Content-Disposition: attachment; filename="smime.p7s" + + MIIE8AYJKoZIhvcNAQcCoIIE4TCCBN0CAQExCzAJBgUrDgMCGgUAMCIGCSqGSIb3 + DQEHAaAVBBNhIHNpZ24gb2Ygb3VyIHRpbWVzoIIC5zCCAuMwggJMoAMCAQICAQAw + DQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv + MRYwFAYDVQQDEw1TL01JTUUgU2VuZGVyMSEwHwYJKoZIhvcNAQkBFhJzZW5kZXJA + ZXhhbXBsZS5kb20wHhcNMDEwMzMxMTE0MDMzWhcNMDIwMzMxMTE0MDMzWjBbMQsw + CQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBT + ZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTCBnzANBgkq + hkiG9w0BAQEFAAOBjQAwgYkCgYEA5c5Tj1CHTSOxa1q2q0FYiwMWYHptJpJcvtZm + UwrgU5sHrA8OnCM0cDXEj0KPf3cfNjHffB8HWMzI4UEgNmFXQNsxoGZ+iqwxLlNj + y9Mh7eFW/Bjq5hNXbouSlQ0rWBRkoxV64y+t6lQehb32WfYXQbKFxFJSXzSxOx3R + 8YhSPd0CAwEAAaOBtjCBszAdBgNVHQ4EFgQUXOyolL1t4jaBwZFRM7MS8nBLzUow + gYMGA1UdIwR8MHqAFFzsqJS9beI2gcGRUTOzEvJwS81KoV+kXTBbMQswCQYDVQQG + EwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIx + ITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbYIBADAMBgNVHRMEBTAD + AQH/MA0GCSqGSIb3DQEBBAUAA4GBAHo3DrCHR86fSTVAvfiXdSswWqKtCEhUHRdC + TLFGl4hDk2GyZxaFuqZwiURz/H7nMicymI2wkz8H/wyHFg8G3BIehURpj2v/ZWXY + eovbgS7EZALVVkDj4hNl/IIHWd6Gtv1UODf7URbxtl3hQ9/eTWITrefT1heuPnar + 8czydsOLMYIBujCCAbYCAQEwYDBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJD + cnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNl + bmRlckBleGFtcGxlLmRvbQIBADAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzEL + BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAxMDMzMTExNDUwMlowIwYJKoZI + hvcNAQkEMRYEFOoeRUd8ExIYXfQq8BTFuKWrSP3iMFIGCSqGSIb3DQEJDzFFMEMw + CgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO + AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIGAQpU8hFUtLCF6hO2t + ec9EYJ/Imqqiiw+BxWxkUUVT81Vbjwdn9JST6+sztM5JRP2ZW+b4txEjZriYC8f3 + kv95YMTGbIsuWkJ93GrbvqoJ/CxO23r9WWRnZEm/1EZN9ZmlrYqzBTxnNRmP3Dhj + cW8kzZwH+2/2zz2G7x1HxRWH95A= + + ------3C93156FC7B4EBF49FE9C7DB7F503087-- + + +Verify +====== + +Assume the above output has been saved into ``sign.p7``. Let's now +verify the signature:: + + from M2Crypto import SMIME, X509 + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load the signer's cert. + x509 = X509.load_cert('signer.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + # Load the signer's CA cert. In this case, because the signer's + # cert is self-signed, it is the signer's cert itself. + st = X509.X509_Store() + st.load_info('signer.pem') + s.set_x509_store(st) + + # Load the data, verify it. + p7, data = SMIME.smime_load_pkcs7('sign.p7') + v = s.verify(p7, data) + print(v) + print(data) + print(data.read()) + +Here's the output of the above program:: + + a sign of our times + + a sign of our times + +Suppose, instead of loading ``signer.pem`` above, we load +``recipient.pem``. That is, we do a global substitution of +``recipient.pem`` for ``signer.pem`` in the above program. Here's the +modified program's output:: + + Traceback (most recent call last): + File "./verify.py", line 22, in ? + v = s.verify(p7) + File "/usr/local/home/ngps/prog/m2/M2Crypto/SMIME.py", line 205, in verify + raise SMIME_Error, Err.get_error() + M2Crypto.SMIME.SMIME_Error: 312:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:213:Verify error:self signed certificate + + +As displayed, the error is generated by line 213 of OpenSSL's +``pk7_smime.c`` (as of OpenSSL 0.9.6); if you are a C programmer, you +may wish to look up the C source to explore OpenSSL's S/MIME +implementation and understand why the error message is worded thus. + +Encrypt +======= + +We now demonstrate how to generate an S/MIME-encrypted message:: + + from M2Crypto import BIO, Rand, SMIME, X509 + + def makebuf(text): + return BIO.MemoryBuffer(text) + + # Make a MemoryBuffer of the message. + buf = makebuf('a sign of our times') + + # Seed the PRNG. + Rand.load_file('randpool.dat', -1) + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load target cert to encrypt to. + x509 = X509.load_cert('recipient.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + # Set cipher: 3-key triple-DES in CBC mode. + s.set_cipher(SMIME.Cipher('des_ede3_cbc')) + + # Encrypt the buffer. + p7 = s.encrypt(buf) + + # Output p7 in mail-friendly format. + out = BIO.MemoryBuffer() + out.write('From: sender@example.dom\n') + out.write('To: recipient@example.dom\n') + out.write('Subject: M2Crypto S/MIME testing\n') + s.write(out, p7) + + print(out.read()) + + # Save the PRNG's state. + Rand.save_file('randpool.dat') + +Here's the output of the above program:: + + From: sender@example.dom + To: recipient@example.dom + Subject: M2Crypto S/MIME testing + MIME-Version: 1.0 + Content-Disposition: attachment; filename="smime.p7m" + Content-Type: application/x-pkcs7-mime; name="smime.p7m" + Content-Transfer-Encoding: base64 + + MIIBVwYJKoZIhvcNAQcDoIIBSDCCAUQCAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE + BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp + ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ + KoZIhvcNAQEBBQAEgYCBaXZ+qjpBEZwdP7gjfzfAtQitESyMwo3i+LBOw6sSDir6 + FlNDPCnkrTvqDX3Rt6X6vBtTCYOm+qiN7ujPkOU61cN7h8dvHR8YW9+0IPY80/W0 + lZ/HihSRgwTNd7LnxUUcPx8YV1id0dlmP0Hz+Lg+mHf6rqaR//JcYhX9vW4XvjA7 + BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECMN+qya6ADywgBgHr9Jkhwn5Gsdu7BwX + nIQfYTYcdL9I5Sk= + + +Decrypt +======= + +Assume the above output has been saved into ``encrypt.p7``. Decrypt the +message thusly:: + + from M2Crypto import BIO, SMIME, X509 + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load private key and cert. + s.load_key('recipient_key.pem', 'recipient.pem') + + # Load the encrypted data. + p7, data = SMIME.smime_load_pkcs7('encrypt.p7') + + # Decrypt p7. + out = s.decrypt(p7) + + print(out) + +Here's the output:: + + a sign of our times + + +Sign and Encrypt +================ + +Here's how to generate an S/MIME-signed/encrypted message:: + + from M2Crypto import BIO, Rand, SMIME, X509 + + def makebuf(text): + return BIO.MemoryBuffer(text) + + # Make a MemoryBuffer of the message. + buf = makebuf('a sign of our times') + + # Seed the PRNG. + Rand.load_file('randpool.dat', -1) + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load signer's key and cert. Sign the buffer. + s.load_key('signer_key.pem', 'signer.pem') + p7 = s.sign(buf) + + # Load target cert to encrypt the signed message to. + x509 = X509.load_cert('recipient.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + # Set cipher: 3-key triple-DES in CBC mode. + s.set_cipher(SMIME.Cipher('des_ede3_cbc')) + + # Create a temporary buffer. + tmp = BIO.MemoryBuffer() + + # Write the signed message into the temporary buffer. + s.write(tmp, p7) + + # Encrypt the temporary buffer. + p7 = s.encrypt(tmp) + + # Output p7 in mail-friendly format. + out = BIO.MemoryBuffer() + out.write('From: sender@example.dom\n') + out.write('To: recipient@example.dom\n') + out.write('Subject: M2Crypto S/MIME testing\n') + s.write(out, p7) + + print(out.read()) + + # Save the PRNG's state. + Rand.save_file('randpool.dat') + +Here's the output of the above program:: + + From: sender@example.dom + To: recipient@example.dom + Subject: M2Crypto S/MIME testing + MIME-Version: 1.0 + Content-Disposition: attachment; filename="smime.p7m" + Content-Type: application/x-pkcs7-mime; name="smime.p7m" + Content-Transfer-Encoding: base64 + + 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 + + +Decrypt and Verify +================== + +Suppose the above output has been saved into ``se.p7``. The following +demonstrates how to decrypt and verify it:: + + from M2Crypto import BIO, SMIME, X509 + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load private key and cert. + s.load_key('recipient_key.pem', 'recipient.pem') + + # Load the signed/encrypted data. + p7, data = SMIME.smime_load_pkcs7('se.p7') + + # After the above step, 'data' == None. + # Decrypt p7. 'out' now contains a PKCS #7 signed blob. + out = s.decrypt(p7) + + # Load the signer's cert. + x509 = X509.load_cert('signer.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + # Load the signer's CA cert. In this case, because the signer's + # cert is self-signed, it is the signer's cert itself. + st = X509.X509_Store() + st.load_info('signer.pem') + s.set_x509_store(st) + + # Recall 'out' contains a PKCS #7 blob. + # Transform 'out'; verify the resulting PKCS #7 blob. + p7_bio = BIO.MemoryBuffer(out) + p7, data = SMIME.smime_load_pkcs7_bio(p7_bio) + v = s.verify(p7) + + print(v) + + +The output is as follows:: + + a sign of our times + + +Sending S/MIME messages via SMTP +================================ + +In the above examples, we've assumed that our S/MIME messages are sent +and received automagically. The following is a Python function that +generates S/MIME-signed/encrypted messages and sends them via +SMTP:: + + from M2Crypto import BIO, SMIME, X509 + import smtplib, string, sys + + def sendsmime(from_addr, to_addrs, subject, msg, from_key, from_cert=None, to_certs=None, smtpd='localhost'): + + msg_bio = BIO.MemoryBuffer(msg) + sign = from_key + encrypt = to_certs + + s = SMIME.SMIME() + if sign: + s.load_key(from_key, from_cert) + if encrypt: + p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT) + else: + p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT|SMIME.PKCS7_DETACHED) + msg_bio = BIO.MemoryBuffer(msg) # Recreate coz sign() has consumed it. + + if encrypt: + sk = X509.X509_Stack() + for x in to_certs: + sk.push(X509.load_cert(x)) + s.set_x509_stack(sk) + s.set_cipher(SMIME.Cipher('des_ede3_cbc')) + tmp_bio = BIO.MemoryBuffer() + if sign: + s.write(tmp_bio, p7) + else: + tmp_bio.write(msg) + p7 = s.encrypt(tmp_bio) + + out = BIO.MemoryBuffer() + out.write('From: %s\r\n' % from_addr) + out.write('To: %s\r\n' % string.join(to_addrs, ", ")) + out.write('Subject: %s\r\n' % subject) + if encrypt: + s.write(out, p7) + else: + if sign: + s.write(out, p7, msg_bio, SMIME.PKCS7_TEXT) + else: + out.write('\r\n') + out.write(msg) + out.close() + + smtp = smtplib.SMTP() + smtp.connect(smtpd) + smtp.sendmail(from_addr, to_addrs, out.read()) + smtp.quit() + + +This function sends plain, S/MIME-signed, S/MIME-encrypted, and +S/MIME-signed/encrypted messages, depending on the parameters +``from_key`` and ``to_certs``. The function's output interoperates with +Netscape Messenger. + +Verifying origin of S/MIME messages +=================================== + +In our examples above that decrypt or verify messages, we skipped a +step: verifying that the ``from`` address of the message matches the +``email address`` attribute in the sender's certificate. + +The premise of current X.509 certification practice is that the CA is +supposed to verify your identity, and to issue a certificate with +``email address`` that matches your actual mail address. (Verisign's +March 2001 failure in identity verification resulting in Microsoft +certificates being issued to spoofers notwithstanding.) + +If you run your own CA, your certification practice is up to you, of +course, and it would probably be part of your security policy. + +Whether your S/MIME messaging application needs to verify the ``from`` +addresses of S/MIME messages depends on your security policy and your +system's threat model, as always. + +Interoperating with Netscape Messenger +====================================== + +Suppose S/MIME Recipient uses Netscape Messenger. To enable Messenger to +handle S/MIME messages from S/MIME Sender, S/MIME Recipient needs to +configure Messenger with his private key and certificate, as well as +S/MIME Sender's certificate. + + **Note:** Configuring Messenger's POP or IMAP settings so that it + retrieves mail correctly is beyond the scope of this HOWTO. + +The following steps demonstrate how to import S/MIME Recipient's private +key and certificate for Messenger: + +1. Transform S/MIME Recipient's private key and certificate into *PKCS + #12* format:: + + openssl pkcs12 -export -in recipient.pem -inkey recipient_key.pem \ + -name "S/MIME Recipient" -out recipient.p12 + + Enter Export Password: + Verifying password - Enter Export Password: + +2. Start Messenger. + +3. Click on the (open) "lock" icon at the bottom left corner of + Messenger's window. This brings up the "Security Info" dialog box. + +4. Click on "Yours" under "Certificates". + +5. Select "Import a certificate", then pick ``recipient.p12`` from the + ensuing file selection dialog box. + +Next, you need to import ``signer.pem`` as a CA certificate, so that +Messenger will mark messages signed by S/MIME Sender as "trusted": + +1. Create a DER encoding of ``signer.pem``:: + + openssl x509 -inform pem -outform der -in signer.pem -out signer.der + +2. Install ``signer.der`` into Messenger as MIME type + ``application/x-x509-ca-cert``. You do this by downloading + ``signer.der`` via Navigator from a HTTP or HTTPS server, with the + correct MIME type mapping. (You may use ``demo/ssl/https_srv.py``, + bundled with M2Crypto, for this purpose.) Follow the series of dialog + boxes to accept ``signer.der`` as a CA for certifying email users. + +S/MIME Recipient is now able to decrypt and read S/MIME Sender's +messages with Messenger. Messenger will indicate that S/MIME Sender's +messages are signed, encrypted, or encrypted *and* signed, as the case +may be, via the "stamp" icon on the message window's top right corner. + +Clicking on the "stamp" icon brings you to the Security Info dialog box. +Messenger informs you that the message is, say, encrypted with 168-bit +DES-EDE3-CBC and that it is digitally signed by the private key +corresponding to the public key contained in the certificate +``signer.pem``. + +Interoperating with Microsoft Outlook +===================================== + +I do not know how to do this, as I do not use Outlook. (Nor do I use +Netscape Messenger, actually. I use Mutt, top dog of MUAs. ;-) +Information on how to configure Outlook with keys and certificates so +that it handles S/MIME mail is gratefully accepted. + +ZSmime +====== + +ZSmime is a `Zope `__ *product* that enables Zope +to generate S/MIME-signed/encrypted messages. ZSmime demonstrates how to +invoke M2Crypto in a web application server extension. + +ZSmime has its own +`HOWTO `__ +explaining its usage. (That HOWTO has some overlap in content with this +document.) + +Resources +========= + +- IETF S/MIME Working Group - http://www.imc.org/ietf-smime + +- S/MIME and OpenPGP - http://www.imc.org/smime-pgpmime.html + +- S/MIME Freeware Library - + http://www.getronicsgov.com/hot/sfl_home.htm + +- Mozilla Network Security Services - + http://www.mozilla.org/projects/security/pkg/nss + +- S/MIME Cracking Screen Saver - http://www.counterpane.com/smime.html diff --git a/doc/howto.ssl.html b/doc/howto.ssl.html deleted file mode 100644 index 340f264..0000000 --- a/doc/howto.ssl.html +++ /dev/null @@ -1,206 +0,0 @@ -HOWTO: Programming SSL in Python with M2Crypto - - - - -

    HOWTO: Programming SSL in Python with M2Crypto

    -

    -Ng Pheng Siong (ngps@netmemetic.com) and Heikki Toivonen (heikki@osafoundation.org) -

    Copyright © 2001, 2002 by Ng Pheng Siong.

    -

    Portions Copyright © 2006 by Open Source Applications Foundation.

    -
    - -

    Introduction

    M2Crypto - is a Python - interface to OpenSSL. It makes - available to the Python programmer SSL functionality to implement clients - and servers, S/MIME v2, RSA, DSA, DH, symmetric ciphers, message digests and - HMACs. -

    This document demonstrates programming HTTPS with M2Crypto. -

    - - -

    A bit of history

    - -

    M2Crypto was created during the time of Python 1.5, which features - a module httplib providing client-side HTTP functionality. M2Crypto sports - a httpslib based on httplib. -

    - -

    - Beginning with version 2.0, Python's socket module provided - (rudimentary) SSL support. Also in the same version, httplib was - enhanced with class HTTPConnection, which is more sophisticated than - the old class HTTP, and HTTPSConnection, which does HTTPS. -

    - -

    - Subsequently, M2Crypto.httpslib grew a compatible (but not identical) - class HTTPSConnection. -

    - -

    - The primary interface difference between the two HTTPSConnection - classes is that M2Crypto's version accepts an M2Crypto.SSL.Context - instance as a parameter, whereas Python 2.x's SSL support does not - permit Pythonic control of the SSL context. -

    - -

    Within the implementations, Python's - HTTPSConnection employs a - FakeSocket object, which collects all input from - the SSL connection before returning it to the application as a - StringIO buffer, whereas M2Crypto's - HTTPSConnection uses a buffering - M2Crypto.BIO.IOBuffer object that works over the - underlying M2Crypto.SSL.Connection directly.

    - -

    Since then M2Crypto has gained a Twisted wrapper that allows securing - Twisted SSL connections with M2Crypto.

    -
    - - -
    -

    Secure SSL

    - -

    It is recommended that you read the book Network Security with OpenSSL by John Viega, Matt Messier and Pravir Chandra, -ISBN 059600270X.

    - -

    Using M2Crypto does not automatically make an SSL connection secure. There are various steps that need to be made -before we can make that claim. Let's see how a simple client can establish a secure connection:

    - -
    -ctx = SSL.Context()
    -ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9)
    -if ctx.load_verify_locations('ca.pem') != 1: raise Exception('No CA certs')
    -s = SSL.Connection(ctx)
    -s.connect(server_address)
    -# Normal protocol (for example HTTP) commands follow
    -
    - -

    The first line creates an SSL context. The defaults allow any SSL version (except SSL version 2 which has known -weaknesses) and sets the allowed ciphers to secure ones.

    - -

    The second line tells M2Crypto to perform certificate validation. The flags shown above are typical for clients, -and requires the server to send a certificate. The depth parameter tells how long certificate chains are allowed - -9 is pretty common default, although probably too long in practice.

    - -

    The third line loads the allowed root (certificate authority or CA) certificates. -Most Linux distributions come with CA certificates in suitable format. You -could also download the certdata.txt -file from the NSS -project and convert it -with the little M2Crypto utility script demo/x509/certdata2pem.py.

    - -

    The fourth line creates an SSL connection object with the secure context.

    - -

    The fifth line connects to the server. During this time we perform the last security step: just after connection, but before -exchanging any data, we compare the commonName (or subjectAltName DNS field) field in the certificate the server returned to the -server address we tried to connect to. This happens automatically with SSL.Connection and the Twisted wrapper class, and anything -that uses those. In all other cases you must do the check manually. It is recommended you call the SSL.Checker to do the actual check.

    - -

    SSL servers are different in that they typically do not require the client to send a certificate, so there is usually no certificate -checking. Also, it is typically useless to perform host name checking.

    - -
    - -
    -

    Code Samples

    - -

    The best samples of how to use the various SSL objects are in the tests directory, and the test_ssl.py file specifically. -There are additional samples in the demo directory, but they are not quaranteed to be up to date.

    - -

    NOTE: The tests and demos -may not be secure as is. Use the information above on how to make them secure.

    -
    - -

    ssldump

    -

    ssldump "is an SSLv3/TLS network protocol analyser. It identifies - TCP connections on the chosen network interface and attempts to interpret - them as SSLv3/TLS traffic. When it identifies SSLv3/TLS traffic, it - decodes the records and displays them in a textual form to stdout. If - provided with the appropriate keying material, it will also decrypt the - connections and display the application data traffic. -

    - -

    - If linked with OpenSSL, ssldump can display certificates in decoded form - and decrypt traffic (provided that it has the appropriate keying - material)." -

    - -

    ssldump is written by Eric Rescorla. -

    -
    - - - diff --git a/doc/howto.ssl.rst b/doc/howto.ssl.rst new file mode 100644 index 0000000..7f3278c --- /dev/null +++ b/doc/howto.ssl.rst @@ -0,0 +1,131 @@ +:orphan: + +.. _howto-ssl: + +HOWTO: Programming SSL in Python with M2Crypto +============================================== + +:author: Pheng Siong Ng and Heikki Toivonen (heikki@osafoundation.org) +:copyright: © 2000, 2001 by Ng Pheng Siong, + portions © 2006 by Open Source Applications Foundation + +Introduction +============ + +`M2Crypto `__ is a +`Python `__ interface to +`OpenSSL `__. It makes available to the Python +programmer SSL functionality to implement clients and servers, S/MIME +v2, RSA, DSA, DH, symmetric ciphers, message digests and HMACs. + +This document demonstrates programming HTTPS with M2Crypto. + +A bit of history +================ + +M2Crypto was created during the time of Python 1.5, which features a +module httplib providing client-side HTTP functionality. M2Crypto sports +a httpslib based on httplib. + +Beginning with version 2.0, Python's socket module provided +(rudimentary) SSL support. Also in the same version, httplib was +enhanced with class HTTPConnection, which is more sophisticated than the +old class HTTP, and HTTPSConnection, which does HTTPS. + +Subsequently, M2Crypto.httpslib grew a compatible (but not identical) +class HTTPSConnection. + +The primary interface difference between the two HTTPSConnection classes +is that M2Crypto's version accepts an M2Crypto.SSL.Context instance as a +parameter, whereas Python 2.x's SSL support does not permit Pythonic +control of the SSL context. + +Within the implementations, Python's ``HTTPSConnection`` employs a +``FakeSocket`` object, which collects all input from the SSL connection +before returning it to the application as a ``StringIO`` buffer, whereas +M2Crypto's ``HTTPSConnection`` uses a buffering +``M2Crypto.BIO.IOBuffer`` object that works over the underlying +M2Crypto.SSL.Connection directly. + +Since then M2Crypto has gained a Twisted wrapper that allows securing +Twisted SSL connections with M2Crypto. + +Secure SSL +========== + +It is recommended that you read the book Network Security with OpenSSL +by John Viega, Matt Messier and Pravir Chandra, ISBN 059600270X. + +Using M2Crypto does not automatically make an SSL connection secure. +There are various steps that need to be made before we can make that +claim. Let's see how a simple client can establish a secure +connection:: + + ctx = SSL.Context() + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9) + if ctx.load_verify_locations('ca.pem') != 1: raise Exception('No CA certs') + s = SSL.Connection(ctx) + s.connect(server_address) + # Normal protocol (for example HTTP) commands follow + +The first line creates an SSL context. The defaults allow any SSL +version (except SSL version 2 which has known weaknesses) and sets the +allowed ciphers to secure ones. + +The second line tells M2Crypto to perform certificate validation. The +flags shown above are typical for clients, and requires the server to +send a certificate. The depth parameter tells how long certificate +chains are allowed - 9 is pretty common default, although probably too +long in practice. + +The third line loads the allowed root (certificate authority or CA) +certificates. Most Linux distributions come with CA certificates in +suitable format. You could also download the +`certdata.txt `__ +file from the +`NSS `__ project and +convert it with the little M2Crypto utility script +`demo/x509/certdata2pem.py `__. + +The fourth line creates an SSL connection object with the secure +context. + +The fifth line connects to the server. During this time we perform the +last security step: just after connection, but before exchanging any +data, we compare the commonName (or subjectAltName DNS field) field in +the certificate the server returned to the server address we tried to +connect to. This happens automatically with SSL.Connection and the +Twisted wrapper class, and anything that uses those. In all other cases +you must do the check manually. It is recommended you call the +SSL.Checker to do the actual check. + +SSL servers are different in that they typically do not require the +client to send a certificate, so there is usually no certificate +checking. Also, it is typically useless to perform host name checking. + +Code Samples +============ + +The best samples of how to use the various SSL objects are in the tests +directory, and the test\_ssl.py file specifically. There are additional +samples in the demo directory, but they are not quaranteed to be up to +date. + +NOTE: The tests and demos may not be secure as is. Use the information +above on how to make them secure. + +ssldump +======= + +ssldump "is an SSLv3/TLS network protocol analyser. It identifies TCP +connections on the chosen network interface and attempts to interpret +them as SSLv3/TLS traffic. When it identifies SSLv3/TLS traffic, it +decodes the records and displays them in a textual form to stdout. If +provided with the appropriate keying material, it will also decrypt the +connections and display the application data traffic. + +If linked with OpenSSL, ssldump can display certificates in decoded form +and decrypt traffic (provided that it has the appropriate keying +material)." + +ssldump is written by Eric Rescorla. diff --git a/doc/html/.buildinfo b/doc/html/.buildinfo new file mode 100644 index 0000000..50b077b --- /dev/null +++ b/doc/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: f47da9e27c47bb67c681b112c1dbec32 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/doc/html/M2Crypto.SSL.html b/doc/html/M2Crypto.SSL.html new file mode 100644 index 0000000..4a81972 --- /dev/null +++ b/doc/html/M2Crypto.SSL.html @@ -0,0 +1,1706 @@ + + + + + + + + SSL Package — M2Crypto documentation + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    SSL Package¶

    +
    +

    SSL Package¶

    +
    +
    +exception M2Crypto.SSL.SSLError[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +exception M2Crypto.SSL.SSLTimeoutError[source]¶
    +

    Bases: M2Crypto.SSL.SSLError, socket.timeout

    +
    + +
    +
    +

    Checker Module¶

    +

    SSL peer certificate checking routines

    +

    Copyright (c) 2004-2007 Open Source Applications Foundation. +All rights reserved.

    +

    Copyright 2008 Heikki Toivonen. All rights reserved.

    +
    +
    +exception M2Crypto.SSL.Checker.SSLVerificationError[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +exception M2Crypto.SSL.Checker.NoCertificate[source]¶
    +

    Bases: M2Crypto.SSL.Checker.SSLVerificationError

    +
    + +
    +
    +exception M2Crypto.SSL.Checker.WrongCertificate[source]¶
    +

    Bases: M2Crypto.SSL.Checker.SSLVerificationError

    +
    + +
    +
    +exception M2Crypto.SSL.Checker.WrongHost(expectedHost, actualHost, fieldName='commonName')[source]¶
    +

    Bases: M2Crypto.SSL.Checker.SSLVerificationError

    +
    + +
    +
    +class M2Crypto.SSL.Checker.Checker(host=None, peerCertHash=None, peerCertDigest='sha1')[source]¶
    +

    Bases: object

    +
    +
    +numericIpMatch = re.compile('^[0-9]+(\\.[0-9]+)*$')¶
    +
    + +
    + +
    +
    +

    Cipher Module¶

    +

    SSL Ciphers

    +

    Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.

    +
    +
    +class M2Crypto.SSL.Cipher.Cipher(cipher)[source]¶
    +

    Bases: object

    +
    +
    +name()[source]¶
    +
    + +
    +
    +version()[source]¶
    +
    + +
    + +
    +
    +class M2Crypto.SSL.Cipher.Cipher_Stack(stack)[source]¶
    +

    Bases: object

    +
    + +
    +
    +

    Connection Module¶

    +
    +
    +class M2Crypto.SSL.Connection.Connection(ctx, sock=None, family=<AddressFamily.AF_INET: 2>)[source]¶
    +

    Bases: object

    +

    An SSL connection.

    +
    +
    +accept()[source]¶
    +

    Accept an SSL connection.

    +

    The return value is a pair (ssl, addr) where ssl is a new SSL +connection object and addr is the address bound to the other end +of the SSL connection.

    + +++ + + + +
    Returns:tuple of Connection and addr. Address can take very +various forms (see socket documentation), for IPv4 it +is tuple(str, int), for IPv6 a tuple of four (host, +port, flowinfo, scopeid), where the last two are +optional ints.
    +
    + +
    +
    +accept_ssl()[source]¶
    +

    Waits for a TLS/SSL client to initiate the TLS/SSL handshake.

    +

    The communication channel must already have been set and +assigned to the ssl by setting an underlying BIO.

    + +++ + + + +
    Returns:
    +
    0 The TLS/SSL handshake was not successful but was shut
    +
    down controlled and by the specifications of the +TLS/SSL protocol. Call get_error() with the return +value ret to find out the reason.
    +
    1 The TLS/SSL handshake was successfully completed,
    +
    a TLS/SSL connection has been established.
    +
    <0 The TLS/SSL handshake was not successful because
    +
    a fatal error occurred either at the protocol level +or a connection failure occurred. The shutdown was +not clean. It can also occur of action is need to +continue the operation for non-blocking BIOs. Call +get_error() with the return value ret to find +out the reason.
    +
    +
    +
    + +
    +
    +bind(addr)[source]¶
    +
    + +
    +
    +clear()[source]¶
    +

    If there were errors in this connection, call clear() rather +than close() to end it, so that bad sessions will be cleared +from cache.

    +
    + +
    +
    +clientPostConnectionCheck = <M2Crypto.SSL.Checker.Checker object>¶
    +
    + +
    +
    +close()[source]¶
    +
    + +
    +
    +connect(addr)[source]¶
    +

    Overloading socket.connect()

    + +++ + + + +
    Parameters:addr – addresses have various depending on their type
    +

    :return:status of ssl_connect()

    +
    + +
    +
    +connect_ssl()[source]¶
    +
    + +
    +
    +fileno()[source]¶
    +
    + +
    +
    +get_cipher()[source]¶
    +

    Return an M2Crypto.SSL.Cipher object for this connection; if the +connection has not been initialised with a cipher suite, return None.

    +
    + +
    +
    +get_cipher_list(idx=0)[source]¶
    +

    Return the cipher suites for this connection as a string object.

    +
    + +
    +
    +get_ciphers()[source]¶
    +

    Return an M2Crypto.SSL.Cipher_Stack object for this +connection; if the connection has not been initialised with +cipher suites, return None.

    +
    + +
    +
    +get_context()[source]¶
    +

    Return the Context object associated with this connection.

    +
    + +
    +
    +get_default_session_timeout()[source]¶
    +
    + +
    +
    +get_peer_cert()[source]¶
    +

    Return the peer certificate.

    +

    If the peer did not provide a certificate, return None.

    +
    + +
    +
    +get_peer_cert_chain()[source]¶
    +

    Return the peer certificate chain; if the peer did not provide +a certificate chain, return None.

    + +++ + + + +
    Warning:The returned chain will be valid only for as long as the +connection object is alive. Once the connection object +gets freed, the chain will be freed as well.
    +
    + +
    +
    +get_session()[source]¶
    +
    + +
    +
    +get_shutdown()[source]¶
    +

    Get the current shutdown mode of the Connection.

    +
    + +
    +
    +get_socket_read_timeout()[source]¶
    +
    + +
    +
    +get_socket_write_timeout()[source]¶
    +
    + +
    +
    +get_state()[source]¶
    +

    Return the SSL state of this connection.

    +

    During its use, an SSL objects passes several states. The state +is internally maintained. Querying the state information is not +very informative before or when a connection has been +established. It however can be of significant interest during +the handshake.

    + +++ + + + +
    Returns:6 letter string indicating the current state of the SSL +object ssl.
    +
    + +
    +
    +get_verify_depth()[source]¶
    +

    Return the peer certificate verification depth.

    +
    + +
    +
    +get_verify_mode()[source]¶
    +

    Return the peer certificate verification mode.

    +
    + +
    +
    +get_verify_result()[source]¶
    +

    Return the peer certificate verification result.

    +
    + +
    +
    +get_version()[source]¶
    +

    Return the TLS/SSL protocol version for this connection.

    +
    + +
    +
    +getpeername()[source]¶
    +

    Return the remote address to which the socket is connected.

    +

    This is useful to find out the port number of a remote IPv4/v6 socket, +for instance. +On some systems this function is not supported.

    + +++ + + + +
    Returns:
    +
    + +
    +
    +getsockname()[source]¶
    +

    Return the socket’s own address.

    +

    This is useful to find out the port number of an IPv4/v6 socket, +for instance. (The format of the address returned depends +on the address family – see above.)

    +

    :return:socket’s address as addr type

    +
    + +
    +
    +getsockopt(level, optname, buflen=None)[source]¶
    +

    Get the value of the given socket option.

    + +++ + + + + + +
    Parameters:
      +
    • level – level at which the option resides. +To manipulate options at the sockets API level, level is +specified as socket.SOL_SOCKET. To manipulate options at +any other level the protocol number of the appropriate +protocol controlling the option is supplied. For example, +to indicate that an option is to be interpreted by the +TCP protocol, level should be set to the protocol number +of socket.SOL_TCP; see getprotoent(3).
    • +
    • optname – The value of the given socket option is +described in the Unix man page getsockopt(2)). The needed +symbolic constants (SO_* etc.) are defined in the socket +module.
    • +
    • buflen – If it is absent, an integer option is assumed +and its integer value is returned by the function. If +buflen is present, it specifies the maximum length of the +buffer used to receive the option in, and this buffer is +returned as a bytes object.
    • +
    +
    Returns:

    Either integer or bytes value of the option. It is up +to the caller to decode the contents of the buffer (see +the optional built-in module struct for a way to decode +C structures encoded as byte strings).

    +
    +
    + +
    +
    +listen(qlen=5)[source]¶
    +
    + +
    +
    +m2_bio_free()¶
    +
    + +
    +
    +m2_bio_noclose = 0¶
    +
    + +
    +
    +m2_ssl_free()¶
    +
    + +
    +
    +makefile(mode='rb', bufsize=-1)[source]¶
    +
    + +
    +
    +pending()[source]¶
    +

    Return the numbers of octets that can be read from the connection.

    +
    + +
    +
    +read(size=1024)[source]¶
    +
    + +
    +
    +recv(size=1024)¶
    +
    + +
    +
    +recv_into(buff, nbytes=0)[source]¶
    +

    A version of recv() that stores its data into a buffer rather +than creating a new string. Receive up to buffersize bytes from +the socket. If buffersize is not specified (or 0), receive up +to the size available in the given buffer.

    +

    If buff is bytearray, it will have after return length of the +actually returned number of bytes. If buff is memoryview, then +the size of buff won’t change (it cannot), but all bytes after +the number of returned bytes will be NULL.

    + +++ + + + + + +
    Parameters:
      +
    • buffer – a buffer for the received bytes
    • +
    • nbytes – maximum number of bytes to read
    • +
    +
    Returns:

    number of bytes read

    +
    +

    See recv() for documentation about the flags.

    +
    + +
    +
    +renegotiate()[source]¶
    +

    Renegotiate this connection’s SSL parameters.

    +
    + +
    +
    +send(data)¶
    +
    + +
    +
    +sendall(data)¶
    +
    + +
    +
    +serverPostConnectionCheck(**kw)¶
    +
    + +
    +
    +set1_host(name)[source]¶
    +

    Set the requested hostname to check in the server certificate.

    +
    + +
    +
    +set_accept_state()[source]¶
    +

    Sets Connection to work in the server mode.

    +
    + +
    +
    +set_bio(readbio, writebio)[source]¶
    +

    Explicitly set read and write bios

    +

    Connects the BIOs for the read and write operations of the +TLS/SSL (encrypted) side of ssl.

    +

    The SSL engine inherits the behaviour of both BIO objects, +respectively. If a BIO is non-blocking, the Connection will also +have non-blocking behaviour.

    +

    If there was already a BIO connected to Connection, BIO_free() +will be called (for both the reading and writing side, if +different).

    + +++ + + + +
    Parameters:
      +
    • readbio – BIO for reading
    • +
    • writebio – BIO for writing.
    • +
    +
    +
    + +
    +
    +set_cipher_list(cipher_list)[source]¶
    +

    Set the cipher suites for this connection.

    +
    + +
    +
    +set_client_CA_list_from_context()[source]¶
    +

    Set the acceptable client CA list. If the client +returns a certificate, it must have been issued by +one of the CAs listed in context.

    +

    Makes sense only for servers.

    +
    + +
    +
    +set_client_CA_list_from_file(cafile)[source]¶
    +

    Set the acceptable client CA list.

    +

    If the client returns a certificate, it must have been issued by +one of the CAs listed in cafile.

    +

    Makes sense only for servers.

    + +++ + + + + + +
    Parameters:cafile – Filename from which to load the CA list.
    Returns:
    +
    0 A failure while manipulating the STACK_OF(X509_NAME)
    +
    object occurred or the X509_NAME could not be +extracted from cacert. Check the error stack to find +out the reason.
    +
    +

    1 The operation succeeded.

    +
    +
    + +
    +
    +set_connect_state()[source]¶
    +

    Sets Connection to work in the client mode.

    +
    + +
    +
    +set_post_connection_check_callback(postConnectionCheck)[source]¶
    +
    + +
    +
    +set_session(session)[source]¶
    +
    + +
    +
    +set_session_id_ctx(id)[source]¶
    +
    + +
    +
    +set_shutdown(mode)[source]¶
    +

    Sets the shutdown state of the Connection to mode.

    +

    The shutdown state of an ssl connection is a bitmask of (use +m2.SSL_* constants):

    +

    0 No shutdown setting, yet.

    +
    +
    SSL_SENT_SHUTDOWN
    +
    A “close notify” shutdown alert was sent to the peer, the +connection is being considered closed and the session is +closed and correct.
    +
    SSL_RECEIVED_SHUTDOWN
    +
    A shutdown alert was received form the peer, either a normal +“close notify” or a fatal error.
    +
    +

    SSL_SENT_SHUTDOWN and SSL_RECEIVED_SHUTDOWN can be set at the +same time.

    + +++ + + + +
    Parameters:mode – set the mode bitmask.
    +
    + +
    +
    +set_socket_read_timeout(timeo)[source]¶
    +
    + +
    +
    +set_socket_write_timeout(timeo)[source]¶
    +
    + +
    +
    +set_ssl_close_flag(flag)[source]¶
    +

    By default, SSL struct will be freed in __del__. Call with +m2.bio_close to override this default.

    + +++ + + + +
    Parameters:flag – either m2.bio_close or m2.bio_noclose
    +
    + +
    +
    +set_tlsext_host_name(name)[source]¶
    +

    Set the requested hostname for the SNI (Server Name Indication) +extension.

    +
    + +
    +
    +setblocking(mode)[source]¶
    +

    Set this connection’s underlying socket to _mode_.

    +

    Set blocking or non-blocking mode of the socket: if flag is 0, +the socket is set to non-blocking, else to blocking mode. +Initially all sockets are in blocking mode. In non-blocking mode, +if a recv() call doesn’t find any data, or if a send() call can’t +immediately dispose of the data, a error exception is raised; +in blocking mode, the calls block until they can proceed. +s.setblocking(0) is equivalent to s.settimeout(0.0); +s.setblocking(1) is equivalent to s.settimeout(None).

    + +++ + + + +
    Parameters:mode – new mode to be set
    +
    + +
    +
    +setsockopt(level, optname, value=None)[source]¶
    +

    Set the value of the given socket option.

    + +++ + + + + + +
    Parameters:
      +
    • level – same as with getsockopt() above
    • +
    • optname – same as with getsockopt() above
    • +
    • value – an integer or a string representing a buffer. In +the latter case it is up to the caller to ensure +that the string contains the proper bits (see the +optional built-in module struct for a way to +encode C structures as strings).
    • +
    +
    Returns:

    None for success or the error handler for failure.

    +
    +
    + +
    +
    +settimeout(timeout)[source]¶
    +

    Set this connection’s underlying socket’s timeout to _timeout_.

    +
    + +
    +
    +setup_addr(addr)[source]¶
    +
    + +
    +
    +setup_ssl()[source]¶
    +
    + +
    +
    +shutdown(how)[source]¶
    +
    + +
    +
    +ssl_get_error(ret)[source]¶
    +
    + +
    +
    +verify_ok()[source]¶
    +
    + +
    +
    +write(data)[source]¶
    +
    + +
    + +
    +
    +

    Context Module¶

    +
    +
    +M2Crypto.SSL.Context.ctxmap()[source]¶
    +
    + +
    +
    +class M2Crypto.SSL.Context.Context(protocol='tls', weak_crypto=None, post_connection_check=None)[source]¶
    +

    Bases: object

    +

    ‘Context’ for SSL connections.

    +
    +
    +add_session(session)[source]¶
    +

    Add the session to the context.

    + +++ + + + + + +
    Parameters:session – the session to be added.
    Returns:
    +
    0 The operation failed. It was tried to add the same
    +
    (identical) session twice.
    +
    +

    1 The operation succeeded.

    +
    +
    + +
    +
    +close()[source]¶
    +
    + +
    +
    +get_allow_unknown_ca()[source]¶
    +

    Get the context’s setting that accepts/rejects a peer +certificate if the certificate’s CA is unknown.

    +

    FIXME 2Bconverted to bool

    +
    + +
    +
    +get_cert_store()[source]¶
    +

    Get the certificate store associated with this context.

    + +++ + + + +
    Warning:The store is NOT refcounted, and as such can not be relied +to be valid once the context goes away or is changed.
    +
    + +
    +
    +get_session_cache_mode()[source]¶
    +

    Gets the current session caching.

    +

    The mode is set to m2.SSL_SESS_CACHE_* constants.

    + +++ + + + +
    Returns:the previously set cache mode value.
    +
    + +
    +
    +get_session_timeout()[source]¶
    +

    Get current session timeout.

    +

    Whenever a new session is created, it is assigned a maximum +lifetime. This lifetime is specified by storing the creation +time of the session and the timeout value valid at this time. If +the actual time is later than creation time plus timeout, the +session is not reused.

    +

    Due to this realization, all sessions behave according to the +timeout value valid at the time of the session negotiation. +Changes of the timeout value do not affect already established +sessions.

    +

    Expired sessions are removed from the internal session cache, +whenever SSL_CTX_flush_sessions(3) is called, either directly by +the application or automatically (see +SSL_CTX_set_session_cache_mode(3))

    +

    The default value for session timeout is decided on a per +protocol basis, see SSL_get_default_timeout(3). All currently +supported protocols have the same default timeout value of 300 +seconds.

    +

    SSL_CTX_set_timeout() returns the previously set timeout value.

    + +++ + + + +
    Returns:the currently set timeout value.
    +
    + +
    +
    +get_verify_depth()[source]¶
    +

    Returns the verification mode currently set in the SSL Context.

    +
    + +
    +
    +get_verify_mode()[source]¶
    +
    + +
    +
    +load_cert(certfile, keyfile=None, callback=<function passphrase_callback>)[source]¶
    +

    Load certificate and private key into the context.

    + +++ + + + +
    Parameters:
      +
    • certfile – File that contains the PEM-encoded certificate.
    • +
    • keyfile – File that contains the PEM-encoded private key. +Default value of None indicates that the private key +is to be found in ‘certfile’.
    • +
    • callback – Callable object to be invoked if the private key is +passphrase-protected. Default callback provides a +simple terminal-style input for the passphrase.
    • +
    +
    +
    + +
    +
    +load_cert_chain(certchainfile, keyfile=None, callback=<function passphrase_callback>)[source]¶
    +

    Load certificate chain and private key into the context.

    + +++ + + + +
    Parameters:
      +
    • certchainfile – File object containing the PEM-encoded +certificate chain.
    • +
    • keyfile – File object containing the PEM-encoded private +key. Default value of None indicates that the +private key is to be found in ‘certchainfile’.
    • +
    • callback – Callable object to be invoked if the private key +is passphrase-protected. Default callback +provides a simple terminal-style input for the +passphrase.
    • +
    +
    +
    + +
    +
    +load_client_CA(cafile)¶
    +

    Load CA certs into the context. These CA certs are sent to the +peer during SSLv3 certificate request.

    + +++ + + + +
    Parameters:cafile – File object containing one or more PEM-encoded CA +certificates concatenated together.
    +
    + +
    +
    +load_client_ca(cafile)¶
    +

    Load CA certs into the context. These CA certs are sent to the +peer during SSLv3 certificate request.

    + +++ + + + +
    Parameters:cafile – File object containing one or more PEM-encoded CA +certificates concatenated together.
    +
    + +
    +
    +load_verify_info(cafile=None, capath=None)¶
    +

    Load CA certs into the context.

    +

    These CA certs are used during verification of the peer’s +certificate.

    + +++ + + + + + +
    Parameters:
      +
    • cafile – File containing one or more PEM-encoded CA +certificates concatenated together.
    • +
    • capath – Directory containing PEM-encoded CA certificates +(one certificate per file).
    • +
    +
    Returns:

    +
    0 if the operation failed because CAfile and CApath are NULL
    +

    or the processing at one of the locations specified failed. +Check the error stack to find out the reason.

    +
    +
    +

    1 The operation succeeded.

    +

    +
    +
    + +
    +
    +load_verify_locations(cafile=None, capath=None)[source]¶
    +

    Load CA certs into the context.

    +

    These CA certs are used during verification of the peer’s +certificate.

    + +++ + + + + + +
    Parameters:
      +
    • cafile – File containing one or more PEM-encoded CA +certificates concatenated together.
    • +
    • capath – Directory containing PEM-encoded CA certificates +(one certificate per file).
    • +
    +
    Returns:

    +
    0 if the operation failed because CAfile and CApath are NULL
    +

    or the processing at one of the locations specified failed. +Check the error stack to find out the reason.

    +
    +
    +

    1 The operation succeeded.

    +

    +
    +
    + +
    +
    +m2_ssl_ctx_free()¶
    +
    + +
    +
    +remove_session(session)[source]¶
    +

    Remove the session from the context.

    + +++ + + + + + +
    Parameters:session – the session to be removed.
    Returns:
    +
    0 The operation failed. The session was not found in
    +
    the cache.
    +
    +

    1 The operation succeeded.

    +
    +
    + +
    +
    +set_allow_unknown_ca(ok)[source]¶
    +

    Set the context to accept/reject a peer certificate if the +certificate’s CA is unknown.

    + +++ + + + +
    Parameters:ok – True to accept, False to reject.
    +
    + +
    +
    +set_cipher_list(cipher_list)[source]¶
    +

    Sets the list of available ciphers.

    + +++ + + + + + +
    Parameters:cipher_list – The format of the string is described in +ciphers(1).
    Returns:1 if any cipher could be selected and 0 on complete +failure.
    +
    + +
    +
    +set_client_CA_list_from_file(cafile)[source]¶
    +

    Load CA certs into the context. These CA certs are sent to the +peer during SSLv3 certificate request.

    + +++ + + + +
    Parameters:cafile – File object containing one or more PEM-encoded CA +certificates concatenated together.
    +
    + +
    +
    +set_default_verify_paths()[source]¶
    +

    Specifies that the default locations from which CA certs are +loaded should be used.

    +

    There is one default directory and one default file. The default +CA certificates directory is called “certs” in the default +OpenSSL directory. Alternatively the SSL_CERT_DIR environment +variable can be defined to override this location. The default +CA certificates file is called “cert.pem” in the default OpenSSL +directory. Alternatively the SSL_CERT_FILE environment variable +can be defined to override this location.

    +
    +
    @return 0 if the operation failed. A missing default location is
    +
    +
    still treated as a success. No error code is set.
    +

    1 The operation succeeded.

    +
    +
    +
    + +
    +
    +set_info_callback(callback=<function ssl_info_callback>)[source]¶
    +

    Set a callback function to get state information.

    +

    It can be used to get state information about the SSL +connections that are created from this context.

    + +++ + + + +
    Parameters:callback – Callback function. The default prints +information to stderr.
    +
    + +
    +
    +set_options(op)[source]¶
    +

    Adds the options set via bitmask in options to the Context.

    +

    !!! Options already set before are not cleared!

    +

    The behaviour of the SSL library can be changed by setting +several options. The options are coded as bitmasks and can be +combined by a logical or operation (|).

    +

    SSL.Context.set_options() and SSL.set_options() affect the +(external) protocol behaviour of the SSL library. The (internal) +behaviour of the API can be changed by using the similar +SSL.Context.set_mode() and SSL.set_mode() functions.

    +

    During a handshake, the option settings of the SSL object are +used. When a new SSL object is created from a context using +SSL(), the current option setting is copied. Changes to ctx +do not affect already created SSL objects. SSL.clear() does not +affect the settings.

    + +++ + + + + + +
    Parameters:op – bitmask of additional options specified in +SSL_CTX_set_options(3) manpage.
    Returns:the new options bitmask after adding options.
    +
    + +
    +
    +set_session_cache_mode(mode)[source]¶
    +

    Enables/disables session caching.

    +

    The mode is set by using m2.SSL_SESS_CACHE_* constants.

    + +++ + + + + + +
    Parameters:mode – new mode value.
    Returns:the previously set cache mode value.
    +
    + +
    +
    +set_session_id_ctx(id)[source]¶
    +

    Sets the session id for the SSL.Context w/in a session can be reused.

    + +++ + + + +
    Parameters:id – Sessions are generated within a certain context. When +exporting/importing sessions with +i2d_SSL_SESSION/d2i_SSL_SESSION it would be possible, +to re-import a session generated from another context +(e.g. another application), which might lead to +malfunctions. Therefore each application must set its +own session id context sid_ctx which is used to +distinguish the contexts and is stored in exported +sessions. The sid_ctx can be any kind of binary data +with a given length, it is therefore possible to use +e.g. the name of the application and/or the hostname +and/or service name.
    +
    + +
    +
    +set_session_timeout(timeout)[source]¶
    +

    Set new session timeout.

    +

    See self.get_session_timeout() for explanation of the session +timeouts.

    + +++ + + + + + +
    Parameters:timeout – new timeout value.
    Returns:the previously set timeout value.
    +
    + +
    +
    +set_tmp_dh(dhpfile)[source]¶
    +

    Load ephemeral DH parameters into the context.

    + +++ + + + +
    Parameters:dhpfile – Filename of the file containing the PEM-encoded +DH parameters.
    +
    + +
    +
    +set_tmp_dh_callback(callback=None)[source]¶
    +

    Sets the callback function for SSL.Context.

    + +++ + + + +
    Parameters:callback – Callable to be used when a DH parameters are required.
    +
    + +
    +
    +set_tmp_rsa(rsa)[source]¶
    +

    Load ephemeral RSA key into the context.

    + +++ + + + +
    Parameters:rsa – RSA.RSA instance.
    +
    + +
    +
    +set_tmp_rsa_callback(callback=None)[source]¶
    +

    Sets the callback function to be used when +a temporary/ephemeral RSA key is required.

    +
    + +
    +
    +set_verify(mode, depth, callback=None)[source]¶
    +

    Set verify options. Most applications will need to call this +method with the right options to make a secure SSL connection.

    + +++ + + + +
    Parameters:
      +
    • mode – The verification mode to use. Typically at least +SSL.verify_peer is used. Clients would also typically +add SSL.verify_fail_if_no_peer_cert.
    • +
    • depth – The maximum allowed depth of the certificate chain +returned by the peer.
    • +
    • callback – Callable that can be used to specify custom +verification checks.
    • +
    +
    +
    + +
    + +
    +
    +M2Crypto.SSL.Context.map()¶
    +
    + +
    +
    +

    SSLServer Module¶

    +
    +
    +class M2Crypto.SSL.SSLServer.SSLServer(server_address, RequestHandlerClass, ssl_context, bind_and_activate=True)[source]¶
    +

    Bases: socketserver.TCPServer

    +
    +
    +handle_error(request, client_address)[source]¶
    +

    Handle an error gracefully. May be overridden.

    +

    The default is to print a traceback and continue.

    +
    + +
    +
    +handle_request()[source]¶
    +

    Handle one request, possibly blocking.

    +

    Respects self.timeout.

    +
    + +
    + +
    +
    +class M2Crypto.SSL.SSLServer.ForkingSSLServer(server_address, RequestHandlerClass, ssl_context, bind_and_activate=True)[source]¶
    +

    Bases: socketserver.ForkingMixIn, M2Crypto.SSL.SSLServer.SSLServer

    +
    + +
    +
    +class M2Crypto.SSL.SSLServer.ThreadingSSLServer(server_address, RequestHandlerClass, ssl_context, bind_and_activate=True)[source]¶
    +

    Bases: socketserver.ThreadingMixIn, M2Crypto.SSL.SSLServer.SSLServer

    +
    + +
    +
    +

    Session Module¶

    +

    SSL Session

    +

    Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.

    +
    +
    +class M2Crypto.SSL.Session.Session(session, _pyfree=0)[source]¶
    +

    Bases: object

    +
    +
    +as_der()[source]¶
    +
    + +
    +
    +as_text()[source]¶
    +
    + +
    +
    +get_time()[source]¶
    +
    + +
    +
    +get_timeout()[source]¶
    +
    + +
    +
    +m2_ssl_session_free()¶
    +
    + +
    +
    +set_time(t)[source]¶
    +
    + +
    +
    +set_timeout(t)[source]¶
    +
    + +
    +
    +write_bio(bio)[source]¶
    +
    + +
    + +
    +
    +M2Crypto.SSL.Session.load_session(pemfile)[source]¶
    +
    + +
    +
    +

    TwistedProtocolWrapper Module¶

    +

    Make Twisted use M2Crypto for SSL

    +

    Copyright (c) 2004-2007 Open Source Applications Foundation. +All rights reserved.

    +

    FIXME THIS HAS NOT BEEN FINISHED. NEITHER PEP484 NOR PORT PYTHON3 HAS +BEEN FINISHED. THE FURTHER WORK WILL BE DONE WHEN THE STATUS OF TWISTED +IN THE PYTHON 3 (AND ASYNCIO) WORLD WILL BE CLEAR.

    +
    +
    +M2Crypto.SSL.TwistedProtocolWrapper.connectSSL(host, port, factory, contextFactory, timeout=30, bindAddress=None, reactor=<twisted.internet.epollreactor.EPollReactor object>, postConnectionCheck=<M2Crypto.SSL.Checker.Checker object>)[source]¶
    +

    A convenience function to start an SSL/TLS connection using Twisted.

    +

    See IReactorSSL interface in Twisted.

    +
    + +
    +
    +M2Crypto.SSL.TwistedProtocolWrapper.connectTCP(host, port, factory, timeout=30, bindAddress=None, reactor=<twisted.internet.epollreactor.EPollReactor object>, postConnectionCheck=<M2Crypto.SSL.Checker.Checker object>)[source]¶
    +

    A convenience function to start a TCP connection using Twisted.

    +

    NOTE: You must call startTLS(ctx) to go into SSL/TLS mode.

    +

    See IReactorTCP interface in Twisted.

    +
    + +
    +
    +M2Crypto.SSL.TwistedProtocolWrapper.listenSSL(port, factory, contextFactory, backlog=5, interface='', reactor=<twisted.internet.epollreactor.EPollReactor object>, postConnectionCheck=<function _alwaysSucceedsPostConnectionCheck>)[source]¶
    +

    A convenience function to listen for SSL/TLS connections using Twisted.

    +

    See IReactorSSL interface in Twisted.

    +
    + +
    +
    +M2Crypto.SSL.TwistedProtocolWrapper.listenTCP(port, factory, backlog=5, interface='', reactor=<twisted.internet.epollreactor.EPollReactor object>, postConnectionCheck=None)[source]¶
    +

    A convenience function to listen for TCP connections using Twisted.

    +

    NOTE: You must call startTLS(ctx) to go into SSL/TLS mode.

    +

    See IReactorTCP interface in Twisted.

    +
    + +
    +
    +class M2Crypto.SSL.TwistedProtocolWrapper.TLSProtocolWrapper(factory, wrappedProtocol, startPassThrough, client, contextFactory, postConnectionCheck)[source]¶
    +

    Bases: twisted.protocols.policies.ProtocolWrapper

    +

    A SSL/TLS protocol wrapper to be used with Twisted. Typically +you would not use this class directly. Use connectTCP, +connectSSL, listenTCP, listenSSL functions defined above, +which will hook in this class.

    +
    +
    +clear()[source]¶
    +

    Clear this instance, after which it is ready for reuse.

    +
    + +
    +
    +connectionLost(reason)[source]¶
    +

    Called when the connection is shut down.

    +

    Clear any circular references here, and any external references +to this Protocol. The connection has been closed.

    +

    @type reason: L{twisted.python.failure.Failure}

    +
    + +
    +
    +connectionMade()[source]¶
    +

    Called when a connection is made.

    +

    This may be considered the initializer of the protocol, because +it is called when the connection is completed. For clients, +this is called once the connection to the server has been +established; for servers, this is called after an accept() call +stops blocking and a socket has been received. If you need to +send any greeting or initial message, do it here.

    +
    + +
    +
    +dataReceived(data)[source]¶
    +

    Called whenever data is received.

    +

    Use this method to translate to a higher-level message. Usually, some +callback will be made upon the receipt of each complete protocol +message.

    +
    +
    @param data: a string of indeterminate length. Please keep in mind
    +
    that you will probably need to buffer some data, as partial +(or multiple) protocol messages may be received! I recommend +that unit tests for protocols call through to this method with +differing chunk sizes, down to one byte at a time.
    +
    +
    + +
    +
    +loseConnection()[source]¶
    +
    + +
    +
    +startTLS(ctx)[source]¶
    +

    Start SSL/TLS. If this is not called, this instance just passes data +through untouched.

    +
    + +
    +
    +write(data)[source]¶
    +
    + +
    +
    +writeSequence(data)[source]¶
    +
    + +
    + +
    +
    +

    cb Module¶

    +
    +
    +M2Crypto.SSL.cb.ssl_verify_callback_stub(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok)[source]¶
    +
    + +
    +
    +M2Crypto.SSL.cb.ssl_verify_callback(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok)[source]¶
    +
    + +
    +
    +M2Crypto.SSL.cb.ssl_verify_callback_allow_unknown_ca(ok, store)[source]¶
    +
    + +
    +
    +M2Crypto.SSL.cb.ssl_info_callback(where, ret, ssl_ptr)[source]¶
    +
    + +
    +
    +

    ssl_dispatcher Module¶

    +
    +
    +class M2Crypto.SSL.ssl_dispatcher.ssl_dispatcher(sock=None, map=None)[source]¶
    +

    Bases: asyncore.dispatcher

    +
    +
    +connect(addr)[source]¶
    +
    + +
    +
    +create_socket(ssl_context)[source]¶
    +
    + +
    +
    +recv(buffer_size=4096)[source]¶
    +

    Receive data over SSL.

    +
    + +
    +
    +send(buffer)[source]¶
    +

    Send data over SSL.

    +
    + +
    + +
    +
    +

    timeout Module¶

    +

    Support for SSL socket timeouts.

    +

    Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.

    +

    Copyright 2008 Heikki Toivonen. All rights reserved.

    +
    +
    +class M2Crypto.SSL.timeout.timeout(sec=600, microsec=0)[source]¶
    +

    Bases: object

    +
    +
    +pack()[source]¶
    +
    + +
    + +
    +
    +M2Crypto.SSL.timeout.struct_to_timeout(binstr)[source]¶
    +
    + +
    +
    +M2Crypto.SSL.timeout.struct_size()[source]¶
    +
    + +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/M2Crypto.html b/doc/html/M2Crypto.html new file mode 100644 index 0000000..b659a5e --- /dev/null +++ b/doc/html/M2Crypto.html @@ -0,0 +1,4874 @@ + + + + + + + + M2Crypto Package — M2Crypto documentation + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    M2Crypto Package¶

    +
    +

    M2Crypto Package¶

    +
    +
    +

    ASN1 Module¶

    +
    +
    +class M2Crypto.ASN1.ASN1_Integer(asn1int, _pyfree=0)[source]¶
    +

    Bases: object

    +
    +
    +m2_asn1_integer_free()¶
    +
    + +
    + +
    +
    +class M2Crypto.ASN1.ASN1_Object(asn1obj, _pyfree=0)[source]¶
    +

    Bases: object

    +
    +
    +m2_asn1_object_free()¶
    +
    + +
    + +
    +
    +class M2Crypto.ASN1.ASN1_String(asn1str, _pyfree=0)[source]¶
    +

    Bases: object

    +
    +
    +as_text(flags=0)[source]¶
    +

    Output an ASN1_STRING structure according to the set flags.

    + +++ + + + + + +
    Parameters:flags – determine the format of the output by using +predetermined constants, see ASN1_STRING_print_ex(3) +manpage for their meaning.
    Returns:output an ASN1_STRING structure.
    +
    + +
    +
    +m2_asn1_string_free()¶
    +
    + +
    + +
    +
    +class M2Crypto.ASN1.ASN1_TIME(asn1_time=None, _pyfree=0, asn1_utctime=None)[source]¶
    +

    Bases: object

    +
    +
    +get_datetime()[source]¶
    +
    + +
    +
    +m2_asn1_time_free()¶
    +
    + +
    +
    +set_datetime(date)[source]¶
    +
    + +
    +
    +set_string(string)[source]¶
    +

    Set time from UTC string.

    +
    + +
    +
    +set_time(time)[source]¶
    +

    Set time from seconds since epoch (int).

    +
    + +
    + +
    +
    +M2Crypto.ASN1.ASN1_UTCTIME¶
    +

    alias of M2Crypto.ASN1.ASN1_TIME

    +
    + +
    +
    +class M2Crypto.ASN1.LocalTimezone[source]¶
    +

    Bases: datetime.tzinfo

    +

    Localtimezone from datetime manual.

    +
    +
    +dst(dt)[source]¶
    +

    datetime -> DST offset as timedelta positive east of UTC.

    +
    + +
    +
    +tzname(dt)[source]¶
    +

    datetime -> string name of time zone.

    +
    + +
    +
    +utcoffset(dt)[source]¶
    +

    datetime -> timedelta showing offset from UTC, negative values indicating West of UTC

    +
    + +
    + +
    +
    +

    AuthCookie Module¶

    +
    +
    +class M2Crypto.AuthCookie.AuthCookie(expiry, data, dough, mac)[source]¶
    +

    Bases: object

    +
    +
    +data()[source]¶
    +

    Return the data portion of the cookie.

    +
    + +
    +
    +expiry()[source]¶
    +

    Return the cookie’s expiry time.

    +
    + +
    +
    +headerValue()[source]¶
    +
    + +
    +
    +isExpired()[source]¶
    +

    Return 1 if the cookie has expired, 0 otherwise.

    +
    + +
    +
    +mac()[source]¶
    +

    Return the cookie’s MAC.

    +
    + +
    +
    +name()[source]¶
    +
    + +
    +
    +output(header='Set-Cookie:')[source]¶
    +

    Return the cookie’s output in “Set-Cookie” format.

    +
    + +
    +
    +value()[source]¶
    +

    Return the cookie’s output minus the “Set-Cookie: ” portion.

    +
    + +
    + +
    +
    +class M2Crypto.AuthCookie.AuthCookieJar[source]¶
    +

    Bases: object

    +
    +
    +isGoodCookie(cookie)[source]¶
    +
    + +
    +
    +isGoodCookieString(cookie_str, _debug=False)[source]¶
    +
    + +
    +
    +makeCookie(expiry, data)[source]¶
    +

    Make a cookie

    + +++ + + + + + +
    Parameters:
      +
    • expiry – expiration time (float in seconds)
    • +
    • data – cookie content
    • +
    +
    Returns:

    AuthCookie object

    +
    +
    + +
    + +
    +
    +M2Crypto.AuthCookie.mix(expiry, data, format='exp=%f&data=%s&digest=')[source]¶
    +
    + +
    +
    +M2Crypto.AuthCookie.unmix(dough, regex=re.compile('exp=(\\d+\\.\\d+)&data=(.+)&digest=(\\S*)'))[source]¶
    +
    + +
    +
    +M2Crypto.AuthCookie.unmix3(dough, regex=re.compile('exp=(\\d+\\.\\d+)&data=(.+)&digest=(\\S*)'))[source]¶
    +
    + +
    +
    +

    BIO Module¶

    +
    +
    +class M2Crypto.BIO.BIO(bio=None, _pyfree=0, _close_cb=None)[source]¶
    +

    Bases: object

    +

    Abstract object interface to the BIO API.

    +
    +
    +bio_ptr()¶
    +
    + +
    +
    +close()[source]¶
    +
    + +
    +
    +fileno()[source]¶
    +
    + +
    +
    +flush()[source]¶
    +

    Flush the buffers.

    + +++ + + + +
    Returns:1 for success, and 0 or -1 for failure
    +
    + +
    +
    +m2_bio_free()¶
    +
    + +
    +
    +read(size=None)[source]¶
    +
    + +
    +
    +readable()[source]¶
    +
    + +
    +
    +readline(size=4096)[source]¶
    +
    + +
    +
    +readlines(sizehint='ignored')[source]¶
    +
    + +
    +
    +reset()[source]¶
    +

    Set the bio to its initial state.

    + +++ + + + +
    Returns:1 for success, and 0 or -1 for failure
    +
    + +
    +
    +seek(off)[source]¶
    +

    Seek to the specified absolute offset.

    +
    + +
    +
    +should_read()[source]¶
    +

    Should we read more data?

    +
    + +
    +
    +should_retry()[source]¶
    +

    Can the call be attempted again, or was there an error +ie do_handshake

    +
    + +
    +
    +should_write()[source]¶
    +

    Should we write more data?

    +
    + +
    +
    +tell()[source]¶
    +

    Return the current offset.

    +
    + +
    +
    +write(data)[source]¶
    +

    Write data to BIO.

    + +++ + + + +
    Returns:either data written, or [0, -1] for nothing written, +-2 not implemented
    +
    + +
    +
    +write_close()[source]¶
    +
    + +
    +
    +writeable()[source]¶
    +
    + +
    + +
    +
    +exception M2Crypto.BIO.BIOError[source]¶
    +

    Bases: ValueError

    +
    + +
    +
    +class M2Crypto.BIO.CipherStream(obio)[source]¶
    +

    Bases: M2Crypto.BIO.BIO

    +

    Object interface to BIO_f_cipher.

    +
    +
    +SALT_LEN = 8¶
    +
    + +
    +
    +close()[source]¶
    +
    + +
    +
    +m2_bio_free()¶
    +
    + +
    +
    +m2_bio_pop()¶
    +
    + +
    +
    +set_cipher(algo, key, iv, op)[source]¶
    +
    + +
    +
    +write_close()[source]¶
    +
    + +
    + +
    +
    +class M2Crypto.BIO.File(pyfile, close_pyfile=1, mode='rb')[source]¶
    +

    Bases: M2Crypto.BIO.BIO

    +

    Object interface to BIO_s_pyfd.

    +

    This class interfaces Python to OpenSSL functions that expect BIO. For +general file manipulation in Python, use Python’s builtin file object.

    +
    +
    +close()[source]¶
    +
    + +
    +
    +flush()[source]¶
    +

    Flush the buffers.

    + +++ + + + +
    Returns:1 for success, and 0 or -1 for failure
    +
    + +
    +
    +reset()[source]¶
    +

    Set the bio to its initial state.

    + +++ + + + +
    Returns:0 for success, and -1 for failure
    +
    + +
    + +
    +
    +class M2Crypto.BIO.IOBuffer(under_bio, mode='rwb', _pyfree=1)[source]¶
    +

    Bases: M2Crypto.BIO.BIO

    +

    Object interface to BIO_f_buffer.

    +

    Its principal function is to be BIO_push()’ed on top of a BIO_f_ssl, so +that makefile() of said underlying SSL socket works.

    +
    +
    +close()[source]¶
    +
    + +
    +
    +m2_bio_free()¶
    +
    + +
    +
    +m2_bio_pop()¶
    +
    + +
    + +
    +
    +class M2Crypto.BIO.MemoryBuffer(data=None)[source]¶
    +

    Bases: M2Crypto.BIO.BIO

    +

    Object interface to BIO_s_mem.

    +

    Empirical testing suggests that this class performs less well than +cStringIO, because cStringIO is implemented in C, whereas this class +is implemented in Python. Thus, the recommended practice is to use +cStringIO for regular work and convert said cStringIO object to +a MemoryBuffer object only when necessary.

    +
    +
    +close()¶
    +
    + +
    +
    +getvalue(size=0)¶
    +
    + +
    +
    +read(size=0)[source]¶
    +
    + +
    +
    +read_all(size=0)¶
    +
    + +
    +
    +write_close()[source]¶
    +
    + +
    + +
    +
    +class M2Crypto.BIO.SSLBio(_pyfree=1)[source]¶
    +

    Bases: M2Crypto.BIO.BIO

    +

    Object interface to BIO_f_ssl.

    +
    +
    +do_handshake()[source]¶
    +

    Do the handshake.

    +

    Return 1 if the handshake completes +Return 0 or a negative number if there is a problem

    +
    + +
    +
    +set_ssl(conn, close_flag=0)[source]¶
    +

    Sets the bio to the SSL pointer which is +contained in the connection object.

    +
    + +
    + +
    +
    +M2Crypto.BIO.openfile(filename, mode='rb')[source]¶
    +
    + +
    +
    +

    BN Module¶

    +
    +
    +M2Crypto.BN.rand(bits, top=-1, bottom=0)[source]¶
    +

    Generate cryptographically strong random number.

    + +++ + + + +
    Parameters:
      +
    • bits – Length of random number in bits.
    • +
    • top – If -1, the most significant bit can be 0. If 0, the most +significant bit is 1, and if 1, the two most significant +bits will be 1.
    • +
    • bottom – If bottom is true, the number will be odd.
    • +
    +
    +
    + +
    +
    +M2Crypto.BN.rand_range(range)[source]¶
    +

    Generate a random number in a range.

    + +++ + + + + + +
    Parameters:range – Upper limit for range.
    Returns:A random number in the range [0, range)
    +
    + +
    +
    +M2Crypto.BN.randfname(length)[source]¶
    +

    Return a random filename, which is simply a string where all +the characters are from the set [a-zA-Z0-9].

    + +++ + + + + + +
    Parameters:length – Length of filename to return.
    Returns:random filename string
    +
    + +
    +
    +

    DH Module¶

    +
    +
    +class M2Crypto.DH.DH(dh, _pyfree=0)[source]¶
    +

    Bases: object

    +

    Object interface to the Diffie-Hellman key exchange protocol.

    +
    +
    +check_params()[source]¶
    +
    + +
    +
    +compute_key(pubkey)[source]¶
    +
    + +
    +
    +gen_key()[source]¶
    +
    + +
    +
    +m2_dh_free()¶
    +
    + +
    +
    +print_params(bio)[source]¶
    +
    + +
    + +
    +
    +exception M2Crypto.DH.DHError[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +M2Crypto.DH.gen_params(plen, g, callback=<function genparam_callback>)[source]¶
    +
    + +
    +
    +M2Crypto.DH.load_params(file)[source]¶
    +
    + +
    +
    +M2Crypto.DH.load_params_bio(bio)[source]¶
    +
    + +
    +
    +M2Crypto.DH.set_params(p, g)[source]¶
    +
    + +
    +
    +

    DSA Module¶

    +
    +
    +class M2Crypto.DSA.DSA(dsa, _pyfree=0)[source]¶
    +

    Bases: object

    +

    This class is a context supporting DSA key and parameter +values, signing and verifying.

    +

    Simple example:

    +
    from M2Crypto import EVP, DSA, util
    +
    +message = 'Kilroy was here!'
    +md = EVP.MessageDigest('sha1')
    +md.update(message)
    +digest = md.final()
    +
    +dsa = DSA.gen_params(1024)
    +dsa.gen_key()
    +r, s = dsa.sign(digest)
    +good = dsa.verify(digest, r, s)
    +if good:
    +    print('  ** success **')
    +else:
    +    print('  ** verification failed **')
    +
    +
    +
    +
    +check_key()[source]¶
    +

    Check to be sure the DSA object has a valid private key.

    + +++ + + + +
    Returns:1 (true) if a valid private key
    +
    + +
    +
    +gen_key()[source]¶
    +

    Generate a key pair.

    +
    + +
    +
    +m2_dsa_free()¶
    +
    + +
    +
    +save_key(filename, cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Save the DSA key pair to a file.

    + +++ + + + + + +
    Parameters:
      +
    • filename – Save the DSA key pair to this file.
    • +
    • cipher – name of symmetric key algorithm and mode +to encrypt the private key.
    • +
    +
    Returns:

    1 (true) if successful

    +
    +
    + +
    +
    +save_key_bio(bio, cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Save DSA key pair to a BIO object.

    + +++ + + + + + +
    Parameters:
      +
    • bio – Save DSA parameters to this object.
    • +
    • cipher – name of symmetric key algorithm and mode +to encrypt the private key.
    • +
    +
    Returns:

    1 (true) if successful

    +
    +
    + +
    +
    +save_params(filename)[source]¶
    +

    Save the DSA parameters to a file.

    + +++ + + + + + +
    Parameters:filename – Save the DSA parameters to this file.
    Returns:1 (true) if successful
    +
    + +
    +
    +save_params_bio(bio)[source]¶
    +

    Save DSA parameters to a BIO object.

    + +++ + + + + + +
    Parameters:bio – Save DSA parameters to this object.
    Returns:1 (true) if successful
    +
    + +
    +
    +save_pub_key(filename)[source]¶
    +

    Save the DSA public key (with parameters) to a file.

    + +++ + + + + + +
    Parameters:filename – Save DSA public key (with parameters) +to this file.
    Returns:1 (true) if successful
    +
    + +
    +
    +save_pub_key_bio(bio)[source]¶
    +

    Save DSA public key (with parameters) to a BIO object.

    + +++ + + + + + +
    Parameters:bio – Save DSA public key (with parameters) +to this object.
    Returns:1 (true) if successful
    +
    + +
    +
    +set_params(p, q, g)[source]¶
    +

    Set new parameters.

    + +++ + + + +
    Parameters:
      +
    • p – MPI binary representation … format that consists of +the number’s length in bytes represented as a 4-byte +big-endian number, and the number itself in big-endian +format, where the most significant bit signals +a negative number (the representation of numbers with +the MSB set is prefixed with null byte).
    • +
    • q – ditto
    • +
    • g – ditto
    • +
    +
    +
    +
    @warning: This does not change the private key, so it may be
    +
    unsafe to use this method. It is better to use +gen_params function to create a new DSA object.
    +
    +
    + +
    +
    +sign(digest)[source]¶
    +

    Sign the digest.

    + +++ + + + + + +
    Parameters:digest – SHA-1 hash of message (same as output +from MessageDigest, a “byte string”)
    Returns:DSA signature, a tuple of two values, r and s, +both “byte strings”.
    +
    + +
    +
    +sign_asn1(digest)[source]¶
    +
    + +
    +
    +verify(digest, r, s)[source]¶
    +

    Verify a newly calculated digest against the signature +values r and s.

    + +++ + + + + + +
    Parameters:
      +
    • digest – SHA-1 hash of message (same as output +from MessageDigest, a “byte string”)
    • +
    • r – r value of the signature, a “byte string”
    • +
    • s – s value of the signature, a “byte string”
    • +
    +
    Returns:

    1 (true) if verify succeeded, 0 if failed

    +
    +
    + +
    +
    +verify_asn1(digest, blob)[source]¶
    +
    + +
    + +
    +
    +exception M2Crypto.DSA.DSAError[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +class M2Crypto.DSA.DSA_pub(dsa, _pyfree=0)[source]¶
    +

    Bases: M2Crypto.DSA.DSA

    +

    This class is a DSA context that only supports a public key +and verification. It does NOT support a private key or +signing.

    +
    +
    +check_key()[source]¶
    +
    +++ + + + +
    Returns:does DSA_pub contain a pub key?
    +
    + +
    +
    +save_key(filename)¶
    +

    Save the DSA public key (with parameters) to a file.

    + +++ + + + + + +
    Parameters:filename – Save DSA public key (with parameters) +to this file.
    Returns:1 (true) if successful
    +
    + +
    +
    +save_key_bio(bio)¶
    +

    Save DSA public key (with parameters) to a BIO object.

    + +++ + + + + + +
    Parameters:bio – Save DSA public key (with parameters) +to this object.
    Returns:1 (true) if successful
    +
    + +
    +
    +sign(*argv)[source]¶
    +

    Sign the digest.

    + +++ + + + + + +
    Parameters:digest – SHA-1 hash of message (same as output +from MessageDigest, a “byte string”)
    Returns:DSA signature, a tuple of two values, r and s, +both “byte strings”.
    +
    + +
    +
    +sign_asn1(*argv)¶
    +

    Sign the digest.

    + +++ + + + + + +
    Parameters:digest – SHA-1 hash of message (same as output +from MessageDigest, a “byte string”)
    Returns:DSA signature, a tuple of two values, r and s, +both “byte strings”.
    +
    + +
    + +
    +
    +M2Crypto.DSA.gen_params(bits, callback=<function genparam_callback>)[source]¶
    +

    Factory function that generates DSA parameters and +instantiates a DSA object from the output.

    + +++ + + + + + +
    Parameters:
      +
    • bits – The length of the prime to be generated. If +‘bits’ < 512, it is set to 512.
    • +
    • callback – A Python callback object that will be +invoked during parameter generation; it usual +purpose is to provide visual feedback.
    • +
    +
    Returns:

    instance of DSA.

    +
    +
    + +
    +
    +M2Crypto.DSA.load_key(file, callback=<function passphrase_callback>)[source]¶
    +

    Factory function that instantiates a DSA object from a +PEM encoded DSA key pair.

    + +++ + + + + + +
    Parameters:
      +
    • file – Names the file (a path) that contains the PEM +representation of the DSA key pair.
    • +
    • callback – A Python callback object that will be +invoked if the DSA key pair is +passphrase-protected.
    • +
    +
    Returns:

    instance of DSA.

    +
    +
    + +
    +
    +M2Crypto.DSA.load_key_bio(bio, callback=<function passphrase_callback>)[source]¶
    +

    Factory function that instantiates a DSA object from a +PEM encoded DSA key pair.

    + +++ + + + + + +
    Parameters:
      +
    • bio – Contains the PEM representation of the DSA +key pair.
    • +
    • callback – A Python callback object that will be +invoked if the DSA key pair is +passphrase-protected.
    • +
    +
    Returns:

    instance of DSA.

    +
    +
    + +
    +
    +M2Crypto.DSA.load_params(file, callback=<function passphrase_callback>)[source]¶
    +

    Factory function that instantiates a DSA object with DSA +parameters from a file.

    + +++ + + + + + +
    Parameters:
      +
    • file – Names the file (a path) that contains the PEM +representation of the DSA parameters.
    • +
    • callback – A Python callback object that will be +invoked if the DSA parameters file is +passphrase-protected.
    • +
    +
    Returns:

    instance of DSA.

    +
    +
    + +
    +
    +M2Crypto.DSA.load_params_bio(bio, callback=<function passphrase_callback>)[source]¶
    +

    Factory function that instantiates a DSA object with DSA +parameters from a M2Crypto.BIO object.

    + +++ + + + + + +
    Parameters:
      +
    • bio – Contains the PEM representation of the DSA +parameters.
    • +
    • callback – A Python callback object that will be +invoked if the DSA parameters file is +passphrase-protected.
    • +
    +
    Returns:

    instance of DSA.

    +
    +
    + +
    +
    +M2Crypto.DSA.load_pub_key(file, callback=<function passphrase_callback>)[source]¶
    +

    Factory function that instantiates a DSA_pub object using +a DSA public key contained in PEM file. The PEM file +must contain the parameters in addition to the public key.

    + +++ + + + + + +
    Parameters:
      +
    • file – Names the file (a path) that contains the PEM +representation of the DSA public key.
    • +
    • callback – A Python callback object that will be +invoked should the DSA public key be +passphrase-protected.
    • +
    +
    Returns:

    instance of DSA_pub.

    +
    +
    + +
    +
    +M2Crypto.DSA.load_pub_key_bio(bio, callback=<function passphrase_callback>)[source]¶
    +

    Factory function that instantiates a DSA_pub object using +a DSA public key contained in PEM format. The PEM +must contain the parameters in addition to the public key.

    + +++ + + + + + +
    Parameters:
      +
    • bio – Contains the PEM representation of the DSA +public key (with params).
    • +
    • callback – A Python callback object that will be +invoked should the DSA public key be +passphrase-protected.
    • +
    +
    Returns:

    instance of DSA_pub.

    +
    +
    + +
    +
    +M2Crypto.DSA.pub_key_from_params(p, q, g, pub)[source]¶
    +

    Factory function that instantiates a DSA_pub object using +the parameters and public key specified.

    + +++ + + + + + +
    Parameters:
      +
    • p – value of p
    • +
    • q – value of q
    • +
    • g – value of g
    • +
    • pub – value of the public key
    • +
    +
    Returns:

    instance of DSA_pub.

    +
    +
    + +
    +
    +M2Crypto.DSA.set_params(p, q, g)[source]¶
    +

    Factory function that instantiates a DSA object with DSA +parameters.

    + +++ + + + + + +
    Parameters:
      +
    • p – value of p, a “byte string”
    • +
    • q – value of q, a “byte string”
    • +
    • g – value of g, a “byte string”
    • +
    +
    Returns:

    instance of DSA.

    +
    +
    + +
    +
    +

    EC Module¶

    +
    +
    +class M2Crypto.EC.EC(ec, _pyfree=0)[source]¶
    +

    Bases: object

    +

    Object interface to a EC key pair.

    +
    +
    +as_pem(cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Returns the key(pair) as a string in PEM format. +If no password is passed and the cipher is set +it exits with error

    +
    + +
    +
    +check_key()[source]¶
    +
    + +
    +
    +compute_dh_key(pub_key)[source]¶
    +

    Compute the ECDH shared key of this key pair and the given public +key object. They must both use the same curve. Returns the +shared key in binary as a buffer object. No Key Derivation Function is +applied.

    +
    + +
    +
    +gen_key()[source]¶
    +

    Generates the key pair from its parameters. Use:

    +
    keypair = EC.gen_params(curve)
    +keypair.gen_key()
    +
    +
    +

    to create an EC key pair.

    +
    + +
    +
    +m2_ec_key_free()¶
    +
    + +
    +
    +pub()[source]¶
    +
    + +
    +
    +save_key(file, cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Save the key pair to a file in PEM format.

    + +++ + + + +
    Parameters:
      +
    • file – Name of filename to save key to.
    • +
    • cipher – Symmetric cipher to protect the key. The default +cipher is ‘aes_128_cbc’. If cipher is None, then +the key is saved in the clear.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect +the key. The default is +util.passphrase_callback.
    • +
    +
    +
    + +
    +
    +save_key_bio(bio, cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Save the key pair to an M2Crypto.BIO.BIO object in PEM format.

    + +++ + + + +
    Parameters:
      +
    • bio – M2Crypto.BIO.BIO object to save key to.
    • +
    • cipher – Symmetric cipher to protect the key. The default +cipher is ‘aes_128_cbc’. If cipher is None, then +the key is saved in the clear.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect +the key. The default is +util.passphrase_callback.
    • +
    +
    +
    + +
    +
    +save_pub_key(file)[source]¶
    +

    Save the public key to a filename in PEM format.

    + +++ + + + +
    Parameters:file – Name of filename to save key to.
    +
    + +
    +
    +save_pub_key_bio(bio)[source]¶
    +

    Save the public key to an M2Crypto.BIO.BIO object in PEM format.

    + +++ + + + +
    Parameters:bio – M2Crypto.BIO.BIO object to save key to.
    +
    + +
    +
    +sign_dsa(digest)[source]¶
    +

    Sign the given digest using ECDSA. Returns a tuple (r,s), the two +ECDSA signature parameters.

    +
    + +
    +
    +sign_dsa_asn1(digest)[source]¶
    +
    + +
    +
    +verify_dsa(digest, r, s)[source]¶
    +

    Verify the given digest using ECDSA. r and s are the ECDSA +signature parameters.

    +
    + +
    +
    +verify_dsa_asn1(digest, blob)[source]¶
    +
    + +
    + +
    +
    +exception M2Crypto.EC.ECError[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +class M2Crypto.EC.EC_pub(ec, _pyfree=0)[source]¶
    +

    Bases: M2Crypto.EC.EC

    +

    Object interface to an EC public key. +((don’t like this implementation inheritance))

    +
    +
    +get_der()[source]¶
    +

    Returns the public key in DER format as a buffer object.

    +
    + +
    +
    +get_key()[source]¶
    +

    Returns the public key as a byte string.

    +
    + +
    +
    +save_key(file)¶
    +

    Save the public key to a filename in PEM format.

    + +++ + + + +
    Parameters:file – Name of filename to save key to.
    +
    + +
    +
    +save_key_bio(bio)¶
    +

    Save the public key to an M2Crypto.BIO.BIO object in PEM format.

    + +++ + + + +
    Parameters:bio – M2Crypto.BIO.BIO object to save key to.
    +
    + +
    + +
    +
    +M2Crypto.EC.ec_error()[source]¶
    +
    + +
    +
    +M2Crypto.EC.gen_params(curve)[source]¶
    +

    Factory function that generates EC parameters and +instantiates a EC object from the output.

    + +++ + + + +
    Parameters:curve – This is the OpenSSL nid of the curve to use.
    +
    + +
    +
    +M2Crypto.EC.get_builtin_curves()[source]¶
    +
    + +
    +
    +M2Crypto.EC.load_key(file, callback=<function passphrase_callback>)[source]¶
    +

    Factory function that instantiates a EC object.

    + +++ + + + +
    Parameters:
      +
    • file – Names the filename that contains the PEM representation +of the EC key pair.
    • +
    • callback – Python callback object that will be invoked +if the EC key pair is passphrase-protected.
    • +
    +
    +
    + +
    +
    +M2Crypto.EC.load_key_bio(bio, callback=<function passphrase_callback>)[source]¶
    +

    Factory function that instantiates a EC object.

    + +++ + + + +
    Parameters:
      +
    • bio – M2Crypto.BIO object that contains the PEM +representation of the EC key pair.
    • +
    • callback – Python callback object that will be invoked +if the EC key pair is passphrase-protected.
    • +
    +
    +
    + +
    +
    +M2Crypto.EC.load_key_string(string, callback=<function passphrase_callback>)[source]¶
    +

    Load an EC key pair from a string.

    + +++ + + + + + +
    Parameters:
      +
    • string – String containing EC key pair in PEM format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to unlock the +key. The default is util.passphrase_callback.
    • +
    +
    Returns:

    M2Crypto.EC.EC object.

    +
    +
    + +
    +
    +M2Crypto.EC.load_key_string_pubkey(string, callback=<function passphrase_callback>)[source]¶
    +

    Load an M2Crypto.EC.PKey from a public key as a string.

    + +++ + + + + + +
    Parameters:
      +
    • string – String containing the key in PEM format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect the +key.
    • +
    +
    Returns:

    M2Crypto.EC.PKey object.

    +
    +
    + +
    +
    +M2Crypto.EC.load_pub_key(file)[source]¶
    +

    Load an EC public key from filename.

    + +++ + + + + + +
    Parameters:file – Name of filename containing EC public key in PEM +format.
    Returns:M2Crypto.EC.EC_pub object.
    +
    + +
    +
    +M2Crypto.EC.load_pub_key_bio(bio)[source]¶
    +

    Load an EC public key from an M2Crypto.BIO.BIO object.

    + +++ + + + + + +
    Parameters:bio – M2Crypto.BIO.BIO object containing EC public key in PEM +format.
    Returns:M2Crypto.EC.EC_pub object.
    +
    + +
    +
    +M2Crypto.EC.pub_key_from_der(der)[source]¶
    +

    Create EC_pub from DER.

    +
    + +
    +
    +M2Crypto.EC.pub_key_from_params(curve, bytes)[source]¶
    +

    Create EC_pub from curve name and octet string.

    +
    + +
    +
    +

    EVP Module¶

    +
    +
    +class M2Crypto.EVP.Cipher(alg, key, iv, op, key_as_bytes=0, d='md5', salt=b'12345678', i=1, padding=1)[source]¶
    +

    Bases: object

    +
    +
    +final()[source]¶
    +
    + +
    +
    +m2_cipher_ctx_free()¶
    +
    + +
    +
    +set_padding(padding=1)[source]¶
    +

    Actually always return 1

    +
    + +
    +
    +update(data)[source]¶
    +
    + +
    + +
    +
    +exception M2Crypto.EVP.EVPError[source]¶
    +

    Bases: ValueError

    +
    + +
    +
    +class M2Crypto.EVP.HMAC(key, algo='sha1')[source]¶
    +

    Bases: object

    +
    +
    +digest()¶
    +
    + +
    +
    +final()[source]¶
    +
    + +
    +
    +m2_hmac_ctx_free()¶
    +
    + +
    +
    +reset(key)[source]¶
    +
    + +
    +
    +update(data)[source]¶
    +
    + +
    + +
    +
    +class M2Crypto.EVP.MessageDigest(algo)[source]¶
    +

    Bases: object

    +

    Message Digest

    +
    +
    +digest()¶
    +
    + +
    +
    +final()[source]¶
    +
    + +
    +
    +m2_md_ctx_free()¶
    +
    + +
    +
    +update(data)[source]¶
    +

    Add data to be digested.

    + +++ + + + +
    Returns:-1 for Python error, 1 for success, 0 for OpenSSL failure.
    +
    + +
    + +
    +
    +class M2Crypto.EVP.PKey(pkey=None, _pyfree=0, md='sha1')[source]¶
    +

    Bases: object

    +

    Public Key

    +
    +
    +as_der()[source]¶
    +

    Return key in DER format in a string

    +
    + +
    +
    +as_pem(cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Return key in PEM format in a string.

    + +++ + + + +
    Parameters:
      +
    • cipher – Symmetric cipher to protect the key. The default +cipher is 'aes_128_cbc'. If cipher is None, +then the key is saved in the clear.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect +the key. The default is +util.passphrase_callback.
    • +
    +
    +
    + +
    +
    +assign_rsa(rsa, capture=1)[source]¶
    +

    Assign the RSA key pair to self.

    + +++ + + + + + +
    Parameters:
      +
    • rsa – M2Crypto.RSA.RSA object to be assigned to self.
    • +
    • capture – If true (default), this PKey object will own the RSA +object, meaning that once the PKey object gets +deleted it is no longer safe to use the RSA object.
    • +
    +
    Returns:

    Return 1 for success and 0 for failure.

    +
    +
    + +
    +
    +final()¶
    +

    Return signature.

    + +++ + + + +
    Returns:The signature.
    +
    + +
    +
    +get_modulus()[source]¶
    +

    Return the modulus in hex format.

    +
    + +
    +
    +get_rsa()[source]¶
    +

    Return the underlying RSA key if that is what the EVP +instance is holding.

    +
    + +
    +
    +m2_md_ctx_free()¶
    +
    + +
    +
    +m2_pkey_free()¶
    +
    + +
    +
    +reset_context(md='sha1')[source]¶
    +

    Reset internal message digest context.

    + +++ + + + +
    Parameters:md – The message digest algorithm.
    +
    + +
    +
    +save_key(file, cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Save the key pair to a file in PEM format.

    + +++ + + + +
    Parameters:
      +
    • file – Name of file to save key to.
    • +
    • cipher – Symmetric cipher to protect the key. The default +cipher is ‘aes_128_cbc’. If cipher is None, then +the key is saved in the clear.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect +the key. The default is +util.passphrase_callback.
    • +
    +
    +
    + +
    +
    +save_key_bio(bio, cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Save the key pair to the M2Crypto.BIO object ‘bio’ in PEM format.

    + +++ + + + +
    Parameters:
      +
    • bio – M2Crypto.BIO object to save key to.
    • +
    • cipher – Symmetric cipher to protect the key. The default +cipher is ‘aes_128_cbc’. If cipher is None, then +the key is saved in the clear.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect +the key. The default is +util.passphrase_callback.
    • +
    +
    +
    + +
    +
    +sign_final()[source]¶
    +

    Return signature.

    + +++ + + + +
    Returns:The signature.
    +
    + +
    +
    +sign_init()[source]¶
    +

    Initialise signing operation with self.

    +
    + +
    +
    +sign_update(data)[source]¶
    +

    Feed data to signing operation.

    + +++ + + + +
    Parameters:data – Data to be signed.
    +
    + +
    +
    +size()[source]¶
    +

    Return the size of the key in bytes.

    +
    + +
    +
    +update(data)¶
    +

    Feed data to signing operation.

    + +++ + + + +
    Parameters:data – Data to be signed.
    +
    + +
    +
    +verify_final(sign)[source]¶
    +

    Return result of verification.

    + +++ + + + + + +
    Parameters:sign – Signature to use for verification
    Returns:Result of verification: 1 for success, 0 for failure, -1 on +other error.
    +
    + +
    +
    +verify_init()[source]¶
    +

    Initialise signature verification operation with self.

    +
    + +
    +
    +verify_update(data)[source]¶
    +

    Feed data to verification operation.

    + +++ + + + + + +
    Parameters:data – Data to be verified.
    Returns:-1 on Python error, 1 for success, 0 for OpenSSL error
    +
    + +
    + +
    +
    +M2Crypto.EVP.hmac(key, data, algo='sha1')[source]¶
    +
    + +
    +
    +M2Crypto.EVP.load_key(file, callback=<function passphrase_callback>)[source]¶
    +

    Load an M2Crypto.EVP.PKey from file.

    + +++ + + + + + +
    Parameters:
      +
    • file – Name of file containing the key in PEM format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect the +key.
    • +
    +
    Returns:

    M2Crypto.EVP.PKey object.

    +
    +
    + +
    +
    +M2Crypto.EVP.load_key_bio(bio, callback=<function passphrase_callback>)[source]¶
    +

    Load an M2Crypto.EVP.PKey from an M2Crypto.BIO object.

    + +++ + + + + + +
    Parameters:
      +
    • bio – M2Crypto.BIO object containing the key in PEM format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect the +key.
    • +
    +
    Returns:

    M2Crypto.EVP.PKey object.

    +
    +
    + +
    +
    +M2Crypto.EVP.load_key_bio_pubkey(bio, callback=<function passphrase_callback>)[source]¶
    +

    Load an M2Crypto.EVP.PKey from a public key as a M2Crypto.BIO object.

    + +++ + + + + + +
    Parameters:
      +
    • bio – M2Crypto.BIO object containing the key in PEM format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect the +key.
    • +
    +
    Returns:

    M2Crypto.EVP.PKey object.

    +
    +
    + +
    +
    +M2Crypto.EVP.load_key_string(string, callback=<function passphrase_callback>)[source]¶
    +

    Load an M2Crypto.EVP.PKey from a string.

    + +++ + + + + + +
    Parameters:
      +
    • string – String containing the key in PEM format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect the +key.
    • +
    +
    Returns:

    M2Crypto.EVP.PKey object.

    +
    +
    + +
    +
    +M2Crypto.EVP.load_key_string_pubkey(string, callback=<function passphrase_callback>)[source]¶
    +

    Load an M2Crypto.EVP.PKey from a public key as a string.

    + +++ + + + + + +
    Parameters:
      +
    • string – String containing the key in PEM format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect the +key.
    • +
    +
    Returns:

    M2Crypto.EVP.PKey object.

    +
    +
    + +
    +
    +M2Crypto.EVP.pbkdf2(password, salt, iter, keylen)[source]¶
    +

    Derive a key from password using PBKDF2 algorithm specified in RFC 2898.

    + +++ + + + + + +
    Parameters:
      +
    • password – Derive the key from this password.
    • +
    • salt – Salt.
    • +
    • iter – Number of iterations to perform.
    • +
    • keylen – Length of key to produce.
    • +
    +
    Returns:

    Key.

    +
    +
    + +
    +
    +

    Engine Module¶

    +
    +
    +class M2Crypto.Engine.Engine(id=None, _ptr=None, _pyfree=1)[source]¶
    +

    Bases: object

    +

    Wrapper for ENGINE object.

    +
    +
    +ctrl_cmd_string(cmd, arg, optional=0)[source]¶
    +

    Call ENGINE_ctrl_cmd_string

    +
    + +
    +
    +finish()[source]¶
    +

    Release a functional and structural reference to the engine.

    +
    + +
    +
    +get_id()[source]¶
    +

    Return engine id

    +
    + +
    +
    +get_name()[source]¶
    +

    Return engine name

    +
    + +
    +
    +init()[source]¶
    +

    Obtain a functional reference to the engine.

    + +++ + + + +
    Returns:0 on error, non-zero on success.
    +
    + +
    +
    +load_certificate(name)[source]¶
    +

    Load certificate from engine (e.g from smartcard). +NOTE: This function may be not implemented by engine!

    +
    + +
    +
    +load_private_key(name, pin=None)[source]¶
    +

    Load private key with engine methods (e.g from smartcard). +If pin is not set it will be asked

    +
    + +
    +
    +load_public_key(name, pin=None)[source]¶
    +

    Load public key with engine methods (e.g from smartcard).

    +
    + +
    +
    +m2_engine_free()¶
    +
    + +
    +
    +set_default(methods=65535)[source]¶
    +

    Use this engine as default for methods specified in argument

    + +++ + + + +
    Parameters:methods – Possible values are bitwise OR of m2.ENGINE_METHOD_*
    +
    + +
    + +
    +
    +exception M2Crypto.Engine.EngineError[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +M2Crypto.Engine.cleanup()[source]¶
    +

    If you load any engines, you need to clean up after your application +is finished with the engines.

    +
    + +
    +
    +M2Crypto.Engine.load_dynamic()[source]¶
    +

    Load dynamic engine

    +
    + +
    +
    +M2Crypto.Engine.load_dynamic_engine(id, sopath)[source]¶
    +

    Load and return dymanic engine from sopath and assign id to it

    +
    + +
    +
    +M2Crypto.Engine.load_openssl()[source]¶
    +

    Load openssl engine

    +
    + +
    +
    +

    Err Module¶

    +
    +
    +exception M2Crypto.Err.M2CryptoError[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +exception M2Crypto.Err.SSLError(err, client_addr)[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +M2Crypto.Err.get_error()[source]¶
    +
    + +
    +
    +M2Crypto.Err.get_error_code()[source]¶
    +
    + +
    +
    +M2Crypto.Err.get_error_func(err)[source]¶
    +
    + +
    +
    +M2Crypto.Err.get_error_lib(err)[source]¶
    +
    + +
    +
    +M2Crypto.Err.get_error_message()[source]¶
    +
    + +
    +
    +M2Crypto.Err.get_error_reason(err)[source]¶
    +
    + +
    +
    +M2Crypto.Err.get_x509_verify_error(err)[source]¶
    +
    + +
    +
    +M2Crypto.Err.peek_error_code()[source]¶
    +
    + +
    +
    +

    RC4 Module¶

    +
    +
    +class M2Crypto.RC4.RC4(key=None)[source]¶
    +

    Bases: object

    +

    Object interface to the stream cipher RC4.

    +
    +
    +final()[source]¶
    +
    + +
    +
    +rc4_free()¶
    +
    + +
    +
    +set_key(key)[source]¶
    +
    + +
    +
    +update(data)[source]¶
    +
    + +
    + +
    +
    +

    RSA Module¶

    +
    +
    +class M2Crypto.RSA.RSA(rsa, _pyfree=0)[source]¶
    +

    Bases: object

    +

    RSA Key Pair.

    +
    +
    +as_pem(cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Returns the key(pair) as a string in PEM format.

    +
    + +
    +
    +check_key()[source]¶
    +

    Validate RSA keys.

    +

    It checks that p and q are in fact prime, and that n = p*q.

    + +++ + + + +
    Returns:returns 1 if rsa is a valid RSA key, and 0 otherwise. +-1 is returned if an error occurs while checking the key. +If the key is invalid or an error occurred, the reason +code can be obtained using ERR_get_error(3).
    +
    + +
    +
    +m2_rsa_free()¶
    +
    + +
    +
    +private_decrypt(data, padding)[source]¶
    +
    + +
    +
    +private_encrypt(data, padding)[source]¶
    +
    + +
    +
    +pub()[source]¶
    +
    + +
    +
    +public_decrypt(data, padding)[source]¶
    +
    + +
    +
    +public_encrypt(data, padding)[source]¶
    +
    + +
    +
    +save_key(file, cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Save the key pair to a file in PEM format.

    + +++ + + + +
    Parameters:
      +
    • file – Name of file to save key to.
    • +
    • cipher – Symmetric cipher to protect the key. The default +cipher is ‘aes_128_cbc’. If cipher is None, then +the key is saved in the clear.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect +the key. The default is +util.passphrase_callback.
    • +
    +
    +
    + +
    +
    +save_key_bio(bio, cipher='aes_128_cbc', callback=<function passphrase_callback>)[source]¶
    +

    Save the key pair to an M2Crypto.BIO.BIO object in PEM format.

    + +++ + + + +
    Parameters:
      +
    • bio – M2Crypto.BIO.BIO object to save key to.
    • +
    • cipher – Symmetric cipher to protect the key. The default +cipher is ‘aes_128_cbc’. If cipher is None, then +the key is saved in the clear.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect +the key. The default is +util.passphrase_callback.
    • +
    +
    +
    + +
    +
    +save_key_der(file)[source]¶
    +

    Save the key pair to a file in DER format.

    + +++ + + + +
    Parameters:file – Filename to save key to
    +
    + +
    +
    +save_key_der_bio(bio)[source]¶
    +

    Save the key pair to an M2Crypto.BIO.BIO object in DER format.

    + +++ + + + +
    Parameters:bio – M2Crypto.BIO.BIO object to save key to.
    +
    + +
    +
    +save_pem(file, cipher='aes_128_cbc', callback=<function passphrase_callback>)¶
    +

    Save the key pair to a file in PEM format.

    + +++ + + + +
    Parameters:
      +
    • file – Name of file to save key to.
    • +
    • cipher – Symmetric cipher to protect the key. The default +cipher is ‘aes_128_cbc’. If cipher is None, then +the key is saved in the clear.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to protect +the key. The default is +util.passphrase_callback.
    • +
    +
    +
    + +
    +
    +save_pub_key(file)[source]¶
    +

    Save the public key to a file in PEM format.

    + +++ + + + +
    Parameters:file – Name of file to save key to.
    +
    + +
    +
    +save_pub_key_bio(bio)[source]¶
    +

    Save the public key to an M2Crypto.BIO.BIO object in PEM format.

    + +++ + + + +
    Parameters:bio – M2Crypto.BIO.BIO object to save key to.
    +
    + +
    +
    +sign(digest, algo='sha1')[source]¶
    +

    Signs a digest with the private key

    + +++ + + + + + +
    Parameters:
      +
    • digest – A digest created by using the digest method
    • +
    • algo – The method that created the digest. +Legal values like ‘sha1’,’sha224’, ‘sha256’, +‘ripemd160’, and ‘md5’.
    • +
    +
    Returns:

    a string which is the signature

    +
    +
    + +
    +
    +sign_rsassa_pss(digest, algo='sha1', salt_length=20)[source]¶
    +

    Signs a digest with the private key using RSASSA-PSS

    + +++ + + + + + +
    Parameters:
      +
    • digest – A digest created by using the digest method
    • +
    • salt_length – The length of the salt to use
    • +
    • algo – The hash algorithm to use +Legal values like ‘sha1’,’sha224’, ‘sha256’, +‘ripemd160’, and ‘md5’.
    • +
    +
    Returns:

    a string which is the signature

    +
    +
    + +
    +
    +verify(data, signature, algo='sha1')[source]¶
    +

    Verifies the signature with the public key

    + +++ + + + + + +
    Parameters:
      +
    • data – Data that has been signed
    • +
    • signature – The signature signed with the private key
    • +
    • algo – The method use to create digest from the data +before it was signed. Legal values like +‘sha1’,’sha224’, ‘sha256’, ‘ripemd160’, and ‘md5’.
    • +
    +
    Returns:

    1 or 0, depending on whether the signature was +verified or not.

    +
    +
    + +
    +
    +verify_rsassa_pss(data, signature, algo='sha1', salt_length=20)[source]¶
    +

    Verifies the signature RSASSA-PSS

    + +++ + + + + + +
    Parameters:
      +
    • data – Data that has been signed
    • +
    • signature – The signature signed with RSASSA-PSS
    • +
    • salt_length – The length of the salt that was used
    • +
    • algo – The hash algorithm to use +Legal values are for example ‘sha1’,’sha224’, +‘sha256’, ‘ripemd160’, and ‘md5’.
    • +
    +
    Returns:

    1 or 0, depending on whether the signature was +verified or not.

    +
    +
    + +
    + +
    +
    +exception M2Crypto.RSA.RSAError[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +class M2Crypto.RSA.RSA_pub(rsa, _pyfree=0)[source]¶
    +

    Bases: M2Crypto.RSA.RSA

    +

    Object interface to an RSA public key.

    +
    +
    +check_key()[source]¶
    +

    Validate RSA keys.

    +

    It checks that p and q are in fact prime, and that n = p*q.

    + +++ + + + +
    Returns:returns 1 if rsa is a valid RSA key, and 0 otherwise. +-1 is returned if an error occurs while checking the key. +If the key is invalid or an error occurred, the reason +code can be obtained using ERR_get_error(3).
    +
    + +
    +
    +private_decrypt(*argv)[source]¶
    +
    + +
    +
    +private_encrypt(*argv)[source]¶
    +
    + +
    +
    +save_key(file, *args, **kw)[source]¶
    +

    Save public key to file.

    +
    + +
    +
    +save_key_bio(bio, *args, **kw)[source]¶
    +

    Save public key to BIO.

    +
    + +
    + +
    +
    +M2Crypto.RSA.gen_key(bits, e, callback=<function keygen_callback>)[source]¶
    +

    Generate an RSA key pair.

    + +++ + + + + + +
    Parameters:
      +
    • bits – Key length, in bits.
    • +
    • e – The RSA public exponent.
    • +
    • callback – A Python callable object that is invoked +during key generation; its usual purpose is to +provide visual feedback. The default callback is +keygen_callback.
    • +
    +
    Returns:

    M2Crypto.RSA.RSA object.

    +
    +
    + +
    +
    +M2Crypto.RSA.keygen_callback(p, n, out=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>)[source]¶
    +

    Default callback for gen_key().

    +
    + +
    +
    +M2Crypto.RSA.load_key(file, callback=<function passphrase_callback>)[source]¶
    +

    Load an RSA key pair from file.

    + +++ + + + + + +
    Parameters:
      +
    • file – Name of file containing RSA public key in PEM format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to unlock the +key. The default is util.passphrase_callback.
    • +
    +
    Returns:

    M2Crypto.RSA.RSA object.

    +
    +
    + +
    +
    +M2Crypto.RSA.load_key_bio(bio, callback=<function passphrase_callback>)[source]¶
    +

    Load an RSA key pair from an M2Crypto.BIO.BIO object.

    + +++ + + + + + +
    Parameters:
      +
    • bio – M2Crypto.BIO.BIO object containing RSA key pair in PEM +format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to unlock the +key. The default is util.passphrase_callback.
    • +
    +
    Returns:

    M2Crypto.RSA.RSA object.

    +
    +
    + +
    +
    +M2Crypto.RSA.load_key_string(string, callback=<function passphrase_callback>)[source]¶
    +

    Load an RSA key pair from a string.

    + +++ + + + + + +
    Parameters:
      +
    • string – String containing RSA key pair in PEM format.
    • +
    • callback – A Python callable object that is invoked +to acquire a passphrase with which to unlock the +key. The default is util.passphrase_callback.
    • +
    +
    Returns:

    M2Crypto.RSA.RSA object.

    +
    +
    + +
    +
    +M2Crypto.RSA.load_pub_key(file)[source]¶
    +

    Load an RSA public key from file.

    + +++ + + + + + +
    Parameters:file – Name of file containing RSA public key in PEM format.
    Returns:M2Crypto.RSA.RSA_pub object.
    +
    + +
    +
    +M2Crypto.RSA.load_pub_key_bio(bio)[source]¶
    +

    Load an RSA public key from an M2Crypto.BIO.BIO object.

    + +++ + + + + + +
    Parameters:bio – M2Crypto.BIO.BIO object containing RSA public key in PEM +format.
    Returns:M2Crypto.RSA.RSA_pub object.
    +
    + +
    +
    +M2Crypto.RSA.new_pub_key(e_n)[source]¶
    +

    Instantiate an RSA_pub object from an (e, n) tuple.

    + +++ + + + + + +
    Parameters:
      +
    • e – The RSA public exponent; it is a string in OpenSSL’s MPINT +format - 4-byte big-endian bit-count followed by the +appropriate number of bits.
    • +
    • n – The RSA composite of primes; it is a string in OpenSSL’s +MPINT format - 4-byte big-endian bit-count followed by the +appropriate number of bits.
    • +
    +
    Returns:

    M2Crypto.RSA.RSA_pub object.

    +
    +
    + +
    +
    +M2Crypto.RSA.rsa_error()[source]¶
    +
    + +
    +
    +

    Rand Module¶

    +

    M2Crypto wrapper for OpenSSL PRNG. Requires OpenSSL 0.9.5 and above.

    +

    Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. +Copyright (c) 2014-2017 Matej Cepl. All rights reserved.

    +

    See LICENCE for the license information.

    +
    +
    +M2Crypto.Rand.rand_seed(seed)[source]¶
    +

    Equivalent to rand_add() when len(seed) == entropy.

    + +++ + + + +
    Parameters:seed – added data (see description at rand_add)
    +
    + +
    +
    +M2Crypto.Rand.rand_add(blob, entropy)[source]¶
    +

    Mixes blob into the PRNG state.

    + +++ + + + +
    Parameters:
      +
    • blob – added data
    • +
    • entropy – (the lower bound of) an estimate of how much randomness +is contained in blob, measured in bytes.
    • +
    +
    +

    Thus, if the data at buf are unpredictable to an adversary, this +increases the uncertainty about the state and makes the PRNG output less +predictable. Suitable input comes from user interaction (random key +presses, mouse movements) and certain hardware events.

    +

    Details about sources of randomness and how to estimate their entropy +can be found in the literature, e.g. RFC 1750.

    +
    + +
    +
    +M2Crypto.Rand.load_file(filename, max_bytes)[source]¶
    +

    Read a number of bytes from file filename and adds them to the PRNG.

    +

    If max_bytes is non-negative, up to to max_bytes are read; starting with +OpenSSL 0.9.5, if max_bytes is -1, the complete file is read.

    + +++ + + + + + +
    Parameters:
      +
    • filename –
    • +
    • max_bytes –
    • +
    +
    Returns:

    the number of bytes read.

    +
    +
    + +
    +
    +M2Crypto.Rand.save_file(filename)[source]¶
    +

    Write a number of random bytes (currently 1024) to file.

    +

    The file then can be used to initialize the PRNG by calling load_file() in +a later session.

    + +++ + + + + + +
    Parameters:filename –
    Returns:returns the number of bytes written, and -1 if the bytes +written were generated without appropriate seed.
    +
    + +
    +
    +M2Crypto.Rand.rand_bytes(num)[source]¶
    +

    Return n cryptographically strong pseudo-random bytes.

    +

    An error occurs if the PRNG has not been seeded with enough randomness +to ensure an unpredictable byte sequence.

    + +++ + + + + + +
    Parameters:num – number of bytes to be returned
    Returns:random bytes
    +
    + +
    +
    +M2Crypto.Rand.rand_pseudo_bytes(num)[source]¶
    +

    Return num pseudo-random bytes into buf.

    +

    Pseudo-random byte sequences generated by this method will be unique +if they are of sufficient length, but are not necessarily +unpredictable. They can be used for non-cryptographic purposes and for +certain purposes in cryptographic protocols, but usually not for key +generation etc.

    +

    Output of the function is mixed into the entropy pool before +retrieving the new pseudo-random bytes unless disabled at compile +time (see FAQ).

    + +++ + + + + + +
    Parameters:num – number of bytes to be returned
    Returns:random bytes
    +
    + +
    +
    +M2Crypto.Rand.rand_file_name()[source]¶
    +

    Generate a default path for the random seed file.

    + +++ + + + +
    Returns:string with the filename. +The seed file is $RANDFILE if that environment variable +is set, $HOME/.rnd otherwise. If $HOME is not set either, +an error occurs.
    +
    + +
    +
    +M2Crypto.Rand.rand_status()[source]¶
    +

    Check whether there is enough entropy in PRNG.

    + +++ + + + +
    Returns:1 if the PRNG has been seeded with enough +data, 0 otherwise.
    +
    + +
    +
    +

    SMIME Module¶

    +
    +
    +class M2Crypto.SMIME.Cipher(algo)[source]¶
    +

    Bases: object

    +

    Object interface to EVP_CIPHER without all the frills of +M2Crypto.EVP.Cipher.

    +
    + +
    +
    +class M2Crypto.SMIME.PKCS7(pkcs7=None, _pyfree=0)[source]¶
    +

    Bases: object

    +
    +
    +get0_signers(certs, flags=0)[source]¶
    +
    + +
    +
    +m2_pkcs7_free()¶
    +
    + +
    +
    +type(text_name=0)[source]¶
    +
    + +
    +
    +write(bio)[source]¶
    +
    + +
    +
    +write_der(bio)[source]¶
    +
    + +
    + +
    +
    +exception M2Crypto.SMIME.PKCS7_Error[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +class M2Crypto.SMIME.SMIME[source]¶
    +

    Bases: object

    +
    +
    +decrypt(pkcs7, flags=0)[source]¶
    +
    + +
    +
    +encrypt(data_bio, flags=0)[source]¶
    +
    + +
    +
    +load_key(keyfile, certfile=None, callback=<function passphrase_callback>)[source]¶
    +
    + +
    +
    +load_key_bio(keybio, certbio=None, callback=<function passphrase_callback>)[source]¶
    +
    + +
    +
    +set_cipher(cipher)[source]¶
    +
    + +
    +
    +set_x509_stack(stack)[source]¶
    +
    + +
    +
    +set_x509_store(store)[source]¶
    +
    + +
    +
    +sign(data_bio, flags=0, algo='sha1')[source]¶
    +
    + +
    +
    +unset_cipher()[source]¶
    +
    + +
    +
    +unset_key()[source]¶
    +
    + +
    +
    +unset_x509_stack()[source]¶
    +
    + +
    +
    +unset_x509_store()[source]¶
    +
    + +
    +
    +verify(pkcs7, data_bio=None, flags=0)[source]¶
    +
    + +
    +
    +write(out_bio, pkcs7, data_bio=None, flags=0)[source]¶
    +
    + +
    + +
    +
    +exception M2Crypto.SMIME.SMIME_Error[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +M2Crypto.SMIME.load_pkcs7(p7file)[source]¶
    +
    + +
    +
    +M2Crypto.SMIME.load_pkcs7_bio(p7_bio)[source]¶
    +
    + +
    +
    +M2Crypto.SMIME.load_pkcs7_bio_der(p7_bio)[source]¶
    +
    + +
    +
    +M2Crypto.SMIME.load_pkcs7_der(p7file)[source]¶
    +
    + +
    +
    +M2Crypto.SMIME.smime_load_pkcs7(p7file)[source]¶
    +
    + +
    +
    +M2Crypto.SMIME.smime_load_pkcs7_bio(p7_bio)[source]¶
    +
    + +
    +
    +M2Crypto.SMIME.text_crlf(text)[source]¶
    +
    + +
    +
    +M2Crypto.SMIME.text_crlf_bio(bio_in)[source]¶
    +
    + +
    +
    +

    X509 Module¶

    +
    +
    +class M2Crypto.X509.CRL(crl=None, _pyfree=0)[source]¶
    +

    Bases: object

    +

    X509 Certificate Revocation List

    +
    +
    +as_text()[source]¶
    +

    Return CRL in PEM format in a string.

    + +++ + + + +
    Returns:String containing the CRL in PEM format.
    +
    + +
    +
    +m2_x509_crl_free()¶
    +
    + +
    + +
    +
    +class M2Crypto.X509.Request(req=None, _pyfree=0)[source]¶
    +

    Bases: object

    +

    X509 Certificate Request.

    +
    +
    +add_extensions(ext_stack)[source]¶
    +

    Add X509 extensions to this request.

    + +++ + + + + + +
    Parameters:ext_stack – Stack of extensions to add.
    Returns:1 for success and 0 for failure
    +
    + +
    +
    +as_der()[source]¶
    +
    + +
    +
    +as_pem()[source]¶
    +
    + +
    +
    +as_text()[source]¶
    +
    + +
    +
    +get_pubkey()[source]¶
    +

    Get the public key for the request.

    + +++ + + + +
    Returns:Public key from the request.
    +
    + +
    +
    +get_subject()[source]¶
    +
    + +
    +
    +get_version()[source]¶
    +

    Get version.

    + +++ + + + +
    Returns:Returns version.
    +
    + +
    +
    +m2_x509_req_free()¶
    +
    + +
    +
    +save(filename, format=1)[source]¶
    +

    Saves X.509 certificate request to a file. Default output +format is PEM.

    + +++ + + + + + +
    Parameters:
      +
    • filename – Name of the file the request will be saved to.
    • +
    • format – Controls what output format is used to save the +request. Either FORMAT_PEM or FORMAT_DER to save +in PEM or DER format. Raises ValueError if an +unknown format is used.
    • +
    +
    Returns:

    1 for success, 0 for failure. +The error code can be obtained by ERR_get_error.

    +
    +
    + +
    +
    +save_pem(filename)[source]¶
    +
    + +
    +
    +set_pubkey(pkey)[source]¶
    +

    Set the public key for the request.

    + +++ + + + + + +
    Parameters:pkey – Public key
    Returns:Return 1 for success and 0 for failure.
    +
    + +
    +
    +set_subject(name)¶
    +

    Set subject name.

    + +++ + + + + + +
    Parameters:name – subjectName field.
    Returns:1 for success and 0 for failure
    +
    + +
    +
    +set_subject_name(name)[source]¶
    +

    Set subject name.

    + +++ + + + + + +
    Parameters:name – subjectName field.
    Returns:1 for success and 0 for failure
    +
    + +
    +
    +set_version(version)[source]¶
    +

    Set version.

    + +++ + + + + + +
    Parameters:version – Version number.
    Returns:Returns 0 on failure.
    +
    + +
    +
    +sign(pkey, md)[source]¶
    +
    +++ + + + + + +
    Parameters:
      +
    • pkey – PKey to be signed
    • +
    • md – used algorigthm
    • +
    +
    Returns:

    1 for success and 0 for failure

    +
    +
    + +
    +
    +verify(pkey)[source]¶
    +
    +++ + + + + + +
    Parameters:pkey – PKey to be verified
    Returns:1 for success and 0 for failure
    +
    + +
    + +
    +
    +class M2Crypto.X509.X509(x509=None, _pyfree=0)[source]¶
    +

    Bases: object

    +

    X.509 Certificate

    +
    +
    +add_ext(ext)[source]¶
    +

    Add X509 extension to this certificate.

    + +++ + + + +
    Parameters:ext – Extension
    +

    :return 1 for success and 0 for failure

    +
    + +
    +
    +as_der()[source]¶
    +
    + +
    +
    +as_pem()[source]¶
    +
    + +
    +
    +as_text()[source]¶
    +
    + +
    +
    +check_ca()[source]¶
    +

    Check if the certificate is a Certificate Authority (CA) certificate.

    + +++ + + + + + +
    Returns:0 if the certificate is not CA, nonzero otherwise.
    Requires:OpenSSL 0.9.8 or newer
    +
    + +
    +
    +check_purpose(id, ca)[source]¶
    +

    Check if the certificate’s purpose matches the asked purpose.

    + +++ + + + + + +
    Parameters:
      +
    • id – Purpose id. See X509_PURPOSE_* constants.
    • +
    • ca – 1 if the certificate should be CA, 0 otherwise.
    • +
    +
    Returns:

    0 if the certificate purpose does not match, nonzero +otherwise.

    +
    +
    + +
    +
    +get_ext(name)[source]¶
    +

    Get X509 extension by name.

    + +++ + + + + + +
    Parameters:name – Name of the extension
    Returns:X509_Extension
    +
    + +
    +
    +get_ext_at(index)[source]¶
    +

    Get X509 extension by index.

    + +++ + + + + + +
    Parameters:index – Name of the extension
    Returns:X509_Extension
    +
    + +
    +
    +get_ext_count()[source]¶
    +

    Get X509 extension count.

    +
    + +
    +
    +get_fingerprint(md='md5')[source]¶
    +

    Get the fingerprint of the certificate.

    + +++ + + + + + +
    Parameters:md – Message digest algorithm to use.
    Returns:String containing the fingerprint in hex format.
    +
    + +
    +
    +get_issuer()[source]¶
    +
    + +
    +
    +get_not_after()[source]¶
    +
    + +
    +
    +get_not_before()[source]¶
    +
    + +
    +
    +get_pubkey()[source]¶
    +
    + +
    +
    +get_serial_number()[source]¶
    +
    + +
    +
    +get_subject()[source]¶
    +
    + +
    +
    +get_version()[source]¶
    +
    + +
    +
    +m2_x509_free()¶
    +
    + +
    +
    +save(filename, format=1)[source]¶
    +

    Saves X.509 certificate to a file. Default output +format is PEM.

    + +++ + + + + + +
    Parameters:
      +
    • filename – Name of the file the cert will be saved to.
    • +
    • format – Controls what output format is used to save the cert. +Either FORMAT_PEM or FORMAT_DER to save in PEM or +DER format. Raises a ValueError if an unknow +format is used.
    • +
    +
    Returns:

    1 for success or 0 for failure

    +
    +
    + +
    +
    +save_pem(filename)[source]¶
    +
    +++ + + + + + +
    Parameters:filename – name of the file to be loaded
    Returns:1 for success or 0 for failure
    +
    + +
    +
    +set_issuer(name)[source]¶
    +

    Set issuer name.

    + +++ + + + +
    Parameters:name – subjectName field.
    +

    :return 1 for success and 0 for failure

    +
    + +
    +
    +set_issuer_name(name)[source]¶
    +
    +++ + + + +
    Returns:1 on success, 0 on failure
    +
    + +
    +
    +set_not_after(asn1_time)[source]¶
    +
    +++ + + + +
    Returns:1 on success, 0 on failure
    +
    + +
    +
    +set_not_before(asn1_time)[source]¶
    +
    +++ + + + +
    Returns:1 on success, 0 on failure
    +
    + +
    +
    +set_pubkey(pkey)[source]¶
    +

    Set the public key for the certificate

    + +++ + + + +
    Parameters:pkey – Public key
    +

    :return 1 for success and 0 for failure

    +
    + +
    +
    +set_serial_number(serial)[source]¶
    +

    Set serial number.

    + +++ + + + +
    Parameters:serial – Serial number.
    +

    :return 1 for success and 0 for failure.

    +
    + +
    +
    +set_subject(name)[source]¶
    +

    Set subject name.

    + +++ + + + +
    Parameters:name – subjectName field.
    +

    :return 1 for success and 0 for failure

    +
    + +
    +
    +set_subject_name(name)[source]¶
    +
    +++ + + + +
    Returns:1 on success, 0 on failure
    +
    + +
    +
    +set_version(version)[source]¶
    +

    Set version of the certificate.

    + +++ + + + + + +
    Parameters:version – Version number.
    Returns:Returns 0 on failure.
    +
    + +
    +
    +sign(pkey, md)[source]¶
    +

    Sign the certificate.

    + +++ + + + +
    Parameters:
      +
    • pkey – Public key
    • +
    • md – Message digest algorithm to use for signing, +for example ‘sha1’.
    • +
    +
    +

    :return int

    +
    + +
    +
    +verify(pkey=None)[source]¶
    +
    + +
    + +
    +
    +exception M2Crypto.X509.X509Error[source]¶
    +

    Bases: ValueError

    +
    + +
    +
    +class M2Crypto.X509.X509_Extension(x509_ext_ptr=None, _pyfree=1)[source]¶
    +

    Bases: object

    +

    X509 Extension

    +
    +
    +get_critical()[source]¶
    +

    Return whether or not this is a critical extension.

    + +++ + + + +
    Returns:Nonzero if this is a critical extension.
    +
    + +
    +
    +get_name()[source]¶
    +

    Get the extension name, for example ‘subjectAltName’.

    +
    + +
    +
    +get_value(flag=0, indent=0)[source]¶
    +

    Get the extension value, for example ‘DNS:www.example.com’.

    + +++ + + + +
    Parameters:
      +
    • flag – Flag to control what and how to print.
    • +
    • indent – How many spaces to print before actual value.
    • +
    +
    +
    + +
    +
    +m2_x509_extension_free()¶
    +
    + +
    +
    +set_critical(critical=1)[source]¶
    +

    Mark this extension critical or noncritical. By default an +extension is not critical.

    + +++ + + + + + +
    Parameters:critical – Nonzero sets this extension as critical. +Calling this method without arguments will +set this extension to critical.
    Returns:1 for success, 0 for failure
    +
    + +
    + +
    +
    +class M2Crypto.X509.X509_Extension_Stack(stack=None, _pyfree=0)[source]¶
    +

    Bases: object

    +

    X509 Extension Stack

    + +++ + + + +
    Warning:Do not modify the underlying OpenSSL stack +except through this interface, or use any OpenSSL +functions that do so indirectly. Doing so will get the +OpenSSL stack and the internal pystack of this class out +of sync, leading to python memory leaks, exceptions or +even python crashes!
    +
    +
    +m2_sk_x509_extension_free()¶
    +
    + +
    +
    +pop()[source]¶
    +

    Pop X509_Extension object from the stack.

    + +++ + + + +
    Returns:X509_Extension popped
    +
    + +
    +
    +push(x509_ext)[source]¶
    +

    Push X509_Extension object onto the stack.

    + +++ + + + + + +
    Parameters:x509_ext – X509_Extension object to be pushed onto the stack.
    Returns:The number of extensions on the stack.
    +
    + +
    + +
    +
    +class M2Crypto.X509.X509_Name(x509_name=None, _pyfree=0)[source]¶
    +

    Bases: object

    +

    X509 Name

    +
    +
    +add_entry_by_txt(field, type, entry, len, loc, set)[source]¶
    +

    Add X509_Name field whose name is identified by its name.

    + +++ + + + +
    Parameters:
      +
    • field – name of the entry
    • +
    • type – use MBSTRING_ASC or MBSTRING_UTF8 +(or standard ASN1 type like V_ASN1_IA5STRING)
    • +
    • entry – value
    • +
    • len – buf_len of the entry +(-1 and the length is computed automagically)
    • +
    +
    +

    The loc and set parameters determine where a new entry +should be added. +For almost all applications loc can be set to -1 and set to 0. +This adds a new entry to the end of name as a single valued +RelativeDistinguishedName (RDN).

    + +++ + + + + + +
    Parameters:
      +
    • loc – determines the index where the new entry is +inserted: if it is -1 it is appended.
    • +
    • set – determines how the new type is added. If it is zero +a new RDN is created. +If set is -1 or 1 it is added to the previous or next RDN +structure respectively. This will then be a multivalued +RDN: since multivalues RDNs are very seldom used set is +almost always set to zero.
    • +
    +
    Returns:

    1 for success of 0 if an error occurred.

    +
    +
    + +
    +
    +as_der()[source]¶
    +
    + +
    +
    +as_hash()[source]¶
    +
    + +
    +
    +as_text(indent=0, flags=0)[source]¶
    +

    as_text returns the name as a string.

    + +++ + + + +
    Parameters:
      +
    • indent – Each line in multiline format is indented +by this many spaces.
    • +
    • flags – Flags that control how the output should be formatted.
    • +
    +
    +
    + +
    +
    +entry_count()[source]¶
    +
    + +
    +
    +get_entries_by_nid(nid)[source]¶
    +

    Retrieve the next index matching nid.

    + +++ + + + + + +
    Parameters:nid – name of the entry (as m2.NID* constants)
    Returns:list of X509_Name_Entry items
    +
    + +
    +
    +m2_x509_name_free()¶
    +
    + +
    +
    +nid = {'C': 14, 'CN': 13, 'Email': 48, 'GN': 99, 'L': 15, 'O': 17, 'OU': 18, 'SN': 100, 'SP': 16, 'ST': 16, 'commonName': 13, 'emailAddress': 48, 'givenName': 99, 'localityName': 15, 'organizationName': 17, 'organizationUnitName': 18, 'serialNumber': 105, 'stateOrProvinceName': 16, 'surname': 100}¶
    +
    + +
    + +
    +
    +class M2Crypto.X509.X509_Name_Entry(x509_name_entry, _pyfree=0)[source]¶
    +

    Bases: object

    +

    X509 Name Entry

    +
    +
    +create_by_txt(field, type, entry, len)[source]¶
    +
    + +
    +
    +get_data()[source]¶
    +
    + +
    +
    +get_object()[source]¶
    +
    + +
    +
    +m2_x509_name_entry_free()¶
    +
    + +
    +
    +set_data(data, type=4097)[source]¶
    +

    Sets the field name to asn1obj

    + +++ + + + + + +
    Parameters:data – data in a binary form to be set
    Returns:0 on failure, 1 on success
    +
    + +
    +
    +set_object(asn1obj)[source]¶
    +

    Sets the field name to asn1obj

    + +++ + + + + + +
    Parameters:asn1obj –
    Returns:0 on failure, 1 on success
    +
    + +
    + +
    +
    +class M2Crypto.X509.X509_Stack(stack=None, _pyfree=0, _pyfree_x509=0)[source]¶
    +

    Bases: object

    +

    X509 Stack

    + +++ + + + +
    Warning:Do not modify the underlying OpenSSL stack +except through this interface, or use any OpenSSL +functions that do so indirectly. Doing so will get the +OpenSSL stack and the internal pystack of this class out +of sync, leading to python memory leaks, exceptions or +even python crashes!
    +
    +
    +as_der()[source]¶
    +

    Return the stack as a DER encoded string

    +
    + +
    +
    +m2_sk_x509_free()¶
    +
    + +
    +
    +pop()[source]¶
    +

    pop a certificate from the stack.

    + +++ + + + +
    Returns:X509 object that was popped, or None if there is +nothing to pop.
    +
    + +
    +
    +push(x509)[source]¶
    +

    push an X509 certificate onto the stack.

    + +++ + + + + + +
    Parameters:x509 – X509 object.
    Returns:The number of X509 objects currently on the stack.
    +
    + +
    + +
    +
    +class M2Crypto.X509.X509_Store(store=None, _pyfree=0)[source]¶
    +

    Bases: object

    +

    X509 Store

    +
    +
    +add_cert(x509)¶
    +
    + +
    +
    +add_x509(x509)[source]¶
    +
    + +
    +
    +load_info(file)[source]¶
    +
    +++ + + + + + +
    Parameters:file – filename
    Returns:1 on success, 0 on failure
    +
    + +
    +
    +load_locations(file)¶
    +
    +++ + + + + + +
    Parameters:file – filename
    Returns:1 on success, 0 on failure
    +
    + +
    +
    +m2_x509_store_free()¶
    +
    + +
    +
    +set_verify_cb(callback=None)[source]¶
    +

    Set callback which will be called when the store is verified. +Wrapper over OpenSSL X509_STORE_set_verify_cb().

    + +++ + + + + + + + + + +
    Parameters:callback – Callable to specify verification options. +Type of the callable must be: +(int, X509_Store_Context) -> int. +If None: set the standard options.
    Note:compile-time or run-time errors in the callback would result +in mysterious errors during verification, which could be hard +to trace.
    Note:Python exceptions raised in callbacks do not propagate to +verify() call.
    Returns:None
    +
    + +
    + +
    +
    +class M2Crypto.X509.X509_Store_Context(x509_store_ctx, _pyfree=0)[source]¶
    +

    Bases: object

    +

    X509 Store Context

    +
    +
    +get1_chain()[source]¶
    +

    Get certificate chain.

    + +++ + + + +
    Returns:Reference counted (i.e. safe to use even after the store +context goes away) stack of certificates in the chain.
    +
    + +
    +
    +get_current_cert()[source]¶
    +

    Get current X.509 certificate.

    + +++ + + + +
    Warning:The returned certificate is NOT refcounted, so you can not +rely on it being valid once the store context goes +away or is modified.
    +
    + +
    +
    +get_error()[source]¶
    +

    Get error code.

    +
    + +
    +
    +get_error_depth()[source]¶
    +

    Get error depth.

    +
    + +
    +
    +m2_x509_store_ctx_free()¶
    +
    + +
    + +
    +
    +M2Crypto.X509.load_cert(file, format=1)[source]¶
    +

    Load certificate from file.

    + +++ + + + + + +
    Parameters:
      +
    • file – Name of file containing certificate in either DER or +PEM format.
    • +
    • format – Describes the format of the file to be loaded, +either PEM or DER.
    • +
    +
    Returns:

    M2Crypto.X509.X509 object.

    +
    +
    + +
    +
    +M2Crypto.X509.load_cert_bio(bio, format=1)[source]¶
    +

    Load certificate from a bio.

    + +++ + + + + + +
    Parameters:
      +
    • bio – BIO pointing at a certificate in either DER or PEM format.
    • +
    • format – Describes the format of the cert to be loaded, +either PEM or DER (via constants FORMAT_PEM +and FORMAT_FORMAT_DER)
    • +
    +
    Returns:

    M2Crypto.X509.X509 object.

    +
    +
    + +
    +
    +M2Crypto.X509.load_cert_der_string(string)[source]¶
    +

    Load certificate from a string.

    + +++ + + + + + +
    Parameters:string – String containing a certificate in DER format.
    Returns:M2Crypto.X509.X509 object.
    +
    + +
    +
    +M2Crypto.X509.load_cert_string(string, format=1)[source]¶
    +

    Load certificate from a string.

    + +++ + + + + + +
    Parameters:
      +
    • string – String containing a certificate in either DER or PEM format.
    • +
    • format – Describes the format of the cert to be loaded, +either PEM or DER (via constants FORMAT_PEM +and FORMAT_FORMAT_DER)
    • +
    +
    Returns:

    M2Crypto.X509.X509 object.

    +
    +
    + +
    +
    +M2Crypto.X509.load_crl(file)[source]¶
    +

    Load CRL from file.

    + +++ + + + + + +
    Parameters:file – Name of file containing CRL in PEM format.
    Returns:M2Crypto.X509.CRL object.
    +
    + +
    +
    +M2Crypto.X509.load_request(file, format=1)[source]¶
    +

    Load certificate request from file.

    + +++ + + + + + +
    Parameters:
      +
    • file – Name of file containing certificate request in +either PEM or DER format.
    • +
    • format – Describes the format of the file to be loaded, +either PEM or DER. (using constants FORMAT_PEM +and FORMAT_DER)
    • +
    +
    Returns:

    Request object.

    +
    +
    + +
    +
    +M2Crypto.X509.load_request_bio(bio, format=1)[source]¶
    +

    Load certificate request from a bio.

    + +++ + + + + + +
    Parameters:
      +
    • bio – BIO pointing at a certificate request in +either DER or PEM format.
    • +
    • format – Describes the format of the request to be loaded, +either PEM or DER. (using constants FORMAT_PEM +and FORMAT_DER)
    • +
    +
    Returns:

    M2Crypto.X509.Request object.

    +
    +
    + +
    +
    +M2Crypto.X509.load_request_der_string(string)[source]¶
    +

    Load certificate request from a string.

    + +++ + + + + + +
    Parameters:string – String containing a certificate request in DER format.
    Returns:M2Crypto.X509.Request object.
    +
    + +
    +
    +M2Crypto.X509.load_request_string(string, format=1)[source]¶
    +

    Load certificate request from a string.

    + +++ + + + + + +
    Parameters:
      +
    • string – String containing a certificate request in +either DER or PEM format.
    • +
    • format – Describes the format of the request to be loaded, +either PEM or DER. (using constants FORMAT_PEM +and FORMAT_DER)
    • +
    +
    Returns:

    M2Crypto.X509.Request object.

    +
    +
    + +
    +
    +M2Crypto.X509.new_extension(name, value, critical=0, _pyfree=1)[source]¶
    +

    Create new X509_Extension instance.

    +
    + +
    +
    +M2Crypto.X509.new_stack_from_der(der_string)[source]¶
    +

    Create a new X509_Stack from DER string.

    + +++ + + + +
    Returns:X509_Stack
    +
    + +
    +
    +M2Crypto.X509.x509_store_default_cb(ok, ctx)[source]¶
    +
    + +
    +
    +

    callback Module¶

    +
    +
    +

    ftpslib Module¶

    +
    +
    +class M2Crypto.ftpslib.FTP_TLS(host=None, ssl_ctx=None)[source]¶
    +

    Bases: ftplib.FTP

    +

    Python OO interface to client-side FTP/TLS.

    +
    +
    +auth_ssl()[source]¶
    +

    Secure the control connection per AUTH SSL, aka AUTH TLS-P.

    +
    + +
    +
    +auth_tls()[source]¶
    +

    Secure the control connection per AUTH TLS, aka AUTH TLS-C.

    +
    + +
    +
    +ntransfercmd(cmd, rest=None)[source]¶
    +

    Initiate a data transfer.

    +
    + +
    +
    +prot_c()[source]¶
    +

    Set up data connection in the clear.

    +
    + +
    +
    +prot_p()[source]¶
    +

    Set up secure data connection.

    +
    + +
    + +
    +
    +

    httpslib Module¶

    +
    +
    +class M2Crypto.httpslib.HTTPSConnection(host, port=None, strict=None, **ssl)[source]¶
    +

    Bases: http.client.HTTPConnection

    +

    This class allows communication via SSL using M2Crypto.

    +
    +
    +close()[source]¶
    +

    Close the connection to the HTTP server.

    +
    + +
    +
    +connect()[source]¶
    +

    Connect to the host and port specified in __init__.

    +
    + +
    +
    +default_port = 443¶
    +
    + +
    +
    +get_session()[source]¶
    +
    + +
    +
    +set_session(session)[source]¶
    +
    + +
    + +
    +
    +class M2Crypto.httpslib.ProxyHTTPSConnection(host, port=None, strict=None, username=None, password=None, **ssl)[source]¶
    +

    Bases: M2Crypto.httpslib.HTTPSConnection

    +

    An HTTPS Connection that uses a proxy and the CONNECT request.

    +

    When the connection is initiated, CONNECT is first sent to the proxy (along +with authorization headers, if supplied). If successful, an SSL connection +will be established over the socket through the proxy and to the target +host.

    +

    Finally, the actual request is sent over the SSL connection tunneling +through the proxy.

    +
    +
    +connect()[source]¶
    +

    Connect to the host and port specified in __init__.

    +
    + +
    +
    +endheaders(*args, **kwargs)[source]¶
    +

    Indicate that the last header line has been sent to the server.

    +

    This method sends the request to the server. The optional message_body +argument can be used to pass a message body associated with the +request.

    +
    + +
    +
    +putheader(header, value)[source]¶
    +

    Send a request header line to the server.

    +

    For example: h.putheader(‘Accept’, ‘text/html’)

    +
    + +
    +
    +putrequest(method, url, skip_host=0, skip_accept_encoding=0)[source]¶
    +

    putrequest is called before connect, so can interpret url and get +real host/port to be used to make CONNECT request to proxy

    +
    + +
    + +
    +
    +

    m2 Module¶

    +
    +
    +

    m2crypto Module¶

    +
    +
    +

    m2urllib Module¶

    +
    +
    +M2Crypto.m2urllib.open_https(self, url, data=None, ssl_context=None)[source]¶
    +

    Open URL over the SSL connection.

    + +++ + + + + + +
    Parameters:
      +
    • url – URL to be opened
    • +
    • data – data for the POST request
    • +
    • ssl_context – SSL.Context to be used
    • +
    +
    Returns:

    +
    +
    + +
    +
    +

    m2urllib2 Module¶

    +
    +
    +class M2Crypto.m2urllib2.HTTPSHandler(ssl_context=None)[source]¶
    +

    Bases: urllib.request.AbstractHTTPHandler

    +
    +
    +https_open(req)[source]¶
    +

    Return an addinfourl object for the request, using http_class.

    +

    http_class must implement the HTTPConnection API from httplib. +The addinfourl return value is a file-like object. It also +has methods and attributes including:

    +
    +
      +
    • info(): return a mimetools.Message object for the headers
    • +
    • geturl(): return the original request URL
    • +
    • code: HTTP status code
    • +
    +
    +
    + +
    +
    +https_request(request)¶
    +
    + +
    + +
    +
    +M2Crypto.m2urllib2.build_opener(ssl_context=None, *handlers)[source]¶
    +

    Create an opener object from a list of handlers.

    +

    The opener will use several default handlers, including support +for HTTP and FTP.

    +

    If any of the handlers passed as arguments are subclasses of the +default handlers, the default handlers will not be used.

    +
    + +
    +
    +

    m2xmlrpclib Module¶

    +
    +
    +class M2Crypto.m2xmlrpclib.SSL_Transport(ssl_context=None, *args, **kw)[source]¶
    +

    Bases: xmlrpc.client.Transport

    +
    +
    +request(host, handler, request_body, verbose=0)[source]¶
    +
    + +
    +
    +user_agent = 'M2Crypto_XMLRPC/0.33.0 - Python-xmlrpc/3.7'¶
    +
    + +
    + +
    +
    +

    threading Module¶

    +
    +
    +M2Crypto.threading.cleanup()[source]¶
    +

    End and cleanup threading support.

    +
    + +
    +
    +M2Crypto.threading.init()[source]¶
    +

    Initialize threading support.

    +
    + +
    +
    +

    util Module¶

    +
    +
    +exception M2Crypto.util.UtilError[source]¶
    +

    Bases: Exception

    +
    + +
    +
    +M2Crypto.util.bin_to_hex(b)[source]¶
    +
    + +
    +
    +M2Crypto.util.genparam_callback(p, n, out=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>)[source]¶
    +
    + +
    +
    +M2Crypto.util.no_passphrase_callback(*args)[source]¶
    +
    + +
    +
    +M2Crypto.util.octx_to_num(x)[source]¶
    +
    + +
    +
    +M2Crypto.util.passphrase_callback(v, prompt1='Enter passphrase:', prompt2='Verify passphrase:')[source]¶
    +
    + +
    +
    +M2Crypto.util.pkcs5_pad(data, blklen=8)[source]¶
    +
    + +
    +
    +M2Crypto.util.pkcs7_pad(data, blklen)[source]¶
    +
    + +
    +
    +M2Crypto.util.quiet_genparam_callback(p, n, out)[source]¶
    +
    + +
    + +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/ZServerSSL-HOWTO.html b/doc/html/ZServerSSL-HOWTO.html new file mode 100644 index 0000000..67023d0 --- /dev/null +++ b/doc/html/ZServerSSL-HOWTO.html @@ -0,0 +1,355 @@ + + + + + + + + 1.   ZServerSSL-HOWTO — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    1.   ZServerSSL-HOWTO¶

    + +++ + + + + + + + +
    author:Pheng Siong Ng <ngps@post1.com>
    copyright:© 2000, 2001 by Ng Pheng Siong.
    date:2003-06-22
    + +
    +

    1.1.   Introduction¶

    +

    ZServerSSL adds to Zope’s ZServer the following:

    +
      +
    • HTTPS server
    • +
    • WebDAV-source-over-HTTPS server
    • +
    +

    With the HTTPS server, ZServerSSL also provides WebDAV-over-HTTPS and +XMLRPC-over-HTTPS access to Zope.

    +

    These instructions apply to both Un*x and Windows installations of Zope +2.6.1. To avoid cluttering the presentation, Windows pathnames are shown +in Un*x fashion.

    +
    +
    +

    1.2.   Preparation¶

    +
      +
    1. Download M2Crypto 0.11, contained in the file m2crypto-0.11.zip.
    2. +
    3. Unpack m2crypto-0.11.zip. This will create a directory +m2crypto-0.11. Henceforth, we refer to this directory as $M2.
    4. +
    5. Install M2Crypto per the instructions in $M2/INSTALL.
    6. +
    +

    The ZServerSSL distribution is in $M2/demo/Zope. We shall refer to +this directory as $ZSSL.

    +
    +
    +

    1.3.   Installation¶

    +

    Below, we refer to your Zope top-level directory as $ZOPE.

    +
      +
    1. Copy $ZSSL/z2s.py into $ZOPE.

      +
    2. +
    3. Depending on your operating system, modify $ZOPE/start or +$ZOPE/start.bat to invoke $ZOPE/z2s.py, instead of +$ZOPE/z2.py. The files $ZSSL/starts and $ZSSL/starts.bat +serve as examples.

      +
    4. +
    5. Copy $ZSSL/dh1024.pem into $ZOPE. This file contains +Diffie-Hellman parameters for use by the SSL protocol.

      +
    6. +
    7. Copy $ZSSL/randpool.dat into $ZOPE. This file contains seed +material for the OpenSSL PRNG. Alternatively, create +$ZOPE/randpool.dat thusly:

      +
      $ dd if=/dev/urandom of=randpool.dat bs=1024 count=1
      +
      +
      +
    8. +
    9. Copy $ZSSL/ca.pem to $ZOPE. This file contains an +example Certification Authority (CA) certificate. For +information on operating your own CA, see HOWTO: Creating your own CA with OpenSSL or +one of numerous similar documents available on the web.

      +
    10. +
    11. Copy $ZSSL/server.pem to $ZOPE. This file contains an RSA key +pair and its X.509v3 certificate issued by the above CA. You may also +create your own key/certificate bundle.

      +
    12. +
    13. Copy $ZSSL/ZServer/HTTPS_Server.py to $ZOPE/ZServer.

      +
    14. +
    15. Copy $ZSSL/ZServer/__init__.py to $ZOPE/ZServer. This +overwrites the existing $ZOPE/ZServer/__init__.py. Alternatively, +apply the following patch to $ZOPE/ZServer/__init__.py:

      +
      --- __init__.py.org     Sat Jun 21 23:20:41 2003
      ++++ __init__.py Tue Jan  7 23:30:53 2003
      +@@ -84,6 +84,7 @@
      + import asyncore
      + from medusa import resolver, logger
      + from HTTPServer import zhttp_server, zhttp_handler
      ++from HTTPS_Server import zhttps_server, zhttps_handler
      + from PCGIServer import PCGIServer
      + from FCGIServer import FCGIServer
      + from FTPServer import FTPServer
      +
      +
      +
    16. +
    17. Copy $ZSSL/ZServer/medusa/https_server.py to +$ZOPE/ZServer/medusa.

      +
    18. +
    19. Stop Zope, if it is running.

      +
    20. +
    21. Start Zope with ZServerSSL thusly:

      +
      ./starts -X -f 9021 -w 9080 -W 9081 -y 9443 -Y 9444
      +
      +
      +

      This starts the following:

      +
        +
      • an FTP server on port 9021
      • +
      • a HTTP server on port 9080
      • +
      • a WebDAV-source server on port 9081
      • +
      • a HTTPS server on port 9443
      • +
      • a WebDAV-source-over-HTTPS server on port 9444
      • +
      +
    22. +
    +
    +
    +

    1.4.   Testing¶

    +

    Below, we assume your Zope server is running on localhost.

    +
    +
    +

    1.5.   HTTPS¶

    +

    This testing is done with Mozilla 1.1 on FreeBSD.

    +
      +
    1. With a browser, connect to https://localhost:9443/. Browse around. +Check out your browser’s HTTPS informational screens.
    2. +
    3. Connect to https://localhost:9443/manage. Verify that you can access +Zope’s management functionality.
    4. +
    +
    +
    +

    1.6.   WebDAV-over-HTTPS¶

    +

    This testing is done with Cadaver 0.21.0 on FreeBSD.:

    +
    $ cadaver https://localhost:9443/
    +WARNING: Untrusted server certificate presented:
    +Issued to: M2Crypto, SG
    +Issued by: M2Crypto, SG
    +Do you wish to accept the certificate? (y/n) y
    +dav:/> ls
    +Listing collection `/': succeeded.
    +Coll:   Channels                               0  Jun 19 00:04
    +Coll:   Control_Panel                          0  Jun  6 00:13
    +Coll:   Examples                               0  Jun  6 00:12
    +Coll:   catalog                                0  Jun 12 11:53
    +Coll:   ngps                                   0  Jun 16 15:34
    +Coll:   portal                                 0  Jun 21 15:21
    +Coll:   skunk                                  0  Jun 18 21:18
    +Coll:   temp_folder                            0  Jun 22 17:57
    +Coll:   zope                                   0  Jun 20 15:27
    +        acl_users                              0  Dec 30  1998
    +        browser_id_manager                     0  Jun  6 00:12
    +        default.css                         3037  Jun 21 16:38
    +        error_log                              0  Jun  6 00:12
    +        index_html                           313  Jun 12 13:36
    +        portal0                                0  Jun 21 15:21
    +        session_data_manager                   0  Jun  6 00:12
    +        standard_error_message              1365  Jan 21  2001
    +        standard_html_footer                  50  Jun 12 12:30
    +        standard_html_header                  80  Jan 21  2001
    +        standard_template.pt                 282  Jun  6 00:12
    +        zsyncer                                0  Jun 17 15:28
    +dav:/> quit
    +Connection to `localhost' closed.
    +$
    +
    +
    +
    +
    +

    1.7.   WebDAV-Source-over-HTTPS¶

    +

    This testing is done with Mozilla 1.1 on FreeBSD.

    +
      +
    1. Open the Mozilla Composer window.
    2. +
    3. Click “File”, “Open Web Location”. A dialog box appears.
    4. +
    5. Enter https://localhost:9444/index_html for the URL.
    6. +
    7. Select “Open in new Composer window.”
    8. +
    9. Click “Open”. A new Composer window will open with index_html +loaded.
    10. +
    +
    +
    +

    1.8.   Python with M2Crypto¶

    +

    This testing is done with M2Crypto 0.11 and Python 2.2.2 on FreeBSD.

    +
    +
    +

    1.9.   HTTPS¶

    +
    >>> from M2Crypto import Rand, SSL, m2urllib
    +>>> url = m2urllib.FancyURLopener()
    +>>> url.addheader('Connection', 'close')
    +>>> u = url.open('https://127.0.0.1:9443/')
    +send: 'GET / HTTP/1.1\r\nHost: 127.0.0.1:9443\r\nAccept-Encoding: identity\r\nUser-agent: Python-urllib/1.15\r\nConnection: close\r\n\r\n'
    +reply: 'HTTP/1.1 200 OK\r\n'
    +header: Server: ZServerSSL/0.11
    +header: Date: Sun, 22 Jun 2003 13:42:34 GMT
    +header: Connection: close
    +header: Content-Type: text/html
    +header: Etag:
    +header: Content-Length: 535
    +>>> while 1:
    +...     data = u.read()
    +...     if not data: break
    +...     print(data)
    +...
    +
    +
    +
    <html><head>
    +<base href="https://127.0.0.1:9443/" />
    +<title>Zope</title></head><body bgcolor="#FFFFFF">
    +
    +<h1>NgPS Desktop Portal</h1>
    +
    +&nbsp;&nbsp;So many hacks.<br>
    +&nbsp;&nbsp;So little time.<br>
    +
    +<h2>Link Farm</h2>
    +<ul>
    +<li><a href="http://localhost:8080/portal">Portal</a></li>
    +<li><a href="http://localhost/">Local Apache Home Page</a></li>
    +</ul>
    +
    +<hr><a href="http://www.zope.org/Credits" target="_top"><img src="https://127.0.0.1:9443/p_/ZopeButton" width="115" height="50" border="0" alt="Powered by Zope" /></a></body></html>
    +
    +
    +
    >>> u.close()
    +>>>
    +
    +
    +
    +
    +

    1.10.   XMLRPC-over-HTTPS¶

    +
    >>> from M2Crypto.m2xmlrpclib import Server, SSL_Transport
    +>>> zs = Server('https://127.0.0.1:9443/', SSL_Transport())
    +>>> print(zs.propertyMap())
    +[{'type': 'string', 'id': 'title', 'mode': 'w'}]
    +>>>
    +
    +
    +
    +
    +

    1.11.   Conclusion¶

    +

    Well, it works! ;-)

    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/ASN1.html b/doc/html/_modules/M2Crypto/ASN1.html new file mode 100644 index 0000000..bac4c1b --- /dev/null +++ b/doc/html/_modules/M2Crypto/ASN1.html @@ -0,0 +1,357 @@ + + + + + + + + M2Crypto.ASN1 — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.ASN1

    +from __future__ import absolute_import
    +
    +"""
    +M2Crypto wrapper for OpenSSL ASN1 API.
    +
    +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
    +
    +Portions created by Open Source Applications Foundation (OSAF) are
    +Copyright (C) 2005 OSAF. All Rights Reserved.
    +"""
    +
    +import datetime
    +import time
    +
    +from M2Crypto import BIO, m2, py27plus, six
    +if py27plus:
    +    from typing import Any, Callable, Optional, Tuple  # noqa
    +
    +MBSTRING_FLAG = 0x1000
    +MBSTRING_ASC = MBSTRING_FLAG | 1
    +MBSTRING_BMP = MBSTRING_FLAG | 2
    +
    +
    +
    [docs]class ASN1_Integer(object): + + m2_asn1_integer_free = m2.asn1_integer_free + + def __init__(self, asn1int, _pyfree=0): + # type: (ASN1_Integer, int) -> None + self.asn1int = asn1int + self._pyfree = _pyfree + + def __cmp__(self, other): + # type: (ASN1_Integer) -> int + if not isinstance(other, ASN1_Integer): + raise TypeError( + "Comparisons supported only between ANS1_Integer objects") + + return m2.asn1_integer_cmp(self.asn1int, other.asn1int) + + def __del__(self): + # type: () -> None + if self._pyfree: + self.m2_asn1_integer_free(self.asn1int) + + def __int__(self): + # type: () -> int + return m2.asn1_integer_get(self.asn1int)
    + + +
    [docs]class ASN1_String(object): + + m2_asn1_string_free = m2.asn1_string_free + + def __init__(self, asn1str, _pyfree=0): + # type: (ASN1_String, int) -> None + self.asn1str = asn1str + self._pyfree = _pyfree + + def __bytes__(self): + # type: () -> bytes + buf = BIO.MemoryBuffer() + m2.asn1_string_print(buf.bio_ptr(), self.asn1str) + return buf.read_all() + + def __str__(self): + # type: () -> str + return six.ensure_text(self.__bytes__()) + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_asn1_string_free(self.asn1str) + + def _ptr(self): + return self.asn1str + +
    [docs] def as_text(self, flags=0): + # type: (int) -> str + """Output an ASN1_STRING structure according to the set flags. + + :param flags: determine the format of the output by using + predetermined constants, see ASN1_STRING_print_ex(3) + manpage for their meaning. + :return: output an ASN1_STRING structure. + """ + buf = BIO.MemoryBuffer() + m2.asn1_string_print_ex(buf.bio_ptr(), self.asn1str, flags) + return six.ensure_text(buf.read_all())
    + + +
    [docs]class ASN1_Object(object): + + m2_asn1_object_free = m2.asn1_object_free + + def __init__(self, asn1obj, _pyfree=0): + # type: (ASN1_Object, int) -> None + self.asn1obj = asn1obj + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + if self._pyfree: + self.m2_asn1_object_free(self.asn1obj) + + def _ptr(self): + return self.asn1obj
    + + +class _UTC(datetime.tzinfo): + def tzname(self, dt): + # type: (Optional[datetime.datetime]) -> str + return "UTC" + + def dst(self, dt): + # type: (Optional[datetime.datetime]) -> datetime.timedelta + return datetime.timedelta(0) + + def utcoffset(self, dt): + # type: (Optional[datetime.datetime]) -> datetime.timedelta + return datetime.timedelta(0) + + def __repr__(self): + return "<Timezone: %s>" % self.tzname(None) + + +UTC = _UTC() # type: _UTC + + +
    [docs]class LocalTimezone(datetime.tzinfo): + """Localtimezone from datetime manual.""" + + def __init__(self): + # type: () -> None + self._stdoffset = datetime.timedelta(seconds=-time.timezone) + if time.daylight: + self._dstoffset = datetime.timedelta(seconds=-time.altzone) + else: + self._dstoffset = self._stdoffset + self._dstdiff = self._dstoffset - self._stdoffset + +
    [docs] def utcoffset(self, dt): + # type: (datetime.datetime) -> datetime.timedelta + if self._isdst(dt): + return self._dstoffset + else: + return self._stdoffset
    + +
    [docs] def dst(self, dt): + # type: (datetime.datetime) -> datetime.timedelta + if self._isdst(dt): + return self._dstdiff + else: + return datetime.timedelta(0)
    + +
    [docs] def tzname(self, dt): + # type: (datetime.datetime) -> str + return time.tzname[self._isdst(dt).real]
    + + def _isdst(self, dt): + # type: (datetime.datetime) -> bool + tt = (dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, + dt.weekday(), 0, -1) + stamp = time.mktime(tt) + tt = time.localtime(stamp) + return tt.tm_isdst > 0
    + + +
    [docs]class ASN1_TIME(object): + _ssl_months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec"] + m2_asn1_time_free = m2.asn1_time_free + + def __init__(self, asn1_time=None, _pyfree=0, asn1_utctime=None): + # type: (Optional[ASN1_TIME], Optional[int], Optional[ASN1_TIME]) -> None + # handle old keyword parameter + if asn1_time is None: + asn1_time = asn1_utctime + if asn1_time is not None: + assert m2.asn1_time_type_check(asn1_time), \ + "'asn1_time' type error'" + self.asn1_time = asn1_time + self._pyfree = _pyfree + else: + self.asn1_time = m2.asn1_time_new() + self._pyfree = 1 + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_asn1_time_free(self.asn1_time) + + def __str__(self): + # type: () -> str + assert m2.asn1_time_type_check(self.asn1_time), \ + "'asn1_time' type error'" + buf = BIO.MemoryBuffer() + m2.asn1_time_print(buf.bio_ptr(), self.asn1_time) + return six.ensure_text(buf.read_all()) + + def _ptr(self): + assert m2.asn1_time_type_check(self.asn1_time), \ + "'asn1_time' type error'" + return self.asn1_time + +
    [docs] def set_string(self, string): + # type: (bytes) -> int + """Set time from UTC string.""" + assert m2.asn1_time_type_check(self.asn1_time), \ + "'asn1_time' type error'" + return m2.asn1_time_set_string(self.asn1_time, string)
    + +
    [docs] def set_time(self, time): + # type: (int) -> ASN1_TIME + """Set time from seconds since epoch (int).""" + assert m2.asn1_time_type_check(self.asn1_time), \ + "'asn1_time' type error'" + return m2.asn1_time_set(self.asn1_time, time)
    + +
    [docs] def get_datetime(self): + # type: () -> ASN1_TIME + date = str(self) + + timezone = None + if ' ' not in date: + raise ValueError("Invalid date: %s" % date) + month, rest = date.split(' ', 1) + if month not in self._ssl_months: + raise ValueError("Invalid date %s: Invalid month: %s" % + (date, month)) + if rest.endswith(' GMT'): + timezone = UTC + rest = rest[:-4] + if '.' in rest: + dt = datetime.datetime.strptime(rest, "%d %H:%M:%S.%f %Y") + else: + dt = datetime.datetime.strptime(rest, "%d %H:%M:%S %Y") + dt = dt.replace(month=self._ssl_months.index(month) + 1) + if timezone: + dt = dt.replace(tzinfo=UTC) + return dt
    + +
    [docs] def set_datetime(self, date): + # type: (datetime.datetime) -> ASN1_TIME + local = LocalTimezone() + if date.tzinfo is None: + date = date.replace(tzinfo=local) + date = date.astimezone(local) + return self.set_time(int(time.mktime(date.timetuple())))
    + + +ASN1_UTCTIME = ASN1_TIME +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/AuthCookie.html b/doc/html/_modules/M2Crypto/AuthCookie.html new file mode 100644 index 0000000..3b2d629 --- /dev/null +++ b/doc/html/_modules/M2Crypto/AuthCookie.html @@ -0,0 +1,273 @@ + + + + + + + + M2Crypto.AuthCookie — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.AuthCookie

    +from __future__ import absolute_import
    +
    +"""Secure Authenticator Cookies
    +
    +Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved."""
    +
    +import logging
    +import re
    +import time
    +
    +from M2Crypto import Rand, m2, py27plus, six, util
    +from M2Crypto.six.moves.http_cookies import SimpleCookie  # pylint: disable=no-name-in-module,import-error
    +
    +if py27plus:
    +    from typing import re as type_re, AnyStr, Dict, Optional, Union  # noqa
    +
    +_MIX_FORMAT = 'exp=%f&data=%s&digest='
    +_MIX_RE = re.compile(r'exp=(\d+\.\d+)&data=(.+)&digest=(\S*)')
    +
    +log = logging.getLogger(__name__)
    +
    +
    +
    [docs]def mix(expiry, data, format=_MIX_FORMAT): + # type: (float, AnyStr, str) -> AnyStr + return format % (expiry, data)
    + + +
    [docs]def unmix(dough, regex=_MIX_RE): + # type: (AnyStr, type_re) -> object + mo = regex.match(dough) + if mo: + return float(mo.group(1)), mo.group(2) + else: + return None
    + + +
    [docs]def unmix3(dough, regex=_MIX_RE): + # type: (AnyStr, type_re) -> Optional[tuple[float, AnyStr, AnyStr]] + mo = regex.match(dough) + if mo: + return float(mo.group(1)), mo.group(2), mo.group(3) + else: + return None
    + + +_TOKEN = '_M2AUTH_' # type: str + + +
    [docs]class AuthCookieJar(object): + + _keylen = 20 # type: int + + def __init__(self): + # type: () -> None + self._key = Rand.rand_bytes(self._keylen) + + def _hmac(self, key, data): + # type: (bytes, str) -> str + return util.bin_to_hex(m2.hmac(key, six.ensure_binary(data), m2.sha1())) + +
    [docs] def makeCookie(self, expiry, data): + # type: (float, str) -> AuthCookie + """ + Make a cookie + + :param expiry: expiration time (float in seconds) + :param data: cookie content + :return: AuthCookie object + """ + if not isinstance(expiry, (six.integer_types, float)): + raise ValueError('Expiration time must be number, not "%s' % expiry) + dough = mix(expiry, data) + return AuthCookie(expiry, data, dough, self._hmac(self._key, dough))
    + +
    [docs] def isGoodCookie(self, cookie): + # type: (AuthCookie) -> Union[bool, int] + assert isinstance(cookie, AuthCookie) + if cookie.isExpired(): + return 0 + c = self.makeCookie(cookie._expiry, cookie._data) + return (c._expiry == cookie._expiry) \ + and (c._data == cookie._data) \ + and (c._mac == cookie._mac) \ + and (c.output() == cookie.output())
    + +
    [docs] def isGoodCookieString(self, cookie_str, _debug=False): + # type: (Union[dict, bytes], bool) -> Union[bool, int] + c = SimpleCookie() + c.load(cookie_str) + if _TOKEN not in c: + log.debug('_TOKEN not in c (keys = %s)', dir(c)) + return 0 + undough = unmix3(c[_TOKEN].value) + if undough is None: + log.debug('undough is None') + return 0 + exp, data, mac = undough + c2 = self.makeCookie(exp, data) + if _debug and (c2._mac == mac): + log.error('cookie_str = %s', cookie_str) + log.error('c2.isExpired = %s', c2.isExpired()) + log.error('mac = %s', mac) + log.error('c2._mac = %s', c2._mac) + log.error('c2._mac == mac: %s', str(c2._mac == mac)) + return (not c2.isExpired()) and (c2._mac == mac)
    + + +
    [docs]class AuthCookie(object): + + def __init__(self, expiry, data, dough, mac): + # type: (float, str, str, str) -> None + """ + Create new authentication cookie + + :param expiry: expiration time (in seconds) + :param data: cookie payload (as a string) + :param dough: expiry & data concatenated to URL compliant + string + :param mac: SHA1-based HMAC of dough and random key + """ + self._expiry = expiry + self._data = data + self._mac = mac + self._cookie = SimpleCookie() + self._cookie[_TOKEN] = '%s%s' % (dough, mac) + self._name = '%s%s' % (dough, mac) # WebKit only. + +
    [docs] def expiry(self): + # type: () -> float + """Return the cookie's expiry time.""" + return self._expiry
    + +
    [docs] def data(self): + # type: () -> str + """Return the data portion of the cookie.""" + return self._data
    + +
    [docs] def mac(self): + # type: () -> str + """Return the cookie's MAC.""" + return self._mac
    + +
    [docs] def output(self, header="Set-Cookie:"): + # type: (Optional[str]) -> str + """Return the cookie's output in "Set-Cookie" format.""" + return self._cookie.output(header=header)
    + +
    [docs] def value(self): + # type: () -> str + """Return the cookie's output minus the "Set-Cookie: " portion. + """ + return self._cookie[_TOKEN].value
    + +
    [docs] def isExpired(self): + # type: () -> bool + """Return 1 if the cookie has expired, 0 otherwise.""" + return isinstance(self._expiry, (float, six.integer_types)) and \ + (time.time() > self._expiry)
    + + # Following two methods are for WebKit only. + # I may wish to push them to WKAuthCookie, but they are part + # of the API now. Oh well. +
    [docs] def name(self): + # type: () -> str + return self._name
    + +
    [docs] def headerValue(self): + # type: () -> str + return self.value()
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/BIO.html b/doc/html/_modules/M2Crypto/BIO.html new file mode 100644 index 0000000..212c05d --- /dev/null +++ b/doc/html/_modules/M2Crypto/BIO.html @@ -0,0 +1,494 @@ + + + + + + + + M2Crypto.BIO — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.BIO

    +from __future__ import absolute_import
    +
    +"""M2Crypto wrapper for OpenSSL BIO API.
    +
    +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
    +
    +import logging
    +
    +from M2Crypto import m2, py27plus, six
    +if py27plus:
    +    from typing import AnyStr, Callable, Iterable, Optional, Union  # noqa
    +
    +log = logging.getLogger('BIO')
    +
    +
    +
    [docs]class BIOError(ValueError): + pass
    + + +m2.bio_init(BIOError) + + +
    [docs]class BIO(object): + """Abstract object interface to the BIO API.""" + + m2_bio_free = m2.bio_free + + def __init__(self, bio=None, _pyfree=0, _close_cb=None): + # type: (Optional[BIO], int, Optional[Callable]) -> None + self.bio = bio + self._pyfree = _pyfree + self._close_cb = _close_cb + self.closed = 0 + self.write_closed = 0 + + def __del__(self): + if self._pyfree: + self.m2_bio_free(self.bio) + + def _ptr(self): + return self.bio + + # Deprecated. + bio_ptr = _ptr + +
    [docs] def fileno(self): + # type: () -> int + return m2.bio_get_fd(self.bio)
    + +
    [docs] def readable(self): + # type: () -> bool + return not self.closed
    + +
    [docs] def read(self, size=None): + # type: (int) -> Union[bytes, bytearray] + if not self.readable(): + raise IOError('cannot read') + if size is None: + buf = bytearray() + while 1: + data = m2.bio_read(self.bio, 4096) + if not data: + break + buf += data + return buf + elif size == 0: + return b'' + elif size < 0: + raise ValueError('read count is negative') + else: + return bytes(m2.bio_read(self.bio, size))
    + +
    [docs] def readline(self, size=4096): + # type: (int) -> bytes + if not self.readable(): + raise IOError('cannot read') + buf = m2.bio_gets(self.bio, size) + buf = '' if buf is None else buf + return six.ensure_binary(buf)
    + +
    [docs] def readlines(self, sizehint='ignored'): + # type: (Union[AnyStr, int]) -> Iterable[bytes] + if not self.readable(): + raise IOError('cannot read') + lines = [] + while 1: + buf = m2.bio_gets(self.bio, 4096) + if buf is None: + break + lines.append(six.ensure_binary(buf)) + return lines
    + +
    [docs] def writeable(self): + # type: () -> bool + return (not self.closed) and (not self.write_closed)
    + +
    [docs] def write(self, data): + # type: (AnyStr) -> int + """Write data to BIO. + + :return: either data written, or [0, -1] for nothing written, + -2 not implemented + """ + if not self.writeable(): + raise IOError('cannot write') + if isinstance(data, six.text_type): + data = data.encode('utf8') + return m2.bio_write(self.bio, data)
    + +
    [docs] def write_close(self): + # type: () -> None + self.write_closed = 1
    + +
    [docs] def flush(self): + # type: () -> None + """Flush the buffers. + + :return: 1 for success, and 0 or -1 for failure + """ + m2.bio_flush(self.bio)
    + +
    [docs] def reset(self): + # type: () -> int + """Set the bio to its initial state. + + :return: 1 for success, and 0 or -1 for failure + """ + return m2.bio_reset(self.bio)
    + +
    [docs] def close(self): + # type: () -> None + self.closed = 1 + if self._close_cb: + self._close_cb()
    + +
    [docs] def should_retry(self): + # type: () -> int + """ + Can the call be attempted again, or was there an error + ie do_handshake + + """ + return m2.bio_should_retry(self.bio)
    + +
    [docs] def should_read(self): + # type: () -> int + """Should we read more data?""" + + return m2.bio_should_read(self.bio)
    + +
    [docs] def should_write(self): + # type: () -> int + """Should we write more data?""" + return m2.bio_should_write(self.bio)
    + +
    [docs] def tell(self): + """Return the current offset.""" + return m2.bio_tell(self.bio)
    + +
    [docs] def seek(self, off): + """Seek to the specified absolute offset.""" + return m2.bio_seek(self.bio, off)
    + + def __enter__(self): + return self + + def __exit__(self, *args): + # type: (*Any) -> int + self.close()
    + + +
    [docs]class MemoryBuffer(BIO): + """Object interface to BIO_s_mem. + + Empirical testing suggests that this class performs less well than + cStringIO, because cStringIO is implemented in C, whereas this class + is implemented in Python. Thus, the recommended practice is to use + cStringIO for regular work and convert said cStringIO object to + a MemoryBuffer object only when necessary. + """ + + def __init__(self, data=None): + # type: (Optional[bytes]) -> None + super(MemoryBuffer, self).__init__(self) + if data is not None and not isinstance(data, bytes): + raise TypeError( + "data must be bytes or None, not %s" % (type(data).__name__, )) + self.bio = m2.bio_new(m2.bio_s_mem()) + self._pyfree = 1 + if data is not None: + m2.bio_write(self.bio, data) + + def __len__(self): + # type: () -> int + return m2.bio_ctrl_pending(self.bio) + +
    [docs] def read(self, size=0): + # type: (int) -> bytes + if not self.readable(): + raise IOError('cannot read') + if size: + return m2.bio_read(self.bio, size) + else: + return m2.bio_read(self.bio, m2.bio_ctrl_pending(self.bio))
    + + # Backwards-compatibility. + getvalue = read_all = read + +
    [docs] def write_close(self): + # type: () -> None + super(MemoryBuffer, self).write_close() + m2.bio_set_mem_eof_return(self.bio, 0)
    + + close = write_close
    + + +
    [docs]class File(BIO): + """Object interface to BIO_s_pyfd. + + This class interfaces Python to OpenSSL functions that expect BIO. For + general file manipulation in Python, use Python's builtin file object. + """ + + def __init__(self, pyfile, close_pyfile=1, mode='rb'): + # type: (Union[io.BytesIO, AnyStr], int, AnyStr) -> None + super(File, self).__init__(self, _pyfree=1) + + if isinstance(pyfile, six.string_types): + pyfile = open(pyfile, mode) + + # This is for downward compatibility, but I don't think, that it is + # good practice to have two handles for the same file. Whats about + # concurrent write access? Last write, last wins? Especially since Py3 + # has its own buffer management. See: + # + # https://docs.python.org/3.3/c-api/file.html + # + pyfile.flush() + self.fname = pyfile.name + self.pyfile = pyfile + # Be wary of https://github.com/openssl/openssl/pull/1925 + # BIO_new_fd is NEVER to be used before OpenSSL 1.1.1 + if hasattr(m2, "bio_new_pyfd"): + self.bio = m2.bio_new_pyfd(pyfile.fileno(), m2.bio_noclose) + else: + self.bio = m2.bio_new_pyfile(pyfile, m2.bio_noclose) + + self.close_pyfile = close_pyfile + self.closed = False + +
    [docs] def flush(self): + # type: () -> None + super(File, self).flush() + self.pyfile.flush()
    + +
    [docs] def close(self): + # type: () -> None + self.flush() + super(File, self).close() + if self.close_pyfile: + self.pyfile.close()
    + +
    [docs] def reset(self): + # type: () -> int + """Set the bio to its initial state. + + :return: 0 for success, and -1 for failure + """ + return super(File, self).reset()
    + + def __del__(self): + if not self.closed: + m2.bio_free(self.bio)
    + + +
    [docs]def openfile(filename, mode='rb'): + # type: (AnyStr, AnyStr) -> File + try: + f = open(filename, mode) + except IOError as ex: + raise BIOError(ex.args) + + return File(f)
    + + +
    [docs]class IOBuffer(BIO): + """Object interface to BIO_f_buffer. + + Its principal function is to be BIO_push()'ed on top of a BIO_f_ssl, so + that makefile() of said underlying SSL socket works. + """ + + m2_bio_pop = m2.bio_pop + m2_bio_free = m2.bio_free + + def __init__(self, under_bio, mode='rwb', _pyfree=1): + # type: (BIO, str, int) -> None + super(IOBuffer, self).__init__(self, _pyfree=_pyfree) + self.io = m2.bio_new(m2.bio_f_buffer()) + self.bio = m2.bio_push(self.io, under_bio._ptr()) + # This reference keeps the underlying BIO alive while we're not closed. + self._under_bio = under_bio + if 'w' in mode: + self.write_closed = 0 + else: + self.write_closed = 1 + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_bio_pop(self.bio) + self.m2_bio_free(self.io) + +
    [docs] def close(self): + # type: () -> None + BIO.close(self)
    + + +
    [docs]class CipherStream(BIO): + """Object interface to BIO_f_cipher.""" + + SALT_LEN = m2.PKCS5_SALT_LEN + + m2_bio_pop = m2.bio_pop + m2_bio_free = m2.bio_free + + def __init__(self, obio): + # type: (BIO) -> None + super(CipherStream, self).__init__(self, _pyfree=1) + self.obio = obio + self.bio = m2.bio_new(m2.bio_f_cipher()) + self.closed = 0 + + def __del__(self): + # type: () -> None + if not getattr(self, 'closed', 1): + self.close() + +
    [docs] def close(self): + # type: () -> None + self.m2_bio_pop(self.bio) + self.m2_bio_free(self.bio) + self.closed = 1
    + +
    [docs] def write_close(self): + # type: () -> None + self.obio.write_close()
    + +
    [docs] def set_cipher(self, algo, key, iv, op): + # type: (str, AnyStr, AnyStr, int) -> None + cipher = getattr(m2, algo, None) + if cipher is None: + raise ValueError('unknown cipher', algo) + else: + if not isinstance(key, bytes): + key = key.encode('utf8') + if not isinstance(iv, bytes): + iv = iv.encode('utf8') + m2.bio_set_cipher(self.bio, cipher(), key, iv, int(op)) + m2.bio_push(self.bio, self.obio._ptr())
    + + +
    [docs]class SSLBio(BIO): + """Object interface to BIO_f_ssl.""" + + def __init__(self, _pyfree=1): + # type: (int) -> None + super(SSLBio, self).__init__(self, _pyfree=_pyfree) + self.bio = m2.bio_new(m2.bio_f_ssl()) + self.closed = 0 + +
    [docs] def set_ssl(self, conn, close_flag=m2.bio_noclose): + # type: (Connection, int) -> None + """ + Sets the bio to the SSL pointer which is + contained in the connection object. + """ + self._pyfree = 0 + m2.bio_set_ssl(self.bio, conn.ssl, close_flag) + if close_flag == m2.bio_noclose: + conn.set_ssl_close_flag(m2.bio_close)
    + +
    [docs] def do_handshake(self): + # type: () -> int + """Do the handshake. + + Return 1 if the handshake completes + Return 0 or a negative number if there is a problem + """ + return m2.bio_do_handshake(self.bio)
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/BN.html b/doc/html/_modules/M2Crypto/BN.html new file mode 100644 index 0000000..b8287fb --- /dev/null +++ b/doc/html/_modules/M2Crypto/BN.html @@ -0,0 +1,162 @@ + + + + + + + + M2Crypto.BN — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.BN

    +from __future__ import absolute_import
    +
    +"""
    +M2Crypto wrapper for OpenSSL BN (BIGNUM) API.
    +
    +Copyright (c) 2005 Open Source Applications Foundation. All rights reserved.
    +"""
    +
    +from M2Crypto import m2, util
    +if util.py27plus:
    +    from typing import Optional  # noqa
    +
    +
    +
    [docs]def rand(bits, top=-1, bottom=0): + # type: (int, int, int) -> Optional[int] + """ + Generate cryptographically strong random number. + + :param bits: Length of random number in bits. + :param top: If -1, the most significant bit can be 0. If 0, the most + significant bit is 1, and if 1, the two most significant + bits will be 1. + :param bottom: If bottom is true, the number will be odd. + """ + return m2.bn_rand(bits, top, bottom)
    + + +
    [docs]def rand_range(range): + # type: (int) -> int + """ + Generate a random number in a range. + + :param range: Upper limit for range. + :return: A random number in the range [0, range) + """ + return m2.bn_rand_range(range)
    + + +
    [docs]def randfname(length): + # type: (int) -> str + """ + Return a random filename, which is simply a string where all + the characters are from the set [a-zA-Z0-9]. + + :param length: Length of filename to return. + :return: random filename string + """ + import warnings + warnings.warn( + "Don't use BN.randfname(), use tempfile methods instead.", + DeprecationWarning, stacklevel=2) + letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890' + lettersLen = len(letters) + fname = [] # type: list + for x in range(length): + fname += [letters[m2.bn_rand_range(lettersLen)]] + + return ''.join(fname)
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/DH.html b/doc/html/_modules/M2Crypto/DH.html new file mode 100644 index 0000000..0e6d33a --- /dev/null +++ b/doc/html/_modules/M2Crypto/DH.html @@ -0,0 +1,217 @@ + + + + + + + + M2Crypto.DH — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.DH

    +from __future__ import absolute_import
    +
    +"""M2Crypto wrapper for OpenSSL DH API.
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +from M2Crypto import BIO, m2, util
    +from M2Crypto.util import genparam_callback
    +if util.py27plus:
    +    from typing import AnyStr, Callable  # noqa
    +
    +
    +
    [docs]class DHError(Exception): + pass
    + +m2.dh_init(DHError) + + +
    [docs]class DH(object): + """Object interface to the Diffie-Hellman key exchange protocol. + """ + + m2_dh_free = m2.dh_free + + def __init__(self, dh, _pyfree=0): + # type: (bytes, int) -> None + assert m2.dh_type_check(dh) + self.dh = dh + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_dh_free(self.dh) + + def __len__(self): + # type: () -> int + assert m2.dh_type_check(self.dh), "'dh' type error" + return int(m2.dh_size(self.dh)) + + def __getattr__(self, name): + # type: (str) -> bytes + if name in ('p', 'g', 'pub', 'priv'): + method = getattr(m2, 'dh_get_%s' % (name,)) + assert m2.dh_type_check(self.dh), "'dh' type error" + return method(self.dh) + else: + raise AttributeError + + def __setattr__(self, name, value): + # type: (str, bytes) -> bytes + if name in ('p', 'g'): + raise DHError('set (p, g) via set_params()') + elif name in ('pub', 'priv'): + raise DHError('generate (pub, priv) via gen_key()') + else: + self.__dict__[name] = value + + def _ptr(self): + return self.dh + +
    [docs] def check_params(self): + # type: () -> int + assert m2.dh_type_check(self.dh), "'dh' type error" + return m2.dh_check(self.dh)
    + +
    [docs] def gen_key(self): + # type: () -> None + assert m2.dh_type_check(self.dh), "'dh' type error" + m2.dh_generate_key(self.dh)
    + +
    [docs] def compute_key(self, pubkey): + # type: (bytes) -> bytes + assert m2.dh_type_check(self.dh), "'dh' type error" + return m2.dh_compute_key(self.dh, pubkey)
    + +
    [docs] def print_params(self, bio): + # type: (BIO.BIO) -> int + assert m2.dh_type_check(self.dh), "'dh' type error" + return m2.dhparams_print(bio._ptr(), self.dh)
    + + +
    [docs]def gen_params(plen, g, callback=genparam_callback): + # type: (int, int, Optional[Callable]) -> DH + dh_parms = m2.dh_generate_parameters(plen, g, callback) + dh_obj = DH(dh_parms, 1) + return dh_obj
    + + +
    [docs]def load_params(file): + # type: (AnyStr) -> DH + with BIO.openfile(file) as bio: + return load_params_bio(bio)
    + + +
    [docs]def load_params_bio(bio): + # type: (BIO.BIO) -> DH + return DH(m2.dh_read_parameters(bio._ptr()), 1)
    + + +
    [docs]def set_params(p, g): + # type: (bytes, bytes) -> DH + dh = m2.dh_new() + m2.dh_set_pg(dh, p, g) + return DH(dh, 1)
    + + +# def free_params(cptr): +# m2.dh_free(cptr) + + +DH_GENERATOR_2 = m2.DH_GENERATOR_2 +DH_GENERATOR_5 = m2.DH_GENERATOR_5 +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/DSA.html b/doc/html/_modules/M2Crypto/DSA.html new file mode 100644 index 0000000..6d97c52 --- /dev/null +++ b/doc/html/_modules/M2Crypto/DSA.html @@ -0,0 +1,552 @@ + + + + + + + + M2Crypto.DSA — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.DSA

    +from __future__ import absolute_import, print_function
    +
    +"""
    +    M2Crypto wrapper for OpenSSL DSA API.
    +
    +    Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.
    +
    +    Portions created by Open Source Applications Foundation (OSAF) are
    +    Copyright (C) 2004 OSAF. All Rights Reserved.
    +"""
    +
    +from M2Crypto import BIO, m2, util
    +if util.py27plus:
    +    from typing import AnyStr, Callable, Tuple  # noqa
    +
    +
    +
    [docs]class DSAError(Exception): + pass
    + +m2.dsa_init(DSAError) + + +
    [docs]class DSA(object): + + """ + This class is a context supporting DSA key and parameter + values, signing and verifying. + + Simple example:: + + from M2Crypto import EVP, DSA, util + + message = 'Kilroy was here!' + md = EVP.MessageDigest('sha1') + md.update(message) + digest = md.final() + + dsa = DSA.gen_params(1024) + dsa.gen_key() + r, s = dsa.sign(digest) + good = dsa.verify(digest, r, s) + if good: + print(' ** success **') + else: + print(' ** verification failed **') + """ + + m2_dsa_free = m2.dsa_free + + def __init__(self, dsa, _pyfree=0): + # type: (bytes, int) -> None + """ + Use one of the factory functions to create an instance. + :param dsa: binary representation of OpenSSL DSA type + """ + assert m2.dsa_type_check(dsa), "'dsa' type error" + self.dsa = dsa + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_dsa_free(self.dsa) + + def __len__(self): + # type: () -> int + """ + Return the key length. + + :return: the DSA key length in bits + """ + assert m2.dsa_type_check(self.dsa), "'dsa' type error" + return m2.dsa_keylen(self.dsa) + + def __getattr__(self, name): + # type: (str) -> bytes + """ + Return specified DSA parameters and key values. + + :param name: name of variable to be returned. Must be + one of 'p', 'q', 'g', 'pub', 'priv'. + :return: value of specified variable (a "byte string") + """ + if name in ['p', 'q', 'g', 'pub', 'priv']: + method = getattr(m2, 'dsa_get_%s' % (name,)) + assert m2.dsa_type_check(self.dsa), "'dsa' type error" + return method(self.dsa) + else: + raise AttributeError + + def __setattr__(self, name, value): + # type: (str, bytes) -> None + if name in ['p', 'q', 'g']: + raise DSAError('set (p, q, g) via set_params()') + elif name in ['pub', 'priv']: + raise DSAError('generate (pub, priv) via gen_key()') + else: + self.__dict__[name] = value + +
    [docs] def set_params(self, p, q, g): + # type: (bytes, bytes, bytes) -> None + """ + Set new parameters. + + :param p: MPI binary representation ... format that consists of + the number's length in bytes represented as a 4-byte + big-endian number, and the number itself in big-endian + format, where the most significant bit signals + a negative number (the representation of numbers with + the MSB set is prefixed with null byte). + :param q: ditto + :param g: ditto + + @warning: This does not change the private key, so it may be + unsafe to use this method. It is better to use + gen_params function to create a new DSA object. + """ + m2.dsa_set_pqg(self.dsa, p, q, g)
    + +
    [docs] def gen_key(self): + # type: () -> None + """ + Generate a key pair. + """ + assert m2.dsa_type_check(self.dsa), "'dsa' type error" + m2.dsa_gen_key(self.dsa)
    + +
    [docs] def save_params(self, filename): + # type: (AnyStr) -> int + """ + Save the DSA parameters to a file. + + :param filename: Save the DSA parameters to this file. + :return: 1 (true) if successful + """ + with BIO.openfile(filename, 'wb') as bio: + ret = m2.dsa_write_params_bio(self.dsa, bio._ptr()) + + return ret
    + +
    [docs] def save_params_bio(self, bio): + # type: (BIO.BIO) -> int + """ + Save DSA parameters to a BIO object. + + :param bio: Save DSA parameters to this object. + :return: 1 (true) if successful + """ + return m2.dsa_write_params_bio(self.dsa, bio._ptr())
    + +
    [docs] def save_key(self, filename, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (AnyStr, str, Callable) -> int + """ + Save the DSA key pair to a file. + + :param filename: Save the DSA key pair to this file. + :param cipher: name of symmetric key algorithm and mode + to encrypt the private key. + :return: 1 (true) if successful + """ + with BIO.openfile(filename, 'wb') as bio: + ret = self.save_key_bio(bio, cipher, callback) + + return ret
    + +
    [docs] def save_key_bio(self, bio, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (BIO.BIO, str, Callable) -> int + """ + Save DSA key pair to a BIO object. + + :param bio: Save DSA parameters to this object. + :param cipher: name of symmetric key algorithm and mode + to encrypt the private key. + :return: 1 (true) if successful + """ + if cipher is None: + return m2.dsa_write_key_bio_no_cipher(self.dsa, + bio._ptr(), callback) + else: + ciph = getattr(m2, cipher, None) + if ciph is None: + raise DSAError('no such cipher: %s' % cipher) + else: + ciph = ciph() + return m2.dsa_write_key_bio(self.dsa, bio._ptr(), ciph, callback)
    + +
    [docs] def save_pub_key(self, filename): + # type: (AnyStr) -> int + """ + Save the DSA public key (with parameters) to a file. + + :param filename: Save DSA public key (with parameters) + to this file. + :return: 1 (true) if successful + """ + with BIO.openfile(filename, 'wb') as bio: + ret = self.save_pub_key_bio(bio) + + return ret
    + +
    [docs] def save_pub_key_bio(self, bio): + # type: (BIO.BIO) -> int + """ + Save DSA public key (with parameters) to a BIO object. + + :param bio: Save DSA public key (with parameters) + to this object. + :return: 1 (true) if successful + """ + return m2.dsa_write_pub_key_bio(self.dsa, bio._ptr())
    + +
    [docs] def sign(self, digest): + # type: (bytes) -> Tuple[bytes, bytes] + """ + Sign the digest. + + :param digest: SHA-1 hash of message (same as output + from MessageDigest, a "byte string") + :return: DSA signature, a tuple of two values, r and s, + both "byte strings". + """ + assert self.check_key(), 'key is not initialised' + return m2.dsa_sign(self.dsa, digest)
    + +
    [docs] def verify(self, digest, r, s): + # type: (bytes, bytes, bytes) -> int + """ + Verify a newly calculated digest against the signature + values r and s. + + :param digest: SHA-1 hash of message (same as output + from MessageDigest, a "byte string") + :param r: r value of the signature, a "byte string" + :param s: s value of the signature, a "byte string" + :return: 1 (true) if verify succeeded, 0 if failed + """ + assert self.check_key(), 'key is not initialised' + return m2.dsa_verify(self.dsa, digest, r, s)
    + +
    [docs] def sign_asn1(self, digest): + assert self.check_key(), 'key is not initialised' + return m2.dsa_sign_asn1(self.dsa, digest)
    + +
    [docs] def verify_asn1(self, digest, blob): + assert self.check_key(), 'key is not initialised' + return m2.dsa_verify_asn1(self.dsa, digest, blob)
    + +
    [docs] def check_key(self): + """ + Check to be sure the DSA object has a valid private key. + + :return: 1 (true) if a valid private key + """ + assert m2.dsa_type_check(self.dsa), "'dsa' type error" + return m2.dsa_check_key(self.dsa)
    + + +
    [docs]class DSA_pub(DSA): + + """ + This class is a DSA context that only supports a public key + and verification. It does NOT support a private key or + signing. + + """ + +
    [docs] def sign(self, *argv): + # type: (*Any) -> None + raise DSAError('DSA_pub object has no private key')
    + + sign_asn1 = sign + +
    [docs] def check_key(self): + # type: () -> int + """ + :return: does DSA_pub contain a pub key? + """ + return m2.dsa_check_pub_key(self.dsa)
    + + save_key = DSA.save_pub_key + + save_key_bio = DSA.save_pub_key_bio
    + +# -------------------------------------------------------------- +# factories and other functions + + +
    [docs]def gen_params(bits, callback=util.genparam_callback): + # type: (int, Callable) -> DSA + """ + Factory function that generates DSA parameters and + instantiates a DSA object from the output. + + :param bits: The length of the prime to be generated. If + 'bits' < 512, it is set to 512. + :param callback: A Python callback object that will be + invoked during parameter generation; it usual + purpose is to provide visual feedback. + :return: instance of DSA. + """ + dsa = m2.dsa_generate_parameters(bits, callback) + return DSA(dsa, 1)
    + + +
    [docs]def set_params(p, q, g): + # type: (bytes, bytes, bytes) -> DSA + """ + Factory function that instantiates a DSA object with DSA + parameters. + + :param p: value of p, a "byte string" + :param q: value of q, a "byte string" + :param g: value of g, a "byte string" + :return: instance of DSA. + """ + dsa = m2.dsa_new() + m2.dsa_set_pqg(dsa, p, q, g) + return DSA(dsa, 1)
    + + +
    [docs]def load_params(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> DSA + """ + Factory function that instantiates a DSA object with DSA + parameters from a file. + + :param file: Names the file (a path) that contains the PEM + representation of the DSA parameters. + :param callback: A Python callback object that will be + invoked if the DSA parameters file is + passphrase-protected. + :return: instance of DSA. + """ + with BIO.openfile(file) as bio: + ret = load_params_bio(bio, callback) + + return ret
    + + +
    [docs]def load_params_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> DSA + """ + Factory function that instantiates a DSA object with DSA + parameters from a M2Crypto.BIO object. + + :param bio: Contains the PEM representation of the DSA + parameters. + :param callback: A Python callback object that will be + invoked if the DSA parameters file is + passphrase-protected. + :return: instance of DSA. + """ + dsa = m2.dsa_read_params(bio._ptr(), callback) + return DSA(dsa, 1)
    + + +
    [docs]def load_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> DSA + """ + Factory function that instantiates a DSA object from a + PEM encoded DSA key pair. + + :param file: Names the file (a path) that contains the PEM + representation of the DSA key pair. + :param callback: A Python callback object that will be + invoked if the DSA key pair is + passphrase-protected. + :return: instance of DSA. + """ + with BIO.openfile(file) as bio: + ret = load_key_bio(bio, callback) + + return ret
    + + +
    [docs]def load_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> DSA + """ + Factory function that instantiates a DSA object from a + PEM encoded DSA key pair. + + :param bio: Contains the PEM representation of the DSA + key pair. + :param callback: A Python callback object that will be + invoked if the DSA key pair is + passphrase-protected. + :return: instance of DSA. + """ + dsa = m2.dsa_read_key(bio._ptr(), callback) + return DSA(dsa, 1)
    + + +
    [docs]def pub_key_from_params(p, q, g, pub): + # type: (bytes, bytes, bytes, bytes) -> DSA_pub + """ + Factory function that instantiates a DSA_pub object using + the parameters and public key specified. + + :param p: value of p + :param q: value of q + :param g: value of g + :param pub: value of the public key + :return: instance of DSA_pub. + """ + dsa = m2.dsa_new() + m2.dsa_set_pqg(dsa, p, q, g) + m2.dsa_set_pub(dsa, pub) + return DSA_pub(dsa, 1)
    + + +
    [docs]def load_pub_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> DSA_pub + """ + Factory function that instantiates a DSA_pub object using + a DSA public key contained in PEM file. The PEM file + must contain the parameters in addition to the public key. + + :param file: Names the file (a path) that contains the PEM + representation of the DSA public key. + :param callback: A Python callback object that will be + invoked should the DSA public key be + passphrase-protected. + :return: instance of DSA_pub. + """ + with BIO.openfile(file) as bio: + ret = load_pub_key_bio(bio, callback) + + return ret
    + + +
    [docs]def load_pub_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> DSA_pub + """ + Factory function that instantiates a DSA_pub object using + a DSA public key contained in PEM format. The PEM + must contain the parameters in addition to the public key. + + :param bio: Contains the PEM representation of the DSA + public key (with params). + :param callback: A Python callback object that will be + invoked should the DSA public key be + passphrase-protected. + :return: instance of DSA_pub. + """ + dsapub = m2.dsa_read_pub_key(bio._ptr(), callback) + return DSA_pub(dsapub, 1)
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/EC.html b/doc/html/_modules/M2Crypto/EC.html new file mode 100644 index 0000000..8b62996 --- /dev/null +++ b/doc/html/_modules/M2Crypto/EC.html @@ -0,0 +1,563 @@ + + + + + + + + M2Crypto.EC — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.EC

    +from __future__ import absolute_import
    +
    +"""
    +M2Crypto wrapper for OpenSSL ECDH/ECDSA API.
    +
    +@requires: OpenSSL 0.9.8 or newer
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.
    +
    +Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam.
    +All rights reserved."""
    +
    +from M2Crypto import BIO, Err, EVP, m2, util
    +if util.py27plus:
    +    from typing import AnyStr, Callable, Dict, Optional, Tuple, Union  # noqa
    +
    +EC_Key = bytes
    +
    +
    +
    [docs]class ECError(Exception): + pass
    + +m2.ec_init(ECError) + +# Curve identifier constants +NID_secp112r1 = m2.NID_secp112r1 # type: int +NID_secp112r2 = m2.NID_secp112r2 # type: int +NID_secp128r1 = m2.NID_secp128r1 # type: int +NID_secp128r2 = m2.NID_secp128r2 # type: int +NID_secp160k1 = m2.NID_secp160k1 # type: int +NID_secp160r1 = m2.NID_secp160r1 # type: int +NID_secp160r2 = m2.NID_secp160r2 # type: int +NID_secp192k1 = m2.NID_secp192k1 # type: int +NID_secp224k1 = m2.NID_secp224k1 # type: int +NID_secp224r1 = m2.NID_secp224r1 # type: int +NID_secp256k1 = m2.NID_secp256k1 # type: int +NID_secp384r1 = m2.NID_secp384r1 # type: int +NID_secp521r1 = m2.NID_secp521r1 # type: int +NID_sect113r1 = m2.NID_sect113r1 # type: int +NID_sect113r2 = m2.NID_sect113r2 # type: int +NID_sect131r1 = m2.NID_sect131r1 # type: int +NID_sect131r2 = m2.NID_sect131r2 # type: int +NID_sect163k1 = m2.NID_sect163k1 # type: int +NID_sect163r1 = m2.NID_sect163r1 # type: int +NID_sect163r2 = m2.NID_sect163r2 # type: int +NID_sect193r1 = m2.NID_sect193r1 # type: int +NID_sect193r2 = m2.NID_sect193r2 # type: int +# default for secg.org TLS test server +NID_sect233k1 = m2.NID_sect233k1 # type: int +NID_sect233r1 = m2.NID_sect233r1 # type: int +NID_sect239k1 = m2.NID_sect239k1 # type: int +NID_sect283k1 = m2.NID_sect283k1 # type: int +NID_sect283r1 = m2.NID_sect283r1 # type: int +NID_sect409k1 = m2.NID_sect409k1 # type: int +NID_sect409r1 = m2.NID_sect409r1 # type: int +NID_sect571k1 = m2.NID_sect571k1 # type: int +NID_sect571r1 = m2.NID_sect571r1 # type: int + +NID_prime192v1 = m2.NID_X9_62_prime192v1 # type: int +NID_prime192v2 = m2.NID_X9_62_prime192v2 # type: int +NID_prime192v3 = m2.NID_X9_62_prime192v3 # type: int +NID_prime239v1 = m2.NID_X9_62_prime239v1 # type: int +NID_prime239v2 = m2.NID_X9_62_prime239v2 # type: int +NID_prime239v3 = m2.NID_X9_62_prime239v3 # type: int +NID_prime256v1 = m2.NID_X9_62_prime256v1 # type: int +NID_c2pnb163v1 = m2.NID_X9_62_c2pnb163v1 # type: int +NID_c2pnb163v2 = m2.NID_X9_62_c2pnb163v2 # type: int +NID_c2pnb163v3 = m2.NID_X9_62_c2pnb163v3 # type: int +NID_c2pnb176v1 = m2.NID_X9_62_c2pnb176v1 # type: int +NID_c2tnb191v1 = m2.NID_X9_62_c2tnb191v1 # type: int +NID_c2tnb191v2 = m2.NID_X9_62_c2tnb191v2 # type: int +NID_c2tnb191v3 = m2.NID_X9_62_c2tnb191v3 # type: int +NID_c2pnb208w1 = m2.NID_X9_62_c2pnb208w1 # type: int +NID_c2tnb239v1 = m2.NID_X9_62_c2tnb239v1 # type: int +NID_c2tnb239v2 = m2.NID_X9_62_c2tnb239v2 # type: int +NID_c2tnb239v3 = m2.NID_X9_62_c2tnb239v3 # type: int +NID_c2pnb272w1 = m2.NID_X9_62_c2pnb272w1 # type: int +NID_c2pnb304w1 = m2.NID_X9_62_c2pnb304w1 # type: int +NID_c2tnb359v1 = m2.NID_X9_62_c2tnb359v1 # type: int +NID_c2pnb368w1 = m2.NID_X9_62_c2pnb368w1 # type: int +NID_c2tnb431r1 = m2.NID_X9_62_c2tnb431r1 # type: int + +# To preserve compatibility with older names +NID_X9_62_prime192v1 = NID_prime192v1 # type: int +NID_X9_62_prime192v2 = NID_prime192v2 # type: int +NID_X9_62_prime192v3 = NID_prime192v3 # type: int +NID_X9_62_prime239v1 = NID_prime239v1 # type: int +NID_X9_62_prime239v2 = NID_prime239v2 # type: int +NID_X9_62_prime239v3 = NID_prime239v3 # type: int +NID_X9_62_prime256v1 = NID_prime256v1 # type: int +NID_X9_62_c2pnb163v1 = NID_c2pnb163v1 # type: int +NID_X9_62_c2pnb163v2 = NID_c2pnb163v2 # type: int +NID_X9_62_c2pnb163v3 = NID_c2pnb163v3 # type: int +NID_X9_62_c2pnb176v1 = NID_c2pnb176v1 # type: int +NID_X9_62_c2tnb191v1 = NID_c2tnb191v1 # type: int +NID_X9_62_c2tnb191v2 = NID_c2tnb191v2 # type: int +NID_X9_62_c2tnb191v3 = NID_c2tnb191v3 # type: int +NID_X9_62_c2pnb208w1 = NID_c2pnb208w1 # type: int +NID_X9_62_c2tnb239v1 = NID_c2tnb239v1 # type: int +NID_X9_62_c2tnb239v2 = NID_c2tnb239v2 # type: int +NID_X9_62_c2tnb239v3 = NID_c2tnb239v3 # type: int +NID_X9_62_c2pnb272w1 = NID_c2pnb272w1 # type: int +NID_X9_62_c2pnb304w1 = NID_c2pnb304w1 # type: int +NID_X9_62_c2tnb359v1 = NID_c2tnb359v1 # type: int +NID_X9_62_c2pnb368w1 = NID_c2pnb368w1 # type: int +NID_X9_62_c2tnb431r1 = NID_c2tnb431r1 # type: int + +NID_wap_wsg_idm_ecid_wtls1 = m2.NID_wap_wsg_idm_ecid_wtls1 # type: int +NID_wap_wsg_idm_ecid_wtls3 = m2.NID_wap_wsg_idm_ecid_wtls3 # type: int +NID_wap_wsg_idm_ecid_wtls4 = m2.NID_wap_wsg_idm_ecid_wtls4 # type: int +NID_wap_wsg_idm_ecid_wtls5 = m2.NID_wap_wsg_idm_ecid_wtls5 # type: int +NID_wap_wsg_idm_ecid_wtls6 = m2.NID_wap_wsg_idm_ecid_wtls6 # type: int +NID_wap_wsg_idm_ecid_wtls7 = m2.NID_wap_wsg_idm_ecid_wtls7 # type: int +NID_wap_wsg_idm_ecid_wtls8 = m2.NID_wap_wsg_idm_ecid_wtls8 # type: int +NID_wap_wsg_idm_ecid_wtls9 = m2.NID_wap_wsg_idm_ecid_wtls9 # type: int +NID_wap_wsg_idm_ecid_wtls10 = m2.NID_wap_wsg_idm_ecid_wtls10 # type: int +NID_wap_wsg_idm_ecid_wtls11 = m2.NID_wap_wsg_idm_ecid_wtls11 # type: int +NID_wap_wsg_idm_ecid_wtls12 = m2.NID_wap_wsg_idm_ecid_wtls12 # type: int + +# The following two curves, according to OpenSSL, have a +# "Questionable extension field!" and are not supported by +# the OpenSSL inverse function. ECError: no inverse. +# As such they cannot be used for signing. They might, +# however, be usable for encryption but that has not +# been tested. Until thir usefulness can be established, +# they are not supported at this time. +# NID_ipsec3 = m2.NID_ipsec3 +# NID_ipsec4 = m2.NID_ipsec4 + + +
    [docs]class EC(object): + + """ + Object interface to a EC key pair. + """ + + m2_ec_key_free = m2.ec_key_free + + def __init__(self, ec, _pyfree=0): + # type: (EC, int) -> None + assert m2.ec_key_type_check(ec), "'ec' type error" + self.ec = ec + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_ec_key_free(self.ec) + + def __len__(self): + # type: () -> int + assert m2.ec_key_type_check(self.ec), "'ec' type error" + return m2.ec_key_keylen(self.ec) + +
    [docs] def gen_key(self): + # type: () -> int + """ + Generates the key pair from its parameters. Use:: + + keypair = EC.gen_params(curve) + keypair.gen_key() + + to create an EC key pair. + """ + assert m2.ec_key_type_check(self.ec), "'ec' type error" + m2.ec_key_gen_key(self.ec)
    + +
    [docs] def pub(self): + # type: () -> EC_pub + # Don't let python free + return EC_pub(self.ec, 0)
    + +
    [docs] def sign_dsa(self, digest): + # type: (bytes) -> Tuple[bytes, bytes] + """ + Sign the given digest using ECDSA. Returns a tuple (r,s), the two + ECDSA signature parameters. + """ + assert self._check_key_type(), "'ec' type error" + return m2.ecdsa_sign(self.ec, digest)
    + +
    [docs] def verify_dsa(self, digest, r, s): + # type: (bytes, bytes, bytes) -> int + """ + Verify the given digest using ECDSA. r and s are the ECDSA + signature parameters. + """ + assert self._check_key_type(), "'ec' type error" + return m2.ecdsa_verify(self.ec, digest, r, s)
    + +
    [docs] def sign_dsa_asn1(self, digest): + # type: (bytes) -> bytes + assert self._check_key_type(), "'ec' type error" + return m2.ecdsa_sign_asn1(self.ec, digest)
    + +
    [docs] def verify_dsa_asn1(self, digest, blob): + assert self._check_key_type(), "'ec' type error" + return m2.ecdsa_verify_asn1(self.ec, digest, blob)
    + +
    [docs] def compute_dh_key(self, pub_key): + # type: (EC) -> Optional[bytes] + """ + Compute the ECDH shared key of this key pair and the given public + key object. They must both use the same curve. Returns the + shared key in binary as a buffer object. No Key Derivation Function is + applied. + """ + assert self.check_key(), 'key is not initialised' + return m2.ecdh_compute_key(self.ec, pub_key.ec)
    + +
    [docs] def save_key_bio(self, bio, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (BIO.BIO, Optional[str], Callable) -> int + """ + Save the key pair to an M2Crypto.BIO.BIO object in PEM format. + + :param bio: M2Crypto.BIO.BIO object to save key to. + + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. + """ + if cipher is None: + return m2.ec_key_write_bio_no_cipher(self.ec, bio._ptr(), callback) + else: + ciph = getattr(m2, cipher, None) + if ciph is None: + raise ValueError('not such cipher %s' % cipher) + return m2.ec_key_write_bio(self.ec, bio._ptr(), ciph(), callback)
    + +
    [docs] def save_key(self, file, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (AnyStr, Optional[str], Callable) -> int + """ + Save the key pair to a file in PEM format. + + :param file: Name of filename to save key to. + + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. + """ + with BIO.openfile(file, 'wb') as bio: + return self.save_key_bio(bio, cipher, callback)
    + +
    [docs] def save_pub_key_bio(self, bio): + # type: (BIO.BIO) -> int + """ + Save the public key to an M2Crypto.BIO.BIO object in PEM format. + + :param bio: M2Crypto.BIO.BIO object to save key to. + """ + return m2.ec_key_write_pubkey(self.ec, bio._ptr())
    + +
    [docs] def save_pub_key(self, file): + # type: (AnyStr) -> int + """ + Save the public key to a filename in PEM format. + + :param file: Name of filename to save key to. + """ + with BIO.openfile(file, 'wb') as bio: + return m2.ec_key_write_pubkey(self.ec, bio._ptr())
    + +
    [docs] def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback): + """ + Returns the key(pair) as a string in PEM format. + If no password is passed and the cipher is set + it exits with error + """ + with BIO.MemoryBuffer() as bio: + self.save_key_bio(bio, cipher, callback) + return bio.read()
    + + def _check_key_type(self): + # type: () -> int + return m2.ec_key_type_check(self.ec) + +
    [docs] def check_key(self): + # type: () -> int + assert m2.ec_key_type_check(self.ec), "'ec' type error" + return m2.ec_key_check_key(self.ec)
    + + +
    [docs]class EC_pub(EC): + + """ + Object interface to an EC public key. + ((don't like this implementation inheritance)) + """ + def __init__(self, ec, _pyfree=0): + # type: (EC, int) -> None + EC.__init__(self, ec, _pyfree) + self.der = None # type: Optional[bytes] + +
    [docs] def get_der(self): + # type: () -> bytes + """ + Returns the public key in DER format as a buffer object. + """ + assert self.check_key(), 'key is not initialised' + if self.der is None: + self.der = m2.ec_key_get_public_der(self.ec) + return self.der
    + +
    [docs] def get_key(self): + # type: () -> bytes + """ + Returns the public key as a byte string. + """ + assert self.check_key(), 'key is not initialised' + return m2.ec_key_get_public_key(self.ec)
    + + save_key = EC.save_pub_key + + save_key_bio = EC.save_pub_key_bio
    + + +
    [docs]def gen_params(curve): + # type: (int) -> EC + """ + Factory function that generates EC parameters and + instantiates a EC object from the output. + + :param curve: This is the OpenSSL nid of the curve to use. + """ + assert curve in [x['NID'] for x in m2.ec_get_builtin_curves()], \ + 'Elliptic curve %s is not available on this system.' % \ + m2.obj_nid2sn(curve) + return EC(m2.ec_key_new_by_curve_name(curve), 1)
    + + +
    [docs]def load_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> EC + """ + Factory function that instantiates a EC object. + + :param file: Names the filename that contains the PEM representation + of the EC key pair. + + :param callback: Python callback object that will be invoked + if the EC key pair is passphrase-protected. + """ + with BIO.openfile(file) as bio: + return load_key_bio(bio, callback)
    + + +
    [docs]def load_key_string(string, callback=util.passphrase_callback): + # type: (str, Callable) -> EC + """ + Load an EC key pair from a string. + + :param string: String containing EC key pair in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to unlock the + key. The default is util.passphrase_callback. + + :return: M2Crypto.EC.EC object. + """ + with BIO.MemoryBuffer(string) as bio: + return load_key_bio(bio, callback)
    + + +
    [docs]def load_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> EC + """ + Factory function that instantiates a EC object. + + :param bio: M2Crypto.BIO object that contains the PEM + representation of the EC key pair. + + :param callback: Python callback object that will be invoked + if the EC key pair is passphrase-protected. + """ + return EC(m2.ec_key_read_bio(bio._ptr(), callback), 1)
    + + +
    [docs]def load_pub_key(file): + # type: (AnyStr) -> EC_pub + """ + Load an EC public key from filename. + + :param file: Name of filename containing EC public key in PEM + format. + + :return: M2Crypto.EC.EC_pub object. + """ + with BIO.openfile(file) as bio: + return load_pub_key_bio(bio)
    + + +
    [docs]def load_key_string_pubkey(string, callback=util.passphrase_callback): + # type: (str, Callable) -> PKey + """ + Load an M2Crypto.EC.PKey from a public key as a string. + + :param string: String containing the key in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. + + :return: M2Crypto.EC.PKey object. + """ + with BIO.MemoryBuffer(string) as bio: + return EVP.load_key_bio_pubkey(bio, callback)
    + + +
    [docs]def load_pub_key_bio(bio): + # type: (BIO.BIO) -> EC_pub + """ + Load an EC public key from an M2Crypto.BIO.BIO object. + + :param bio: M2Crypto.BIO.BIO object containing EC public key in PEM + format. + + :return: M2Crypto.EC.EC_pub object. + """ + ec = m2.ec_key_read_pubkey(bio._ptr()) + if ec is None: + ec_error() + return EC_pub(ec, 1)
    + + +
    [docs]def ec_error(): + # type: () -> ECError + raise ECError(Err.get_error_message())
    + + +
    [docs]def pub_key_from_der(der): + # type: (bytes) -> EC_pub + """ + Create EC_pub from DER. + """ + return EC_pub(m2.ec_key_from_pubkey_der(der), 1)
    + + +
    [docs]def pub_key_from_params(curve, bytes): + # type: (bytes, bytes) -> EC_pub + """ + Create EC_pub from curve name and octet string. + """ + return EC_pub(m2.ec_key_from_pubkey_params(curve, bytes), 1)
    + + +
    [docs]def get_builtin_curves(): + # type: () -> Tuple[Dict[str, Union[int, str]]] + return m2.ec_get_builtin_curves()
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/EVP.html b/doc/html/_modules/M2Crypto/EVP.html new file mode 100644 index 0000000..4aebc66 --- /dev/null +++ b/doc/html/_modules/M2Crypto/EVP.html @@ -0,0 +1,571 @@ + + + + + + + + M2Crypto.EVP — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.EVP

    +from __future__ import absolute_import
    +
    +"""M2Crypto wrapper for OpenSSL EVP API.
    +
    +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
    +
    +Portions Copyright (c) 2004-2007 Open Source Applications Foundation.
    +Author: Heikki Toivonen
    +"""
    +
    +import logging
    +from M2Crypto import BIO, Err, RSA, m2, util
    +if util.py27plus:
    +    from typing import AnyStr, Optional, Callable  # noqa
    +
    +log = logging.getLogger('EVP')
    +
    +
    [docs]class EVPError(ValueError): + pass
    + +m2.evp_init(EVPError) + + +
    [docs]def pbkdf2(password, salt, iter, keylen): + # type: (bytes, bytes, int, int) -> bytes + """ + Derive a key from password using PBKDF2 algorithm specified in RFC 2898. + + :param password: Derive the key from this password. + :param salt: Salt. + :param iter: Number of iterations to perform. + :param keylen: Length of key to produce. + :return: Key. + """ + return m2.pkcs5_pbkdf2_hmac_sha1(password, salt, iter, keylen)
    + + +
    [docs]class MessageDigest(object): + """ + Message Digest + """ + m2_md_ctx_free = m2.md_ctx_free + + def __init__(self, algo): + # type: (str) -> None + md = getattr(m2, algo, None) # type: Optional[Callable] + if md is None: + # if the digest algorithm isn't found as an attribute of the m2 + # module, try to look up the digest using get_digestbyname() + self.md = m2.get_digestbyname(algo) + else: + self.md = md() + self.ctx = m2.md_ctx_new() + m2.digest_init(self.ctx, self.md) + + def __del__(self): + # type: () -> None + if getattr(self, 'ctx', None): + self.m2_md_ctx_free(self.ctx) + +
    [docs] def update(self, data): + # type: (bytes) -> int + """ + Add data to be digested. + + :return: -1 for Python error, 1 for success, 0 for OpenSSL failure. + """ + return m2.digest_update(self.ctx, data)
    + +
    [docs] def final(self): + return m2.digest_final(self.ctx)
    + + # Deprecated. + digest = final
    + + +
    [docs]class HMAC(object): + + m2_hmac_ctx_free = m2.hmac_ctx_free + + def __init__(self, key, algo='sha1'): + # type: (bytes, str) -> None + md = getattr(m2, algo, None) + if md is None: + raise ValueError('unknown algorithm', algo) + self.md = md() + self.ctx = m2.hmac_ctx_new() + m2.hmac_init(self.ctx, key, self.md) + + def __del__(self): + # type: () -> None + if getattr(self, 'ctx', None): + self.m2_hmac_ctx_free(self.ctx) + +
    [docs] def reset(self, key): + # type: (bytes) -> None + m2.hmac_init(self.ctx, key, self.md)
    + +
    [docs] def update(self, data): + # type: (bytes) -> None + m2.hmac_update(self.ctx, data)
    + +
    [docs] def final(self): + # type: () -> bytes + return m2.hmac_final(self.ctx)
    + + digest = final
    + + +
    [docs]def hmac(key, data, algo='sha1'): + # type: (bytes, bytes, str) -> bytes + md = getattr(m2, algo, None) + if md is None: + raise ValueError('unknown algorithm', algo) + return m2.hmac(key, data, md())
    + + +
    [docs]class Cipher(object): + + m2_cipher_ctx_free = m2.cipher_ctx_free + + def __init__(self, alg, key, iv, op, key_as_bytes=0, d='md5', + salt=b'12345678', i=1, padding=1): + # type: (str, bytes, bytes, object, int, str, bytes, int, int) -> None + cipher = getattr(m2, alg, None) + if cipher is None: + raise ValueError('unknown cipher', alg) + self.cipher = cipher() + if key_as_bytes: + kmd = getattr(m2, d, None) + if kmd is None: + raise ValueError('unknown message digest', d) + key = m2.bytes_to_key(self.cipher, kmd(), key, salt, iv, i) + self.ctx = m2.cipher_ctx_new() + m2.cipher_init(self.ctx, self.cipher, key, iv, op) + self.set_padding(padding) + del key + + def __del__(self): + # type: () -> None + if getattr(self, 'ctx', None): + self.m2_cipher_ctx_free(self.ctx) + +
    [docs] def update(self, data): + # type: (bytes) -> bytes + return m2.cipher_update(self.ctx, data)
    + +
    [docs] def final(self): + # type: () -> bytes + return m2.cipher_final(self.ctx)
    + +
    [docs] def set_padding(self, padding=1): + # type: (int) -> int + """ + Actually always return 1 + """ + return m2.cipher_set_padding(self.ctx, padding)
    + + +
    [docs]class PKey(object): + """ + Public Key + """ + + m2_pkey_free = m2.pkey_free + m2_md_ctx_free = m2.md_ctx_free + + def __init__(self, pkey=None, _pyfree=0, md='sha1'): + # type: (Optional[bytes], int, str) -> None + if pkey is not None: + self.pkey = pkey # type: bytes + self._pyfree = _pyfree + else: + self.pkey = m2.pkey_new() + self._pyfree = 1 + self._set_context(md) + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_pkey_free(self.pkey) + if getattr(self, 'ctx', None): + self.m2_md_ctx_free(self.ctx) + + def _ptr(self): + return self.pkey + + def _set_context(self, md): + # type: (str) -> None + mda = getattr(m2, md, None) # type: Optional[Callable] + if mda is None: + raise ValueError('unknown message digest', md) + self.md = mda() + self.ctx = m2.md_ctx_new() # type: Context + +
    [docs] def reset_context(self, md='sha1'): + # type: (str) -> None + """ + Reset internal message digest context. + + :param md: The message digest algorithm. + """ + self._set_context(md)
    + +
    [docs] def sign_init(self): + # type: () -> None + """ + Initialise signing operation with self. + """ + m2.sign_init(self.ctx, self.md)
    + +
    [docs] def sign_update(self, data): + # type: (bytes) -> None + """ + Feed data to signing operation. + + :param data: Data to be signed. + """ + m2.sign_update(self.ctx, data)
    + +
    [docs] def sign_final(self): + # type: () -> bytes + """ + Return signature. + + :return: The signature. + """ + return m2.sign_final(self.ctx, self.pkey)
    + + # Deprecated + update = sign_update + final = sign_final + +
    [docs] def verify_init(self): + # type: () -> None + """ + Initialise signature verification operation with self. + """ + m2.verify_init(self.ctx, self.md)
    + +
    [docs] def verify_update(self, data): + # type: (bytes) -> int + """ + Feed data to verification operation. + + :param data: Data to be verified. + :return: -1 on Python error, 1 for success, 0 for OpenSSL error + """ + return m2.verify_update(self.ctx, data)
    + +
    [docs] def verify_final(self, sign): + # type: (bytes) -> int + """ + Return result of verification. + + :param sign: Signature to use for verification + :return: Result of verification: 1 for success, 0 for failure, -1 on + other error. + """ + return m2.verify_final(self.ctx, sign, self.pkey)
    + +
    [docs] def assign_rsa(self, rsa, capture=1): + # type: (RSA.RSA, int) -> int + """ + Assign the RSA key pair to self. + + :param rsa: M2Crypto.RSA.RSA object to be assigned to self. + + :param capture: If true (default), this PKey object will own the RSA + object, meaning that once the PKey object gets + deleted it is no longer safe to use the RSA object. + + :return: Return 1 for success and 0 for failure. + """ + if capture: + ret = m2.pkey_assign_rsa(self.pkey, rsa.rsa) + if ret: + rsa._pyfree = 0 + else: + ret = m2.pkey_set1_rsa(self.pkey, rsa.rsa) + return ret
    + +
    [docs] def get_rsa(self): + # type: () -> RSA.RSA_pub + """ + Return the underlying RSA key if that is what the EVP + instance is holding. + """ + rsa_ptr = m2.pkey_get1_rsa(self.pkey) + + rsa = RSA.RSA_pub(rsa_ptr, 1) + return rsa
    + +
    [docs] def save_key(self, file, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (AnyStr, Optional[str], Callable) -> int + """ + Save the key pair to a file in PEM format. + + :param file: Name of file to save key to. + + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. + """ + with BIO.openfile(file, 'wb') as bio: + return self.save_key_bio(bio, cipher, callback)
    + +
    [docs] def save_key_bio(self, bio, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (BIO.BIO, Optional[str], Callable) -> int + """ + Save the key pair to the M2Crypto.BIO object 'bio' in PEM format. + + :param bio: M2Crypto.BIO object to save key to. + + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. + """ + if cipher is None: + return m2.pkey_write_pem_no_cipher(self.pkey, bio._ptr(), callback) + else: + proto = getattr(m2, cipher, None) + if proto is None: + raise ValueError('no such cipher %s' % cipher) + return m2.pkey_write_pem(self.pkey, bio._ptr(), proto(), callback)
    + +
    [docs] def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback): + # type: (Optional[str], Callable) -> bytes + """ + Return key in PEM format in a string. + + :param cipher: Symmetric cipher to protect the key. The default + cipher is ``'aes_128_cbc'``. If cipher is None, + then the key is saved in the clear. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. + """ + bio = BIO.MemoryBuffer() + self.save_key_bio(bio, cipher, callback) + return bio.read_all()
    + +
    [docs] def as_der(self): + # type: () -> bytes + """ + Return key in DER format in a string + """ + buf = m2.pkey_as_der(self.pkey) + bio = BIO.MemoryBuffer(buf) + return bio.read_all()
    + +
    [docs] def size(self): + # type: () -> int + """ + Return the size of the key in bytes. + """ + return m2.pkey_size(self.pkey)
    + +
    [docs] def get_modulus(self): + # type: () -> Optional[bytes] + """ + Return the modulus in hex format. + """ + return m2.pkey_get_modulus(self.pkey)
    + + +
    [docs]def load_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> PKey + """ + Load an M2Crypto.EVP.PKey from file. + + :param file: Name of file containing the key in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. + + :return: M2Crypto.EVP.PKey object. + """ + with BIO.openfile(file, 'r') as bio: + cptr = m2.pkey_read_pem(bio.bio, callback) + + return PKey(cptr, 1)
    + + +
    [docs]def load_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> PKey + """ + Load an M2Crypto.EVP.PKey from an M2Crypto.BIO object. + + :param bio: M2Crypto.BIO object containing the key in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. + + :return: M2Crypto.EVP.PKey object. + """ + cptr = m2.pkey_read_pem(bio._ptr(), callback) + return PKey(cptr, 1)
    + + +
    [docs]def load_key_bio_pubkey(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> PKey + """ + Load an M2Crypto.EVP.PKey from a public key as a M2Crypto.BIO object. + + :param bio: M2Crypto.BIO object containing the key in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. + + :return: M2Crypto.EVP.PKey object. + """ + cptr = m2.pkey_read_pem_pubkey(bio._ptr(), callback) + if cptr is None: + raise EVPError(Err.get_error()) + return PKey(cptr, 1)
    + + +
    [docs]def load_key_string(string, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> PKey + """ + Load an M2Crypto.EVP.PKey from a string. + + :param string: String containing the key in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. + + :return: M2Crypto.EVP.PKey object. + """ + bio = BIO.MemoryBuffer(string) + return load_key_bio(bio, callback)
    + + +
    [docs]def load_key_string_pubkey(string, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> PKey + """ + Load an M2Crypto.EVP.PKey from a public key as a string. + + :param string: String containing the key in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect the + key. + + :return: M2Crypto.EVP.PKey object. + """ + bio = BIO.MemoryBuffer(string) + return load_key_bio_pubkey(bio, callback)
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/Engine.html b/doc/html/_modules/M2Crypto/Engine.html new file mode 100644 index 0000000..4d8474c --- /dev/null +++ b/doc/html/_modules/M2Crypto/Engine.html @@ -0,0 +1,254 @@ + + + + + + + + M2Crypto.Engine — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.Engine

    +# vim: sts=4 sw=4 et
    +from __future__ import absolute_import
    +
    +"""
    +M2Crypto wrapper for OpenSSL ENGINE API.
    +
    +Pavel Shramov
    +IMEC MSU
    +"""
    +
    +from M2Crypto import EVP, Err, X509, m2, six, util
    +if util.py27plus:
    +    from typing import AnyStr, Callable, Optional  # noqa
    +
    +
    +
    [docs]class EngineError(Exception): + pass
    + +m2.engine_init_error(EngineError) + + +
    [docs]class Engine(object): + """Wrapper for ENGINE object.""" + + m2_engine_free = m2.engine_free + + def __init__(self, id=None, _ptr=None, _pyfree=1): + # type: (Optional[bytes], Optional[bytes], int) -> None + """Create new Engine from ENGINE pointer or obtain by id""" + if not _ptr and not id: + raise ValueError("No engine id specified") + self._ptr = _ptr + if not self._ptr: + self._ptr = m2.engine_by_id(id) + if not self._ptr: + raise ValueError("Unknown engine: %s" % id) + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_engine_free(self._ptr) + +
    [docs] def init(self): + # type: () -> int + """Obtain a functional reference to the engine. + + :return: 0 on error, non-zero on success.""" + return m2.engine_init(self._ptr)
    + +
    [docs] def finish(self): + # type: () -> int + """Release a functional and structural reference to the engine.""" + return m2.engine_finish(self._ptr)
    + +
    [docs] def ctrl_cmd_string(self, cmd, arg, optional=0): + # type: (AnyStr, Optional[AnyStr], int) -> None + """Call ENGINE_ctrl_cmd_string""" + cmd = six.ensure_str(cmd) + if arg is not None: + arg = six.ensure_str(arg) + if not m2.engine_ctrl_cmd_string(self._ptr, cmd, arg, optional): + raise EngineError(Err.get_error())
    + +
    [docs] def get_name(self): + # type: () -> bytes + """Return engine name""" + return m2.engine_get_name(self._ptr)
    + +
    [docs] def get_id(self): + # type: () -> bytes + """Return engine id""" + return m2.engine_get_id(self._ptr)
    + +
    [docs] def set_default(self, methods=m2.ENGINE_METHOD_ALL): + # type: (int) -> int + """ + Use this engine as default for methods specified in argument + + :param methods: Possible values are bitwise OR of m2.ENGINE_METHOD_* + """ + return m2.engine_set_default(self._ptr, methods)
    + + def _engine_load_key(self, func, name, pin=None): + # type: (Callable, bytes, Optional[bytes]) -> EVP.PKey + """Helper function for loading keys""" + ui = m2.ui_openssl() + cbd = m2.engine_pkcs11_data_new(pin) + try: + kptr = func(self._ptr, name, ui, cbd) + if not kptr: + raise EngineError(Err.get_error()) + key = EVP.PKey(kptr, _pyfree=1) + finally: + m2.engine_pkcs11_data_free(cbd) + return key + +
    [docs] def load_private_key(self, name, pin=None): + # type: (bytes, Optional[bytes]) -> X509.X509 + """Load private key with engine methods (e.g from smartcard). + If pin is not set it will be asked + """ + return self._engine_load_key(m2.engine_load_private_key, name, pin)
    + +
    [docs] def load_public_key(self, name, pin=None): + # type: (bytes, Optional[bytes]) -> EVP.PKey + """Load public key with engine methods (e.g from smartcard).""" + return self._engine_load_key(m2.engine_load_public_key, name, pin)
    + +
    [docs] def load_certificate(self, name): + # type: (bytes) -> X509.X509 + """Load certificate from engine (e.g from smartcard). + NOTE: This function may be not implemented by engine!""" + cptr = m2.engine_load_certificate(self._ptr, name) + if not cptr: + raise EngineError("Certificate or card not found") + return X509.X509(cptr, _pyfree=1)
    + + +
    [docs]def load_dynamic_engine(id, sopath): + # type: (bytes, AnyStr) -> Engine + """Load and return dymanic engine from sopath and assign id to it""" + if isinstance(sopath, six.text_type): + sopath = sopath.encode('utf8') + m2.engine_load_dynamic() + e = Engine('dynamic') + e.ctrl_cmd_string('SO_PATH', sopath) + e.ctrl_cmd_string('ID', id) + e.ctrl_cmd_string('LIST_ADD', '1') + e.ctrl_cmd_string('LOAD', None) + return e
    + + +
    [docs]def load_dynamic(): + # type: () -> None + """Load dynamic engine""" + m2.engine_load_dynamic()
    + + +
    [docs]def load_openssl(): + # type: () -> None + """Load openssl engine""" + m2.engine_load_openssl()
    + + +
    [docs]def cleanup(): + # type: () -> None + """If you load any engines, you need to clean up after your application + is finished with the engines.""" + m2.engine_cleanup()
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/Err.html b/doc/html/_modules/M2Crypto/Err.html new file mode 100644 index 0000000..1688939 --- /dev/null +++ b/doc/html/_modules/M2Crypto/Err.html @@ -0,0 +1,177 @@ + + + + + + + + M2Crypto.Err — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.Err

    +from __future__ import absolute_import
    +
    +"""M2Crypto wrapper for OpenSSL Error API.
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +from M2Crypto import BIO, m2, py27plus, util, six  # noqa
    +if py27plus:
    +    from typing import Optional  # noqa
    +
    +
    +
    [docs]def get_error(): + # type: () -> Optional[str] + err = BIO.MemoryBuffer() + m2.err_print_errors(err.bio_ptr()) + err_msg = err.read() + if err_msg: + return six.ensure_text(err_msg)
    + + +
    [docs]def get_error_code(): + # type: () -> int + return m2.err_get_error()
    + + +
    [docs]def peek_error_code(): + # type: () -> int + return m2.err_peek_error()
    + + +
    [docs]def get_error_lib(err): + # type: (int) -> str + return six.ensure_text(m2.err_lib_error_string(err))
    + + +
    [docs]def get_error_func(err): + # type: (int) -> str + return six.ensure_text(m2.err_func_error_string(err))
    + + +
    [docs]def get_error_reason(err): + # type: (int) -> str + return six.ensure_text(m2.err_reason_error_string(err))
    + + +
    [docs]def get_error_message(): + # type: () -> str + return six.ensure_text(get_error_reason(get_error_code()))
    + + +
    [docs]def get_x509_verify_error(err): + # type: (int) -> str + return six.ensure_text(m2.x509_get_verify_error(err))
    + + +
    [docs]class SSLError(Exception): + def __init__(self, err, client_addr): + # type: (int, util.AddrType) -> None + self.err = err + self.client_addr = client_addr + + def __str__(self): + # type: () -> str + if not isinstance(self.client_addr, six.text_type): + s = self.client_addr.decode('utf8') + else: + s = self.client_addr + return "%s: %s: %s" % (get_error_func(self.err), s, + get_error_reason(self.err))
    + + +
    [docs]class M2CryptoError(Exception): + pass
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/RC4.html b/doc/html/_modules/M2Crypto/RC4.html new file mode 100644 index 0000000..95456f5 --- /dev/null +++ b/doc/html/_modules/M2Crypto/RC4.html @@ -0,0 +1,140 @@ + + + + + + + + M2Crypto.RC4 — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.RC4

    +from __future__ import absolute_import
    +
    +"""M2Crypto wrapper for OpenSSL RC4 API.
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +from M2Crypto.m2 import rc4_free, rc4_new, rc4_set_key, rc4_update
    +
    +
    +
    [docs]class RC4(object): + """Object interface to the stream cipher RC4.""" + + rc4_free = rc4_free + + def __init__(self, key=None): + # type: (bytes) -> None + self.cipher = rc4_new() + if key: + rc4_set_key(self.cipher, key) + + def __del__(self): + # type: () -> None + if getattr(self, 'cipher', None): + self.rc4_free(self.cipher) + +
    [docs] def set_key(self, key): + # type: (bytes) -> None + rc4_set_key(self.cipher, key)
    + +
    [docs] def update(self, data): + # type: (bytes) -> bytes + return rc4_update(self.cipher, data)
    + +
    [docs] def final(self): + # type: () -> str + return ''
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/RSA.html b/doc/html/_modules/M2Crypto/RSA.html new file mode 100644 index 0000000..172316b --- /dev/null +++ b/doc/html/_modules/M2Crypto/RSA.html @@ -0,0 +1,570 @@ + + + + + + + + M2Crypto.RSA — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.RSA

    +from __future__ import absolute_import
    +
    +"""M2Crypto wrapper for OpenSSL RSA API.
    +
    +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
    +
    +import sys
    +
    +from M2Crypto import BIO, Err, m2, util
    +if util.py27plus:
    +    from typing import Any, AnyStr, Callable, Dict, List, IO, Optional, Tuple  # noqa
    +
    +
    +
    [docs]class RSAError(Exception): + pass
    + +m2.rsa_init(RSAError) + +no_padding = m2.no_padding +pkcs1_padding = m2.pkcs1_padding +sslv23_padding = m2.sslv23_padding +pkcs1_oaep_padding = m2.pkcs1_oaep_padding + + +
    [docs]class RSA(object): + """ + RSA Key Pair. + """ + + m2_rsa_free = m2.rsa_free + + def __init__(self, rsa, _pyfree=0): + # type: (bytes, int) -> None + """ + :param rsa: binary representation of OpenSSL RSA type + """ + assert m2.rsa_type_check(rsa), "'rsa' type error" + self.rsa = rsa + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_rsa_free(self.rsa) + + def __len__(self): + # type: () -> int + return int(m2.rsa_size(self.rsa) << 3) + + def __getattr__(self, name): + # type: (str) -> bytes + if name == 'e': + return m2.rsa_get_e(self.rsa) + elif name == 'n': + return m2.rsa_get_n(self.rsa) + else: + raise AttributeError + +
    [docs] def pub(self): + # type: () -> Tuple[bytes, bytes] + assert self.check_key(), 'key is not initialised' + return m2.rsa_get_e(self.rsa), m2.rsa_get_n(self.rsa)
    + +
    [docs] def public_encrypt(self, data, padding): + # type: (bytes, int) -> bytes + assert self.check_key(), 'key is not initialised' + return m2.rsa_public_encrypt(self.rsa, data, padding)
    + +
    [docs] def public_decrypt(self, data, padding): + # type: (bytes, int) -> bytes + assert self.check_key(), 'key is not initialised' + return m2.rsa_public_decrypt(self.rsa, data, padding)
    + +
    [docs] def private_encrypt(self, data, padding): + # type: (bytes, int) -> bytes + assert self.check_key(), 'key is not initialised' + return m2.rsa_private_encrypt(self.rsa, data, padding)
    + +
    [docs] def private_decrypt(self, data, padding): + # type: (bytes, int) -> bytes + assert self.check_key(), 'key is not initialised' + return m2.rsa_private_decrypt(self.rsa, data, padding)
    + +
    [docs] def save_key_bio(self, bio, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (BIO.BIO, Optional[str], Callable) -> int + """ + Save the key pair to an M2Crypto.BIO.BIO object in PEM format. + + :param bio: M2Crypto.BIO.BIO object to save key to. + + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. + """ + if cipher is None: + return m2.rsa_write_key_no_cipher(self.rsa, bio._ptr(), callback) + else: + ciph = getattr(m2, cipher, None) + if ciph is None: + raise RSAError('not such cipher %s' % cipher) + else: + ciph = ciph() + return m2.rsa_write_key(self.rsa, bio._ptr(), ciph, callback)
    + +
    [docs] def save_key(self, file, cipher='aes_128_cbc', + callback=util.passphrase_callback): + # type: (AnyStr, Optional[str], Callable) -> int + """ + Save the key pair to a file in PEM format. + + :param file: Name of file to save key to. + + :param cipher: Symmetric cipher to protect the key. The default + cipher is 'aes_128_cbc'. If cipher is None, then + the key is saved in the clear. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to protect + the key. The default is + util.passphrase_callback. + """ + with BIO.openfile(file, 'wb') as bio: + return self.save_key_bio(bio, cipher, callback)
    + + save_pem = save_key + +
    [docs] def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback): + # type: (Optional[str], Callable) -> bytes + """ + Returns the key(pair) as a string in PEM format. + """ + bio = BIO.MemoryBuffer() + self.save_key_bio(bio, cipher, callback) + return bio.read()
    + +
    [docs] def save_key_der_bio(self, bio): + # type: (BIO.BIO) -> int + """ + Save the key pair to an M2Crypto.BIO.BIO object in DER format. + + :param bio: M2Crypto.BIO.BIO object to save key to. + """ + return m2.rsa_write_key_der(self.rsa, bio._ptr())
    + +
    [docs] def save_key_der(self, file): + # type: (AnyStr) -> int + """ + Save the key pair to a file in DER format. + + :param file: Filename to save key to + """ + with BIO.openfile(file, 'wb') as bio: + return self.save_key_der_bio(bio)
    + +
    [docs] def save_pub_key_bio(self, bio): + # type: (BIO.BIO) -> int + """ + Save the public key to an M2Crypto.BIO.BIO object in PEM format. + + :param bio: M2Crypto.BIO.BIO object to save key to. + """ + return m2.rsa_write_pub_key(self.rsa, bio._ptr())
    + +
    [docs] def save_pub_key(self, file): + # type: (AnyStr) -> int + """ + Save the public key to a file in PEM format. + + :param file: Name of file to save key to. + """ + with BIO.openfile(file, 'wb') as bio: + return m2.rsa_write_pub_key(self.rsa, bio._ptr())
    + +
    [docs] def check_key(self): + # type: () -> int + """ + Validate RSA keys. + + It checks that p and q are in fact prime, and that n = p*q. + + :return: returns 1 if rsa is a valid RSA key, and 0 otherwise. + -1 is returned if an error occurs while checking the key. + If the key is invalid or an error occurred, the reason + code can be obtained using ERR_get_error(3). + """ + return m2.rsa_check_key(self.rsa)
    + +
    [docs] def sign_rsassa_pss(self, digest, algo='sha1', salt_length=20): + # type: (bytes, str, int) -> bytes + """ + Signs a digest with the private key using RSASSA-PSS + + :param digest: A digest created by using the digest method + + :param salt_length: The length of the salt to use + + :param algo: The hash algorithm to use + Legal values like 'sha1','sha224', 'sha256', + 'ripemd160', and 'md5'. + + :return: a string which is the signature + """ + hash = getattr(m2, algo, None) + + if hash is None: + raise RSAError('not such hash algorithm %s' % algo) + + signature = m2.rsa_padding_add_pkcs1_pss(self.rsa, digest, hash(), salt_length) + + return self.private_encrypt(signature, m2.no_padding)
    + +
    [docs] def verify_rsassa_pss(self, data, signature, algo='sha1', salt_length=20): + # type: (bytes, bytes, str, int) -> int + """ + Verifies the signature RSASSA-PSS + + :param data: Data that has been signed + + :param signature: The signature signed with RSASSA-PSS + + :param salt_length: The length of the salt that was used + + :param algo: The hash algorithm to use + Legal values are for example 'sha1','sha224', + 'sha256', 'ripemd160', and 'md5'. + + :return: 1 or 0, depending on whether the signature was + verified or not. + """ + hash = getattr(m2, algo, None) + + if hash is None: + raise RSAError('not such hash algorithm %s' % algo) + + plain_signature = self.public_decrypt(signature, m2.no_padding) + + return m2.rsa_verify_pkcs1_pss(self.rsa, data, plain_signature, hash(), salt_length)
    + +
    [docs] def sign(self, digest, algo='sha1'): + # type: (bytes, str) -> bytes + """ + Signs a digest with the private key + + :param digest: A digest created by using the digest method + + :param algo: The method that created the digest. + Legal values like 'sha1','sha224', 'sha256', + 'ripemd160', and 'md5'. + + :return: a string which is the signature + """ + digest_type = getattr(m2, 'NID_' + algo, None) + if digest_type is None: + raise ValueError('unknown algorithm', algo) + + return m2.rsa_sign(self.rsa, digest, digest_type)
    + +
    [docs] def verify(self, data, signature, algo='sha1'): + # type: (bytes, bytes, str) -> int + """ + Verifies the signature with the public key + + :param data: Data that has been signed + + :param signature: The signature signed with the private key + + :param algo: The method use to create digest from the data + before it was signed. Legal values like + 'sha1','sha224', 'sha256', 'ripemd160', and 'md5'. + + :return: 1 or 0, depending on whether the signature was + verified or not. + """ + digest_type = getattr(m2, 'NID_' + algo, None) + if digest_type is None: + raise ValueError('unknown algorithm', algo) + + return m2.rsa_verify(self.rsa, data, signature, digest_type)
    + + +
    [docs]class RSA_pub(RSA): + + """ + Object interface to an RSA public key. + """ + + def __setattr__(self, name, value): + # type: (str, bytes) -> None + if name in ['e', 'n']: + raise RSAError('use factory function new_pub_key() to set (e, n)') + else: + self.__dict__[name] = value + +
    [docs] def private_encrypt(self, *argv): + # type: (*Any) -> None + raise RSAError('RSA_pub object has no private key')
    + +
    [docs] def private_decrypt(self, *argv): + # type: (*Any) -> None + raise RSAError('RSA_pub object has no private key')
    + +
    [docs] def save_key(self, file, *args, **kw): + # type: (AnyStr, *Any, **Any) -> int + """ + Save public key to file. + """ + return self.save_pub_key(file)
    + +
    [docs] def save_key_bio(self, bio, *args, **kw): + # type: (BIO.BIO, *Any, **Any) -> int + """ + Save public key to BIO. + """ + return self.save_pub_key_bio(bio)
    + + # save_key_der + + # save_key_der_bio + +
    [docs] def check_key(self): + # type: () -> int + return m2.rsa_check_pub_key(self.rsa)
    + + +
    [docs]def rsa_error(): + # type: () -> None + raise RSAError(Err.get_error_message())
    + + +
    [docs]def keygen_callback(p, n, out=sys.stdout): + # type: (int, Any, IO[str]) -> None + """ + Default callback for gen_key(). + """ + ch = ['.', '+', '*', '\n'] + out.write(ch[p]) + out.flush()
    + + +
    [docs]def gen_key(bits, e, callback=keygen_callback): + # type: (int, int, Callable) -> RSA + """ + Generate an RSA key pair. + + :param bits: Key length, in bits. + + :param e: The RSA public exponent. + + :param callback: A Python callable object that is invoked + during key generation; its usual purpose is to + provide visual feedback. The default callback is + keygen_callback. + + :return: M2Crypto.RSA.RSA object. + """ + return RSA(m2.rsa_generate_key(bits, e, callback), 1)
    + + +
    [docs]def load_key(file, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> RSA + """ + Load an RSA key pair from file. + + :param file: Name of file containing RSA public key in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to unlock the + key. The default is util.passphrase_callback. + + :return: M2Crypto.RSA.RSA object. + """ + with BIO.openfile(file) as bio: + return load_key_bio(bio, callback)
    + + +
    [docs]def load_key_bio(bio, callback=util.passphrase_callback): + # type: (BIO.BIO, Callable) -> RSA + """ + Load an RSA key pair from an M2Crypto.BIO.BIO object. + + :param bio: M2Crypto.BIO.BIO object containing RSA key pair in PEM + format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to unlock the + key. The default is util.passphrase_callback. + + :return: M2Crypto.RSA.RSA object. + """ + rsa = m2.rsa_read_key(bio._ptr(), callback) + if rsa is None: + rsa_error() + return RSA(rsa, 1)
    + + +
    [docs]def load_key_string(string, callback=util.passphrase_callback): + # type: (AnyStr, Callable) -> RSA + """ + Load an RSA key pair from a string. + + :param string: String containing RSA key pair in PEM format. + + :param callback: A Python callable object that is invoked + to acquire a passphrase with which to unlock the + key. The default is util.passphrase_callback. + + :return: M2Crypto.RSA.RSA object. + """ + bio = BIO.MemoryBuffer(string) + return load_key_bio(bio, callback)
    + + +
    [docs]def load_pub_key(file): + # type: (AnyStr) -> RSA_pub + """ + Load an RSA public key from file. + + :param file: Name of file containing RSA public key in PEM format. + + :return: M2Crypto.RSA.RSA_pub object. + """ + with BIO.openfile(file) as bio: + return load_pub_key_bio(bio)
    + + +
    [docs]def load_pub_key_bio(bio): + # type: (BIO.BIO) -> RSA_pub + """ + Load an RSA public key from an M2Crypto.BIO.BIO object. + + :param bio: M2Crypto.BIO.BIO object containing RSA public key in PEM + format. + + :return: M2Crypto.RSA.RSA_pub object. + """ + rsa = m2.rsa_read_pub_key(bio._ptr()) + if rsa is None: + rsa_error() + return RSA_pub(rsa, 1)
    + + +
    [docs]def new_pub_key(e_n): + # type: (Tuple[bytes, bytes]) -> RSA_pub + """ + Instantiate an RSA_pub object from an (e, n) tuple. + + :param e: The RSA public exponent; it is a string in OpenSSL's MPINT + format - 4-byte big-endian bit-count followed by the + appropriate number of bits. + + :param n: The RSA composite of primes; it is a string in OpenSSL's + MPINT format - 4-byte big-endian bit-count followed by the + appropriate number of bits. + + :return: M2Crypto.RSA.RSA_pub object. + """ + (e, n) = e_n + rsa = m2.rsa_new() + m2.rsa_set_en(rsa, e, n) + return RSA_pub(rsa, 1)
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/Rand.html b/doc/html/_modules/M2Crypto/Rand.html new file mode 100644 index 0000000..b2fa075 --- /dev/null +++ b/doc/html/_modules/M2Crypto/Rand.html @@ -0,0 +1,251 @@ + + + + + + + + M2Crypto.Rand — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.Rand

    +"""M2Crypto wrapper for OpenSSL PRNG. Requires OpenSSL 0.9.5 and above.
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.
    +Copyright (c) 2014-2017 Matej Cepl. All rights reserved.
    +
    +See LICENCE for the license information.
    +"""
    +from __future__ import absolute_import
    +
    +from M2Crypto import m2, py27plus, six
    +if py27plus:
    +    from typing import AnyStr, Tuple  # noqa
    +
    +
    +__all__ = ['rand_seed', 'rand_add', 'load_file', 'save_file', 'rand_bytes',
    +           'rand_pseudo_bytes', 'rand_file_name', 'rand_status']
    +
    +
    +class RandError(ValueError):
    +    pass
    +
    +m2.rand_init(RandError)
    +
    +
    +
    [docs]def rand_add(blob, entropy): + # type: (bytes, float) -> None + """ + Mixes blob into the PRNG state. + + :param blob: added data + :param entropy: (the lower bound of) an estimate of how much randomness + is contained in blob, measured in bytes. + + Thus, if the data at buf are unpredictable to an adversary, this + increases the uncertainty about the state and makes the PRNG output less + predictable. Suitable input comes from user interaction (random key + presses, mouse movements) and certain hardware events. + + Details about sources of randomness and how to estimate their entropy + can be found in the literature, e.g. RFC 1750. + """ + m2.rand_add(blob, entropy) # pylint: disable=no-member
    + + +
    [docs]def rand_seed(seed): + # type: (bytes) -> None + """ + Equivalent to rand_add() when len(seed) == entropy. + + :param seed: added data (see description at rand_add) + """ + m2.rand_seed(seed) # pylint: disable=no-member
    + + +
    [docs]def rand_status(): + # type: () -> int + """ + Check whether there is enough entropy in PRNG. + + :return: 1 if the PRNG has been seeded with enough + data, 0 otherwise. + """ + return m2.rand_status() # pylint: disable=no-member
    + + +
    [docs]def rand_file_name(): + # type: () -> str + """ + Generate a default path for the random seed file. + + :return: string with the filename. + The seed file is $RANDFILE if that environment variable + is set, $HOME/.rnd otherwise. If $HOME is not set either, + an error occurs. + """ + return six.ensure_text(m2.rand_file_name()) # pylint: disable=no-member
    + + +
    [docs]def load_file(filename, max_bytes): + # type: (AnyStr, int) -> int + """ + Read a number of bytes from file filename and adds them to the PRNG. + + If max_bytes is non-negative, up to to max_bytes are read; starting with + OpenSSL 0.9.5, if max_bytes is -1, the complete file is read. + + :param filename: + :param max_bytes: + :return: the number of bytes read. + """ + return m2.rand_load_file(six.ensure_str(filename), max_bytes) # pylint: disable=no-member
    + + +
    [docs]def save_file(filename): + # type: (AnyStr) -> int + """ + Write a number of random bytes (currently 1024) to file. + + The file then can be used to initialize the PRNG by calling load_file() in + a later session. + + :param filename: + :return: returns the number of bytes written, and -1 if the bytes + written were generated without appropriate seed. + """ + return m2.rand_save_file(filename) # pylint: disable=no-member
    + + +
    [docs]def rand_bytes(num): + # type: (int) -> bytes + """ + Return n cryptographically strong pseudo-random bytes. + + An error occurs if the PRNG has not been seeded with enough randomness + to ensure an unpredictable byte sequence. + + :param num: number of bytes to be returned + :return: random bytes + """ + return m2.rand_bytes(num) # pylint: disable=no-member
    + + +
    [docs]def rand_pseudo_bytes(num): + # type: (int) -> Tuple[bytes, int] + """ + Return num pseudo-random bytes into buf. + + Pseudo-random byte sequences generated by this method will be unique + if they are of sufficient length, but are not necessarily + unpredictable. They can be used for non-cryptographic purposes and for + certain purposes in cryptographic protocols, but usually not for key + generation etc. + + Output of the function is mixed into the entropy pool before + retrieving the new pseudo-random bytes unless disabled at compile + time (see FAQ). + + :param num: number of bytes to be returned + :return: random bytes + """ + import warnings + if m2.OPENSSL_VERSION_NUMBER >= 0x10100000: + warnings.warn('The underlying OpenSSL method has been ' + + 'deprecated. Use Rand.rand_bytes instead.', + DeprecationWarning) + + return m2.rand_pseudo_bytes(num) # pylint: disable=no-member
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SMIME.html b/doc/html/_modules/M2Crypto/SMIME.html new file mode 100644 index 0000000..dbd0bb3 --- /dev/null +++ b/doc/html/_modules/M2Crypto/SMIME.html @@ -0,0 +1,395 @@ + + + + + + + + M2Crypto.SMIME — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SMIME

    +from __future__ import absolute_import
    +
    +"""M2Crypto wrapper for OpenSSL S/MIME API.
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +from M2Crypto import BIO, EVP, Err, X509, m2, util
    +if util.py27plus:
    +    from typing import AnyStr, Callable, Optional  # noqa
    +
    +PKCS7_TEXT = m2.PKCS7_TEXT  # type: int
    +PKCS7_NOCERTS = m2.PKCS7_NOCERTS  # type: int
    +PKCS7_NOSIGS = m2.PKCS7_NOSIGS  # type: int
    +PKCS7_NOCHAIN = m2.PKCS7_NOCHAIN  # type: int
    +PKCS7_NOINTERN = m2.PKCS7_NOINTERN  # type: int
    +PKCS7_NOVERIFY = m2.PKCS7_NOVERIFY  # type: int
    +PKCS7_DETACHED = m2.PKCS7_DETACHED  # type: int
    +PKCS7_BINARY = m2.PKCS7_BINARY  # type: int
    +PKCS7_NOATTR = m2.PKCS7_NOATTR  # type: int
    +
    +PKCS7_SIGNED = m2.PKCS7_SIGNED  # type: int
    +PKCS7_ENVELOPED = m2.PKCS7_ENVELOPED  # type: int
    +PKCS7_SIGNED_ENVELOPED = m2.PKCS7_SIGNED_ENVELOPED  # Deprecated
    +PKCS7_DATA = m2.PKCS7_DATA  # type: int
    +
    +
    +
    [docs]class PKCS7_Error(Exception): + pass
    + +m2.pkcs7_init(PKCS7_Error) + + +
    [docs]class PKCS7(object): + + m2_pkcs7_free = m2.pkcs7_free + + def __init__(self, pkcs7=None, _pyfree=0): + # type: (Optional[bytes], int) -> None + """PKCS7 object. + + :param pkcs7: binary representation of + the OpenSSL type PKCS7 + """ + if pkcs7 is not None: + self.pkcs7 = pkcs7 + self._pyfree = _pyfree + else: + self.pkcs7 = m2.pkcs7_new() + self._pyfree = 1 + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_pkcs7_free(self.pkcs7) + + def _ptr(self): + return self.pkcs7 + +
    [docs] def type(self, text_name=0): + # type: (int) -> int + if text_name: + return m2.pkcs7_type_sn(self.pkcs7) + else: + return m2.pkcs7_type_nid(self.pkcs7)
    + +
    [docs] def write(self, bio): + # type: (BIO.BIO) -> int + return m2.pkcs7_write_bio(self.pkcs7, bio._ptr())
    + +
    [docs] def write_der(self, bio): + # type: (BIO.BIO) -> int + return m2.pkcs7_write_bio_der(self.pkcs7, bio._ptr())
    + +
    [docs] def get0_signers(self, certs, flags=0): + # type: (X509.X509_Stack, int) -> X509.X509_Stack + return X509.X509_Stack(m2.pkcs7_get0_signers(self.pkcs7, + certs.stack, flags), 1)
    + + +
    [docs]def load_pkcs7(p7file): + # type: (AnyStr) -> PKCS7 + with BIO.openfile(p7file, 'r') as bio: + p7_ptr = m2.pkcs7_read_bio(bio.bio) + + return PKCS7(p7_ptr, 1)
    + + +
    [docs]def load_pkcs7_der(p7file): + # type: (AnyStr) -> PKCS7 + with BIO.openfile(p7file, 'rb') as bio: + p7_ptr = m2.pkcs7_read_bio_der(bio.bio) + + return PKCS7(p7_ptr, 1)
    + + +
    [docs]def load_pkcs7_bio(p7_bio): + # type: (BIO.BIO) -> PKCS7 + p7_ptr = m2.pkcs7_read_bio(p7_bio._ptr()) + return PKCS7(p7_ptr, 1)
    + + +
    [docs]def load_pkcs7_bio_der(p7_bio): + # type: (BIO.BIO) -> PKCS7 + p7_ptr = m2.pkcs7_read_bio_der(p7_bio._ptr()) + return PKCS7(p7_ptr, 1)
    + + +
    [docs]def smime_load_pkcs7(p7file): + # type: (AnyStr) -> PKCS7 + bio = m2.bio_new_file(p7file, 'r') + + try: + p7_ptr, bio_ptr = m2.smime_read_pkcs7(bio) + finally: + m2.bio_free(bio) + + if bio_ptr is None: + return PKCS7(p7_ptr, 1), None + else: + return PKCS7(p7_ptr, 1), BIO.BIO(bio_ptr, 1)
    + + +
    [docs]def smime_load_pkcs7_bio(p7_bio): + # type: (BIO.BIO) -> PKCS7 + p7_ptr, bio_ptr = m2.smime_read_pkcs7(p7_bio._ptr()) + if p7_ptr is None: + raise SMIME_Error(Err.get_error()) + if bio_ptr is None: + return PKCS7(p7_ptr, 1), None + else: + return PKCS7(p7_ptr, 1), BIO.BIO(bio_ptr, 1)
    + + +
    [docs]class Cipher(object): + """Object interface to EVP_CIPHER without all the frills of + M2Crypto.EVP.Cipher. + """ + + def __init__(self, algo): + # type: (str) -> None + cipher = getattr(m2, algo, None) + if cipher is None: + raise ValueError('unknown cipher', algo) + self.cipher = cipher() + + def _ptr(self): + return self.cipher
    + + +
    [docs]class SMIME_Error(Exception): + pass
    + +m2.smime_init(SMIME_Error) + + +# FIXME class has no __init__ method +
    [docs]class SMIME(object): +
    [docs] def load_key(self, keyfile, certfile=None, + callback=util.passphrase_callback): + # type: (AnyStr, Optional[AnyStr], Callable) -> None + if certfile is None: + certfile = keyfile + self.pkey = EVP.load_key(keyfile, callback) + self.x509 = X509.load_cert(certfile)
    + +
    [docs] def load_key_bio(self, keybio, certbio=None, + callback=util.passphrase_callback): + # type: (BIO.BIO, Optional[BIO.BIO], Callable) -> None + if certbio is None: + certbio = keybio + self.pkey = EVP.load_key_bio(keybio, callback) + self.x509 = X509.load_cert_bio(certbio)
    + +
    [docs] def set_x509_stack(self, stack): + # type: (X509.X509_Stack) -> None + assert isinstance(stack, X509.X509_Stack) + self.x509_stack = stack
    + +
    [docs] def set_x509_store(self, store): + # type: (X509.X509_Store) -> None + assert isinstance(store, X509.X509_Store) + self.x509_store = store
    + +
    [docs] def set_cipher(self, cipher): + # type: (Cipher) -> None + assert isinstance(cipher, Cipher) + self.cipher = cipher
    + +
    [docs] def unset_key(self): + # type: () -> None + del self.pkey + del self.x509
    + +
    [docs] def unset_x509_stack(self): + # type: () -> None + del self.x509_stack
    + +
    [docs] def unset_x509_store(self): + # type: () -> None + del self.x509_store
    + +
    [docs] def unset_cipher(self): + # type: () -> None + del self.cipher
    + +
    [docs] def encrypt(self, data_bio, flags=0): + # type: (BIO.BIO, int) -> PKCS7 + if not hasattr(self, 'cipher'): + raise SMIME_Error('no cipher: use set_cipher()') + if not hasattr(self, 'x509_stack'): + raise SMIME_Error('no recipient certs: use set_x509_stack()') + + pkcs7 = m2.pkcs7_encrypt(self.x509_stack._ptr(), data_bio._ptr(), + self.cipher._ptr(), flags) + + return PKCS7(pkcs7, 1)
    + +
    [docs] def decrypt(self, pkcs7, flags=0): + # type: (PKCS7, int) -> Optional[bytes] + if not hasattr(self, 'pkey'): + raise SMIME_Error('no private key: use load_key()') + if not hasattr(self, 'x509'): + raise SMIME_Error('no certificate: load_key() used incorrectly?') + blob = m2.pkcs7_decrypt(pkcs7._ptr(), self.pkey._ptr(), + self.x509._ptr(), flags) + return blob
    + +
    [docs] def sign(self, data_bio, flags=0, algo='sha1'): + # type: (BIO.BIO, int, Optional[str]) -> PKCS7 + if not hasattr(self, 'pkey'): + raise SMIME_Error('no private key: use load_key()') + + hash = getattr(m2, algo, None) + + if hash is None: + raise SMIME_Error('no such hash algorithm %s' % algo) + + if hasattr(self, 'x509_stack'): + pkcs7 = m2.pkcs7_sign1(self.x509._ptr(), self.pkey._ptr(), + self.x509_stack._ptr(), + data_bio._ptr(), hash(), flags) + return PKCS7(pkcs7, 1) + else: + pkcs7 = m2.pkcs7_sign0(self.x509._ptr(), self.pkey._ptr(), + data_bio._ptr(), hash(), flags) + return PKCS7(pkcs7, 1)
    + +
    [docs] def verify(self, pkcs7, data_bio=None, flags=0): + # type: (PKCS7, BIO.BIO, int) -> Optional[bytes] + if not hasattr(self, 'x509_stack'): + raise SMIME_Error('no signer certs: use set_x509_stack()') + if not hasattr(self, 'x509_store'): + raise SMIME_Error('no x509 cert store: use set_x509_store()') + assert isinstance(pkcs7, PKCS7), 'pkcs7 not an instance of PKCS7' + p7 = pkcs7._ptr() + if data_bio is None: + blob = m2.pkcs7_verify0(p7, self.x509_stack._ptr(), + self.x509_store._ptr(), flags) + else: + blob = m2.pkcs7_verify1(p7, self.x509_stack._ptr(), + self.x509_store._ptr(), + data_bio._ptr(), flags) + return blob
    + +
    [docs] def write(self, out_bio, pkcs7, data_bio=None, flags=0): + # type: (BIO.BIO, PKCS7, Optional[BIO.BIO], int) -> int + assert isinstance(pkcs7, PKCS7) + if data_bio is None: + return m2.smime_write_pkcs7(out_bio._ptr(), pkcs7._ptr(), flags) + else: + return m2.smime_write_pkcs7_multi(out_bio._ptr(), pkcs7._ptr(), + data_bio._ptr(), flags)
    + + +
    [docs]def text_crlf(text): + # type: (bytes) -> bytes + bio_in = BIO.MemoryBuffer(text) + bio_out = BIO.MemoryBuffer() + if m2.smime_crlf_copy(bio_in._ptr(), bio_out._ptr()): + return bio_out.read() + else: + raise SMIME_Error(Err.get_error())
    + + +
    [docs]def text_crlf_bio(bio_in): + # type: (BIO.BIO) -> BIO.BIO + bio_out = BIO.MemoryBuffer() + if m2.smime_crlf_copy(bio_in._ptr(), bio_out._ptr()): + return bio_out + else: + raise SMIME_Error(Err.get_error())
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL.html b/doc/html/_modules/M2Crypto/SSL.html new file mode 100644 index 0000000..ff0aa7a --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL.html @@ -0,0 +1,145 @@ + + + + + + + + M2Crypto.SSL — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL

    +from __future__ import absolute_import
    +
    +"""M2Crypto SSL services.
    +
    +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
    +
    +import socket, os
    +
    +# M2Crypto
    +from M2Crypto import _m2crypto as m2
    +
    +
    +
    [docs]class SSLError(Exception): + pass
    + + +
    [docs]class SSLTimeoutError(SSLError, socket.timeout): + pass
    + +m2.ssl_init(SSLError, SSLTimeoutError) + +# M2Crypto.SSL +from M2Crypto.SSL.Cipher import Cipher, Cipher_Stack +from M2Crypto.SSL.Connection import Connection +from M2Crypto.SSL.Context import Context +from M2Crypto.SSL.SSLServer import SSLServer, ThreadingSSLServer +if os.name != 'nt': + from M2Crypto.SSL.SSLServer import ForkingSSLServer +from M2Crypto.SSL.ssl_dispatcher import ssl_dispatcher +from M2Crypto.SSL.timeout import timeout, struct_to_timeout, struct_size + +verify_none = m2.SSL_VERIFY_NONE # type: int +verify_peer = m2.SSL_VERIFY_PEER # type: int +verify_fail_if_no_peer_cert = m2.SSL_VERIFY_FAIL_IF_NO_PEER_CERT # type: int +verify_client_once = m2.SSL_VERIFY_CLIENT_ONCE # type: int + +SSL_SENT_SHUTDOWN = m2.SSL_SENT_SHUTDOWN # type: int +SSL_RECEIVED_SHUTDOWN = m2.SSL_RECEIVED_SHUTDOWN # type: int + +op_all = m2.SSL_OP_ALL # type: int +op_no_sslv2 = m2.SSL_OP_NO_SSLv2 # type: int +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/Checker.html b/doc/html/_modules/M2Crypto/SSL/Checker.html new file mode 100644 index 0000000..dc1aea8 --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/Checker.html @@ -0,0 +1,403 @@ + + + + + + + + M2Crypto.SSL.Checker — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.Checker

    +"""
    +SSL peer certificate checking routines
    +
    +Copyright (c) 2004-2007 Open Source Applications Foundation.
    +All rights reserved.
    +
    +Copyright 2008 Heikki Toivonen. All rights reserved.
    +"""
    +
    +__all__ = ['SSLVerificationError', 'NoCertificate', 'WrongCertificate',
    +           'WrongHost', 'Checker']
    +
    +import re
    +import socket
    +
    +from M2Crypto import X509, m2, six, util  # noqa
    +if util.py27plus:
    +    from typing import AnyStr, Optional  # noqa
    +
    +
    +
    [docs]class SSLVerificationError(Exception): + pass
    + + +
    [docs]class NoCertificate(SSLVerificationError): + pass
    + + +
    [docs]class WrongCertificate(SSLVerificationError): + pass
    + + +
    [docs]class WrongHost(SSLVerificationError): + def __init__(self, expectedHost, actualHost, fieldName='commonName'): + # type: (str, AnyStr, str) -> None + """ + This exception will be raised if the certificate returned by the + peer was issued for a different host than we tried to connect to. + This could be due to a server misconfiguration or an active attack. + + :param expectedHost: The name of the host we expected to find in the + certificate. + :param actualHost: The name of the host we actually found in the + certificate. + :param fieldName: The field name where we noticed the error. This + should be either 'commonName' or 'subjectAltName'. + """ + if fieldName not in ('commonName', 'subjectAltName'): + raise ValueError( + 'Unknown fieldName, should be either commonName ' + + 'or subjectAltName') + + SSLVerificationError.__init__(self) + self.expectedHost = expectedHost + self.actualHost = actualHost + self.fieldName = fieldName + + def __str__(self): + # type: () -> str + s = 'Peer certificate %s does not match host, expected %s, got %s' \ + % (self.fieldName, self.expectedHost, self.actualHost) + return six.ensure_text(s)
    + + +
    [docs]class Checker(object): + + numericIpMatch = re.compile('^[0-9]+(\.[0-9]+)*$') + + def __init__(self, host=None, peerCertHash=None, peerCertDigest='sha1'): + # type: (Optional[str], Optional[bytes], str) -> None + self.host = host + if peerCertHash is not None: + peerCertHash = six.ensure_binary(peerCertHash) + self.fingerprint = peerCertHash + self.digest = peerCertDigest # type: str + + def __call__(self, peerCert, host=None): + # type: (X509.X509, Optional[str]) -> bool + if peerCert is None: + raise NoCertificate('peer did not return certificate') + + if host is not None: + self.host = host # type: str + + if self.fingerprint: + if self.digest not in ('sha1', 'md5'): + raise ValueError('unsupported digest "%s"' % self.digest) + + if self.digest == 'sha1': + expected_len = 40 + elif self.digest == 'md5': + expected_len = 32 + else: + raise ValueError('Unexpected digest {0}'.format(self.digest)) + + if len(self.fingerprint) != expected_len: + raise WrongCertificate( + ('peer certificate fingerprint length does not match\n' + + 'fingerprint: {0}\nexpected = {1}\n' + + 'observed = {2}').format(self.fingerprint, + expected_len, + len(self.fingerprint))) + + expected_fingerprint = six.ensure_text(self.fingerprint) + observed_fingerprint = peerCert.get_fingerprint(md=self.digest) + if observed_fingerprint != expected_fingerprint: + raise WrongCertificate( + ('peer certificate fingerprint does not match\n' + + 'expected = {0},\n' + + 'observed = {1}').format(expected_fingerprint, + observed_fingerprint)) + + if self.host: + hostValidationPassed = False + self.useSubjectAltNameOnly = False + + # subjectAltName=DNS:somehost[, ...]* + try: + subjectAltName = peerCert.get_ext('subjectAltName').get_value() + if self._splitSubjectAltName(self.host, subjectAltName): + hostValidationPassed = True + elif self.useSubjectAltNameOnly: + raise WrongHost(expectedHost=self.host, + actualHost=subjectAltName, + fieldName='subjectAltName') + except LookupError: + pass + + # commonName=somehost[, ...]* + if not hostValidationPassed: + hasCommonName = False + commonNames = '' + for entry in peerCert.get_subject().get_entries_by_nid( + m2.NID_commonName): + hasCommonName = True + commonName = entry.get_data().as_text() + if not commonNames: + commonNames = commonName + else: + commonNames += ',' + commonName + if self._match(self.host, commonName): + hostValidationPassed = True + break + + if not hasCommonName: + raise WrongCertificate('no commonName in peer certificate') + + if not hostValidationPassed: + raise WrongHost(expectedHost=self.host, + actualHost=commonNames, + fieldName='commonName') + + return True + + def _splitSubjectAltName(self, host, subjectAltName): + # type: (AnyStr, AnyStr) -> bool + """ + >>> check = Checker() + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:my.example.com') + True + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:*.example.com') + True + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*.example.com') + True + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*ample.com') + False + >>> check.useSubjectAltNameOnly + True + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*ample.com, othername:<unsupported>') + False + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*ample.com, DNS:my.example.org') + False + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:m*ample.com, DNS:my.example.com') + True + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='DNS:my.example.com, DNS:my.example.org') + True + >>> check.useSubjectAltNameOnly + True + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='') + False + >>> check._splitSubjectAltName(host='my.example.com', + ... subjectAltName='othername:<unsupported>') + False + >>> check.useSubjectAltNameOnly + False + """ + self.useSubjectAltNameOnly = False + for certHost in subjectAltName.split(','): + certHost = certHost.lower().strip() + if certHost[:4] == 'dns:': + self.useSubjectAltNameOnly = True + if self._match(host, certHost[4:]): + return True + elif certHost[:11] == 'ip address:': + self.useSubjectAltNameOnly = True + if self._matchIPAddress(host, certHost[11:]): + return True + return False + + def _match(self, host, certHost): + # type: (str, str) -> bool + """ + >>> check = Checker() + >>> check._match(host='my.example.com', certHost='my.example.com') + True + >>> check._match(host='my.example.com', certHost='*.example.com') + True + >>> check._match(host='my.example.com', certHost='m*.example.com') + True + >>> check._match(host='my.example.com', certHost='m*.EXAMPLE.com') + True + >>> check._match(host='my.example.com', certHost='m*ample.com') + False + >>> check._match(host='my.example.com', certHost='*.*.com') + False + >>> check._match(host='1.2.3.4', certHost='1.2.3.4') + True + >>> check._match(host='1.2.3.4', certHost='*.2.3.4') + False + >>> check._match(host='1234', certHost='1234') + True + """ + # XXX See RFC 2818 and 3280 for matching rules, this is may not + # XXX yet be complete. + + host = host.lower() + certHost = certHost.lower() + + if host == certHost: + return True + + if certHost.count('*') > 1: + # Not sure about this, but being conservative + return False + + if self.numericIpMatch.match(host) or \ + self.numericIpMatch.match(certHost.replace('*', '')): + # Not sure if * allowed in numeric IP, but think not. + return False + + if certHost.find('\\') > -1: + # Not sure about this, maybe some encoding might have these. + # But being conservative for now, because regex below relies + # on this. + return False + + # Massage certHost so that it can be used in regex + certHost = certHost.replace('.', '\.') + certHost = certHost.replace('*', '[^\.]*') + if re.compile('^%s$' % certHost).match(host): + return True + + return False + + def _matchIPAddress(self, host, certHost): + # type: (AnyStr, AnyStr) -> bool + """ + >>> check = Checker() + >>> check._matchIPAddress(host='my.example.com', + ... certHost='my.example.com') + False + >>> check._matchIPAddress(host='1.2.3.4', certHost='1.2.3.4') + True + >>> check._matchIPAddress(host='1.2.3.4', certHost='*.2.3.4') + False + >>> check._matchIPAddress(host='1.2.3.4', certHost='1.2.3.40') + False + >>> check._matchIPAddress(host='::1', certHost='::1') + True + >>> check._matchIPAddress(host='::1', certHost='0:0:0:0:0:0:0:1') + True + >>> check._matchIPAddress(host='::1', certHost='::2') + False + """ + try: + canonical = socket.getaddrinfo(host, 0, 0, socket.SOCK_STREAM, 0, + socket.AI_NUMERICHOST) + certCanonical = socket.getaddrinfo(certHost, 0, 0, + socket.SOCK_STREAM, 0, + socket.AI_NUMERICHOST) + except: + return False + return canonical == certCanonical
    + + +if __name__ == '__main__': + import doctest + doctest.testmod() +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/Cipher.html b/doc/html/_modules/M2Crypto/SSL/Cipher.html new file mode 100644 index 0000000..d9a39b4 --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/Cipher.html @@ -0,0 +1,166 @@ + + + + + + + + M2Crypto.SSL.Cipher — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.Cipher

    +"""SSL Ciphers
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +__all__ = ['Cipher', 'Cipher_Stack']
    +
    +from M2Crypto import m2, py27plus, six
    +if py27plus:
    +    from typing import Iterable  # noqa
    +
    +
    +
    [docs]class Cipher(object): + def __init__(self, cipher): + # type: (str) -> None + self.cipher = cipher + + def __len__(self): + # type: () -> int + return m2.ssl_cipher_get_bits(self.cipher) + + def __repr__(self): + # type: () -> str + return "%s-%s" % (self.name(), len(self)) + + def __str__(self): + # type: () -> str + return "%s-%s" % (self.name(), len(self)) + +
    [docs] def version(self): + # type: () -> int + return m2.ssl_cipher_get_version(self.cipher)
    + +
    [docs] def name(self): + # type: () -> str + return six.ensure_text(m2.ssl_cipher_get_name(self.cipher))
    + + +
    [docs]class Cipher_Stack(object): + def __init__(self, stack): + # type: (bytes) -> None + """ + :param stack: binary of the C-type STACK_OF(SSL_CIPHER) + """ + self.stack = stack + + def __len__(self): + # type: () -> int + return m2.sk_ssl_cipher_num(self.stack) + + def __getitem__(self, idx): + # type: (int) -> Cipher + if not 0 <= idx < m2.sk_ssl_cipher_num(self.stack): + raise IndexError('index out of range') + v = m2.sk_ssl_cipher_value(self.stack, idx) + return Cipher(v) + + def __iter__(self): + # type: () -> Iterable + for i in six.moves.range(m2.sk_ssl_cipher_num(self.stack)): + yield self[i]
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/Connection.html b/doc/html/_modules/M2Crypto/SSL/Connection.html new file mode 100644 index 0000000..fcc8c69 --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/Connection.html @@ -0,0 +1,796 @@ + + + + + + + + M2Crypto.SSL.Connection — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.Connection

    +from __future__ import absolute_import
    +
    +"""SSL Connection aka socket
    +
    +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
    +
    +Portions created by Open Source Applications Foundation (OSAF) are
    +Copyright (C) 2004-2007 OSAF. All Rights Reserved.
    +
    +Copyright 2008 Heikki Toivonen. All rights reserved.
    +"""
    +
    +import logging
    +import socket
    +
    +from M2Crypto import BIO, Err, X509, m2, py27plus, six, util  # noqa
    +from M2Crypto.SSL import Checker, Context, timeout  # noqa
    +from M2Crypto.SSL import SSLError
    +from M2Crypto.SSL.Cipher import Cipher, Cipher_Stack
    +from M2Crypto.SSL.Session import Session
    +if py27plus:
    +    from typing import Any, AnyStr, Callable, Dict, List, Optional, Tuple, Union  # noqa
    +
    +__all__ = ['Connection',
    +           'timeout',  # XXX Not really, but for documentation purposes
    +           ]
    +
    +log = logging.getLogger(__name__)
    +
    +
    +def _serverPostConnectionCheck(*args, **kw):
    +    # type: (*Any, **Any) -> int
    +    return 1
    +
    +
    +
    [docs]class Connection(object): + """An SSL connection.""" + + clientPostConnectionCheck = Checker.Checker() + serverPostConnectionCheck = _serverPostConnectionCheck + + m2_bio_free = m2.bio_free + m2_ssl_free = m2.ssl_free + m2_bio_noclose = m2.bio_noclose + + def __init__(self, ctx, sock=None, family=socket.AF_INET): + # type: (Context, socket.socket, int) -> None + """ + + :param ctx: SSL.Context + :param sock: socket to be used + :param family: socket family + """ + self.ctx = ctx + self.ssl = m2.ssl_new(self.ctx.ctx) # type: bytes + if sock is not None: + self.socket = sock + else: + self.socket = socket.socket(family, socket.SOCK_STREAM) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._fileno = self.socket.fileno() + + self._timeout = self.socket.gettimeout() + if self._timeout is None: + self._timeout = -1.0 + + self.ssl_close_flag = m2.bio_noclose + + if self.ctx.post_connection_check is not None: + self.set_post_connection_check_callback( + self.ctx.post_connection_check) + + self.host = None + + def __del__(self): + # type: () -> None + # Notice that M2Crypto doesn't automatically shuts down the + # connection here. You have to call self.close() in your + # program, M2Crypto won't do it automatically for you. + if getattr(self, 'sslbio', None): + self.m2_bio_free(self.sslbio) + if getattr(self, 'sockbio', None): + self.m2_bio_free(self.sockbio) + if self.ssl_close_flag == self.m2_bio_noclose and \ + getattr(self, 'ssl', None): + self.m2_ssl_free(self.ssl) + self.socket.close() + +
    [docs] def close(self): + # type: () -> None + m2.ssl_shutdown(self.ssl)
    + +
    [docs] def clear(self): + # type: () -> int + """ + If there were errors in this connection, call clear() rather + than close() to end it, so that bad sessions will be cleared + from cache. + """ + return m2.ssl_clear(self.ssl)
    + +
    [docs] def set_shutdown(self, mode): + # type: (int) -> None + """Sets the shutdown state of the Connection to mode. + + The shutdown state of an ssl connection is a bitmask of (use + m2.SSL_* constants): + + 0 No shutdown setting, yet. + + SSL_SENT_SHUTDOWN + A "close notify" shutdown alert was sent to the peer, the + connection is being considered closed and the session is + closed and correct. + + SSL_RECEIVED_SHUTDOWN + A shutdown alert was received form the peer, either a normal + "close notify" or a fatal error. + + SSL_SENT_SHUTDOWN and SSL_RECEIVED_SHUTDOWN can be set at the + same time. + + :param mode: set the mode bitmask. + """ + m2.ssl_set_shutdown1(self.ssl, mode)
    + +
    [docs] def get_shutdown(self): + # type: () -> None + """Get the current shutdown mode of the Connection.""" + return m2.ssl_get_shutdown(self.ssl)
    + +
    [docs] def bind(self, addr): + # type: (util.AddrType) -> None + self.socket.bind(addr)
    + +
    [docs] def listen(self, qlen=5): + # type: (int) -> None + self.socket.listen(qlen)
    + +
    [docs] def ssl_get_error(self, ret): + # type: (int) -> int + return m2.ssl_get_error(self.ssl, ret)
    + +
    [docs] def set_bio(self, readbio, writebio): + # type: (BIO.BIO, BIO.BIO) -> None + """Explicitly set read and write bios + + Connects the BIOs for the read and write operations of the + TLS/SSL (encrypted) side of ssl. + + The SSL engine inherits the behaviour of both BIO objects, + respectively. If a BIO is non-blocking, the Connection will also + have non-blocking behaviour. + + If there was already a BIO connected to Connection, BIO_free() + will be called (for both the reading and writing side, if + different). + + :param readbio: BIO for reading + :param writebio: BIO for writing. + """ + m2.ssl_set_bio(self.ssl, readbio._ptr(), writebio._ptr())
    + +
    [docs] def set_client_CA_list_from_file(self, cafile): + # type: (AnyStr) -> None + """Set the acceptable client CA list. + + If the client returns a certificate, it must have been issued by + one of the CAs listed in cafile. + + Makes sense only for servers. + + :param cafile: Filename from which to load the CA list. + + :return: 0 A failure while manipulating the STACK_OF(X509_NAME) + object occurred or the X509_NAME could not be + extracted from cacert. Check the error stack to find + out the reason. + + 1 The operation succeeded. + """ + m2.ssl_set_client_CA_list_from_file(self.ssl, cafile)
    + +
    [docs] def set_client_CA_list_from_context(self): + # type: () -> None + """ + Set the acceptable client CA list. If the client + returns a certificate, it must have been issued by + one of the CAs listed in context. + + Makes sense only for servers. + """ + m2.ssl_set_client_CA_list_from_context(self.ssl, self.ctx.ctx)
    + +
    [docs] def setup_addr(self, addr): + # type: (util.AddrType) -> None + self.addr = addr
    + +
    [docs] def set_ssl_close_flag(self, flag): + # type: (int) -> None + """ + By default, SSL struct will be freed in __del__. Call with + m2.bio_close to override this default. + + :param flag: either m2.bio_close or m2.bio_noclose + """ + if flag not in (m2.bio_close, m2.bio_noclose): + raise ValueError("flag must be m2.bio_close or m2.bio_noclose") + self.ssl_close_flag = flag
    + +
    [docs] def setup_ssl(self): + # type: () -> None + # Make a BIO_s_socket. + self.sockbio = m2.bio_new_socket(self.socket.fileno(), 0) + # Link SSL struct with the BIO_socket. + m2.ssl_set_bio(self.ssl, self.sockbio, self.sockbio) + # Make a BIO_f_ssl. + self.sslbio = m2.bio_new(m2.bio_f_ssl()) + # Link BIO_f_ssl with the SSL struct. + m2.bio_set_ssl(self.sslbio, self.ssl, m2.bio_noclose)
    + + def _setup_ssl(self, addr): + # type: (util.AddrType) -> None + """Deprecated""" + self.setup_addr(addr) + self.setup_ssl() + +
    [docs] def set_accept_state(self): + # type: () -> None + """Sets Connection to work in the server mode.""" + m2.ssl_set_accept_state(self.ssl)
    + +
    [docs] def accept_ssl(self): + # type: () -> Optional[int] + """Waits for a TLS/SSL client to initiate the TLS/SSL handshake. + + The communication channel must already have been set and + assigned to the ssl by setting an underlying BIO. + + :return: 0 The TLS/SSL handshake was not successful but was shut + down controlled and by the specifications of the + TLS/SSL protocol. Call get_error() with the return + value ret to find out the reason. + + 1 The TLS/SSL handshake was successfully completed, + a TLS/SSL connection has been established. + + <0 The TLS/SSL handshake was not successful because + a fatal error occurred either at the protocol level + or a connection failure occurred. The shutdown was + not clean. It can also occur of action is need to + continue the operation for non-blocking BIOs. Call + get_error() with the return value ret to find + out the reason. + """ + return m2.ssl_accept(self.ssl, self._timeout)
    + +
    [docs] def accept(self): + # type: () -> Tuple[Connection, util.AddrType] + """Accept an SSL connection. + + The return value is a pair (ssl, addr) where ssl is a new SSL + connection object and addr is the address bound to the other end + of the SSL connection. + + :return: tuple of Connection and addr. Address can take very + various forms (see socket documentation), for IPv4 it + is tuple(str, int), for IPv6 a tuple of four (host, + port, flowinfo, scopeid), where the last two are + optional ints. + """ + sock, addr = self.socket.accept() + ssl = Connection(self.ctx, sock) + ssl.addr = addr + ssl.setup_ssl() + ssl.set_accept_state() + ssl.accept_ssl() + check = getattr(self, 'postConnectionCheck', + self.serverPostConnectionCheck) + if check is not None: + if not check(ssl.get_peer_cert(), ssl.addr[0]): + raise Checker.SSLVerificationError( + 'post connection check failed') + return ssl, addr
    + +
    [docs] def set_connect_state(self): + # type: () -> None + """Sets Connection to work in the client mode.""" + m2.ssl_set_connect_state(self.ssl)
    + +
    [docs] def connect_ssl(self): + # type: () -> Optional[int] + return m2.ssl_connect(self.ssl, self._timeout)
    + +
    [docs] def connect(self, addr): + # type: (util.AddrType) -> int + """Overloading socket.connect() + + :param addr: addresses have various depending on their type + + :return:status of ssl_connect() + """ + self.socket.connect(addr) + self.addr = addr + self.setup_ssl() + self.set_connect_state() + ret = self.connect_ssl() + check = getattr(self, 'postConnectionCheck', + self.clientPostConnectionCheck) + if check is not None: + if not check(self.get_peer_cert(), + self.host if self.host else self.addr[0]): + raise Checker.SSLVerificationError( + 'post connection check failed') + return ret
    + +
    [docs] def shutdown(self, how): + # type: (int) -> None + m2.ssl_set_shutdown(self.ssl, how)
    + +
    [docs] def renegotiate(self): + # type: () -> int + """Renegotiate this connection's SSL parameters.""" + return m2.ssl_renegotiate(self.ssl)
    + +
    [docs] def pending(self): + # type: () -> int + """Return the numbers of octets that can be read from the connection.""" + return m2.ssl_pending(self.ssl)
    + + def _write_bio(self, data): + # type: (bytes) -> int + return m2.ssl_write(self.ssl, data, self._timeout) + + def _write_nbio(self, data): + # type: (bytes) -> int + return m2.ssl_write_nbio(self.ssl, data) + + def _read_bio(self, size=1024): + # type: (int) -> bytes + if size <= 0: + raise ValueError('size <= 0') + return m2.ssl_read(self.ssl, size, self._timeout) + + def _read_nbio(self, size=1024): + # type: (int) -> bytes + if size <= 0: + raise ValueError('size <= 0') + return m2.ssl_read_nbio(self.ssl, size) + +
    [docs] def write(self, data): + # type: (bytes) -> int + if self._timeout != 0.0: + return self._write_bio(data) + return self._write_nbio(data)
    + sendall = send = write + + def _decref_socketios(self): + pass + +
    [docs] def recv_into(self, buff, nbytes=0): + # type: (Union[bytearray, memoryview], int) -> int + """ + A version of recv() that stores its data into a buffer rather + than creating a new string. Receive up to buffersize bytes from + the socket. If buffersize is not specified (or 0), receive up + to the size available in the given buffer. + + If buff is bytearray, it will have after return length of the + actually returned number of bytes. If buff is memoryview, then + the size of buff won't change (it cannot), but all bytes after + the number of returned bytes will be NULL. + + :param buffer: a buffer for the received bytes + :param nbytes: maximum number of bytes to read + :return: number of bytes read + + See recv() for documentation about the flags. + """ + n = len(buff) if nbytes == 0 else nbytes + + if n <= 0: + raise ValueError('size <= 0') + + # buff_bytes are actual bytes returned + buff_bytes = m2.ssl_read(self.ssl, n, self._timeout) + buflen = len(buff_bytes) + + # memoryview type has been added in 2.7 + if py27plus and isinstance(buff, memoryview): + buff[:buflen] = buff_bytes + buff[buflen:] = b'\x00' * (len(buff) - buflen) + else: + buff[:] = buff_bytes + + return buflen
    + +
    [docs] def read(self, size=1024): + # type: (int) -> bytes + if self._timeout != 0.0: + return self._read_bio(size) + return self._read_nbio(size)
    + recv = read + +
    [docs] def setblocking(self, mode): + # type: (int) -> None + """Set this connection's underlying socket to _mode_. + + Set blocking or non-blocking mode of the socket: if flag is 0, + the socket is set to non-blocking, else to blocking mode. + Initially all sockets are in blocking mode. In non-blocking mode, + if a recv() call doesn't find any data, or if a send() call can't + immediately dispose of the data, a error exception is raised; + in blocking mode, the calls block until they can proceed. + s.setblocking(0) is equivalent to s.settimeout(0.0); + s.setblocking(1) is equivalent to s.settimeout(None). + + :param mode: new mode to be set + """ + self.socket.setblocking(mode) + if mode: + self._timeout = -1.0 + else: + self._timeout = 0.0
    + +
    [docs] def settimeout(self, timeout): + # type: (float) -> None + """Set this connection's underlying socket's timeout to _timeout_.""" + self.socket.settimeout(timeout) + self._timeout = timeout + if self._timeout is None: + self._timeout = -1.0
    + +
    [docs] def fileno(self): + # type: () -> int + return self.socket.fileno()
    + +
    [docs] def getsockopt(self, level, optname, buflen=None): + # type: (int, int, Optional[int]) -> Union[int, bytes] + """Get the value of the given socket option. + + :param level: level at which the option resides. + To manipulate options at the sockets API level, level is + specified as socket.SOL_SOCKET. To manipulate options at + any other level the protocol number of the appropriate + protocol controlling the option is supplied. For example, + to indicate that an option is to be interpreted by the + TCP protocol, level should be set to the protocol number + of socket.SOL_TCP; see getprotoent(3). + + :param optname: The value of the given socket option is + described in the Unix man page getsockopt(2)). The needed + symbolic constants (SO_* etc.) are defined in the socket + module. + + :param buflen: If it is absent, an integer option is assumed + and its integer value is returned by the function. If + buflen is present, it specifies the maximum length of the + buffer used to receive the option in, and this buffer is + returned as a bytes object. + + :return: Either integer or bytes value of the option. It is up + to the caller to decode the contents of the buffer (see + the optional built-in module struct for a way to decode + C structures encoded as byte strings). + """ + return self.socket.getsockopt(level, optname, buflen)
    + +
    [docs] def setsockopt(self, level, optname, value=None): + # type: (int, int, Union[int, bytes, None]) -> Optional[bytes] + """Set the value of the given socket option. + + :param level: same as with getsockopt() above + + :param optname: same as with getsockopt() above + + :param value: an integer or a string representing a buffer. In + the latter case it is up to the caller to ensure + that the string contains the proper bits (see the + optional built-in module struct for a way to + encode C structures as strings). + + :return: None for success or the error handler for failure. + """ + return self.socket.setsockopt(level, optname, value)
    + +
    [docs] def get_context(self): + # type: () -> Context + """Return the Context object associated with this connection.""" + return m2.ssl_get_ssl_ctx(self.ssl)
    + +
    [docs] def get_state(self): + # type: () -> bytes + """Return the SSL state of this connection. + + During its use, an SSL objects passes several states. The state + is internally maintained. Querying the state information is not + very informative before or when a connection has been + established. It however can be of significant interest during + the handshake. + + :return: 6 letter string indicating the current state of the SSL + object ssl. + """ + return m2.ssl_get_state(self.ssl)
    + +
    [docs] def verify_ok(self): + # type: () -> bool + return (m2.ssl_get_verify_result(self.ssl) == m2.X509_V_OK)
    + +
    [docs] def get_verify_mode(self): + # type: () -> int + """Return the peer certificate verification mode.""" + return m2.ssl_get_verify_mode(self.ssl)
    + +
    [docs] def get_verify_depth(self): + # type: () -> int + """Return the peer certificate verification depth.""" + return m2.ssl_get_verify_depth(self.ssl)
    + +
    [docs] def get_verify_result(self): + # type: () -> int + """Return the peer certificate verification result.""" + return m2.ssl_get_verify_result(self.ssl)
    + +
    [docs] def get_peer_cert(self): + # type: () -> X509.X509 + """Return the peer certificate. + + If the peer did not provide a certificate, return None. + """ + c = m2.ssl_get_peer_cert(self.ssl) + if c is None: + return None + # Need to free the pointer coz OpenSSL doesn't. + return X509.X509(c, 1)
    + +
    [docs] def get_peer_cert_chain(self): + # type: () -> Optional[X509.X509_Stack] + """Return the peer certificate chain; if the peer did not provide + a certificate chain, return None. + + :warning: The returned chain will be valid only for as long as the + connection object is alive. Once the connection object + gets freed, the chain will be freed as well. + """ + c = m2.ssl_get_peer_cert_chain(self.ssl) + if c is None: + return None + # No need to free the pointer coz OpenSSL does. + return X509.X509_Stack(c)
    + +
    [docs] def get_cipher(self): + # type: () -> Optional[Cipher] + """Return an M2Crypto.SSL.Cipher object for this connection; if the + connection has not been initialised with a cipher suite, return None. + """ + c = m2.ssl_get_current_cipher(self.ssl) + if c is None: + return None + return Cipher(c)
    + +
    [docs] def get_ciphers(self): + # type: () -> Optional[Cipher_Stack] + """Return an M2Crypto.SSL.Cipher_Stack object for this + connection; if the connection has not been initialised with + cipher suites, return None. + """ + c = m2.ssl_get_ciphers(self.ssl) + if c is None: + return None + return Cipher_Stack(c)
    + +
    [docs] def get_cipher_list(self, idx=0): + # type: (int) -> str + """Return the cipher suites for this connection as a string object.""" + return six.ensure_text(m2.ssl_get_cipher_list(self.ssl, idx))
    + +
    [docs] def set_cipher_list(self, cipher_list): + # type: (str) -> int + """Set the cipher suites for this connection.""" + return m2.ssl_set_cipher_list(self.ssl, cipher_list)
    + +
    [docs] def makefile(self, mode='rb', bufsize=-1): + # type: (AnyStr, int) -> socket._fileobject + if six.PY3: + return socket.SocketIO(self, mode) + else: + return socket._fileobject(self, mode, bufsize)
    + +
    [docs] def getsockname(self): + # type: () -> util.AddrType + """Return the socket's own address. + + This is useful to find out the port number of an IPv4/v6 socket, + for instance. (The format of the address returned depends + on the address family -- see above.) + + :return:socket's address as addr type + """ + return self.socket.getsockname()
    + +
    [docs] def getpeername(self): + # type: () -> util.AddrType + """Return the remote address to which the socket is connected. + + This is useful to find out the port number of a remote IPv4/v6 socket, + for instance. + On some systems this function is not supported. + + :return: + """ + return self.socket.getpeername()
    + +
    [docs] def set_session_id_ctx(self, id): + # type: (bytes) -> int + ret = m2.ssl_set_session_id_context(self.ssl, id) + if not ret: + raise SSLError(Err.get_error_message())
    + +
    [docs] def get_session(self): + # type: () -> Session + sess = m2.ssl_get_session(self.ssl) + return Session(sess)
    + +
    [docs] def set_session(self, session): + # type: (Session) -> None + m2.ssl_set_session(self.ssl, session._ptr())
    + +
    [docs] def get_default_session_timeout(self): + # type: () -> int + return m2.ssl_get_default_session_timeout(self.ssl)
    + +
    [docs] def get_socket_read_timeout(self): + # type: () -> timeout + return timeout.struct_to_timeout( + self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, + timeout.struct_size()))
    + + @staticmethod + def _hexdump(s): + assert isinstance(s, six.binary_type) + return ":".join("{0:02x}".format(ord(c) if six.PY2 else c) for c in s) + +
    [docs] def get_socket_write_timeout(self): + # type: () -> timeout + binstr = self.socket.getsockopt( + socket.SOL_SOCKET, socket.SO_SNDTIMEO, timeout.struct_size()) + timeo = timeout.struct_to_timeout(binstr) + #print("Debug: get_socket_write_timeout: " + # "get sockopt value: %s -> returned timeout(sec=%r, microsec=%r)" % + # (self._hexdump(binstr), timeo.sec, timeo.microsec)) + return timeo
    + +
    [docs] def set_socket_read_timeout(self, timeo): + # type: (timeout) -> None + assert isinstance(timeo, timeout.timeout) + self.socket.setsockopt( + socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeo.pack())
    + +
    [docs] def set_socket_write_timeout(self, timeo): + # type: (timeout) -> None + assert isinstance(timeo, timeout.timeout) + binstr = timeo.pack() + #print("Debug: set_socket_write_timeout: " + # "input timeout(sec=%r, microsec=%r) -> set sockopt value: %s" % + # (timeo.sec, timeo.microsec, self._hexdump(binstr))) + self.socket.setsockopt( + socket.SOL_SOCKET, socket.SO_SNDTIMEO, binstr)
    + +
    [docs] def get_version(self): + # type: () -> str + """Return the TLS/SSL protocol version for this connection.""" + return six.ensure_text(m2.ssl_get_version(self.ssl))
    + +
    [docs] def set_post_connection_check_callback(self, postConnectionCheck): # noqa + # type: (Callable) -> None + self.postConnectionCheck = postConnectionCheck
    + +
    [docs] def set_tlsext_host_name(self, name): + # type: (bytes) -> None + """Set the requested hostname for the SNI (Server Name Indication) + extension. + """ + m2.ssl_set_tlsext_host_name(self.ssl, name)
    + +
    [docs] def set1_host(self, name): + # type: (bytes) -> None + """Set the requested hostname to check in the server certificate.""" + self.host = name
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/Context.html b/doc/html/_modules/M2Crypto/SSL/Context.html new file mode 100644 index 0000000..f61a146 --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/Context.html @@ -0,0 +1,552 @@ + + + + + + + + M2Crypto.SSL.Context — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.Context

    +from __future__ import absolute_import
    +
    +"""SSL Context
    +
    +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
    +
    +from M2Crypto import BIO, Err, RSA, X509, m2, util  # noqa
    +from M2Crypto.SSL import cb  # noqa
    +from M2Crypto.SSL.Session import Session  # noqa
    +from weakref import WeakValueDictionary
    +if util.py27plus:
    +    from typing import Any, AnyStr, Callable, Optional, Union  # noqa
    +
    +__all__ = ['ctxmap', 'Context', 'map']
    +
    +
    +class _ctxmap(object):
    +    singleton = None  # type: Optional[_ctxmap]
    +
    +    def __init__(self):
    +        # type: () -> None
    +        """Simple WeakReffed list.
    +        """
    +        self._ctxmap = WeakValueDictionary()
    +
    +    def __getitem__(self, key):
    +        # type: (int) -> Any
    +        return self._ctxmap[key]
    +
    +    def __setitem__(self, key, value):
    +        # type: (int, Any) -> None
    +        self._ctxmap[key] = value
    +
    +    def __delitem__(self, key):
    +        # type: (int) -> None
    +        del self._ctxmap[key]
    +
    +
    +
    [docs]def ctxmap(): + # type: () -> _ctxmap + if _ctxmap.singleton is None: + _ctxmap.singleton = _ctxmap() + return _ctxmap.singleton
    +# deprecated!!! +map = ctxmap + + +
    [docs]class Context(object): + + """'Context' for SSL connections.""" + + m2_ssl_ctx_free = m2.ssl_ctx_free + + def __init__(self, protocol='tls', weak_crypto=None, + post_connection_check=None): + # type: (str, Optional[int], Optional[Callable]) -> None + proto = getattr(m2, protocol + '_method', None) + if proto is None: + # default is 'sslv23' for older versions of OpenSSL + if protocol == 'tls': + proto = getattr(m2, 'sslv23_method') + else: + raise ValueError("no such protocol '%s'" % protocol) + self.ctx = m2.ssl_ctx_new(proto()) + self.allow_unknown_ca = 0 # type: Union[int, bool] + self.post_connection_check = post_connection_check + ctxmap()[int(self.ctx)] = self + m2.ssl_ctx_set_cache_size(self.ctx, 128) + if weak_crypto is None and protocol in ('sslv23', 'tls'): + self.set_options(m2.SSL_OP_ALL | m2.SSL_OP_NO_SSLv2 | + m2.SSL_OP_NO_SSLv3) + + def __del__(self): + # type: () -> None + if getattr(self, 'ctx', None): + self.m2_ssl_ctx_free(self.ctx) + +
    [docs] def close(self): + # type: () -> None + del ctxmap()[int(self.ctx)]
    + +
    [docs] def load_cert(self, certfile, keyfile=None, + callback=util.passphrase_callback): + # type: (AnyStr, Optional[AnyStr], Callable) -> None + """Load certificate and private key into the context. + + :param certfile: File that contains the PEM-encoded certificate. + :param keyfile: File that contains the PEM-encoded private key. + Default value of None indicates that the private key + is to be found in 'certfile'. + :param callback: Callable object to be invoked if the private key is + passphrase-protected. Default callback provides a + simple terminal-style input for the passphrase. + """ + m2.ssl_ctx_passphrase_callback(self.ctx, callback) + m2.ssl_ctx_use_cert(self.ctx, certfile) + if not keyfile: + keyfile = certfile + m2.ssl_ctx_use_privkey(self.ctx, keyfile) + if not m2.ssl_ctx_check_privkey(self.ctx): + raise ValueError('public/private key mismatch')
    + +
    [docs] def load_cert_chain(self, certchainfile, keyfile=None, + callback=util.passphrase_callback): + # type: (AnyStr, Optional[AnyStr], Callable) -> None + """Load certificate chain and private key into the context. + + :param certchainfile: File object containing the PEM-encoded + certificate chain. + :param keyfile: File object containing the PEM-encoded private + key. Default value of None indicates that the + private key is to be found in 'certchainfile'. + :param callback: Callable object to be invoked if the private key + is passphrase-protected. Default callback + provides a simple terminal-style input for the + passphrase. + """ + m2.ssl_ctx_passphrase_callback(self.ctx, callback) + m2.ssl_ctx_use_cert_chain(self.ctx, certchainfile) + if not keyfile: + keyfile = certchainfile + m2.ssl_ctx_use_privkey(self.ctx, keyfile) + if not m2.ssl_ctx_check_privkey(self.ctx): + raise ValueError('public/private key mismatch')
    + +
    [docs] def set_client_CA_list_from_file(self, cafile): + # type: (AnyStr) -> None + """Load CA certs into the context. These CA certs are sent to the + peer during *SSLv3 certificate request*. + + :param cafile: File object containing one or more PEM-encoded CA + certificates concatenated together. + """ + m2.ssl_ctx_set_client_CA_list_from_file(self.ctx, cafile)
    + + # Deprecated. + load_client_CA = load_client_ca = set_client_CA_list_from_file + +
    [docs] def load_verify_locations(self, cafile=None, capath=None): + # type: (Optional[AnyStr], Optional[AnyStr]) -> int + """Load CA certs into the context. + + These CA certs are used during verification of the peer's + certificate. + + :param cafile: File containing one or more PEM-encoded CA + certificates concatenated together. + + :param capath: Directory containing PEM-encoded CA certificates + (one certificate per file). + + :return: 0 if the operation failed because CAfile and CApath are NULL + or the processing at one of the locations specified failed. + Check the error stack to find out the reason. + + 1 The operation succeeded. + """ + if cafile is None and capath is None: + raise ValueError("cafile and capath can not both be None.") + return m2.ssl_ctx_load_verify_locations(self.ctx, cafile, capath)
    + + # Deprecated. + load_verify_info = load_verify_locations + +
    [docs] def set_session_id_ctx(self, id): + # type: (bytes) -> None + """Sets the session id for the SSL.Context w/in a session can be reused. + + :param id: Sessions are generated within a certain context. When + exporting/importing sessions with + i2d_SSL_SESSION/d2i_SSL_SESSION it would be possible, + to re-import a session generated from another context + (e.g. another application), which might lead to + malfunctions. Therefore each application must set its + own session id context sid_ctx which is used to + distinguish the contexts and is stored in exported + sessions. The sid_ctx can be any kind of binary data + with a given length, it is therefore possible to use + e.g. the name of the application and/or the hostname + and/or service name. + """ + ret = m2.ssl_ctx_set_session_id_context(self.ctx, id) + if not ret: + raise Err.SSLError(Err.get_error_code(), '')
    + +
    [docs] def set_default_verify_paths(self): + # type: () -> int + """ + Specifies that the default locations from which CA certs are + loaded should be used. + + There is one default directory and one default file. The default + CA certificates directory is called "certs" in the default + OpenSSL directory. Alternatively the SSL_CERT_DIR environment + variable can be defined to override this location. The default + CA certificates file is called "cert.pem" in the default OpenSSL + directory. Alternatively the SSL_CERT_FILE environment variable + can be defined to override this location. + + @return 0 if the operation failed. A missing default location is + still treated as a success. No error code is set. + + 1 The operation succeeded. + """ + ret = m2.ssl_ctx_set_default_verify_paths(self.ctx) + if not ret: + raise ValueError('Cannot use default SSL certificate store!')
    + +
    [docs] def set_allow_unknown_ca(self, ok): + # type: (Union[int, bool]) -> None + """Set the context to accept/reject a peer certificate if the + certificate's CA is unknown. + + :param ok: True to accept, False to reject. + """ + self.allow_unknown_ca = ok
    + +
    [docs] def get_allow_unknown_ca(self): + # type: () -> Union[int, bool] + """Get the context's setting that accepts/rejects a peer + certificate if the certificate's CA is unknown. + + FIXME 2Bconverted to bool + """ + return self.allow_unknown_ca
    + +
    [docs] def set_verify(self, mode, depth, callback=None): + # type: (int, int, Optional[Callable]) -> None + """ + Set verify options. Most applications will need to call this + method with the right options to make a secure SSL connection. + + :param mode: The verification mode to use. Typically at least + SSL.verify_peer is used. Clients would also typically + add SSL.verify_fail_if_no_peer_cert. + :param depth: The maximum allowed depth of the certificate chain + returned by the peer. + :param callback: Callable that can be used to specify custom + verification checks. + """ + if callback is None: + m2.ssl_ctx_set_verify_default(self.ctx, mode) + else: + m2.ssl_ctx_set_verify(self.ctx, mode, callback) + m2.ssl_ctx_set_verify_depth(self.ctx, depth)
    + +
    [docs] def get_verify_mode(self): + # type: () -> int + return m2.ssl_ctx_get_verify_mode(self.ctx)
    + +
    [docs] def get_verify_depth(self): + # type: () -> int + """Returns the verification mode currently set in the SSL Context.""" + return m2.ssl_ctx_get_verify_depth(self.ctx)
    + +
    [docs] def set_tmp_dh(self, dhpfile): + # type: (AnyStr) -> int + """Load ephemeral DH parameters into the context. + + :param dhpfile: Filename of the file containing the PEM-encoded + DH parameters. + """ + f = BIO.openfile(dhpfile) + dhp = m2.dh_read_parameters(f.bio_ptr()) + return m2.ssl_ctx_set_tmp_dh(self.ctx, dhp)
    + +
    [docs] def set_tmp_dh_callback(self, callback=None): + # type: (Optional[Callable]) -> None + """Sets the callback function for SSL.Context. + + :param callback: Callable to be used when a DH parameters are required. + """ + if callback is not None: + m2.ssl_ctx_set_tmp_dh_callback(self.ctx, callback)
    + +
    [docs] def set_tmp_rsa(self, rsa): + # type: (RSA.RSA) -> int + """Load ephemeral RSA key into the context. + + :param rsa: RSA.RSA instance. + """ + if isinstance(rsa, RSA.RSA): + return m2.ssl_ctx_set_tmp_rsa(self.ctx, rsa.rsa) + else: + raise TypeError("Expected an instance of RSA.RSA, got %s." % rsa)
    + +
    [docs] def set_tmp_rsa_callback(self, callback=None): + # type: (Optional[Callable]) -> None + """Sets the callback function to be used when + a temporary/ephemeral RSA key is required. + """ + if callback is not None: + m2.ssl_ctx_set_tmp_rsa_callback(self.ctx, callback)
    + +
    [docs] def set_info_callback(self, callback=cb.ssl_info_callback): + # type: (Callable) -> None + """Set a callback function to get state information. + + It can be used to get state information about the SSL + connections that are created from this context. + + :param callback: Callback function. The default prints + information to stderr. + """ + m2.ssl_ctx_set_info_callback(self.ctx, callback)
    + +
    [docs] def set_cipher_list(self, cipher_list): + # type: (str) -> int + """Sets the list of available ciphers. + + :param cipher_list: The format of the string is described in + ciphers(1). + :return: 1 if any cipher could be selected and 0 on complete + failure. + """ + return m2.ssl_ctx_set_cipher_list(self.ctx, cipher_list)
    + +
    [docs] def add_session(self, session): + # type: (Session) -> int + """Add the session to the context. + + :param session: the session to be added. + + :return: 0 The operation failed. It was tried to add the same + (identical) session twice. + + 1 The operation succeeded. + """ + return m2.ssl_ctx_add_session(self.ctx, session._ptr())
    + +
    [docs] def remove_session(self, session): + # type: (Session) -> int + """Remove the session from the context. + + :param session: the session to be removed. + + :return: 0 The operation failed. The session was not found in + the cache. + + 1 The operation succeeded. + """ + return m2.ssl_ctx_remove_session(self.ctx, session._ptr())
    + +
    [docs] def get_session_timeout(self): + # type: () -> int + """Get current session timeout. + + Whenever a new session is created, it is assigned a maximum + lifetime. This lifetime is specified by storing the creation + time of the session and the timeout value valid at this time. If + the actual time is later than creation time plus timeout, the + session is not reused. + + Due to this realization, all sessions behave according to the + timeout value valid at the time of the session negotiation. + Changes of the timeout value do not affect already established + sessions. + + Expired sessions are removed from the internal session cache, + whenever SSL_CTX_flush_sessions(3) is called, either directly by + the application or automatically (see + SSL_CTX_set_session_cache_mode(3)) + + The default value for session timeout is decided on a per + protocol basis, see SSL_get_default_timeout(3). All currently + supported protocols have the same default timeout value of 300 + seconds. + + SSL_CTX_set_timeout() returns the previously set timeout value. + + :return: the currently set timeout value. + """ + return m2.ssl_ctx_get_session_timeout(self.ctx)
    + +
    [docs] def set_session_timeout(self, timeout): + # type: (int) -> int + """Set new session timeout. + + See self.get_session_timeout() for explanation of the session + timeouts. + + :param timeout: new timeout value. + + :return: the previously set timeout value. + """ + return m2.ssl_ctx_set_session_timeout(self.ctx, timeout)
    + +
    [docs] def set_session_cache_mode(self, mode): + # type: (int) -> int + """Enables/disables session caching. + + The mode is set by using m2.SSL_SESS_CACHE_* constants. + + :param mode: new mode value. + + :return: the previously set cache mode value. + """ + return m2.ssl_ctx_set_session_cache_mode(self.ctx, mode)
    + +
    [docs] def get_session_cache_mode(self): + # type: () -> int + """Gets the current session caching. + + The mode is set to m2.SSL_SESS_CACHE_* constants. + + :return: the previously set cache mode value. + """ + return m2.ssl_ctx_get_session_cache_mode(self.ctx)
    + +
    [docs] def set_options(self, op): + # type: (int) -> int + """Adds the options set via bitmask in options to the Context. + + !!! Options already set before are not cleared! + + The behaviour of the SSL library can be changed by setting + several options. The options are coded as bitmasks and can be + combined by a logical or operation (|). + + SSL.Context.set_options() and SSL.set_options() affect the + (external) protocol behaviour of the SSL library. The (internal) + behaviour of the API can be changed by using the similar + SSL.Context.set_mode() and SSL.set_mode() functions. + + During a handshake, the option settings of the SSL object are + used. When a new SSL object is created from a context using + SSL(), the current option setting is copied. Changes to ctx + do not affect already created SSL objects. SSL.clear() does not + affect the settings. + + :param op: bitmask of additional options specified in + SSL_CTX_set_options(3) manpage. + + :return: the new options bitmask after adding options. + """ + return m2.ssl_ctx_set_options(self.ctx, op)
    + +
    [docs] def get_cert_store(self): + # type: () -> X509.X509 + """ + Get the certificate store associated with this context. + + :warning: The store is NOT refcounted, and as such can not be relied + to be valid once the context goes away or is changed. + """ + return X509.X509_Store(m2.ssl_ctx_get_cert_store(self.ctx))
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/SSLServer.html b/doc/html/_modules/M2Crypto/SSL/SSLServer.html new file mode 100644 index 0000000..3abb777 --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/SSLServer.html @@ -0,0 +1,172 @@ + + + + + + + + M2Crypto.SSL.SSLServer — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.SSLServer

    +from __future__ import absolute_import, print_function
    +
    +"""SSLServer
    +
    +Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved."""
    +
    +
    +# M2Crypto
    +from M2Crypto.SSL import SSLError
    +from M2Crypto.SSL.Connection import Connection
    +from M2Crypto.SSL.Context import Context  # noqa
    +from M2Crypto import six  # noqa
    +from M2Crypto import util  # noqa
    +from M2Crypto.six.moves.socketserver import (BaseServer, TCPServer,
    +                                             ThreadingMixIn)
    +import os
    +if os.name != 'nt':
    +   from M2Crypto.six.moves.socketserver import ForkingMixIn
    +from socket import socket  # noqa
    +if util.py27plus:
    +    from typing import Union  # noqa
    +
    +__all__ = ['SSLServer', 'ForkingSSLServer', 'ThreadingSSLServer']
    +
    +
    +
    [docs]class SSLServer(TCPServer): + def __init__(self, server_address, RequestHandlerClass, ssl_context, # noqa + bind_and_activate=True): + # type: (util.AddrType, socketserver.BaseRequestHandler, Context, bool) -> None + """ + Superclass says: Constructor. May be extended, do not override. + This class says: Ho-hum. + """ + BaseServer.__init__(self, server_address, RequestHandlerClass) + self.ssl_ctx = ssl_context + self.socket = Connection(self.ssl_ctx) + if bind_and_activate: + self.server_bind() + self.server_activate() + +
    [docs] def handle_request(self): + # type: () -> None + request = None + client_address = None + try: + request, client_address = self.get_request() + if self.verify_request(request, client_address): + self.process_request(request, client_address) + except SSLError: + self.handle_error(request, client_address)
    + +
    [docs] def handle_error(self, request, client_address): + # type: (Union[socket, Connection], util.AddrType) -> None + print('-' * 40) + import traceback + traceback.print_exc() + print('-' * 40)
    + + +
    [docs]class ThreadingSSLServer(ThreadingMixIn, SSLServer): + pass
    + + +if os.name != 'nt': +
    [docs] class ForkingSSLServer(ForkingMixIn, SSLServer): + pass
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/Session.html b/doc/html/_modules/M2Crypto/SSL/Session.html new file mode 100644 index 0000000..d22a29c --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/Session.html @@ -0,0 +1,176 @@ + + + + + + + + M2Crypto.SSL.Session — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.Session

    +"""SSL Session
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +__all__ = ['Session', 'load_session']
    +
    +from M2Crypto import BIO, Err, m2, util
    +from M2Crypto.SSL import SSLError
    +if util.py27plus:
    +    from typing import AnyStr  # noqa
    +
    +
    +
    [docs]class Session(object): + + m2_ssl_session_free = m2.ssl_session_free + + def __init__(self, session, _pyfree=0): + # type: (bytes, int) -> None + assert session is not None + self.session = session + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_ssl_session_free(self.session) + + def _ptr(self): + # type: () -> bytes + return self.session + +
    [docs] def as_text(self): + # type: () -> bytes + buf = BIO.MemoryBuffer() + m2.ssl_session_print(buf.bio_ptr(), self.session) + return buf.read_all()
    + +
    [docs] def as_der(self): + # type: () -> bytes + buf = BIO.MemoryBuffer() + m2.i2d_ssl_session(buf.bio_ptr(), self.session) + return buf.read_all()
    + +
    [docs] def write_bio(self, bio): + # type: (BIO.BIO) -> int + return m2.ssl_session_write_bio(bio.bio_ptr(), self.session)
    + +
    [docs] def get_time(self): + # type: () -> int + return m2.ssl_session_get_time(self.session)
    + +
    [docs] def set_time(self, t): + # type: (int) -> int + return m2.ssl_session_set_time(self.session, t)
    + +
    [docs] def get_timeout(self): + # type: () -> int + return m2.ssl_session_get_timeout(self.session)
    + +
    [docs] def set_timeout(self, t): + # type: (int) -> int + return m2.ssl_session_set_timeout(self.session, t)
    + + +
    [docs]def load_session(pemfile): + # type: (AnyStr) -> Session + with BIO.openfile(pemfile) as f: + cptr = m2.ssl_session_read_pem(f.bio_ptr()) + + return Session(cptr, 1)
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/TwistedProtocolWrapper.html b/doc/html/_modules/M2Crypto/SSL/TwistedProtocolWrapper.html new file mode 100644 index 0000000..88c32e0 --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/TwistedProtocolWrapper.html @@ -0,0 +1,597 @@ + + + + + + + + M2Crypto.SSL.TwistedProtocolWrapper — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.TwistedProtocolWrapper

    +"""
    +Make Twisted use M2Crypto for SSL
    +
    +Copyright (c) 2004-2007 Open Source Applications Foundation.
    +All rights reserved.
    +
    +FIXME THIS HAS NOT BEEN FINISHED. NEITHER PEP484 NOR PORT PYTHON3 HAS
    +BEEN FINISHED. THE FURTHER WORK WILL BE DONE WHEN THE STATUS OF TWISTED
    +IN THE PYTHON 3 (AND ASYNCIO) WORLD WILL BE CLEAR.
    +"""
    +
    +__all__ = ['connectSSL', 'connectTCP', 'listenSSL', 'listenTCP',
    +           'TLSProtocolWrapper']
    +
    +import logging
    +
    +from functools import partial
    +
    +import twisted.internet.reactor
    +import twisted.protocols.policies as policies
    +
    +from M2Crypto import BIO, X509, m2, util
    +from M2Crypto.SSL.Checker import Checker, SSLVerificationError
    +
    +from twisted.internet.interfaces import ITLSTransport
    +from twisted.protocols.policies import ProtocolWrapper
    +if util.py27plus:
    +    from typing import AnyStr, Callable, Iterable, Optional  # noqa
    +    from zope.interface import implementer
    +
    +log = logging.getLogger(__name__)
    +
    +
    +def _alwaysSucceedsPostConnectionCheck(peerX509, expectedHost):
    +    return 1
    +
    +
    +
    [docs]def connectSSL(host, port, factory, contextFactory, timeout=30, + bindAddress=None, + reactor=twisted.internet.reactor, + postConnectionCheck=Checker()): + # type: (str, int, object, object, int, Optional[str], twisted.internet.reactor, Checker) -> reactor.connectTCP + """ + A convenience function to start an SSL/TLS connection using Twisted. + + See IReactorSSL interface in Twisted. + """ + wrappingFactory = policies.WrappingFactory(factory) + wrappingFactory.protocol = lambda factory, wrappedProtocol: \ + TLSProtocolWrapper(factory, + wrappedProtocol, + startPassThrough=0, + client=1, + contextFactory=contextFactory, + postConnectionCheck=postConnectionCheck) + return reactor.connectTCP(host, port, wrappingFactory, timeout, bindAddress)
    + + +
    [docs]def connectTCP(host, port, factory, timeout=30, bindAddress=None, + reactor=twisted.internet.reactor, + postConnectionCheck=Checker()): + # type: (str, int, object, int, Optional[util.AddrType], object, Callable) -> object + """ + A convenience function to start a TCP connection using Twisted. + + NOTE: You must call startTLS(ctx) to go into SSL/TLS mode. + + See IReactorTCP interface in Twisted. + """ + wrappingFactory = policies.WrappingFactory(factory) + wrappingFactory.protocol = lambda factory, wrappedProtocol: \ + TLSProtocolWrapper(factory, + wrappedProtocol, + startPassThrough=1, + client=1, + contextFactory=None, + postConnectionCheck=postConnectionCheck) + return reactor.connectTCP(host, port, wrappingFactory, timeout, bindAddress)
    + + +
    [docs]def listenSSL(port, factory, contextFactory, backlog=5, interface='', + reactor=twisted.internet.reactor, + postConnectionCheck=_alwaysSucceedsPostConnectionCheck): + """ + A convenience function to listen for SSL/TLS connections using Twisted. + + See IReactorSSL interface in Twisted. + """ + wrappingFactory = policies.WrappingFactory(factory) + wrappingFactory.protocol = lambda factory, wrappedProtocol: \ + TLSProtocolWrapper(factory, + wrappedProtocol, + startPassThrough=0, + client=0, + contextFactory=contextFactory, + postConnectionCheck=postConnectionCheck) + return reactor.listenTCP(port, wrappingFactory, backlog, interface)
    + + +
    [docs]def listenTCP(port, factory, backlog=5, interface='', + reactor=twisted.internet.reactor, + postConnectionCheck=None): + """ + A convenience function to listen for TCP connections using Twisted. + + NOTE: You must call startTLS(ctx) to go into SSL/TLS mode. + + See IReactorTCP interface in Twisted. + """ + wrappingFactory = policies.WrappingFactory(factory) + wrappingFactory.protocol = lambda factory, wrappedProtocol: \ + TLSProtocolWrapper(factory, + wrappedProtocol, + startPassThrough=1, + client=0, + contextFactory=None, + postConnectionCheck=postConnectionCheck) + return reactor.listenTCP(port, wrappingFactory, backlog, interface)
    + + +class _BioProxy(object): + """ + The purpose of this class is to eliminate the __del__ method from + TLSProtocolWrapper, and thus letting it be garbage collected. + """ + + m2_bio_free_all = m2.bio_free_all + + def __init__(self, bio): + self.bio = bio + + def _ptr(self): + return self.bio + + def __del__(self): + if self.bio is not None: + self.m2_bio_free_all(self.bio) + + +class _SSLProxy(object): + """ + The purpose of this class is to eliminate the __del__ method from + TLSProtocolWrapper, and thus letting it be garbage collected. + """ + + m2_ssl_free = m2.ssl_free + + def __init__(self, ssl): + self.ssl = ssl + + def _ptr(self): + return self.ssl + + def __del__(self): + if self.ssl is not None: + self.m2_ssl_free(self.ssl) + + +
    [docs]@implementer(ITLSTransport) +class TLSProtocolWrapper(ProtocolWrapper): + """ + A SSL/TLS protocol wrapper to be used with Twisted. Typically + you would not use this class directly. Use connectTCP, + connectSSL, listenTCP, listenSSL functions defined above, + which will hook in this class. + """ + + def __init__(self, factory, wrappedProtocol, startPassThrough, client, + contextFactory, postConnectionCheck): + # type: (policies.WrappingFactory, object, int, int, object, Checker) -> None + """ + :param factory: + :param wrappedProtocol: + :param startPassThrough: If true we won't encrypt at all. Need to + call startTLS() later to switch to SSL/TLS. + :param client: True if this should be a client protocol. + :param contextFactory: Factory that creates SSL.Context objects. + The called function is getContext(). + :param postConnectionCheck: The post connection check callback that + will be called just after connection has + been established but before any real data + has been exchanged. The first argument to + this function is an X509 object, the second + is the expected host name string. + """ + # ProtocolWrapper.__init__(self, factory, wrappedProtocol) + # XXX: Twisted 2.0 has a new addition where the wrappingFactory is + # set as the factory of the wrappedProtocol. This is an issue + # as the wrap should be transparent. What we want is + # the factory of the wrappedProtocol to be the wrappedFactory and + # not the outer wrappingFactory. This is how it was implemented in + # Twisted 1.3 + self.factory = factory + self.wrappedProtocol = wrappedProtocol + + # wrappedProtocol == client/server instance + # factory.wrappedFactory == client/server factory + + self.data = b'' # Clear text to encrypt and send + self.encrypted = b'' # Encrypted data we need to decrypt and pass on + self.tlsStarted = 0 # SSL/TLS mode or pass through + self.checked = 0 # Post connection check done or not + self.isClient = client + self.helloDone = 0 # True when hello has been sent + if postConnectionCheck is None: + self.postConnectionCheck = _alwaysSucceedsPostConnectionCheck + else: + self.postConnectionCheck = postConnectionCheck + + if not startPassThrough: + self.startTLS(contextFactory.getContext()) + +
    [docs] def clear(self): + """ + Clear this instance, after which it is ready for reuse. + """ + if getattr(self, 'tlsStarted', 0): + self.sslBio = None + self.ssl = None + self.internalBio = None + self.networkBio = None + self.data = b'' + self.encrypted = b'' + self.tlsStarted = 0 + self.checked = 0 + self.isClient = 1 + self.helloDone = 0
    + # We can reuse self.ctx and it will be deleted automatically + # when this instance dies + +
    [docs] def startTLS(self, ctx): + """ + Start SSL/TLS. If this is not called, this instance just passes data + through untouched. + """ + # NOTE: This method signature must match the startTLS() method Twisted + # expects transports to have. This will be called automatically + # by Twisted in STARTTLS situations, for example with SMTP. + if self.tlsStarted: + raise Exception('TLS already started') + + self.ctx = ctx + + self.internalBio = m2.bio_new(m2.bio_s_bio()) + m2.bio_set_write_buf_size(self.internalBio, 0) + self.networkBio = _BioProxy(m2.bio_new(m2.bio_s_bio())) + m2.bio_set_write_buf_size(self.networkBio._ptr(), 0) + m2.bio_make_bio_pair(self.internalBio, self.networkBio._ptr()) + + self.sslBio = _BioProxy(m2.bio_new(m2.bio_f_ssl())) + + self.ssl = _SSLProxy(m2.ssl_new(self.ctx.ctx)) + + if self.isClient: + m2.ssl_set_connect_state(self.ssl._ptr()) + else: + m2.ssl_set_accept_state(self.ssl._ptr()) + + m2.ssl_set_bio(self.ssl._ptr(), self.internalBio, self.internalBio) + m2.bio_set_ssl(self.sslBio._ptr(), self.ssl._ptr(), m2.bio_noclose) + + # Need this for writes that are larger than BIO pair buffers + mode = m2.ssl_get_mode(self.ssl._ptr()) + m2.ssl_set_mode(self.ssl._ptr(), + mode | + m2.SSL_MODE_ENABLE_PARTIAL_WRITE | + m2.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) + + self.tlsStarted = 1
    + +
    [docs] def write(self, data): + # type: (bytes) -> None + if not self.tlsStarted: + ProtocolWrapper.write(self, data) + return + + try: + encryptedData = self._encrypt(data) + ProtocolWrapper.write(self, encryptedData) + self.helloDone = 1 + except BIO.BIOError as e: + # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS + # for the error codes returned by SSL_get_verify_result. + e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) + raise e
    + +
    [docs] def writeSequence(self, data): + # type: (Iterable[bytes]) -> None + if not self.tlsStarted: + ProtocolWrapper.writeSequence(self, b''.join(data)) + return + + self.write(b''.join(data))
    + +
    [docs] def loseConnection(self): + # XXX Do we need to do m2.ssl_shutdown(self.ssl._ptr())? + ProtocolWrapper.loseConnection(self)
    + +
    [docs] def connectionMade(self): + ProtocolWrapper.connectionMade(self) + if self.tlsStarted and self.isClient and not self.helloDone: + self._clientHello()
    + +
    [docs] def dataReceived(self, data): + # type: (bytes) -> None + if not self.tlsStarted: + ProtocolWrapper.dataReceived(self, data) + return + + self.encrypted += data + + try: + while 1: + decryptedData = self._decrypt() + + self._check() + + encryptedData = self._encrypt() + ProtocolWrapper.write(self, encryptedData) + + ProtocolWrapper.dataReceived(self, decryptedData) + + if decryptedData == b'' and encryptedData == b'': + break + except BIO.BIOError as e: + # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS + # for the error codes returned by SSL_get_verify_result. + e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) + raise e
    + +
    [docs] def connectionLost(self, reason): + # type: (AnyStr) -> None + self.clear() + ProtocolWrapper.connectionLost(self, reason)
    + + def _check(self): + if not self.checked and m2.ssl_is_init_finished(self.ssl._ptr()): + x509 = m2.ssl_get_peer_cert(self.ssl._ptr()) + if x509 is not None: + x509 = X509.X509(x509, 1) + if self.isClient: + host = self.transport.addr[0] + else: + host = self.transport.getPeer().host + if not self.postConnectionCheck(x509, host): + raise SSLVerificationError('post connection check') + self.checked = 1 + + def _clientHello(self): + try: + # We rely on OpenSSL implicitly starting with client hello + # when we haven't yet established an SSL connection + encryptedData = self._encrypt(clientHello=1) + ProtocolWrapper.write(self, encryptedData) + self.helloDone = 1 + except BIO.BIOError as e: + # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS + # for the error codes returned by SSL_get_verify_result. + e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) + raise e + + # Optimizations to reduce attribute accesses + + @property + def _get_wr_guar_ssl(self): + # type: () -> Callable[[], int] + """Return max. length of data can be written to the BIO. + + Writes larger than this value will return a value from + BIO_write() less than the amount requested or if the buffer is + full request a retry. + """ + return partial(m2.bio_ctrl_get_write_guarantee, + self.sslBio._ptr()) + + @property + def _get_wr_guar_net(self): + # type: () -> Callable[[], int] + return partial(m2.bio_ctrl_get_write_guarantee, + self.networkBio._ptr()) + + @property + def _shoud_retry_ssl(self): + # type: () -> Callable[[], int] + # BIO_should_retry() is true if the call that produced this + # condition should then be retried at a later time. + return partial(m2.bio_should_retry, self.sslBio._ptr()) + + @property + def _shoud_retry_net(self): + # type: () -> Callable[[], int] + return partial(m2.bio_should_retry, self.networkBio._ptr()) + + @property + def _ctrl_pend_ssl(self): + # type: () -> Callable[[], int] + # size_t BIO_ctrl_pending(BIO *b); + # BIO_ctrl_pending() return the number of pending characters in + # the BIOs read and write buffers. + return partial(m2.bio_ctrl_pending, self.sslBio._ptr()) + + @property + def _ctrl_pend_net(self): + # type: () -> Callable[[], int] + return partial(m2.bio_ctrl_pending, self.networkBio._ptr()) + + @property + def _write_ssl(self): + # type: () -> Callable[[bytes], int] + # All these functions return either the amount of data + # successfully read or written (if the return value is + # positive) or that no data was successfully read or written + # if the result is 0 or -1. If the return value is -2 then + # the operation is not implemented in the specific BIO type. + return partial(m2.bio_write, self.sslBio._ptr()) + + @property + def _write_net(self): + # type: () -> Callable[[bytes], int] + return partial(m2.bio_write, self.networkBio._ptr()) + + @property + def _read_ssl(self): + # type: () -> Callable[[int], Optional[bytes]] + return partial(m2.bio_read, self.sslBio._ptr()) + + @property + def _read_net(self): + # type: () -> Callable[[int], Optional[bytes]] + return partial(m2.bio_read, self.networkBio._ptr()) + + def _encrypt(self, data=b'', clientHello=0): + # type: (bytes, int) -> bytes + """ + :param data: + :param clientHello: + :return: + """ + encryptedData = b'' + self.data += data + + while 1: + if (self._get_wr_guar_ssl() > 0 and self.data != b'') or clientHello: + r = self._write_ssl(self.data) + if r <= 0: + if not self._shoud_retry_ssl(): + raise IOError( + ('Data left to be written to {}, ' + + 'but cannot retry SSL connection!').format(self.sslBio)) + else: + assert self.checked + self.data = self.data[r:] + + pending = self._ctrl_pend_net() + if pending: + d = self._read_net(pending) + if d is not None: # This is strange, but d can be None + encryptedData += d + else: + assert(self._shoud_retry_net()) + else: + break + return encryptedData + + def _decrypt(self, data=b''): + # type: (bytes) -> bytes + self.encrypted += data + decryptedData = b'' + + while 1: + if self._get_wr_guar_ssl() > 0 and self.encrypted != b'': + r = self._write_net(self.encrypted) + if r <= 0: + if not self._shoud_retry_net(): + raise IOError( + ('Data left to be written to {}, ' + + 'but cannot retry SSL connection!').format(self.networkBio)) + else: + self.encrypted = self.encrypted[r:] + + pending = self._ctrl_pend_ssl() + if pending: + d = self._read_ssl(pending) + if d is not None: # This is strange, but d can be None + decryptedData += d + else: + assert(self._shoud_retry_ssl()) + else: + break + + return decryptedData
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/cb.html b/doc/html/_modules/M2Crypto/SSL/cb.html new file mode 100644 index 0000000..0e7c20f --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/cb.html @@ -0,0 +1,202 @@ + + + + + + + + M2Crypto.SSL.cb — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.cb

    +from __future__ import absolute_import
    +
    +"""SSL callbacks
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +import sys
    +
    +from M2Crypto import m2, util
    +if util.py27plus:
    +    from typing import Any, List  # noqa
    +
    +__all__ = ['unknown_issuer', 'ssl_verify_callback_stub', 'ssl_verify_callback',
    +           'ssl_verify_callback_allow_unknown_ca', 'ssl_info_callback']
    +
    +
    +
    [docs]def ssl_verify_callback_stub(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok): + # Deprecated + return ok
    + +unknown_issuer = [ + m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, + m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, + m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, + m2.X509_V_ERR_CERT_UNTRUSTED, +] + + +
    [docs]def ssl_verify_callback(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok): + # type: (bytes, bytes, int, int, int) -> int + # Deprecated + + from M2Crypto.SSL.Context import Context + ssl_ctx = Context.ctxmap()[int(ssl_ctx_ptr)] + if errnum in unknown_issuer: + if ssl_ctx.get_allow_unknown_ca(): + sys.stderr.write("policy: %s: permitted...\n" % + (m2.x509_get_verify_error(errnum))) + sys.stderr.flush() + ok = 1 + # CRL checking goes here... + if ok: + if ssl_ctx.get_verify_depth() >= errdepth: + ok = 1 + else: + ok = 0 + return ok
    + + +
    [docs]def ssl_verify_callback_allow_unknown_ca(ok, store): + # type: (int, Any) -> int + errnum = store.get_error() + if errnum in unknown_issuer: + ok = 1 + return ok
    + + +# Cribbed from OpenSSL's apps/s_cb.c. +
    [docs]def ssl_info_callback(where, ret, ssl_ptr): + # type: (int, int, bytes) -> None + + w = where & ~m2.SSL_ST_MASK + if w & m2.SSL_ST_CONNECT: + state = "SSL connect" + elif w & m2.SSL_ST_ACCEPT: + state = "SSL accept" + else: + state = "SSL state unknown" + + if where & m2.SSL_CB_LOOP: + sys.stderr.write("LOOP: %s: %s\n" % + (state, m2.ssl_get_state_v(ssl_ptr))) + sys.stderr.flush() + return + + if where & m2.SSL_CB_EXIT: + if not ret: + sys.stderr.write("FAILED: %s: %s\n" % + (state, m2.ssl_get_state_v(ssl_ptr))) + sys.stderr.flush() + else: + sys.stderr.write("INFO: %s: %s\n" % + (state, m2.ssl_get_state_v(ssl_ptr))) + sys.stderr.flush() + return + + if where & m2.SSL_CB_ALERT: + if where & m2.SSL_CB_READ: + w = 'read' + else: + w = 'write' + sys.stderr.write("ALERT: %s: %s: %s\n" % + (w, m2.ssl_get_alert_type_v(ret), + m2.ssl_get_alert_desc_v(ret))) + sys.stderr.flush() + return
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/ssl_dispatcher.html b/doc/html/_modules/M2Crypto/SSL/ssl_dispatcher.html new file mode 100644 index 0000000..a6b964d --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/ssl_dispatcher.html @@ -0,0 +1,149 @@ + + + + + + + + M2Crypto.SSL.ssl_dispatcher — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.ssl_dispatcher

    +from __future__ import absolute_import
    +
    +"""SSL dispatcher
    +
    +Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved."""
    +
    +# Python
    +import asyncore
    +import socket
    +
    +# M2Crypto
    +from M2Crypto import util  # noqa
    +from M2Crypto.SSL.Connection import Connection
    +from M2Crypto.SSL.Context import Context  # noqa
    +
    +__all__ = ['ssl_dispatcher']
    +
    +
    +
    [docs]class ssl_dispatcher(asyncore.dispatcher): + +
    [docs] def create_socket(self, ssl_context): + # type: (Context) -> None + self.family_and_type = socket.AF_INET, socket.SOCK_STREAM + self.ssl_ctx = ssl_context + self.socket = Connection(self.ssl_ctx) + # self.socket.setblocking(0) + self.add_channel()
    + +
    [docs] def connect(self, addr): + # type: (util.AddrType) -> None + self.socket.setblocking(1) + self.socket.connect(addr) + self.socket.setblocking(0)
    + +
    [docs] def recv(self, buffer_size=4096): + # type: (int) -> bytes + """Receive data over SSL.""" + return self.socket.recv(buffer_size)
    + +
    [docs] def send(self, buffer): + # type: (bytes) -> int + """Send data over SSL.""" + return self.socket.send(buffer)
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/SSL/timeout.html b/doc/html/_modules/M2Crypto/SSL/timeout.html new file mode 100644 index 0000000..d7fb07f --- /dev/null +++ b/doc/html/_modules/M2Crypto/SSL/timeout.html @@ -0,0 +1,156 @@ + + + + + + + + M2Crypto.SSL.timeout — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.SSL.timeout

    +"""Support for SSL socket timeouts.
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.
    +
    +Copyright 2008 Heikki Toivonen. All rights reserved.
    +"""
    +
    +__all__ = ['DEFAULT_TIMEOUT', 'timeout', 'struct_to_timeout', 'struct_size']
    +
    +import sys
    +import struct
    +
    +DEFAULT_TIMEOUT = 600  # type: int
    +
    +
    +
    [docs]class timeout(object): + + def __init__(self, sec=DEFAULT_TIMEOUT, microsec=0): + # type: (int, int) -> None + self.sec = sec + self.microsec = microsec + +
    [docs] def pack(self): + if sys.platform == 'win32': + millisec = int(self.sec * 1000 + round(float(self.microsec) / 1000)) + binstr = struct.pack('l', millisec) + else: + binstr = struct.pack('ll', self.sec, self.microsec) + return binstr
    + + +
    [docs]def struct_to_timeout(binstr): + # type: (bytes) -> timeout + if sys.platform == 'win32': + millisec = struct.unpack('l', binstr)[0] + # On py3, int/int performs exact division and returns float. We want + # the whole number portion of the exact division result: + sec = int(millisec / 1000) + microsec = (millisec % 1000) * 1000 + else: + (sec, microsec) = struct.unpack('ll', binstr) + return timeout(sec, microsec)
    + + +
    [docs]def struct_size(): + # type: () -> int + if sys.platform == 'win32': + return struct.calcsize('l') + else: + return struct.calcsize('ll')
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/X509.html b/doc/html/_modules/M2Crypto/X509.html new file mode 100644 index 0000000..b546394 --- /dev/null +++ b/doc/html/_modules/M2Crypto/X509.html @@ -0,0 +1,1495 @@ + + + + + + + + M2Crypto.X509 — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.X509

    +from __future__ import absolute_import
    +
    +"""M2Crypto wrapper for OpenSSL X509 API.
    +
    +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
    +
    +Portions created by Open Source Applications Foundation (OSAF) are
    +Copyright (C) 2004-2007 OSAF. All Rights Reserved.
    +Author: Heikki Toivonen
    +"""
    +
    +import binascii
    +import logging
    +
    +from M2Crypto import ASN1, BIO, EVP, m2, py27plus, six  # noqa
    +if py27plus:
    +    from typing import AnyStr, Optional  # noqa
    +
    +FORMAT_DER = 0
    +FORMAT_PEM = 1
    +
    +log = logging.getLogger(__name__)
    +
    +
    +
    [docs]class X509Error(ValueError): + pass
    + +m2.x509_init(X509Error) + +V_OK = m2.X509_V_OK # type: int + + +
    [docs]def x509_store_default_cb(ok, ctx): + # type: (int, X509_Store_Context) -> int + return ok
    + + +
    [docs]def new_extension(name, value, critical=0, _pyfree=1): + # type: (str, bytes, int, int) -> X509_Extension + """ + Create new X509_Extension instance. + """ + if name == 'subjectKeyIdentifier' and \ + value.strip('0123456789abcdefABCDEF:') is not '': + raise ValueError('value must be precomputed hash') + ctx = m2.x509v3_set_nconf() + x509_ext_ptr = m2.x509v3_ext_conf(None, ctx, name, value) + if x509_ext_ptr is None: + raise X509Error( + "Cannot create X509_Extension with name '%s' and value '%s'" % + (name, value)) + x509_ext = X509_Extension(x509_ext_ptr, _pyfree) + x509_ext.set_critical(critical) + return x509_ext
    + + +
    [docs]class X509_Extension(object): + """ + X509 Extension + """ + + m2_x509_extension_free = m2.x509_extension_free + + def __init__(self, x509_ext_ptr=None, _pyfree=1): + # type: (Optional[bytes], int) -> None + self.x509_ext = x509_ext_ptr + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0) and self.x509_ext: + self.m2_x509_extension_free(self.x509_ext) + + def _ptr(self): + # type: () -> bytes + return self.x509_ext + +
    [docs] def set_critical(self, critical=1): + # type: (int) -> int + """ + Mark this extension critical or noncritical. By default an + extension is not critical. + + :param critical: Nonzero sets this extension as critical. + Calling this method without arguments will + set this extension to critical. + :return: 1 for success, 0 for failure + """ + return m2.x509_extension_set_critical(self.x509_ext, critical)
    + +
    [docs] def get_critical(self): + # type: () -> int + """ + Return whether or not this is a critical extension. + + :return: Nonzero if this is a critical extension. + """ + return m2.x509_extension_get_critical(self.x509_ext)
    + +
    [docs] def get_name(self): + # type: () -> str + """ + Get the extension name, for example 'subjectAltName'. + """ + return six.ensure_text(m2.x509_extension_get_name(self.x509_ext))
    + +
    [docs] def get_value(self, flag=0, indent=0): + # type: (int, int) -> str + """ + Get the extension value, for example 'DNS:www.example.com'. + + :param flag: Flag to control what and how to print. + :param indent: How many spaces to print before actual value. + """ + buf = BIO.MemoryBuffer() + m2.x509_ext_print(buf.bio_ptr(), self.x509_ext, flag, indent) + return six.ensure_text(buf.read_all())
    + + +
    [docs]class X509_Extension_Stack(object): + """ + X509 Extension Stack + + :warning: Do not modify the underlying OpenSSL stack + except through this interface, or use any OpenSSL + functions that do so indirectly. Doing so will get the + OpenSSL stack and the internal pystack of this class out + of sync, leading to python memory leaks, exceptions or + even python crashes! + """ + + m2_sk_x509_extension_free = m2.sk_x509_extension_free + + def __init__(self, stack=None, _pyfree=0): + # type: (Optional[bytes], int) -> None + if stack is not None: + self.stack = stack + self._pyfree = _pyfree + num = m2.sk_x509_extension_num(self.stack) + for i in range(num): + self.pystack.append(X509_Extension( + m2.sk_x509_extension_value(self.stack, i), + _pyfree=_pyfree)) + else: + self.stack = m2.sk_x509_extension_new_null() + self._pyfree = 1 + self.pystack = [] # This must be kept in sync with self.stack + + def __del__(self): + # type: () -> None + # see BIO.py - unbalanced __init__ / __del__ + if getattr(self, '_pyfree', 0): + self.m2_sk_x509_extension_free(self.stack) + + def __len__(self): + # type: () -> int + assert m2.sk_x509_extension_num(self.stack) == len(self.pystack) + return len(self.pystack) + + def __getitem__(self, idx): + # type: (int) -> X509_Extension + return self.pystack[idx] + + def __iter__(self): + return iter(self.pystack) + + def _ptr(self): + # type: () -> bytes + return self.stack + +
    [docs] def push(self, x509_ext): + # type: (X509_Extension) -> int + """ + Push X509_Extension object onto the stack. + + :param x509_ext: X509_Extension object to be pushed onto the stack. + :return: The number of extensions on the stack. + """ + self.pystack.append(x509_ext) + ret = m2.sk_x509_extension_push(self.stack, x509_ext._ptr()) + assert ret == len(self.pystack) + return ret
    + +
    [docs] def pop(self): + # type: () -> X509_Extension + """ + Pop X509_Extension object from the stack. + + :return: X509_Extension popped + """ + x509_ext_ptr = m2.sk_x509_extension_pop(self.stack) + if x509_ext_ptr is None: + assert len(self.pystack) == 0 + return None + return self.pystack.pop()
    + + +
    [docs]class X509_Name_Entry(object): + """ + X509 Name Entry + """ + + m2_x509_name_entry_free = m2.x509_name_entry_free + + def __init__(self, x509_name_entry, _pyfree=0): + # type: (bytes, int) -> None + """ + :param x509_name_entry: this should be OpenSSL X509_NAME_ENTRY binary + :param _pyfree: + """ + self.x509_name_entry = x509_name_entry + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_x509_name_entry_free(self.x509_name_entry) + + def _ptr(self): + # type: () -> bytes + return self.x509_name_entry + +
    [docs] def set_object(self, asn1obj): + # type: (ASN1.ASN1_Object) -> int + """ + Sets the field name to asn1obj + + :param asn1obj: + :return: 0 on failure, 1 on success + """ + return m2.x509_name_entry_set_object(self.x509_name_entry, + asn1obj._ptr())
    + +
    [docs] def set_data(self, data, type=ASN1.MBSTRING_ASC): + # type: (bytes, int) -> int + """ + Sets the field name to asn1obj + + :param data: data in a binary form to be set + :return: 0 on failure, 1 on success + """ + return m2.x509_name_entry_set_data(self.x509_name_entry, type, data)
    + +
    [docs] def get_object(self): + # type: () -> ASN1.ASN1_Object + return ASN1.ASN1_Object( + m2.x509_name_entry_get_object(self.x509_name_entry))
    + +
    [docs] def get_data(self): + # type: () -> ASN1.ASN1_String + return ASN1.ASN1_String( + m2.x509_name_entry_get_data(self.x509_name_entry))
    + +
    [docs] def create_by_txt(self, field, type, entry, len): + return m2.x509_name_entry_create_by_txt(self.x509_name_entry._ptr(), + field, type, entry, len)
    + + +
    [docs]class X509_Name(object): + """ + X509 Name + """ + + nid = {'C': m2.NID_countryName, + 'SP': m2.NID_stateOrProvinceName, + 'ST': m2.NID_stateOrProvinceName, + 'stateOrProvinceName': m2.NID_stateOrProvinceName, + 'L': m2.NID_localityName, + 'localityName': m2.NID_localityName, + 'O': m2.NID_organizationName, + 'organizationName': m2.NID_organizationName, + 'OU': m2.NID_organizationalUnitName, + 'organizationUnitName': m2.NID_organizationalUnitName, + 'CN': m2.NID_commonName, + 'commonName': m2.NID_commonName, + 'Email': m2.NID_pkcs9_emailAddress, + 'emailAddress': m2.NID_pkcs9_emailAddress, + 'serialNumber': m2.NID_serialNumber, + 'SN': m2.NID_surname, + 'surname': m2.NID_surname, + 'GN': m2.NID_givenName, + 'givenName': m2.NID_givenName + } + + m2_x509_name_free = m2.x509_name_free + + def __init__(self, x509_name=None, _pyfree=0): + # type: (bytes, int) -> None + """ + :param x509_name: this should be OpenSSL X509_NAME binary + :param _pyfree: + """ + if x509_name is not None: + assert m2.x509_name_type_check(x509_name), "'x509_name' type error" + self.x509_name = x509_name + self._pyfree = _pyfree + else: + self.x509_name = m2.x509_name_new() + self._pyfree = 1 + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_x509_name_free(self.x509_name) + + def __str__(self): + # type: () -> bytes + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + return m2.x509_name_oneline(self.x509_name) + + def __getattr__(self, attr): + # type: (str) -> str + if attr in self.nid: + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + return six.ensure_text(m2.x509_name_by_nid(self.x509_name, self.nid[attr])) + + if attr in self.__dict__: + return self.__dict__[attr] + + raise AttributeError(self, attr) + + def __setattr__(self, attr, value): + # type: (str, AnyStr) -> int + """ + :return: 1 for success of 0 if an error occurred. + """ + if attr in self.nid: + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + return m2.x509_name_set_by_nid(self.x509_name, self.nid[attr], + six.ensure_binary(value)) + + self.__dict__[attr] = value + + def __len__(self): + # type: () -> int + return m2.x509_name_entry_count(self.x509_name) + + def __getitem__(self, idx): + # type: (int) -> X509_Name_Entry + if not 0 <= idx < self.entry_count(): + raise IndexError("index out of range") + return X509_Name_Entry(m2.x509_name_get_entry(self.x509_name, idx)) + + def __iter__(self): + for i in range(self.entry_count()): + yield self[i] + + def _ptr(self): + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + return self.x509_name + +
    [docs] def add_entry_by_txt(self, field, type, entry, len, loc, set): + # entry_type: (str, int, bytes, int, int, int) -> int + """ + Add X509_Name field whose name is identified by its name. + + :param field: name of the entry + :param type: use MBSTRING_ASC or MBSTRING_UTF8 + (or standard ASN1 type like V_ASN1_IA5STRING) + :param entry: value + :param len: buf_len of the entry + (-1 and the length is computed automagically) + + The ``loc`` and ``set`` parameters determine where a new entry + should be added. + For almost all applications loc can be set to -1 and set to 0. + This adds a new entry to the end of name as a single valued + RelativeDistinguishedName (RDN). + + :param loc: determines the index where the new entry is + inserted: if it is -1 it is appended. + :param set: determines how the new type is added. If it is zero + a new RDN is created. + If set is -1 or 1 it is added to the previous or next RDN + structure respectively. This will then be a multivalued + RDN: since multivalues RDNs are very seldom used set is + almost always set to zero. + + :return: 1 for success of 0 if an error occurred. + """ + return m2.x509_name_add_entry_by_txt(self.x509_name, + six.ensure_str(field), type, + six.ensure_str(entry), len, loc, set)
    + +
    [docs] def entry_count(self): + # type: () -> int + return m2.x509_name_entry_count(self.x509_name)
    + +
    [docs] def get_entries_by_nid(self, nid): + # type: (int) -> List[X509_Name_Entry] + """ + Retrieve the next index matching nid. + + :param nid: name of the entry (as m2.NID* constants) + + :return: list of X509_Name_Entry items + """ + ret = [] + lastpos = -1 + + while True: + lastpos = m2.x509_name_get_index_by_nid(self.x509_name, nid, + lastpos) + if lastpos == -1: + break + + ret.append(self[lastpos]) + + return ret
    + +
    [docs] def as_text(self, indent=0, flags=m2.XN_FLAG_COMPAT): + # type: (int, int) -> str + """ + as_text returns the name as a string. + + :param indent: Each line in multiline format is indented + by this many spaces. + :param flags: Flags that control how the output should be formatted. + """ + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + buf = BIO.MemoryBuffer() + m2.x509_name_print_ex(buf.bio_ptr(), self.x509_name, indent, flags) + return six.ensure_text(buf.read_all())
    + +
    [docs] def as_der(self): + # type: () -> bytes + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + return m2.x509_name_get_der(self.x509_name)
    + +
    [docs] def as_hash(self): + # type: () -> int + assert m2.x509_name_type_check(self.x509_name), \ + "'x509_name' type error" + return m2.x509_name_hash(self.x509_name)
    + + +
    [docs]class X509(object): + """ + X.509 Certificate + """ + + m2_x509_free = m2.x509_free + + def __init__(self, x509=None, _pyfree=0): + # type: (Optional[bytes], int) -> None + """ + :param x509: binary representation of + the underlying OpenSSL X509 object. + :param _pyfree: + """ + if x509 is not None: + assert m2.x509_type_check(x509), "'x509' type error" + self.x509 = x509 + self._pyfree = _pyfree + else: + self.x509 = m2.x509_new() + self._pyfree = 1 + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_x509_free(self.x509) + + def _ptr(self): + # type: () -> bytes + assert m2.x509_type_check(self.x509), "'x509' type error" + return self.x509 + +
    [docs] def as_text(self): + # type: () -> str + assert m2.x509_type_check(self.x509), "'x509' type error" + buf = BIO.MemoryBuffer() + m2.x509_print(buf.bio_ptr(), self.x509) + return six.ensure_text(buf.read_all())
    + +
    [docs] def as_der(self): + # type: () -> bytes + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.i2d_x509(self.x509)
    + +
    [docs] def as_pem(self): + # type: () -> bytes + buf = BIO.MemoryBuffer() + m2.x509_write_pem(buf.bio_ptr(), self.x509) + return buf.read_all()
    + +
    [docs] def save_pem(self, filename): + # type: (AnyStr) -> int + """ + :param filename: name of the file to be loaded + :return: 1 for success or 0 for failure + """ + with BIO.openfile(filename, 'wb') as bio: + return m2.x509_write_pem(bio.bio_ptr(), self.x509)
    + +
    [docs] def save(self, filename, format=FORMAT_PEM): + # type: (AnyStr, int) -> int + """ + Saves X.509 certificate to a file. Default output + format is PEM. + + :param filename: Name of the file the cert will be saved to. + + :param format: Controls what output format is used to save the cert. + Either FORMAT_PEM or FORMAT_DER to save in PEM or + DER format. Raises a ValueError if an unknow + format is used. + + :return: 1 for success or 0 for failure + """ + with BIO.openfile(filename, 'wb') as bio: + if format == FORMAT_PEM: + return m2.x509_write_pem(bio.bio_ptr(), self.x509) + elif format == FORMAT_DER: + return m2.i2d_x509_bio(bio.bio_ptr(), self.x509) + else: + raise ValueError( + "Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER")
    + +
    [docs] def set_version(self, version): + # type: (int) -> int + """ + Set version of the certificate. + + :param version: Version number. + :return: Returns 0 on failure. + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_set_version(self.x509, version)
    + +
    [docs] def set_not_before(self, asn1_time): + # type: (ASN1.ASN1_TIME) -> int + """ + :return: 1 on success, 0 on failure + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_set_not_before(self.x509, asn1_time._ptr())
    + +
    [docs] def set_not_after(self, asn1_time): + # type: (ASN1.ASN1_TIME) -> int + """ + :return: 1 on success, 0 on failure + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_set_not_after(self.x509, asn1_time._ptr())
    + +
    [docs] def set_subject_name(self, name): + # type: (X509_Name) -> int + """ + :return: 1 on success, 0 on failure + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_set_subject_name(self.x509, name.x509_name)
    + +
    [docs] def set_issuer_name(self, name): + # type: (X509_Name) -> int + """ + :return: 1 on success, 0 on failure + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_set_issuer_name(self.x509, name.x509_name)
    + +
    [docs] def get_version(self): + # type: () -> int + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_get_version(self.x509)
    + +
    [docs] def get_serial_number(self): + # type: () -> ASN1.ASN1_Integer + assert m2.x509_type_check(self.x509), "'x509' type error" + asn1_integer = m2.x509_get_serial_number(self.x509) + return m2.asn1_integer_get(asn1_integer)
    + +
    [docs] def set_serial_number(self, serial): + # type: (ASN1.ASN1_Integer) -> int + """ + Set serial number. + + :param serial: Serial number. + + :return 1 for success and 0 for failure. + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + # This "magically" changes serial since asn1_integer + # is C pointer to x509's internal serial number. + asn1_integer = m2.x509_get_serial_number(self.x509) + return m2.asn1_integer_set(asn1_integer, serial)
    + # XXX Or should I do this? + # asn1_integer = m2.asn1_integer_new() + # m2.asn1_integer_set(asn1_integer, serial) + # return m2.x509_set_serial_number(self.x509, asn1_integer) + +
    [docs] def get_not_before(self): + # type: () -> ASN1.ASN1_TIME + assert m2.x509_type_check(self.x509), "'x509' type error" + return ASN1.ASN1_TIME(m2.x509_get_not_before(self.x509))
    + +
    [docs] def get_not_after(self): + # type: () -> ASN1.ASN1_TIME + assert m2.x509_type_check(self.x509), "'x509' type error" + out = ASN1.ASN1_TIME(m2.x509_get_not_after(self.x509)) + if 'Bad time value' in str(out): + raise X509Error( + '''M2Crypto cannot handle dates after year 2050. + See RFC 5280 4.1.2.5 for more information. + ''') + return out
    + +
    [docs] def get_pubkey(self): + # type: () -> EVP.PKey + assert m2.x509_type_check(self.x509), "'x509' type error" + return EVP.PKey(m2.x509_get_pubkey(self.x509), _pyfree=1)
    + +
    [docs] def set_pubkey(self, pkey): + # type: (EVP.PKey) -> int + """ + Set the public key for the certificate + + :param pkey: Public key + + :return 1 for success and 0 for failure + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_set_pubkey(self.x509, pkey.pkey)
    + +
    [docs] def get_issuer(self): + # type: () -> X509_Name + assert m2.x509_type_check(self.x509), "'x509' type error" + return X509_Name(m2.x509_get_issuer_name(self.x509))
    + +
    [docs] def set_issuer(self, name): + # type: (X509_Name) -> int + """ + Set issuer name. + + :param name: subjectName field. + + :return 1 for success and 0 for failure + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_set_issuer_name(self.x509, name.x509_name)
    + +
    [docs] def get_subject(self): + # type: () -> X509_Name + assert m2.x509_type_check(self.x509), "'x509' type error" + return X509_Name(m2.x509_get_subject_name(self.x509))
    + +
    [docs] def set_subject(self, name): + # type: (X509_Name) -> int + """ + Set subject name. + + :param name: subjectName field. + + :return 1 for success and 0 for failure + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_set_subject_name(self.x509, name.x509_name)
    + +
    [docs] def add_ext(self, ext): + # type: (X509_Extension) -> int + """ + Add X509 extension to this certificate. + + :param ext: Extension + + :return 1 for success and 0 for failure + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + return m2.x509_add_ext(self.x509, ext.x509_ext, -1)
    + +
    [docs] def get_ext(self, name): + # type: (str) -> X509_Extension + """ + Get X509 extension by name. + + :param name: Name of the extension + + :return: X509_Extension + """ + # Optimizations to reduce attribute accesses + m2x509_get_ext = m2.x509_get_ext + m2x509_extension_get_name = m2.x509_extension_get_name + x509 = self.x509 + + name = six.ensure_binary(name) + for i in range(m2.x509_get_ext_count(x509)): + ext_ptr = m2x509_get_ext(x509, i) + if m2x509_extension_get_name(ext_ptr) == name: + return X509_Extension(ext_ptr, _pyfree=0) + + raise LookupError
    + +
    [docs] def get_ext_at(self, index): + # type: (int) -> X509_Extension + """ + Get X509 extension by index. + + :param index: Name of the extension + + :return: X509_Extension + """ + if index < 0 or index >= self.get_ext_count(): + raise IndexError + + return X509_Extension(m2.x509_get_ext(self.x509, index), + _pyfree=0)
    + +
    [docs] def get_ext_count(self): + # type: () -> int + """ + Get X509 extension count. + """ + return m2.x509_get_ext_count(self.x509)
    + +
    [docs] def sign(self, pkey, md): + # type: (EVP.PKey, str) -> int + """ + Sign the certificate. + + :param pkey: Public key + + :param md: Message digest algorithm to use for signing, + for example 'sha1'. + + :return int + """ + assert m2.x509_type_check(self.x509), "'x509' type error" + mda = getattr(m2, md, None) + if mda is None: + raise ValueError('unknown message digest', md) + return m2.x509_sign(self.x509, pkey.pkey, mda())
    + +
    [docs] def verify(self, pkey=None): + # type: (Optional[EVP.PKey]) -> int + assert m2.x509_type_check(self.x509), "'x509' type error" + if pkey: + return m2.x509_verify(self.x509, pkey.pkey) + else: + return m2.x509_verify(self.x509, self.get_pubkey().pkey)
    + +
    [docs] def check_ca(self): + # type: () -> int + """ + Check if the certificate is a Certificate Authority (CA) certificate. + + :return: 0 if the certificate is not CA, nonzero otherwise. + + :requires: OpenSSL 0.9.8 or newer + """ + return m2.x509_check_ca(self.x509)
    + +
    [docs] def check_purpose(self, id, ca): + # type: (int, int) -> int + """ + Check if the certificate's purpose matches the asked purpose. + + :param id: Purpose id. See X509_PURPOSE_* constants. + + :param ca: 1 if the certificate should be CA, 0 otherwise. + + :return: 0 if the certificate purpose does not match, nonzero + otherwise. + """ + return m2.x509_check_purpose(self.x509, id, ca)
    + +
    [docs] def get_fingerprint(self, md='md5'): + # type: (str) -> str + """ + Get the fingerprint of the certificate. + + :param md: Message digest algorithm to use. + + :return: String containing the fingerprint in hex format. + """ + der = self.as_der() + md = EVP.MessageDigest(md) + md.update(der) + digest = md.final() + return six.ensure_text(binascii.hexlify(digest).upper())
    + + +
    [docs]def load_cert(file, format=FORMAT_PEM): + # type: (AnyStr, int) -> X509 + """ + Load certificate from file. + + :param file: Name of file containing certificate in either DER or + PEM format. + + :param format: Describes the format of the file to be loaded, + either PEM or DER. + + :return: M2Crypto.X509.X509 object. + """ + with BIO.openfile(file) as bio: + if format == FORMAT_PEM: + return load_cert_bio(bio) + elif format == FORMAT_DER: + cptr = m2.d2i_x509(bio._ptr()) + return X509(cptr, _pyfree=1) + else: + raise ValueError( + "Unknown format. Must be either FORMAT_DER or FORMAT_PEM")
    + + +
    [docs]def load_cert_bio(bio, format=FORMAT_PEM): + # type: (BIO.BIO, int) -> X509 + """ + Load certificate from a bio. + + :param bio: BIO pointing at a certificate in either DER or PEM format. + + :param format: Describes the format of the cert to be loaded, + either PEM or DER (via constants FORMAT_PEM + and FORMAT_FORMAT_DER) + + :return: M2Crypto.X509.X509 object. + """ + if format == FORMAT_PEM: + cptr = m2.x509_read_pem(bio._ptr()) + elif format == FORMAT_DER: + cptr = m2.d2i_x509(bio._ptr()) + else: + raise ValueError( + "Unknown format. Must be either FORMAT_DER or FORMAT_PEM") + return X509(cptr, _pyfree=1)
    + + +
    [docs]def load_cert_string(string, format=FORMAT_PEM): + # type: (AnyStr, int) -> X509 + """ + Load certificate from a string. + + :param string: String containing a certificate in either DER or PEM format. + + :param format: Describes the format of the cert to be loaded, + either PEM or DER (via constants FORMAT_PEM + and FORMAT_FORMAT_DER) + + :return: M2Crypto.X509.X509 object. + """ + string = six.ensure_binary(string) + bio = BIO.MemoryBuffer(string) + return load_cert_bio(bio, format)
    + + +
    [docs]def load_cert_der_string(string): + # type: (AnyStr) -> X509 + """ + Load certificate from a string. + + :param string: String containing a certificate in DER format. + + :return: M2Crypto.X509.X509 object. + """ + string = six.ensure_binary(string) + bio = BIO.MemoryBuffer(string) + cptr = m2.d2i_x509(bio._ptr()) + return X509(cptr, _pyfree=1)
    + + +
    [docs]class X509_Store_Context(object): + """ + X509 Store Context + """ + + m2_x509_store_ctx_free = m2.x509_store_ctx_free + + def __init__(self, x509_store_ctx, _pyfree=0): + # type: (bytes, int) -> None + """ + + :param x509_store_ctx: binary data for + OpenSSL X509_STORE_CTX type + """ + self.ctx = x509_store_ctx + self._pyfree = _pyfree + + def __del__(self): + # type: () -> None + # see BIO.py - unbalanced __init__ / __del__ + if not hasattr(self, '_pyfree'): + pass # print("OOPS") + elif self._pyfree: + self.m2_x509_store_ctx_free(self.ctx) + + def _ptr(self): + return self.ctx + +
    [docs] def get_current_cert(self): + # type: () -> X509 + """ + Get current X.509 certificate. + + :warning: The returned certificate is NOT refcounted, so you can not + rely on it being valid once the store context goes + away or is modified. + """ + return X509(m2.x509_store_ctx_get_current_cert(self.ctx), _pyfree=0)
    + +
    [docs] def get_error(self): + # type: () -> int + """ + Get error code. + """ + return m2.x509_store_ctx_get_error(self.ctx)
    + +
    [docs] def get_error_depth(self): + # type: () -> int + """ + Get error depth. + """ + return m2.x509_store_ctx_get_error_depth(self.ctx)
    + +
    [docs] def get1_chain(self): + # type: () -> X509_Stack + """ + Get certificate chain. + + :return: Reference counted (i.e. safe to use even after the store + context goes away) stack of certificates in the chain. + """ + return X509_Stack(m2.x509_store_ctx_get1_chain(self.ctx), 1, 1)
    + + +
    [docs]class X509_Store(object): + """ + X509 Store + """ + + m2_x509_store_free = m2.x509_store_free + + def __init__(self, store=None, _pyfree=0): + # type: (Optional[bytes], int) -> None + """ + :param store: binary data for OpenSSL X509_STORE_CTX type. + """ + if store is not None: + self.store = store + self._pyfree = _pyfree + else: + self.store = m2.x509_store_new() + self._pyfree = 1 + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_x509_store_free(self.store) + + def _ptr(self): + return self.store + +
    [docs] def load_info(self, file): + # type: (AnyStr) -> int + """ + :param file: filename + + :return: 1 on success, 0 on failure + """ + ret = m2.x509_store_load_locations(self.store, file) + return ret
    + + load_locations = load_info + +
    [docs] def add_x509(self, x509): + # type: (X509) -> int + assert isinstance(x509, X509) + return m2.x509_store_add_cert(self.store, x509._ptr())
    + +
    [docs] def set_verify_cb(self, callback=None): + # type: (Optional[callable]) -> None + """ + Set callback which will be called when the store is verified. + Wrapper over OpenSSL X509_STORE_set_verify_cb(). + + :param callback: Callable to specify verification options. + Type of the callable must be: + (int, X509_Store_Context) -> int. + If None: set the standard options. + + :note: compile-time or run-time errors in the callback would result + in mysterious errors during verification, which could be hard + to trace. + + :note: Python exceptions raised in callbacks do not propagate to + verify() call. + + :return: None + """ + if callback is None: + return self.set_verify_cb(x509_store_default_cb) + + if not callable(callback): + raise X509Error("set_verify(): callback is not callable") + return m2.x509_store_set_verify_cb(self.store, callback)
    + + add_cert = add_x509
    + + +
    [docs]class X509_Stack(object): + """ + X509 Stack + + :warning: Do not modify the underlying OpenSSL stack + except through this interface, or use any OpenSSL + functions that do so indirectly. Doing so will get the + OpenSSL stack and the internal pystack of this class out + of sync, leading to python memory leaks, exceptions or + even python crashes! + """ + + m2_sk_x509_free = m2.sk_x509_free + + def __init__(self, stack=None, _pyfree=0, _pyfree_x509=0): + # type: (bytes, int, int) -> None + if stack is not None: + self.stack = stack + self._pyfree = _pyfree + self.pystack = [] # This must be kept in sync with self.stack + num = m2.sk_x509_num(self.stack) + for i in range(num): + self.pystack.append(X509(m2.sk_x509_value(self.stack, i), + _pyfree=_pyfree_x509)) + else: + self.stack = m2.sk_x509_new_null() + self._pyfree = 1 + self.pystack = [] # This must be kept in sync with self.stack + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_sk_x509_free(self.stack) + + def __len__(self): + # type: () -> int + assert m2.sk_x509_num(self.stack) == len(self.pystack) + return len(self.pystack) + + def __getitem__(self, idx): + # type: (int) -> X509 + return self.pystack[idx] + + def __iter__(self): + return iter(self.pystack) + + def _ptr(self): + return self.stack + +
    [docs] def push(self, x509): + # type: (X509) -> int + """ + push an X509 certificate onto the stack. + + :param x509: X509 object. + + :return: The number of X509 objects currently on the stack. + """ + assert isinstance(x509, X509) + self.pystack.append(x509) + ret = m2.sk_x509_push(self.stack, x509._ptr()) + assert ret == len(self.pystack) + return ret
    + +
    [docs] def pop(self): + # type: () -> X509 + """ + pop a certificate from the stack. + + :return: X509 object that was popped, or None if there is + nothing to pop. + """ + x509_ptr = m2.sk_x509_pop(self.stack) + if x509_ptr is None: + assert len(self.pystack) == 0 + return None + return self.pystack.pop()
    + +
    [docs] def as_der(self): + # type: () -> bytes + """ + Return the stack as a DER encoded string + """ + return m2.get_der_encoding_stack(self.stack)
    + + +
    [docs]def new_stack_from_der(der_string): + # type: (bytes) -> X509_Stack + """ + Create a new X509_Stack from DER string. + + :return: X509_Stack + """ + der_string = six.ensure_binary(der_string) + stack_ptr = m2.make_stack_from_der_sequence(der_string) + return X509_Stack(stack_ptr, 1, 1)
    + + +
    [docs]class Request(object): + """ + X509 Certificate Request. + """ + + m2_x509_req_free = m2.x509_req_free + + def __init__(self, req=None, _pyfree=0): + # type: (Optional[int], int) -> None + if req is not None: + self.req = req + self._pyfree = _pyfree + else: + self.req = m2.x509_req_new() + m2.x509_req_set_version(self.req, 0) + self._pyfree = 1 + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_x509_req_free(self.req) + +
    [docs] def as_text(self): + # type: () -> str + buf = BIO.MemoryBuffer() + m2.x509_req_print(buf.bio_ptr(), self.req) + return six.ensure_text(buf.read_all())
    + +
    [docs] def as_pem(self): + # type: () -> bytes + buf = BIO.MemoryBuffer() + m2.x509_req_write_pem(buf.bio_ptr(), self.req) + return buf.read_all()
    + +
    [docs] def as_der(self): + # type: () -> bytes + buf = BIO.MemoryBuffer() + m2.i2d_x509_req_bio(buf.bio_ptr(), self.req) + return buf.read_all()
    + +
    [docs] def save_pem(self, filename): + # type: (AnyStr) -> int + with BIO.openfile(filename, 'wb') as bio: + return m2.x509_req_write_pem(bio.bio_ptr(), self.req)
    + +
    [docs] def save(self, filename, format=FORMAT_PEM): + # type: (AnyStr, int) -> int + """ + Saves X.509 certificate request to a file. Default output + format is PEM. + + :param filename: Name of the file the request will be saved to. + + :param format: Controls what output format is used to save the + request. Either FORMAT_PEM or FORMAT_DER to save + in PEM or DER format. Raises ValueError if an + unknown format is used. + + :return: 1 for success, 0 for failure. + The error code can be obtained by ERR_get_error. + """ + with BIO.openfile(filename, 'wb') as bio: + if format == FORMAT_PEM: + return m2.x509_req_write_pem(bio.bio_ptr(), self.req) + elif format == FORMAT_DER: + return m2.i2d_x509_req_bio(bio.bio_ptr(), self.req) + else: + raise ValueError( + "Unknown filetype. Must be either FORMAT_DER or FORMAT_PEM")
    + +
    [docs] def get_pubkey(self): + # type: () -> EVP.PKey + """ + Get the public key for the request. + + :return: Public key from the request. + """ + return EVP.PKey(m2.x509_req_get_pubkey(self.req), _pyfree=1)
    + +
    [docs] def set_pubkey(self, pkey): + # type: (EVP.PKey) -> int + """ + Set the public key for the request. + + :param pkey: Public key + + :return: Return 1 for success and 0 for failure. + """ + return m2.x509_req_set_pubkey(self.req, pkey.pkey)
    + +
    [docs] def get_version(self): + # type: () -> int + """ + Get version. + + :return: Returns version. + """ + return m2.x509_req_get_version(self.req)
    + +
    [docs] def set_version(self, version): + # type: (int) -> int + """ + Set version. + + :param version: Version number. + :return: Returns 0 on failure. + """ + return m2.x509_req_set_version(self.req, version)
    + +
    [docs] def get_subject(self): + # type: () -> X509_Name + return X509_Name(m2.x509_req_get_subject_name(self.req))
    + +
    [docs] def set_subject_name(self, name): + # type: (X509_Name) -> int + """ + Set subject name. + + :param name: subjectName field. + :return: 1 for success and 0 for failure + """ + return m2.x509_req_set_subject_name(self.req, name.x509_name)
    + + set_subject = set_subject_name + +
    [docs] def add_extensions(self, ext_stack): + # type: (X509_Extension_Stack) -> int + """ + Add X509 extensions to this request. + + :param ext_stack: Stack of extensions to add. + :return: 1 for success and 0 for failure + """ + return m2.x509_req_add_extensions(self.req, ext_stack._ptr())
    + +
    [docs] def verify(self, pkey): + # type: (EVP.PKey) -> int + """ + + :param pkey: PKey to be verified + :return: 1 for success and 0 for failure + """ + return m2.x509_req_verify(self.req, pkey.pkey)
    + +
    [docs] def sign(self, pkey, md): + # type: (EVP.PKey, str) -> int + """ + + :param pkey: PKey to be signed + :param md: used algorigthm + :return: 1 for success and 0 for failure + """ + mda = getattr(m2, md, None) + if mda is None: + raise ValueError('unknown message digest', md) + return m2.x509_req_sign(self.req, pkey.pkey, mda())
    + + +
    [docs]def load_request(file, format=FORMAT_PEM): + # type: (AnyStr, int) -> Request + """ + Load certificate request from file. + + :param file: Name of file containing certificate request in + either PEM or DER format. + :param format: Describes the format of the file to be loaded, + either PEM or DER. (using constants FORMAT_PEM + and FORMAT_DER) + :return: Request object. + """ + with BIO.openfile(file) as f: + if format == FORMAT_PEM: + cptr = m2.x509_req_read_pem(f.bio_ptr()) + elif format == FORMAT_DER: + cptr = m2.d2i_x509_req(f.bio_ptr()) + else: + raise ValueError( + "Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER") + + return Request(cptr, 1)
    + + +
    [docs]def load_request_bio(bio, format=FORMAT_PEM): + # type: (BIO.BIO, int) -> Request + """ + Load certificate request from a bio. + + :param bio: BIO pointing at a certificate request in + either DER or PEM format. + :param format: Describes the format of the request to be loaded, + either PEM or DER. (using constants FORMAT_PEM + and FORMAT_DER) + :return: M2Crypto.X509.Request object. + """ + if format == FORMAT_PEM: + cptr = m2.x509_req_read_pem(bio._ptr()) + elif format == FORMAT_DER: + cptr = m2.d2i_x509_req(bio._ptr()) + else: + raise ValueError( + "Unknown format. Must be either FORMAT_DER or FORMAT_PEM") + + return Request(cptr, _pyfree=1)
    + + +
    [docs]def load_request_string(string, format=FORMAT_PEM): + # type: (AnyStr, int) -> Request + """ + Load certificate request from a string. + + :param string: String containing a certificate request in + either DER or PEM format. + :param format: Describes the format of the request to be loaded, + either PEM or DER. (using constants FORMAT_PEM + and FORMAT_DER) + + :return: M2Crypto.X509.Request object. + """ + string = six.ensure_binary(string) + bio = BIO.MemoryBuffer(string) + return load_request_bio(bio, format)
    + + +
    [docs]def load_request_der_string(string): + # type: (AnyStr) -> Request + """ + Load certificate request from a string. + + :param string: String containing a certificate request in DER format. + :return: M2Crypto.X509.Request object. + """ + string = six.ensure_binary(string) + bio = BIO.MemoryBuffer(string) + return load_request_bio(bio, FORMAT_DER)
    + + +
    [docs]class CRL(object): + """ + X509 Certificate Revocation List + """ + + m2_x509_crl_free = m2.x509_crl_free + + def __init__(self, crl=None, _pyfree=0): + # type: (Optional[bytes], int) -> None + """ + + :param crl: binary representation of + the underlying OpenSSL X509_CRL object. + """ + if crl is not None: + self.crl = crl + self._pyfree = _pyfree + else: + self.crl = m2.x509_crl_new() + self._pyfree = 1 + + def __del__(self): + # type: () -> None + if getattr(self, '_pyfree', 0): + self.m2_x509_crl_free(self.crl) + +
    [docs] def as_text(self): + # type: () -> str + """ + Return CRL in PEM format in a string. + + :return: String containing the CRL in PEM format. + """ + buf = BIO.MemoryBuffer() + m2.x509_crl_print(buf.bio_ptr(), self.crl) + return six.ensure_text(buf.read_all())
    + + +
    [docs]def load_crl(file): + # type: (AnyStr) -> CRL + """ + Load CRL from file. + + :param file: Name of file containing CRL in PEM format. + + :return: M2Crypto.X509.CRL object. + """ + with BIO.openfile(file) as f: + cptr = m2.x509_crl_read_pem(f.bio_ptr()) + + return CRL(cptr, 1)
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/ftpslib.html b/doc/html/_modules/M2Crypto/ftpslib.html new file mode 100644 index 0000000..b0db673 --- /dev/null +++ b/doc/html/_modules/M2Crypto/ftpslib.html @@ -0,0 +1,195 @@ + + + + + + + + M2Crypto.ftpslib — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.ftpslib

    +from __future__ import absolute_import
    +
    +"""M2Crypto client-side FTP/TLS.
    +
    +This implementation complies with draft-murray-auth-ftp-ssl-07.txt.
    +
    +Example:
    +
    +>>> from M2Crypto import ftpslib
    +>>> f = ftpslib.FTP_TLS()
    +>>> f.connect('', 9021)
    +'220 spinnaker.dyndns.org M2Crypto (Medusa) FTP/TLS server v0.07 ready.'
    +>>> f.auth_tls()
    +>>> f.set_pasv(0)
    +>>> f.login('ftp', 'ngps@')
    +'230 Ok.'
    +>>> f.retrlines('LIST')
    +-rw-rw-r--   1 0        198          2326 Jul  3  1996 apache_pb.gif
    +drwxrwxr-x   7 0        198          1536 Oct 10  2000 manual
    +drwxrwxr-x   2 0        198           512 Oct 31  2000 modpy
    +drwxrwxr-x   2 0        198           512 Oct 31  2000 bobo
    +drwxr-xr-x   2 0        198         14336 May 28 15:54 postgresql
    +drwxr-xr-x   4 100      198           512 May 16 17:19 home
    +drwxr-xr-x   7 100      100          3584 Sep 23  2000 openacs
    +drwxr-xr-x  10 0        0             512 Aug  5  2000 python1.5
    +-rw-r--r--   1 100      198           326 Jul 29 03:29 index.html
    +drwxr-xr-x  12 0        0             512 May 31 17:08 python2.1
    +'226 Transfer complete'
    +>>> f.quit()
    +'221 Goodbye.'
    +>>>
    +
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +# We want to import whole stdlib ftplib objects, because our users want
    +# to use them.
    +from ftplib import *  # noqa
    +
    +# M2Crypto
    +from M2Crypto import SSL
    +
    +
    +
    [docs]class FTP_TLS(FTP): + + """Python OO interface to client-side FTP/TLS.""" + + def __init__(self, host=None, ssl_ctx=None): + """Initialise the client. If 'host' is supplied, connect to it.""" + if ssl_ctx is not None: + self.ssl_ctx = ssl_ctx + else: + self.ssl_ctx = SSL.Context() + FTP.__init__(self, host) + self.prot = 0 + +
    [docs] def auth_tls(self): + """Secure the control connection per AUTH TLS, aka AUTH TLS-C.""" + self.voidcmd('AUTH TLS') + s = SSL.Connection(self.ssl_ctx, self.sock) + s.setup_ssl() + s.set_connect_state() + s.connect_ssl() + self.sock = s + self.file = self.sock.makefile()
    + +
    [docs] def auth_ssl(self): + """Secure the control connection per AUTH SSL, aka AUTH TLS-P.""" + raise NotImplementedError
    + +
    [docs] def prot_p(self): + """Set up secure data connection.""" + self.voidcmd('PBSZ 0') + self.voidcmd('PROT P') + self.prot = 1
    + +
    [docs] def prot_c(self): + """Set up data connection in the clear.""" + self.voidcmd('PROT C') + self.prot = 0
    + +
    [docs] def ntransfercmd(self, cmd, rest=None): + """Initiate a data transfer.""" + conn, size = FTP.ntransfercmd(self, cmd, rest) + if self.prot: + conn = SSL.Connection(self.ssl_ctx, conn) + conn.setup_ssl() + conn.set_connect_state() + conn.set_session(self.sock.get_session()) + conn.connect_ssl() + return conn, size
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/httpslib.html b/doc/html/_modules/M2Crypto/httpslib.html new file mode 100644 index 0000000..93c1cc5 --- /dev/null +++ b/doc/html/_modules/M2Crypto/httpslib.html @@ -0,0 +1,373 @@ + + + + + + + + M2Crypto.httpslib — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.httpslib

    +from __future__ import absolute_import
    +
    +import warnings
    +
    +"""M2Crypto support for Python's httplib.
    +
    +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
    +
    +import base64
    +import socket
    +
    +from M2Crypto import SSL, py27plus, six
    +from M2Crypto.six.moves.urllib_parse import urlsplit, urlunsplit
    +from M2Crypto.six.moves.http_client import *  # noqa
    +# This is not imported with just '*'
    +from M2Crypto.six.moves.http_client import HTTPS_PORT
    +if py27plus:
    +    from typing import Any, AnyStr, Callable, Dict, List, Optional  # noqa
    +
    +
    +
    [docs]class HTTPSConnection(HTTPConnection): + + """ + This class allows communication via SSL using M2Crypto. + """ + + default_port = HTTPS_PORT + + def __init__(self, host, port=None, strict=None, **ssl): + # type: (str, Optional[int], Optional[bool], **Any) -> None + """ + Represents one transaction with an HTTP server over the SSL + connection. + + :param host: host name + :param port: port number + :param strict: if switched on, it raises BadStatusLine to be + raised if the status line can't be parsed as + a valid HTTP/1.0 or 1.1 status line. + :param ssl: dict with all remaining named real parameters of the + function. Specifically, ``ssl_context`` is expected + to be included with SSL.Context; if it is not + default ``'sslv23'`` is substituted). + """ + self.session = None # type: bytes + self.host = host + self.port = port + keys = set(ssl.keys()) - set(('key_file', 'cert_file', 'ssl_context')) + if keys: + raise ValueError('unknown keyword argument: %s', keys) + try: + self.ssl_ctx = ssl['ssl_context'] + assert isinstance(self.ssl_ctx, SSL.Context), self.ssl_ctx + except KeyError: + self.ssl_ctx = SSL.Context() + HTTPConnection.__init__(self, host, port, strict) + +
    [docs] def connect(self): + # type: () -> None + error = None + # We ignore the returned sockaddr because SSL.Connection.connect needs + # a host name. + for (family, _, _, _, _) in \ + socket.getaddrinfo(self.host, self.port, 0, + socket.SOCK_STREAM): + sock = None + try: + sock = SSL.Connection(self.ssl_ctx, family=family) + + # set SNI server name since we know it at this point + sock.set_tlsext_host_name(self.host) + + if self.session is not None: + sock.set_session(self.session) + sock.connect((self.host, self.port)) + + self.sock = sock + sock = None + return + except socket.error as e: + # Other exception are probably SSL-related, in that case we + # abort and the exception is forwarded to the caller. + error = e + finally: + if sock is not None: + sock.close() + + if error is None: + raise AssertionError("Empty list returned by getaddrinfo") + raise error
    + +
    [docs] def close(self): + # type: () -> None + # This kludges around line 545 of httplib.py, + # which closes the connection in this object; + # the connection remains open in the response + # object. + # + # M2Crypto doesn't close-here-keep-open-there, + # so, in effect, we don't close until the whole + # business is over and gc kicks in. + # + # XXX Long-running callers beware leakage. + # + # XXX 05-Jan-2002: This module works with Python 2.2, + # XXX but I've not investigated if the above conditions + # XXX remain. + pass
    + +
    [docs] def get_session(self): + # type: () -> SSL.Session.Session + return self.sock.get_session()
    + +
    [docs] def set_session(self, session): + # type: (SSL.Session.Session) -> None + self.session = session
    + + +
    [docs]class ProxyHTTPSConnection(HTTPSConnection): + """ + An HTTPS Connection that uses a proxy and the CONNECT request. + + When the connection is initiated, CONNECT is first sent to the proxy (along + with authorization headers, if supplied). If successful, an SSL connection + will be established over the socket through the proxy and to the target + host. + + Finally, the actual request is sent over the SSL connection tunneling + through the proxy. + """ + + _ports = {'http': 80, 'https': 443} + _AUTH_HEADER = "Proxy-Authorization" + _UA_HEADER = "User-Agent" + + def __init__(self, host, port=None, strict=None, username=None, + password=None, **ssl): + # type: (str, Optional[int], Optional[bool], Optional[AnyStr], Optional[AnyStr], **Any) -> None + """ + Create the ProxyHTTPSConnection object. + + :param host: host name of the proxy server + :param port: port number of the proxy server + :param strict: if switched on, it raises BadStatusLine to be + raised if the status line can't be parsed as + a valid HTTP/1.0 or 1.1 status line. + :param username: username on the proxy server, when required + Username can be ``str``, but preferred type + is ``bytes``. M2Crypto does some conversion to + ``bytes`` when necessary, but it's better when + the user of the library does it on its own. + :param password: password on the proxy server, when required + The same as with ``username``, ``str`` is accepted, + but ``bytes`` are preferred. + :param ssl: dict with all remaining named real parameters of the + function. Specifically, ``ssl_context`` is expected + to be included with SSL.Context; if it is not + default ``'sslv23'`` is substituted). + """ + HTTPSConnection.__init__(self, host, port, strict, **ssl) + + self._username = username.encode('utf8') \ + if isinstance(username, six.string_types) else username + self._password = password.encode('utf8') \ + if isinstance(password, six.string_types) else password + self._proxy_auth = None # type: str + self._proxy_UA = None # type: str + +
    [docs] def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0): + # type: (AnyStr, AnyStr, int, int) -> None + """ + putrequest is called before connect, so can interpret url and get + real host/port to be used to make CONNECT request to proxy + """ + proto, netloc, path, query, fragment = urlsplit(url) + if not proto: + raise ValueError("unknown URL type: %s" % url) + + # get host & port + try: + username_password, host_port = netloc.split('@') + except ValueError: + host_port = netloc + + try: + host, port_s = host_port.split(':') + port = int(port_s) + except ValueError: + host = host_port + # try to get port from proto + try: + port = self._ports[proto] + except KeyError: + raise ValueError("unknown protocol for: %s" % url) + + self._real_host = host # type: str + self._real_port = port # type: int + rest = urlunsplit(('', '', path, query, fragment)) + HTTPSConnection.putrequest(self, method, rest, skip_host, + skip_accept_encoding)
    + +
    [docs] def putheader(self, header, value): + # type: (AnyStr, AnyStr) -> None + # Store the auth header if passed in. + if header.lower() == self._UA_HEADER.lower(): + self._proxy_UA = value + if header.lower() == self._AUTH_HEADER.lower(): + self._proxy_auth = value + else: + HTTPSConnection.putheader(self, header, value)
    + +
    [docs] def endheaders(self, *args, **kwargs): + # type: (*Any, **Any) -> None + # We've recieved all of hte headers. Use the supplied username + # and password for authorization, possibly overriding the authstring + # supplied in the headers. + if not self._proxy_auth: + self._proxy_auth = self._encode_auth() + + HTTPSConnection.endheaders(self, *args, **kwargs)
    + +
    [docs] def connect(self): + # type: () -> None + HTTPConnection.connect(self) + + # send proxy CONNECT request + self.sock.sendall(self._get_connect_msg()) + response = HTTPResponse(self.sock) + response.begin() + + code = response.status + if code != 200: + # proxy returned and error, abort connection, and raise exception + self.close() + raise socket.error("Proxy connection failed: %d" % code) + + self._start_ssl()
    + + def _get_connect_msg(self): + # type: () -> bytes + """ Return an HTTP CONNECT request to send to the proxy. """ + msg = "CONNECT %s:%d HTTP/1.1\r\n" % (self._real_host, self._real_port) + msg = msg + "Host: %s:%d\r\n" % (self._real_host, self._real_port) + if self._proxy_UA: + msg = msg + "%s: %s\r\n" % (self._UA_HEADER, self._proxy_UA) + if self._proxy_auth: + msg = msg + "%s: %s\r\n" % (self._AUTH_HEADER, self._proxy_auth) + msg = msg + "\r\n" + return six.ensure_binary(msg) + + def _start_ssl(self): + # type: () -> None + """ Make this connection's socket SSL-aware. """ + self.sock = SSL.Connection(self.ssl_ctx, self.sock) + self.sock.setup_ssl() + self.sock.set_connect_state() + self.sock.connect_ssl() + + def _encode_auth(self): + # type: () -> Optional[bytes] + """ Encode the username and password for use in the auth header. """ + if not (self._username and self._password): + return None + # Authenticated proxy + userpass = "%s:%s" % (self._username, self._password) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + enc_userpass = base64.encodestring(userpass).replace("\n", "") + return six.ensure_binary("Basic %s" % enc_userpass)
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/m2urllib.html b/doc/html/_modules/M2Crypto/m2urllib.html new file mode 100644 index 0000000..bb1f8cb --- /dev/null +++ b/doc/html/_modules/M2Crypto/m2urllib.html @@ -0,0 +1,225 @@ + + + + + + + + M2Crypto.m2urllib — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.m2urllib

    +from __future__ import absolute_import, print_function
    +
    +"""M2Crypto enhancement to Python's urllib for handling
    +'https' url's.
    +
    +FIXME: it is questionable whether we need this old-style module at all. urllib
    +(not urllib2) is in Python 3 support just as a legacy API.
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +import base64
    +import warnings
    +
    +from M2Crypto import SSL, httpslib, six, util
    +
    +from M2Crypto.six.moves.urllib_response import addinfourl
    +if util.py27plus:
    +    from typing import AnyStr, Optional  # noqa
    +
    +# six.moves doesn't support star imports
    +if six.PY3:
    +    from urllib.request import *  # noqa for other modules to import
    +    from urllib.parse import *  # noqa for other modules to import
    +    from urllib.error import *  # noqa for other modules to import
    +else:
    +    from urllib import *  # noqa
    +
    +
    +
    [docs]def open_https(self, url, data=None, ssl_context=None): + # type: (URLOpener, AnyStr, Optional[bytes], Optional[SSL.Context]) -> addinfourl + """ + Open URL over the SSL connection. + + :param url: URL to be opened + :param data: data for the POST request + :param ssl_context: SSL.Context to be used + :return: + """ + if six.PY3: + warnings.warn('URLOpener has been deprecated in Py3k', DeprecationWarning) + + if ssl_context is not None and isinstance(ssl_context, SSL.Context): + self.ctx = ssl_context + else: + self.ctx = SSL.Context() + user_passwd = None + if isinstance(url, six.string_types): + try: # python 2 + # http://pydoc.org/2.5.1/urllib.html + host, selector = splithost(url) + if host: + user_passwd, host = splituser(host) + host = unquote(host) + realhost = host + except NameError: # python 3 has no splithost + # https://docs.python.org/3/library/urllib.parse.html + parsed = urlparse(url) + host = parsed.hostname + if parsed.port: + host += ":{0}".format(parsed.port) + user_passwd = parsed.password + if parsed.password: + user_passwd += ":{0}".format(parsed.password) + selector = parsed.path + else: + host, selector = url + urltype, rest = splittype(selector) + url = rest + user_passwd = None + if urltype.lower() != 'http': + realhost = None + else: + try: # python 2 + realhost, rest = splithost(rest) + if realhost: + user_passwd, realhost = splituser(realhost) + if user_passwd: + selector = "%s://%s%s" % (urltype, realhost, rest) + except NameError: # python 3 has no splithost + parsed = urlparse(rest) + host = parsed.hostname + if parsed.port: + host += ":{0}".format(parsed.port) + user_passwd = parsed.username + if parsed.password: + user_passwd += ":{0}".format(parsed.password) + # print("proxy via http:", host, selector) + if not host: + raise IOError('http error', 'no host given') + if user_passwd: + if six.PY3: + auth = base64.encodebytes(user_passwd).strip() + else: + auth = base64.encodestring(user_passwd).strip() + else: + auth = None + # Start here! + h = httpslib.HTTPSConnection(host=host, ssl_context=self.ctx) + # h.set_debuglevel(1) + # Stop here! + if data is not None: + h.putrequest('POST', selector) + h.putheader('Content-type', 'application/x-www-form-urlencoded') + h.putheader('Content-length', '%d' % len(data)) + else: + h.putrequest('GET', selector) + if auth: + h.putheader('Authorization', 'Basic %s' % auth) + for args in self.addheaders: + h.putheader(*args) # for python3 - used to use apply + h.endheaders() + if data is not None: + h.send(data + '\r\n') + # Here again! + resp = h.getresponse() + fp = resp.fp + return addinfourl(fp, resp.msg, "https:" + url)
    + # Stop again. + +# Minor brain surgery. +URLopener.open_https = open_https +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/m2urllib2.html b/doc/html/_modules/M2Crypto/m2urllib2.html new file mode 100644 index 0000000..23bf5f2 --- /dev/null +++ b/doc/html/_modules/M2Crypto/m2urllib2.html @@ -0,0 +1,290 @@ + + + + + + + + M2Crypto.m2urllib2 — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.m2urllib2

    +from __future__ import absolute_import
    +
    +"""
    +M2Crypto enhancement to Python's urllib2 for handling
    +'https' url's.
    +
    +Code from urllib2 is Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007
    +Python Software Foundation; All Rights Reserved
    +
    +Summary of changes:
    + - Use an HTTPSProxyConnection if the request is going through a proxy.
    + - Add the SSL context to the https connection when performing https_open.
    + - Add the M2Crypto HTTPSHandler when building a default opener.
    +"""
    +
    +import socket
    +
    +from M2Crypto import SSL, httpslib, six, util
    +
    +from M2Crypto.six.moves.urllib_parse import urldefrag, urlparse as url_parse
    +from M2Crypto.six.moves.urllib_response import addinfourl
    +if util.py27plus:
    +    from typing import List, Optional  # noqa
    +
    +# six.moves doesn't support star imports
    +if six.PY3:
    +    from urllib.request import *  # noqa other modules want to import
    +    from urllib.error import *  # noqa other modules want to import
    +else:
    +    from urllib2 import *  # noqa
    +
    +
    +try:
    +    mother_class = socket._fileobject
    +except AttributeError:
    +    mother_class = socket.SocketIO
    +
    +
    +class _closing_fileobject(mother_class):  # noqa
    +    """socket._fileobject that propagates self.close() to the socket.
    +
    +    Python 2.5 provides this as socket._fileobject(sock, close=True).
    +    """
    +
    +# for python 3
    +try:
    +    AbstractHTTPHandler
    +except NameError:
    +    # somehow this won't get imported by the import * above
    +    import urllib.request
    +    AbstractHTTPHandler = urllib.request.AbstractHTTPHandler
    +
    +
    +
    [docs]class HTTPSHandler(AbstractHTTPHandler): + def __init__(self, ssl_context=None): + # type: (SSL.Context) -> None + AbstractHTTPHandler.__init__(self) + + if ssl_context is not None: + assert isinstance(ssl_context, SSL.Context), ssl_context + self.ctx = ssl_context + else: + self.ctx = SSL.Context() + + # Copied from urllib2, so we can set the ssl context. +
    [docs] def https_open(self, req): + # type: (Request) -> addinfourl + """Return an addinfourl object for the request, using http_class. + + http_class must implement the HTTPConnection API from httplib. + The addinfourl return value is a file-like object. It also + has methods and attributes including: + + - info(): return a mimetools.Message object for the headers + + - geturl(): return the original request URL + + - code: HTTP status code + """ + # https://docs.python.org/3.3/library/urllib.request.html#urllib.request.Request.get_host + try: # up to python-3.2 + host = req.get_host() + except AttributeError: # from python-3.3 + host = req.host + if not host: + raise URLError('no host given') + + # Our change: Check to see if we're using a proxy. + # Then create an appropriate ssl-aware connection. + full_url = req.get_full_url() + target_host = url_parse(full_url)[1] + + if target_host != host: + request_uri = urldefrag(full_url)[0] + h = httpslib.ProxyHTTPSConnection(host=host, ssl_context=self.ctx) + else: + try: # up to python-3.2 + request_uri = req.get_selector() + except AttributeError: # from python-3.3 + request_uri = req.selector + h = httpslib.HTTPSConnection(host=host, ssl_context=self.ctx) + # End our change + h.set_debuglevel(self._debuglevel) + + headers = dict(req.headers) + headers.update(req.unredirected_hdrs) + # We want to make an HTTP/1.1 request, but the addinfourl + # class isn't prepared to deal with a persistent connection. + # It will try to read all remaining data from the socket, + # which will block while the server waits for the next request. + # So make sure the connection gets closed after the (only) + # request. + headers["Connection"] = "close" + try: + h.request(req.get_method(), request_uri, req.data, headers) + r = h.getresponse() + except socket.error as err: # XXX what error? + raise URLError(err) + + # Pick apart the HTTPResponse object to get the addinfourl + # object initialized properly. + + # Wrap the HTTPResponse object in socket's file object adapter + # for Windows. That adapter calls recv(), so delegate recv() + # to read(). This weird wrapping allows the returned object to + # have readline() and readlines() methods. + r.recv = r.read + if six.PY2: + fp = socket._fileobject(r, close=True) + else: + r._decref_socketios = lambda: None + r.ssl = h.sock.ssl + r._timeout = -1.0 + r.recv_into = r.readinto + fp = socket.SocketIO(r, 'rb') + + resp = addinfourl(fp, r.msg, req.get_full_url()) + resp.code = r.status + resp.msg = r.reason + return resp
    + + https_request = AbstractHTTPHandler.do_request_
    + + +# Copied from urllib2 with modifications for ssl +
    [docs]def build_opener(ssl_context=None, *handlers): + # type: (Optional[SSL.Context], *object) -> OpenerDirector + """Create an opener object from a list of handlers. + + The opener will use several default handlers, including support + for HTTP and FTP. + + If any of the handlers passed as arguments are subclasses of the + default handlers, the default handlers will not be used. + """ + + def isclass(obj): + return isinstance(obj, type) or hasattr(obj, "__bases__") + + opener = OpenerDirector() + default_classes = [ProxyHandler, UnknownHandler, HTTPHandler, + HTTPDefaultErrorHandler, HTTPRedirectHandler, + FTPHandler, FileHandler, HTTPErrorProcessor] + skip = [] + for klass in default_classes: + for check in handlers: + if isclass(check): + if issubclass(check, klass): + skip.append(klass) + elif isinstance(check, klass): + skip.append(klass) + for klass in skip: + default_classes.remove(klass) + + for klass in default_classes: + opener.add_handler(klass()) + + # Add the HTTPS handler with ssl_context + if HTTPSHandler not in skip: + opener.add_handler(HTTPSHandler(ssl_context)) + + for h in handlers: + if isclass(h): + h = h() + opener.add_handler(h) + return opener
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/m2xmlrpclib.html b/doc/html/_modules/M2Crypto/m2xmlrpclib.html new file mode 100644 index 0000000..fb3834f --- /dev/null +++ b/doc/html/_modules/M2Crypto/m2xmlrpclib.html @@ -0,0 +1,183 @@ + + + + + + + + M2Crypto.m2xmlrpclib — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.m2xmlrpclib

    +from __future__ import absolute_import
    +
    +"""M2Crypto enhancement to xmlrpclib.
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +import base64
    +
    +import M2Crypto
    +
    +from M2Crypto import SSL, httpslib, m2urllib, six, util
    +if util.py27plus:
    +    from typing import Any, AnyStr, Callable, Optional  # noqa
    +
    +from M2Crypto.six.moves.xmlrpc_client import ProtocolError, Transport
    +# six.moves doesn't support star imports
    +if six.PY3:
    +    from xmlrpc.client import *  # noqa
    +else:
    +    from xmlrpclib import *  # noqa
    +
    +__version__ = M2Crypto.__version__
    +
    +
    +
    [docs]class SSL_Transport(Transport): + + user_agent = "M2Crypto_XMLRPC/%s - %s" % (__version__, + Transport.user_agent) + + def __init__(self, ssl_context=None, *args, **kw): + # type: (Optional[SSL.Context], *Any, **Any) -> None + Transport.__init__(self, *args, **kw) + if ssl_context is None: + self.ssl_ctx = SSL.Context() + else: + self.ssl_ctx = ssl_context + +
    [docs] def request(self, host, handler, request_body, verbose=0): + # type: (AnyStr, Callable, bytes, int) -> object + # Handle username and password. + user_passwd, host_port = m2urllib.splituser(host) + _host, _port = m2urllib.splitport(host_port) + h = httpslib.HTTPSConnection(_host, int(_port), + ssl_context=self.ssl_ctx) + if verbose: + h.set_debuglevel(1) + + # What follows is as in xmlrpclib.Transport. (Except the authz bit.) + h.putrequest("POST", handler) + + # required by HTTP/1.1 + h.putheader("Host", _host) + + # required by XML-RPC + h.putheader("User-Agent", self.user_agent) + h.putheader("Content-Type", "text/xml") + h.putheader("Content-Length", str(len(request_body))) + + # Authorisation. + if user_passwd is not None: + auth = base64.encodestring(user_passwd).strip() + h.putheader('Authorization', 'Basic %s' % auth) + + h.endheaders() + + if request_body: + h.send(request_body) + + errcode, errmsg, headers = h.getreply() + + if errcode != 200: + raise ProtocolError( + host + handler, + errcode, errmsg, + headers + ) + + self.verbose = verbose + return self.parse_response(h.getfile())
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/threading.html b/doc/html/_modules/M2Crypto/threading.html new file mode 100644 index 0000000..7074d6c --- /dev/null +++ b/doc/html/_modules/M2Crypto/threading.html @@ -0,0 +1,129 @@ + + + + + + + + M2Crypto.threading — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.threading

    +from __future__ import absolute_import
    +
    +"""
    +M2Crypto threading support, required for multithreaded applications.
    +
    +Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
    +
    +# M2Crypto
    +from M2Crypto import m2
    +
    +
    +
    [docs]def init(): + # type: () -> None + """ + Initialize threading support. + """ + m2.threading_init()
    + + +
    [docs]def cleanup(): + # type: () -> None + """ + End and cleanup threading support. + """ + m2.threading_cleanup()
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/M2Crypto/util.html b/doc/html/_modules/M2Crypto/util.html new file mode 100644 index 0000000..3cd7461 --- /dev/null +++ b/doc/html/_modules/M2Crypto/util.html @@ -0,0 +1,193 @@ + + + + + + + + M2Crypto.util — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for M2Crypto.util

    +from __future__ import absolute_import
    +"""
    +    M2Crypto utility routines.
    +
    +    NOTHING IN THIS MODULE IS GUARANTEED TO BE STABLE, USED ONLY FOR
    +    INTERNAL PURPOSES OF M2CRYPTO.
    +
    +    Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
    +
    +    Portions created by Open Source Applications Foundation (OSAF) are
    +    Copyright (C) 2004 OSAF. All Rights Reserved.
    +"""
    +
    +import binascii
    +import logging
    +import sys
    +
    +from M2Crypto import m2, py27plus, six
    +if py27plus:
    +    from typing import Any, AnyStr, Optional, Tuple, Union  # noqa
    +    # see https://github.com/python/typeshed/issues/222
    +    AddrType = Union[Tuple[str, int], str]
    +
    +log = logging.getLogger('util')
    +
    +
    +
    [docs]class UtilError(Exception): + pass
    + +m2.util_init(UtilError) + + +
    [docs]def pkcs5_pad(data, blklen=8): + # type: (str, int) -> str + pad = (8 - (len(data) % 8)) + return data + chr(pad) * pad
    + + +
    [docs]def pkcs7_pad(data, blklen): + # type: (str, int) -> str + if blklen > 255: + raise ValueError('illegal block size') + pad = (blklen - (len(data) % blklen)) + return data + chr(pad) * pad
    + + +
    [docs]def bin_to_hex(b): + # type: (bytes) -> str + return six.ensure_text(binascii.b2a_base64(b)[:-1])
    + + +
    [docs]def octx_to_num(x): + # type: (bytes) -> int + return int(binascii.hexlify(x), 16)
    + + +
    [docs]def genparam_callback(p, n, out=sys.stdout): + # type: (int, Any, file) -> None + ch = ['.', '+', '*', '\n'] + out.write(ch[p]) + out.flush()
    + + +
    [docs]def quiet_genparam_callback(p, n, out): + # type: (Any, Any, Any) -> None + pass
    + + +
    [docs]def passphrase_callback(v, prompt1='Enter passphrase:', + prompt2='Verify passphrase:'): + # type: (bool, str, str) -> Optional[str] + from getpass import getpass + while 1: + try: + p1 = getpass(prompt1) + if v: + p2 = getpass(prompt2) + if p1 == p2: + break + else: + break + except KeyboardInterrupt: + return None + return p1
    + + +
    [docs]def no_passphrase_callback(*args): + # type: (*Any) -> str + return ''
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/index.html b/doc/html/_modules/index.html new file mode 100644 index 0000000..56bc7ef --- /dev/null +++ b/doc/html/_modules/index.html @@ -0,0 +1,137 @@ + + + + + + + + Overview: module code — M2Crypto documentation + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/html/_modules/urllib/request.html b/doc/html/_modules/urllib/request.html new file mode 100644 index 0000000..ee22b9d --- /dev/null +++ b/doc/html/_modules/urllib/request.html @@ -0,0 +1,2841 @@ + + + + + + + + urllib.request — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Source code for urllib.request

    +"""An extensible library for opening URLs using a variety of protocols
    +
    +The simplest way to use this module is to call the urlopen function,
    +which accepts a string containing a URL or a Request object (described
    +below).  It opens the URL and returns the results as file-like
    +object; the returned object has some extra methods described below.
    +
    +The OpenerDirector manages a collection of Handler objects that do
    +all the actual work.  Each Handler implements a particular protocol or
    +option.  The OpenerDirector is a composite object that invokes the
    +Handlers needed to open the requested URL.  For example, the
    +HTTPHandler performs HTTP GET and POST requests and deals with
    +non-error returns.  The HTTPRedirectHandler automatically deals with
    +HTTP 301, 302, 303 and 307 redirect errors, and the HTTPDigestAuthHandler
    +deals with digest authentication.
    +
    +urlopen(url, data=None) -- Basic usage is the same as original
    +urllib.  pass the url and optionally data to post to an HTTP URL, and
    +get a file-like object back.  One difference is that you can also pass
    +a Request instance instead of URL.  Raises a URLError (subclass of
    +OSError); for HTTP errors, raises an HTTPError, which can also be
    +treated as a valid response.
    +
    +build_opener -- Function that creates a new OpenerDirector instance.
    +Will install the default handlers.  Accepts one or more Handlers as
    +arguments, either instances or Handler classes that it will
    +instantiate.  If one of the argument is a subclass of the default
    +handler, the argument will be installed instead of the default.
    +
    +install_opener -- Installs a new opener as the default opener.
    +
    +objects of interest:
    +
    +OpenerDirector -- Sets up the User Agent as the Python-urllib client and manages
    +the Handler classes, while dealing with requests and responses.
    +
    +Request -- An object that encapsulates the state of a request.  The
    +state can be as simple as the URL.  It can also include extra HTTP
    +headers, e.g. a User-Agent.
    +
    +BaseHandler --
    +
    +internals:
    +BaseHandler and parent
    +_call_chain conventions
    +
    +Example usage:
    +
    +import urllib.request
    +
    +# set up authentication info
    +authinfo = urllib.request.HTTPBasicAuthHandler()
    +authinfo.add_password(realm='PDQ Application',
    +                      uri='https://mahler:8092/site-updates.py',
    +                      user='klem',
    +                      passwd='geheim$parole')
    +
    +proxy_support = urllib.request.ProxyHandler({"http" : "http://ahad-haam:3128"})
    +
    +# build a new opener that adds authentication and caching FTP handlers
    +opener = urllib.request.build_opener(proxy_support, authinfo,
    +                                     urllib.request.CacheFTPHandler)
    +
    +# install it
    +urllib.request.install_opener(opener)
    +
    +f = urllib.request.urlopen('http://www.python.org/')
    +"""
    +
    +# XXX issues:
    +# If an authentication error handler that tries to perform
    +# authentication for some reason but fails, how should the error be
    +# signalled?  The client needs to know the HTTP error code.  But if
    +# the handler knows that the problem was, e.g., that it didn't know
    +# that hash algo that requested in the challenge, it would be good to
    +# pass that information along to the client, too.
    +# ftp errors aren't handled cleanly
    +# check digest against correct (i.e. non-apache) implementation
    +
    +# Possible extensions:
    +# complex proxies  XXX not sure what exactly was meant by this
    +# abstract factory for opener
    +
    +import base64
    +import bisect
    +import email
    +import hashlib
    +import http.client
    +import io
    +import os
    +import posixpath
    +import re
    +import socket
    +import string
    +import sys
    +import time
    +import tempfile
    +import contextlib
    +import warnings
    +
    +
    +from urllib.error import URLError, HTTPError, ContentTooShortError
    +from urllib.parse import (
    +    urlparse, urlsplit, urljoin, unwrap, quote, unquote,
    +    splittype, splithost, splitport, splituser, splitpasswd,
    +    splitattr, splitquery, splitvalue, splittag, to_bytes,
    +    unquote_to_bytes, urlunparse)
    +from urllib.response import addinfourl, addclosehook
    +
    +# check for SSL
    +try:
    +    import ssl
    +except ImportError:
    +    _have_ssl = False
    +else:
    +    _have_ssl = True
    +
    +__all__ = [
    +    # Classes
    +    'Request', 'OpenerDirector', 'BaseHandler', 'HTTPDefaultErrorHandler',
    +    'HTTPRedirectHandler', 'HTTPCookieProcessor', 'ProxyHandler',
    +    'HTTPPasswordMgr', 'HTTPPasswordMgrWithDefaultRealm',
    +    'HTTPPasswordMgrWithPriorAuth', 'AbstractBasicAuthHandler',
    +    'HTTPBasicAuthHandler', 'ProxyBasicAuthHandler', 'AbstractDigestAuthHandler',
    +    'HTTPDigestAuthHandler', 'ProxyDigestAuthHandler', 'HTTPHandler',
    +    'FileHandler', 'FTPHandler', 'CacheFTPHandler', 'DataHandler',
    +    'UnknownHandler', 'HTTPErrorProcessor',
    +    # Functions
    +    'urlopen', 'install_opener', 'build_opener',
    +    'pathname2url', 'url2pathname', 'getproxies',
    +    # Legacy interface
    +    'urlretrieve', 'urlcleanup', 'URLopener', 'FancyURLopener',
    +]
    +
    +# used in User-Agent header sent
    +__version__ = '%d.%d' % sys.version_info[:2]
    +
    +_opener = None
    +def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
    +            *, cafile=None, capath=None, cadefault=False, context=None):
    +    '''Open the URL url, which can be either a string or a Request object.
    +
    +    *data* must be an object specifying additional data to be sent to
    +    the server, or None if no such data is needed.  See Request for
    +    details.
    +
    +    urllib.request module uses HTTP/1.1 and includes a "Connection:close"
    +    header in its HTTP requests.
    +
    +    The optional *timeout* parameter specifies a timeout in seconds for
    +    blocking operations like the connection attempt (if not specified, the
    +    global default timeout setting will be used). This only works for HTTP,
    +    HTTPS and FTP connections.
    +
    +    If *context* is specified, it must be a ssl.SSLContext instance describing
    +    the various SSL options. See HTTPSConnection for more details.
    +
    +    The optional *cafile* and *capath* parameters specify a set of trusted CA
    +    certificates for HTTPS requests. cafile should point to a single file
    +    containing a bundle of CA certificates, whereas capath should point to a
    +    directory of hashed certificate files. More information can be found in
    +    ssl.SSLContext.load_verify_locations().
    +
    +    The *cadefault* parameter is ignored.
    +
    +    This function always returns an object which can work as a context
    +    manager and has methods such as
    +
    +    * geturl() - return the URL of the resource retrieved, commonly used to
    +      determine if a redirect was followed
    +
    +    * info() - return the meta-information of the page, such as headers, in the
    +      form of an email.message_from_string() instance (see Quick Reference to
    +      HTTP Headers)
    +
    +    * getcode() - return the HTTP status code of the response.  Raises URLError
    +      on errors.
    +
    +    For HTTP and HTTPS URLs, this function returns a http.client.HTTPResponse
    +    object slightly modified. In addition to the three new methods above, the
    +    msg attribute contains the same information as the reason attribute ---
    +    the reason phrase returned by the server --- instead of the response
    +    headers as it is specified in the documentation for HTTPResponse.
    +
    +    For FTP, file, and data URLs and requests explicitly handled by legacy
    +    URLopener and FancyURLopener classes, this function returns a
    +    urllib.response.addinfourl object.
    +
    +    Note that None may be returned if no handler handles the request (though
    +    the default installed global OpenerDirector uses UnknownHandler to ensure
    +    this never happens).
    +
    +    In addition, if proxy settings are detected (for example, when a *_proxy
    +    environment variable like http_proxy is set), ProxyHandler is default
    +    installed and makes sure the requests are handled through the proxy.
    +
    +    '''
    +    global _opener
    +    if cafile or capath or cadefault:
    +        import warnings
    +        warnings.warn("cafile, capath and cadefault are deprecated, use a "
    +                      "custom context instead.", DeprecationWarning, 2)
    +        if context is not None:
    +            raise ValueError(
    +                "You can't pass both context and any of cafile, capath, and "
    +                "cadefault"
    +            )
    +        if not _have_ssl:
    +            raise ValueError('SSL support not available')
    +        context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH,
    +                                             cafile=cafile,
    +                                             capath=capath)
    +        https_handler = HTTPSHandler(context=context)
    +        opener = build_opener(https_handler)
    +    elif context:
    +        https_handler = HTTPSHandler(context=context)
    +        opener = build_opener(https_handler)
    +    elif _opener is None:
    +        _opener = opener = build_opener()
    +    else:
    +        opener = _opener
    +    return opener.open(url, data, timeout)
    +
    +def install_opener(opener):
    +    global _opener
    +    _opener = opener
    +
    +_url_tempfiles = []
    +def urlretrieve(url, filename=None, reporthook=None, data=None):
    +    """
    +    Retrieve a URL into a temporary location on disk.
    +
    +    Requires a URL argument. If a filename is passed, it is used as
    +    the temporary file location. The reporthook argument should be
    +    a callable that accepts a block number, a read size, and the
    +    total file size of the URL target. The data argument should be
    +    valid URL encoded data.
    +
    +    If a filename is passed and the URL points to a local resource,
    +    the result is a copy from local file to new file.
    +
    +    Returns a tuple containing the path to the newly created
    +    data file as well as the resulting HTTPMessage object.
    +    """
    +    url_type, path = splittype(url)
    +
    +    with contextlib.closing(urlopen(url, data)) as fp:
    +        headers = fp.info()
    +
    +        # Just return the local path and the "headers" for file://
    +        # URLs. No sense in performing a copy unless requested.
    +        if url_type == "file" and not filename:
    +            return os.path.normpath(path), headers
    +
    +        # Handle temporary file setup.
    +        if filename:
    +            tfp = open(filename, 'wb')
    +        else:
    +            tfp = tempfile.NamedTemporaryFile(delete=False)
    +            filename = tfp.name
    +            _url_tempfiles.append(filename)
    +
    +        with tfp:
    +            result = filename, headers
    +            bs = 1024*8
    +            size = -1
    +            read = 0
    +            blocknum = 0
    +            if "content-length" in headers:
    +                size = int(headers["Content-Length"])
    +
    +            if reporthook:
    +                reporthook(blocknum, bs, size)
    +
    +            while True:
    +                block = fp.read(bs)
    +                if not block:
    +                    break
    +                read += len(block)
    +                tfp.write(block)
    +                blocknum += 1
    +                if reporthook:
    +                    reporthook(blocknum, bs, size)
    +
    +    if size >= 0 and read < size:
    +        raise ContentTooShortError(
    +            "retrieval incomplete: got only %i out of %i bytes"
    +            % (read, size), result)
    +
    +    return result
    +
    +def urlcleanup():
    +    """Clean up temporary files from urlretrieve calls."""
    +    for temp_file in _url_tempfiles:
    +        try:
    +            os.unlink(temp_file)
    +        except OSError:
    +            pass
    +
    +    del _url_tempfiles[:]
    +    global _opener
    +    if _opener:
    +        _opener = None
    +
    +# copied from cookielib.py
    +_cut_port_re = re.compile(r":\d+$", re.ASCII)
    +def request_host(request):
    +    """Return request-host, as defined by RFC 2965.
    +
    +    Variation from RFC: returned value is lowercased, for convenient
    +    comparison.
    +
    +    """
    +    url = request.full_url
    +    host = urlparse(url)[1]
    +    if host == "":
    +        host = request.get_header("Host", "")
    +
    +    # remove port, if present
    +    host = _cut_port_re.sub("", host, 1)
    +    return host.lower()
    +
    +class Request:
    +
    +    def __init__(self, url, data=None, headers={},
    +                 origin_req_host=None, unverifiable=False,
    +                 method=None):
    +        self.full_url = url
    +        self.headers = {}
    +        self.unredirected_hdrs = {}
    +        self._data = None
    +        self.data = data
    +        self._tunnel_host = None
    +        for key, value in headers.items():
    +            self.add_header(key, value)
    +        if origin_req_host is None:
    +            origin_req_host = request_host(self)
    +        self.origin_req_host = origin_req_host
    +        self.unverifiable = unverifiable
    +        if method:
    +            self.method = method
    +
    +    @property
    +    def full_url(self):
    +        if self.fragment:
    +            return '{}#{}'.format(self._full_url, self.fragment)
    +        return self._full_url
    +
    +    @full_url.setter
    +    def full_url(self, url):
    +        # unwrap('<URL:type://host/path>') --> 'type://host/path'
    +        self._full_url = unwrap(url)
    +        self._full_url, self.fragment = splittag(self._full_url)
    +        self._parse()
    +
    +    @full_url.deleter
    +    def full_url(self):
    +        self._full_url = None
    +        self.fragment = None
    +        self.selector = ''
    +
    +    @property
    +    def data(self):
    +        return self._data
    +
    +    @data.setter
    +    def data(self, data):
    +        if data != self._data:
    +            self._data = data
    +            # issue 16464
    +            # if we change data we need to remove content-length header
    +            # (cause it's most probably calculated for previous value)
    +            if self.has_header("Content-length"):
    +                self.remove_header("Content-length")
    +
    +    @data.deleter
    +    def data(self):
    +        self.data = None
    +
    +    def _parse(self):
    +        self.type, rest = splittype(self._full_url)
    +        if self.type is None:
    +            raise ValueError("unknown url type: %r" % self.full_url)
    +        self.host, self.selector = splithost(rest)
    +        if self.host:
    +            self.host = unquote(self.host)
    +
    +    def get_method(self):
    +        """Return a string indicating the HTTP request method."""
    +        default_method = "POST" if self.data is not None else "GET"
    +        return getattr(self, 'method', default_method)
    +
    +    def get_full_url(self):
    +        return self.full_url
    +
    +    def set_proxy(self, host, type):
    +        if self.type == 'https' and not self._tunnel_host:
    +            self._tunnel_host = self.host
    +        else:
    +            self.type= type
    +            self.selector = self.full_url
    +        self.host = host
    +
    +    def has_proxy(self):
    +        return self.selector == self.full_url
    +
    +    def add_header(self, key, val):
    +        # useful for something like authentication
    +        self.headers[key.capitalize()] = val
    +
    +    def add_unredirected_header(self, key, val):
    +        # will not be added to a redirected request
    +        self.unredirected_hdrs[key.capitalize()] = val
    +
    +    def has_header(self, header_name):
    +        return (header_name in self.headers or
    +                header_name in self.unredirected_hdrs)
    +
    +    def get_header(self, header_name, default=None):
    +        return self.headers.get(
    +            header_name,
    +            self.unredirected_hdrs.get(header_name, default))
    +
    +    def remove_header(self, header_name):
    +        self.headers.pop(header_name, None)
    +        self.unredirected_hdrs.pop(header_name, None)
    +
    +    def header_items(self):
    +        hdrs = self.unredirected_hdrs.copy()
    +        hdrs.update(self.headers)
    +        return list(hdrs.items())
    +
    +class OpenerDirector:
    +    def __init__(self):
    +        client_version = "Python-urllib/%s" % __version__
    +        self.addheaders = [('User-agent', client_version)]
    +        # self.handlers is retained only for backward compatibility
    +        self.handlers = []
    +        # manage the individual handlers
    +        self.handle_open = {}
    +        self.handle_error = {}
    +        self.process_response = {}
    +        self.process_request = {}
    +
    +    def add_handler(self, handler):
    +        if not hasattr(handler, "add_parent"):
    +            raise TypeError("expected BaseHandler instance, got %r" %
    +                            type(handler))
    +
    +        added = False
    +        for meth in dir(handler):
    +            if meth in ["redirect_request", "do_open", "proxy_open"]:
    +                # oops, coincidental match
    +                continue
    +
    +            i = meth.find("_")
    +            protocol = meth[:i]
    +            condition = meth[i+1:]
    +
    +            if condition.startswith("error"):
    +                j = condition.find("_") + i + 1
    +                kind = meth[j+1:]
    +                try:
    +                    kind = int(kind)
    +                except ValueError:
    +                    pass
    +                lookup = self.handle_error.get(protocol, {})
    +                self.handle_error[protocol] = lookup
    +            elif condition == "open":
    +                kind = protocol
    +                lookup = self.handle_open
    +            elif condition == "response":
    +                kind = protocol
    +                lookup = self.process_response
    +            elif condition == "request":
    +                kind = protocol
    +                lookup = self.process_request
    +            else:
    +                continue
    +
    +            handlers = lookup.setdefault(kind, [])
    +            if handlers:
    +                bisect.insort(handlers, handler)
    +            else:
    +                handlers.append(handler)
    +            added = True
    +
    +        if added:
    +            bisect.insort(self.handlers, handler)
    +            handler.add_parent(self)
    +
    +    def close(self):
    +        # Only exists for backwards compatibility.
    +        pass
    +
    +    def _call_chain(self, chain, kind, meth_name, *args):
    +        # Handlers raise an exception if no one else should try to handle
    +        # the request, or return None if they can't but another handler
    +        # could.  Otherwise, they return the response.
    +        handlers = chain.get(kind, ())
    +        for handler in handlers:
    +            func = getattr(handler, meth_name)
    +            result = func(*args)
    +            if result is not None:
    +                return result
    +
    +    def open(self, fullurl, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
    +        # accept a URL or a Request object
    +        if isinstance(fullurl, str):
    +            req = Request(fullurl, data)
    +        else:
    +            req = fullurl
    +            if data is not None:
    +                req.data = data
    +
    +        req.timeout = timeout
    +        protocol = req.type
    +
    +        # pre-process request
    +        meth_name = protocol+"_request"
    +        for processor in self.process_request.get(protocol, []):
    +            meth = getattr(processor, meth_name)
    +            req = meth(req)
    +
    +        response = self._open(req, data)
    +
    +        # post-process response
    +        meth_name = protocol+"_response"
    +        for processor in self.process_response.get(protocol, []):
    +            meth = getattr(processor, meth_name)
    +            response = meth(req, response)
    +
    +        return response
    +
    +    def _open(self, req, data=None):
    +        result = self._call_chain(self.handle_open, 'default',
    +                                  'default_open', req)
    +        if result:
    +            return result
    +
    +        protocol = req.type
    +        result = self._call_chain(self.handle_open, protocol, protocol +
    +                                  '_open', req)
    +        if result:
    +            return result
    +
    +        return self._call_chain(self.handle_open, 'unknown',
    +                                'unknown_open', req)
    +
    +    def error(self, proto, *args):
    +        if proto in ('http', 'https'):
    +            # XXX http[s] protocols are special-cased
    +            dict = self.handle_error['http'] # https is not different than http
    +            proto = args[2]  # YUCK!
    +            meth_name = 'http_error_%s' % proto
    +            http_err = 1
    +            orig_args = args
    +        else:
    +            dict = self.handle_error
    +            meth_name = proto + '_error'
    +            http_err = 0
    +        args = (dict, proto, meth_name) + args
    +        result = self._call_chain(*args)
    +        if result:
    +            return result
    +
    +        if http_err:
    +            args = (dict, 'default', 'http_error_default') + orig_args
    +            return self._call_chain(*args)
    +
    +# XXX probably also want an abstract factory that knows when it makes
    +# sense to skip a superclass in favor of a subclass and when it might
    +# make sense to include both
    +
    +def build_opener(*handlers):
    +    """Create an opener object from a list of handlers.
    +
    +    The opener will use several default handlers, including support
    +    for HTTP, FTP and when applicable HTTPS.
    +
    +    If any of the handlers passed as arguments are subclasses of the
    +    default handlers, the default handlers will not be used.
    +    """
    +    opener = OpenerDirector()
    +    default_classes = [ProxyHandler, UnknownHandler, HTTPHandler,
    +                       HTTPDefaultErrorHandler, HTTPRedirectHandler,
    +                       FTPHandler, FileHandler, HTTPErrorProcessor,
    +                       DataHandler]
    +    if hasattr(http.client, "HTTPSConnection"):
    +        default_classes.append(HTTPSHandler)
    +    skip = set()
    +    for klass in default_classes:
    +        for check in handlers:
    +            if isinstance(check, type):
    +                if issubclass(check, klass):
    +                    skip.add(klass)
    +            elif isinstance(check, klass):
    +                skip.add(klass)
    +    for klass in skip:
    +        default_classes.remove(klass)
    +
    +    for klass in default_classes:
    +        opener.add_handler(klass())
    +
    +    for h in handlers:
    +        if isinstance(h, type):
    +            h = h()
    +        opener.add_handler(h)
    +    return opener
    +
    +class BaseHandler:
    +    handler_order = 500
    +
    +    def add_parent(self, parent):
    +        self.parent = parent
    +
    +    def close(self):
    +        # Only exists for backwards compatibility
    +        pass
    +
    +    def __lt__(self, other):
    +        if not hasattr(other, "handler_order"):
    +            # Try to preserve the old behavior of having custom classes
    +            # inserted after default ones (works only for custom user
    +            # classes which are not aware of handler_order).
    +            return True
    +        return self.handler_order < other.handler_order
    +
    +
    +class HTTPErrorProcessor(BaseHandler):
    +    """Process HTTP error responses."""
    +    handler_order = 1000  # after all other processing
    +
    +    def http_response(self, request, response):
    +        code, msg, hdrs = response.code, response.msg, response.info()
    +
    +        # According to RFC 2616, "2xx" code indicates that the client's
    +        # request was successfully received, understood, and accepted.
    +        if not (200 <= code < 300):
    +            response = self.parent.error(
    +                'http', request, response, code, msg, hdrs)
    +
    +        return response
    +
    +    https_response = http_response
    +
    +class HTTPDefaultErrorHandler(BaseHandler):
    +    def http_error_default(self, req, fp, code, msg, hdrs):
    +        raise HTTPError(req.full_url, code, msg, hdrs, fp)
    +
    +class HTTPRedirectHandler(BaseHandler):
    +    # maximum number of redirections to any single URL
    +    # this is needed because of the state that cookies introduce
    +    max_repeats = 4
    +    # maximum total number of redirections (regardless of URL) before
    +    # assuming we're in a loop
    +    max_redirections = 10
    +
    +    def redirect_request(self, req, fp, code, msg, headers, newurl):
    +        """Return a Request or None in response to a redirect.
    +
    +        This is called by the http_error_30x methods when a
    +        redirection response is received.  If a redirection should
    +        take place, return a new Request to allow http_error_30x to
    +        perform the redirect.  Otherwise, raise HTTPError if no-one
    +        else should try to handle this url.  Return None if you can't
    +        but another Handler might.
    +        """
    +        m = req.get_method()
    +        if (not (code in (301, 302, 303, 307) and m in ("GET", "HEAD")
    +            or code in (301, 302, 303) and m == "POST")):
    +            raise HTTPError(req.full_url, code, msg, headers, fp)
    +
    +        # Strictly (according to RFC 2616), 301 or 302 in response to
    +        # a POST MUST NOT cause a redirection without confirmation
    +        # from the user (of urllib.request, in this case).  In practice,
    +        # essentially all clients do redirect in this case, so we do
    +        # the same.
    +
    +        # Be conciliant with URIs containing a space.  This is mainly
    +        # redundant with the more complete encoding done in http_error_302(),
    +        # but it is kept for compatibility with other callers.
    +        newurl = newurl.replace(' ', '%20')
    +
    +        CONTENT_HEADERS = ("content-length", "content-type")
    +        newheaders = {k: v for k, v in req.headers.items()
    +                      if k.lower() not in CONTENT_HEADERS}
    +        return Request(newurl,
    +                       headers=newheaders,
    +                       origin_req_host=req.origin_req_host,
    +                       unverifiable=True)
    +
    +    # Implementation note: To avoid the server sending us into an
    +    # infinite loop, the request object needs to track what URLs we
    +    # have already seen.  Do this by adding a handler-specific
    +    # attribute to the Request object.
    +    def http_error_302(self, req, fp, code, msg, headers):
    +        # Some servers (incorrectly) return multiple Location headers
    +        # (so probably same goes for URI).  Use first header.
    +        if "location" in headers:
    +            newurl = headers["location"]
    +        elif "uri" in headers:
    +            newurl = headers["uri"]
    +        else:
    +            return
    +
    +        # fix a possible malformed URL
    +        urlparts = urlparse(newurl)
    +
    +        # For security reasons we don't allow redirection to anything other
    +        # than http, https or ftp.
    +
    +        if urlparts.scheme not in ('http', 'https', 'ftp', ''):
    +            raise HTTPError(
    +                newurl, code,
    +                "%s - Redirection to url '%s' is not allowed" % (msg, newurl),
    +                headers, fp)
    +
    +        if not urlparts.path and urlparts.netloc:
    +            urlparts = list(urlparts)
    +            urlparts[2] = "/"
    +        newurl = urlunparse(urlparts)
    +
    +        # http.client.parse_headers() decodes as ISO-8859-1.  Recover the
    +        # original bytes and percent-encode non-ASCII bytes, and any special
    +        # characters such as the space.
    +        newurl = quote(
    +            newurl, encoding="iso-8859-1", safe=string.punctuation)
    +        newurl = urljoin(req.full_url, newurl)
    +
    +        # XXX Probably want to forget about the state of the current
    +        # request, although that might interact poorly with other
    +        # handlers that also use handler-specific request attributes
    +        new = self.redirect_request(req, fp, code, msg, headers, newurl)
    +        if new is None:
    +            return
    +
    +        # loop detection
    +        # .redirect_dict has a key url if url was previously visited.
    +        if hasattr(req, 'redirect_dict'):
    +            visited = new.redirect_dict = req.redirect_dict
    +            if (visited.get(newurl, 0) >= self.max_repeats or
    +                len(visited) >= self.max_redirections):
    +                raise HTTPError(req.full_url, code,
    +                                self.inf_msg + msg, headers, fp)
    +        else:
    +            visited = new.redirect_dict = req.redirect_dict = {}
    +        visited[newurl] = visited.get(newurl, 0) + 1
    +
    +        # Don't close the fp until we are sure that we won't use it
    +        # with HTTPError.
    +        fp.read()
    +        fp.close()
    +
    +        return self.parent.open(new, timeout=req.timeout)
    +
    +    http_error_301 = http_error_303 = http_error_307 = http_error_302
    +
    +    inf_msg = "The HTTP server returned a redirect error that would " \
    +              "lead to an infinite loop.\n" \
    +              "The last 30x error message was:\n"
    +
    +
    +def _parse_proxy(proxy):
    +    """Return (scheme, user, password, host/port) given a URL or an authority.
    +
    +    If a URL is supplied, it must have an authority (host:port) component.
    +    According to RFC 3986, having an authority component means the URL must
    +    have two slashes after the scheme.
    +    """
    +    scheme, r_scheme = splittype(proxy)
    +    if not r_scheme.startswith("/"):
    +        # authority
    +        scheme = None
    +        authority = proxy
    +    else:
    +        # URL
    +        if not r_scheme.startswith("//"):
    +            raise ValueError("proxy URL with no authority: %r" % proxy)
    +        # We have an authority, so for RFC 3986-compliant URLs (by ss 3.
    +        # and 3.3.), path is empty or starts with '/'
    +        end = r_scheme.find("/", 2)
    +        if end == -1:
    +            end = None
    +        authority = r_scheme[2:end]
    +    userinfo, hostport = splituser(authority)
    +    if userinfo is not None:
    +        user, password = splitpasswd(userinfo)
    +    else:
    +        user = password = None
    +    return scheme, user, password, hostport
    +
    +class ProxyHandler(BaseHandler):
    +    # Proxies must be in front
    +    handler_order = 100
    +
    +    def __init__(self, proxies=None):
    +        if proxies is None:
    +            proxies = getproxies()
    +        assert hasattr(proxies, 'keys'), "proxies must be a mapping"
    +        self.proxies = proxies
    +        for type, url in proxies.items():
    +            setattr(self, '%s_open' % type,
    +                    lambda r, proxy=url, type=type, meth=self.proxy_open:
    +                        meth(r, proxy, type))
    +
    +    def proxy_open(self, req, proxy, type):
    +        orig_type = req.type
    +        proxy_type, user, password, hostport = _parse_proxy(proxy)
    +        if proxy_type is None:
    +            proxy_type = orig_type
    +
    +        if req.host and proxy_bypass(req.host):
    +            return None
    +
    +        if user and password:
    +            user_pass = '%s:%s' % (unquote(user),
    +                                   unquote(password))
    +            creds = base64.b64encode(user_pass.encode()).decode("ascii")
    +            req.add_header('Proxy-authorization', 'Basic ' + creds)
    +        hostport = unquote(hostport)
    +        req.set_proxy(hostport, proxy_type)
    +        if orig_type == proxy_type or orig_type == 'https':
    +            # let other handlers take care of it
    +            return None
    +        else:
    +            # need to start over, because the other handlers don't
    +            # grok the proxy's URL type
    +            # e.g. if we have a constructor arg proxies like so:
    +            # {'http': 'ftp://proxy.example.com'}, we may end up turning
    +            # a request for http://acme.example.com/a into one for
    +            # ftp://proxy.example.com/a
    +            return self.parent.open(req, timeout=req.timeout)
    +
    +class HTTPPasswordMgr:
    +
    +    def __init__(self):
    +        self.passwd = {}
    +
    +    def add_password(self, realm, uri, user, passwd):
    +        # uri could be a single URI or a sequence
    +        if isinstance(uri, str):
    +            uri = [uri]
    +        if realm not in self.passwd:
    +            self.passwd[realm] = {}
    +        for default_port in True, False:
    +            reduced_uri = tuple(
    +                self.reduce_uri(u, default_port) for u in uri)
    +            self.passwd[realm][reduced_uri] = (user, passwd)
    +
    +    def find_user_password(self, realm, authuri):
    +        domains = self.passwd.get(realm, {})
    +        for default_port in True, False:
    +            reduced_authuri = self.reduce_uri(authuri, default_port)
    +            for uris, authinfo in domains.items():
    +                for uri in uris:
    +                    if self.is_suburi(uri, reduced_authuri):
    +                        return authinfo
    +        return None, None
    +
    +    def reduce_uri(self, uri, default_port=True):
    +        """Accept authority or URI and extract only the authority and path."""
    +        # note HTTP URLs do not have a userinfo component
    +        parts = urlsplit(uri)
    +        if parts[1]:
    +            # URI
    +            scheme = parts[0]
    +            authority = parts[1]
    +            path = parts[2] or '/'
    +        else:
    +            # host or host:port
    +            scheme = None
    +            authority = uri
    +            path = '/'
    +        host, port = splitport(authority)
    +        if default_port and port is None and scheme is not None:
    +            dport = {"http": 80,
    +                     "https": 443,
    +                     }.get(scheme)
    +            if dport is not None:
    +                authority = "%s:%d" % (host, dport)
    +        return authority, path
    +
    +    def is_suburi(self, base, test):
    +        """Check if test is below base in a URI tree
    +
    +        Both args must be URIs in reduced form.
    +        """
    +        if base == test:
    +            return True
    +        if base[0] != test[0]:
    +            return False
    +        common = posixpath.commonprefix((base[1], test[1]))
    +        if len(common) == len(base[1]):
    +            return True
    +        return False
    +
    +
    +class HTTPPasswordMgrWithDefaultRealm(HTTPPasswordMgr):
    +
    +    def find_user_password(self, realm, authuri):
    +        user, password = HTTPPasswordMgr.find_user_password(self, realm,
    +                                                            authuri)
    +        if user is not None:
    +            return user, password
    +        return HTTPPasswordMgr.find_user_password(self, None, authuri)
    +
    +
    +class HTTPPasswordMgrWithPriorAuth(HTTPPasswordMgrWithDefaultRealm):
    +
    +    def __init__(self, *args, **kwargs):
    +        self.authenticated = {}
    +        super().__init__(*args, **kwargs)
    +
    +    def add_password(self, realm, uri, user, passwd, is_authenticated=False):
    +        self.update_authenticated(uri, is_authenticated)
    +        # Add a default for prior auth requests
    +        if realm is not None:
    +            super().add_password(None, uri, user, passwd)
    +        super().add_password(realm, uri, user, passwd)
    +
    +    def update_authenticated(self, uri, is_authenticated=False):
    +        # uri could be a single URI or a sequence
    +        if isinstance(uri, str):
    +            uri = [uri]
    +
    +        for default_port in True, False:
    +            for u in uri:
    +                reduced_uri = self.reduce_uri(u, default_port)
    +                self.authenticated[reduced_uri] = is_authenticated
    +
    +    def is_authenticated(self, authuri):
    +        for default_port in True, False:
    +            reduced_authuri = self.reduce_uri(authuri, default_port)
    +            for uri in self.authenticated:
    +                if self.is_suburi(uri, reduced_authuri):
    +                    return self.authenticated[uri]
    +
    +
    +class AbstractBasicAuthHandler:
    +
    +    # XXX this allows for multiple auth-schemes, but will stupidly pick
    +    # the last one with a realm specified.
    +
    +    # allow for double- and single-quoted realm values
    +    # (single quotes are a violation of the RFC, but appear in the wild)
    +    rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+'
    +                    'realm=(["\']?)([^"\']*)\\2', re.I)
    +
    +    # XXX could pre-emptively send auth info already accepted (RFC 2617,
    +    # end of section 2, and section 1.2 immediately after "credentials"
    +    # production).
    +
    +    def __init__(self, password_mgr=None):
    +        if password_mgr is None:
    +            password_mgr = HTTPPasswordMgr()
    +        self.passwd = password_mgr
    +        self.add_password = self.passwd.add_password
    +
    +    def http_error_auth_reqed(self, authreq, host, req, headers):
    +        # host may be an authority (without userinfo) or a URL with an
    +        # authority
    +        # XXX could be multiple headers
    +        authreq = headers.get(authreq, None)
    +
    +        if authreq:
    +            scheme = authreq.split()[0]
    +            if scheme.lower() != 'basic':
    +                raise ValueError("AbstractBasicAuthHandler does not"
    +                                 " support the following scheme: '%s'" %
    +                                 scheme)
    +            else:
    +                mo = AbstractBasicAuthHandler.rx.search(authreq)
    +                if mo:
    +                    scheme, quote, realm = mo.groups()
    +                    if quote not in ['"',"'"]:
    +                        warnings.warn("Basic Auth Realm was unquoted",
    +                                      UserWarning, 2)
    +                    if scheme.lower() == 'basic':
    +                        return self.retry_http_basic_auth(host, req, realm)
    +
    +    def retry_http_basic_auth(self, host, req, realm):
    +        user, pw = self.passwd.find_user_password(realm, host)
    +        if pw is not None:
    +            raw = "%s:%s" % (user, pw)
    +            auth = "Basic " + base64.b64encode(raw.encode()).decode("ascii")
    +            if req.get_header(self.auth_header, None) == auth:
    +                return None
    +            req.add_unredirected_header(self.auth_header, auth)
    +            return self.parent.open(req, timeout=req.timeout)
    +        else:
    +            return None
    +
    +    def http_request(self, req):
    +        if (not hasattr(self.passwd, 'is_authenticated') or
    +           not self.passwd.is_authenticated(req.full_url)):
    +            return req
    +
    +        if not req.has_header('Authorization'):
    +            user, passwd = self.passwd.find_user_password(None, req.full_url)
    +            credentials = '{0}:{1}'.format(user, passwd).encode()
    +            auth_str = base64.standard_b64encode(credentials).decode()
    +            req.add_unredirected_header('Authorization',
    +                                        'Basic {}'.format(auth_str.strip()))
    +        return req
    +
    +    def http_response(self, req, response):
    +        if hasattr(self.passwd, 'is_authenticated'):
    +            if 200 <= response.code < 300:
    +                self.passwd.update_authenticated(req.full_url, True)
    +            else:
    +                self.passwd.update_authenticated(req.full_url, False)
    +        return response
    +
    +    https_request = http_request
    +    https_response = http_response
    +
    +
    +
    +class HTTPBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler):
    +
    +    auth_header = 'Authorization'
    +
    +    def http_error_401(self, req, fp, code, msg, headers):
    +        url = req.full_url
    +        response = self.http_error_auth_reqed('www-authenticate',
    +                                          url, req, headers)
    +        return response
    +
    +
    +class ProxyBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler):
    +
    +    auth_header = 'Proxy-authorization'
    +
    +    def http_error_407(self, req, fp, code, msg, headers):
    +        # http_error_auth_reqed requires that there is no userinfo component in
    +        # authority.  Assume there isn't one, since urllib.request does not (and
    +        # should not, RFC 3986 s. 3.2.1) support requests for URLs containing
    +        # userinfo.
    +        authority = req.host
    +        response = self.http_error_auth_reqed('proxy-authenticate',
    +                                          authority, req, headers)
    +        return response
    +
    +
    +# Return n random bytes.
    +_randombytes = os.urandom
    +
    +
    +class AbstractDigestAuthHandler:
    +    # Digest authentication is specified in RFC 2617.
    +
    +    # XXX The client does not inspect the Authentication-Info header
    +    # in a successful response.
    +
    +    # XXX It should be possible to test this implementation against
    +    # a mock server that just generates a static set of challenges.
    +
    +    # XXX qop="auth-int" supports is shaky
    +
    +    def __init__(self, passwd=None):
    +        if passwd is None:
    +            passwd = HTTPPasswordMgr()
    +        self.passwd = passwd
    +        self.add_password = self.passwd.add_password
    +        self.retried = 0
    +        self.nonce_count = 0
    +        self.last_nonce = None
    +
    +    def reset_retry_count(self):
    +        self.retried = 0
    +
    +    def http_error_auth_reqed(self, auth_header, host, req, headers):
    +        authreq = headers.get(auth_header, None)
    +        if self.retried > 5:
    +            # Don't fail endlessly - if we failed once, we'll probably
    +            # fail a second time. Hm. Unless the Password Manager is
    +            # prompting for the information. Crap. This isn't great
    +            # but it's better than the current 'repeat until recursion
    +            # depth exceeded' approach <wink>
    +            raise HTTPError(req.full_url, 401, "digest auth failed",
    +                            headers, None)
    +        else:
    +            self.retried += 1
    +        if authreq:
    +            scheme = authreq.split()[0]
    +            if scheme.lower() == 'digest':
    +                return self.retry_http_digest_auth(req, authreq)
    +            elif scheme.lower() != 'basic':
    +                raise ValueError("AbstractDigestAuthHandler does not support"
    +                                 " the following scheme: '%s'" % scheme)
    +
    +    def retry_http_digest_auth(self, req, auth):
    +        token, challenge = auth.split(' ', 1)
    +        chal = parse_keqv_list(filter(None, parse_http_list(challenge)))
    +        auth = self.get_authorization(req, chal)
    +        if auth:
    +            auth_val = 'Digest %s' % auth
    +            if req.headers.get(self.auth_header, None) == auth_val:
    +                return None
    +            req.add_unredirected_header(self.auth_header, auth_val)
    +            resp = self.parent.open(req, timeout=req.timeout)
    +            return resp
    +
    +    def get_cnonce(self, nonce):
    +        # The cnonce-value is an opaque
    +        # quoted string value provided by the client and used by both client
    +        # and server to avoid chosen plaintext attacks, to provide mutual
    +        # authentication, and to provide some message integrity protection.
    +        # This isn't a fabulous effort, but it's probably Good Enough.
    +        s = "%s:%s:%s:" % (self.nonce_count, nonce, time.ctime())
    +        b = s.encode("ascii") + _randombytes(8)
    +        dig = hashlib.sha1(b).hexdigest()
    +        return dig[:16]
    +
    +    def get_authorization(self, req, chal):
    +        try:
    +            realm = chal['realm']
    +            nonce = chal['nonce']
    +            qop = chal.get('qop')
    +            algorithm = chal.get('algorithm', 'MD5')
    +            # mod_digest doesn't send an opaque, even though it isn't
    +            # supposed to be optional
    +            opaque = chal.get('opaque', None)
    +        except KeyError:
    +            return None
    +
    +        H, KD = self.get_algorithm_impls(algorithm)
    +        if H is None:
    +            return None
    +
    +        user, pw = self.passwd.find_user_password(realm, req.full_url)
    +        if user is None:
    +            return None
    +
    +        # XXX not implemented yet
    +        if req.data is not None:
    +            entdig = self.get_entity_digest(req.data, chal)
    +        else:
    +            entdig = None
    +
    +        A1 = "%s:%s:%s" % (user, realm, pw)
    +        A2 = "%s:%s" % (req.get_method(),
    +                        # XXX selector: what about proxies and full urls
    +                        req.selector)
    +        if qop == 'auth':
    +            if nonce == self.last_nonce:
    +                self.nonce_count += 1
    +            else:
    +                self.nonce_count = 1
    +                self.last_nonce = nonce
    +            ncvalue = '%08x' % self.nonce_count
    +            cnonce = self.get_cnonce(nonce)
    +            noncebit = "%s:%s:%s:%s:%s" % (nonce, ncvalue, cnonce, qop, H(A2))
    +            respdig = KD(H(A1), noncebit)
    +        elif qop is None:
    +            respdig = KD(H(A1), "%s:%s" % (nonce, H(A2)))
    +        else:
    +            # XXX handle auth-int.
    +            raise URLError("qop '%s' is not supported." % qop)
    +
    +        # XXX should the partial digests be encoded too?
    +
    +        base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \
    +               'response="%s"' % (user, realm, nonce, req.selector,
    +                                  respdig)
    +        if opaque:
    +            base += ', opaque="%s"' % opaque
    +        if entdig:
    +            base += ', digest="%s"' % entdig
    +        base += ', algorithm="%s"' % algorithm
    +        if qop:
    +            base += ', qop=auth, nc=%s, cnonce="%s"' % (ncvalue, cnonce)
    +        return base
    +
    +    def get_algorithm_impls(self, algorithm):
    +        # lambdas assume digest modules are imported at the top level
    +        if algorithm == 'MD5':
    +            H = lambda x: hashlib.md5(x.encode("ascii")).hexdigest()
    +        elif algorithm == 'SHA':
    +            H = lambda x: hashlib.sha1(x.encode("ascii")).hexdigest()
    +        # XXX MD5-sess
    +        else:
    +            raise ValueError("Unsupported digest authentication "
    +                             "algorithm %r" % algorithm)
    +        KD = lambda s, d: H("%s:%s" % (s, d))
    +        return H, KD
    +
    +    def get_entity_digest(self, data, chal):
    +        # XXX not implemented yet
    +        return None
    +
    +
    +class HTTPDigestAuthHandler(BaseHandler, AbstractDigestAuthHandler):
    +    """An authentication protocol defined by RFC 2069
    +
    +    Digest authentication improves on basic authentication because it
    +    does not transmit passwords in the clear.
    +    """
    +
    +    auth_header = 'Authorization'
    +    handler_order = 490  # before Basic auth
    +
    +    def http_error_401(self, req, fp, code, msg, headers):
    +        host = urlparse(req.full_url)[1]
    +        retry = self.http_error_auth_reqed('www-authenticate',
    +                                           host, req, headers)
    +        self.reset_retry_count()
    +        return retry
    +
    +
    +class ProxyDigestAuthHandler(BaseHandler, AbstractDigestAuthHandler):
    +
    +    auth_header = 'Proxy-Authorization'
    +    handler_order = 490  # before Basic auth
    +
    +    def http_error_407(self, req, fp, code, msg, headers):
    +        host = req.host
    +        retry = self.http_error_auth_reqed('proxy-authenticate',
    +                                           host, req, headers)
    +        self.reset_retry_count()
    +        return retry
    +
    +class AbstractHTTPHandler(BaseHandler):
    +
    +    def __init__(self, debuglevel=0):
    +        self._debuglevel = debuglevel
    +
    +    def set_http_debuglevel(self, level):
    +        self._debuglevel = level
    +
    +    def _get_content_length(self, request):
    +        return http.client.HTTPConnection._get_content_length(
    +            request.data,
    +            request.get_method())
    +
    +    def do_request_(self, request):
    +        host = request.host
    +        if not host:
    +            raise URLError('no host given')
    +
    +        if request.data is not None:  # POST
    +            data = request.data
    +            if isinstance(data, str):
    +                msg = "POST data should be bytes, an iterable of bytes, " \
    +                      "or a file object. It cannot be of type str."
    +                raise TypeError(msg)
    +            if not request.has_header('Content-type'):
    +                request.add_unredirected_header(
    +                    'Content-type',
    +                    'application/x-www-form-urlencoded')
    +            if (not request.has_header('Content-length')
    +                    and not request.has_header('Transfer-encoding')):
    +                content_length = self._get_content_length(request)
    +                if content_length is not None:
    +                    request.add_unredirected_header(
    +                            'Content-length', str(content_length))
    +                else:
    +                    request.add_unredirected_header(
    +                            'Transfer-encoding', 'chunked')
    +
    +        sel_host = host
    +        if request.has_proxy():
    +            scheme, sel = splittype(request.selector)
    +            sel_host, sel_path = splithost(sel)
    +        if not request.has_header('Host'):
    +            request.add_unredirected_header('Host', sel_host)
    +        for name, value in self.parent.addheaders:
    +            name = name.capitalize()
    +            if not request.has_header(name):
    +                request.add_unredirected_header(name, value)
    +
    +        return request
    +
    +    def do_open(self, http_class, req, **http_conn_args):
    +        """Return an HTTPResponse object for the request, using http_class.
    +
    +        http_class must implement the HTTPConnection API from http.client.
    +        """
    +        host = req.host
    +        if not host:
    +            raise URLError('no host given')
    +
    +        # will parse host:port
    +        h = http_class(host, timeout=req.timeout, **http_conn_args)
    +        h.set_debuglevel(self._debuglevel)
    +
    +        headers = dict(req.unredirected_hdrs)
    +        headers.update({k: v for k, v in req.headers.items()
    +                        if k not in headers})
    +
    +        # TODO(jhylton): Should this be redesigned to handle
    +        # persistent connections?
    +
    +        # We want to make an HTTP/1.1 request, but the addinfourl
    +        # class isn't prepared to deal with a persistent connection.
    +        # It will try to read all remaining data from the socket,
    +        # which will block while the server waits for the next request.
    +        # So make sure the connection gets closed after the (only)
    +        # request.
    +        headers["Connection"] = "close"
    +        headers = {name.title(): val for name, val in headers.items()}
    +
    +        if req._tunnel_host:
    +            tunnel_headers = {}
    +            proxy_auth_hdr = "Proxy-Authorization"
    +            if proxy_auth_hdr in headers:
    +                tunnel_headers[proxy_auth_hdr] = headers[proxy_auth_hdr]
    +                # Proxy-Authorization should not be sent to origin
    +                # server.
    +                del headers[proxy_auth_hdr]
    +            h.set_tunnel(req._tunnel_host, headers=tunnel_headers)
    +
    +        try:
    +            try:
    +                h.request(req.get_method(), req.selector, req.data, headers,
    +                          encode_chunked=req.has_header('Transfer-encoding'))
    +            except OSError as err: # timeout error
    +                raise URLError(err)
    +            r = h.getresponse()
    +        except:
    +            h.close()
    +            raise
    +
    +        # If the server does not send us a 'Connection: close' header,
    +        # HTTPConnection assumes the socket should be left open. Manually
    +        # mark the socket to be closed when this response object goes away.
    +        if h.sock:
    +            h.sock.close()
    +            h.sock = None
    +
    +        r.url = req.get_full_url()
    +        # This line replaces the .msg attribute of the HTTPResponse
    +        # with .headers, because urllib clients expect the response to
    +        # have the reason in .msg.  It would be good to mark this
    +        # attribute is deprecated and get then to use info() or
    +        # .headers.
    +        r.msg = r.reason
    +        return r
    +
    +
    +class HTTPHandler(AbstractHTTPHandler):
    +
    +    def http_open(self, req):
    +        return self.do_open(http.client.HTTPConnection, req)
    +
    +    http_request = AbstractHTTPHandler.do_request_
    +
    +if hasattr(http.client, 'HTTPSConnection'):
    +
    +    class HTTPSHandler(AbstractHTTPHandler):
    +
    +        def __init__(self, debuglevel=0, context=None, check_hostname=None):
    +            AbstractHTTPHandler.__init__(self, debuglevel)
    +            self._context = context
    +            self._check_hostname = check_hostname
    +
    +        def https_open(self, req):
    +            return self.do_open(http.client.HTTPSConnection, req,
    +                context=self._context, check_hostname=self._check_hostname)
    +
    +        https_request = AbstractHTTPHandler.do_request_
    +
    +    __all__.append('HTTPSHandler')
    +
    +class HTTPCookieProcessor(BaseHandler):
    +    def __init__(self, cookiejar=None):
    +        import http.cookiejar
    +        if cookiejar is None:
    +            cookiejar = http.cookiejar.CookieJar()
    +        self.cookiejar = cookiejar
    +
    +    def http_request(self, request):
    +        self.cookiejar.add_cookie_header(request)
    +        return request
    +
    +    def http_response(self, request, response):
    +        self.cookiejar.extract_cookies(response, request)
    +        return response
    +
    +    https_request = http_request
    +    https_response = http_response
    +
    +class UnknownHandler(BaseHandler):
    +    def unknown_open(self, req):
    +        type = req.type
    +        raise URLError('unknown url type: %s' % type)
    +
    +def parse_keqv_list(l):
    +    """Parse list of key=value strings where keys are not duplicated."""
    +    parsed = {}
    +    for elt in l:
    +        k, v = elt.split('=', 1)
    +        if v[0] == '"' and v[-1] == '"':
    +            v = v[1:-1]
    +        parsed[k] = v
    +    return parsed
    +
    +def parse_http_list(s):
    +    """Parse lists as described by RFC 2068 Section 2.
    +
    +    In particular, parse comma-separated lists where the elements of
    +    the list may include quoted-strings.  A quoted-string could
    +    contain a comma.  A non-quoted string could have quotes in the
    +    middle.  Neither commas nor quotes count if they are escaped.
    +    Only double-quotes count, not single-quotes.
    +    """
    +    res = []
    +    part = ''
    +
    +    escape = quote = False
    +    for cur in s:
    +        if escape:
    +            part += cur
    +            escape = False
    +            continue
    +        if quote:
    +            if cur == '\\':
    +                escape = True
    +                continue
    +            elif cur == '"':
    +                quote = False
    +            part += cur
    +            continue
    +
    +        if cur == ',':
    +            res.append(part)
    +            part = ''
    +            continue
    +
    +        if cur == '"':
    +            quote = True
    +
    +        part += cur
    +
    +    # append last part
    +    if part:
    +        res.append(part)
    +
    +    return [part.strip() for part in res]
    +
    +class FileHandler(BaseHandler):
    +    # Use local file or FTP depending on form of URL
    +    def file_open(self, req):
    +        url = req.selector
    +        if url[:2] == '//' and url[2:3] != '/' and (req.host and
    +                req.host != 'localhost'):
    +            if not req.host in self.get_names():
    +                raise URLError("file:// scheme is supported only on localhost")
    +        else:
    +            return self.open_local_file(req)
    +
    +    # names for the localhost
    +    names = None
    +    def get_names(self):
    +        if FileHandler.names is None:
    +            try:
    +                FileHandler.names = tuple(
    +                    socket.gethostbyname_ex('localhost')[2] +
    +                    socket.gethostbyname_ex(socket.gethostname())[2])
    +            except socket.gaierror:
    +                FileHandler.names = (socket.gethostbyname('localhost'),)
    +        return FileHandler.names
    +
    +    # not entirely sure what the rules are here
    +    def open_local_file(self, req):
    +        import email.utils
    +        import mimetypes
    +        host = req.host
    +        filename = req.selector
    +        localfile = url2pathname(filename)
    +        try:
    +            stats = os.stat(localfile)
    +            size = stats.st_size
    +            modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
    +            mtype = mimetypes.guess_type(filename)[0]
    +            headers = email.message_from_string(
    +                'Content-type: %s\nContent-length: %d\nLast-modified: %s\n' %
    +                (mtype or 'text/plain', size, modified))
    +            if host:
    +                host, port = splitport(host)
    +            if not host or \
    +                (not port and _safe_gethostbyname(host) in self.get_names()):
    +                if host:
    +                    origurl = 'file://' + host + filename
    +                else:
    +                    origurl = 'file://' + filename
    +                return addinfourl(open(localfile, 'rb'), headers, origurl)
    +        except OSError as exp:
    +            raise URLError(exp)
    +        raise URLError('file not on local host')
    +
    +def _safe_gethostbyname(host):
    +    try:
    +        return socket.gethostbyname(host)
    +    except socket.gaierror:
    +        return None
    +
    +class FTPHandler(BaseHandler):
    +    def ftp_open(self, req):
    +        import ftplib
    +        import mimetypes
    +        host = req.host
    +        if not host:
    +            raise URLError('ftp error: no host given')
    +        host, port = splitport(host)
    +        if port is None:
    +            port = ftplib.FTP_PORT
    +        else:
    +            port = int(port)
    +
    +        # username/password handling
    +        user, host = splituser(host)
    +        if user:
    +            user, passwd = splitpasswd(user)
    +        else:
    +            passwd = None
    +        host = unquote(host)
    +        user = user or ''
    +        passwd = passwd or ''
    +
    +        try:
    +            host = socket.gethostbyname(host)
    +        except OSError as msg:
    +            raise URLError(msg)
    +        path, attrs = splitattr(req.selector)
    +        dirs = path.split('/')
    +        dirs = list(map(unquote, dirs))
    +        dirs, file = dirs[:-1], dirs[-1]
    +        if dirs and not dirs[0]:
    +            dirs = dirs[1:]
    +        try:
    +            fw = self.connect_ftp(user, passwd, host, port, dirs, req.timeout)
    +            type = file and 'I' or 'D'
    +            for attr in attrs:
    +                attr, value = splitvalue(attr)
    +                if attr.lower() == 'type' and \
    +                   value in ('a', 'A', 'i', 'I', 'd', 'D'):
    +                    type = value.upper()
    +            fp, retrlen = fw.retrfile(file, type)
    +            headers = ""
    +            mtype = mimetypes.guess_type(req.full_url)[0]
    +            if mtype:
    +                headers += "Content-type: %s\n" % mtype
    +            if retrlen is not None and retrlen >= 0:
    +                headers += "Content-length: %d\n" % retrlen
    +            headers = email.message_from_string(headers)
    +            return addinfourl(fp, headers, req.full_url)
    +        except ftplib.all_errors as exp:
    +            exc = URLError('ftp error: %r' % exp)
    +            raise exc.with_traceback(sys.exc_info()[2])
    +
    +    def connect_ftp(self, user, passwd, host, port, dirs, timeout):
    +        return ftpwrapper(user, passwd, host, port, dirs, timeout,
    +                          persistent=False)
    +
    +class CacheFTPHandler(FTPHandler):
    +    # XXX would be nice to have pluggable cache strategies
    +    # XXX this stuff is definitely not thread safe
    +    def __init__(self):
    +        self.cache = {}
    +        self.timeout = {}
    +        self.soonest = 0
    +        self.delay = 60
    +        self.max_conns = 16
    +
    +    def setTimeout(self, t):
    +        self.delay = t
    +
    +    def setMaxConns(self, m):
    +        self.max_conns = m
    +
    +    def connect_ftp(self, user, passwd, host, port, dirs, timeout):
    +        key = user, host, port, '/'.join(dirs), timeout
    +        if key in self.cache:
    +            self.timeout[key] = time.time() + self.delay
    +        else:
    +            self.cache[key] = ftpwrapper(user, passwd, host, port,
    +                                         dirs, timeout)
    +            self.timeout[key] = time.time() + self.delay
    +        self.check_cache()
    +        return self.cache[key]
    +
    +    def check_cache(self):
    +        # first check for old ones
    +        t = time.time()
    +        if self.soonest <= t:
    +            for k, v in list(self.timeout.items()):
    +                if v < t:
    +                    self.cache[k].close()
    +                    del self.cache[k]
    +                    del self.timeout[k]
    +        self.soonest = min(list(self.timeout.values()))
    +
    +        # then check the size
    +        if len(self.cache) == self.max_conns:
    +            for k, v in list(self.timeout.items()):
    +                if v == self.soonest:
    +                    del self.cache[k]
    +                    del self.timeout[k]
    +                    break
    +            self.soonest = min(list(self.timeout.values()))
    +
    +    def clear_cache(self):
    +        for conn in self.cache.values():
    +            conn.close()
    +        self.cache.clear()
    +        self.timeout.clear()
    +
    +class DataHandler(BaseHandler):
    +    def data_open(self, req):
    +        # data URLs as specified in RFC 2397.
    +        #
    +        # ignores POSTed data
    +        #
    +        # syntax:
    +        # dataurl   := "data:" [ mediatype ] [ ";base64" ] "," data
    +        # mediatype := [ type "/" subtype ] *( ";" parameter )
    +        # data      := *urlchar
    +        # parameter := attribute "=" value
    +        url = req.full_url
    +
    +        scheme, data = url.split(":",1)
    +        mediatype, data = data.split(",",1)
    +
    +        # even base64 encoded data URLs might be quoted so unquote in any case:
    +        data = unquote_to_bytes(data)
    +        if mediatype.endswith(";base64"):
    +            data = base64.decodebytes(data)
    +            mediatype = mediatype[:-7]
    +
    +        if not mediatype:
    +            mediatype = "text/plain;charset=US-ASCII"
    +
    +        headers = email.message_from_string("Content-type: %s\nContent-length: %d\n" %
    +            (mediatype, len(data)))
    +
    +        return addinfourl(io.BytesIO(data), headers, url)
    +
    +
    +# Code move from the old urllib module
    +
    +MAXFTPCACHE = 10        # Trim the ftp cache beyond this size
    +
    +# Helper for non-unix systems
    +if os.name == 'nt':
    +    from nturl2path import url2pathname, pathname2url
    +else:
    +    def url2pathname(pathname):
    +        """OS-specific conversion from a relative URL of the 'file' scheme
    +        to a file system path; not recommended for general use."""
    +        return unquote(pathname)
    +
    +    def pathname2url(pathname):
    +        """OS-specific conversion from a file system path to a relative URL
    +        of the 'file' scheme; not recommended for general use."""
    +        return quote(pathname)
    +
    +
    +ftpcache = {}
    +
    +
    +class URLopener:
    +    """Class to open URLs.
    +    This is a class rather than just a subroutine because we may need
    +    more than one set of global protocol-specific options.
    +    Note -- this is a base class for those who don't want the
    +    automatic handling of errors type 302 (relocated) and 401
    +    (authorization needed)."""
    +
    +    __tempfiles = None
    +
    +    version = "Python-urllib/%s" % __version__
    +
    +    # Constructor
    +    def __init__(self, proxies=None, **x509):
    +        msg = "%(class)s style of invoking requests is deprecated. " \
    +              "Use newer urlopen functions/methods" % {'class': self.__class__.__name__}
    +        warnings.warn(msg, DeprecationWarning, stacklevel=3)
    +        if proxies is None:
    +            proxies = getproxies()
    +        assert hasattr(proxies, 'keys'), "proxies must be a mapping"
    +        self.proxies = proxies
    +        self.key_file = x509.get('key_file')
    +        self.cert_file = x509.get('cert_file')
    +        self.addheaders = [('User-Agent', self.version), ('Accept', '*/*')]
    +        self.__tempfiles = []
    +        self.__unlink = os.unlink # See cleanup()
    +        self.tempcache = None
    +        # Undocumented feature: if you assign {} to tempcache,
    +        # it is used to cache files retrieved with
    +        # self.retrieve().  This is not enabled by default
    +        # since it does not work for changing documents (and I
    +        # haven't got the logic to check expiration headers
    +        # yet).
    +        self.ftpcache = ftpcache
    +        # Undocumented feature: you can use a different
    +        # ftp cache by assigning to the .ftpcache member;
    +        # in case you want logically independent URL openers
    +        # XXX This is not threadsafe.  Bah.
    +
    +    def __del__(self):
    +        self.close()
    +
    +    def close(self):
    +        self.cleanup()
    +
    +    def cleanup(self):
    +        # This code sometimes runs when the rest of this module
    +        # has already been deleted, so it can't use any globals
    +        # or import anything.
    +        if self.__tempfiles:
    +            for file in self.__tempfiles:
    +                try:
    +                    self.__unlink(file)
    +                except OSError:
    +                    pass
    +            del self.__tempfiles[:]
    +        if self.tempcache:
    +            self.tempcache.clear()
    +
    +    def addheader(self, *args):
    +        """Add a header to be used by the HTTP interface only
    +        e.g. u.addheader('Accept', 'sound/basic')"""
    +        self.addheaders.append(args)
    +
    +    # External interface
    +    def open(self, fullurl, data=None):
    +        """Use URLopener().open(file) instead of open(file, 'r')."""
    +        fullurl = unwrap(to_bytes(fullurl))
    +        fullurl = quote(fullurl, safe="%/:=&?~#+!$,;'@()*[]|")
    +        if self.tempcache and fullurl in self.tempcache:
    +            filename, headers = self.tempcache[fullurl]
    +            fp = open(filename, 'rb')
    +            return addinfourl(fp, headers, fullurl)
    +        urltype, url = splittype(fullurl)
    +        if not urltype:
    +            urltype = 'file'
    +        if urltype in self.proxies:
    +            proxy = self.proxies[urltype]
    +            urltype, proxyhost = splittype(proxy)
    +            host, selector = splithost(proxyhost)
    +            url = (host, fullurl) # Signal special case to open_*()
    +        else:
    +            proxy = None
    +        name = 'open_' + urltype
    +        self.type = urltype
    +        name = name.replace('-', '_')
    +        if not hasattr(self, name):
    +            if proxy:
    +                return self.open_unknown_proxy(proxy, fullurl, data)
    +            else:
    +                return self.open_unknown(fullurl, data)
    +        try:
    +            if data is None:
    +                return getattr(self, name)(url)
    +            else:
    +                return getattr(self, name)(url, data)
    +        except (HTTPError, URLError):
    +            raise
    +        except OSError as msg:
    +            raise OSError('socket error', msg).with_traceback(sys.exc_info()[2])
    +
    +    def open_unknown(self, fullurl, data=None):
    +        """Overridable interface to open unknown URL type."""
    +        type, url = splittype(fullurl)
    +        raise OSError('url error', 'unknown url type', type)
    +
    +    def open_unknown_proxy(self, proxy, fullurl, data=None):
    +        """Overridable interface to open unknown URL type."""
    +        type, url = splittype(fullurl)
    +        raise OSError('url error', 'invalid proxy for %s' % type, proxy)
    +
    +    # External interface
    +    def retrieve(self, url, filename=None, reporthook=None, data=None):
    +        """retrieve(url) returns (filename, headers) for a local object
    +        or (tempfilename, headers) for a remote object."""
    +        url = unwrap(to_bytes(url))
    +        if self.tempcache and url in self.tempcache:
    +            return self.tempcache[url]
    +        type, url1 = splittype(url)
    +        if filename is None and (not type or type == 'file'):
    +            try:
    +                fp = self.open_local_file(url1)
    +                hdrs = fp.info()
    +                fp.close()
    +                return url2pathname(splithost(url1)[1]), hdrs
    +            except OSError as msg:
    +                pass
    +        fp = self.open(url, data)
    +        try:
    +            headers = fp.info()
    +            if filename:
    +                tfp = open(filename, 'wb')
    +            else:
    +                garbage, path = splittype(url)
    +                garbage, path = splithost(path or "")
    +                path, garbage = splitquery(path or "")
    +                path, garbage = splitattr(path or "")
    +                suffix = os.path.splitext(path)[1]
    +                (fd, filename) = tempfile.mkstemp(suffix)
    +                self.__tempfiles.append(filename)
    +                tfp = os.fdopen(fd, 'wb')
    +            try:
    +                result = filename, headers
    +                if self.tempcache is not None:
    +                    self.tempcache[url] = result
    +                bs = 1024*8
    +                size = -1
    +                read = 0
    +                blocknum = 0
    +                if "content-length" in headers:
    +                    size = int(headers["Content-Length"])
    +                if reporthook:
    +                    reporthook(blocknum, bs, size)
    +                while 1:
    +                    block = fp.read(bs)
    +                    if not block:
    +                        break
    +                    read += len(block)
    +                    tfp.write(block)
    +                    blocknum += 1
    +                    if reporthook:
    +                        reporthook(blocknum, bs, size)
    +            finally:
    +                tfp.close()
    +        finally:
    +            fp.close()
    +
    +        # raise exception if actual size does not match content-length header
    +        if size >= 0 and read < size:
    +            raise ContentTooShortError(
    +                "retrieval incomplete: got only %i out of %i bytes"
    +                % (read, size), result)
    +
    +        return result
    +
    +    # Each method named open_<type> knows how to open that type of URL
    +
    +    def _open_generic_http(self, connection_factory, url, data):
    +        """Make an HTTP connection using connection_class.
    +
    +        This is an internal method that should be called from
    +        open_http() or open_https().
    +
    +        Arguments:
    +        - connection_factory should take a host name and return an
    +          HTTPConnection instance.
    +        - url is the url to retrieval or a host, relative-path pair.
    +        - data is payload for a POST request or None.
    +        """
    +
    +        user_passwd = None
    +        proxy_passwd= None
    +        if isinstance(url, str):
    +            host, selector = splithost(url)
    +            if host:
    +                user_passwd, host = splituser(host)
    +                host = unquote(host)
    +            realhost = host
    +        else:
    +            host, selector = url
    +            # check whether the proxy contains authorization information
    +            proxy_passwd, host = splituser(host)
    +            # now we proceed with the url we want to obtain
    +            urltype, rest = splittype(selector)
    +            url = rest
    +            user_passwd = None
    +            if urltype.lower() != 'http':
    +                realhost = None
    +            else:
    +                realhost, rest = splithost(rest)
    +                if realhost:
    +                    user_passwd, realhost = splituser(realhost)
    +                if user_passwd:
    +                    selector = "%s://%s%s" % (urltype, realhost, rest)
    +                if proxy_bypass(realhost):
    +                    host = realhost
    +
    +        if not host: raise OSError('http error', 'no host given')
    +
    +        if proxy_passwd:
    +            proxy_passwd = unquote(proxy_passwd)
    +            proxy_auth = base64.b64encode(proxy_passwd.encode()).decode('ascii')
    +        else:
    +            proxy_auth = None
    +
    +        if user_passwd:
    +            user_passwd = unquote(user_passwd)
    +            auth = base64.b64encode(user_passwd.encode()).decode('ascii')
    +        else:
    +            auth = None
    +        http_conn = connection_factory(host)
    +        headers = {}
    +        if proxy_auth:
    +            headers["Proxy-Authorization"] = "Basic %s" % proxy_auth
    +        if auth:
    +            headers["Authorization"] =  "Basic %s" % auth
    +        if realhost:
    +            headers["Host"] = realhost
    +
    +        # Add Connection:close as we don't support persistent connections yet.
    +        # This helps in closing the socket and avoiding ResourceWarning
    +
    +        headers["Connection"] = "close"
    +
    +        for header, value in self.addheaders:
    +            headers[header] = value
    +
    +        if data is not None:
    +            headers["Content-Type"] = "application/x-www-form-urlencoded"
    +            http_conn.request("POST", selector, data, headers)
    +        else:
    +            http_conn.request("GET", selector, headers=headers)
    +
    +        try:
    +            response = http_conn.getresponse()
    +        except http.client.BadStatusLine:
    +            # something went wrong with the HTTP status line
    +            raise URLError("http protocol error: bad status line")
    +
    +        # According to RFC 2616, "2xx" code indicates that the client's
    +        # request was successfully received, understood, and accepted.
    +        if 200 <= response.status < 300:
    +            return addinfourl(response, response.msg, "http:" + url,
    +                              response.status)
    +        else:
    +            return self.http_error(
    +                url, response.fp,
    +                response.status, response.reason, response.msg, data)
    +
    +    def open_http(self, url, data=None):
    +        """Use HTTP protocol."""
    +        return self._open_generic_http(http.client.HTTPConnection, url, data)
    +
    +    def http_error(self, url, fp, errcode, errmsg, headers, data=None):
    +        """Handle http errors.
    +
    +        Derived class can override this, or provide specific handlers
    +        named http_error_DDD where DDD is the 3-digit error code."""
    +        # First check if there's a specific handler for this error
    +        name = 'http_error_%d' % errcode
    +        if hasattr(self, name):
    +            method = getattr(self, name)
    +            if data is None:
    +                result = method(url, fp, errcode, errmsg, headers)
    +            else:
    +                result = method(url, fp, errcode, errmsg, headers, data)
    +            if result: return result
    +        return self.http_error_default(url, fp, errcode, errmsg, headers)
    +
    +    def http_error_default(self, url, fp, errcode, errmsg, headers):
    +        """Default error handler: close the connection and raise OSError."""
    +        fp.close()
    +        raise HTTPError(url, errcode, errmsg, headers, None)
    +
    +    if _have_ssl:
    +        def _https_connection(self, host):
    +            return http.client.HTTPSConnection(host,
    +                                           key_file=self.key_file,
    +                                           cert_file=self.cert_file)
    +
    +        def open_https(self, url, data=None):
    +            """Use HTTPS protocol."""
    +            return self._open_generic_http(self._https_connection, url, data)
    +
    +    def open_file(self, url):
    +        """Use local file or FTP depending on form of URL."""
    +        if not isinstance(url, str):
    +            raise URLError('file error: proxy support for file protocol currently not implemented')
    +        if url[:2] == '//' and url[2:3] != '/' and url[2:12].lower() != 'localhost/':
    +            raise ValueError("file:// scheme is supported only on localhost")
    +        else:
    +            return self.open_local_file(url)
    +
    +    def open_local_file(self, url):
    +        """Use local file."""
    +        import email.utils
    +        import mimetypes
    +        host, file = splithost(url)
    +        localname = url2pathname(file)
    +        try:
    +            stats = os.stat(localname)
    +        except OSError as e:
    +            raise URLError(e.strerror, e.filename)
    +        size = stats.st_size
    +        modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
    +        mtype = mimetypes.guess_type(url)[0]
    +        headers = email.message_from_string(
    +            'Content-Type: %s\nContent-Length: %d\nLast-modified: %s\n' %
    +            (mtype or 'text/plain', size, modified))
    +        if not host:
    +            urlfile = file
    +            if file[:1] == '/':
    +                urlfile = 'file://' + file
    +            return addinfourl(open(localname, 'rb'), headers, urlfile)
    +        host, port = splitport(host)
    +        if (not port
    +           and socket.gethostbyname(host) in ((localhost(),) + thishost())):
    +            urlfile = file
    +            if file[:1] == '/':
    +                urlfile = 'file://' + file
    +            elif file[:2] == './':
    +                raise ValueError("local file url may start with / or file:. Unknown url of type: %s" % url)
    +            return addinfourl(open(localname, 'rb'), headers, urlfile)
    +        raise URLError('local file error: not on local host')
    +
    +    def open_ftp(self, url):
    +        """Use FTP protocol."""
    +        if not isinstance(url, str):
    +            raise URLError('ftp error: proxy support for ftp protocol currently not implemented')
    +        import mimetypes
    +        host, path = splithost(url)
    +        if not host: raise URLError('ftp error: no host given')
    +        host, port = splitport(host)
    +        user, host = splituser(host)
    +        if user: user, passwd = splitpasswd(user)
    +        else: passwd = None
    +        host = unquote(host)
    +        user = unquote(user or '')
    +        passwd = unquote(passwd or '')
    +        host = socket.gethostbyname(host)
    +        if not port:
    +            import ftplib
    +            port = ftplib.FTP_PORT
    +        else:
    +            port = int(port)
    +        path, attrs = splitattr(path)
    +        path = unquote(path)
    +        dirs = path.split('/')
    +        dirs, file = dirs[:-1], dirs[-1]
    +        if dirs and not dirs[0]: dirs = dirs[1:]
    +        if dirs and not dirs[0]: dirs[0] = '/'
    +        key = user, host, port, '/'.join(dirs)
    +        # XXX thread unsafe!
    +        if len(self.ftpcache) > MAXFTPCACHE:
    +            # Prune the cache, rather arbitrarily
    +            for k in list(self.ftpcache):
    +                if k != key:
    +                    v = self.ftpcache[k]
    +                    del self.ftpcache[k]
    +                    v.close()
    +        try:
    +            if key not in self.ftpcache:
    +                self.ftpcache[key] = \
    +                    ftpwrapper(user, passwd, host, port, dirs)
    +            if not file: type = 'D'
    +            else: type = 'I'
    +            for attr in attrs:
    +                attr, value = splitvalue(attr)
    +                if attr.lower() == 'type' and \
    +                   value in ('a', 'A', 'i', 'I', 'd', 'D'):
    +                    type = value.upper()
    +            (fp, retrlen) = self.ftpcache[key].retrfile(file, type)
    +            mtype = mimetypes.guess_type("ftp:" + url)[0]
    +            headers = ""
    +            if mtype:
    +                headers += "Content-Type: %s\n" % mtype
    +            if retrlen is not None and retrlen >= 0:
    +                headers += "Content-Length: %d\n" % retrlen
    +            headers = email.message_from_string(headers)
    +            return addinfourl(fp, headers, "ftp:" + url)
    +        except ftperrors() as exp:
    +            raise URLError('ftp error %r' % exp).with_traceback(sys.exc_info()[2])
    +
    +    def open_data(self, url, data=None):
    +        """Use "data" URL."""
    +        if not isinstance(url, str):
    +            raise URLError('data error: proxy support for data protocol currently not implemented')
    +        # ignore POSTed data
    +        #
    +        # syntax of data URLs:
    +        # dataurl   := "data:" [ mediatype ] [ ";base64" ] "," data
    +        # mediatype := [ type "/" subtype ] *( ";" parameter )
    +        # data      := *urlchar
    +        # parameter := attribute "=" value
    +        try:
    +            [type, data] = url.split(',', 1)
    +        except ValueError:
    +            raise OSError('data error', 'bad data URL')
    +        if not type:
    +            type = 'text/plain;charset=US-ASCII'
    +        semi = type.rfind(';')
    +        if semi >= 0 and '=' not in type[semi:]:
    +            encoding = type[semi+1:]
    +            type = type[:semi]
    +        else:
    +            encoding = ''
    +        msg = []
    +        msg.append('Date: %s'%time.strftime('%a, %d %b %Y %H:%M:%S GMT',
    +                                            time.gmtime(time.time())))
    +        msg.append('Content-type: %s' % type)
    +        if encoding == 'base64':
    +            # XXX is this encoding/decoding ok?
    +            data = base64.decodebytes(data.encode('ascii')).decode('latin-1')
    +        else:
    +            data = unquote(data)
    +        msg.append('Content-Length: %d' % len(data))
    +        msg.append('')
    +        msg.append(data)
    +        msg = '\n'.join(msg)
    +        headers = email.message_from_string(msg)
    +        f = io.StringIO(msg)
    +        #f.fileno = None     # needed for addinfourl
    +        return addinfourl(f, headers, url)
    +
    +
    +class FancyURLopener(URLopener):
    +    """Derived class with handlers for errors we can handle (perhaps)."""
    +
    +    def __init__(self, *args, **kwargs):
    +        URLopener.__init__(self, *args, **kwargs)
    +        self.auth_cache = {}
    +        self.tries = 0
    +        self.maxtries = 10
    +
    +    def http_error_default(self, url, fp, errcode, errmsg, headers):
    +        """Default error handling -- don't raise an exception."""
    +        return addinfourl(fp, headers, "http:" + url, errcode)
    +
    +    def http_error_302(self, url, fp, errcode, errmsg, headers, data=None):
    +        """Error 302 -- relocated (temporarily)."""
    +        self.tries += 1
    +        try:
    +            if self.maxtries and self.tries >= self.maxtries:
    +                if hasattr(self, "http_error_500"):
    +                    meth = self.http_error_500
    +                else:
    +                    meth = self.http_error_default
    +                return meth(url, fp, 500,
    +                            "Internal Server Error: Redirect Recursion",
    +                            headers)
    +            result = self.redirect_internal(url, fp, errcode, errmsg,
    +                                            headers, data)
    +            return result
    +        finally:
    +            self.tries = 0
    +
    +    def redirect_internal(self, url, fp, errcode, errmsg, headers, data):
    +        if 'location' in headers:
    +            newurl = headers['location']
    +        elif 'uri' in headers:
    +            newurl = headers['uri']
    +        else:
    +            return
    +        fp.close()
    +
    +        # In case the server sent a relative URL, join with original:
    +        newurl = urljoin(self.type + ":" + url, newurl)
    +
    +        urlparts = urlparse(newurl)
    +
    +        # For security reasons, we don't allow redirection to anything other
    +        # than http, https and ftp.
    +
    +        # We are using newer HTTPError with older redirect_internal method
    +        # This older method will get deprecated in 3.3
    +
    +        if urlparts.scheme not in ('http', 'https', 'ftp', ''):
    +            raise HTTPError(newurl, errcode,
    +                            errmsg +
    +                            " Redirection to url '%s' is not allowed." % newurl,
    +                            headers, fp)
    +
    +        return self.open(newurl)
    +
    +    def http_error_301(self, url, fp, errcode, errmsg, headers, data=None):
    +        """Error 301 -- also relocated (permanently)."""
    +        return self.http_error_302(url, fp, errcode, errmsg, headers, data)
    +
    +    def http_error_303(self, url, fp, errcode, errmsg, headers, data=None):
    +        """Error 303 -- also relocated (essentially identical to 302)."""
    +        return self.http_error_302(url, fp, errcode, errmsg, headers, data)
    +
    +    def http_error_307(self, url, fp, errcode, errmsg, headers, data=None):
    +        """Error 307 -- relocated, but turn POST into error."""
    +        if data is None:
    +            return self.http_error_302(url, fp, errcode, errmsg, headers, data)
    +        else:
    +            return self.http_error_default(url, fp, errcode, errmsg, headers)
    +
    +    def http_error_401(self, url, fp, errcode, errmsg, headers, data=None,
    +            retry=False):
    +        """Error 401 -- authentication required.
    +        This function supports Basic authentication only."""
    +        if 'www-authenticate' not in headers:
    +            URLopener.http_error_default(self, url, fp,
    +                                         errcode, errmsg, headers)
    +        stuff = headers['www-authenticate']
    +        match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff)
    +        if not match:
    +            URLopener.http_error_default(self, url, fp,
    +                                         errcode, errmsg, headers)
    +        scheme, realm = match.groups()
    +        if scheme.lower() != 'basic':
    +            URLopener.http_error_default(self, url, fp,
    +                                         errcode, errmsg, headers)
    +        if not retry:
    +            URLopener.http_error_default(self, url, fp, errcode, errmsg,
    +                    headers)
    +        name = 'retry_' + self.type + '_basic_auth'
    +        if data is None:
    +            return getattr(self,name)(url, realm)
    +        else:
    +            return getattr(self,name)(url, realm, data)
    +
    +    def http_error_407(self, url, fp, errcode, errmsg, headers, data=None,
    +            retry=False):
    +        """Error 407 -- proxy authentication required.
    +        This function supports Basic authentication only."""
    +        if 'proxy-authenticate' not in headers:
    +            URLopener.http_error_default(self, url, fp,
    +                                         errcode, errmsg, headers)
    +        stuff = headers['proxy-authenticate']
    +        match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff)
    +        if not match:
    +            URLopener.http_error_default(self, url, fp,
    +                                         errcode, errmsg, headers)
    +        scheme, realm = match.groups()
    +        if scheme.lower() != 'basic':
    +            URLopener.http_error_default(self, url, fp,
    +                                         errcode, errmsg, headers)
    +        if not retry:
    +            URLopener.http_error_default(self, url, fp, errcode, errmsg,
    +                    headers)
    +        name = 'retry_proxy_' + self.type + '_basic_auth'
    +        if data is None:
    +            return getattr(self,name)(url, realm)
    +        else:
    +            return getattr(self,name)(url, realm, data)
    +
    +    def retry_proxy_http_basic_auth(self, url, realm, data=None):
    +        host, selector = splithost(url)
    +        newurl = 'http://' + host + selector
    +        proxy = self.proxies['http']
    +        urltype, proxyhost = splittype(proxy)
    +        proxyhost, proxyselector = splithost(proxyhost)
    +        i = proxyhost.find('@') + 1
    +        proxyhost = proxyhost[i:]
    +        user, passwd = self.get_user_passwd(proxyhost, realm, i)
    +        if not (user or passwd): return None
    +        proxyhost = "%s:%s@%s" % (quote(user, safe=''),
    +                                  quote(passwd, safe=''), proxyhost)
    +        self.proxies['http'] = 'http://' + proxyhost + proxyselector
    +        if data is None:
    +            return self.open(newurl)
    +        else:
    +            return self.open(newurl, data)
    +
    +    def retry_proxy_https_basic_auth(self, url, realm, data=None):
    +        host, selector = splithost(url)
    +        newurl = 'https://' + host + selector
    +        proxy = self.proxies['https']
    +        urltype, proxyhost = splittype(proxy)
    +        proxyhost, proxyselector = splithost(proxyhost)
    +        i = proxyhost.find('@') + 1
    +        proxyhost = proxyhost[i:]
    +        user, passwd = self.get_user_passwd(proxyhost, realm, i)
    +        if not (user or passwd): return None
    +        proxyhost = "%s:%s@%s" % (quote(user, safe=''),
    +                                  quote(passwd, safe=''), proxyhost)
    +        self.proxies['https'] = 'https://' + proxyhost + proxyselector
    +        if data is None:
    +            return self.open(newurl)
    +        else:
    +            return self.open(newurl, data)
    +
    +    def retry_http_basic_auth(self, url, realm, data=None):
    +        host, selector = splithost(url)
    +        i = host.find('@') + 1
    +        host = host[i:]
    +        user, passwd = self.get_user_passwd(host, realm, i)
    +        if not (user or passwd): return None
    +        host = "%s:%s@%s" % (quote(user, safe=''),
    +                             quote(passwd, safe=''), host)
    +        newurl = 'http://' + host + selector
    +        if data is None:
    +            return self.open(newurl)
    +        else:
    +            return self.open(newurl, data)
    +
    +    def retry_https_basic_auth(self, url, realm, data=None):
    +        host, selector = splithost(url)
    +        i = host.find('@') + 1
    +        host = host[i:]
    +        user, passwd = self.get_user_passwd(host, realm, i)
    +        if not (user or passwd): return None
    +        host = "%s:%s@%s" % (quote(user, safe=''),
    +                             quote(passwd, safe=''), host)
    +        newurl = 'https://' + host + selector
    +        if data is None:
    +            return self.open(newurl)
    +        else:
    +            return self.open(newurl, data)
    +
    +    def get_user_passwd(self, host, realm, clear_cache=0):
    +        key = realm + '@' + host.lower()
    +        if key in self.auth_cache:
    +            if clear_cache:
    +                del self.auth_cache[key]
    +            else:
    +                return self.auth_cache[key]
    +        user, passwd = self.prompt_user_passwd(host, realm)
    +        if user or passwd: self.auth_cache[key] = (user, passwd)
    +        return user, passwd
    +
    +    def prompt_user_passwd(self, host, realm):
    +        """Override this in a GUI environment!"""
    +        import getpass
    +        try:
    +            user = input("Enter username for %s at %s: " % (realm, host))
    +            passwd = getpass.getpass("Enter password for %s in %s at %s: " %
    +                (user, realm, host))
    +            return user, passwd
    +        except KeyboardInterrupt:
    +            print()
    +            return None, None
    +
    +
    +# Utility functions
    +
    +_localhost = None
    +def localhost():
    +    """Return the IP address of the magic hostname 'localhost'."""
    +    global _localhost
    +    if _localhost is None:
    +        _localhost = socket.gethostbyname('localhost')
    +    return _localhost
    +
    +_thishost = None
    +def thishost():
    +    """Return the IP addresses of the current host."""
    +    global _thishost
    +    if _thishost is None:
    +        try:
    +            _thishost = tuple(socket.gethostbyname_ex(socket.gethostname())[2])
    +        except socket.gaierror:
    +            _thishost = tuple(socket.gethostbyname_ex('localhost')[2])
    +    return _thishost
    +
    +_ftperrors = None
    +def ftperrors():
    +    """Return the set of errors raised by the FTP class."""
    +    global _ftperrors
    +    if _ftperrors is None:
    +        import ftplib
    +        _ftperrors = ftplib.all_errors
    +    return _ftperrors
    +
    +_noheaders = None
    +def noheaders():
    +    """Return an empty email Message object."""
    +    global _noheaders
    +    if _noheaders is None:
    +        _noheaders = email.message_from_string("")
    +    return _noheaders
    +
    +
    +# Utility classes
    +
    +class ftpwrapper:
    +    """Class used by open_ftp() for cache of open FTP connections."""
    +
    +    def __init__(self, user, passwd, host, port, dirs, timeout=None,
    +                 persistent=True):
    +        self.user = user
    +        self.passwd = passwd
    +        self.host = host
    +        self.port = port
    +        self.dirs = dirs
    +        self.timeout = timeout
    +        self.refcount = 0
    +        self.keepalive = persistent
    +        try:
    +            self.init()
    +        except:
    +            self.close()
    +            raise
    +
    +    def init(self):
    +        import ftplib
    +        self.busy = 0
    +        self.ftp = ftplib.FTP()
    +        self.ftp.connect(self.host, self.port, self.timeout)
    +        self.ftp.login(self.user, self.passwd)
    +        _target = '/'.join(self.dirs)
    +        self.ftp.cwd(_target)
    +
    +    def retrfile(self, file, type):
    +        import ftplib
    +        self.endtransfer()
    +        if type in ('d', 'D'): cmd = 'TYPE A'; isdir = 1
    +        else: cmd = 'TYPE ' + type; isdir = 0
    +        try:
    +            self.ftp.voidcmd(cmd)
    +        except ftplib.all_errors:
    +            self.init()
    +            self.ftp.voidcmd(cmd)
    +        conn = None
    +        if file and not isdir:
    +            # Try to retrieve as a file
    +            try:
    +                cmd = 'RETR ' + file
    +                conn, retrlen = self.ftp.ntransfercmd(cmd)
    +            except ftplib.error_perm as reason:
    +                if str(reason)[:3] != '550':
    +                    raise URLError('ftp error: %r' % reason).with_traceback(
    +                        sys.exc_info()[2])
    +        if not conn:
    +            # Set transfer mode to ASCII!
    +            self.ftp.voidcmd('TYPE A')
    +            # Try a directory listing. Verify that directory exists.
    +            if file:
    +                pwd = self.ftp.pwd()
    +                try:
    +                    try:
    +                        self.ftp.cwd(file)
    +                    except ftplib.error_perm as reason:
    +                        raise URLError('ftp error: %r' % reason) from reason
    +                finally:
    +                    self.ftp.cwd(pwd)
    +                cmd = 'LIST ' + file
    +            else:
    +                cmd = 'LIST'
    +            conn, retrlen = self.ftp.ntransfercmd(cmd)
    +        self.busy = 1
    +
    +        ftpobj = addclosehook(conn.makefile('rb'), self.file_close)
    +        self.refcount += 1
    +        conn.close()
    +        # Pass back both a suitably decorated object and a retrieval length
    +        return (ftpobj, retrlen)
    +
    +    def endtransfer(self):
    +        self.busy = 0
    +
    +    def close(self):
    +        self.keepalive = False
    +        if self.refcount <= 0:
    +            self.real_close()
    +
    +    def file_close(self):
    +        self.endtransfer()
    +        self.refcount -= 1
    +        if self.refcount <= 0 and not self.keepalive:
    +            self.real_close()
    +
    +    def real_close(self):
    +        self.endtransfer()
    +        try:
    +            self.ftp.close()
    +        except ftperrors():
    +            pass
    +
    +# Proxy handling
    +def getproxies_environment():
    +    """Return a dictionary of scheme -> proxy server URL mappings.
    +
    +    Scan the environment for variables named <scheme>_proxy;
    +    this seems to be the standard convention.  If you need a
    +    different way, you can pass a proxies dictionary to the
    +    [Fancy]URLopener constructor.
    +
    +    """
    +    proxies = {}
    +    # in order to prefer lowercase variables, process environment in
    +    # two passes: first matches any, second pass matches lowercase only
    +    for name, value in os.environ.items():
    +        name = name.lower()
    +        if value and name[-6:] == '_proxy':
    +            proxies[name[:-6]] = value
    +    # CVE-2016-1000110 - If we are running as CGI script, forget HTTP_PROXY
    +    # (non-all-lowercase) as it may be set from the web server by a "Proxy:"
    +    # header from the client
    +    # If "proxy" is lowercase, it will still be used thanks to the next block
    +    if 'REQUEST_METHOD' in os.environ:
    +        proxies.pop('http', None)
    +    for name, value in os.environ.items():
    +        if name[-6:] == '_proxy':
    +            name = name.lower()
    +            if value:
    +                proxies[name[:-6]] = value
    +            else:
    +                proxies.pop(name[:-6], None)
    +    return proxies
    +
    +def proxy_bypass_environment(host, proxies=None):
    +    """Test if proxies should not be used for a particular host.
    +
    +    Checks the proxy dict for the value of no_proxy, which should
    +    be a list of comma separated DNS suffixes, or '*' for all hosts.
    +
    +    """
    +    if proxies is None:
    +        proxies = getproxies_environment()
    +    # don't bypass, if no_proxy isn't specified
    +    try:
    +        no_proxy = proxies['no']
    +    except KeyError:
    +        return 0
    +    # '*' is special case for always bypass
    +    if no_proxy == '*':
    +        return 1
    +    # strip port off host
    +    hostonly, port = splitport(host)
    +    # check if the host ends with any of the DNS suffixes
    +    no_proxy_list = [proxy.strip() for proxy in no_proxy.split(',')]
    +    for name in no_proxy_list:
    +        if name:
    +            name = name.lstrip('.')  # ignore leading dots
    +            name = re.escape(name)
    +            pattern = r'(.+\.)?%s$' % name
    +            if (re.match(pattern, hostonly, re.I)
    +                    or re.match(pattern, host, re.I)):
    +                return 1
    +    # otherwise, don't bypass
    +    return 0
    +
    +
    +# This code tests an OSX specific data structure but is testable on all
    +# platforms
    +def _proxy_bypass_macosx_sysconf(host, proxy_settings):
    +    """
    +    Return True iff this host shouldn't be accessed using a proxy
    +
    +    This function uses the MacOSX framework SystemConfiguration
    +    to fetch the proxy information.
    +
    +    proxy_settings come from _scproxy._get_proxy_settings or get mocked ie:
    +    { 'exclude_simple': bool,
    +      'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.1', '10.0/16']
    +    }
    +    """
    +    from fnmatch import fnmatch
    +
    +    hostonly, port = splitport(host)
    +
    +    def ip2num(ipAddr):
    +        parts = ipAddr.split('.')
    +        parts = list(map(int, parts))
    +        if len(parts) != 4:
    +            parts = (parts + [0, 0, 0, 0])[:4]
    +        return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]
    +
    +    # Check for simple host names:
    +    if '.' not in host:
    +        if proxy_settings['exclude_simple']:
    +            return True
    +
    +    hostIP = None
    +
    +    for value in proxy_settings.get('exceptions', ()):
    +        # Items in the list are strings like these: *.local, 169.254/16
    +        if not value: continue
    +
    +        m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
    +        if m is not None:
    +            if hostIP is None:
    +                try:
    +                    hostIP = socket.gethostbyname(hostonly)
    +                    hostIP = ip2num(hostIP)
    +                except OSError:
    +                    continue
    +
    +            base = ip2num(m.group(1))
    +            mask = m.group(2)
    +            if mask is None:
    +                mask = 8 * (m.group(1).count('.') + 1)
    +            else:
    +                mask = int(mask[1:])
    +            mask = 32 - mask
    +
    +            if (hostIP >> mask) == (base >> mask):
    +                return True
    +
    +        elif fnmatch(host, value):
    +            return True
    +
    +    return False
    +
    +
    +if sys.platform == 'darwin':
    +    from _scproxy import _get_proxy_settings, _get_proxies
    +
    +    def proxy_bypass_macosx_sysconf(host):
    +        proxy_settings = _get_proxy_settings()
    +        return _proxy_bypass_macosx_sysconf(host, proxy_settings)
    +
    +    def getproxies_macosx_sysconf():
    +        """Return a dictionary of scheme -> proxy server URL mappings.
    +
    +        This function uses the MacOSX framework SystemConfiguration
    +        to fetch the proxy information.
    +        """
    +        return _get_proxies()
    +
    +
    +
    +    def proxy_bypass(host):
    +        """Return True, if host should be bypassed.
    +
    +        Checks proxy settings gathered from the environment, if specified,
    +        or from the MacOSX framework SystemConfiguration.
    +
    +        """
    +        proxies = getproxies_environment()
    +        if proxies:
    +            return proxy_bypass_environment(host, proxies)
    +        else:
    +            return proxy_bypass_macosx_sysconf(host)
    +
    +    def getproxies():
    +        return getproxies_environment() or getproxies_macosx_sysconf()
    +
    +
    +elif os.name == 'nt':
    +    def getproxies_registry():
    +        """Return a dictionary of scheme -> proxy server URL mappings.
    +
    +        Win32 uses the registry to store proxies.
    +
    +        """
    +        proxies = {}
    +        try:
    +            import winreg
    +        except ImportError:
    +            # Std module, so should be around - but you never know!
    +            return proxies
    +        try:
    +            internetSettings = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
    +                r'Software\Microsoft\Windows\CurrentVersion\Internet Settings')
    +            proxyEnable = winreg.QueryValueEx(internetSettings,
    +                                               'ProxyEnable')[0]
    +            if proxyEnable:
    +                # Returned as Unicode but problems if not converted to ASCII
    +                proxyServer = str(winreg.QueryValueEx(internetSettings,
    +                                                       'ProxyServer')[0])
    +                if '=' in proxyServer:
    +                    # Per-protocol settings
    +                    for p in proxyServer.split(';'):
    +                        protocol, address = p.split('=', 1)
    +                        # See if address has a type:// prefix
    +                        if not re.match('^([^/:]+)://', address):
    +                            address = '%s://%s' % (protocol, address)
    +                        proxies[protocol] = address
    +                else:
    +                    # Use one setting for all protocols
    +                    if proxyServer[:5] == 'http:':
    +                        proxies['http'] = proxyServer
    +                    else:
    +                        proxies['http'] = 'http://%s' % proxyServer
    +                        proxies['https'] = 'https://%s' % proxyServer
    +                        proxies['ftp'] = 'ftp://%s' % proxyServer
    +            internetSettings.Close()
    +        except (OSError, ValueError, TypeError):
    +            # Either registry key not found etc, or the value in an
    +            # unexpected format.
    +            # proxies already set up to be empty so nothing to do
    +            pass
    +        return proxies
    +
    +    def getproxies():
    +        """Return a dictionary of scheme -> proxy server URL mappings.
    +
    +        Returns settings gathered from the environment, if specified,
    +        or the registry.
    +
    +        """
    +        return getproxies_environment() or getproxies_registry()
    +
    +    def proxy_bypass_registry(host):
    +        try:
    +            import winreg
    +        except ImportError:
    +            # Std modules, so should be around - but you never know!
    +            return 0
    +        try:
    +            internetSettings = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
    +                r'Software\Microsoft\Windows\CurrentVersion\Internet Settings')
    +            proxyEnable = winreg.QueryValueEx(internetSettings,
    +                                               'ProxyEnable')[0]
    +            proxyOverride = str(winreg.QueryValueEx(internetSettings,
    +                                                     'ProxyOverride')[0])
    +            # ^^^^ Returned as Unicode but problems if not converted to ASCII
    +        except OSError:
    +            return 0
    +        if not proxyEnable or not proxyOverride:
    +            return 0
    +        # try to make a host list from name and IP address.
    +        rawHost, port = splitport(host)
    +        host = [rawHost]
    +        try:
    +            addr = socket.gethostbyname(rawHost)
    +            if addr != rawHost:
    +                host.append(addr)
    +        except OSError:
    +            pass
    +        try:
    +            fqdn = socket.getfqdn(rawHost)
    +            if fqdn != rawHost:
    +                host.append(fqdn)
    +        except OSError:
    +            pass
    +        # make a check value list from the registry entry: replace the
    +        # '<local>' string by the localhost entry and the corresponding
    +        # canonical entry.
    +        proxyOverride = proxyOverride.split(';')
    +        # now check if we match one of the registry values.
    +        for test in proxyOverride:
    +            if test == '<local>':
    +                if '.' not in rawHost:
    +                    return 1
    +            test = test.replace(".", r"\.")     # mask dots
    +            test = test.replace("*", r".*")     # change glob sequence
    +            test = test.replace("?", r".")      # change glob char
    +            for val in host:
    +                if re.match(test, val, re.I):
    +                    return 1
    +        return 0
    +
    +    def proxy_bypass(host):
    +        """Return True, if host should be bypassed.
    +
    +        Checks proxy settings gathered from the environment, if specified,
    +        or the registry.
    +
    +        """
    +        proxies = getproxies_environment()
    +        if proxies:
    +            return proxy_bypass_environment(host, proxies)
    +        else:
    +            return proxy_bypass_registry(host)
    +
    +else:
    +    # By default use environment variables
    +    getproxies = getproxies_environment
    +    proxy_bypass = proxy_bypass_environment
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/_sources/M2Crypto.SSL.rst.txt b/doc/html/_sources/M2Crypto.SSL.rst.txt new file mode 100644 index 0000000..233c1eb --- /dev/null +++ b/doc/html/_sources/M2Crypto.SSL.rst.txt @@ -0,0 +1,91 @@ +SSL Package +=========== + +:mod:`SSL` Package +------------------ + +.. automodule:: M2Crypto.SSL + :members: + :undoc-members: + :show-inheritance: + +:mod:`Checker` Module +--------------------- + +.. automodule:: M2Crypto.SSL.Checker + :members: + :undoc-members: + :show-inheritance: + +:mod:`Cipher` Module +-------------------- + +.. automodule:: M2Crypto.SSL.Cipher + :members: + :undoc-members: + :show-inheritance: + +:mod:`Connection` Module +------------------------ + +.. automodule:: M2Crypto.SSL.Connection + :members: + :undoc-members: + :show-inheritance: + +:mod:`Context` Module +--------------------- + +.. automodule:: M2Crypto.SSL.Context + :members: + :undoc-members: + :show-inheritance: + +:mod:`SSLServer` Module +----------------------- + +.. automodule:: M2Crypto.SSL.SSLServer + :members: + :undoc-members: + :show-inheritance: + +:mod:`Session` Module +--------------------- + +.. automodule:: M2Crypto.SSL.Session + :members: + :undoc-members: + :show-inheritance: + +:mod:`TwistedProtocolWrapper` Module +------------------------------------ + +.. automodule:: M2Crypto.SSL.TwistedProtocolWrapper + :members: + :undoc-members: + :show-inheritance: + +:mod:`cb` Module +---------------- + +.. automodule:: M2Crypto.SSL.cb + :members: + :undoc-members: + :show-inheritance: + +:mod:`ssl_dispatcher` Module +---------------------------- + +.. automodule:: M2Crypto.SSL.ssl_dispatcher + :members: + :undoc-members: + :show-inheritance: + +:mod:`timeout` Module +--------------------- + +.. automodule:: M2Crypto.SSL.timeout + :members: + :undoc-members: + :show-inheritance: + diff --git a/doc/html/_sources/M2Crypto.rst.txt b/doc/html/_sources/M2Crypto.rst.txt new file mode 100644 index 0000000..dc6c706 --- /dev/null +++ b/doc/html/_sources/M2Crypto.rst.txt @@ -0,0 +1,218 @@ +M2Crypto Package +================ + +:mod:`M2Crypto` Package +----------------------- + +.. automodule:: M2Crypto.__init__ + :members: + :undoc-members: + :show-inheritance: + +:mod:`ASN1` Module +------------------ + +.. automodule:: M2Crypto.ASN1 + :members: + :undoc-members: + :show-inheritance: + +:mod:`AuthCookie` Module +------------------------ + +.. automodule:: M2Crypto.AuthCookie + :members: + :undoc-members: + :show-inheritance: + +:mod:`BIO` Module +----------------- + +.. automodule:: M2Crypto.BIO + :members: + :undoc-members: + :show-inheritance: + +:mod:`BN` Module +---------------- + +.. automodule:: M2Crypto.BN + :members: + :undoc-members: + :show-inheritance: + +:mod:`DH` Module +---------------- + +.. automodule:: M2Crypto.DH + :members: + :undoc-members: + :show-inheritance: + +:mod:`DSA` Module +----------------- + +.. automodule:: M2Crypto.DSA + :members: + :undoc-members: + :show-inheritance: + +:mod:`EC` Module +---------------- + +.. automodule:: M2Crypto.EC + :members: + :undoc-members: + :show-inheritance: + +:mod:`EVP` Module +----------------- + +.. automodule:: M2Crypto.EVP + :members: + :undoc-members: + :show-inheritance: + +:mod:`Engine` Module +-------------------- + +.. automodule:: M2Crypto.Engine + :members: + :undoc-members: + :show-inheritance: + +:mod:`Err` Module +----------------- + +.. automodule:: M2Crypto.Err + :members: + :undoc-members: + :show-inheritance: + +:mod:`RC4` Module +----------------- + +.. automodule:: M2Crypto.RC4 + :members: + :undoc-members: + :show-inheritance: + +:mod:`RSA` Module +----------------- + +.. automodule:: M2Crypto.RSA + :members: + :undoc-members: + :show-inheritance: + +:mod:`Rand` Module +------------------ + +.. automodule:: M2Crypto.Rand + :members: + :undoc-members: + :show-inheritance: + +:mod:`SMIME` Module +------------------- + +.. automodule:: M2Crypto.SMIME + :members: + :undoc-members: + :show-inheritance: + +:mod:`X509` Module +------------------ + +.. automodule:: M2Crypto.X509 + :members: + :undoc-members: + :show-inheritance: + +:mod:`callback` Module +---------------------- + +.. automodule:: M2Crypto.callback + :members: + :undoc-members: + :show-inheritance: + +:mod:`ftpslib` Module +--------------------- + +.. automodule:: M2Crypto.ftpslib + :members: + :undoc-members: + :show-inheritance: + +:mod:`httpslib` Module +---------------------- + +.. automodule:: M2Crypto.httpslib + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2` Module +---------------- + +.. automodule:: M2Crypto.m2 + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2crypto` Module +---------------------- + +.. automodule:: M2Crypto.m2crypto + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2urllib` Module +---------------------- + +.. automodule:: M2Crypto.m2urllib + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2urllib2` Module +----------------------- + +.. automodule:: M2Crypto.m2urllib2 + :members: + :undoc-members: + :show-inheritance: + +:mod:`m2xmlrpclib` Module +------------------------- + +.. automodule:: M2Crypto.m2xmlrpclib + :members: + :undoc-members: + :show-inheritance: + +:mod:`threading` Module +----------------------- + +.. automodule:: M2Crypto.threading + :members: + :undoc-members: + :show-inheritance: + +:mod:`util` Module +------------------ + +.. automodule:: M2Crypto.util + :members: + :undoc-members: + :show-inheritance: + +Subpackages +----------- + +.. toctree:: + + M2Crypto.SSL + diff --git a/doc/html/_sources/ZServerSSL-HOWTO.rst.txt b/doc/html/_sources/ZServerSSL-HOWTO.rst.txt new file mode 100644 index 0000000..91ef5af --- /dev/null +++ b/doc/html/_sources/ZServerSSL-HOWTO.rst.txt @@ -0,0 +1,239 @@ +:orphan: + +.. _zserverssl-howto: + +ZServerSSL-HOWTO +################ + +:author: Pheng Siong Ng +:copyright: © 2000, 2001 by Ng Pheng Siong. +:date: 2003-06-22 + +.. contents:: + :backlinks: entry + +.. sectnum:: + :suffix: . + +Introduction +============ + +ZServerSSL adds to Zope's ZServer the following: + +- HTTPS server +- WebDAV-source-over-HTTPS server + +With the HTTPS server, ZServerSSL also provides WebDAV-over-HTTPS and +XMLRPC-over-HTTPS access to Zope. + +These instructions apply to both Un\*x and Windows installations of Zope +2.6.1. To avoid cluttering the presentation, Windows pathnames are shown +in Un\*x fashion. + +Preparation +=========== + +#. Download M2Crypto 0.11, contained in the file ``m2crypto-0.11.zip``. +#. Unpack ``m2crypto-0.11.zip``. This will create a directory + ``m2crypto-0.11``. Henceforth, we refer to this directory as ``$M2``. +#. Install M2Crypto per the instructions in ``$M2/INSTALL``. + +The ZServerSSL distribution is in ``$M2/demo/Zope``. We shall refer to +this directory as ``$ZSSL``. + +Installation +============ + +Below, we refer to your Zope top-level directory as ``$ZOPE``. + +#. Copy ``$ZSSL/z2s.py`` into ``$ZOPE``. + +#. Depending on your operating system, modify ``$ZOPE/start`` or + ``$ZOPE/start.bat`` to invoke ``$ZOPE/z2s.py``, instead of + ``$ZOPE/z2.py``. The files ``$ZSSL/starts`` and ``$ZSSL/starts.bat`` + serve as examples. + +#. Copy ``$ZSSL/dh1024.pem`` into ``$ZOPE``. This file contains + Diffie-Hellman parameters for use by the SSL protocol. + +#. Copy ``$ZSSL/randpool.dat`` into ``$ZOPE``. This file contains seed + material for the OpenSSL PRNG. Alternatively, create + ``$ZOPE/randpool.dat`` thusly:: + + $ dd if=/dev/urandom of=randpool.dat bs=1024 count=1 + +#. Copy ``$ZSSL/ca.pem`` to ``$ZOPE``. This file contains an + example Certification Authority (CA) certificate. For + information on operating your own CA, see :ref:`howto-ca` or + one of numerous similar documents available on the web. + +#. Copy ``$ZSSL/server.pem`` to ``$ZOPE``. This file contains an RSA key + pair and its X.509v3 certificate issued by the above CA. You may also + create your own key/certificate bundle. + +#. Copy ``$ZSSL/ZServer/HTTPS_Server.py`` to ``$ZOPE/ZServer``. + +#. Copy ``$ZSSL/ZServer/__init__.py`` to ``$ZOPE/ZServer``. This + overwrites the existing ``$ZOPE/ZServer/__init__.py``. Alternatively, + apply the following patch to ``$ZOPE/ZServer/__init__.py``:: + + --- __init__.py.org Sat Jun 21 23:20:41 2003 + +++ __init__.py Tue Jan 7 23:30:53 2003 + @@ -84,6 +84,7 @@ + import asyncore + from medusa import resolver, logger + from HTTPServer import zhttp_server, zhttp_handler + +from HTTPS_Server import zhttps_server, zhttps_handler + from PCGIServer import PCGIServer + from FCGIServer import FCGIServer + from FTPServer import FTPServer + +#. Copy ``$ZSSL/ZServer/medusa/https_server.py`` to + ``$ZOPE/ZServer/medusa``. + +#. Stop Zope, if it is running. + +#. Start Zope with ZServerSSL thusly:: + + ./starts -X -f 9021 -w 9080 -W 9081 -y 9443 -Y 9444 + + This starts the following: + + - an FTP server on port 9021 + - a HTTP server on port 9080 + - a WebDAV-source server on port 9081 + - a HTTPS server on port 9443 + - a WebDAV-source-over-HTTPS server on port 9444 + +Testing +======= + +Below, we assume your Zope server is running on ``localhost``. + +HTTPS +===== + +This testing is done with Mozilla 1.1 on FreeBSD. + +#. With a browser, connect to https://localhost:9443/. Browse around. + Check out your browser's HTTPS informational screens. +#. Connect to https://localhost:9443/manage. Verify that you can access + Zope's management functionality. + +WebDAV-over-HTTPS +================= + +This testing is done with Cadaver 0.21.0 on FreeBSD.:: + + $ cadaver https://localhost:9443/ + WARNING: Untrusted server certificate presented: + Issued to: M2Crypto, SG + Issued by: M2Crypto, SG + Do you wish to accept the certificate? (y/n) y + dav:/> ls + Listing collection `/': succeeded. + Coll: Channels 0 Jun 19 00:04 + Coll: Control_Panel 0 Jun 6 00:13 + Coll: Examples 0 Jun 6 00:12 + Coll: catalog 0 Jun 12 11:53 + Coll: ngps 0 Jun 16 15:34 + Coll: portal 0 Jun 21 15:21 + Coll: skunk 0 Jun 18 21:18 + Coll: temp_folder 0 Jun 22 17:57 + Coll: zope 0 Jun 20 15:27 + acl_users 0 Dec 30 1998 + browser_id_manager 0 Jun 6 00:12 + default.css 3037 Jun 21 16:38 + error_log 0 Jun 6 00:12 + index_html 313 Jun 12 13:36 + portal0 0 Jun 21 15:21 + session_data_manager 0 Jun 6 00:12 + standard_error_message 1365 Jan 21 2001 + standard_html_footer 50 Jun 12 12:30 + standard_html_header 80 Jan 21 2001 + standard_template.pt 282 Jun 6 00:12 + zsyncer 0 Jun 17 15:28 + dav:/> quit + Connection to `localhost' closed. + $ + + +WebDAV-Source-over-HTTPS +======================== + +This testing is done with Mozilla 1.1 on FreeBSD. + +#. Open the Mozilla Composer window. +#. Click "File", "Open Web Location". A dialog box appears. +#. Enter ``https://localhost:9444/index_html`` for the URL. +#. Select "Open in new Composer window." +#. Click "Open". A new Composer window will open with ``index_html`` + loaded. + +Python with M2Crypto +==================== + +This testing is done with M2Crypto 0.11 and Python 2.2.2 on FreeBSD. + +HTTPS +===== + +:: + + >>> from M2Crypto import Rand, SSL, m2urllib + >>> url = m2urllib.FancyURLopener() + >>> url.addheader('Connection', 'close') + >>> u = url.open('https://127.0.0.1:9443/') + send: 'GET / HTTP/1.1\r\nHost: 127.0.0.1:9443\r\nAccept-Encoding: identity\r\nUser-agent: Python-urllib/1.15\r\nConnection: close\r\n\r\n' + reply: 'HTTP/1.1 200 OK\r\n' + header: Server: ZServerSSL/0.11 + header: Date: Sun, 22 Jun 2003 13:42:34 GMT + header: Connection: close + header: Content-Type: text/html + header: Etag: + header: Content-Length: 535 + >>> while 1: + ... data = u.read() + ... if not data: break + ... print(data) + ... + +:: + + + + Zope + +

    NgPS Desktop Portal

    + +   So many hacks.
    +   So little time.
    + +

    Link Farm

    + + +
    Powered by Zope + +:: + + >>> u.close() + >>> + +XMLRPC-over-HTTPS +================= + +:: + + >>> from M2Crypto.m2xmlrpclib import Server, SSL_Transport + >>> zs = Server('https://127.0.0.1:9443/', SSL_Transport()) + >>> print(zs.propertyMap()) + [{'type': 'string', 'id': 'title', 'mode': 'w'}] + >>> + +Conclusion +========== + +Well, it works! ;-) diff --git a/doc/html/_sources/howto.ca.rst.txt b/doc/html/_sources/howto.ca.rst.txt new file mode 100644 index 0000000..e950b59 --- /dev/null +++ b/doc/html/_sources/howto.ca.rst.txt @@ -0,0 +1,370 @@ +:orphan: + +.. _howto-ca: + +HOWTO: Creating your own CA with OpenSSL +######################################## + +:author: Pheng Siong Ng +:copyright: © 2000, 2001 by Ng Pheng Siong. + +Introduction +============ + +This is a HOWTO on creating your own *certification authority* (*CA*) +with OpenSSL. + +I last created a CA about a year ago, when I began work on +`M2Crypto `__ and needed +certificates for the SSL bits. I accepted the tools' default +settings then, e.g., certificate validity of 365 days; this meant +that my certificates, including my CA's certificate, have now +expired. + +Since I am using these certificates for M2Crypto's demonstration +programs (and I have forgotten the passphrase to the CA's private +key), I decided to discard the old CA and start afresh. I also +decided to document the process, hence this HOWTO. + +The Procedure +============= + +I use ``CA.pl``, a Perl program written by Steve Hanson and bundled with +OpenSSL. + +The following are the steps to create a CA: + +1. Choose a directory to do your CA work. All commands are executed + within this directory. Let's call the directory ``demo``. + +2. Copy ``CA.pl`` and ``openssl.cnf`` into ``demo``. + +3. Apply the following patch to ``CA.pl``, which allows it to generate a + CA certificate with a validity period of 1095 days, i.e., + 3 years:: + + --- CA.pl.org Sat Mar 31 12:40:13 2001 + +++ CA.pl Sat Mar 31 12:41:15 2001 + @@ -97,7 +97,7 @@ + } else { + print "Making CA certificate ...\n"; + system ("$REQ -new -x509 -keyout " . + - "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT $DAYS"); + + "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT -days 1095"); + $RET=$?; + } + } + + +4. Create a new CA like this:: + + ./CA.pl -newca + + A certificate filename (or enter to create) + + Making CA certificate ... + Using configuration from openssl.cnf + Generating a 1024 bit RSA private key + ............++++++ + ......................++++++ + writing new private key to './demoCA/private/cakey.pem' + Enter PEM pass phrase: + Verifying password - Enter PEM pass phrase: + ----- + You are about to be asked to enter information that will be incorporated + into your certificate request. + What you are about to enter is what is called a Distinguished Name or a DN. + There are quite a few fields but you can leave some blank + For some fields there will be a default value, + If you enter '.', the field will be left blank. + ----- + Country Name (2 letter code) [AU]:SG + State or Province Name (full name) [Some-State]:. + Locality Name (eg, city) []:.. + Organization Name (eg, company) [Internet Widgits Pty Ltd]:DemoCA + Organizational Unit Name (eg, section) []:. + Common Name (eg, YOUR name) []:DemoCA Certificate Master + Email Address []:certmaster@democa.dom + + This creates a new CA in the directory ``demoCA``. The CA's + self-signed certificate is in ``demoCA/cacert.pem`` and its RSA key + pair is in ``demoCA/private/cakey.pem``. + + ``demoCA/private/cakey.pem`` looks like this:: + + cat demoCA/private/cakey.pem + + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED + DEK-Info: DES-EDE3-CBC,19973A9DBBB601BA + + eOq9WFScNiI4/UWEUaSnGTKpJv2JYuMD3HwQox2Q3Cd4zGqVjJ6gF3exa5126cKf + X/bMVnwbPpuFZPiAIvaLyCjT6pYeXTBbSzs7/GQnvEOv+nYnDUFWi0Qm92qLk0uy + pFi/M1aWheN3vir2ZlAw+DW0bOOZhj8tC7Co7lMYb0YE271b6/YRPZCwQ3GXAHUJ + +aMYxlUDrK45aCUa/1CZDzTgk7h9cDgx2QJSIvYMYytCfI3zsuZMJS8/4OXLL0bI + lKmAc1dwB3DqGJt5XK4WJesiNfdxeCNEgAcYtEAgYZTPIApU+kTgTCIxJl2nMW7j + ax+Q1z7g+4MpgG20WD633D4z4dTlDdz+dnLi0rvuvxiwt+dUhrqiML1tyi+Z6EBH + jU4/cLBWev3rYfrlp4x8J9mDte0YKOk3t0wQOHqRetTsIfdtjnFp/Hu3qDmTCWjD + z/g7PPoO/bg/B877J9WBPbL/1hXXFYo88M+2aGlPOgDcFdiOqbLb2DCscohMbbVr + A4mgiy2kwWfIE73qiyV7yyG8FlRvr1iib+jbT3LTGf743utYAAs7HNGuOUObhoyt + jYvBD7ACn35P5YX7KTqvqErwdijxYCaNBCnvmRtmYSaNw9Kv1UJTxc5Vx7YLwIPk + E9KyBgKI7vPOjWBZ27+zOvNycmv1ciNtpALAw4bWtXnhCDVTHaVDy34OkheMzNCg + 2cjcBFzOkMIjcI03KbTQXOFIQGlsTWXGzkNf/zBQ+KksT1MCj+zBXSCvlDASMckg + kef21pGgUqPF14gKGfWX3sV4bjc1vbrRwq6zlG3nMuYqR5MtJJY9eQ== + -----END RSA PRIVATE KEY----- + + +5. Next, generate a certificate request:: + + ./CA.pl -newreq + + Using configuration from openssl.cnf + Generating a 1024 bit RSA private key + ..........++++++ + ..............++++++ + writing new private key to 'newreq.pem' + Enter PEM pass phrase: + Verifying password - Enter PEM pass phrase: + ----- + You are about to be asked to enter information that will be incorporated + into your certificate request. + What you are about to enter is what is called a Distinguished Name or a DN. + There are quite a few fields but you can leave some blank + For some fields there will be a default value, + If you enter '.', the field will be left blank. + ----- + Country Name (2 letter code) [AU]:SG + State or Province Name (full name) [Some-State]:.. + Locality Name (eg, city) []:. + Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto + Organizational Unit Name (eg, section) []:. + Common Name (eg, YOUR name) []:localhost + Email Address []:admin@server.example.dom + + Please enter the following 'extra' attributes + to be sent with your certificate request + A challenge password []: + An optional company name []: + Request (and private key) is in newreq.pem + +\ + + The certificate request and private key in ``newreq.pem`` looks like + this:: + + cat newreq.pem + + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED + DEK-Info: DES-EDE3-CBC,41B2874DF3D02DD4 + + mg611EoVkLEooSTv+qTM0Ddmm/M1jE/Jy5RD/sc3LSMhuGu9xc26OgsTJmkQuIAh + J/B4lAw8G59VTG6DykeEtrG0rUBx4bggc7PKbFuiN423YjJODWcHvVgnPOzXMQt+ + lY4tPl5+217MRHyx2NsWGrpkQNdu3GeSPOVMl3jeQiaXupONbwQ7rj42+X/VtAJP + W4D1NNwu8aGCPyShsEXHc/fI1WDpphYWke97pOjIZVQESFZOPty5HjIYZux4U+td + W81xODtq2ecJXc8fn2Wpa9y5VD1LT7oJksOuL1+Z04OVaeUe4x0swM17HlBm2kVt + fe/C/L6kN27MwZhE331VjtTjSGl4/gknqQDbLOtqT06f3OISsDJETm2itllyhgzv + C6Fi3N03rGFmKectijC+tws5k+P+HRG6sai33usk8xPokJqA+HYSWPz1XVlpRmv4 + kdjQOdST7ovU62mOTgf3ARcduPPwuzTfxOlYONe5NioO1APVHBrInQwcpLkpOTQR + vI4roIN+b75/nihUWGUJn/nbbBa2Yl0N5Gs1Tyiy9Z+CcRT2TfWKBBFlEUIFl7Mb + J9fTV3DI+k+akbR4il1NkQ8EcSmCr3WpA0I9n0EHI7ZVpVaHxc0sqaPFl8YGdFHq + 1Qk53C/w6+qPpDzT3yKFmG2LZytAAM1czvb6RbNRJJP2ZrpBwn/h99sUTo/yPfxY + nueYmFJDm0uVNtG0icXGNUfSfnjKNTtHPAgyKGetRIC3kgJz/bo2w7EI6iEjBAzK + l5TRm4x6ZJxwuXXMiJCehMMd8TC8ybwWO4AO19B3ebFFeTVsUgxSGA== + -----END RSA PRIVATE KEY----- + -----BEGIN CERTIFICATE REQUEST----- + MIIBnTCCAQYCAQAwXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIw + EAYDVQQDEwlsb2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5l + eGFtcGxlLmRvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr1nYY1Qrll1r + uB/FqlCRrr5nvupdIN+3wF7q915tvEQoc74bnu6b8IbbGRMhzdzmvQ4SzFfVEAuM + MuTHeybPq5th7YDrTNizKKxOBnqE2KYuX9X22A1Kh49soJJFg6kPb9MUgiZBiMlv + tb7K3CHfgw5WagWnLl8Lb+ccvKZZl+8CAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GB + AHpoRp5YS55CZpy+wdigQEwjL/wSluvo+WjtpvP0YoBMJu4VMKeZi405R7o8oEwi + PdlrrliKNknFmHKIaCKTLRcU59ScA6ADEIWUzqmUzP5Cs6jrSRo3NKfg1bd09D1K + 9rsQkRc9Urv9mRBIsredGnYECNeRaK5R1yzpOowninXC + -----END CERTIFICATE REQUEST----- + +\ + + Decoding the certificate request gives the following:: + + openssl req -text -noout < newreq.pem + + Using configuration from /usr/local/pkg/openssl/openssl.cnf + Certificate Request: + Data: + Version: 0 (0x0) + Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50: + 91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e: + 6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13: + 21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4: + c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac: + 4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f: + 6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9: + 6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f: + 0b:6f:e7:1c:bc:a6:59:97:ef + Exponent: 65537 (0x10001) + Attributes: + a0:00 + Signature Algorithm: md5WithRSAEncryption + 7a:68:46:9e:58:4b:9e:42:66:9c:be:c1:d8:a0:40:4c:23:2f: + fc:12:96:eb:e8:f9:68:ed:a6:f3:f4:62:80:4c:26:ee:15:30: + a7:99:8b:8d:39:47:ba:3c:a0:4c:22:3d:d9:6b:ae:58:8a:36: + 49:c5:98:72:88:68:22:93:2d:17:14:e7:d4:9c:03:a0:03:10: + 85:94:ce:a9:94:cc:fe:42:b3:a8:eb:49:1a:37:34:a7:e0:d5: + b7:74:f4:3d:4a:f6:bb:10:91:17:3d:52:bb:fd:99:10:48:b2: + b7:9d:1a:76:04:08:d7:91:68:ae:51:d7:2c:e9:3a:8c:27:8a: + 75:c2 + +6. Now, sign the certificate request:: + + ./CA.pl -sign + + Using configuration from openssl.cnf + Enter PEM pass phrase: + Check that the request matches the signature + Signature ok + The Subjects Distinguished Name is as follows + countryName :PRINTABLE:'SG' + organizationName :PRINTABLE:'M2Crypto' + commonName :PRINTABLE:'localhost' + emailAddress :IA5STRING:'admin@server.example.dom' + Certificate is to be certified until Mar 31 02:57:30 2002 GMT (365 days) + Sign the certificate? [y/n]:y + + + 1 out of 1 certificate requests certified, commit? [y/n]y + Write out database with 1 new entries + Data Base Updated + Signed certificate is in newcert.pem + +\ + + ``newcert.pem`` looks like this:: + + cat newcert.pem + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom + Validity + Not Before: Mar 31 02:57:30 2001 GMT + Not After : Mar 31 02:57:30 2002 GMT + Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50: + 91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e: + 6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13: + 21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4: + c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac: + 4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f: + 6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9: + 6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f: + 0b:6f:e7:1c:bc:a6:59:97:ef + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom + Validity + Not Before: Mar 31 02:57:30 2001 GMT + Not After : Mar 31 02:57:30 2002 GMT + Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50: + 91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e: + 6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13: + 21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4: + c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac: + 4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f: + 6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9: + 6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f: + 0b:6f:e7:1c:bc:a6:59:97:ef + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + B3:D6:89:88:2F:B1:15:40:EC:0A:C0:30:35:3A:B7:DA:72:73:1B:4D + X509v3 Authority Key Identifier: + keyid:F9:6A:A6:34:97:6B:BC:BB:5A:17:0D:19:FC:62:21:0B:00:B5:0E:29 + DirName:/C=SG/O=DemoCA/CN=DemoCA Certificate Master/Email=certmaster@democa.dom + serial:00 + + Signature Algorithm: md5WithRSAEncryption + +7. In certain situations, e.g., where your certificate and private key + are to be used in an unattended SSL server, you may wish to not + encrypt the private key, i.e., leave the key in the clear. This + decision should be governed by your site's security policy and threat + model, of course:: + + openssl rsa < newkey.pem > newkey2.pem + + read RSA key + Enter PEM pass phrase: + writing RSA key + + ``newkey2.pem`` looks like this:: + + cat newkey2.pem + + -----BEGIN RSA PRIVATE KEY----- + MIICXgIBAAKBgQCvWdhjVCuWXWu4H8WqUJGuvme+6l0g37fAXur3Xm28RChzvhue + 7pvwhtsZEyHN3Oa9DhLMV9UQC4wy5Md7Js+rm2HtgOtM2LMorE4GeoTYpi5f1fbY + DUqHj2ygkkWDqQ9v0xSCJkGIyW+1vsrcId+DDlZqBacuXwtv5xy8plmX7wIDAQAB + AoGAbAkU8w3W1Qu15Hle1bJSL7GMReoreqeblOBmMAZz4by0l6sXZXJpjWXo86f/ + +dASMYTMPC4ZTYtv06N07AFbjL+kDfqDMTfzQkYMHp1LAq1Ihbq1rHWSBH5n3ekq + KiY8JKpv8DR5Po1iKaXJFuDByGDENJwYbSRSpSK3P+vkWWECQQDkEUE/ZPqqqZkQ + 2iWRPAsCbEID8SAraQl3DdCLYs/GgARfmmj4yUHEwkys9Jo1H8k4BdxugmaUwNi5 + YQ/CVzrXAkEAxNO80ArbGxPUmr11GHG/bGBYj1DUBkHZSc7dgxZdtUCLGNxQnNsg + Iwq3n6j1sUzS3UW6abQ8bivYNOUcMKJAqQJBANQxFaLU4b/NQaODQ3aoBZpAfP9L + 5eFdvbet+7zjt2r5CpikgkwOfAmDuXEltx/8LevY0CllW+nErx9zJgVrwUsCQQCu + 76H5JiznPBDSF2FjgHWqVVdgyW4owY3mU739LHvNBLicN/RN9VPy0Suy8/CqzKT9 + lWPBXzf2k3FuUdNkRlFBAkEAmpXoybuiFR2S5Bma/ax96lVs0/VihhfC1zZP/X/F + Br77+h9dIul+2DnyOl50zu0Sdzst1/7ay4JSDHyiBCMGSQ== + -----END RSA PRIVATE KEY----- + + +That's it! The certificate, ``newcert.pem``, and the private key - +``newkey.pem`` (encrypted) or ``newkey2.pem`` (unencrypted) - are now +ready to be used. You may wish to rename the files to more intuitive +names. + +You should also keep the CA's certificate ``demo/cacert.pem`` handy +for use when developing and deploying SSL or S/MIME applications. + +Conclusion +========== + +We've walked through the basic steps in the creation of a CA and +certificates using the tools that come with OpenSSL. We did not cover +more advanced topics such as constraining a certificate to be SSL-only +or S/MIME-only. + +There exist several HOWTOs similar to this one on the net. This one is +written specifically to facilitate discussions in my other HOWTOs on +developing SSL and S/MIME applications in +`Python `__ using +`M2Crypto `__. + diff --git a/doc/html/_sources/howto.smime.rst.txt b/doc/html/_sources/howto.smime.rst.txt new file mode 100644 index 0000000..715e7c4 --- /dev/null +++ b/doc/html/_sources/howto.smime.rst.txt @@ -0,0 +1,778 @@ +:orphan: + +.. _howto-smime: + +HOWTO: Programming S/MIME in Python with M2Crypto +================================================= + +:author: Pheng Siong Ng +:copyright: © 2000, 2001 by Ng Pheng Siong. + +Introduction +============ + +`M2Crypto `__ is a +`Python `__ interface to +`OpenSSL `__. It makes available to the Python +programmer SSL functionality to implement clients and servers, S/MIME +v2, RSA, DSA, DH, symmetric ciphers, message digests and HMACs. + +This document demonstrates programming S/MIME with M2Crypto. + +S/MIME +====== + +S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC +2312] - provides a consistent way to send and receive secure MIME data. +Based on the popular Internet MIME standard, S/MIME provides the +following cryptographic security services for electronic messaging +applications - *authentication*, *message integrity* and +*non-repudiation of origin* (using *digital signatures*), and *privacy* +and *data security* (using *encryption*). + +Keys and Certificates +===================== + +To create an S/MIME-signed message, you need an RSA key pair (this +consists of a public key and a private key) and an X.509 certificate of +said public key. + +To create an S/MIME-encrypted message, you need an X.509 certificate for +each recipient. + +To create an S/MIME-signed *and* -encrypted message, first create a +signed message, then encrypt the signed message with the recipients' +certificates. + +You may generate key pairs and obtain certificates by using a commercial +*certification authority* service. + +You can also do so using freely-available software. For many purposes, +e.g., automated S/MIME messaging by system administration processes, +this approach is cheap and effective. + +We now work through using OpenSSL to generate key pairs and +certificates. This assumes you have OpenSSL installed properly on your +system. + +First, we generate an X.509 certificate to be used for signing:: + + openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out signer.pem + + Using configuration from /usr/local/pkg/openssl/openssl.cnf + Generating a 1024 bit RSA private key + ..++++++ + ....................++++++ + writing new private key to 'privkey.pem' + ----- + You are about to be asked to enter information that will be incorporated + into your certificate request. + What you are about to enter is what is called a Distinguished Name or a DN. + There are quite a few fields but you can leave some blank + For some fields there will be a default value, + If you enter '.', the field will be left blank. + ----- + Country Name (2 letter code) [AU]:SG + State or Province Name (full name) [Some-State]:. + Locality Name (eg, city) []:. + Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto + Organizational Unit Name (eg, section) []:. + Common Name (eg, YOUR name) []:S/MIME Sender + Email Address []:sender@example.dom + + +This generates a 1024-bit RSA key pair, unencrypted, into +``privkey.pem``; it also generates a self-signed X.509 certificate for +the public key into ``signer.pem``. The certificate is valid for 365 +days, i.e., a year. + +Let's rename ``privkey.pem`` so that we know it is a companion of +``signer.pem``'s:: + + mv privkey.pem signer_key.pem + +To verify the content of ``signer.pem``, execute the following:: + + openssl x509 -noout -text -in signer.pem + + Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom + Validity + Not Before: Mar 24 12:56:16 2001 GMT + Not After : Mar 24 12:56:16 2002 GMT + Subject: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a9:d6:e2:b5:11:3b:ae:3c:e2:17:31:70:e1:6e: + 01:f4:19:6d:bd:2a:42:36:2b:37:34:e2:83:1d:0d: + 11:2e:b4:99:44:db:10:67:be:97:5f:5b:1a:26:33: + 46:23:2f:95:04:7a:35:da:9d:f9:26:88:39:9e:17: + cd:3e:eb:a8:19:8d:a8:2a:f1:43:da:55:a9:2e:2c: + 65:ed:04:71:42:ce:73:53:b8:ea:7e:c7:f0:23:c6: + 63:c5:5e:68:96:64:a7:b4:2a:94:26:76:eb:79:ea: + e3:4e:aa:82:09:4f:44:87:4a:12:62:b5:d7:1f:ca: + f2:ce:d5:ba:7e:1f:48:fd:b9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99 + X509v3 Authority Key Identifier: + keyid:29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99 + DirName:/C=SG/O=M2Crypto/CN=S/MIME Sender/Email=sender@example.dom + serial:00 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 68:c8:6b:1b:fa:7c:9a:39:35:76:18:15:c9:fd:89:97:62:db: + 7a:b0:2d:13:dd:97:e8:1b:7a:9f:22:27:83:24:9d:2e:56:ec: + 97:89:3c:ef:16:55:80:5a:18:7c:22:d0:f6:bb:e3:a4:e8:59: + 30:ff:99:5a:93:3e:ea:bc:ee:7f:8d:d6:7d:37:8c:ac:3d:74: + 80:ce:7a:99:ba:27:b9:2a:a3:71:fa:a5:25:ba:47:17:df:07: + 56:96:36:fd:60:b9:6c:96:06:e8:e3:7b:9f:4b:6a:95:71:a8: + 34:fc:fc:b5:88:8b:c4:3f:1e:24:f6:52:47:b2:7d:44:67:d9: + 83:e8 + +Next, we generate a self-signed X.509 certificate for the recipient. +Note that ``privkey.pem`` will be recreated:: + + openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out recipient.pem + + Using configuration from /usr/local/pkg/openssl/openssl.cnf + Generating a 1024 bit RSA private key + .....................................++++++ + .................++++++ + writing new private key to 'privkey.pem' + ----- + You are about to be asked to enter information that will be incorporated + into your certificate request. + What you are about to enter is what is called a Distinguished Name or a DN. + There are quite a few fields but you can leave some blank + For some fields there will be a default value, + If you enter '.', the field will be left blank. + ----- + Country Name (2 letter code) [AU]:SG + State or Province Name (full name) [Some-State]:. + Locality Name (eg, city) []:. + Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto + Organizational Unit Name (eg, section) []:. + Common Name (eg, YOUR name) []:S/MIME Recipient + Email Address []:recipient@example.dom + +Again, rename ``privkey.pem``:: + + mv privkey.pem recipient_key.pem + + +In the examples to follow, S/MIME Sender, ````, +shall be the sender of S/MIME messages, while S/MIME Recipient, +````, shall be the recipient of S/MIME messages. + +Armed with the key pairs and certificates, we are now ready to begin +programming S/MIME in Python. + + **Note:** The private keys generated above are *not + passphrase-protected*, i.e., they are *in the clear*. Anyone who has + access to such a key can generate S/MIME-signed messages with it, + and decrypt S/MIME messages encrypted to it's corresponding public + key. + + We may passphrase-protect the keys, if we so choose. M2Crypto will + prompt the user for the passphrase when such a key is being loaded. + +M2Crypto.SMIME +============== + +The Python programmer accesses M2Crypto's S/MIME functionality through +class ``SMIME`` in the module ``M2Crypto.SMIME``. Typically, an +``SMIME`` object is instantiated; the object is then set up for the +intended operation: sign, encrypt, decrypt or verify; finally, the +operation is invoked on the object. + +``M2Crypto.SMIME`` makes extensive use of ``M2Crypto.BIO``: +``M2Crypto.BIO`` is a Python abstraction of the ``BIO`` abstraction in +OpenSSL. A commonly used ``BIO`` abstraction in M2Crypto is +``M2Crypto.BIO.MemoryBuffer``, which implements a memory-based file-like +object, similar to Python's own ``StringIO``. + +Sign +==== + +The following code demonstrates how to generate an S/MIME-signed +message. ``randpool.dat`` contains random data which is used to seed +OpenSSL's pseudo-random number generator via M2Crypto:: + + from M2Crypto import BIO, Rand, SMIME + + def makebuf(text): + return BIO.MemoryBuffer(text) + + # Make a MemoryBuffer of the message. + buf = makebuf('a sign of our times') + + # Seed the PRNG. + Rand.load_file('randpool.dat', -1) + + # Instantiate an SMIME object; set it up; sign the buffer. + s = SMIME.SMIME() + s.load_key('signer_key.pem', 'signer.pem') + p7 = s.sign(buf, SMIME.PKCS7_DETACHED) + + +``p7`` now contains a *PKCS #7 signature blob* wrapped in an +``M2Crypto.SMIME.PKCS7`` object. Note that ``buf`` has been consumed by +``sign()`` and has to be recreated if it is to be used again. + +We may now send the signed message via SMTP. In these examples, we shall +not do so; instead, we'll render the S/MIME output in mail-friendly +format, and pretend that our messages are sent and received +correctly:: + + # Recreate buf. + buf = makebuf('a sign of our times') + + # Output p7 in mail-friendly format. + out = BIO.MemoryBuffer() + out.write('From: sender@example.dom\n') + out.write('To: recipient@example.dom\n') + out.write('Subject: M2Crypto S/MIME testing\n') + s.write(out, p7, buf) + + print(out.read()) + + # Save the PRNG's state. + Rand.save_file('randpool.dat') + +Here's the output:: + + From: sender@example.dom + To: recipient@example.dom + Subject: M2Crypto S/MIME testing + MIME-Version: 1.0 + Content-Type: multipart/signed ; protocol="application/x-pkcs7-signature" ; micalg=sha1 ; boundary="----3C93156FC7B4EBF49FE9C7DB7F503087" + + This is an S/MIME signed message + + ------3C93156FC7B4EBF49FE9C7DB7F503087 + a sign of our times + ------3C93156FC7B4EBF49FE9C7DB7F503087 + Content-Type: application/x-pkcs7-signature; name="smime.p7s" + Content-Transfer-Encoding: base64 + Content-Disposition: attachment; filename="smime.p7s" + + MIIE8AYJKoZIhvcNAQcCoIIE4TCCBN0CAQExCzAJBgUrDgMCGgUAMCIGCSqGSIb3 + DQEHAaAVBBNhIHNpZ24gb2Ygb3VyIHRpbWVzoIIC5zCCAuMwggJMoAMCAQICAQAw + DQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv + MRYwFAYDVQQDEw1TL01JTUUgU2VuZGVyMSEwHwYJKoZIhvcNAQkBFhJzZW5kZXJA + ZXhhbXBsZS5kb20wHhcNMDEwMzMxMTE0MDMzWhcNMDIwMzMxMTE0MDMzWjBbMQsw + CQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBT + ZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTCBnzANBgkq + hkiG9w0BAQEFAAOBjQAwgYkCgYEA5c5Tj1CHTSOxa1q2q0FYiwMWYHptJpJcvtZm + UwrgU5sHrA8OnCM0cDXEj0KPf3cfNjHffB8HWMzI4UEgNmFXQNsxoGZ+iqwxLlNj + y9Mh7eFW/Bjq5hNXbouSlQ0rWBRkoxV64y+t6lQehb32WfYXQbKFxFJSXzSxOx3R + 8YhSPd0CAwEAAaOBtjCBszAdBgNVHQ4EFgQUXOyolL1t4jaBwZFRM7MS8nBLzUow + gYMGA1UdIwR8MHqAFFzsqJS9beI2gcGRUTOzEvJwS81KoV+kXTBbMQswCQYDVQQG + EwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIx + ITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbYIBADAMBgNVHRMEBTAD + AQH/MA0GCSqGSIb3DQEBBAUAA4GBAHo3DrCHR86fSTVAvfiXdSswWqKtCEhUHRdC + TLFGl4hDk2GyZxaFuqZwiURz/H7nMicymI2wkz8H/wyHFg8G3BIehURpj2v/ZWXY + eovbgS7EZALVVkDj4hNl/IIHWd6Gtv1UODf7URbxtl3hQ9/eTWITrefT1heuPnar + 8czydsOLMYIBujCCAbYCAQEwYDBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJD + cnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNl + bmRlckBleGFtcGxlLmRvbQIBADAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzEL + BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAxMDMzMTExNDUwMlowIwYJKoZI + hvcNAQkEMRYEFOoeRUd8ExIYXfQq8BTFuKWrSP3iMFIGCSqGSIb3DQEJDzFFMEMw + CgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO + AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIGAQpU8hFUtLCF6hO2t + ec9EYJ/Imqqiiw+BxWxkUUVT81Vbjwdn9JST6+sztM5JRP2ZW+b4txEjZriYC8f3 + kv95YMTGbIsuWkJ93GrbvqoJ/CxO23r9WWRnZEm/1EZN9ZmlrYqzBTxnNRmP3Dhj + cW8kzZwH+2/2zz2G7x1HxRWH95A= + + ------3C93156FC7B4EBF49FE9C7DB7F503087-- + + +Verify +====== + +Assume the above output has been saved into ``sign.p7``. Let's now +verify the signature:: + + from M2Crypto import SMIME, X509 + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load the signer's cert. + x509 = X509.load_cert('signer.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + # Load the signer's CA cert. In this case, because the signer's + # cert is self-signed, it is the signer's cert itself. + st = X509.X509_Store() + st.load_info('signer.pem') + s.set_x509_store(st) + + # Load the data, verify it. + p7, data = SMIME.smime_load_pkcs7('sign.p7') + v = s.verify(p7, data) + print(v) + print(data) + print(data.read()) + +Here's the output of the above program:: + + a sign of our times + + a sign of our times + +Suppose, instead of loading ``signer.pem`` above, we load +``recipient.pem``. That is, we do a global substitution of +``recipient.pem`` for ``signer.pem`` in the above program. Here's the +modified program's output:: + + Traceback (most recent call last): + File "./verify.py", line 22, in ? + v = s.verify(p7) + File "/usr/local/home/ngps/prog/m2/M2Crypto/SMIME.py", line 205, in verify + raise SMIME_Error, Err.get_error() + M2Crypto.SMIME.SMIME_Error: 312:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:213:Verify error:self signed certificate + + +As displayed, the error is generated by line 213 of OpenSSL's +``pk7_smime.c`` (as of OpenSSL 0.9.6); if you are a C programmer, you +may wish to look up the C source to explore OpenSSL's S/MIME +implementation and understand why the error message is worded thus. + +Encrypt +======= + +We now demonstrate how to generate an S/MIME-encrypted message:: + + from M2Crypto import BIO, Rand, SMIME, X509 + + def makebuf(text): + return BIO.MemoryBuffer(text) + + # Make a MemoryBuffer of the message. + buf = makebuf('a sign of our times') + + # Seed the PRNG. + Rand.load_file('randpool.dat', -1) + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load target cert to encrypt to. + x509 = X509.load_cert('recipient.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + # Set cipher: 3-key triple-DES in CBC mode. + s.set_cipher(SMIME.Cipher('des_ede3_cbc')) + + # Encrypt the buffer. + p7 = s.encrypt(buf) + + # Output p7 in mail-friendly format. + out = BIO.MemoryBuffer() + out.write('From: sender@example.dom\n') + out.write('To: recipient@example.dom\n') + out.write('Subject: M2Crypto S/MIME testing\n') + s.write(out, p7) + + print(out.read()) + + # Save the PRNG's state. + Rand.save_file('randpool.dat') + +Here's the output of the above program:: + + From: sender@example.dom + To: recipient@example.dom + Subject: M2Crypto S/MIME testing + MIME-Version: 1.0 + Content-Disposition: attachment; filename="smime.p7m" + Content-Type: application/x-pkcs7-mime; name="smime.p7m" + Content-Transfer-Encoding: base64 + + MIIBVwYJKoZIhvcNAQcDoIIBSDCCAUQCAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE + BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp + ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ + KoZIhvcNAQEBBQAEgYCBaXZ+qjpBEZwdP7gjfzfAtQitESyMwo3i+LBOw6sSDir6 + FlNDPCnkrTvqDX3Rt6X6vBtTCYOm+qiN7ujPkOU61cN7h8dvHR8YW9+0IPY80/W0 + lZ/HihSRgwTNd7LnxUUcPx8YV1id0dlmP0Hz+Lg+mHf6rqaR//JcYhX9vW4XvjA7 + BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECMN+qya6ADywgBgHr9Jkhwn5Gsdu7BwX + nIQfYTYcdL9I5Sk= + + +Decrypt +======= + +Assume the above output has been saved into ``encrypt.p7``. Decrypt the +message thusly:: + + from M2Crypto import BIO, SMIME, X509 + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load private key and cert. + s.load_key('recipient_key.pem', 'recipient.pem') + + # Load the encrypted data. + p7, data = SMIME.smime_load_pkcs7('encrypt.p7') + + # Decrypt p7. + out = s.decrypt(p7) + + print(out) + +Here's the output:: + + a sign of our times + + +Sign and Encrypt +================ + +Here's how to generate an S/MIME-signed/encrypted message:: + + from M2Crypto import BIO, Rand, SMIME, X509 + + def makebuf(text): + return BIO.MemoryBuffer(text) + + # Make a MemoryBuffer of the message. + buf = makebuf('a sign of our times') + + # Seed the PRNG. + Rand.load_file('randpool.dat', -1) + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load signer's key and cert. Sign the buffer. + s.load_key('signer_key.pem', 'signer.pem') + p7 = s.sign(buf) + + # Load target cert to encrypt the signed message to. + x509 = X509.load_cert('recipient.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + # Set cipher: 3-key triple-DES in CBC mode. + s.set_cipher(SMIME.Cipher('des_ede3_cbc')) + + # Create a temporary buffer. + tmp = BIO.MemoryBuffer() + + # Write the signed message into the temporary buffer. + s.write(tmp, p7) + + # Encrypt the temporary buffer. + p7 = s.encrypt(tmp) + + # Output p7 in mail-friendly format. + out = BIO.MemoryBuffer() + out.write('From: sender@example.dom\n') + out.write('To: recipient@example.dom\n') + out.write('Subject: M2Crypto S/MIME testing\n') + s.write(out, p7) + + print(out.read()) + + # Save the PRNG's state. + Rand.save_file('randpool.dat') + +Here's the output of the above program:: + + From: sender@example.dom + To: recipient@example.dom + Subject: M2Crypto S/MIME testing + MIME-Version: 1.0 + Content-Disposition: attachment; filename="smime.p7m" + Content-Type: application/x-pkcs7-mime; name="smime.p7m" + Content-Transfer-Encoding: base64 + + MIIIwwYJKoZIhvcNAQcDoIIItDCCCLACAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE + BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp + ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ + KoZIhvcNAQEBBQAEgYBlZlGupFphwhsGtIAPvDExN61qisz3oem88xoXkUW0SzoR + B9zJFFAuQTWzdNJgrKKYikhWjDojaAc/PFl1K5dYxRgtZLB36ULJD/v/yWmxnjz8 + TvtK+Wbal2P/MH2pZ4LVERXa/snTElhCawUlwtiFz/JvY5CiF/dcwd+AwFQq4jCC + B6UGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIRF525UfwszaAggeA85RmX6AXQMxb + eBDz/LJeCgc3RqU1UwIsbKMquIs1S46Ebbm5nP75izPnujOkJ2hv+LNzqOWADmOl + +CnGEq1qxTyduIgUDA2nBgCL/gVyVy+/XC9dtImUUTxtxLgYtB0ujkBNsOaENOlM + fv4SGM3jkR+K/xlYG6HHzZGbfYyNGj2Y7yMZ1rL1m8SnRNmkCysKGTrudeNf6wT9 + J6wO9DzLTioz3ZnVr3LjsSKIb4tIp4ugqNJaLuW7m3FtZ3MAgxN68hBbJs8TZ8tL + V/0jwUqS+grcgZEb9ymfcedxahtDUfHjRkpDpsxZzVVGkSBNcbQu92oByQVnRQ8m + wrYLp3/eawM5AvuV7HNpTT5ZR+1t8luishHN9899IMP2Vyg0Ub67FqFypYmM2cm2 + sjAI4KpfvT00XFNvgLuYwYEKs9syGTO7hiHNQKcF44F5LYv6nTFwmFQB11dAtY9V + ull4D2CLDx9OvyNyKwdEZB5dyV0r/uKIdkhST60V2Q9KegpzgFpoZtSKM/HPYSVH + 1Bc9f3Q/GqZCvNZZCMx8UvRjQR8dRWDSmPJ0VXG1+wJ+fCmSPP3AuQ1/VsgPRqx2 + 56VrpGPpGut40hV8xQFbWIZ2whwWLKPFAHj8B79ZtFUzUrU6Z2rNpvv8inHc/+S/ + b6GR5s8/gucRblvd7n3OFNX5UJmPmcw9zWbu/1Dr9DY8l0nAQh21y5FGSS8B1wdE + oD2M3Lp7JbwjQbRtnDhImqul2S4yu+m+wDD1aR2K4k3GAI7KKgOBWT0+BDClcn8A + 4Ju6/YUbj33YlMPJgnGijLnolFy0hNW7TmWqR+8tSI3wO5eNKg4qwBnarqc3vgCV + quVxINAXyGQCO9lzdw6hudk8/+BlweGdqhONaIWbK5z1L/SfQo6LC9MTsj7FJydq + bc+kEbfZS8aSq7uc9axW6Ti0eAPJ8EVHtwhSBgZQRweKFBXs6HbbhMIdc4N0M7Oq + UiFXaF6s4n2uihVP6TqXtHEjTpZoC7pC+HCYiuKXUJtaqtXBOh+y3KLvHk09YL6D + XmTDg+UTiFsh4jKKm/BhdelbR5JbpJcj5AId76Mfr8+F/1g9ePOvsWHpQr/oIQTo + xEkaxCmzEgP0b6caMWfMUQrbVGxBBNcqKc/ir9fGGOPHATzzq/xLcQYvK1tZhd/D + ah/gpMPndsyvVCEuFPluWyDiM0VkwHgC2/3pJIYFHaxK64IutmPsy393rHMEB4kN + AHau6kWK+yL9qEVH1pP2zvswQ12P7gjt3T/G3bGsmvlXkEfztfjkXo6XnjcBNf5y + G+974AKLcjnk1gzIgarz+lAMY57Gkw4oNDMrTqVQ2OJQlvOSbllPXzH+aAiavB8W + ZPECLLwHxD4B1AuaiAArgKl935u/TOB+yQOR8JgGsUzROyJqHJ/SC51HkebgCkL1 + aggtjgPlIBEXLZAlhpWLZ9lAQyrQpvCVJYwaOvfMmvRav4NAFNoZ2/Q7S4Tn1z+U + XX+f+GD58P4MPMhU5IKnz4yH4nlHnAiTEvcs85TZUAXze9g/uBOwZITeGtyLi52S + aETIr4v7SgXMepX7ThQ1Pv/jddsK/u4j2F34u0XktwCP+UrbfkE2mocdXvdzxbmd + tZSznK2qwgVSsPOs9MhUaepbnjmNBFFBrULhrUtSglM/VX/rWNiyh0aw4XYyHhIt + 9ZNlfEjKjJ67VEMBxBJ/ieUCouRGCxPYD1j65VT7oB3ZiyPu2F2nlUIcYNqPg1Sd + QBCrdaOXdJ0uLwyTAUeVE+wMbgscLvWsfZcCCJHAvw9NHFMUcnrdWxAYMVETNUOn + uryVAK7VfOldaz6z3NOSOi6nonNeHpR/sipBa4ik5xCRLT9e0S2QJgRvO9GyfAqz + 3DIzHtxIGePFzTiUYUTxS3i2gnMX2PEe3ChTLlYWD3jNeAKz0iOzpDphIF2xHLLQ + 1tCAqBmq/vUzALyDFFdFuTIqQZys4z/u4Dmyq9uXs421eN3v2hkVHvDy8uT2Ot29 + lg4Q5YezR1EjaW//9guL1BXbcKrTEdtxeNqtem7SpZOMTSwD2lhB8z65GrX90Cyt + EMmaRSGYEdf5h1afL1SmKOMskbqxe1D2jG/vsXC7XX7xO/ioy0BdiJcYN1JiMOHJ + EOzFol5I20YkiV6j+cenfQFwc/NkaSxEkR8AUHJSbvUmRQRl6r0nnsFpZdR1w7pv + wkaT+eOpZynO4mY/ZtF6MpXJsixi6L4ZYXEbS6yHf+XGFfB0okILylmwv2bf6+Mq + nqXlmGj3Jwq7X9/+2BDqvfpFFX5lSmItKZAobLdssjFR6roJxOqRsGia2aZ+0+U5 + VhgdITtnElgtHBaeZU5rHDswgdeLVBP+rGWnKxpJ+pLtNNi25sPYRcWFL6Erd25u + eXiY8GEIr+u7rqBWpc9HR34sAPRs3ubbCUleT748keCbx247ImBtiDctZxcc1O86 + +0QjHP6HUT7FSo/FmT7a120S3Gd2jixGh06l/9ij5Z6mJa7Rm7TTbSjup/XISnOT + MKWcbI1nfVOhCv3xDq2eLae+s0oVoc041ceRazqFM2TL/Z6UXRME + + +Decrypt and Verify +================== + +Suppose the above output has been saved into ``se.p7``. The following +demonstrates how to decrypt and verify it:: + + from M2Crypto import BIO, SMIME, X509 + + # Instantiate an SMIME object. + s = SMIME.SMIME() + + # Load private key and cert. + s.load_key('recipient_key.pem', 'recipient.pem') + + # Load the signed/encrypted data. + p7, data = SMIME.smime_load_pkcs7('se.p7') + + # After the above step, 'data' == None. + # Decrypt p7. 'out' now contains a PKCS #7 signed blob. + out = s.decrypt(p7) + + # Load the signer's cert. + x509 = X509.load_cert('signer.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + # Load the signer's CA cert. In this case, because the signer's + # cert is self-signed, it is the signer's cert itself. + st = X509.X509_Store() + st.load_info('signer.pem') + s.set_x509_store(st) + + # Recall 'out' contains a PKCS #7 blob. + # Transform 'out'; verify the resulting PKCS #7 blob. + p7_bio = BIO.MemoryBuffer(out) + p7, data = SMIME.smime_load_pkcs7_bio(p7_bio) + v = s.verify(p7) + + print(v) + + +The output is as follows:: + + a sign of our times + + +Sending S/MIME messages via SMTP +================================ + +In the above examples, we've assumed that our S/MIME messages are sent +and received automagically. The following is a Python function that +generates S/MIME-signed/encrypted messages and sends them via +SMTP:: + + from M2Crypto import BIO, SMIME, X509 + import smtplib, string, sys + + def sendsmime(from_addr, to_addrs, subject, msg, from_key, from_cert=None, to_certs=None, smtpd='localhost'): + + msg_bio = BIO.MemoryBuffer(msg) + sign = from_key + encrypt = to_certs + + s = SMIME.SMIME() + if sign: + s.load_key(from_key, from_cert) + if encrypt: + p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT) + else: + p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT|SMIME.PKCS7_DETACHED) + msg_bio = BIO.MemoryBuffer(msg) # Recreate coz sign() has consumed it. + + if encrypt: + sk = X509.X509_Stack() + for x in to_certs: + sk.push(X509.load_cert(x)) + s.set_x509_stack(sk) + s.set_cipher(SMIME.Cipher('des_ede3_cbc')) + tmp_bio = BIO.MemoryBuffer() + if sign: + s.write(tmp_bio, p7) + else: + tmp_bio.write(msg) + p7 = s.encrypt(tmp_bio) + + out = BIO.MemoryBuffer() + out.write('From: %s\r\n' % from_addr) + out.write('To: %s\r\n' % string.join(to_addrs, ", ")) + out.write('Subject: %s\r\n' % subject) + if encrypt: + s.write(out, p7) + else: + if sign: + s.write(out, p7, msg_bio, SMIME.PKCS7_TEXT) + else: + out.write('\r\n') + out.write(msg) + out.close() + + smtp = smtplib.SMTP() + smtp.connect(smtpd) + smtp.sendmail(from_addr, to_addrs, out.read()) + smtp.quit() + + +This function sends plain, S/MIME-signed, S/MIME-encrypted, and +S/MIME-signed/encrypted messages, depending on the parameters +``from_key`` and ``to_certs``. The function's output interoperates with +Netscape Messenger. + +Verifying origin of S/MIME messages +=================================== + +In our examples above that decrypt or verify messages, we skipped a +step: verifying that the ``from`` address of the message matches the +``email address`` attribute in the sender's certificate. + +The premise of current X.509 certification practice is that the CA is +supposed to verify your identity, and to issue a certificate with +``email address`` that matches your actual mail address. (Verisign's +March 2001 failure in identity verification resulting in Microsoft +certificates being issued to spoofers notwithstanding.) + +If you run your own CA, your certification practice is up to you, of +course, and it would probably be part of your security policy. + +Whether your S/MIME messaging application needs to verify the ``from`` +addresses of S/MIME messages depends on your security policy and your +system's threat model, as always. + +Interoperating with Netscape Messenger +====================================== + +Suppose S/MIME Recipient uses Netscape Messenger. To enable Messenger to +handle S/MIME messages from S/MIME Sender, S/MIME Recipient needs to +configure Messenger with his private key and certificate, as well as +S/MIME Sender's certificate. + + **Note:** Configuring Messenger's POP or IMAP settings so that it + retrieves mail correctly is beyond the scope of this HOWTO. + +The following steps demonstrate how to import S/MIME Recipient's private +key and certificate for Messenger: + +1. Transform S/MIME Recipient's private key and certificate into *PKCS + #12* format:: + + openssl pkcs12 -export -in recipient.pem -inkey recipient_key.pem \ + -name "S/MIME Recipient" -out recipient.p12 + + Enter Export Password: + Verifying password - Enter Export Password: + +2. Start Messenger. + +3. Click on the (open) "lock" icon at the bottom left corner of + Messenger's window. This brings up the "Security Info" dialog box. + +4. Click on "Yours" under "Certificates". + +5. Select "Import a certificate", then pick ``recipient.p12`` from the + ensuing file selection dialog box. + +Next, you need to import ``signer.pem`` as a CA certificate, so that +Messenger will mark messages signed by S/MIME Sender as "trusted": + +1. Create a DER encoding of ``signer.pem``:: + + openssl x509 -inform pem -outform der -in signer.pem -out signer.der + +2. Install ``signer.der`` into Messenger as MIME type + ``application/x-x509-ca-cert``. You do this by downloading + ``signer.der`` via Navigator from a HTTP or HTTPS server, with the + correct MIME type mapping. (You may use ``demo/ssl/https_srv.py``, + bundled with M2Crypto, for this purpose.) Follow the series of dialog + boxes to accept ``signer.der`` as a CA for certifying email users. + +S/MIME Recipient is now able to decrypt and read S/MIME Sender's +messages with Messenger. Messenger will indicate that S/MIME Sender's +messages are signed, encrypted, or encrypted *and* signed, as the case +may be, via the "stamp" icon on the message window's top right corner. + +Clicking on the "stamp" icon brings you to the Security Info dialog box. +Messenger informs you that the message is, say, encrypted with 168-bit +DES-EDE3-CBC and that it is digitally signed by the private key +corresponding to the public key contained in the certificate +``signer.pem``. + +Interoperating with Microsoft Outlook +===================================== + +I do not know how to do this, as I do not use Outlook. (Nor do I use +Netscape Messenger, actually. I use Mutt, top dog of MUAs. ;-) +Information on how to configure Outlook with keys and certificates so +that it handles S/MIME mail is gratefully accepted. + +ZSmime +====== + +ZSmime is a `Zope `__ *product* that enables Zope +to generate S/MIME-signed/encrypted messages. ZSmime demonstrates how to +invoke M2Crypto in a web application server extension. + +ZSmime has its own +`HOWTO `__ +explaining its usage. (That HOWTO has some overlap in content with this +document.) + +Resources +========= + +- IETF S/MIME Working Group - http://www.imc.org/ietf-smime + +- S/MIME and OpenPGP - http://www.imc.org/smime-pgpmime.html + +- S/MIME Freeware Library - + http://www.getronicsgov.com/hot/sfl_home.htm + +- Mozilla Network Security Services - + http://www.mozilla.org/projects/security/pkg/nss + +- S/MIME Cracking Screen Saver - http://www.counterpane.com/smime.html diff --git a/doc/html/_sources/howto.ssl.rst.txt b/doc/html/_sources/howto.ssl.rst.txt new file mode 100644 index 0000000..7f3278c --- /dev/null +++ b/doc/html/_sources/howto.ssl.rst.txt @@ -0,0 +1,131 @@ +:orphan: + +.. _howto-ssl: + +HOWTO: Programming SSL in Python with M2Crypto +============================================== + +:author: Pheng Siong Ng and Heikki Toivonen (heikki@osafoundation.org) +:copyright: © 2000, 2001 by Ng Pheng Siong, + portions © 2006 by Open Source Applications Foundation + +Introduction +============ + +`M2Crypto `__ is a +`Python `__ interface to +`OpenSSL `__. It makes available to the Python +programmer SSL functionality to implement clients and servers, S/MIME +v2, RSA, DSA, DH, symmetric ciphers, message digests and HMACs. + +This document demonstrates programming HTTPS with M2Crypto. + +A bit of history +================ + +M2Crypto was created during the time of Python 1.5, which features a +module httplib providing client-side HTTP functionality. M2Crypto sports +a httpslib based on httplib. + +Beginning with version 2.0, Python's socket module provided +(rudimentary) SSL support. Also in the same version, httplib was +enhanced with class HTTPConnection, which is more sophisticated than the +old class HTTP, and HTTPSConnection, which does HTTPS. + +Subsequently, M2Crypto.httpslib grew a compatible (but not identical) +class HTTPSConnection. + +The primary interface difference between the two HTTPSConnection classes +is that M2Crypto's version accepts an M2Crypto.SSL.Context instance as a +parameter, whereas Python 2.x's SSL support does not permit Pythonic +control of the SSL context. + +Within the implementations, Python's ``HTTPSConnection`` employs a +``FakeSocket`` object, which collects all input from the SSL connection +before returning it to the application as a ``StringIO`` buffer, whereas +M2Crypto's ``HTTPSConnection`` uses a buffering +``M2Crypto.BIO.IOBuffer`` object that works over the underlying +M2Crypto.SSL.Connection directly. + +Since then M2Crypto has gained a Twisted wrapper that allows securing +Twisted SSL connections with M2Crypto. + +Secure SSL +========== + +It is recommended that you read the book Network Security with OpenSSL +by John Viega, Matt Messier and Pravir Chandra, ISBN 059600270X. + +Using M2Crypto does not automatically make an SSL connection secure. +There are various steps that need to be made before we can make that +claim. Let's see how a simple client can establish a secure +connection:: + + ctx = SSL.Context() + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9) + if ctx.load_verify_locations('ca.pem') != 1: raise Exception('No CA certs') + s = SSL.Connection(ctx) + s.connect(server_address) + # Normal protocol (for example HTTP) commands follow + +The first line creates an SSL context. The defaults allow any SSL +version (except SSL version 2 which has known weaknesses) and sets the +allowed ciphers to secure ones. + +The second line tells M2Crypto to perform certificate validation. The +flags shown above are typical for clients, and requires the server to +send a certificate. The depth parameter tells how long certificate +chains are allowed - 9 is pretty common default, although probably too +long in practice. + +The third line loads the allowed root (certificate authority or CA) +certificates. Most Linux distributions come with CA certificates in +suitable format. You could also download the +`certdata.txt `__ +file from the +`NSS `__ project and +convert it with the little M2Crypto utility script +`demo/x509/certdata2pem.py `__. + +The fourth line creates an SSL connection object with the secure +context. + +The fifth line connects to the server. During this time we perform the +last security step: just after connection, but before exchanging any +data, we compare the commonName (or subjectAltName DNS field) field in +the certificate the server returned to the server address we tried to +connect to. This happens automatically with SSL.Connection and the +Twisted wrapper class, and anything that uses those. In all other cases +you must do the check manually. It is recommended you call the +SSL.Checker to do the actual check. + +SSL servers are different in that they typically do not require the +client to send a certificate, so there is usually no certificate +checking. Also, it is typically useless to perform host name checking. + +Code Samples +============ + +The best samples of how to use the various SSL objects are in the tests +directory, and the test\_ssl.py file specifically. There are additional +samples in the demo directory, but they are not quaranteed to be up to +date. + +NOTE: The tests and demos may not be secure as is. Use the information +above on how to make them secure. + +ssldump +======= + +ssldump "is an SSLv3/TLS network protocol analyser. It identifies TCP +connections on the chosen network interface and attempts to interpret +them as SSLv3/TLS traffic. When it identifies SSLv3/TLS traffic, it +decodes the records and displays them in a textual form to stdout. If +provided with the appropriate keying material, it will also decrypt the +connections and display the application data traffic. + +If linked with OpenSSL, ssldump can display certificates in decoded form +and decrypt traffic (provided that it has the appropriate keying +material)." + +ssldump is written by Eric Rescorla. diff --git a/doc/html/_sources/index.rst.txt b/doc/html/_sources/index.rst.txt new file mode 100644 index 0000000..a472668 --- /dev/null +++ b/doc/html/_sources/index.rst.txt @@ -0,0 +1,30 @@ +Welcome to M2Crypto's documentation! +==================================== + +Contents: + +.. toctree:: + :maxdepth: 4 + + M2Crypto + + +HOWTOs +====== + +* :ref:`howto-ca` + +* :ref:`howto-ssl` + +* :ref:`howto-smime` + +* :ref:`zserverssl-howto` + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/html/_static/ajax-loader.gif b/doc/html/_static/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..61faf8cab23993bd3e1560bff0668bd628642330 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>Rd%XaNQW zW@Cw{|b%Y*pl8F?4B9 zlo4Fz*0kZGJabY|>}Okf0}CCg{u4`zEPY^pV?j2@h+|igy0+Kz6p;@SpM4s6)XEMg z#3Y4GX>Hjlml5ftdH$4x0JGdn8~MX(U~_^d!Hi)=HU{V%g+mi8#UGbE-*ao8f#h+S z2a0-5+vc7MU$e-NhmBjLIC1v|)9+Im8x1yacJ7{^tLX(ZhYi^rpmXm0`@ku9b53aN zEXH@Y3JaztblgpxbJt{AtE1ad1Ca>{v$rwwvK(>{m~Gf_=-Ro7Fk{#;i~+{{>QtvI yb2P8Zac~?~=sRA>$6{!(^3;ZP0TPFR(G_-UDU(8Jl0?(IXu$~#4A!880|o%~Al1tN literal 0 HcmV?d00001 diff --git a/doc/html/_static/alabaster.css b/doc/html/_static/alabaster.css new file mode 100644 index 0000000..0eddaeb --- /dev/null +++ b/doc/html/_static/alabaster.css @@ -0,0 +1,701 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/doc/html/_static/basic.css b/doc/html/_static/basic.css new file mode 100644 index 0000000..0807176 --- /dev/null +++ b/doc/html/_static/basic.css @@ -0,0 +1,676 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist td { + vertical-align: top; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/doc/html/_static/comment-bright.png b/doc/html/_static/comment-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..15e27edb12ac25701ac0ac21b97b52bb4e45415e GIT binary patch literal 756 zcmVgfIX78 z$8Pzv({A~p%??+>KickCb#0FM1rYN=mBmQ&Nwp<#JXUhU;{|)}%&s>suq6lXw*~s{ zvHx}3C%<;wE5CH!BR{p5@ml9ws}y)=QN-kL2?#`S5d*6j zk`h<}j1>tD$b?4D^N9w}-k)bxXxFg>+#kme^xx#qg6FI-%iv2U{0h(Y)cs%5a|m%Pn_K3X_bDJ>EH#(Fb73Z zfUt2Q3B>N+ot3qb*DqbTZpFIn4a!#_R-}{?-~Hs=xSS6p&$sZ-k1zDdtqU`Y@`#qL z&zv-~)Q#JCU(dI)Hf;$CEnK=6CK50}q7~wdbI->?E07bJ0R;!GSQTs5Am`#;*WHjvHRvY?&$Lm-vq1a_BzocI^ULXV!lbMd%|^B#fY;XX)n<&R^L z=84u1e_3ziq;Hz-*k5~zwY3*oDKt0;bM@M@@89;@m*4RFgvvM_4;5LB!@OB@^WbVT zjl{t;a8_>od-~P4 m{5|DvB&z#xT;*OnJqG}gk~_7HcNkCr0000W zanA~u9RIXo;n7c96&U)YLgs-FGlx~*_c{Jgvesu1E5(8YEf&5wF=YFPcRe@1=MJmi zag(L*xc2r0(slpcN!vC5CUju;vHJkHc*&70_n2OZsK%O~A=!+YIw z7zLLl7~Z+~RgWOQ=MI6$#0pvpu$Q43 zP@36QAmu6!_9NPM?o<1_!+stoVRRZbW9#SPe!n;#A_6m8f}|xN1;H{`0RoXQ2LM47 zt(g;iZ6|pCb@h2xk&(}S3=EVBUO0e90m2Lp5CB<(SPIaB;n4))3JB87Or#XPOPcum z?<^(g+m9}VNn4Y&B`g8h{t_$+RB1%HKRY6fjtd-<7&EsU;vs0GM(Lmbhi%Gwcfs0FTF}T zL{_M6Go&E0Eg8FuB*(Yn+Z*RVTBE@10eIOb3El^MhO`GabDll(V0&FlJi2k^;q8af zkENdk2}x2)_KVp`5OAwXZM;dG0?M-S)xE1IKDi6BY@5%Or?#aZ9$gcX)dPZ&wA1a< z$rFXHPn|TBf`e?>Are8sKtKrKcjF$i^lp!zkL?C|y^vlHr1HXeVJd;1I~g&Ob-q)& z(fn7s-KI}G{wnKzg_U5G(V%bX6uk zIa+<@>rdmZYd!9Y=C0cuchrbIjuRB_Wq{-RXlic?flu1*_ux}x%(HDH&nT`k^xCeC ziHi1!ChH*sQ6|UqJpTTzX$aw8e(UfcS^f;6yBWd+(1-70zU(rtxtqR%j z-lsH|CKQJXqD{+F7V0OTv8@{~(wp(`oIP^ZykMWgR>&|RsklFMCnOo&Bd{le} zV5F6424Qzl;o2G%oVvmHgRDP9!=rK8fy^!yV8y*4p=??uIRrrr0?>O!(z*g5AvL2!4z0{sq%vhG*Po}`a<6%kTK5TNhtC8}rXNu&h^QH4A&Sk~Autm*s~45(H7+0bi^MraaRVzr05hQ3iK?j` zR#U@^i0WhkIHTg29u~|ypU?sXCQEQgXfObPW;+0YAF;|5XyaMAEM0sQ@4-xCZe=0e z7r$ofiAxn@O5#RodD8rh5D@nKQ;?lcf@tg4o+Wp44aMl~c47azN_(im0N)7OqdPBC zGw;353_o$DqGRDhuhU$Eaj!@m000000NkvXXu0mjfjZ7Z_ literal 0 HcmV?d00001 diff --git a/doc/html/_static/custom.css b/doc/html/_static/custom.css new file mode 100644 index 0000000..2a924f1 --- /dev/null +++ b/doc/html/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/doc/html/_static/doctools.js b/doc/html/_static/doctools.js new file mode 100644 index 0000000..344db17 --- /dev/null +++ b/doc/html/_static/doctools.js @@ -0,0 +1,315 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/doc/html/_static/documentation_options.js b/doc/html/_static/documentation_options.js new file mode 100644 index 0000000..d28647e --- /dev/null +++ b/doc/html/_static/documentation_options.js @@ -0,0 +1,10 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, +}; \ No newline at end of file diff --git a/doc/html/_static/down-pressed.png b/doc/html/_static/down-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..5756c8cad8854722893dc70b9eb4bb0400343a39 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`OFdm2Ln;`PZ^+1>KjR?B@S0W7 z%OS_REiHONoJ6{+Ks@6k3590|7k9F+ddB6!zw3#&!aw#S`x}3V3&=A(a#84O-&F7T z^k3tZB;&iR9siw0|F|E|DAL<8r-F4!1H-;1{e*~yAKZN5f0|Ei6yUmR#Is)EM(Po_ zi`qJR6|P<~+)N+kSDgL7AjdIC_!O7Q?eGb+L+qOjm{~LLinM4NHn7U%HcK%uoMYO5 VJ~8zD2B3o(JYD@<);T3K0RV0%P>BEl literal 0 HcmV?d00001 diff --git a/doc/html/_static/down.png b/doc/html/_static/down.png new file mode 100644 index 0000000000000000000000000000000000000000..1b3bdad2ceffae91cee61b32f3295f9bbe646e48 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6CVIL!hEy=F?b*7pIY7kW{q%Rg zx!yQ<9v8bmJwa`TQk7YSw}WVQ()mRdQ;TC;* literal 0 HcmV?d00001 diff --git a/doc/html/_static/file.png b/doc/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/doc/html/_static/jquery-3.2.1.js b/doc/html/_static/jquery-3.2.1.js new file mode 100644 index 0000000..d2d8ca4 --- /dev/null +++ b/doc/html/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
    " ], + col: [ 2, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + + +

    Index

    + +
    + A + | B + | C + | D + | E + | F + | G + | H + | I + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | X + +
    +

    A

    + + + +
    + +

    B

    + + + +
    + +

    C

    + + + +
    + +

    D

    + + + +
    + +

    E

    + + + +
    + +

    F

    + + + +
    + +

    G

    + + + +
    + +

    H

    + + + +
    + +

    I

    + + + +
    + +

    K

    + + +
    + +

    L

    + + + +
    + +

    M

    + + + +
    + +

    N

    + + + +
    + +

    O

    + + + +
    + +

    P

    + + + +
    + +

    Q

    + + +
    + +

    R

    + + + +
    + +

    S

    + + + +
    + +

    T

    + + + +
    + +

    U

    + + + +
    + +

    V

    + + + +
    + +

    W

    + + + +
    + +

    X

    + + + +
    + + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/howto.ca.html b/doc/html/howto.ca.html new file mode 100644 index 0000000..7f5bd21 --- /dev/null +++ b/doc/html/howto.ca.html @@ -0,0 +1,478 @@ + + + + + + + + HOWTO: Creating your own CA with OpenSSL — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    HOWTO: Creating your own CA with OpenSSL¶

    + +++ + + + + + +
    author:Pheng Siong Ng <ngps@post1.com>
    copyright:© 2000, 2001 by Ng Pheng Siong.
    +
    +

    Introduction¶

    +

    This is a HOWTO on creating your own certification authority (CA) +with OpenSSL.

    +

    I last created a CA about a year ago, when I began work on +M2Crypto and needed +certificates for the SSL bits. I accepted the tools’ default +settings then, e.g., certificate validity of 365 days; this meant +that my certificates, including my CA’s certificate, have now +expired.

    +

    Since I am using these certificates for M2Crypto’s demonstration +programs (and I have forgotten the passphrase to the CA’s private +key), I decided to discard the old CA and start afresh. I also +decided to document the process, hence this HOWTO.

    +
    +
    +

    The Procedure¶

    +

    I use CA.pl, a Perl program written by Steve Hanson and bundled with +OpenSSL.

    +

    The following are the steps to create a CA:

    +
      +
    1. Choose a directory to do your CA work. All commands are executed +within this directory. Let’s call the directory demo.

      +
    2. +
    3. Copy CA.pl and openssl.cnf into demo.

      +
    4. +
    5. Apply the following patch to CA.pl, which allows it to generate a +CA certificate with a validity period of 1095 days, i.e., +3 years:

      +
      --- CA.pl.org   Sat Mar 31 12:40:13 2001
      ++++ CA.pl       Sat Mar 31 12:41:15 2001
      +@@ -97,7 +97,7 @@
      +                } else {
      +                    print "Making CA certificate ...\n";
      +                    system ("$REQ -new -x509 -keyout " .
      +-                       "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT $DAYS");
      ++                       "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT -days 1095");
      +                    $RET=$?;
      +                }
      +            }
      +
      +
      +
    6. +
    7. Create a new CA like this:

      +
      ./CA.pl -newca
      +
      +A certificate filename (or enter to create) <enter>
      +
      +Making CA certificate ...
      +Using configuration from openssl.cnf
      +Generating a 1024 bit RSA private key
      +............++++++
      +......................++++++
      +writing new private key to './demoCA/private/cakey.pem'
      +Enter PEM pass phrase: <secret passphrase here>
      +Verifying password - Enter PEM pass phrase: <secret passphrase again>
      +-----
      +You are about to be asked to enter information that will be incorporated
      +into your certificate request.
      +What you are about to enter is what is called a Distinguished Name or a DN.
      +There are quite a few fields but you can leave some blank
      +For some fields there will be a default value,
      +If you enter '.', the field will be left blank.
      +-----
      +Country Name (2 letter code) [AU]:SG
      +State or Province Name (full name) [Some-State]:.
      +Locality Name (eg, city) []:..
      +Organization Name (eg, company) [Internet Widgits Pty Ltd]:DemoCA
      +Organizational Unit Name (eg, section) []:.
      +Common Name (eg, YOUR name) []:DemoCA Certificate Master
      +Email Address []:certmaster@democa.dom
      +
      +
      +

      This creates a new CA in the directory demoCA. The CA’s +self-signed certificate is in demoCA/cacert.pem and its RSA key +pair is in demoCA/private/cakey.pem.

      +

      demoCA/private/cakey.pem looks like this:

      +
      cat demoCA/private/cakey.pem
      +
      +-----BEGIN RSA PRIVATE KEY-----
      +Proc-Type: 4,ENCRYPTED
      +DEK-Info: DES-EDE3-CBC,19973A9DBBB601BA
      +
      +eOq9WFScNiI4/UWEUaSnGTKpJv2JYuMD3HwQox2Q3Cd4zGqVjJ6gF3exa5126cKf
      +X/bMVnwbPpuFZPiAIvaLyCjT6pYeXTBbSzs7/GQnvEOv+nYnDUFWi0Qm92qLk0uy
      +pFi/M1aWheN3vir2ZlAw+DW0bOOZhj8tC7Co7lMYb0YE271b6/YRPZCwQ3GXAHUJ
      ++aMYxlUDrK45aCUa/1CZDzTgk7h9cDgx2QJSIvYMYytCfI3zsuZMJS8/4OXLL0bI
      +lKmAc1dwB3DqGJt5XK4WJesiNfdxeCNEgAcYtEAgYZTPIApU+kTgTCIxJl2nMW7j
      +ax+Q1z7g+4MpgG20WD633D4z4dTlDdz+dnLi0rvuvxiwt+dUhrqiML1tyi+Z6EBH
      +jU4/cLBWev3rYfrlp4x8J9mDte0YKOk3t0wQOHqRetTsIfdtjnFp/Hu3qDmTCWjD
      +z/g7PPoO/bg/B877J9WBPbL/1hXXFYo88M+2aGlPOgDcFdiOqbLb2DCscohMbbVr
      +A4mgiy2kwWfIE73qiyV7yyG8FlRvr1iib+jbT3LTGf743utYAAs7HNGuOUObhoyt
      +jYvBD7ACn35P5YX7KTqvqErwdijxYCaNBCnvmRtmYSaNw9Kv1UJTxc5Vx7YLwIPk
      +E9KyBgKI7vPOjWBZ27+zOvNycmv1ciNtpALAw4bWtXnhCDVTHaVDy34OkheMzNCg
      +2cjcBFzOkMIjcI03KbTQXOFIQGlsTWXGzkNf/zBQ+KksT1MCj+zBXSCvlDASMckg
      +kef21pGgUqPF14gKGfWX3sV4bjc1vbrRwq6zlG3nMuYqR5MtJJY9eQ==
      +-----END RSA PRIVATE KEY-----
      +
      +
      +
    8. +
    9. Next, generate a certificate request:

      +
      ./CA.pl -newreq
      +
      +Using configuration from openssl.cnf
      +Generating a 1024 bit RSA private key
      +..........++++++
      +..............++++++
      +writing new private key to 'newreq.pem'
      +Enter PEM pass phrase: <another secret passphrase here>
      +Verifying password - Enter PEM pass phrase: <another secret passphrase again>
      +-----
      +You are about to be asked to enter information that will be incorporated
      +into your certificate request.
      +What you are about to enter is what is called a Distinguished Name or a DN.
      +There are quite a few fields but you can leave some blank
      +For some fields there will be a default value,
      +If you enter '.', the field will be left blank.
      +-----
      +Country Name (2 letter code) [AU]:SG
      +State or Province Name (full name) [Some-State]:..
      +Locality Name (eg, city) []:.
      +Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto
      +Organizational Unit Name (eg, section) []:.
      +Common Name (eg, YOUR name) []:localhost
      +Email Address []:admin@server.example.dom
      +
      +Please enter the following 'extra' attributes
      +to be sent with your certificate request
      +A challenge password []:<enter>
      +An optional company name []:<enter>
      +Request (and private key) is in newreq.pem
      +
      +
      +
    10. +
    +

    +
    +

    The certificate request and private key in newreq.pem looks like +this:

    +
    cat newreq.pem
    +
    +-----BEGIN RSA PRIVATE KEY-----
    +Proc-Type: 4,ENCRYPTED
    +DEK-Info: DES-EDE3-CBC,41B2874DF3D02DD4
    +
    +mg611EoVkLEooSTv+qTM0Ddmm/M1jE/Jy5RD/sc3LSMhuGu9xc26OgsTJmkQuIAh
    +J/B4lAw8G59VTG6DykeEtrG0rUBx4bggc7PKbFuiN423YjJODWcHvVgnPOzXMQt+
    +lY4tPl5+217MRHyx2NsWGrpkQNdu3GeSPOVMl3jeQiaXupONbwQ7rj42+X/VtAJP
    +W4D1NNwu8aGCPyShsEXHc/fI1WDpphYWke97pOjIZVQESFZOPty5HjIYZux4U+td
    +W81xODtq2ecJXc8fn2Wpa9y5VD1LT7oJksOuL1+Z04OVaeUe4x0swM17HlBm2kVt
    +fe/C/L6kN27MwZhE331VjtTjSGl4/gknqQDbLOtqT06f3OISsDJETm2itllyhgzv
    +C6Fi3N03rGFmKectijC+tws5k+P+HRG6sai33usk8xPokJqA+HYSWPz1XVlpRmv4
    +kdjQOdST7ovU62mOTgf3ARcduPPwuzTfxOlYONe5NioO1APVHBrInQwcpLkpOTQR
    +vI4roIN+b75/nihUWGUJn/nbbBa2Yl0N5Gs1Tyiy9Z+CcRT2TfWKBBFlEUIFl7Mb
    +J9fTV3DI+k+akbR4il1NkQ8EcSmCr3WpA0I9n0EHI7ZVpVaHxc0sqaPFl8YGdFHq
    +1Qk53C/w6+qPpDzT3yKFmG2LZytAAM1czvb6RbNRJJP2ZrpBwn/h99sUTo/yPfxY
    +nueYmFJDm0uVNtG0icXGNUfSfnjKNTtHPAgyKGetRIC3kgJz/bo2w7EI6iEjBAzK
    +l5TRm4x6ZJxwuXXMiJCehMMd8TC8ybwWO4AO19B3ebFFeTVsUgxSGA==
    +-----END RSA PRIVATE KEY-----
    +-----BEGIN CERTIFICATE REQUEST-----
    +MIIBnTCCAQYCAQAwXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIw
    +EAYDVQQDEwlsb2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5l
    +eGFtcGxlLmRvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr1nYY1Qrll1r
    +uB/FqlCRrr5nvupdIN+3wF7q915tvEQoc74bnu6b8IbbGRMhzdzmvQ4SzFfVEAuM
    +MuTHeybPq5th7YDrTNizKKxOBnqE2KYuX9X22A1Kh49soJJFg6kPb9MUgiZBiMlv
    +tb7K3CHfgw5WagWnLl8Lb+ccvKZZl+8CAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GB
    +AHpoRp5YS55CZpy+wdigQEwjL/wSluvo+WjtpvP0YoBMJu4VMKeZi405R7o8oEwi
    +PdlrrliKNknFmHKIaCKTLRcU59ScA6ADEIWUzqmUzP5Cs6jrSRo3NKfg1bd09D1K
    +9rsQkRc9Urv9mRBIsredGnYECNeRaK5R1yzpOowninXC
    +-----END CERTIFICATE REQUEST-----
    +
    +
    +
    +

    +
    +

    Decoding the certificate request gives the following:

    +
    openssl req -text -noout < newreq.pem
    +
    +Using configuration from /usr/local/pkg/openssl/openssl.cnf
    +Certificate Request:
    +   Data:
    +       Version: 0 (0x0)
    +       Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom
    +       Subject Public Key Info:
    +           Public Key Algorithm: rsaEncryption
    +           RSA Public Key: (1024 bit)
    +               Modulus (1024 bit):
    +                   00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50:
    +                   91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e:
    +                   6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13:
    +                   21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4:
    +                   c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac:
    +                   4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f:
    +                   6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9:
    +                   6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f:
    +                   0b:6f:e7:1c:bc:a6:59:97:ef
    +               Exponent: 65537 (0x10001)
    +       Attributes:
    +           a0:00
    +   Signature Algorithm: md5WithRSAEncryption
    +       7a:68:46:9e:58:4b:9e:42:66:9c:be:c1:d8:a0:40:4c:23:2f:
    +       fc:12:96:eb:e8:f9:68:ed:a6:f3:f4:62:80:4c:26:ee:15:30:
    +       a7:99:8b:8d:39:47:ba:3c:a0:4c:22:3d:d9:6b:ae:58:8a:36:
    +       49:c5:98:72:88:68:22:93:2d:17:14:e7:d4:9c:03:a0:03:10:
    +       85:94:ce:a9:94:cc:fe:42:b3:a8:eb:49:1a:37:34:a7:e0:d5:
    +       b7:74:f4:3d:4a:f6:bb:10:91:17:3d:52:bb:fd:99:10:48:b2:
    +       b7:9d:1a:76:04:08:d7:91:68:ae:51:d7:2c:e9:3a:8c:27:8a:
    +       75:c2
    +
    +
    +
    +
      +
    1. Now, sign the certificate request:

      +
      ./CA.pl -sign
      +
      +Using configuration from openssl.cnf
      +Enter PEM pass phrase: <CA's passphrase>
      +Check that the request matches the signature
      +Signature ok
      +The Subjects Distinguished Name is as follows
      +countryName           :PRINTABLE:'SG'
      +organizationName      :PRINTABLE:'M2Crypto'
      +commonName            :PRINTABLE:'localhost'
      +emailAddress          :IA5STRING:'admin@server.example.dom'
      +Certificate is to be certified until Mar 31 02:57:30 2002 GMT (365 days)
      +Sign the certificate? [y/n]:y
      +
      +
      +1 out of 1 certificate requests certified, commit?  [y/n]y
      +Write out database with 1 new entries
      +Data Base Updated
      +Signed certificate is in newcert.pem
      +
      +
      +
    2. +
    +

    +
    +

    newcert.pem looks like this:

    +
    cat newcert.pem
    +
    +Certificate:
    +Data:
    +   Version: 3 (0x2)
    +   Serial Number: 1 (0x1)
    +   Signature Algorithm: md5WithRSAEncryption
    +   Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom
    +   Validity
    +       Not Before: Mar 31 02:57:30 2001 GMT
    +       Not After : Mar 31 02:57:30 2002 GMT
    +   Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom
    +   Subject Public Key Info:
    +       Public Key Algorithm: rsaEncryption
    +       RSA Public Key: (1024 bit)
    +           Modulus (1024 bit):
    +               00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50:
    +               91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e:
    +               6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13:
    +               21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4:
    +               c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac:
    +               4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f:
    +               6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9:
    +               6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f:
    +               0b:6f:e7:1c:bc:a6:59:97:ef
    +           Exponent: 65537 (0x10001)
    +   X509v3 extensions:
    +       X509v3 Basic Constraints:
    +Certificate:
    +Data:
    +   Version: 3 (0x2)
    +   Serial Number: 1 (0x1)
    +   Signature Algorithm: md5WithRSAEncryption
    +   Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom
    +   Validity
    +       Not Before: Mar 31 02:57:30 2001 GMT
    +       Not After : Mar 31 02:57:30 2002 GMT
    +   Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom
    +   Subject Public Key Info:
    +       Public Key Algorithm: rsaEncryption
    +       RSA Public Key: (1024 bit)
    +           Modulus (1024 bit):
    +               00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50:
    +               91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e:
    +               6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13:
    +               21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4:
    +               c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac:
    +               4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f:
    +               6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9:
    +               6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f:
    +               0b:6f:e7:1c:bc:a6:59:97:ef
    +           Exponent: 65537 (0x10001)
    +   X509v3 extensions:
    +       X509v3 Basic Constraints:
    +           CA:FALSE
    +       Netscape Comment:
    +           OpenSSL Generated Certificate
    +       X509v3 Subject Key Identifier:
    +           B3:D6:89:88:2F:B1:15:40:EC:0A:C0:30:35:3A:B7:DA:72:73:1B:4D
    +       X509v3 Authority Key Identifier:
    +           keyid:F9:6A:A6:34:97:6B:BC:BB:5A:17:0D:19:FC:62:21:0B:00:B5:0E:29
    +           DirName:/C=SG/O=DemoCA/CN=DemoCA Certificate Master/Email=certmaster@democa.dom
    +           serial:00
    +
    +Signature Algorithm: md5WithRSAEncryption
    +
    +
    +
    +
      +
    1. In certain situations, e.g., where your certificate and private key +are to be used in an unattended SSL server, you may wish to not +encrypt the private key, i.e., leave the key in the clear. This +decision should be governed by your site’s security policy and threat +model, of course:

      +
      openssl rsa < newkey.pem > newkey2.pem
      +
      +read RSA key
      +Enter PEM pass phrase:<secret passphrase here>
      +writing RSA key
      +
      +
      +

      newkey2.pem looks like this:

      +
      cat newkey2.pem
      +
      +-----BEGIN RSA PRIVATE KEY-----
      +MIICXgIBAAKBgQCvWdhjVCuWXWu4H8WqUJGuvme+6l0g37fAXur3Xm28RChzvhue
      +7pvwhtsZEyHN3Oa9DhLMV9UQC4wy5Md7Js+rm2HtgOtM2LMorE4GeoTYpi5f1fbY
      +DUqHj2ygkkWDqQ9v0xSCJkGIyW+1vsrcId+DDlZqBacuXwtv5xy8plmX7wIDAQAB
      +AoGAbAkU8w3W1Qu15Hle1bJSL7GMReoreqeblOBmMAZz4by0l6sXZXJpjWXo86f/
      ++dASMYTMPC4ZTYtv06N07AFbjL+kDfqDMTfzQkYMHp1LAq1Ihbq1rHWSBH5n3ekq
      +KiY8JKpv8DR5Po1iKaXJFuDByGDENJwYbSRSpSK3P+vkWWECQQDkEUE/ZPqqqZkQ
      +2iWRPAsCbEID8SAraQl3DdCLYs/GgARfmmj4yUHEwkys9Jo1H8k4BdxugmaUwNi5
      +YQ/CVzrXAkEAxNO80ArbGxPUmr11GHG/bGBYj1DUBkHZSc7dgxZdtUCLGNxQnNsg
      +Iwq3n6j1sUzS3UW6abQ8bivYNOUcMKJAqQJBANQxFaLU4b/NQaODQ3aoBZpAfP9L
      +5eFdvbet+7zjt2r5CpikgkwOfAmDuXEltx/8LevY0CllW+nErx9zJgVrwUsCQQCu
      +76H5JiznPBDSF2FjgHWqVVdgyW4owY3mU739LHvNBLicN/RN9VPy0Suy8/CqzKT9
      +lWPBXzf2k3FuUdNkRlFBAkEAmpXoybuiFR2S5Bma/ax96lVs0/VihhfC1zZP/X/F
      +Br77+h9dIul+2DnyOl50zu0Sdzst1/7ay4JSDHyiBCMGSQ==
      +-----END RSA PRIVATE KEY-----
      +
      +
      +
    2. +
    +

    That’s it! The certificate, newcert.pem, and the private key - +newkey.pem (encrypted) or newkey2.pem (unencrypted) - are now +ready to be used. You may wish to rename the files to more intuitive +names.

    +

    You should also keep the CA’s certificate demo/cacert.pem handy +for use when developing and deploying SSL or S/MIME applications.

    +
    +
    +

    Conclusion¶

    +

    We’ve walked through the basic steps in the creation of a CA and +certificates using the tools that come with OpenSSL. We did not cover +more advanced topics such as constraining a certificate to be SSL-only +or S/MIME-only.

    +

    There exist several HOWTOs similar to this one on the net. This one is +written specifically to facilitate discussions in my other HOWTOs on +developing SSL and S/MIME applications in +Python using +M2Crypto.

    +
    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/howto.smime.html b/doc/html/howto.smime.html new file mode 100644 index 0000000..7f77e00 --- /dev/null +++ b/doc/html/howto.smime.html @@ -0,0 +1,849 @@ + + + + + + + + HOWTO: Programming S/MIME in Python with M2Crypto — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    HOWTO: Programming S/MIME in Python with M2Crypto¶

    + +++ + + + + + +
    author:Pheng Siong Ng <ngps@post1.com>
    copyright:© 2000, 2001 by Ng Pheng Siong.
    +
    +
    +

    Introduction¶

    +

    M2Crypto is a +Python interface to +OpenSSL. It makes available to the Python +programmer SSL functionality to implement clients and servers, S/MIME +v2, RSA, DSA, DH, symmetric ciphers, message digests and HMACs.

    +

    This document demonstrates programming S/MIME with M2Crypto.

    +
    +
    +

    S/MIME¶

    +

    S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC +2312] - provides a consistent way to send and receive secure MIME data. +Based on the popular Internet MIME standard, S/MIME provides the +following cryptographic security services for electronic messaging +applications - authentication, message integrity and +non-repudiation of origin (using digital signatures), and privacy +and data security (using encryption).

    +
    +
    +

    Keys and Certificates¶

    +

    To create an S/MIME-signed message, you need an RSA key pair (this +consists of a public key and a private key) and an X.509 certificate of +said public key.

    +

    To create an S/MIME-encrypted message, you need an X.509 certificate for +each recipient.

    +

    To create an S/MIME-signed and -encrypted message, first create a +signed message, then encrypt the signed message with the recipients’ +certificates.

    +

    You may generate key pairs and obtain certificates by using a commercial +certification authority service.

    +

    You can also do so using freely-available software. For many purposes, +e.g., automated S/MIME messaging by system administration processes, +this approach is cheap and effective.

    +

    We now work through using OpenSSL to generate key pairs and +certificates. This assumes you have OpenSSL installed properly on your +system.

    +

    First, we generate an X.509 certificate to be used for signing:

    +
    openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out signer.pem
    +
    +Using configuration from /usr/local/pkg/openssl/openssl.cnf
    +Generating a 1024 bit RSA private key
    +..++++++
    +....................++++++
    +writing new private key to 'privkey.pem'
    +-----
    +You are about to be asked to enter information that will be incorporated
    +into your certificate request.
    +What you are about to enter is what is called a Distinguished Name or a DN.
    +There are quite a few fields but you can leave some blank
    +For some fields there will be a default value,
    +If you enter '.', the field will be left blank.
    +-----
    +Country Name (2 letter code) [AU]:SG
    +State or Province Name (full name) [Some-State]:.
    +Locality Name (eg, city) []:.
    +Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto
    +Organizational Unit Name (eg, section) []:.
    +Common Name (eg, YOUR name) []:S/MIME Sender
    +Email Address []:sender@example.dom
    +
    +
    +

    This generates a 1024-bit RSA key pair, unencrypted, into +privkey.pem; it also generates a self-signed X.509 certificate for +the public key into signer.pem. The certificate is valid for 365 +days, i.e., a year.

    +

    Let’s rename privkey.pem so that we know it is a companion of +signer.pem’s:

    +
    mv privkey.pem signer_key.pem
    +
    +
    +

    To verify the content of signer.pem, execute the following:

    +
    openssl x509 -noout -text -in signer.pem
    +
    +Certificate:
    +    Data:
    +        Version: 3 (0x2)
    +        Serial Number: 0 (0x0)
    +        Signature Algorithm: md5WithRSAEncryption
    +        Issuer: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom
    +        Validity
    +            Not Before: Mar 24 12:56:16 2001 GMT
    +            Not After : Mar 24 12:56:16 2002 GMT
    +        Subject: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom
    +        Subject Public Key Info:
    +            Public Key Algorithm: rsaEncryption
    +            RSA Public Key: (1024 bit)
    +                Modulus (1024 bit):
    +                    00:a9:d6:e2:b5:11:3b:ae:3c:e2:17:31:70:e1:6e:
    +                    01:f4:19:6d:bd:2a:42:36:2b:37:34:e2:83:1d:0d:
    +                    11:2e:b4:99:44:db:10:67:be:97:5f:5b:1a:26:33:
    +                    46:23:2f:95:04:7a:35:da:9d:f9:26:88:39:9e:17:
    +                    cd:3e:eb:a8:19:8d:a8:2a:f1:43:da:55:a9:2e:2c:
    +                    65:ed:04:71:42:ce:73:53:b8:ea:7e:c7:f0:23:c6:
    +                    63:c5:5e:68:96:64:a7:b4:2a:94:26:76:eb:79:ea:
    +                    e3:4e:aa:82:09:4f:44:87:4a:12:62:b5:d7:1f:ca:
    +                    f2:ce:d5:ba:7e:1f:48:fd:b9
    +                Exponent: 65537 (0x10001)
    +        X509v3 extensions:
    +            X509v3 Subject Key Identifier:
    +                29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99
    +            X509v3 Authority Key Identifier:
    +                keyid:29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99
    +                DirName:/C=SG/O=M2Crypto/CN=S/MIME Sender/Email=sender@example.dom
    +                serial:00
    +
    +            X509v3 Basic Constraints:
    +                CA:TRUE
    +    Signature Algorithm: md5WithRSAEncryption
    +        68:c8:6b:1b:fa:7c:9a:39:35:76:18:15:c9:fd:89:97:62:db:
    +        7a:b0:2d:13:dd:97:e8:1b:7a:9f:22:27:83:24:9d:2e:56:ec:
    +        97:89:3c:ef:16:55:80:5a:18:7c:22:d0:f6:bb:e3:a4:e8:59:
    +        30:ff:99:5a:93:3e:ea:bc:ee:7f:8d:d6:7d:37:8c:ac:3d:74:
    +        80:ce:7a:99:ba:27:b9:2a:a3:71:fa:a5:25:ba:47:17:df:07:
    +        56:96:36:fd:60:b9:6c:96:06:e8:e3:7b:9f:4b:6a:95:71:a8:
    +        34:fc:fc:b5:88:8b:c4:3f:1e:24:f6:52:47:b2:7d:44:67:d9:
    +        83:e8
    +
    +
    +

    Next, we generate a self-signed X.509 certificate for the recipient. +Note that privkey.pem will be recreated:

    +
    openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out recipient.pem
    +
    +Using configuration from /usr/local/pkg/openssl/openssl.cnf
    +Generating a 1024 bit RSA private key
    +.....................................++++++
    +.................++++++
    +writing new private key to 'privkey.pem'
    +-----
    +You are about to be asked to enter information that will be incorporated
    +into your certificate request.
    +What you are about to enter is what is called a Distinguished Name or a DN.
    +There are quite a few fields but you can leave some blank
    +For some fields there will be a default value,
    +If you enter '.', the field will be left blank.
    +-----
    +Country Name (2 letter code) [AU]:SG
    +State or Province Name (full name) [Some-State]:.
    +Locality Name (eg, city) []:.
    +Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto
    +Organizational Unit Name (eg, section) []:.
    +Common Name (eg, YOUR name) []:S/MIME Recipient
    +Email Address []:recipient@example.dom
    +
    +
    +

    Again, rename privkey.pem:

    +
    mv privkey.pem recipient_key.pem
    +
    +
    +

    In the examples to follow, S/MIME Sender, <sender@example.dom>, +shall be the sender of S/MIME messages, while S/MIME Recipient, +<recipient@example.dom>, shall be the recipient of S/MIME messages.

    +

    Armed with the key pairs and certificates, we are now ready to begin +programming S/MIME in Python.

    +
    +

    Note: The private keys generated above are not +passphrase-protected, i.e., they are in the clear. Anyone who has +access to such a key can generate S/MIME-signed messages with it, +and decrypt S/MIME messages encrypted to it’s corresponding public +key.

    +

    We may passphrase-protect the keys, if we so choose. M2Crypto will +prompt the user for the passphrase when such a key is being loaded.

    +
    +
    +
    +

    M2Crypto.SMIME¶

    +

    The Python programmer accesses M2Crypto’s S/MIME functionality through +class SMIME in the module M2Crypto.SMIME. Typically, an +SMIME object is instantiated; the object is then set up for the +intended operation: sign, encrypt, decrypt or verify; finally, the +operation is invoked on the object.

    +

    M2Crypto.SMIME makes extensive use of M2Crypto.BIO: +M2Crypto.BIO is a Python abstraction of the BIO abstraction in +OpenSSL. A commonly used BIO abstraction in M2Crypto is +M2Crypto.BIO.MemoryBuffer, which implements a memory-based file-like +object, similar to Python’s own StringIO.

    +
    +
    +

    Sign¶

    +

    The following code demonstrates how to generate an S/MIME-signed +message. randpool.dat contains random data which is used to seed +OpenSSL’s pseudo-random number generator via M2Crypto:

    +
    from M2Crypto import BIO, Rand, SMIME
    +
    +def makebuf(text):
    +    return BIO.MemoryBuffer(text)
    +
    +# Make a MemoryBuffer of the message.
    +buf = makebuf('a sign of our times')
    +
    +# Seed the PRNG.
    +Rand.load_file('randpool.dat', -1)
    +
    +# Instantiate an SMIME object; set it up; sign the buffer.
    +s = SMIME.SMIME()
    +s.load_key('signer_key.pem', 'signer.pem')
    +p7 = s.sign(buf, SMIME.PKCS7_DETACHED)
    +
    +
    +

    p7 now contains a PKCS #7 signature blob wrapped in an +M2Crypto.SMIME.PKCS7 object. Note that buf has been consumed by +sign() and has to be recreated if it is to be used again.

    +

    We may now send the signed message via SMTP. In these examples, we shall +not do so; instead, we’ll render the S/MIME output in mail-friendly +format, and pretend that our messages are sent and received +correctly:

    +
    # Recreate buf.
    +buf = makebuf('a sign of our times')
    +
    +# Output p7 in mail-friendly format.
    +out = BIO.MemoryBuffer()
    +out.write('From: sender@example.dom\n')
    +out.write('To: recipient@example.dom\n')
    +out.write('Subject: M2Crypto S/MIME testing\n')
    +s.write(out, p7, buf)
    +
    +print(out.read())
    +
    +# Save the PRNG's state.
    +Rand.save_file('randpool.dat')
    +
    +
    +

    Here’s the output:

    +
    From: sender@example.dom
    +To: recipient@example.dom
    +Subject: M2Crypto S/MIME testing
    +MIME-Version: 1.0
    +Content-Type: multipart/signed ; protocol="application/x-pkcs7-signature" ; micalg=sha1 ; boundary="----3C93156FC7B4EBF49FE9C7DB7F503087"
    +
    +This is an S/MIME signed message
    +
    +------3C93156FC7B4EBF49FE9C7DB7F503087
    +a sign of our times
    +------3C93156FC7B4EBF49FE9C7DB7F503087
    +Content-Type: application/x-pkcs7-signature; name="smime.p7s"
    +Content-Transfer-Encoding: base64
    +Content-Disposition: attachment; filename="smime.p7s"
    +
    +MIIE8AYJKoZIhvcNAQcCoIIE4TCCBN0CAQExCzAJBgUrDgMCGgUAMCIGCSqGSIb3
    +DQEHAaAVBBNhIHNpZ24gb2Ygb3VyIHRpbWVzoIIC5zCCAuMwggJMoAMCAQICAQAw
    +DQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv
    +MRYwFAYDVQQDEw1TL01JTUUgU2VuZGVyMSEwHwYJKoZIhvcNAQkBFhJzZW5kZXJA
    +ZXhhbXBsZS5kb20wHhcNMDEwMzMxMTE0MDMzWhcNMDIwMzMxMTE0MDMzWjBbMQsw
    +CQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBT
    +ZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTCBnzANBgkq
    +hkiG9w0BAQEFAAOBjQAwgYkCgYEA5c5Tj1CHTSOxa1q2q0FYiwMWYHptJpJcvtZm
    +UwrgU5sHrA8OnCM0cDXEj0KPf3cfNjHffB8HWMzI4UEgNmFXQNsxoGZ+iqwxLlNj
    +y9Mh7eFW/Bjq5hNXbouSlQ0rWBRkoxV64y+t6lQehb32WfYXQbKFxFJSXzSxOx3R
    +8YhSPd0CAwEAAaOBtjCBszAdBgNVHQ4EFgQUXOyolL1t4jaBwZFRM7MS8nBLzUow
    +gYMGA1UdIwR8MHqAFFzsqJS9beI2gcGRUTOzEvJwS81KoV+kXTBbMQswCQYDVQQG
    +EwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIx
    +ITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbYIBADAMBgNVHRMEBTAD
    +AQH/MA0GCSqGSIb3DQEBBAUAA4GBAHo3DrCHR86fSTVAvfiXdSswWqKtCEhUHRdC
    +TLFGl4hDk2GyZxaFuqZwiURz/H7nMicymI2wkz8H/wyHFg8G3BIehURpj2v/ZWXY
    +eovbgS7EZALVVkDj4hNl/IIHWd6Gtv1UODf7URbxtl3hQ9/eTWITrefT1heuPnar
    +8czydsOLMYIBujCCAbYCAQEwYDBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJD
    +cnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNl
    +bmRlckBleGFtcGxlLmRvbQIBADAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzEL
    +BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAxMDMzMTExNDUwMlowIwYJKoZI
    +hvcNAQkEMRYEFOoeRUd8ExIYXfQq8BTFuKWrSP3iMFIGCSqGSIb3DQEJDzFFMEMw
    +CgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO
    +AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIGAQpU8hFUtLCF6hO2t
    +ec9EYJ/Imqqiiw+BxWxkUUVT81Vbjwdn9JST6+sztM5JRP2ZW+b4txEjZriYC8f3
    +kv95YMTGbIsuWkJ93GrbvqoJ/CxO23r9WWRnZEm/1EZN9ZmlrYqzBTxnNRmP3Dhj
    +cW8kzZwH+2/2zz2G7x1HxRWH95A=
    +
    +------3C93156FC7B4EBF49FE9C7DB7F503087--
    +
    +
    +
    +
    +

    Verify¶

    +

    Assume the above output has been saved into sign.p7. Let’s now +verify the signature:

    +
    from M2Crypto import SMIME, X509
    +
    +# Instantiate an SMIME object.
    +s = SMIME.SMIME()
    +
    +# Load the signer's cert.
    +x509 = X509.load_cert('signer.pem')
    +sk = X509.X509_Stack()
    +sk.push(x509)
    +s.set_x509_stack(sk)
    +
    +# Load the signer's CA cert. In this case, because the signer's
    +# cert is self-signed, it is the signer's cert itself.
    +st = X509.X509_Store()
    +st.load_info('signer.pem')
    +s.set_x509_store(st)
    +
    +# Load the data, verify it.
    +p7, data = SMIME.smime_load_pkcs7('sign.p7')
    +v = s.verify(p7, data)
    +print(v)
    +print(data)
    +print(data.read())
    +
    +
    +

    Here’s the output of the above program:

    +
    a sign of our times
    +<M2Crypto.BIO.BIO instance at 0x822012c>
    +a sign of our times
    +
    +
    +

    Suppose, instead of loading signer.pem above, we load +recipient.pem. That is, we do a global substitution of +recipient.pem for signer.pem in the above program. Here’s the +modified program’s output:

    +
    Traceback (most recent call last):
    +  File "./verify.py", line 22, in ?
    +    v = s.verify(p7)
    +  File "/usr/local/home/ngps/prog/m2/M2Crypto/SMIME.py", line 205, in verify
    +    raise SMIME_Error, Err.get_error()
    +M2Crypto.SMIME.SMIME_Error: 312:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:213:Verify error:self signed certificate
    +
    +
    +

    As displayed, the error is generated by line 213 of OpenSSL’s +pk7_smime.c (as of OpenSSL 0.9.6); if you are a C programmer, you +may wish to look up the C source to explore OpenSSL’s S/MIME +implementation and understand why the error message is worded thus.

    +
    +
    +

    Encrypt¶

    +

    We now demonstrate how to generate an S/MIME-encrypted message:

    +
    from M2Crypto import BIO, Rand, SMIME, X509
    +
    +def makebuf(text):
    +    return BIO.MemoryBuffer(text)
    +
    +# Make a MemoryBuffer of the message.
    +buf = makebuf('a sign of our times')
    +
    +# Seed the PRNG.
    +Rand.load_file('randpool.dat', -1)
    +
    +# Instantiate an SMIME object.
    +s = SMIME.SMIME()
    +
    +# Load target cert to encrypt to.
    +x509 = X509.load_cert('recipient.pem')
    +sk = X509.X509_Stack()
    +sk.push(x509)
    +s.set_x509_stack(sk)
    +
    +# Set cipher: 3-key triple-DES in CBC mode.
    +s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
    +
    +# Encrypt the buffer.
    +p7 = s.encrypt(buf)
    +
    +# Output p7 in mail-friendly format.
    +out = BIO.MemoryBuffer()
    +out.write('From: sender@example.dom\n')
    +out.write('To: recipient@example.dom\n')
    +out.write('Subject: M2Crypto S/MIME testing\n')
    +s.write(out, p7)
    +
    +print(out.read())
    +
    +# Save the PRNG's state.
    +Rand.save_file('randpool.dat')
    +
    +
    +

    Here’s the output of the above program:

    +
    From: sender@example.dom
    +To: recipient@example.dom
    +Subject: M2Crypto S/MIME testing
    +MIME-Version: 1.0
    +Content-Disposition: attachment; filename="smime.p7m"
    +Content-Type: application/x-pkcs7-mime; name="smime.p7m"
    +Content-Transfer-Encoding: base64
    +
    +MIIBVwYJKoZIhvcNAQcDoIIBSDCCAUQCAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE
    +BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp
    +ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ
    +KoZIhvcNAQEBBQAEgYCBaXZ+qjpBEZwdP7gjfzfAtQitESyMwo3i+LBOw6sSDir6
    +FlNDPCnkrTvqDX3Rt6X6vBtTCYOm+qiN7ujPkOU61cN7h8dvHR8YW9+0IPY80/W0
    +lZ/HihSRgwTNd7LnxUUcPx8YV1id0dlmP0Hz+Lg+mHf6rqaR//JcYhX9vW4XvjA7
    +BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECMN+qya6ADywgBgHr9Jkhwn5Gsdu7BwX
    +nIQfYTYcdL9I5Sk=
    +
    +
    +
    +
    +

    Decrypt¶

    +

    Assume the above output has been saved into encrypt.p7. Decrypt the +message thusly:

    +
    from M2Crypto import BIO, SMIME, X509
    +
    +# Instantiate an SMIME object.
    +s = SMIME.SMIME()
    +
    +# Load private key and cert.
    +s.load_key('recipient_key.pem', 'recipient.pem')
    +
    +# Load the encrypted data.
    +p7, data = SMIME.smime_load_pkcs7('encrypt.p7')
    +
    +# Decrypt p7.
    +out = s.decrypt(p7)
    +
    +print(out)
    +
    +
    +

    Here’s the output:

    +
    a sign of our times
    +
    +
    +
    +
    +

    Sign and Encrypt¶

    +

    Here’s how to generate an S/MIME-signed/encrypted message:

    +
    from M2Crypto import BIO, Rand, SMIME, X509
    +
    +def makebuf(text):
    +    return BIO.MemoryBuffer(text)
    +
    +# Make a MemoryBuffer of the message.
    +buf = makebuf('a sign of our times')
    +
    +# Seed the PRNG.
    +Rand.load_file('randpool.dat', -1)
    +
    +# Instantiate an SMIME object.
    +s = SMIME.SMIME()
    +
    +# Load signer's key and cert. Sign the buffer.
    +s.load_key('signer_key.pem', 'signer.pem')
    +p7 = s.sign(buf)
    +
    +# Load target cert to encrypt the signed message to.
    +x509 = X509.load_cert('recipient.pem')
    +sk = X509.X509_Stack()
    +sk.push(x509)
    +s.set_x509_stack(sk)
    +
    +# Set cipher: 3-key triple-DES in CBC mode.
    +s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
    +
    +# Create a temporary buffer.
    +tmp = BIO.MemoryBuffer()
    +
    +# Write the signed message into the temporary buffer.
    +s.write(tmp, p7)
    +
    +# Encrypt the temporary buffer.
    +p7 = s.encrypt(tmp)
    +
    +# Output p7 in mail-friendly format.
    +out = BIO.MemoryBuffer()
    +out.write('From: sender@example.dom\n')
    +out.write('To: recipient@example.dom\n')
    +out.write('Subject: M2Crypto S/MIME testing\n')
    +s.write(out, p7)
    +
    +print(out.read())
    +
    +# Save the PRNG's state.
    +Rand.save_file('randpool.dat')
    +
    +
    +

    Here’s the output of the above program:

    +
    From: sender@example.dom
    +To: recipient@example.dom
    +Subject: M2Crypto S/MIME testing
    +MIME-Version: 1.0
    +Content-Disposition: attachment; filename="smime.p7m"
    +Content-Type: application/x-pkcs7-mime; name="smime.p7m"
    +Content-Transfer-Encoding: base64
    +
    +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
    +
    +
    +
    +
    +

    Decrypt and Verify¶

    +

    Suppose the above output has been saved into se.p7. The following +demonstrates how to decrypt and verify it:

    +
    from M2Crypto import BIO, SMIME, X509
    +
    +# Instantiate an SMIME object.
    +s = SMIME.SMIME()
    +
    +# Load private key and cert.
    +s.load_key('recipient_key.pem', 'recipient.pem')
    +
    +# Load the signed/encrypted data.
    +p7, data = SMIME.smime_load_pkcs7('se.p7')
    +
    +# After the above step, 'data' == None.
    +# Decrypt p7. 'out' now contains a PKCS #7 signed blob.
    +out = s.decrypt(p7)
    +
    +# Load the signer's cert.
    +x509 = X509.load_cert('signer.pem')
    +sk = X509.X509_Stack()
    +sk.push(x509)
    +s.set_x509_stack(sk)
    +
    +# Load the signer's CA cert. In this case, because the signer's
    +# cert is self-signed, it is the signer's cert itself.
    +st = X509.X509_Store()
    +st.load_info('signer.pem')
    +s.set_x509_store(st)
    +
    +# Recall 'out' contains a PKCS #7 blob.
    +# Transform 'out'; verify the resulting PKCS #7 blob.
    +p7_bio = BIO.MemoryBuffer(out)
    +p7, data = SMIME.smime_load_pkcs7_bio(p7_bio)
    +v = s.verify(p7)
    +
    +print(v)
    +
    +
    +

    The output is as follows:

    +
    a sign of our times
    +
    +
    +
    +
    +

    Sending S/MIME messages via SMTP¶

    +

    In the above examples, we’ve assumed that our S/MIME messages are sent +and received automagically. The following is a Python function that +generates S/MIME-signed/encrypted messages and sends them via +SMTP:

    +
    from M2Crypto import BIO, SMIME, X509
    +import smtplib, string, sys
    +
    +def sendsmime(from_addr, to_addrs, subject, msg, from_key, from_cert=None, to_certs=None, smtpd='localhost'):
    +
    +    msg_bio = BIO.MemoryBuffer(msg)
    +    sign = from_key
    +    encrypt = to_certs
    +
    +    s = SMIME.SMIME()
    +    if sign:
    +        s.load_key(from_key, from_cert)
    +        if encrypt:
    +            p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT)
    +        else:
    +            p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT|SMIME.PKCS7_DETACHED)
    +        msg_bio = BIO.MemoryBuffer(msg) # Recreate coz sign() has consumed it.
    +
    +    if encrypt:
    +        sk = X509.X509_Stack()
    +        for x in to_certs:
    +            sk.push(X509.load_cert(x))
    +        s.set_x509_stack(sk)
    +        s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
    +        tmp_bio = BIO.MemoryBuffer()
    +        if sign:
    +            s.write(tmp_bio, p7)
    +        else:
    +            tmp_bio.write(msg)
    +        p7 = s.encrypt(tmp_bio)
    +
    +    out = BIO.MemoryBuffer()
    +    out.write('From: %s\r\n' % from_addr)
    +    out.write('To: %s\r\n' % string.join(to_addrs, ", "))
    +    out.write('Subject: %s\r\n' % subject)
    +    if encrypt:
    +        s.write(out, p7)
    +    else:
    +        if sign:
    +            s.write(out, p7, msg_bio, SMIME.PKCS7_TEXT)
    +        else:
    +            out.write('\r\n')
    +            out.write(msg)
    +    out.close()
    +
    +    smtp = smtplib.SMTP()
    +    smtp.connect(smtpd)
    +    smtp.sendmail(from_addr, to_addrs, out.read())
    +    smtp.quit()
    +
    +
    +

    This function sends plain, S/MIME-signed, S/MIME-encrypted, and +S/MIME-signed/encrypted messages, depending on the parameters +from_key and to_certs. The function’s output interoperates with +Netscape Messenger.

    +
    +
    +

    Verifying origin of S/MIME messages¶

    +

    In our examples above that decrypt or verify messages, we skipped a +step: verifying that the from address of the message matches the +email address attribute in the sender’s certificate.

    +

    The premise of current X.509 certification practice is that the CA is +supposed to verify your identity, and to issue a certificate with +email address that matches your actual mail address. (Verisign’s +March 2001 failure in identity verification resulting in Microsoft +certificates being issued to spoofers notwithstanding.)

    +

    If you run your own CA, your certification practice is up to you, of +course, and it would probably be part of your security policy.

    +

    Whether your S/MIME messaging application needs to verify the from +addresses of S/MIME messages depends on your security policy and your +system’s threat model, as always.

    +
    +
    +

    Interoperating with Netscape Messenger¶

    +

    Suppose S/MIME Recipient uses Netscape Messenger. To enable Messenger to +handle S/MIME messages from S/MIME Sender, S/MIME Recipient needs to +configure Messenger with his private key and certificate, as well as +S/MIME Sender’s certificate.

    +
    +
    Note: Configuring Messenger’s POP or IMAP settings so that it +retrieves mail correctly is beyond the scope of this HOWTO.
    +

    The following steps demonstrate how to import S/MIME Recipient’s private +key and certificate for Messenger:

    +
      +
    1. Transform S/MIME Recipient’s private key and certificate into PKCS +#12 format:

      +
      openssl pkcs12 -export -in recipient.pem -inkey recipient_key.pem \
      +    -name "S/MIME Recipient" -out recipient.p12
      +
      +Enter Export Password:<enter>
      +Verifying password - Enter Export Password:<enter>
      +
      +
      +
    2. +
    3. Start Messenger.

      +
    4. +
    5. Click on the (open) “lock” icon at the bottom left corner of +Messenger’s window. This brings up the “Security Info” dialog box.

      +
    6. +
    7. Click on “Yours” under “Certificates”.

      +
    8. +
    9. Select “Import a certificate”, then pick recipient.p12 from the +ensuing file selection dialog box.

      +
    10. +
    +

    Next, you need to import signer.pem as a CA certificate, so that +Messenger will mark messages signed by S/MIME Sender as “trusted”:

    +
      +
    1. Create a DER encoding of signer.pem:

      +
      openssl x509 -inform pem -outform der -in signer.pem -out signer.der
      +
      +
      +
    2. +
    3. Install signer.der into Messenger as MIME type +application/x-x509-ca-cert. You do this by downloading +signer.der via Navigator from a HTTP or HTTPS server, with the +correct MIME type mapping. (You may use demo/ssl/https_srv.py, +bundled with M2Crypto, for this purpose.) Follow the series of dialog +boxes to accept signer.der as a CA for certifying email users.

      +
    4. +
    +

    S/MIME Recipient is now able to decrypt and read S/MIME Sender’s +messages with Messenger. Messenger will indicate that S/MIME Sender’s +messages are signed, encrypted, or encrypted and signed, as the case +may be, via the “stamp” icon on the message window’s top right corner.

    +

    Clicking on the “stamp” icon brings you to the Security Info dialog box. +Messenger informs you that the message is, say, encrypted with 168-bit +DES-EDE3-CBC and that it is digitally signed by the private key +corresponding to the public key contained in the certificate +signer.pem.

    +
    +
    +

    Interoperating with Microsoft Outlook¶

    +

    I do not know how to do this, as I do not use Outlook. (Nor do I use +Netscape Messenger, actually. I use Mutt, top dog of MUAs. ;-) +Information on how to configure Outlook with keys and certificates so +that it handles S/MIME mail is gratefully accepted.

    +
    +
    +

    ZSmime¶

    +

    ZSmime is a Zope product that enables Zope +to generate S/MIME-signed/encrypted messages. ZSmime demonstrates how to +invoke M2Crypto in a web application server extension.

    +

    ZSmime has its own +HOWTO +explaining its usage. (That HOWTO has some overlap in content with this +document.)

    +
    +
    +

    Resources¶

    + +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/howto.ssl.html b/doc/html/howto.ssl.html new file mode 100644 index 0000000..759cb85 --- /dev/null +++ b/doc/html/howto.ssl.html @@ -0,0 +1,219 @@ + + + + + + + + HOWTO: Programming SSL in Python with M2Crypto — M2Crypto documentation + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +
    +

    HOWTO: Programming SSL in Python with M2Crypto¶

    + +++ + + + + + +
    author:Pheng Siong Ng <ngps@netmemetic.com> and Heikki Toivonen (heikki@osafoundation.org)
    copyright:© 2000, 2001 by Ng Pheng Siong, +portions © 2006 by Open Source Applications Foundation
    +
    +
    +

    Introduction¶

    +

    M2Crypto is a +Python interface to +OpenSSL. It makes available to the Python +programmer SSL functionality to implement clients and servers, S/MIME +v2, RSA, DSA, DH, symmetric ciphers, message digests and HMACs.

    +

    This document demonstrates programming HTTPS with M2Crypto.

    +
    +
    +

    A bit of history¶

    +

    M2Crypto was created during the time of Python 1.5, which features a +module httplib providing client-side HTTP functionality. M2Crypto sports +a httpslib based on httplib.

    +

    Beginning with version 2.0, Python’s socket module provided +(rudimentary) SSL support. Also in the same version, httplib was +enhanced with class HTTPConnection, which is more sophisticated than the +old class HTTP, and HTTPSConnection, which does HTTPS.

    +

    Subsequently, M2Crypto.httpslib grew a compatible (but not identical) +class HTTPSConnection.

    +

    The primary interface difference between the two HTTPSConnection classes +is that M2Crypto’s version accepts an M2Crypto.SSL.Context instance as a +parameter, whereas Python 2.x’s SSL support does not permit Pythonic +control of the SSL context.

    +

    Within the implementations, Python’s HTTPSConnection employs a +FakeSocket object, which collects all input from the SSL connection +before returning it to the application as a StringIO buffer, whereas +M2Crypto’s HTTPSConnection uses a buffering +M2Crypto.BIO.IOBuffer object that works over the underlying +M2Crypto.SSL.Connection directly.

    +

    Since then M2Crypto has gained a Twisted wrapper that allows securing +Twisted SSL connections with M2Crypto.

    +
    +
    +

    Secure SSL¶

    +

    It is recommended that you read the book Network Security with OpenSSL +by John Viega, Matt Messier and Pravir Chandra, ISBN 059600270X.

    +

    Using M2Crypto does not automatically make an SSL connection secure. +There are various steps that need to be made before we can make that +claim. Let’s see how a simple client can establish a secure +connection:

    +
    ctx = SSL.Context()
    +ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9)
    +if ctx.load_verify_locations('ca.pem') != 1: raise Exception('No CA certs')
    +s = SSL.Connection(ctx)
    +s.connect(server_address)
    +# Normal protocol (for example HTTP) commands follow
    +
    +
    +

    The first line creates an SSL context. The defaults allow any SSL +version (except SSL version 2 which has known weaknesses) and sets the +allowed ciphers to secure ones.

    +

    The second line tells M2Crypto to perform certificate validation. The +flags shown above are typical for clients, and requires the server to +send a certificate. The depth parameter tells how long certificate +chains are allowed - 9 is pretty common default, although probably too +long in practice.

    +

    The third line loads the allowed root (certificate authority or CA) +certificates. Most Linux distributions come with CA certificates in +suitable format. You could also download the +certdata.txt +file from the +NSS project and +convert it with the little M2Crypto utility script +demo/x509/certdata2pem.py.

    +

    The fourth line creates an SSL connection object with the secure +context.

    +

    The fifth line connects to the server. During this time we perform the +last security step: just after connection, but before exchanging any +data, we compare the commonName (or subjectAltName DNS field) field in +the certificate the server returned to the server address we tried to +connect to. This happens automatically with SSL.Connection and the +Twisted wrapper class, and anything that uses those. In all other cases +you must do the check manually. It is recommended you call the +SSL.Checker to do the actual check.

    +

    SSL servers are different in that they typically do not require the +client to send a certificate, so there is usually no certificate +checking. Also, it is typically useless to perform host name checking.

    +
    +
    +

    Code Samples¶

    +

    The best samples of how to use the various SSL objects are in the tests +directory, and the test_ssl.py file specifically. There are additional +samples in the demo directory, but they are not quaranteed to be up to +date.

    +

    NOTE: The tests and demos may not be secure as is. Use the information +above on how to make them secure.

    +
    +
    +

    ssldump¶

    +

    ssldump “is an SSLv3/TLS network protocol analyser. It identifies TCP +connections on the chosen network interface and attempts to interpret +them as SSLv3/TLS traffic. When it identifies SSLv3/TLS traffic, it +decodes the records and displays them in a textual form to stdout. If +provided with the appropriate keying material, it will also decrypt the +connections and display the application data traffic.

    +

    If linked with OpenSSL, ssldump can display certificates in decoded form +and decrypt traffic (provided that it has the appropriate keying +material).”

    +

    ssldump is written by Eric Rescorla.

    +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/index.html b/doc/html/index.html new file mode 100644 index 0000000..6116ded --- /dev/null +++ b/doc/html/index.html @@ -0,0 +1,177 @@ + + + + + + + + Welcome to M2Crypto’s documentation! — M2Crypto documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/html/objects.inv b/doc/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..89558974ed3f1e1a8a12d8aff13b21e6d020eb69 GIT binary patch literal 4395 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 + + + + + + Python Module Index — M2Crypto documentation + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + + +

    Python Module Index

    + +
    + m +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    + m
    + M2Crypto +
        + M2Crypto.__init__ +
        + M2Crypto.ASN1 +
        + M2Crypto.AuthCookie +
        + M2Crypto.BIO +
        + M2Crypto.BN +
        + M2Crypto.callback +
        + M2Crypto.DH +
        + M2Crypto.DSA +
        + M2Crypto.EC +
        + M2Crypto.Engine +
        + M2Crypto.Err +
        + M2Crypto.EVP +
        + M2Crypto.ftpslib +
        + M2Crypto.httpslib +
        + M2Crypto.m2 +
        + M2Crypto.m2crypto +
        + M2Crypto.m2urllib +
        + M2Crypto.m2urllib2 +
        + M2Crypto.m2xmlrpclib +
        + M2Crypto.Rand +
        + M2Crypto.RC4 +
        + M2Crypto.RSA +
        + M2Crypto.SMIME +
        + M2Crypto.SSL +
        + M2Crypto.SSL.cb +
        + M2Crypto.SSL.Checker +
        + M2Crypto.SSL.Cipher +
        + M2Crypto.SSL.Connection +
        + M2Crypto.SSL.Context +
        + M2Crypto.SSL.Session +
        + M2Crypto.SSL.ssl_dispatcher +
        + M2Crypto.SSL.SSLServer +
        + M2Crypto.SSL.timeout +
        + M2Crypto.SSL.TwistedProtocolWrapper +
        + M2Crypto.threading +
        + M2Crypto.util +
        + M2Crypto.X509 +
    + + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/search.html b/doc/html/search.html new file mode 100644 index 0000000..5e59920 --- /dev/null +++ b/doc/html/search.html @@ -0,0 +1,120 @@ + + + + + + + + Search — M2Crypto documentation + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    + +

    Search

    +
    + +

    + Please activate JavaScript to enable the search + functionality. +

    +
    +

    + From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

    +
    + + + +
    + +
    + +
    + +
    + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/doc/html/searchindex.js b/doc/html/searchindex.js new file mode 100644 index 0000000..d376536 --- /dev/null +++ b/doc/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["M2Crypto","M2Crypto.SSL","ZServerSSL-HOWTO","howto.ca","howto.smime","howto.ssl","index"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.viewcode":1,sphinx:55},filenames:["M2Crypto.rst","M2Crypto.SSL.rst","ZServerSSL-HOWTO.rst","howto.ca.rst","howto.smime.rst","howto.ssl.rst","index.rst"],objects:{"M2Crypto.ASN1":{ASN1_Integer:[0,1,1,""],ASN1_Object:[0,1,1,""],ASN1_String:[0,1,1,""],ASN1_TIME:[0,1,1,""],ASN1_UTCTIME:[0,3,1,""],LocalTimezone:[0,1,1,""]},"M2Crypto.ASN1.ASN1_Integer":{m2_asn1_integer_free:[0,2,1,""]},"M2Crypto.ASN1.ASN1_Object":{m2_asn1_object_free:[0,2,1,""]},"M2Crypto.ASN1.ASN1_String":{as_text:[0,2,1,""],m2_asn1_string_free:[0,2,1,""]},"M2Crypto.ASN1.ASN1_TIME":{get_datetime:[0,2,1,""],m2_asn1_time_free:[0,2,1,""],set_datetime:[0,2,1,""],set_string:[0,2,1,""],set_time:[0,2,1,""]},"M2Crypto.ASN1.LocalTimezone":{dst:[0,2,1,""],tzname:[0,2,1,""],utcoffset:[0,2,1,""]},"M2Crypto.AuthCookie":{AuthCookie:[0,1,1,""],AuthCookieJar:[0,1,1,""],mix:[0,4,1,""],unmix3:[0,4,1,""],unmix:[0,4,1,""]},"M2Crypto.AuthCookie.AuthCookie":{data:[0,2,1,""],expiry:[0,2,1,""],headerValue:[0,2,1,""],isExpired:[0,2,1,""],mac:[0,2,1,""],name:[0,2,1,""],output:[0,2,1,""],value:[0,2,1,""]},"M2Crypto.AuthCookie.AuthCookieJar":{isGoodCookie:[0,2,1,""],isGoodCookieString:[0,2,1,""],makeCookie:[0,2,1,""]},"M2Crypto.BIO":{BIO:[0,1,1,""],BIOError:[0,5,1,""],CipherStream:[0,1,1,""],File:[0,1,1,""],IOBuffer:[0,1,1,""],MemoryBuffer:[0,1,1,""],SSLBio:[0,1,1,""],openfile:[0,4,1,""]},"M2Crypto.BIO.BIO":{bio_ptr:[0,2,1,""],close:[0,2,1,""],fileno:[0,2,1,""],flush:[0,2,1,""],m2_bio_free:[0,2,1,""],read:[0,2,1,""],readable:[0,2,1,""],readline:[0,2,1,""],readlines:[0,2,1,""],reset:[0,2,1,""],seek:[0,2,1,""],should_read:[0,2,1,""],should_retry:[0,2,1,""],should_write:[0,2,1,""],tell:[0,2,1,""],write:[0,2,1,""],write_close:[0,2,1,""],writeable:[0,2,1,""]},"M2Crypto.BIO.CipherStream":{SALT_LEN:[0,3,1,""],close:[0,2,1,""],m2_bio_free:[0,2,1,""],m2_bio_pop:[0,2,1,""],set_cipher:[0,2,1,""],write_close:[0,2,1,""]},"M2Crypto.BIO.File":{close:[0,2,1,""],flush:[0,2,1,""],reset:[0,2,1,""]},"M2Crypto.BIO.IOBuffer":{close:[0,2,1,""],m2_bio_free:[0,2,1,""],m2_bio_pop:[0,2,1,""]},"M2Crypto.BIO.MemoryBuffer":{close:[0,2,1,""],getvalue:[0,2,1,""],read:[0,2,1,""],read_all:[0,2,1,""],write_close:[0,2,1,""]},"M2Crypto.BIO.SSLBio":{do_handshake:[0,2,1,""],set_ssl:[0,2,1,""]},"M2Crypto.BN":{rand:[0,4,1,""],rand_range:[0,4,1,""],randfname:[0,4,1,""]},"M2Crypto.DH":{DH:[0,1,1,""],DHError:[0,5,1,""],gen_params:[0,4,1,""],load_params:[0,4,1,""],load_params_bio:[0,4,1,""],set_params:[0,4,1,""]},"M2Crypto.DH.DH":{check_params:[0,2,1,""],compute_key:[0,2,1,""],gen_key:[0,2,1,""],m2_dh_free:[0,2,1,""],print_params:[0,2,1,""]},"M2Crypto.DSA":{DSA:[0,1,1,""],DSAError:[0,5,1,""],DSA_pub:[0,1,1,""],gen_params:[0,4,1,""],load_key:[0,4,1,""],load_key_bio:[0,4,1,""],load_params:[0,4,1,""],load_params_bio:[0,4,1,""],load_pub_key:[0,4,1,""],load_pub_key_bio:[0,4,1,""],pub_key_from_params:[0,4,1,""],set_params:[0,4,1,""]},"M2Crypto.DSA.DSA":{check_key:[0,2,1,""],gen_key:[0,2,1,""],m2_dsa_free:[0,2,1,""],save_key:[0,2,1,""],save_key_bio:[0,2,1,""],save_params:[0,2,1,""],save_params_bio:[0,2,1,""],save_pub_key:[0,2,1,""],save_pub_key_bio:[0,2,1,""],set_params:[0,2,1,""],sign:[0,2,1,""],sign_asn1:[0,2,1,""],verify:[0,2,1,""],verify_asn1:[0,2,1,""]},"M2Crypto.DSA.DSA_pub":{check_key:[0,2,1,""],save_key:[0,2,1,""],save_key_bio:[0,2,1,""],sign:[0,2,1,""],sign_asn1:[0,2,1,""]},"M2Crypto.EC":{EC:[0,1,1,""],ECError:[0,5,1,""],EC_pub:[0,1,1,""],ec_error:[0,4,1,""],gen_params:[0,4,1,""],get_builtin_curves:[0,4,1,""],load_key:[0,4,1,""],load_key_bio:[0,4,1,""],load_key_string:[0,4,1,""],load_key_string_pubkey:[0,4,1,""],load_pub_key:[0,4,1,""],load_pub_key_bio:[0,4,1,""],pub_key_from_der:[0,4,1,""],pub_key_from_params:[0,4,1,""]},"M2Crypto.EC.EC":{as_pem:[0,2,1,""],check_key:[0,2,1,""],compute_dh_key:[0,2,1,""],gen_key:[0,2,1,""],m2_ec_key_free:[0,2,1,""],pub:[0,2,1,""],save_key:[0,2,1,""],save_key_bio:[0,2,1,""],save_pub_key:[0,2,1,""],save_pub_key_bio:[0,2,1,""],sign_dsa:[0,2,1,""],sign_dsa_asn1:[0,2,1,""],verify_dsa:[0,2,1,""],verify_dsa_asn1:[0,2,1,""]},"M2Crypto.EC.EC_pub":{get_der:[0,2,1,""],get_key:[0,2,1,""],save_key:[0,2,1,""],save_key_bio:[0,2,1,""]},"M2Crypto.EVP":{Cipher:[0,1,1,""],EVPError:[0,5,1,""],HMAC:[0,1,1,""],MessageDigest:[0,1,1,""],PKey:[0,1,1,""],hmac:[0,4,1,""],load_key:[0,4,1,""],load_key_bio:[0,4,1,""],load_key_bio_pubkey:[0,4,1,""],load_key_string:[0,4,1,""],load_key_string_pubkey:[0,4,1,""],pbkdf2:[0,4,1,""]},"M2Crypto.EVP.Cipher":{"final":[0,2,1,""],m2_cipher_ctx_free:[0,2,1,""],set_padding:[0,2,1,""],update:[0,2,1,""]},"M2Crypto.EVP.HMAC":{"final":[0,2,1,""],digest:[0,2,1,""],m2_hmac_ctx_free:[0,2,1,""],reset:[0,2,1,""],update:[0,2,1,""]},"M2Crypto.EVP.MessageDigest":{"final":[0,2,1,""],digest:[0,2,1,""],m2_md_ctx_free:[0,2,1,""],update:[0,2,1,""]},"M2Crypto.EVP.PKey":{"final":[0,2,1,""],as_der:[0,2,1,""],as_pem:[0,2,1,""],assign_rsa:[0,2,1,""],get_modulus:[0,2,1,""],get_rsa:[0,2,1,""],m2_md_ctx_free:[0,2,1,""],m2_pkey_free:[0,2,1,""],reset_context:[0,2,1,""],save_key:[0,2,1,""],save_key_bio:[0,2,1,""],sign_final:[0,2,1,""],sign_init:[0,2,1,""],sign_update:[0,2,1,""],size:[0,2,1,""],update:[0,2,1,""],verify_final:[0,2,1,""],verify_init:[0,2,1,""],verify_update:[0,2,1,""]},"M2Crypto.Engine":{Engine:[0,1,1,""],EngineError:[0,5,1,""],cleanup:[0,4,1,""],load_dynamic:[0,4,1,""],load_dynamic_engine:[0,4,1,""],load_openssl:[0,4,1,""]},"M2Crypto.Engine.Engine":{ctrl_cmd_string:[0,2,1,""],finish:[0,2,1,""],get_id:[0,2,1,""],get_name:[0,2,1,""],init:[0,2,1,""],load_certificate:[0,2,1,""],load_private_key:[0,2,1,""],load_public_key:[0,2,1,""],m2_engine_free:[0,2,1,""],set_default:[0,2,1,""]},"M2Crypto.Err":{M2CryptoError:[0,5,1,""],SSLError:[0,5,1,""],get_error:[0,4,1,""],get_error_code:[0,4,1,""],get_error_func:[0,4,1,""],get_error_lib:[0,4,1,""],get_error_message:[0,4,1,""],get_error_reason:[0,4,1,""],get_x509_verify_error:[0,4,1,""],peek_error_code:[0,4,1,""]},"M2Crypto.RC4":{RC4:[0,1,1,""]},"M2Crypto.RC4.RC4":{"final":[0,2,1,""],rc4_free:[0,2,1,""],set_key:[0,2,1,""],update:[0,2,1,""]},"M2Crypto.RSA":{RSA:[0,1,1,""],RSAError:[0,5,1,""],RSA_pub:[0,1,1,""],gen_key:[0,4,1,""],keygen_callback:[0,4,1,""],load_key:[0,4,1,""],load_key_bio:[0,4,1,""],load_key_string:[0,4,1,""],load_pub_key:[0,4,1,""],load_pub_key_bio:[0,4,1,""],new_pub_key:[0,4,1,""],rsa_error:[0,4,1,""]},"M2Crypto.RSA.RSA":{as_pem:[0,2,1,""],check_key:[0,2,1,""],m2_rsa_free:[0,2,1,""],private_decrypt:[0,2,1,""],private_encrypt:[0,2,1,""],pub:[0,2,1,""],public_decrypt:[0,2,1,""],public_encrypt:[0,2,1,""],save_key:[0,2,1,""],save_key_bio:[0,2,1,""],save_key_der:[0,2,1,""],save_key_der_bio:[0,2,1,""],save_pem:[0,2,1,""],save_pub_key:[0,2,1,""],save_pub_key_bio:[0,2,1,""],sign:[0,2,1,""],sign_rsassa_pss:[0,2,1,""],verify:[0,2,1,""],verify_rsassa_pss:[0,2,1,""]},"M2Crypto.RSA.RSA_pub":{check_key:[0,2,1,""],private_decrypt:[0,2,1,""],private_encrypt:[0,2,1,""],save_key:[0,2,1,""],save_key_bio:[0,2,1,""]},"M2Crypto.Rand":{load_file:[0,4,1,""],rand_add:[0,4,1,""],rand_bytes:[0,4,1,""],rand_file_name:[0,4,1,""],rand_pseudo_bytes:[0,4,1,""],rand_seed:[0,4,1,""],rand_status:[0,4,1,""],save_file:[0,4,1,""]},"M2Crypto.SMIME":{Cipher:[0,1,1,""],PKCS7:[0,1,1,""],PKCS7_Error:[0,5,1,""],SMIME:[0,1,1,""],SMIME_Error:[0,5,1,""],load_pkcs7:[0,4,1,""],load_pkcs7_bio:[0,4,1,""],load_pkcs7_bio_der:[0,4,1,""],load_pkcs7_der:[0,4,1,""],smime_load_pkcs7:[0,4,1,""],smime_load_pkcs7_bio:[0,4,1,""],text_crlf:[0,4,1,""],text_crlf_bio:[0,4,1,""]},"M2Crypto.SMIME.PKCS7":{get0_signers:[0,2,1,""],m2_pkcs7_free:[0,2,1,""],type:[0,2,1,""],write:[0,2,1,""],write_der:[0,2,1,""]},"M2Crypto.SMIME.SMIME":{decrypt:[0,2,1,""],encrypt:[0,2,1,""],load_key:[0,2,1,""],load_key_bio:[0,2,1,""],set_cipher:[0,2,1,""],set_x509_stack:[0,2,1,""],set_x509_store:[0,2,1,""],sign:[0,2,1,""],unset_cipher:[0,2,1,""],unset_key:[0,2,1,""],unset_x509_stack:[0,2,1,""],unset_x509_store:[0,2,1,""],verify:[0,2,1,""],write:[0,2,1,""]},"M2Crypto.SSL":{Checker:[1,0,0,"-"],Cipher:[1,0,0,"-"],Connection:[1,0,0,"-"],Context:[1,0,0,"-"],SSLError:[1,5,1,""],SSLServer:[1,0,0,"-"],SSLTimeoutError:[1,5,1,""],Session:[1,0,0,"-"],TwistedProtocolWrapper:[1,0,0,"-"],cb:[1,0,0,"-"],ssl_dispatcher:[1,0,0,"-"],timeout:[1,0,0,"-"]},"M2Crypto.SSL.Checker":{Checker:[1,1,1,""],NoCertificate:[1,5,1,""],SSLVerificationError:[1,5,1,""],WrongCertificate:[1,5,1,""],WrongHost:[1,5,1,""]},"M2Crypto.SSL.Checker.Checker":{numericIpMatch:[1,3,1,""]},"M2Crypto.SSL.Cipher":{Cipher:[1,1,1,""],Cipher_Stack:[1,1,1,""]},"M2Crypto.SSL.Cipher.Cipher":{name:[1,2,1,""],version:[1,2,1,""]},"M2Crypto.SSL.Connection":{Connection:[1,1,1,""]},"M2Crypto.SSL.Connection.Connection":{accept:[1,2,1,""],accept_ssl:[1,2,1,""],bind:[1,2,1,""],clear:[1,2,1,""],clientPostConnectionCheck:[1,3,1,""],close:[1,2,1,""],connect:[1,2,1,""],connect_ssl:[1,2,1,""],fileno:[1,2,1,""],get_cipher:[1,2,1,""],get_cipher_list:[1,2,1,""],get_ciphers:[1,2,1,""],get_context:[1,2,1,""],get_default_session_timeout:[1,2,1,""],get_peer_cert:[1,2,1,""],get_peer_cert_chain:[1,2,1,""],get_session:[1,2,1,""],get_shutdown:[1,2,1,""],get_socket_read_timeout:[1,2,1,""],get_socket_write_timeout:[1,2,1,""],get_state:[1,2,1,""],get_verify_depth:[1,2,1,""],get_verify_mode:[1,2,1,""],get_verify_result:[1,2,1,""],get_version:[1,2,1,""],getpeername:[1,2,1,""],getsockname:[1,2,1,""],getsockopt:[1,2,1,""],listen:[1,2,1,""],m2_bio_free:[1,2,1,""],m2_bio_noclose:[1,3,1,""],m2_ssl_free:[1,2,1,""],makefile:[1,2,1,""],pending:[1,2,1,""],read:[1,2,1,""],recv:[1,2,1,""],recv_into:[1,2,1,""],renegotiate:[1,2,1,""],send:[1,2,1,""],sendall:[1,2,1,""],serverPostConnectionCheck:[1,2,1,""],set1_host:[1,2,1,""],set_accept_state:[1,2,1,""],set_bio:[1,2,1,""],set_cipher_list:[1,2,1,""],set_client_CA_list_from_context:[1,2,1,""],set_client_CA_list_from_file:[1,2,1,""],set_connect_state:[1,2,1,""],set_post_connection_check_callback:[1,2,1,""],set_session:[1,2,1,""],set_session_id_ctx:[1,2,1,""],set_shutdown:[1,2,1,""],set_socket_read_timeout:[1,2,1,""],set_socket_write_timeout:[1,2,1,""],set_ssl_close_flag:[1,2,1,""],set_tlsext_host_name:[1,2,1,""],setblocking:[1,2,1,""],setsockopt:[1,2,1,""],settimeout:[1,2,1,""],setup_addr:[1,2,1,""],setup_ssl:[1,2,1,""],shutdown:[1,2,1,""],ssl_get_error:[1,2,1,""],verify_ok:[1,2,1,""],write:[1,2,1,""]},"M2Crypto.SSL.Context":{Context:[1,1,1,""],ctxmap:[1,4,1,""],map:[1,4,1,""]},"M2Crypto.SSL.Context.Context":{add_session:[1,2,1,""],close:[1,2,1,""],get_allow_unknown_ca:[1,2,1,""],get_cert_store:[1,2,1,""],get_session_cache_mode:[1,2,1,""],get_session_timeout:[1,2,1,""],get_verify_depth:[1,2,1,""],get_verify_mode:[1,2,1,""],load_cert:[1,2,1,""],load_cert_chain:[1,2,1,""],load_client_CA:[1,2,1,""],load_client_ca:[1,2,1,""],load_verify_info:[1,2,1,""],load_verify_locations:[1,2,1,""],m2_ssl_ctx_free:[1,2,1,""],remove_session:[1,2,1,""],set_allow_unknown_ca:[1,2,1,""],set_cipher_list:[1,2,1,""],set_client_CA_list_from_file:[1,2,1,""],set_default_verify_paths:[1,2,1,""],set_info_callback:[1,2,1,""],set_options:[1,2,1,""],set_session_cache_mode:[1,2,1,""],set_session_id_ctx:[1,2,1,""],set_session_timeout:[1,2,1,""],set_tmp_dh:[1,2,1,""],set_tmp_dh_callback:[1,2,1,""],set_tmp_rsa:[1,2,1,""],set_tmp_rsa_callback:[1,2,1,""],set_verify:[1,2,1,""]},"M2Crypto.SSL.SSLServer":{ForkingSSLServer:[1,1,1,""],SSLServer:[1,1,1,""],ThreadingSSLServer:[1,1,1,""]},"M2Crypto.SSL.SSLServer.SSLServer":{handle_error:[1,2,1,""],handle_request:[1,2,1,""]},"M2Crypto.SSL.Session":{Session:[1,1,1,""],load_session:[1,4,1,""]},"M2Crypto.SSL.Session.Session":{as_der:[1,2,1,""],as_text:[1,2,1,""],get_time:[1,2,1,""],get_timeout:[1,2,1,""],m2_ssl_session_free:[1,2,1,""],set_time:[1,2,1,""],set_timeout:[1,2,1,""],write_bio:[1,2,1,""]},"M2Crypto.SSL.TwistedProtocolWrapper":{TLSProtocolWrapper:[1,1,1,""],connectSSL:[1,4,1,""],connectTCP:[1,4,1,""],listenSSL:[1,4,1,""],listenTCP:[1,4,1,""]},"M2Crypto.SSL.TwistedProtocolWrapper.TLSProtocolWrapper":{clear:[1,2,1,""],connectionLost:[1,2,1,""],connectionMade:[1,2,1,""],dataReceived:[1,2,1,""],loseConnection:[1,2,1,""],startTLS:[1,2,1,""],write:[1,2,1,""],writeSequence:[1,2,1,""]},"M2Crypto.SSL.cb":{ssl_info_callback:[1,4,1,""],ssl_verify_callback:[1,4,1,""],ssl_verify_callback_allow_unknown_ca:[1,4,1,""],ssl_verify_callback_stub:[1,4,1,""]},"M2Crypto.SSL.ssl_dispatcher":{ssl_dispatcher:[1,1,1,""]},"M2Crypto.SSL.ssl_dispatcher.ssl_dispatcher":{connect:[1,2,1,""],create_socket:[1,2,1,""],recv:[1,2,1,""],send:[1,2,1,""]},"M2Crypto.SSL.timeout":{struct_size:[1,4,1,""],struct_to_timeout:[1,4,1,""],timeout:[1,1,1,""]},"M2Crypto.SSL.timeout.timeout":{pack:[1,2,1,""]},"M2Crypto.X509":{CRL:[0,1,1,""],Request:[0,1,1,""],X509:[0,1,1,""],X509Error:[0,5,1,""],X509_Extension:[0,1,1,""],X509_Extension_Stack:[0,1,1,""],X509_Name:[0,1,1,""],X509_Name_Entry:[0,1,1,""],X509_Stack:[0,1,1,""],X509_Store:[0,1,1,""],X509_Store_Context:[0,1,1,""],load_cert:[0,4,1,""],load_cert_bio:[0,4,1,""],load_cert_der_string:[0,4,1,""],load_cert_string:[0,4,1,""],load_crl:[0,4,1,""],load_request:[0,4,1,""],load_request_bio:[0,4,1,""],load_request_der_string:[0,4,1,""],load_request_string:[0,4,1,""],new_extension:[0,4,1,""],new_stack_from_der:[0,4,1,""],x509_store_default_cb:[0,4,1,""]},"M2Crypto.X509.CRL":{as_text:[0,2,1,""],m2_x509_crl_free:[0,2,1,""]},"M2Crypto.X509.Request":{add_extensions:[0,2,1,""],as_der:[0,2,1,""],as_pem:[0,2,1,""],as_text:[0,2,1,""],get_pubkey:[0,2,1,""],get_subject:[0,2,1,""],get_version:[0,2,1,""],m2_x509_req_free:[0,2,1,""],save:[0,2,1,""],save_pem:[0,2,1,""],set_pubkey:[0,2,1,""],set_subject:[0,2,1,""],set_subject_name:[0,2,1,""],set_version:[0,2,1,""],sign:[0,2,1,""],verify:[0,2,1,""]},"M2Crypto.X509.X509":{add_ext:[0,2,1,""],as_der:[0,2,1,""],as_pem:[0,2,1,""],as_text:[0,2,1,""],check_ca:[0,2,1,""],check_purpose:[0,2,1,""],get_ext:[0,2,1,""],get_ext_at:[0,2,1,""],get_ext_count:[0,2,1,""],get_fingerprint:[0,2,1,""],get_issuer:[0,2,1,""],get_not_after:[0,2,1,""],get_not_before:[0,2,1,""],get_pubkey:[0,2,1,""],get_serial_number:[0,2,1,""],get_subject:[0,2,1,""],get_version:[0,2,1,""],m2_x509_free:[0,2,1,""],save:[0,2,1,""],save_pem:[0,2,1,""],set_issuer:[0,2,1,""],set_issuer_name:[0,2,1,""],set_not_after:[0,2,1,""],set_not_before:[0,2,1,""],set_pubkey:[0,2,1,""],set_serial_number:[0,2,1,""],set_subject:[0,2,1,""],set_subject_name:[0,2,1,""],set_version:[0,2,1,""],sign:[0,2,1,""],verify:[0,2,1,""]},"M2Crypto.X509.X509_Extension":{get_critical:[0,2,1,""],get_name:[0,2,1,""],get_value:[0,2,1,""],m2_x509_extension_free:[0,2,1,""],set_critical:[0,2,1,""]},"M2Crypto.X509.X509_Extension_Stack":{m2_sk_x509_extension_free:[0,2,1,""],pop:[0,2,1,""],push:[0,2,1,""]},"M2Crypto.X509.X509_Name":{add_entry_by_txt:[0,2,1,""],as_der:[0,2,1,""],as_hash:[0,2,1,""],as_text:[0,2,1,""],entry_count:[0,2,1,""],get_entries_by_nid:[0,2,1,""],m2_x509_name_free:[0,2,1,""],nid:[0,3,1,""]},"M2Crypto.X509.X509_Name_Entry":{create_by_txt:[0,2,1,""],get_data:[0,2,1,""],get_object:[0,2,1,""],m2_x509_name_entry_free:[0,2,1,""],set_data:[0,2,1,""],set_object:[0,2,1,""]},"M2Crypto.X509.X509_Stack":{as_der:[0,2,1,""],m2_sk_x509_free:[0,2,1,""],pop:[0,2,1,""],push:[0,2,1,""]},"M2Crypto.X509.X509_Store":{add_cert:[0,2,1,""],add_x509:[0,2,1,""],load_info:[0,2,1,""],load_locations:[0,2,1,""],m2_x509_store_free:[0,2,1,""],set_verify_cb:[0,2,1,""]},"M2Crypto.X509.X509_Store_Context":{get1_chain:[0,2,1,""],get_current_cert:[0,2,1,""],get_error:[0,2,1,""],get_error_depth:[0,2,1,""],m2_x509_store_ctx_free:[0,2,1,""]},"M2Crypto.ftpslib":{FTP_TLS:[0,1,1,""]},"M2Crypto.ftpslib.FTP_TLS":{auth_ssl:[0,2,1,""],auth_tls:[0,2,1,""],ntransfercmd:[0,2,1,""],prot_c:[0,2,1,""],prot_p:[0,2,1,""]},"M2Crypto.httpslib":{HTTPSConnection:[0,1,1,""],ProxyHTTPSConnection:[0,1,1,""]},"M2Crypto.httpslib.HTTPSConnection":{close:[0,2,1,""],connect:[0,2,1,""],default_port:[0,3,1,""],get_session:[0,2,1,""],set_session:[0,2,1,""]},"M2Crypto.httpslib.ProxyHTTPSConnection":{connect:[0,2,1,""],endheaders:[0,2,1,""],putheader:[0,2,1,""],putrequest:[0,2,1,""]},"M2Crypto.m2urllib":{open_https:[0,4,1,""]},"M2Crypto.m2urllib2":{HTTPSHandler:[0,1,1,""],build_opener:[0,4,1,""]},"M2Crypto.m2urllib2.HTTPSHandler":{https_open:[0,2,1,""],https_request:[0,2,1,""]},"M2Crypto.m2xmlrpclib":{SSL_Transport:[0,1,1,""]},"M2Crypto.m2xmlrpclib.SSL_Transport":{request:[0,2,1,""],user_agent:[0,3,1,""]},"M2Crypto.threading":{cleanup:[0,4,1,""],init:[0,4,1,""]},"M2Crypto.util":{UtilError:[0,5,1,""],bin_to_hex:[0,4,1,""],genparam_callback:[0,4,1,""],no_passphrase_callback:[0,4,1,""],octx_to_num:[0,4,1,""],passphrase_callback:[0,4,1,""],pkcs5_pad:[0,4,1,""],pkcs7_pad:[0,4,1,""],quiet_genparam_callback:[0,4,1,""]},M2Crypto:{ASN1:[0,0,0,"-"],AuthCookie:[0,0,0,"-"],BIO:[0,0,0,"-"],BN:[0,0,0,"-"],DH:[0,0,0,"-"],DSA:[0,0,0,"-"],EC:[0,0,0,"-"],EVP:[0,0,0,"-"],Engine:[0,0,0,"-"],Err:[0,0,0,"-"],RC4:[0,0,0,"-"],RSA:[0,0,0,"-"],Rand:[0,0,0,"-"],SMIME:[0,0,0,"-"],SSL:[1,0,0,"-"],X509:[0,0,0,"-"],__init__:[0,0,0,"-"],callback:[0,0,0,"-"],ftpslib:[0,0,0,"-"],httpslib:[0,0,0,"-"],m2:[0,0,0,"-"],m2crypto:[0,0,0,"-"],m2urllib2:[0,0,0,"-"],m2urllib:[0,0,0,"-"],m2xmlrpclib:[0,0,0,"-"],threading:[0,0,0,"-"],util:[0,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"4":["py","function","Python function"],"5":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:function","5":"py:exception"},terms:{"059600270x":5,"0ipy80":4,"0jwuq":4,"0qjhp6hut7fso":4,"0x0":[3,4],"0x1":3,"0x10001":[3,4],"0x2":[3,4],"0x822012c":4,"19973a9dbbb601ba":3,"1bc9f3q":4,"1czdztgk7h9cdgx2qjsivymyytcfi3zsuzmjs8":3,"1dr9dy8l0naqh21y5fgss8b1wd":4,"1ezn9zmlryqzbtxnnrmp3dhj":4,"1g9epovswhpqr":4,"1hxxfyo88m":3,"1qk53c":3,"1t8luishhn9899imp2vyg0ub67fqfypymm2cm2":4,"1tcaqbmq":4,"1vsrcid":3,"217mrhyx2nswgrpkqndu3gespovml3jeqiaxuponbwq7rj42":3,"2aglpogdcfdioqblb2dcscohmbbvr":3,"2bconvert":1,"2bdqvfpffx5lsmitkzaobldssjfr6rojxoqrsgia2az":4,"2cjcbfzokmijci03kbtqxofiqglstwxgzknf":3,"2dnyol50zu0sdzst1":3,"2iwrpascbeid8saraql3ddcli":3,"2zz2g7x1hxrwh95a":4,"3c93156fc7b4ebf49fe9c7db7f503087":4,"3dizhtxigepfztiuyutxs3i2gnmx2pee3chtllywd3jneakz0iozpdphif2xhllq":4,"3pjiyfhaxk64iutmpsy393rhmeb4kn":4,"3wf7q915tveqoc74bnu6b8ibbgrmhzdzmvq4szffveaum":3,"41b2874df3d02dd4":3,"4ju6":4,"4mpgg20wd633d4z4dtlddz":3,"4oxll0bi":3,"509v3":2,"56vrpgppgut40hv8xqfbwiz2whwwlkpfahj8b79ztfuzuru6z2rnpvv8inhc":4,"5efdvbet":3,"6l0g37faxur3xm28rchzvhu":3,"76h5jiznpbdsf2fjghwqvvdgyw4owy3mu739lhvnblicn":3,"7ay4jsdhyibcmgsq":3,"7pvwhtszeyhn3oa9dhlmv9uqc4wy5md7j":3,"7zjt2r5cpikgkwofamduxeltx":3,"8caweaaaaama0gcsqgsib3dqebbauaa4gb":3,"8czydsolmyibujccabycaqewydbbmqswcqydvqqgewjtrzerma8ga1uechmittjd":4,"8levy0cllw":3,"8tsi3wo5enkg4qwbnarqc3vgcv":4,"8yhspd0caweaaaobtjcbszadbgnvhq4efgquxoyoll1t4jabwzfrm7ms8nblzuow":4,"974aklcjnk1gzigarz":4,"9gul1bxbckrtedtxenqtem7spzomtswd2lhb8z65grx90cyt":4,"9ij5z6mja7rm7ttbsjup":4,"9rsqkrc9urv9mrbisredgnyecnerak5r1yzpoowninxc":3,"9znlfejkjj67vembxbj":4,"abstract":[0,4],"break":2,"byte":[0,1],"case":[1,4,5],"class":[0,1,4,5],"default":[0,1,2,3,4,5],"export":[1,4],"final":[0,4],"float":0,"function":[0,1,2,4,5],"import":[0,1,2,4],"int":[0,1],"long":[1,5],"new":[0,1,2,3,4],"null":[0,1],"public":[0,3,4],"return":[0,1,4,5],"true":[0,1,4],"while":[0,1,2,4],AND:1,CAs:1,DES:[3,4],DNS:[0,5],Doing:0,For:[0,1,2,3,4],HAS:1,Its:0,NOT:[0,1],Not:[3,4],THE:1,TLS:[0,1,5],That:[3,4],The:[0,1,2,4,5],There:[1,3,4,5],These:[1,2],Use:[0,1,5],Using:[3,4,5],WILL:1,With:2,__del__:1,__init__:[0,2],_alwayssucceedspostconnectioncheck:1,_close_cb:0,_debug:0,_io:0,_mode_:1,_ptr:0,_pyfre:[0,1],_pyfree_x509:0,_timeout_:1,_top:2,a4mgiy2kwwfie73qiyv7yyg8flrvr1iib:3,aaiavb8w:4,abl:4,about:[0,1,3,4],abov:[0,1,2,4,5],absent:1,absolut:0,abstracthttphandl:0,accept:[0,1,2,3,4,5],accept_ssl:1,access:[2,4],accord:[0,1],acl_us:2,acquir:0,action:1,actual:[0,1,4,5],actualhost:1,add:[0,1,2],add_cert:0,add_entry_by_txt:0,add_ext:0,add_extens:0,add_sess:1,add_x509:0,added:[0,1],addhead:2,addinfourl:0,adding:1,addit:[0,1,5],addr:1,address:[1,3,4,5],addressfamili:1,admin:3,administr:4,advanc:3,adversari:0,aes_128_cbc:0,aetir4v7sgxmepx7thq1pv:4,af_inet:1,affect:1,afresh:3,after:[0,1,3,4,5],again:[0,3,4],against:0,agent:2,aggtjgplibexlzalhpwlz9laqyrqpvcvjywaovfmmvrav4nafnoz2:4,ago:3,ahau6kwk:4,ahporp5ys55czpi:3,aka:0,akbr4il1nkq8ecsmcr3wpa0i9n0ehi7zvpvahxc0sqapfl8ygdfhq:3,alert:1,alg:0,algo:0,algorigthm:0,algorithm:[0,3,4],alia:0,aliv:1,all:[0,1,3,5],allow:[0,1,3,5],almost:0,along:0,alreadi:1,also:[0,1,2,3,4,5],alt:2,altern:[1,2],although:5,alwai:[0,4],amyxludrk45acua:3,analys:5,ani:[0,1,5],anoth:[1,3],anyon:4,anyth:5,aogabaku8w3w1qu15hle1bjsl7gmreoreqeblobmmazz4by0l6sxzxjpjwxo86f:3,apach:2,api:[0,1],appear:2,append:0,appli:[0,2,3],applic:[0,1,3,4,5],approach:4,appropri:[0,1,5],aqh:4,arg:0,argument:0,argv:0,arm:4,around:2,as_der:[0,1],as_hash:0,as_pem:0,as_text:[0,1],ask:[0,3,4],asn1:6,asn1_integ:0,asn1_object:0,asn1_str:0,asn1_string_print_ex:0,asn1_tim:0,asn1_utctim:0,asn1int:0,asn1obj:0,asn1str:0,assign:[0,1],assign_rsa:0,associ:[0,1],assum:[1,2,4],asyncio:1,asyncor:[1,2],attach:4,attempt:[0,5],attribut:[0,3,4],auth:0,auth_ssl:0,auth_tl:0,authcooki:6,authcookiejar:0,authent:4,author:[0,2,3,4,5],autom:4,automag:[0,4],automat:[1,5],avail:[1,2,4,5],avoid:2,awai:[0,1],awfqq4jcc:4,awihma0gccqgsib3dqmcageoma0gcsqgsib3dqebaquabigaqpu8hfutlcf6ho2t:4,ax96lvs0:3,b4law8g59vtg6dykeetrg0rubx4bggc7pkbfuin423yjjodwchvvgnpozxmqt:3,b4txejzriyc8f3:4,b6gr5s8:4,b6ugcsqgsib3dqehataubggqhkig9w0dbwqirf525ufwszaaggea85rmx6axqmxb:4,b75:3,b877j9wbpbl:3,b9zjffauqtwzdnjgrkkyikhwjdojaac:4,backlog:1,bad:1,base64:4,base:[0,1,2,3,4,5],basi:1,basic:[3,4],bat:2,bdclcn8a:4,becaus:[0,1,4],been:[0,1,4],befor:[0,1,3,4,5],began:3,begin:[3,4,5],behav:1,behaviour:1,being:[0,1,4],below:2,best:5,better:0,between:5,beyond:4,bgbyj1dubkhzsc7dgxzdtuclgnxqnnsg:3,bgcolor:2,bgkqhkig9w0bbwewfayikozihvcnawcecmn:4,bgkqhkig9w0bbwewhayjkozihvcnaqkfmq8xdtaxmdmzmtexnduwmlowiwyjkozi:4,bhdelbr5jbpjcj5aid76mfr8:4,bhmcu0cxetapbgnvbaotce0yq3j5chrvmrkwfwydvqqdexbtl01jtuugumvjaxbp:4,big:0,bin_to_hex:0,binari:[0,1],bind:1,bind_and_activ:1,bindaddress:1,binstr:1,bio:[1,4,5,6],bio_clos:1,bio_f_buff:0,bio_f_ciph:0,bio_f_ssl:0,bio_fre:1,bio_in:0,bio_noclos:1,bio_ptr:0,bio_push:0,bio_s_mem:0,bio_s_pyfd:0,bioerror:0,bit:[0,1,3,4],bitmask:1,bitwis:0,bjq5hnxbouslq0rwbrkoxv64i:4,blank:[3,4],blklen:0,blob:[0,4],block:1,blwegdqhonaiwbk5z1l:4,bmrlckblegftcgxllmrvbqibadajbgurdgmcgguaoigxmbggcsqgsib3dqejazel:4,bmvnwbppufzpiaivalycjt6pyextbbszs7:3,bo2w7ei6iejbazk:3,bodi:[0,2],book:5,bool:1,border:2,both:[0,1,2],bottom:[0,4],bound:[0,1],boundari:4,box:[2,4],br77:3,bring:4,brows:2,browser:2,browser_id_manag:2,buf:[0,4],buf_len:0,buff:1,buffer:[0,1,4,5],buffer_s:1,buffers:1,buflen:1,bufsiz:1,build_open:0,built:1,builtin:0,bundl:[2,3,4],bxwxkuuvt81vbjwdn9jst6:4,bytearrai:1,c6fi3n03rgfmkectijc:3,cacert:[1,3],cach:1,cadav:2,cafil:1,cakei:3,calcul:0,call:[0,1,3,4,5],callabl:[0,1],callback:[1,6],caller:1,can:[0,1,2,3,4,5],cannot:1,capath:1,captur:0,cat:3,catalog:2,catop:3,cbc:[3,4],ccrt2tfwkbbfleuifl7mb:3,ccvkzzl:3,cenfqfwc:4,cepl:0,cert:[0,1,4,5],certain:[0,1,3],certbio:0,certchainfil:1,certdata2pem:5,certdata:5,certfil:[0,1],certif:[0,1,2,3,5],certifi:[3,4],certmast:3,cgyikozihvcnawcwdgyikozihvcnawicagcama0gccqgsib3dqmcagfamacgbsso:4,chain:[0,1,5],challeng:3,chandra:5,chang:[0,1],channel:[1,2],charact:0,cheap:4,check:[0,1,2,3,5],check_ca:0,check_kei:0,check_param:0,check_purpos:0,checker:[0,5,6],choos:[3,4],chosen:5,chunk:1,cipher:[0,4,5,6],cipher_list:1,cipher_stack:1,cipherstream:0,circular:1,citi:[3,4],claim:5,clbwev3ryfrlp4x8j9mdte0ykok3t0wqohqrettsifdtjnfp:3,clean:[0,1],cleanup:0,clear:[0,1,3,4],click:[2,4],client:[0,1,4,5],client_addr:0,client_address:1,clientpostconnectioncheck:1,close:[0,1,2,4],close_flag:0,close_pyfil:0,clutter:2,cmd:0,cnf:[3,4],cngeq1qxtyduiguda2nbgcl:4,cnlwdg8xfjaubgnvbamtdvmvtulnrsbtzw5kzxixitafbgkqhkig9w0bcqewennl:4,code:[0,1,3,4],coll:2,collect:[2,5],com:[0,2,3,4,5],combin:1,come:[0,3,5],command:[3,5],comment:3,commerci:4,commit:3,common:[3,4,5],commonli:4,commonnam:[0,1,3,5],commun:[0,1],compani:[3,4],companion:4,compar:5,compat:5,compil:[0,1],complet:[0,1],compos:2,composit:0,comput:0,compute_dh_kei:0,compute_kei:0,concaten:1,configur:[3,4],conn:0,connect:[0,2,4,5,6],connect_ssl:1,connectionlost:1,connectionmad:1,connectssl:1,connecttcp:1,consid:1,consist:[0,4],constant:[0,1],constrain:3,constraint:[3,4],consum:4,contain:[0,1,2,4],content:[0,1,4,6],context:[0,5,6],contextfactori:1,continu:1,control:[0,1,5],control_panel:2,conveni:1,convert:[0,5],cooki:0,cookie_str:0,copi:[1,2,3],copyright:[0,1,2,3,4,5],corner:4,correct:[1,4],correctli:4,correspond:4,could:[0,1,5],count:[0,2],counterpan:4,countri:[3,4],countrynam:3,cours:[3,4],cover:3,coz:4,cqydvqqgewjtrzerma8ga1uechmittjdcnlwdg8xfjaubgnvbamtdvmvtulnrsbt:4,cqzkt9:3,crack:4,crash:0,creat:[0,1,2,4,5,6],create_by_txt:0,create_socket:1,creation:[1,3],credit:2,critic:0,crl:0,cryptograph:[0,4],css:2,cstringio:0,ctrl_cmd_string:0,ctx:[0,1,5],ctxmap:1,current:[0,1,4],curv:0,custom:1,cvzrxakeaxno80arbgxpumr11ghg:3,cw8kzzwh:4,cxo23r9wwrnzem:4,d2i_ssl_sess:1,dai:[3,4],dasmytmpc4ztytv06n07afbjl:3,dat:[2,4],data:[0,1,2,3,4,5],data_bio:0,databas:3,datareceiv:1,date:[0,2,5],datetim:0,dav:2,dcwd:4,ddlzqbacuxwtv5xy8plmx7widaqab:3,dec:2,decid:[1,3],decis:3,decod:[1,3,5],decrypt:[0,5],def:4,default_port:0,defin:1,dek:3,delet:0,demo:[2,3,4,5],democa:3,demonstr:[3,4,5],depend:[0,1,2,4],deploi:3,depth:[0,1,5],der:[0,4],der_str:0,deriv:0,des_ede3_cbc:4,describ:[0,1],descript:0,desktop:2,detail:0,determin:0,dev:2,develop:3,dh1024:2,dherror:0,dhpfile:1,dialog:[2,4],did:[1,3],differ:[1,5],diffi:[0,2],digest:[0,4,5],digit:4,directli:[1,5],directori:[1,2,3,5],dirnam:[3,4],disabl:[0,1],discard:3,discuss:3,dispatch:1,displai:[4,5],dispos:1,disposit:4,distinguish:[1,3,4],distribut:[2,5],ditto:0,dnli0rvuvxiwt:3,do_handshak:0,document:[1,2,3,4,5],doe:[0,1,5],doesn:1,dog:4,dom:[3,4],don:0,done:[1,2],dough:0,down:1,download:[2,4,5],dqehaaavbbnhihnpz24gb2ygb3vyihrpbwvzoiic5zccaumwggjmoamcaqicaqaw:4,dqyjkozihvcnaqeebqawwzelmakga1uebhmcu0cxetapbgnvbaotce0yq3j5chrv:4,dsa:[4,5,6],dsa_pub:0,dsaerror:0,dst:0,due:1,duhrqiml1tyi:3,duqhj2ygkkwdqq9v0xscjkgiyw:3,dure:[0,1,5],dw0boozhj8tc7co7lmyb0ye271b6:3,dyman:0,dynam:0,e9kybgki7vpojwbz27:3,e_n:0,each:[0,1,4],east:0,eawm5avuv7hnptt5zr:4,eaydvqqdewlsb2nhbghvc3qxjzalbgkqhkig9w0bcqewggfkbwluqhnlcnzlci5l:3,ebdz:4,ec9eyj:4,ec_error:0,ec_pub:0,ecdh:0,ecdsa:0,ecerror:0,ede3:[3,4],effect:4,egftcgxllmrvbtcbnzanbgkqhkig9w0baqefaaobjqawgykcgyear1nyy1qrll1r:3,either:[0,1],electron:4,els:[0,1,3,4],email:[0,3,4],emailaddress:[0,3],emmarsgyedf5h1afl1smkomskbqxe1d2jg:4,empir:0,emploi:5,enabl:[1,4],encod:[0,1,2,4],encrypt:[0,1,3],end:[0,1,3],endhead:0,endian:0,engin:[1,6],engine_ctrl_cmd_str:0,engine_method_:0,engineerror:0,enhanc:5,enough:0,ensu:4,ensur:[0,1],enter:[0,2,3,4],entri:[0,3],entropi:0,entry_count:0,environ:[0,1],eopzyno4mi:4,eoq9wfscnii4:3,eovbgs7ezalvvkdj4hnl:4,eozfol5i20ykiv6j:4,ephemer:1,epoch:0,epollreactor:1,equival:[0,1],eric:5,err:[4,6],err_get_error:0,errdepth:1,errnum:1,error:[0,1,4],error_log:2,establish:[0,1,5],estim:0,etag:2,etc:[0,1],etwitreft1heupnar:4,even:0,event:0,evp:6,evp_ciph:0,evperror:0,ewjtrzerma8ga1uechmittjdcnlwdg8xfjaubgnvbamtdvmvtulnrsbtzw5kzxix:4,exampl:[0,1,2,3,4,5],except:[0,1,5],exchang:[0,5],execut:[3,4],exist:[2,3],exit:0,exiy8geir:4,exp:0,expect:0,expectedhost:1,expir:[0,1,3],expiri:0,explain:4,explan:1,explicitli:1,explor:4,expon:[0,3,4],ext:0,ext_stack:0,extens:[0,1,3,4],extern:1,extra:3,extract:1,facilit:3,fact:0,factori:[0,1],fail:[0,1],failur:[0,1,4],fakesocket:5,fals:[0,1,3],famili:1,fancyurlopen:2,faq:0,farm:2,fashion:2,fatal:1,fcgiserv:2,fcmspp3auq1:4,featur:5,feed:0,feedback:0,few:[3,4],ffffff:2,fi1wdpphywke97pojizvqesfzopty5hjiyzux4u:3,field:[0,3,4,5],fieldnam:1,fifth:5,file:[0,1,2,3,4,5],filenam:[0,1,3,4],fileno:[0,1],find:1,fingerprint:0,finish:[0,1],first:[0,4,5],fixm:1,flag:[0,1,4,5],flndpcnkrtvqdx3rt6x6vbttcyom:4,flowinfo:1,flush:0,fmt7a120s3gd2jixgh06l:4,follow:[0,2,3,4,5],forgotten:3,forkingmixin:1,forkingsslserv:1,form:[0,1,5],format:[0,1,4,5],format_d:0,format_format_d:0,format_pem:0,found:[0,1],foundat:[1,5],four:1,fourth:5,fqlcrrr5nvupdin:3,freebsd:2,freed:1,freeli:4,freewar:4,friendli:4,frill:0,from:[0,1,2,3,4,5],from_addr:4,from_cert:4,from_kei:4,ftp:[0,2],ftp_tl:0,ftplib:0,ftpserver:2,ftpslib:6,full:[3,4],further:1,fv4sgm3jkr:4,g3bgsmvlxkefztfjkxo6xnjcbnf5i:4,g7ppoo:3,gain:5,gd58p4mpmhu5iknz4yh4nlhnaitevcs85tzuaxze9g:4,gen_kei:0,gen_param:0,gener:[0,1,3,4],genparam_callback:0,get0_sign:0,get1_chain:0,get:[0,1,2],get_allow_unknown_ca:1,get_builtin_curv:0,get_cert_stor:1,get_ciph:1,get_cipher_list:1,get_context:1,get_crit:0,get_current_cert:0,get_data:0,get_datetim:0,get_default_session_timeout:1,get_der:0,get_entries_by_nid:0,get_error:[0,1,4],get_error_cod:0,get_error_depth:0,get_error_func:0,get_error_lib:0,get_error_messag:0,get_error_reason:0,get_ext:0,get_ext_at:0,get_ext_count:0,get_fingerprint:0,get_id:0,get_issu:0,get_kei:0,get_modulu:0,get_nam:0,get_not_aft:0,get_not_befor:0,get_object:0,get_peer_cert:1,get_peer_cert_chain:1,get_pubkei:0,get_rsa:0,get_serial_numb:0,get_sess:[0,1],get_session_cache_mod:1,get_session_timeout:1,get_shutdown:1,get_socket_read_timeout:1,get_socket_write_timeout:1,get_stat:1,get_subject:0,get_tim:1,get_timeout:1,get_valu:0,get_verify_depth:1,get_verify_mod:1,get_verify_result:1,get_vers:[0,1],get_x509_verify_error:0,getpeernam:1,getproto:1,getronicsgov:4,getsocknam:1,getsockopt:1,geturl:0,getvalu:0,ggarfmmj4yuhewkys9jo1h8k4bdxugmauwni5:3,give:3,given:[0,1],givennam:0,gknqqdblotqt06f3oissdjetm2itllyhgzv:3,global:4,gmt:[2,3,4],goe:[0,1],good:0,govern:3,gpmpndsyvvceufpluwydim0vkwhgc2:4,gqnveov:3,gqzcvnzzcmx8uvrjqr8drwdsmpj0vxg1:4,gracefulli:1,gratefulli:4,grcgzeb9ymfcedxahtdufhjrkpdpsxzzvvgksbncbqu92obyqvnrq8m:4,greet:1,grew:5,group:4,gucrblvd7n3ofnx5ujmpmcw9zwbu:4,gvyvi:4,gymga1udiwr8mhqaffzsqjs9bei2gcgrutozevjws81kov:4,h7nmicymi2wkz8h:4,h99suto:3,h9diul:3,hack:2,handi:3,handl:[1,4],handle_error:1,handle_request:1,handler:[0,1],handshak:[0,1],hanson:3,happen:5,hard:0,hardwar:0,has:[0,1,4,5],hash:0,have:[1,3,4],hcyiukxujtaqtxboh:4,head:2,header:[0,2],headervalu:0,height:2,heikki:[1,5],hellman:[0,2],henc:3,henceforth:2,here:[0,1,3,4],hex:0,higher:1,hihsrgwtnd7lnxuucpx8yv1id0dlmp0hz:4,his:4,hkig9w0baqefaaobjqawgykcgyea5c5tj1chtsoxa1q2q0fyiwmwyhptjpjcvtzm:4,hmac:[0,4,5],hold:0,home:[0,2,4],hook:1,host:[0,1,5],hostnam:1,hot:4,how:[0,1,4,5],howev:1,hpysvh:4,href:2,hrg6sai33usk8xpokjqa:3,htm:4,html:[0,2,4],http:[0,4,5],http_class:0,httpconnect:[0,5],httplib:[0,5],https_open:0,https_request:0,https_server:2,https_srv:4,httpsconnect:[0,5],httpserver:2,httpshandler:0,httpslib:[5,6],hu3qdmtcwjd:3,hvcnaqkemryefooerud8exiyxfqq8btfukwrsp3imfigcsqgsib3dqejdzffmemw:4,hyswpz1xvlprmv4:3,i2d_ssl_sess:1,ia5str:3,icon:4,ident:[1,2,4,5],identifi:[0,3,4,5],idx:1,ietf:4,ieucourgcxpyd1j65vt7ob3ziypu2f2nluicynqpg1sd:4,ignor:0,iihwd6gtv1uodf7urbxtl3hq9:4,imap:4,imc:4,img:2,immedi:1,implement:[0,4,5],imqqiiw:4,includ:[0,3],incorpor:[3,4],increas:0,indent:0,indetermin:1,index:[0,6],index_html:2,indic:[0,1,4],indirectli:0,info:[0,3,4],inform:[0,1,2,3,4,5],inherit:[0,1],init:0,initi:[0,1],initialis:[0,1],inkei:4,input:[0,1,5],insert:0,instal:4,instanc:[0,1,4,5],instanti:[0,4],instead:[2,4],instruct:2,integ:1,integr:4,intend:4,interact:0,interest:1,interfac:[0,1,4,5],intern:[0,1],internet:[1,3,4],interpret:[0,1,5],intuit:3,invalid:0,invok:[0,1,2,4],iobuff:[0,5],ioy0bdijcyn1jimohj:4,ipv4:1,ipv6:1,iqwxllnj:4,ir9fggophatzzq:4,ireactorssl:1,ireactortcp:1,isbn:5,isexpir:0,isgoodcooki:0,isgoodcookiestr:0,issu:[1,2,4],issuer:[0,3,4],itafbgkqhkig9w0bcqewennlbmrlckblegftcgxllmrvbyibadambgnvhrmebtad:4,item:0,iter:0,its:[0,1,2,3,4],itself:[0,4],iwq3n6j1suzs3uw6abq8bivynoucmkjaqqjbanqxfalu4b:3,j6wo9dzltioz3znvr3ljsskib4tip4ugqnjaluw7m3ftz3magxn68hbbjs8tz8tl:4,j9ftv3di:3,jan:2,jbt3ltgf743utyaas7hnguouobhoyt:3,jcyhx9vw4xvja7:4,jddsk:4,john:5,join:4,ju4:3,jun:2,just:[1,5],jvy5cif:4,jy5rd:3,jyvbd7acn35p5yx7ktqvqerwdijxycanbcnvmrtmysanw9kv1ujtxc5vx7ylwipk:3,kdfqdmtfzqkymhp1laq1ihbq1rhwsbh5n3ekq:3,kdjqodst7ovu62motgf3arcduppwuztfxolyone5nioo1apvhbrinqwcplkpotqr:3,kebfzs8asq7uc9axw6ti0eapj8evhtwhsbgzqrwekfbxs6hbbhmidc4n0m7oq:4,keep:[1,3],kef21pgguqpf14gkgfwx3sv4bjc1vbrrwq6zlg3nmuyqr5mtjjy9eq:3,kei:[0,1,2,3,5],key_as_byt:0,keybio:0,keyfil:[0,1],keygen_callback:0,keyid:[3,4],keylen:0,keyout:3,keypair:0,kilroi:0,kind:1,kiy8jkpv8dr5po1ikaxjfudbygdenjwybsrspsk3p:3,kkst1mcj:3,know:4,known:5,kozihvcnaqebbqaegyblzlgupfphwhsgtiapvdexn61qisz3oem88xoxkuw0szor:4,kozihvcnaqebbqaegycbaxz:4,ktgtcixjl2nmw7j:3,kv95ymtgbisuwkj93grbvqoj:4,kwarg:0,kxtbbmqswcqydvqqg:4,l5trm4x6zjxwuxxmijcehmmd8tc8ybwwo4ao19b3ebffetvsugxsga:3,l6kn27mwzhe331vjttjsgl4:3,lamy57gkw4ondmrtqvq2ojqlvosbllpxzh:4,last:[0,1,3,4,5],later:[0,1],latter:1,lbow6ssdir6:4,lead:[0,1],leak:0,least:1,leav:[3,4],left:[3,4],legal:0,len:0,length:[0,1,2],less:0,let:[3,4,5],letter:[1,3,4],level:[1,2],lg4q5yezr1ejaw:4,librari:[1,4],licenc:0,licens:0,lifetim:1,like:[0,3,4],limit:0,line:[0,4,5],link:[2,5],linux:5,list:[0,1,2],listen:1,listenssl:1,listentcp:1,literatur:0,littl:[2,5],ljecgc3rqu1uwisbkmquis1s46ebbm5np75izpnujokj2hv:4,lkmac1dwb3dqgjt5xk4wjesinfdxecnegacyteagyztpiapu:3,lnzqowadmol:4,load:[0,1,2,4,5],load_cert:[0,1,4],load_cert_bio:0,load_cert_chain:1,load_cert_der_str:0,load_cert_str:0,load_certif:0,load_client_ca:1,load_crl:0,load_dynam:0,load_dynamic_engin:0,load_fil:[0,4],load_info:[0,4],load_kei:[0,4],load_key_bio:0,load_key_bio_pubkei:0,load_key_str:0,load_key_string_pubkei:0,load_loc:0,load_openssl:0,load_param:0,load_params_bio:0,load_pkcs7:0,load_pkcs7_bio:0,load_pkcs7_bio_d:0,load_pkcs7_der:0,load_private_kei:0,load_pub_kei:0,load_pub_key_bio:0,load_public_kei:0,load_request:0,load_request_bio:0,load_request_der_str:0,load_request_str:0,load_sess:1,load_verify_info:1,load_verify_loc:[1,5],loc:0,local:[2,3,4],localhost:[2,3,4],localitynam:0,localtimezon:0,locat:[1,2],lock:4,logger:2,logic:1,longer:0,look:[3,4],loseconnect:1,lower:0,ltd:[3,4],lwpbxzf2k3fuudnkrlfbakeampxoybuifr2s5bma:3,ly4tpl5:3,m1awhen3vir2zlaw:3,m1je:3,m2_asn1_integer_fre:0,m2_asn1_object_fre:0,m2_asn1_string_fre:0,m2_asn1_time_fre:0,m2_bio_fre:[0,1],m2_bio_noclos:1,m2_bio_pop:0,m2_cipher_ctx_fre:0,m2_dh_free:0,m2_dsa_fre:0,m2_ec_key_fre:0,m2_engine_fre:0,m2_hmac_ctx_fre:0,m2_md_ctx_free:0,m2_pkcs7_free:0,m2_pkey_fre:0,m2_rsa_fre:0,m2_sk_x509_extension_fre:0,m2_sk_x509_free:0,m2_ssl_ctx_free:1,m2_ssl_free:1,m2_ssl_session_fre:1,m2_x509_crl_free:0,m2_x509_extension_fre:0,m2_x509_free:0,m2_x509_name_entry_fre:0,m2_x509_name_fre:0,m2_x509_req_fre:0,m2_x509_store_ctx_fre:0,m2_x509_store_fre:0,m2crypto:[1,3],m2crypto_xmlrpc:0,m2cryptoerror:0,m2urllib2:6,m2urllib:[2,6],m2xmlrpclib:[2,6],ma0gcsqgsib3dqebbauaa4gbaho3drchr86fstvavfixdsswwqktcehuhrdc:4,mac:0,made:[1,5],mai:[0,1,2,3,4,5],mail:4,maintain:1,make:[0,1,3,4,5],makebuf:4,makecooki:0,makefil:[0,1],malfunct:1,man:1,manag:2,mani:[0,2,4],manipul:[0,1],manpag:[0,1],manual:[0,5],map:[1,4],mar:[3,4],march:4,mark:[0,4],master:3,match:[0,3,4],matej:0,materi:[2,5],matt:5,max_byt:0,maximum:1,mbstring_asc:0,mbstring_utf8:0,md5:0,md5withrsaencrypt:[3,4],mean:0,meant:3,measur:0,medusa:2,memori:[0,4],memorybuff:[0,4],memoryview:1,messag:[0,1,5],message_bodi:0,messagedigest:0,messier:5,method:[0,1],mg611eovkleoostv:3,mh2pz4lverxa:4,mhf6rqar:4,micalg:4,microsec:1,might:1,miibntccaqycaqawxtelmakga1uebhmcu0cxetapbgnvbaotce0yq3j5chrvmriw:3,miibvwyjkozihvcnaqcdoiibsdccauqcaqaxggeamih9ageamgywytelmakga1u:4,miicxgibaakbgqcvwdhjvcuwxwu4h8wqujguvm:3,miie8ayjkozihvcnaqccoiie4tccbn0caqexczajbgurdgmcgguamcigcsqgsib3:4,miiiwwyjkozihvcnaqcdoiiitdccclacaqaxggeamih9ageamgywytelmakga1u:4,mime:[3,5,6],mimetool:0,mind:1,minu:0,miss:1,mix:0,mkwcbi1nfvohcv3xdq2ela:4,mode:[0,1,2,4],model:[3,4],modifi:[0,2,4],modul:[4,5,6],modulu:[0,3,4],more:[0,1,3,5],most:[0,1,4,5],mous:0,movement:0,mozilla:[2,4],mpi:0,mpint:0,mrywfaydvqqdew1tl01jtuugu2vuzgvymsewhwyjkozihvcnaqkbfhjzzw5kzxja:4,msb:0,msg:4,msg_bio:4,mua:4,much:0,multilin:0,multipart:4,multipl:1,multipurpos:4,multivalu:0,must:[0,1,5],mutheybpq5th7ydrtnizkkxobnqe2kyux9x22a1kh49sojjfg6kpb9mugizbimlv:3,mutt:4,mysteri:0,naccept:2,name:[0,1,3,4,5],navig:4,nbbba2yl0n5gs1tyiy9z:3,nbsp:2,nbyte:1,nconnect:2,necessari:0,necessarili:0,need:[0,1,3,4,5],neg:0,negoti:1,neither:1,nerx9zjgvrwuscqqcu:3,net:3,netmemet:5,netscap:3,network:[4,5],new_extens:0,new_pub_kei:0,new_stack_from_d:0,newca:3,newcert:3,newer:0,newkei:[3,4],newkey2:3,newli:0,newreq:3,next:[0,3,4],ngp:[2,3,4,5],nhost:2,nid:0,nihuwgujn:3,niqfytycdl9i5sk:4,nkasxekr8auhjsbvumrqrl6r0nnsfpzdr1w7pv:4,no_passphrase_callback:0,nocertif:1,node:4,non:[0,1,4],noncrit:0,none:[0,1,4],nonzero:0,noout:[3,4],nor:[1,4],normal:[1,5],note:[0,1,4,5],noth:0,notifi:1,notwithstand:4,now:[3,4],nqaodq3aobzpafp9l:3,nqxlmgj3jwq7x9:4,nss:[4,5],ntransfercmd:0,nueymfjdm0uvntg0icxgnufsfnjkntthpagykgetric3kgjz:3,num:0,number:[0,1,3,4],numer:2,numericipmatch:1,nuser:2,nyndufwi0qm92qlk0ui:3,obio:0,object:[0,1,4,5],obtain:[0,4],occur:[0,1],octet:[0,1],octx_to_num:0,od2m3lp7jbwjqbrtndhimqul2s4yu:4,odd:0,off:0,offset:0,oiqto:4,old:[3,5],onc:[0,1],one:[1,2,3],ones:5,onli:[0,1,3],onto:0,open:[0,1,2,4,5],open_http:0,openfil:0,openpgp:4,openssl:[0,1,2,4,5,6],oper:[0,1,2,4],option:[0,1,3],optnam:1,org:[2,3,4,5],organ:[3,4],organiz:[3,4],organizationnam:[0,3],organizationunitnam:0,origin:0,osafound:5,other:[0,1,3,5],otherwis:0,our:4,out:[0,1,2,3,4],out_bio:0,outform:4,output:[0,4],over:[0,1,5],overlap:4,overload:1,overrid:1,overridden:1,overwrit:2,own:[0,1,2,4,6],p12:4,p7_bio:[0,4],p7file:0,p7m:4,p7s:4,pack:1,packag:6,pad:0,page:[1,2,6],pair:[0,1,2,3,4],param:[0,1],paramet:[0,1,2,4,5],part:4,partial:1,pass:[0,1,3],passphras:[0,1,3,4],passphrase_callback:[0,1],password:[0,3,4],patch:[2,3],path:0,pathnam:2,pbkdf2:0,pcgiserv:2,pdlrrliknknfmhkiacktlrcu59sca6adeiwuzqmuzp5cs6jrsro3nkfg1bd09d1k:3,peek_error_cod:0,peer:1,peercertdigest:1,peercerthash:1,pem:[0,1,2,3,4,5],pemfil:1,pend:1,pep484:1,per:[0,1,2],perform:[0,5],period:3,perl:3,permit:5,pfi:3,pfl1k5dyxrgtzlb36uljd:4,pgpmime:4,pheng:[0,1,2,3,4,5],phrase:3,pick:4,pin:0,pk7_smime:4,pkc:4,pkcs12:4,pkcs5_pad:0,pkcs7:[0,4],pkcs7_detach:4,pkcs7_error:0,pkcs7_pad:0,pkcs7_text:4,pkcs7_verifi:4,pkei:0,pkg:[3,4],plain:4,pleas:[1,3],plen:0,pltnni25spyrcwfl6erd25u:4,plu:1,point:0,pointer:0,polici:[1,3,4],pool:0,pop:[0,4],popular:4,port:[0,1,2],portal0:2,portal:2,portion:[0,5],posit:0,possibl:[0,1],post1:[2,3,4],post:0,post_connection_check:1,postconnectioncheck:1,power:2,practic:[0,4,5],pravir:5,predetermin:0,predict:0,prefix:0,premis:4,present:[1,2],press:0,pretend:4,pretti:5,previou:0,previous:1,primari:5,prime:0,princip:0,print:[0,1,2,3,4],print_param:0,printabl:3,privaci:4,privat:[0,1,3,4],private_decrypt:0,private_encrypt:0,privkei:4,prng:[0,2,4],probabl:[1,4,5],problem:0,proc:3,proce:1,process:[1,3,4],produc:0,product:4,prog:4,program:[3,6],programm:[4,5],project:[4,5],prompt1:0,prompt2:0,prompt:4,propag:0,proper:1,properli:4,propertymap:2,prot_c:0,prot_p:0,protect:[0,1,4],protocol:[0,1,2,4,5],protocolwrapp:1,provid:[0,1,2,4,5],provinc:[3,4],proxi:0,proxyhttpsconnect:0,pseudo:[0,4],pss:0,pty:[3,4],pub:0,pub_kei:0,pub_key_from_d:0,pub_key_from_param:0,pubkei:0,public_decrypt:0,public_encrypt:0,purpos:[0,4],push:[0,4],puthead:0,putrequest:0,pyfil:0,pystack:0,python3:1,python:[0,1,3,6],q1z7g:3,q7s4tn1z:4,qbcrdaoxdj0ulwytauev:4,qin7ujpkou61cn7h8dvhr8yw9:4,qjpbezwdp7gjfzfatqitesymwo3i:4,qlen:1,qppdzt3ykfmg2lzytaam1czvb6rbnrjjp2zrpbwn:3,qtm0ddmm:3,quarante:5,queri:1,quiet_genparam_callback:0,quit:[2,3,4],quvxinaxygqco9lzdw6hudk8:4,qya6adywgbghr9jkhwn5gsdu7bwx:4,rais:[0,1,4,5],rand:[2,4,6],rand_add:0,rand_byt:0,rand_file_nam:0,rand_pseudo_byt:0,rand_rang:0,rand_se:0,rand_statu:0,randfil:0,randfnam:0,random:[0,4],randpool:[2,4],rang:0,rather:1,rc4:6,rc4_free:0,rdn:0,reactor:1,read:[0,1,2,3,4,5],read_al:0,readabl:0,readbio:1,readi:[1,3,4],readlin:0,real:0,realiz:1,reason:[0,1],recal:4,receipt:1,receiv:[1,4],recent:4,recipi:4,recipient_kei:4,recommend:[0,1,5],record:5,recreat:4,recv:1,recv_into:1,refcount:[0,1],refer:[0,1,2],regex:0,regular:0,reject:1,relativedistinguishednam:0,releas:0,reli:[0,1],remot:1,remov:1,remove_sess:1,renam:[3,4],render:4,renegoti:1,repli:2,repres:[0,1],represent:0,repudi:4,req:[0,3,4],request:[0,1,3,4],request_bodi:0,requesthandlerclass:1,requir:[0,1,5],rescorla:5,reserv:[0,1],reset:0,reset_context:0,resid:1,resolv:2,respect:[0,1],rest:0,result:[0,1,4],ret:[1,3],retriev:[0,4],reus:1,revoc:0,rfc:[0,4],rgwnkxpj:4,right:[0,1,4],ripemd160:0,rm2htgotm2lmore4geotypi5f1fbi:3,rn9vpy0suy8:3,rnd:0,root:5,routin:[1,4],rsa:[1,2,3,4,5,6],rsa_error:0,rsa_pub:0,rsaencrypt:[3,4],rsaerror:0,rsassa:0,rudimentari:5,run:[0,2,4],rwb:0,rwniyh0aw4xyyhhit:4,s0ovoc041cerazqfm2tl:4,safe:0,sai:4,said:[0,4],salt:0,salt_len:0,salt_length:0,same:[0,1,5],sat:[2,3],save:[0,4],save_fil:[0,4],save_kei:0,save_key_bio:0,save_key_d:0,save_key_der_bio:0,save_param:0,save_params_bio:0,save_pem:0,save_pub_kei:0,save_pub_key_bio:0,saver:4,sc3lsmhugu9xc26ogstjmkquiah:3,sc51hkebgckl1:4,scope:4,scopeid:1,screen:[2,4],script:5,search:6,sec:1,second:[0,1,5],secret:3,section:[3,4],secur:[0,1,3,4],see:[0,1,2,5],seed:[0,2,4],seek:0,seldom:0,select:[1,2,4],self:[0,1,3,4],send:[0,1,2,5],sendal:1,sender:4,sendmail:4,sendsmim:4,sens:1,sent:[0,1,3,4],sequenc:0,seri:4,serial:[0,3,4],serialnumb:0,serv:2,server:[0,1,2,3,4,5],server_address:[1,5],serverpostconnectioncheck:1,servic:[1,4],session:[0,6],session_data_manag:2,set1_host:1,set:[0,1,3,4,5],set_accept_st:1,set_allow_unknown_ca:1,set_bio:1,set_ciph:[0,4],set_cipher_list:1,set_client_ca_list_from_context:1,set_client_ca_list_from_fil:1,set_connect_st:1,set_crit:0,set_data:0,set_datetim:0,set_default:0,set_default_verify_path:1,set_info_callback:1,set_issu:0,set_issuer_nam:0,set_kei:0,set_mod:1,set_not_aft:0,set_not_befor:0,set_object:0,set_opt:1,set_pad:0,set_param:0,set_post_connection_check_callback:1,set_pubkei:0,set_serial_numb:0,set_sess:[0,1],set_session_cache_mod:1,set_session_id_ctx:1,set_session_timeout:1,set_shutdown:1,set_socket_read_timeout:1,set_socket_write_timeout:1,set_ssl:0,set_ssl_close_flag:1,set_str:0,set_subject:0,set_subject_nam:0,set_tim:[0,1],set_timeout:1,set_tlsext_host_nam:1,set_tmp_dh:1,set_tmp_dh_callback:1,set_tmp_rsa:1,set_tmp_rsa_callback:1,set_verifi:[1,5],set_verify_cb:0,set_vers:0,set_x509_stack:[0,4],set_x509_stor:[0,4],setblock:1,setsockopt:1,settimeout:1,setup_addr:1,setup_ssl:1,sever:[0,1,3],sfl_home:4,sfqo6lc9mtsj7fjydq:4,sha1:[0,1,4],sha224:0,sha256:0,sha:0,shall:[2,4],share:0,should:[0,1,3],should_read:0,should_retri:0,should_writ:0,show:0,shown:[2,5],shut:1,shutdown:1,sid_ctx:1,side:[0,1,5],sign:[0,3],sign_asn1:0,sign_dsa:0,sign_dsa_asn1:0,sign_fin:0,sign_init:0,sign_rsassa_pss:0,sign_upd:0,signal:0,signatur:[0,3,4],signer:4,signer_kei:4,signific:[0,1],similar:[1,2,3,4],simpl:[0,1,5],simpli:0,sinc:[0,3,5],singl:0,siong:[0,1,2,3,4,5],sipba4ik5xcrlt9e0s2qjgrvo9gyfaqz:4,site:3,situat:3,size:[0,1],sizehint:0,sjai4kpfvt00xfnvgluywyeks9sygto7hihnqkcf44f5lyv6ntfwmfqb11daty9v:4,skip:4,skip_accept_encod:0,skip_host:0,skunk:2,smartcard:0,smime:6,smime_error:[0,4],smime_load_pkcs7:[0,4],smime_load_pkcs7_bio:[0,4],smtpd:4,smtplib:4,sni:1,sntelhcawulwtifz:4,so_:1,sock:1,socket:[0,1,5],socketserv:1,softwar:4,sol_socket:1,sol_tcp:1,some:[1,3,4],sopath:0,sophist:5,sourc:[0,1,4,5],space:0,specif:[1,3,5],specifi:[0,1],spoofer:4,sport:5,src:2,ssl:[0,2,3,4,6],ssl_:1,ssl_cert_dir:1,ssl_cert_fil:1,ssl_connect:1,ssl_context:[0,1],ssl_ctx:0,ssl_ctx_flush_sess:1,ssl_ctx_ptr:1,ssl_ctx_set_opt:1,ssl_ctx_set_session_cache_mod:1,ssl_ctx_set_timeout:1,ssl_dispatch:[0,6],ssl_get_default_timeout:1,ssl_get_error:1,ssl_info_callback:1,ssl_ptr:1,ssl_received_shutdown:1,ssl_sent_shutdown:1,ssl_sess_cache_:1,ssl_transport:[0,2],ssl_verify_callback:1,ssl_verify_callback_allow_unknown_ca:1,ssl_verify_callback_stub:1,sslbio:0,sslerror:[0,1],sslserver:[0,6],ssltimeouterror:1,sslv3:[1,5],sslverificationerror:1,stack:[0,1],stack_of:1,stamp:4,standard:[0,4],standard_error_messag:2,standard_html_foot:2,standard_html_head:2,standard_templ:2,start:[0,1,2,3,4],startpassthrough:1,starttl:1,state:[0,1,3,4],stateorprovincenam:0,statu:[0,1],stderr:1,stdout:[0,5],step:[3,4,5],steve:3,still:1,stop:[1,2],store:[0,1],str:1,stream:0,strict:0,string:[0,1,2,4],stringio:[4,5],strong:0,struct:1,struct_siz:1,struct_to_timeout:1,structur:[0,1],style:1,subclass:0,subject:[0,3,4],subjectaltnam:[0,5],subjectnam:0,subpackag:6,subsequ:5,substitut:4,succeed:[0,1,2],success:[0,1],successfulli:1,suffici:0,suggest:0,suit:1,suitabl:[0,5],sun:2,suppli:[0,1],support:[0,1,5],suppos:4,sure:0,surnam:0,symbol:1,symmetr:[0,4,5],sync:0,sys:4,system:[1,2,3,4],sztm5jrp2zw:4,t6lqehb32wfyxqbkfxfjsxzsxox3r:4,take:1,target:[0,2,4],tb7k3chfgw5wagwnll8lb:3,tcp:[1,5],tcpserver:1,tell:[0,5],temp_fold:2,temporari:[1,4],termin:1,test:[0,1,4,5],test_ssl:5,text:[0,2,3,4],text_crlf:0,text_crlf_bio:0,text_nam:0,textiowrapp:0,textual:5,than:[0,1,5],thei:[0,1,4,5],them:[0,4,5],therefor:1,thi:[0,1,2,3,4,5],third:5,those:5,thread:6,threadingmixin:1,threadingsslserv:1,threat:[3,4],through:[0,1,3,4],thu:[0,4],thusli:[2,4],time:[0,1,2,4,5],timedelta:0,timeo:1,timeout:[0,6],titl:2,tlfgl4hdk2gyzxafuqzwiurz:4,tls:1,tlsprotocolwrapp:1,tmp:4,tmp_bio:4,to_addr:4,to_cert:4,tob:4,togeth:1,toivonen:[1,5],too:5,tool:3,top:[0,2,4],topic:3,trace:0,traceback:[1,4],traffic:5,transfer:[0,4],transform:4,translat:1,transport:0,treat:1,tri:[1,5],tripl:4,trust:4,tue:2,tunnel:0,tupl:[0,1],tvtk:4,twice:1,twist:[1,5],twistedprotocolwrapp:[0,6],two:[0,1,5],tws5k:3,txt:5,type:[0,1,2,3,4],typic:[1,4,5],tzinfo:0,tzname:0,tzsznk2qwgvsspos9mhuaepbnjmnbffbrulhrutsglm:4,u4dmyq9uxs421en3v2hkvhvdy8ut2ot29:4,u4j2f34u0xktwcp:4,u7rqbwpc9hr34saprs3ubbculet748kecbx247imbtidctzxcc1o86:4,ubowzitegtyli52:4,uifxaf6s4n2uihvp6tqxthejtpzoc7pc:4,ukidkhst60v2q9kegpzgfpoztskm:4,ull4d2cldx9ovynykwdezb5dyv0r:4,unattend:3,uncertainti:0,under:4,under_bio:0,underli:[0,1,5],understand:4,unencrypt:[3,4],uniqu:0,unit:[1,3,4],unix:1,unknow:0,unknown:[0,1],unless:0,unlock:0,unmix3:0,unmix:0,unpack:2,unpredict:0,unsaf:0,unset_ciph:0,unset_kei:0,unset_x509_stack:0,unset_x509_stor:0,until:[1,3],untouch:1,untrust:2,updat:[0,3],upon:1,upper:0,urandom:2,urbfke2mocdxvdzxbmd:4,url:[0,2],urllib:[0,2],uryvak7vfoldaz6z3nosoi6nonnehpr:4,usag:4,use:[0,1,2,3,4,5],used:[0,1,3,4],useful:1,useless:5,user:[0,4],user_ag:0,usernam:0,uses:[0,4,5],using:[0,1,3,4],usr:[3,4],usual:[0,1,5],utc:0,utcoffset:0,utf:0,utifsh4jkkm:4,util:[5,6],utilerror:0,uweuasngtkpjv2jyumd3hwqox2q3cd4zgqvjj6gf3exa5126ckf:3,uwrgu5shra8oncm0cdxej0kpf3cfnjhffb8hwmzi4uegnmfxqnsxogz:4,v_asn1_ia5str:0,valid:[0,1,3,4,5],valu:[0,1,3,4],valueerror:0,variabl:[0,1],variou:[1,5],verbos:0,veri:[0,1],verif:[0,1,4],verifi:[0,1,2,3],verify_asn1:0,verify_dsa:0,verify_dsa_asn1:0,verify_fail_if_no_peer_cert:[1,5],verify_fin:0,verify_init:0,verify_ok:1,verify_p:[1,5],verify_rsassa_pss:0,verify_upd:0,verisign:4,version:[0,1,3,4,5],vhgdittnelgthbaezu5rhdswgdelvbp:4,vi4roin:3,via:[0,1],viega:5,vihhfc1zzp:3,visual:0,vkwwecqqdkeu:3,vsgprqx2:4,vsxc7xx7xo:4,vtajp:3,vuzalydffdfutiqqzys4z:4,w4d1nnwu8agcpyshsexhc:3,w81xodtq2ecjxc8fn2wpa9y5vd1lt7ojksoul1:3,wai:[1,4],wait:1,walk:3,warn:[0,1,2],wbal2p:4,wdd1ar2k4k3gai7kkgobwt0:4,wdigqewjl:3,weak:5,weak_crypto:1,web:[2,4],well:[0,1,2,4],were:[0,1],west:0,what:[0,3,4],when:[0,1,3,4,5],whenev:1,where:[0,1,3],wherea:[0,5],whether:[0,4],which:[0,1,3,4,5],who:4,whose:0,why:4,widgit:[3,4],width:2,window:[2,4],wish:[2,3,4],within:[1,3,5],without:0,wjtpvp0yobmju4vmkezi405r7o8oewi:3,wkat:4,wmbgsclvwsfzcccjhavw9nhfmucnrdwxaymvetnuon:4,won:1,word:4,work:[0,1,2,3,4,5],world:1,would:[0,1,4],wrap:4,wrappedprotocol:1,wrapper:[0,1,5],write:[0,1,3,4],write_bio:1,write_clos:0,write_d:0,writeabl:0,writebio:1,writesequ:1,written:[0,3,5],wrongcertif:1,wronghost:1,wrylp3:4,wsluvo:3,www:[0,2,4],wyhfg8g3biehurpj2v:4,x509:[3,4,5,6],x509_ext:0,x509_ext_ptr:0,x509_extens:0,x509_extension_stack:0,x509_name:[0,1],x509_name_entri:0,x509_ptr:1,x509_purpose_:0,x509_stack:[0,4],x509_store:[0,4],x509_store_context:0,x509_store_ctx:0,x509_store_default_cb:0,x509_store_set_verify_cb:0,x509error:0,x509v3:[3,4],xc9dtimuutxtxlgytb0ujkbnsoaenolm:4,xekaxcmzegp0b6camwfmuqrbvgxbbncqkc:4,xgffb0okilylmwv2bf6:4,xisnot:4,xlcqyvk1tzhd:4,xlyg6hhzzgbfyyngj2y7ymz1rl1m8snrnmkcyskgtrudenf6wt9:4,xmlrpc:0,xmtdg:4,y3klvhk09yl6d:4,y9mh7efw:4,year:[3,4],yet:1,yl9qevh1pp2zvswq12p7gjt3t:4,you:[0,1,2,3,4,5],your:[0,2,4,6],ypfxy:3,yqor8jggsuzroyjqhj:4,yrpzcwq3gxahuj:3,yubj33ylmpjgngijlnolfy0hnw7tmwqr:4,ywmxnjz8:4,z04ovaeue4x0swm17hlbm2kvt:3,z2s:2,z6ebh:3,z6uxrm:4,zbq:3,zbxscvldasmckg:3,zero:0,zhttp_handler:2,zhttp_server:2,zhttps_handler:2,zhttps_server:2,zip:2,zone:0,zope:[2,4],zopebutton:2,zovnycmv1cintpalaw4bwtxnhcdvthavdy34okhemzncg:3,zpecllwhxd4b1auaiaargkl935u:4,zpqqqzkq:3,zserver:2,zserverssl:6,zssl:2,zsyncer:2,ztf6mpxjsixi6l4zyxebs6yhf:4,zw50msqwigyjkozihvcnaqkbfhvyzwnpcgllbnrazxhhbxbszs5kb20caqawdqyj:4,zw5kzxixitafbgkqhkig9w0bcqewennlbmrlckblegftcgxllmrvbtcbnzanbgkq:4,zwxy:4,zxhhbxbszs5kb20whhcnmdewmzmxmte0mdmzwhcnmdiwmzmxmte0mdmzwjbbmqsw:4},titles:["M2Crypto Package","SSL Package","1.   ZServerSSL-HOWTO","HOWTO: Creating your own CA with OpenSSL","HOWTO: Programming S/MIME in Python with M2Crypto","HOWTO: Programming SSL in Python with M2Crypto","Welcome to M2Crypto\u2019s documentation!"],titleterms:{The:3,asn1:0,authcooki:0,bio:0,bit:5,callback:0,certif:4,checker:1,cipher:1,code:5,conclus:[2,3],connect:1,content:2,context:1,creat:3,decrypt:4,document:6,dsa:0,encrypt:4,engin:0,err:0,evp:0,ftpslib:0,histori:5,howto:[2,3,4,5,6],http:2,httpslib:0,indic:6,instal:2,interoper:4,introduct:[2,3,4,5],kei:4,m2crypto:[0,2,4,5,6],m2urllib2:0,m2urllib:0,m2xmlrpclib:0,messag:4,messeng:4,microsoft:4,mime:4,modul:[0,1],netscap:4,openssl:3,origin:4,outlook:4,over:2,own:3,packag:[0,1],prepar:2,procedur:3,program:[4,5],python:[2,4,5],rand:0,rc4:0,resourc:4,rsa:0,sampl:5,secur:5,send:4,session:1,sign:4,smime:[0,4],smtp:4,sourc:2,ssl:[1,5],ssl_dispatch:1,ssldump:5,sslserver:1,subpackag:0,tabl:6,test:2,thread:0,timeout:1,twistedprotocolwrapp:1,util:0,verifi:4,via:4,webdav:2,welcom:6,x509:0,xmlrpc:2,your:3,zserverssl:2,zsmime:4}}) \ No newline at end of file diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..a472668 --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,30 @@ +Welcome to M2Crypto's documentation! +==================================== + +Contents: + +.. toctree:: + :maxdepth: 4 + + M2Crypto + + +HOWTOs +====== + +* :ref:`howto-ca` + +* :ref:`howto-ssl` + +* :ref:`howto-smime` + +* :ref:`zserverssl-howto` + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/make.bat b/doc/make.bat new file mode 100644 index 0000000..8c9f7cc --- /dev/null +++ b/doc/make.bat @@ -0,0 +1,190 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\M2Crypto.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\M2Crypto.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/epydoc.conf b/epydoc.conf index 2afa556..d2c1826 100644 --- a/epydoc.conf +++ b/epydoc.conf @@ -18,9 +18,6 @@ exclude-introspect = M2Crypto.__m2crypto # Variable shadows module, which causes the module to double in the doc # with second instance showing '. Exclude so we only get one (with '). -exclude = M2Crypto.PGP.PublicKey -exclude = M2Crypto.PGP.PublicKeyRing -exclude = M2Crypto.PGP.packet exclude = M2Crypto.SSL.Cipher exclude = M2Crypto.SSL.Connection exclude = M2Crypto.SSL.Context diff --git a/fedora_setup.sh b/fedora_setup.sh deleted file mode 100755 index 76d1f59..0000000 --- a/fedora_setup.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# This script is meant to work around the differences on Fedora Core-based -# distributions (Redhat, CentOS, ...) compared to other common Linux -# distributions. -# -# Usage: ./fedora_setup.sh [setup.py options] -# - -arch=`uname -m` -for i in SWIG/_{ec,evp}.i; do - sed -i -e "s/opensslconf\./opensslconf-${arch}\./" "$i" -done - -SWIG_FEATURES=-cpperraswarn python setup.py $* - diff --git a/pack.py b/pack.py deleted file mode 100644 index 0005026..0000000 --- a/pack.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python - -# Clean up M2Crypto source base. - -import glob, os, os.path, sys - -def zap(arg, dirname, names): - for f in glob.glob(dirname + arg): - try: - os.remove(f) - except: - pass - -if __name__ == "__main__": - start = sys.argv[1] - - os.path.walk(start, zap, "/*.pyc") - - if os.name == 'nt': - zap_m2 = ("__m2cryptoc.pyd","_m2crypto.py") - elif os.name == 'posix': - zap_m2 = ("__m2crypto.so","_m2crypto.py") - for x in zap_m2: - try: - os.remove("%s/M2Crypto/%s" % (start, x)) - except: - pass - - zap_swig = ("_m2crypto_wrap*", "_m2crypto.c", "_m2crypto.py", "vc60.pdb") - for x in zap_swig: - for z in glob.glob("%s/SWIG/%s" % (start, x)): - try: - os.remove(z) - except: - pass - - diff --git a/packaging/python-M2Crypto.spec b/packaging/python-M2Crypto.spec index f8aa0f3..f77bcf0 100644 --- a/packaging/python-M2Crypto.spec +++ b/packaging/python-M2Crypto.spec @@ -13,7 +13,7 @@ # published by the Open Source Initiative. Name: python-M2Crypto -Version: 0.21.1 +Version: 0.35.1.1 Release: 0 Url: http://chandlerproject.org/bin/view/Projects/MeTooCrypto Summary: Crypto and SSL toolkit for Python diff --git a/pylintrc b/pylintrc new file mode 100644 index 0000000..0f2393b --- /dev/null +++ b/pylintrc @@ -0,0 +1,272 @@ +# -*- coding: utf-8; mode: conf -*- +# lint Python modules using external checkers. +# +# This is the main checker controlling the other ones and the reports +# generation. It is itself both a raw checker and an astng checker in order +# to: +# * handle message activation / deactivation at the module level +# * handle some basic but necessary stats'data (number of classes, methods...) +# +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Add to the black list. It should be a base name, not a +# path. You may set this option multiple times. +ignore=CVS, .git, .svn + +# Pickle collected data for later comparisons. +persistent=yes + +# Set the cache size for astng objects. +cache-size=500 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=C0330, C0103, C0111, C0326, R0901, R0903, R0201, I0011 + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=yes + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +msg-template={path}:{line}:[{msg_id}({symbol}),{obj}] {msg} + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=120 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=2000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + + +[BASIC] + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + +# Regular expression which should only match correct module names +# module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +module-rgx=(([a-z_][a-z0-9_]*)|([a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=[f]?[A-Z_][a-zA-Z0-9_]{2,30}$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_]+[a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-zA-Z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-zA-Z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=([a-z_][a-zA-Z0-9_]{2,30}|[A-Z0-9_]{2,30})$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-zA-Z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-zA-Z0-9_]{0,30}$ + +# Regular expression which should only match correct attribute names in class +# bodies +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=__.*__ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=8 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=100 + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/setup.cfg b/setup.cfg index 861a9f5..a21020e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,10 @@ [egg_info] -tag_build = -tag_date = 0 +tag_build = tag_svn_revision = 0 +[flake8] +; ignore = E402,E501,E731,N806,N803,N802,E265 +ignore = E402,N806,N803,N802,E501 + +[pydocstyle] +ignore = D10,D203,D213 diff --git a/setup.py b/setup.py index e7c49eb..d503577 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Distutils/setuptools installer for M2Crypto. +setuptools based installer for M2Crypto. Copyright (c) 1999-2004, Ng Pheng Siong. All rights reserved. @@ -9,160 +9,388 @@ Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004-2007 OSAF. All Rights Reserved. Copyright 2008-2011 Heikki Toivonen. All rights reserved. + +Copyright 2018 Daniel Wozniak. All rights reserved. """ +import glob +import logging +import os +import platform +import re +import shlex +import shutil +import string +import subprocess +import sys + +from distutils.command import build, sdist +from distutils.command.clean import clean +from distutils.dir_util import mkpath +from distutils.version import StrictVersion + +import setuptools +from setuptools.command import build_ext + +logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', + stream=sys.stdout, level=logging.INFO) +log = logging.getLogger('setup') + +REQUIRED_SWIG_VERSION = '2.0.4' + +if (2, 6) < sys.version_info[:2] < (3, 5): + requires_list = ['typing'] +else: + requires_list = [] +package_data = {} +if sys.platform == 'win32': + package_data.update(M2Crypto=["*.dll"]) + + +def _get_additional_includes(): + if os.name == 'nt': + globmask = os.path.join('C:', os.sep, 'Program Files*', + '*Visual*', 'VC', 'include') + err = glob.glob(globmask) + else: + cpp = shlex.split(os.environ.get('CPP', 'cpp')) + pid = subprocess.Popen(cpp + ['-Wp,-v', '-'], + stdin=open(os.devnull, 'r'), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + _, err = pid.communicate() + err = [line.lstrip() for line in err.decode('utf8').split('\n') + if line and line.startswith(' /')] + + log.debug('additional includes:\n%s', err) + return err + + +def openssl_version(ossldir, req_ver, required=False): + # type: (str, int, bool) -> bool + """ + Compare version of the installed OpenSSL with the maximum required version. + + :param ossldir: the directory where OpenSSL is installed + :param req_ver: required version as integer (e.g. 0x10100000) + :param required: whether we want bigger-or-equal or less-than + :return: Boolean indicating whether the satisfying version of + OpenSSL has been installed. + """ + ver = None + file = os.path.join(ossldir, 'include', 'openssl', 'opensslv.h') + + with open(file) as origin_file: + for line in origin_file: + m = re.match(r'^# *define *OPENSSL_VERSION_NUMBER *(0x[0-9a-fA-F]*)', line) + if m: + log.debug('found version number: %s\n' % m.group(1)) + ver = int(m.group(1), base=16) + break + + if ver is None: + raise OSError('Unknown format of file %s\n' % file) + + if required: + return ver >= req_ver + else: + return ver < req_ver -import os, sys -try: - from setuptools import setup - from setuptools.command import build_ext -except ImportError: - from distutils.core import setup - from distutils.command import build_ext -from distutils.core import Extension +class _M2CryptoBuild(build.build): + """Enable swig_opts to inherit any include_dirs settings made elsewhere.""" + + user_options = build.build.user_options + \ + [('openssl=', 'o', 'Prefix for openssl installation location')] + \ + [('bundledlls', 'b', 'Bundle DLLs (win32 only)')] + + def initialize_options(self): + """Overload to enable custom openssl settings to be picked up.""" + build.build.initialize_options(self) + self.openssl = None + self.bundledlls = None class _M2CryptoBuildExt(build_ext.build_ext): - '''Specialization of build_ext to enable swig_opts to inherit any - include_dirs settings made at the command line or in a setup.cfg file''' + """Enable swig_opts to inherit any include_dirs settings made elsewhere.""" + user_options = build_ext.build_ext.user_options + \ - [('openssl=', 'o', 'Prefix for openssl installation location')] + [('openssl=', 'o', 'Prefix for openssl installation location')] + \ + [('bundledlls', 'b', 'Bundle DLLs (win32 only)')] def initialize_options(self): - '''Overload to enable custom openssl settings to be picked up''' - + """Overload to enable custom openssl settings to be picked up.""" build_ext.build_ext.initialize_options(self) - - # openssl is the attribute corresponding to openssl directory prefix - # command line option - if os.name == 'nt': - self.libraries = ['ssleay32', 'libeay32'] - self.openssl = 'c:\\pkg' - else: - self.libraries = ['ssl', 'crypto'] - self.openssl = '/usr' - - - def finalize_options(self): - '''Overloaded build_ext implementation to append custom openssl - include file and library linking options''' + self.openssl = None + self.bundledlls = None + def finalize_options(self): + # type: (None) -> None + """Append custom openssl include file and library linking options.""" build_ext.build_ext.finalize_options(self) + self.openssl_default = None + self.set_undefined_options('build', ('openssl', 'openssl')) + if self.openssl is None: + self.openssl = self.openssl_default + self.set_undefined_options('build', ('bundledlls', 'bundledlls')) + + self.libraries = ['ssl', 'crypto'] + if sys.platform == 'win32': + self.libraries = ['ssleay32', 'libeay32'] + if self.openssl and openssl_version(self.openssl, 0x10100000, True): + self.libraries = ['libssl', 'libcrypto'] + self.swig_opts.append('-D_WIN32') + # Swig doesn't know the version of MSVC, which causes errors in e_os2.h + # trying to import stdint.h. Since python 2.7 is intimately tied to + # MSVC 2008, it's harmless for now to define this. Will come back to + # this shortly to come up with a better fix. + self.swig_opts.append('-D_MSC_VER=1500') + + + if sys.version_info[:1] >= (3,): + self.swig_opts.append('-py3') + + log.debug('self.include_dirs = %s', self.include_dirs) + log.debug('self.library_dirs = %s', self.library_dirs) - opensslIncludeDir = os.path.join(self.openssl, 'include') - opensslLibraryDir = os.path.join(self.openssl, 'lib') - - self.swig_opts = ['-I%s' % i for i in self.include_dirs + \ - [opensslIncludeDir]] + if self.openssl is not None: + log.debug('self.openssl = %s', self.openssl) + openssl_library_dir = os.path.join(self.openssl, 'lib') + openssl_include_dir = os.path.join(self.openssl, 'include') + + self.library_dirs.append(openssl_library_dir) + self.include_dirs.append(openssl_include_dir) + + log.debug('self.include_dirs = %s', self.include_dirs) + log.debug('self.library_dirs = %s', self.library_dirs) + + if platform.system() == "Linux": + # For RedHat-based distros, the '-D__{arch}__' option for + # Swig needs to be normalized, particularly on i386. + mach = platform.machine().lower() + if mach in ('i386', 'i486', 'i586', 'i686'): + arch = '__i386__' + elif mach in ('ppc64', 'powerpc64', 'ppc64le', 'ppc64el'): + arch = '__powerpc64__' + elif mach in ('ppc', 'powerpc'): + arch = '__powerpc__' + else: + arch = '__%s__' % mach + self.swig_opts.append('-D%s' % arch) + if mach in ('ppc64le', 'ppc64el'): + self.swig_opts.append('-D_CALL_ELF=2') + + self.swig_opts.extend(['-I%s' % i for i in self.include_dirs]) + + # Some Linux distributor has added the following line in + # /usr/include/openssl/opensslconf.h: + # + # #include "openssl-x85_64.h" + # + # This is fine with C compilers, because they are smart enough to + # handle 'local inclusion' correctly. Swig, on the other hand, is + # not as smart, and needs to be told where to find this file... + # + # Note that this is risky workaround, since it takes away the + # namespace that OpenSSL uses. If someone else has similarly + # named header files in /usr/include, there will be clashes. + if self.openssl is None: + self.swig_opts.append('-I/usr/include/openssl') + else: + self.swig_opts.append('-I' + os.path.join(openssl_include_dir, 'openssl')) + + # swig seems to need the default header file directories + self.swig_opts.extend(['-I%s' % i for i in _get_additional_includes()]) self.swig_opts.append('-includeall') - #self.swig_opts.append('-D__i386__') # Uncomment for early OpenSSL 0.9.7 versions, or on Fedora Core if build fails - #self.swig_opts.append('-DOPENSSL_NO_EC') # Try uncommenting if you can't build with EC disabled - - self.include_dirs += [os.path.join(self.openssl, opensslIncludeDir), - os.path.join(os.getcwd(), 'SWIG')] - - if sys.platform == 'cygwin': + self.swig_opts.append('-modern') + self.swig_opts.append('-builtin') + + # These two lines are a workaround for + # http://bugs.python.org/issue2624 , hard-coding that we are only + # building a single extension with a known path; a proper patch to + # distutils would be in the run phase, when extension name and path are + # known. + self.swig_opts.extend(['-outdir', + os.path.join(os.getcwd(), 'M2Crypto')]) + self.include_dirs.append(os.path.join(os.getcwd(), 'SWIG')) + + if sys.platform == 'cygwin' and self.openssl is not None: # Cygwin SHOULD work (there's code in distutils), but # if one first starts a Windows command prompt, then bash, # the distutils code does not seem to work. If you start # Cygwin directly, then it would work even without this change. # Someday distutils will be fixed and this won't be needed. self.library_dirs += [os.path.join(self.openssl, 'bin')] - - self.library_dirs += [os.path.join(self.openssl, opensslLibraryDir)] + mkpath(os.path.join(self.build_lib, 'M2Crypto')) -if sys.version_info < (2,4): + def run(self): + """ + On Win32 platforms include the openssl dll's in the binary packages + """ - # This copy of swig_sources is from Python 2.2. + # Win32 bdist builds must use --openssl in the builds step. + if not self.bundledlls: + build_ext.build_ext.run(self) + return - def swig_sources (self, sources): + if sys.platform == 'win32': + ver_part = '' + if self.openssl and openssl_version(self.openssl, 0x10100000, True): + ver_part += '-1_1' + if sys.maxsize > 2**32: + ver_part += '-x64' + search = list(self.library_dirs) + if self.openssl: + search = search + [self.openssl, os.path.join(self.openssl, 'bin')] + libs = list(self.libraries) + for libname in list(libs): + for search_path in search: + dll_name = '{0}{1}.dll'.format(libname, ver_part) + dll_path = os.path.join(search_path, dll_name) + if os.path.exists(dll_path): + shutil.copy(dll_path, 'M2Crypto') + libs.remove(libname) + break + if libs: + raise Exception("Libs not found {}".format(','.join(libs))) + build_ext.build_ext.run(self) - """Walk the list of source files in 'sources', looking for SWIG - interface (.i) files. Run SWIG on all that are found, and - return a modified 'sources' list with SWIG source files replaced - by the generated C (or C++) files. - """ - new_sources = [] - swig_sources = [] - swig_targets = {} +def swig_version(req_ver): + # type: (str) -> bool + """ + Compare version of the swig with the required version. - # XXX this drops generated C/C++ files into the source tree, which - # is fine for developers who want to distribute the generated - # source -- but there should be an option to put SWIG output in - # the temp dir. + :param req_ver: required version as a str (e.g., '2.0.4') + :return: Boolean indicating whether the satisfying version of swig + has been installed. + """ + ver_str = None + IND_VER_LINE = 'SWIG Version ' - if self.swig_cpp: - target_ext = '.cpp' - else: - target_ext = '.c' - - for source in sources: - (base, ext) = os.path.splitext(source) - if ext == ".i": # SWIG interface file - new_sources.append(base + target_ext) - swig_sources.append(source) - swig_targets[source] = new_sources[-1] - else: - new_sources.append(source) + try: + pid = subprocess.Popen(['swig', '-version'], stdout=subprocess.PIPE) + except OSError: + return False + + out, _ = pid.communicate() + if hasattr(out, 'decode'): + out = out.decode('utf8') + + for line in out.split('\n'): + line = line.strip() + if line.startswith(IND_VER_LINE): + ver_str = line.strip()[len(IND_VER_LINE):] + break + + if not ver_str: + raise OSError('Unknown format of swig -version output:\n%s' % out) + + return StrictVersion(ver_str) >= StrictVersion(req_ver) + + +x_comp_args = set() - if not swig_sources: - return new_sources +# We take care of deprecated functions in OpenSSL with our code, no need +# to spam compiler output with it. +if sys.platform == 'win32': + x_comp_args.update(['-DTHREADING', '-D_CRT_SECURE_NO_WARNINGS']) +else: + x_comp_args.update(['-DTHREADING', '-Wno-deprecated-declarations']) - swig = self.find_swig() - swig_cmd = [swig, "-python", "-ISWIG"] - if self.swig_cpp: - swig_cmd.append("-c++") +# Don't try to run swig on the ancient platforms +if swig_version(REQUIRED_SWIG_VERSION): + lib_sources = ['SWIG/_m2crypto.i'] +else: + lib_sources = ['SWIG/_m2crypto_wrap.c'] - swig_cmd += self.swig_opts - for source in swig_sources: - target = swig_targets[source] - self.announce("swigging %s to %s" % (source, target)) - self.spawn(swig_cmd + ["-o", target, source]) +m2crypto = setuptools.Extension(name='M2Crypto._m2crypto', + sources=lib_sources, + extra_compile_args=list(x_comp_args), + # Uncomment to build Universal Mac binaries + # extra_link_args = + # ['-Wl,-search_paths_first'], + ) - return new_sources - - build_ext.build_ext.swig_sources = swig_sources +class Clean(clean): + def __init__(self, dist): + clean.__init__(self, dist) -m2crypto = Extension(name = 'M2Crypto.__m2crypto', - sources = ['SWIG/_m2crypto.i'], - extra_compile_args = ['-DTHREADING'], - #extra_link_args = ['-Wl,-search_paths_first'], # Uncomment to build Universal Mac binaries - ) + def initialize_options(self): + clean.initialize_options(self) + self.all = True + + def finalize_options(self): + clean.finalize_options(self) + + def run(self): + clean.run(self) + garbage_list = [ + os.path.join('M2Crypto', '*.so'), + os.path.join('M2Crypto', '*.pyd'), + os.path.join('M2Crypto', '*.dll') + ] + for p in garbage_list: + for f in glob.glob(p): + if os.path.exists(f): + os.unlink(f) -setup(name = 'M2Crypto', - version = '0.21.1', - description = 'M2Crypto: A Python crypto and SSL toolkit', - long_description = '''\ +def __get_version(): # noqa + with open('M2Crypto/__init__.py') as init_file: + for line in init_file: + if line.startswith('__version__ ='): + return line.split('=')[1].strip(string.whitespace + "'") + + +long_description_text = '''\ M2Crypto is the most complete Python wrapper for OpenSSL featuring RSA, DSA, DH, EC, HMACs, message digests, symmetric ciphers (including AES); SSL functionality to implement clients and servers; HTTPS extensions to Python's httplib, urllib, and xmlrpclib; unforgeable HMAC'ing AuthCookies for web -session management; FTP/TLS client and server; S/MIME; ZServerSSL: A HTTPS -server for Zope and ZSmime: An S/MIME messenger for Zope. M2Crypto can also be -used to provide SSL for Twisted.''', - license = 'BSD-style license', - platforms = ['any'], - author = 'Ng Pheng Siong', - author_email = 'ngps at sandbox rulemaker net', - maintainer = 'Heikki Toivonen', - maintainer_email = 'heikki@osafoundation.org', - url = 'http://chandlerproject.org/Projects/MeTooCrypto', - packages = ['M2Crypto', 'M2Crypto.SSL', 'M2Crypto.PGP'], - classifiers = [ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Operating System :: OS Independent', - 'Programming Language :: C', - 'Programming Language :: Python', - 'Topic :: Security :: Cryptography', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - - ext_modules = [m2crypto], - test_suite='tests.alltests.suite', - cmdclass = {'build_ext': _M2CryptoBuildExt} - ) +session management; FTP/TLS client and server; S/MIME; M2Crypto can also be +used to provide SSL for Twisted. Smartcards supported through the Engine +interface.''' + +setuptools.setup( + name='M2Crypto', + version=__get_version(), + description='M2Crypto: A Python crypto and SSL toolkit', + long_description=long_description_text, + license='MIT', + platforms=['any'], + author='Ng Pheng Siong', + author_email='ngps@sandbox.rulemaker.net', + maintainer='Matej Cepl', + maintainer_email='mcepl@cepl.eu', + url='https://gitlab.com/m2crypto/m2crypto', + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: OS Independent', + 'Programming Language :: C', + 'Programming Language :: Python', + 'Topic :: Security :: Cryptography', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + ], + keywords='cryptography openssl', + packages=setuptools.find_packages(exclude=['contrib', 'docs', 'tests']), + ext_modules=[m2crypto], + test_suite='tests.alltests.suite', + install_requires=requires_list, + package_data=package_data, + cmdclass={ + 'build_ext': _M2CryptoBuildExt, + 'build': _M2CryptoBuild, + 'clean': Clean + } +) diff --git a/tests/__init__.py b/tests/__init__.py index e69de29..688264f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,16 @@ +import logging +import os.path +import sys + +if sys.version_info[:2] <= (2, 6): + sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(__file__)), + 'vendor')) + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', + level=logging.DEBUG) diff --git a/tests/alltests.py b/tests/alltests.py index b35e58f..141cd88 100644 --- a/tests/alltests.py +++ b/tests/alltests.py @@ -1,10 +1,11 @@ -#!/usr/bin/env python +from __future__ import absolute_import, print_function + def suite(): - from M2Crypto import m2 + from M2Crypto import m2 # noqa import os import unittest - + def my_import(name): # See http://docs.python.org/lib/built-in-funcs.html#l2h-6 components = name.split('.') @@ -19,6 +20,7 @@ def suite(): return mod modules_to_test = [ + 'tests.test_aes', 'tests.test_asn1', 'tests.test_bio', 'tests.test_bio_membuf', @@ -30,16 +32,18 @@ def suite(): 'tests.test_dh', 'tests.test_dsa', 'tests.test_engine', + 'tests.test_err', 'tests.test_evp', 'tests.test_obj', - 'tests.test_pgp', 'tests.test_rand', 'tests.test_rc4', 'tests.test_rsa', 'tests.test_smime', 'tests.test_ssl_offline', 'tests.test_threading', - 'tests.test_x509'] + 'tests.test_util', + 'tests.test_x509', + 'tests.test_timeout'] if os.name == 'posix': modules_to_test.append('tests.test_ssl') elif os.name == 'nt': @@ -51,50 +55,52 @@ def suite(): alltests = unittest.TestSuite() for module in map(my_import, modules_to_test): alltests.addTest(module.suite()) + + print('Version of OpenSSL is {0:x} ({1:s})'.format(m2.OPENSSL_VERSION_NUMBER, + m2.OPENSSL_VERSION_TEXT)) + return alltests def dump_garbage(): import gc - print '\nGarbage:' + print('\nGarbage:') gc.collect() if len(gc.garbage): - - print '\nLeaked objects:' + + print('\nLeaked objects:') for x in gc.garbage: s = str(x) - if len(s) > 77: s = s[:73]+'...' - print type(x), '\n ', s - - print 'There were %d leaks.' % len(gc.garbage) + if len(s) > 77: + s = s[:73] + '...' + print(type(x), '\n ', s) + + print('There were %d leaks.' % len(gc.garbage)) else: - print 'Python garbage collector did not detect any leaks.' - print 'However, it is still possible there are leaks in the C code.' + print('Python garbage collector did not detect any leaks.') + print('However, it is still possible there are leaks in the C code.') def runall(report_leaks=0): report_leaks = report_leaks - + if report_leaks: import gc gc.enable() gc.set_debug(gc.DEBUG_LEAK & ~gc.DEBUG_SAVEALL) - - import os, unittest + + import os + import unittest from M2Crypto import Rand - + try: - Rand.load_file('tests/randpool.dat', -1) + Rand.load_file('tests/randpool.dat', -1) unittest.TextTestRunner(verbosity=2).run(suite()) Rand.save_file('tests/randpool.dat') finally: if os.name == 'posix': - from test_ssl import zap_servers + from .test_ssl import zap_servers zap_servers() if report_leaks: dump_garbage() - - -if __name__ == '__main__': - runall(0) diff --git a/tests/bad_date_cert.crt b/tests/bad_date_cert.crt new file mode 100644 index 0000000..649f2e1 --- /dev/null +++ b/tests/bad_date_cert.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIJAPd8QvAqguI9MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV +BAMMCWxvY2FsaG9zdDAgFw0xNjAzMDQxNDU3NDZaGA8yMTE2MDIwOTE0NTc0Nlow +FDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAsyy/9CI++wVV22U3xor0Hi1nUUusa8Or/a/ppTpgAH0UREcvKrfSCQU0 +cCPbYg2M3Jn+tQlcs3eAfUFnyz4XCDlMnns8iKse6kkzQQpx+budUwAamP21bHa6 +8dMwDFT3+z9LxDstqdbsvW+KzQwyuYCsWnp6l2KRNy1P4wt7gVvnm5+GCGRMo89L +yWJ6iz21XZt6wsafPArKclxVzkzW6Li7JvMaJWyJstSlDaGMlAORUbbO78/VYVYD +idhqtgN+s1rnHZEMKU0io2pTkVTYVVU6hkGvx7OxChVd8ZYQdptYu1jqB4DS9Ima +tNLZZMnBh9aAwZAEWLku8N1EV/pfyQIDAQABo1AwTjAdBgNVHQ4EFgQUWc4wUp+0 +e1cC0gY3DCtCx1ECCgswHwYDVR0jBBgwFoAUWc4wUp+0e1cC0gY3DCtCx1ECCgsw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABmFTO2Q+6VqzQ3Td4Xp4 +TwJ25WJWf/n5E/sY96Z4iG5ABzPEo4jzsx6DQzcxQ445nu62/OHtmF8y8abZWk0/ +KTmTMEl0+z9ab48zHIjp7WkXcUGxHfbIApI8tmYXn/y1+zEtG5+bRXcAODce0pRL +CqWvlchiwLhlao0Pe8Gz1DV7feS/or9XojE8+sokSiuRFGIcwIzpYX/hja4Xtsmc +Z/PUfodHmpKW+c559cn9pnVjJjhjXpKqDrgE2l9jtTwRVLQOGMxcISvfoNwu833z +OJJ1gyor9okGBpmackBUpwpWD7s6tBwkcMo2sJZGD/Kfv1ncYuRXqa6+tQaHxJRS +LA== +-----END CERTIFICATE----- diff --git a/tests/ca.pem b/tests/ca.pem index 5450a68..a1ec319 100644 --- a/tests/ca.pem +++ b/tests/ca.pem @@ -1,62 +1,101 @@ Certificate: Data: Version: 3 (0x2) - Serial Number: - d1:b6:bf:af:06:17:8c:bd - Signature Algorithm: sha1WithRSAEncryption + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity - Not Before: Jul 28 04:30:50 2009 GMT - Not After : Jul 27 04:30:50 2012 GMT + Not Before: Oct 7 15:12:02 2018 GMT + Not After : Oct 4 15:12:02 2028 GMT Subject: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public Key: (1024 bit) - Modulus (1024 bit): - 00:c8:9b:59:18:c2:bf:21:68:dc:d4:62:30:1f:43: - 29:52:85:8d:36:fc:20:7f:11:1b:c6:f3:e6:c2:7a: - d0:17:0e:6e:78:43:21:e9:e2:df:9f:31:87:e8:7a: - 37:88:1f:a4:56:a1:e9:cb:13:7b:1b:c0:28:cf:5a: - db:a3:e7:50:6c:c6:55:76:e3:61:e8:73:4b:c2:8c: - ee:1c:29:c1:ee:2d:fd:e2:30:34:69:06:ea:d0:af: - bd:c5:db:86:70:92:26:0a:33:1b:70:a9:e7:6e:a4: - 2e:ee:4a:8a:f3:b2:6c:c9:97:28:39:28:28:3f:c5: - 90:4d:4e:83:0a:0e:cd:98:93 + RSA Public-Key: (2048 bit) + Modulus: + 00:b8:14:c3:7e:10:d4:0e:55:5e:8c:5c:14:07:14: + da:a6:32:d4:35:37:23:7c:27:bd:29:69:4a:dd:ee: + a7:9f:f3:7f:1b:f4:73:3d:0b:89:6a:a1:f7:35:ac: + b0:20:42:b8:e6:f5:36:9f:83:d9:d6:d0:45:b9:60: + 0c:a9:dd:f6:28:b9:c4:b7:02:ee:63:cc:ba:3a:70: + 0c:34:75:46:9d:f1:7b:d5:5f:46:17:84:94:fc:00: + f6:21:c3:e2:cd:6c:d1:33:bf:d9:c2:1c:5f:c8:af: + 91:20:0b:ed:c9:68:44:00:45:ec:9e:82:5a:62:c2: + a7:53:de:58:db:7d:d5:2c:9e:8f:7c:15:b4:34:30: + ab:b7:3d:ed:72:a2:5c:4a:51:d1:85:33:ad:e0:23: + e9:12:02:b9:64:0b:d8:de:61:f8:d9:18:4e:43:32: + 73:d0:f2:df:c6:de:28:cf:f5:48:7e:46:7c:85:c6: + 1e:96:a2:32:b8:16:ff:96:71:81:a7:d1:87:d2:d9: + 0e:b8:9f:ad:45:14:a1:d3:b9:52:c8:59:63:77:17: + fe:22:ac:f9:c1:97:12:97:98:99:ae:ac:48:1b:97: + 83:fa:88:e0:63:9b:bc:55:ea:e0:c7:ec:55:28:e9: + 28:2a:b4:be:08:e1:50:43:4e:41:df:10:b7:98:1e: + dd:37 Exponent: 65537 (0x10001) X509v3 extensions: - X509v3 Subject Key Identifier: - AD:64:45:74:8F:83:C7:2C:D5:D7:A0:85:91:10:40:9A:9C:96:CF:EE - X509v3 Authority Key Identifier: - keyid:AD:64:45:74:8F:83:C7:2C:D5:D7:A0:85:91:10:40:9A:9C:96:CF:EE - DirName:/C=US/ST=California/O=M2Crypto/CN=Heikki Toivonen - serial:D1:B6:BF:AF:06:17:8C:BD - X509v3 Basic Constraints: CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - c8:11:af:7d:6d:fb:1c:82:0d:c0:e7:41:f4:b2:a5:b0:69:6d: - 18:e3:04:aa:49:e6:4a:69:6d:c3:e3:8b:ab:d1:18:ac:72:ef: - 48:9e:49:c7:57:75:2d:00:1e:08:9f:c3:dc:ca:5f:91:38:0d: - ac:f8:1f:cc:fc:f7:c2:5b:ce:d7:0c:cf:b2:fe:c9:a9:ce:b8: - 07:45:17:1c:cf:b3:07:f9:1f:69:6a:94:03:be:62:62:9c:af: - a2:24:25:2d:1f:63:0a:91:6b:bb:e3:6c:ec:20:de:80:d3:04: - b4:5e:42:1f:27:bc:1f:79:98:18:ba:fb:8a:34:24:a9:40:1e: - b9:7b + X509v3 Subject Key Identifier: + 49:6E:7E:9B:16:48:9F:E9:B8:A7:DC:7C:0E:73:F6:26:2A:9C:9D:7C + Signature Algorithm: sha256WithRSAEncryption + a5:88:b0:1a:e3:fc:89:21:8f:d2:3f:39:5d:bd:84:1c:c9:1b: + 58:16:8d:cc:f7:9d:6d:f1:19:29:05:51:c6:20:c5:cc:00:d5: + 61:5f:8f:de:64:3a:43:81:eb:b2:21:7a:ec:19:6b:21:30:33: + bc:a3:7b:f7:2a:49:f5:8b:d3:48:dc:65:f0:29:f2:fd:3c:f5: + 03:37:19:a3:56:d5:3c:42:60:29:df:ab:aa:36:95:16:eb:6c: + f2:2d:22:ca:5c:0d:e7:14:6e:f3:10:70:b9:d2:82:59:68:9e: + 31:9d:39:f2:8a:6e:00:c3:2c:b5:ed:f9:fa:6f:f4:43:f1:98: + 81:f3:89:ef:23:6d:fc:f1:33:2f:d7:fc:cc:28:2a:dd:3e:da: + 27:8a:1f:5e:a9:7a:df:2e:c1:e5:c6:db:a9:74:c2:e2:9c:3e: + 9b:2c:22:b1:2e:5d:90:09:c9:45:95:35:21:ca:08:12:19:4c: + 8d:ca:a5:1d:2b:55:b3:44:d5:43:5d:86:bc:36:4c:e6:7a:29: + b6:21:ab:e8:a2:23:ec:e4:00:a0:6b:0f:bd:d5:77:64:64:30: + ed:d7:31:88:18:91:24:08:7b:9b:0f:62:8f:31:5c:11:f1:df: + d3:2d:e6:52:27:11:a0:8a:f9:5e:a9:a3:ea:e3:0c:83:56:2b: + 95:6b:b9:f6 -----BEGIN CERTIFICATE----- -MIICzjCCAjegAwIBAgIJANG2v68GF4y9MA0GCSqGSIb3DQEBBQUAME8xCzAJBgNV -BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQKEwhNMkNyeXB0bzEY -MBYGA1UEAxMPSGVpa2tpIFRvaXZvbmVuMB4XDTA5MDcyODA0MzA1MFoXDTEyMDcy -NzA0MzA1MFowTzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAP -BgNVBAoTCE0yQ3J5cHRvMRgwFgYDVQQDEw9IZWlra2kgVG9pdm9uZW4wgZ8wDQYJ -KoZIhvcNAQEBBQADgY0AMIGJAoGBAMibWRjCvyFo3NRiMB9DKVKFjTb8IH8RG8bz -5sJ60BcObnhDIeni358xh+h6N4gfpFah6csTexvAKM9a26PnUGzGVXbjYehzS8KM -7hwpwe4t/eIwNGkG6tCvvcXbhnCSJgozG3Cp526kLu5KivOybMmXKDkoKD/FkE1O -gwoOzZiTAgMBAAGjgbEwga4wHQYDVR0OBBYEFK1kRXSPg8cs1deghZEQQJqcls/u -MH8GA1UdIwR4MHaAFK1kRXSPg8cs1deghZEQQJqcls/uoVOkUTBPMQswCQYDVQQG -EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEChMITTJDcnlwdG8xGDAW -BgNVBAMTD0hlaWtraSBUb2l2b25lboIJANG2v68GF4y9MAwGA1UdEwQFMAMBAf8w -DQYJKoZIhvcNAQEFBQADgYEAyBGvfW37HIINwOdB9LKlsGltGOMEqknmSmltw+OL -q9EYrHLvSJ5Jx1d1LQAeCJ/D3MpfkTgNrPgfzPz3wlvO1wzPsv7Jqc64B0UXHM+z -B/kfaWqUA75iYpyvoiQlLR9jCpFru+Ns7CDegNMEtF5CHye8H3mYGLr7ijQkqUAe -uXs= +MIIDSDCCAjCgAwIBAgIBADANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM +D0hlaWtraSBUb2l2b25lbjAeFw0xODEwMDcxNTEyMDJaFw0yODEwMDQxNTEyMDJa +ME8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN +MkNyeXB0bzEYMBYGA1UEAwwPSGVpa2tpIFRvaXZvbmVuMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAuBTDfhDUDlVejFwUBxTapjLUNTcjfCe9KWlK3e6n +n/N/G/RzPQuJaqH3NaywIEK45vU2n4PZ1tBFuWAMqd32KLnEtwLuY8y6OnAMNHVG +nfF71V9GF4SU/AD2IcPizWzRM7/ZwhxfyK+RIAvtyWhEAEXsnoJaYsKnU95Y233V +LJ6PfBW0NDCrtz3tcqJcSlHRhTOt4CPpEgK5ZAvY3mH42RhOQzJz0PLfxt4oz/VI +fkZ8hcYelqIyuBb/lnGBp9GH0tkOuJ+tRRSh07lSyFljdxf+Iqz5wZcSl5iZrqxI +G5eD+ojgY5u8Vergx+xVKOkoKrS+COFQQ05B3xC3mB7dNwIDAQABoy8wLTAMBgNV +HRMEBTADAQH/MB0GA1UdDgQWBBRJbn6bFkif6bin3HwOc/YmKpydfDANBgkqhkiG +9w0BAQsFAAOCAQEApYiwGuP8iSGP0j85Xb2EHMkbWBaNzPedbfEZKQVRxiDFzADV +YV+P3mQ6Q4HrsiF67BlrITAzvKN79ypJ9YvTSNxl8Cny/Tz1AzcZo1bVPEJgKd+r +qjaVFuts8i0iylwN5xRu8xBwudKCWWieMZ058opuAMMste35+m/0Q/GYgfOJ7yNt +/PEzL9f8zCgq3T7aJ4ofXql63y7B5cbbqXTC4pw+mywisS5dkAnJRZU1IcoIEhlM +jcqlHStVs0TVQ12GvDZM5noptiGr6KIj7OQAoGsPvdV3ZGQw7dcxiBiRJAh7mw9i +jzFcEfHf0y3mUicRoIr5Xqmj6uMMg1YrlWu59g== -----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAuBTDfhDUDlVejFwUBxTapjLUNTcjfCe9KWlK3e6nn/N/G/Rz +PQuJaqH3NaywIEK45vU2n4PZ1tBFuWAMqd32KLnEtwLuY8y6OnAMNHVGnfF71V9G +F4SU/AD2IcPizWzRM7/ZwhxfyK+RIAvtyWhEAEXsnoJaYsKnU95Y233VLJ6PfBW0 +NDCrtz3tcqJcSlHRhTOt4CPpEgK5ZAvY3mH42RhOQzJz0PLfxt4oz/VIfkZ8hcYe +lqIyuBb/lnGBp9GH0tkOuJ+tRRSh07lSyFljdxf+Iqz5wZcSl5iZrqxIG5eD+ojg +Y5u8Vergx+xVKOkoKrS+COFQQ05B3xC3mB7dNwIDAQABAoIBAQCISU8nYbwuVIQo +tO9bAtSS4eT89TK/dAh3xW3ZfBz8rmF4R/adxpHZscp+IblQWTXeQMRNO2gnw5Er +mvIlPaFHK6p5uKDYoLVsGJLgr8c1npkJM32IYe+P2AJio02iu6LzhmHpdepwgZOX +v10wlZJrBVoXTPkwT19lF6R/9NzEJ+qyceixwIUFlqKzFv+LavFL4elP03OVF5Wu +TN2DTaVJzNdpBVGdYKkJX7GhX28/gaDRZw6B2wJoJhl56uhzibNe9Lc0S9nyt+0Y +ARodv5KVTaM07z4LkFQxIliVFJmR8Bin3CHC36K9ike57srkR/BOR13Vxw9EtUHx +tNe11jy5AoGBAOVo1NHwHT7EH06F3O2MvKYJAa5rm8EU9Eq6d70ylVDKHCu2NA9V +KeeUbXxGK9Bk3RhLVevZv870AgZqtD4sUEg3qMrW3ZQHyyAlZq57AAw9GlL8REZv +aWvDE4/fmpNYVyUrpQ9KIyaZa96VZtqUJbLgzcvQsRhiwo2zQAP9UqL9AoGBAM1q +7DJtTqU1Muk5UWc8XS6HxRf0D5c1240UXP1xkRDCfI2lI3AM3sCQ5iKQP/SsOrvK +KgxQDVykdbTqD5F7QDX8BmYTdALzRm/XyqqY52WljDAwNEsdTLPewffDMRhjSBSw +sjPiHMnmXJH+0uKKUrSdvDsElBQASKQ81Ojg+ZlDAoGAS2HiJMYQ5hIN84B7Mze+ +uZRWEBleCdk32OJi/DGF7REsppRtkOg8J9OXEnIAba7nE9eVeTWJGJkHnVIsvg1T +qBdaCKUIFF9nOL3xer4CKwNdBg3M5ZQwgO+OGwWvxmEN6bHowBhtan6Zen9/V628 +oYXLOgDuYIP7SBKxo133bIUCgYEAj4hTrFSmbFfE0CQF1k3eimHB/R/DORQf6e89 +nrYY+A39e/fU0Dmd+A4HUEVc+vjRPWBgiyPwgjhEKvqVkED/t/j2+6JCIMGeCQ5O +hW+72FGZqB42m/nIG7Ld8+KGzpSozBQ/IHOxS/5T1oupDTQ74AqLeO2VDni4SVJc +LrDslwMCgYEArxtk6NGesCUgdCTHEueubcY8VoXn/DOHi1QpqV/Fq93Fs5AkDwle +yI11+KVvXad2UAZI2LcQsN3P12Wdco0ayfHOSpOf8zv1w+/DyDkrcT10ZxgL9EDJ +eBEgQ+XmPoteMubMr6EQrzfXxzKqK/DN+2mq0s7PAFgHOr31g6feLYI= +-----END RSA PRIVATE KEY----- diff --git a/tests/ca_key.pem b/tests/ca_key.pem new file mode 100644 index 0000000..a5525db --- /dev/null +++ b/tests/ca_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAuBTDfhDUDlVejFwUBxTapjLUNTcjfCe9KWlK3e6nn/N/G/Rz +PQuJaqH3NaywIEK45vU2n4PZ1tBFuWAMqd32KLnEtwLuY8y6OnAMNHVGnfF71V9G +F4SU/AD2IcPizWzRM7/ZwhxfyK+RIAvtyWhEAEXsnoJaYsKnU95Y233VLJ6PfBW0 +NDCrtz3tcqJcSlHRhTOt4CPpEgK5ZAvY3mH42RhOQzJz0PLfxt4oz/VIfkZ8hcYe +lqIyuBb/lnGBp9GH0tkOuJ+tRRSh07lSyFljdxf+Iqz5wZcSl5iZrqxIG5eD+ojg +Y5u8Vergx+xVKOkoKrS+COFQQ05B3xC3mB7dNwIDAQABAoIBAQCISU8nYbwuVIQo +tO9bAtSS4eT89TK/dAh3xW3ZfBz8rmF4R/adxpHZscp+IblQWTXeQMRNO2gnw5Er +mvIlPaFHK6p5uKDYoLVsGJLgr8c1npkJM32IYe+P2AJio02iu6LzhmHpdepwgZOX +v10wlZJrBVoXTPkwT19lF6R/9NzEJ+qyceixwIUFlqKzFv+LavFL4elP03OVF5Wu +TN2DTaVJzNdpBVGdYKkJX7GhX28/gaDRZw6B2wJoJhl56uhzibNe9Lc0S9nyt+0Y +ARodv5KVTaM07z4LkFQxIliVFJmR8Bin3CHC36K9ike57srkR/BOR13Vxw9EtUHx +tNe11jy5AoGBAOVo1NHwHT7EH06F3O2MvKYJAa5rm8EU9Eq6d70ylVDKHCu2NA9V +KeeUbXxGK9Bk3RhLVevZv870AgZqtD4sUEg3qMrW3ZQHyyAlZq57AAw9GlL8REZv +aWvDE4/fmpNYVyUrpQ9KIyaZa96VZtqUJbLgzcvQsRhiwo2zQAP9UqL9AoGBAM1q +7DJtTqU1Muk5UWc8XS6HxRf0D5c1240UXP1xkRDCfI2lI3AM3sCQ5iKQP/SsOrvK +KgxQDVykdbTqD5F7QDX8BmYTdALzRm/XyqqY52WljDAwNEsdTLPewffDMRhjSBSw +sjPiHMnmXJH+0uKKUrSdvDsElBQASKQ81Ojg+ZlDAoGAS2HiJMYQ5hIN84B7Mze+ +uZRWEBleCdk32OJi/DGF7REsppRtkOg8J9OXEnIAba7nE9eVeTWJGJkHnVIsvg1T +qBdaCKUIFF9nOL3xer4CKwNdBg3M5ZQwgO+OGwWvxmEN6bHowBhtan6Zen9/V628 +oYXLOgDuYIP7SBKxo133bIUCgYEAj4hTrFSmbFfE0CQF1k3eimHB/R/DORQf6e89 +nrYY+A39e/fU0Dmd+A4HUEVc+vjRPWBgiyPwgjhEKvqVkED/t/j2+6JCIMGeCQ5O +hW+72FGZqB42m/nIG7Ld8+KGzpSozBQ/IHOxS/5T1oupDTQ74AqLeO2VDni4SVJc +LrDslwMCgYEArxtk6NGesCUgdCTHEueubcY8VoXn/DOHi1QpqV/Fq93Fs5AkDwle +yI11+KVvXad2UAZI2LcQsN3P12Wdco0ayfHOSpOf8zv1w+/DyDkrcT10ZxgL9EDJ +eBEgQ+XmPoteMubMr6EQrzfXxzKqK/DN+2mq0s7PAFgHOr31g6feLYI= +-----END RSA PRIVATE KEY----- diff --git a/tests/easy_rsa.pem b/tests/easy_rsa.pem new file mode 100644 index 0000000..0028c63 --- /dev/null +++ b/tests/easy_rsa.pem @@ -0,0 +1,74 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, ST=NC, L=Raleigh, O=Fedora Project, OU=fedmsg, CN=fedmsg/name=fedmsg/emailAddress=admin@fedoraproject.org + Validity + Not Before: Jul 15 21:18:52 2012 GMT + Not After : Jul 13 21:18:52 2022 GMT + Subject: C=US, ST=NC, L=Raleigh, O=Fedora Project, OU=fedmsg, CN=shell-app01.phx2.fedoraproject.org/name=shell-app01.phx2.fedoraproject.org/emailAddress=admin@fedoraproject.org + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:c9:5d:32:76:f9:e8:a4:84:e6:16:cd:24:7e:99: + 68:2a:3e:a7:5b:4f:c2:3b:3a:74:ac:3c:30:be:e5: + 99:17:62:83:76:5d:40:79:15:b3:7e:ca:4e:40:e5: + 88:2b:95:7e:a3:6a:b1:60:0e:ad:6a:22:b8:6c:f7: + f2:95:82:f5:20:62:30:95:53:fd:99:ae:73:c2:44: + 6f:5a:47:ad:5a:31:8e:46:9e:41:ee:0e:e8:10:24: + 0e:06:8d:e0:9d:0b:74:51:fe:53:58:04:35:e9:69: + f4:6c:2a:c8:41:2a:8e:59:52:92:70:af:6f:52:4f: + e8:a2:65:25:01:96:e4:b0:47 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + Easy-RSA Generated Certificate + X509v3 Subject Key Identifier: + 77:71:57:05:B0:F6:25:6D:EA:72:6A:BE:E5:53:FB:19:CB:B1:1C:5E + X509v3 Authority Key Identifier: + keyid:00:98:A5:D5:E7:C4:55:0E:84:A3:67:FE:66:4A:16:E0:04:15:DD:21 + DirName:/C=US/ST=NC/L=Raleigh/O=Fedora Project/OU=fedmsg/CN=fedmsg/name=fedmsg/emailAddress=admin@fedoraproject.org + serial:8E:EB:28:D8:A9:13:9D:7C + + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Key Usage: + Digital Signature + Signature Algorithm: sha1WithRSAEncryption + 11:b5:cc:6f:e5:cd:8c:b3:fe:98:61:44:ea:ba:9f:39:37:41: + 45:5e:34:6c:b1:15:dc:71:a0:1e:7b:8f:8c:43:8b:ad:32:cf: + 2d:b2:01:87:bd:b3:0a:a5:2f:51:a4:f6:38:c0:e3:f6:5f:fe: + 52:cf:17:13:8c:f8:d8:a7:4c:e8:7f:a3:ac:f4:6c:40:41:0a: + e7:f0:14:a8:92:fa:e8:3f:a6:3b:08:a3:af:6f:0b:4d:c5:db: + 54:b4:a6:ab:8c:f1:b4:23:71:da:00:e6:ae:69:76:26:3f:06: + ae:47:50:b9:a8:b3:20:3e:10:db:ba:f6:8b:d0:19:96:54:88: + 96:ff +-----BEGIN CERTIFICATE----- +MIIESTCCA7KgAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBoDELMAkGA1UEBhMCVVMx +CzAJBgNVBAgTAk5DMRAwDgYDVQQHEwdSYWxlaWdoMRcwFQYDVQQKEw5GZWRvcmEg +UHJvamVjdDEPMA0GA1UECxMGZmVkbXNnMQ8wDQYDVQQDEwZmZWRtc2cxDzANBgNV +BCkTBmZlZG1zZzEmMCQGCSqGSIb3DQEJARYXYWRtaW5AZmVkb3JhcHJvamVjdC5v +cmcwHhcNMTIwNzE1MjExODUyWhcNMjIwNzEzMjExODUyWjCB2DELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAk5DMRAwDgYDVQQHEwdSYWxlaWdoMRcwFQYDVQQKEw5GZWRv +cmEgUHJvamVjdDEPMA0GA1UECxMGZmVkbXNnMSswKQYDVQQDEyJzaGVsbC1hcHAw +MS5waHgyLmZlZG9yYXByb2plY3Qub3JnMSswKQYDVQQpEyJzaGVsbC1hcHAwMS5w +aHgyLmZlZG9yYXByb2plY3Qub3JnMSYwJAYJKoZIhvcNAQkBFhdhZG1pbkBmZWRv +cmFwcm9qZWN0Lm9yZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyV0ydvno +pITmFs0kfploKj6nW0/COzp0rDwwvuWZF2KDdl1AeRWzfspOQOWIK5V+o2qxYA6t +aiK4bPfylYL1IGIwlVP9ma5zwkRvWketWjGORp5B7g7oECQOBo3gnQt0Uf5TWAQ1 +6Wn0bCrIQSqOWVKScK9vUk/oomUlAZbksEcCAwEAAaOCAVcwggFTMAkGA1UdEwQC +MAAwLQYJYIZIAYb4QgENBCAWHkVhc3ktUlNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0 +ZTAdBgNVHQ4EFgQUd3FXBbD2JW3qcmq+5VP7GcuxHF4wgdUGA1UdIwSBzTCByoAU +AJil1efEVQ6Eo2f+ZkoW4AQV3SGhgaakgaMwgaAxCzAJBgNVBAYTAlVTMQswCQYD +VQQIEwJOQzEQMA4GA1UEBxMHUmFsZWlnaDEXMBUGA1UEChMORmVkb3JhIFByb2pl +Y3QxDzANBgNVBAsTBmZlZG1zZzEPMA0GA1UEAxMGZmVkbXNnMQ8wDQYDVQQpEwZm +ZWRtc2cxJjAkBgkqhkiG9w0BCQEWF2FkbWluQGZlZG9yYXByb2plY3Qub3JnggkA +juso2KkTnXwwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCwYDVR0PBAQDAgeAMA0GCSqG +SIb3DQEBBQUAA4GBABG1zG/lzYyz/phhROq6nzk3QUVeNGyxFdxxoB57j4xDi60y +zy2yAYe9swqlL1Gk9jjA4/Zf/lLPFxOM+NinTOh/o6z0bEBBCufwFKiS+ug/pjsI +o69vC03F21S0pquM8bQjcdoA5q5pdiY/Bq5HULmosyA+ENu69ovQGZZUiJb/ +-----END CERTIFICATE----- diff --git a/tests/ec.priv.pem b/tests/ec.priv.pem index 2147d67..cddd1d7 100644 --- a/tests/ec.priv.pem +++ b/tests/ec.priv.pem @@ -1,5 +1,6 @@ -----BEGIN EC PRIVATE KEY----- -MG0CAQEEHXXhxMbflWHSfCjfxsqHTsIR+BVbREI6JFYGaUs0oAcGBSuBBAAaoUAD -PgAEAdJXSN/xnRiDqc4wSiYbWB7LGabs71Y9zzIE1ZbzAcvb7uxtoyUxrmRQC8xD -EO2qZX16mtpmgoNz3EeT +MIGkAgEBBDDYZmLKVOPc34hDebkYt5vGMQBcX+WtHbXxnncL6ptQtzgkWN1ePGA6 +x2HU8NFFpwigBwYFK4EEACKhZANiAASkekXfdAy+vfwcOvO0rwsVDWpil6EKYMlo +kdhqz1/kp7hiv5ppw3/LCwsst9CJUUvfAIsRI4qFvTBE0JR8FxLHKFJgasPRHZo9 +x5i2EG07MzSevyODOjtVBrklq6nQCao= -----END EC PRIVATE KEY----- diff --git a/tests/ec.pub.pem b/tests/ec.pub.pem index 4a08b59..288e181 100644 --- a/tests/ec.pub.pem +++ b/tests/ec.pub.pem @@ -1,4 +1,5 @@ -----BEGIN PUBLIC KEY----- -MFIwEAYHKoZIzj0CAQYFK4EEABoDPgAEAdJXSN/xnRiDqc4wSiYbWB7LGabs71Y9 -zzIE1ZbzAcvb7uxtoyUxrmRQC8xDEO2qZX16mtpmgoNz3EeT +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEpHpF33QMvr38HDrztK8LFQ1qYpehCmDJ +aJHYas9f5Ke4Yr+aacN/ywsLLLfQiVFL3wCLESOKhb0wRNCUfBcSxyhSYGrD0R2a +PceYthBtOzM0nr8jgzo7VQa5Jaup0Amq -----END PUBLIC KEY----- diff --git a/tests/fips.py b/tests/fips.py index 32eb75b..6b2ba3e 100644 --- a/tests/fips.py +++ b/tests/fips.py @@ -1,8 +1,5 @@ try: - f = open('/proc/sys/crypto/fips_enabled') - try: + with open('/proc/sys/crypto/fips_enabled') as f: fips_mode = int(f.read()) - finally: - f.close() -except Exception, e: +except (IOError, OSError): fips_mode = 0 diff --git a/tests/makecerts.py b/tests/makecerts.py new file mode 100755 index 0000000..e25a07b --- /dev/null +++ b/tests/makecerts.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python +# +# Create test certificates: +# +# ca.pem +# server.pem +# recipient.pem +# signer.pem +# x509.pem +# +from __future__ import print_function + +import hashlib +import os +import os.path +import sys +import time + +from M2Crypto import ASN1, EC, EVP, RSA, X509, m2, util + +t = int(time.time() + time.timezone) +before = ASN1.ASN1_TIME() +before.set_time(t) +after = ASN1.ASN1_TIME() +after.set_time(t + 60 * 60 * 24 * 365 * 10) # 10 years + +serial = 1 + + +def callback(self, *args): + return ' ' + + +def gen_identifier(cert, dig='sha256'): + instr = cert.get_pubkey().get_rsa().as_pem() + h = hashlib.new(dig) + h.update(instr) + digest = h.hexdigest().upper() + + return ":".join(digest[pos: pos + 2] for pos in range(0, 40, 2)) + + +def make_subject(cn=None, email=None): + sub = X509.X509_Name() + sub.C = 'US' + sub.ST = 'California' + sub.O = 'M2Crypto' + if cn is not None: + sub.CN = cn + else: + sub.CN = 'Heikki Toivonen' + if email is not None: + sub.Email = email + return sub + + +def req(name): + rsa = RSA.load_key(name + '_key.pem') + pk = EVP.PKey() + pk.assign_rsa(rsa) + reqqed = X509.Request() + reqqed.set_pubkey(pk) + reqqed.set_subject(make_subject()) + reqqed.sign(pk, 'sha256') + return reqqed, pk + + +def save_text_pem_key(cert, name, with_key=True): + with open(name + '.pem', 'wb') as f: + for line in cert.as_text(): + f.write(line.encode("ascii")) + f.write(cert.as_pem()) + if with_key: + with open(name + '_key.pem', 'rb') as key_f: + for line in key_f: + f.write(line) + + +def issue(request, ca, capk): + global serial + + pkey = request.get_pubkey() + sub = request.get_subject() + + cert = X509.X509() + cert.set_version(2) + cert.set_subject(sub) + cert.set_serial_number(serial) + serial += 1 + + issuer = ca.get_subject() + cert.set_issuer(issuer) + + cert.set_pubkey(pkey) + + cert.set_not_before(before) + cert.set_not_after(after) + + ext = X509.new_extension('basicConstraints', 'CA:FALSE') + cert.add_ext(ext) + + ext = X509.new_extension('subjectKeyIdentifier', + gen_identifier(cert)) + cert.add_ext(ext) + + # auth = X509.load_cert('ca.pem') + # auth_id = auth.get_ext('subjectKeyIdentifier').get_value() + # ext = X509.new_extension('authorityKeyIdentifier', 'keyid:%s' % auth_id) + # # cert.add_ext(ext) + + cert.sign(capk, 'sha256') + + assert cert.verify(capk) + + return cert + + +def mk_ca(): + r, pk = req('ca') + pkey = r.get_pubkey() + sub = r.get_subject() + + cert = X509.X509() + cert.set_version(2) + cert.set_subject(sub) + cert.set_serial_number(0) + + issuer = X509.X509_Name() + issuer.C = sub.C + issuer.ST = sub.ST + issuer.O = sub.O + issuer.CN = sub.CN + cert.set_issuer(issuer) + + cert.set_pubkey(pkey) + + cert.set_not_before(before) + cert.set_not_after(after) + + ext = X509.new_extension('basicConstraints', 'CA:TRUE') + cert.add_ext(ext) + + ski = gen_identifier(cert) + ext = X509.new_extension('subjectKeyIdentifier', ski) + cert.add_ext(ext) + + # ext = X509.new_extension('authorityKeyIdentifier', 'keyid:%s' % ski) + # cert.add_ext(ext) + + cert.sign(pk, 'sha256') + + save_text_pem_key(cert, 'ca') + + return cert, pk + + +def mk_server(ca, capk): + r, _ = req('server') + r.set_subject(make_subject(cn='localhost')) + cert = issue(r, ca, capk) + save_text_pem_key(cert, 'server') + + +def mk_x509(ca, capk): + r, _ = req('x509') + r.set_subject(make_subject(cn='X509')) + cert = issue(r, ca, capk) + save_text_pem_key(cert, 'x509') + + with open('x509.der', 'wb') as derf: + derf.write(cert.as_der()) + + +def mk_signer(ca, capk): + r, _ = req('signer') + r.set_subject(make_subject(cn='Signer', email='signer@example.com')) + cert = issue(r, ca, capk) + + save_text_pem_key(cert, 'signer', with_key=False) + + +def mk_recipient(ca, capk): + r, _ = req('recipient') + r.set_subject(make_subject(cn='Recipient', email='recipient@example.com')) + cert = issue(r, ca, capk) + save_text_pem_key(cert, 'recipient') + + +def mk_ec_pair(): + priv_key = EC.gen_params(EC.NID_secp384r1) + priv_key.gen_key() + priv_key.save_key('ec.priv.pem', + callback=util.no_passphrase_callback) + pub_key = priv_key.pub() + pub_key.save_pub_key('ec.pub.pem') + +if __name__ == '__main__': + names = ['ca', 'server', 'recipient', 'signer', 'x509'] + + os.chdir(os.path.dirname(sys.argv[0])) + + for key_name in names: + genned_key = RSA.gen_key(2048, m2.RSA_F4) + genned_key.save_key('%s_key.pem' % key_name, None) + + ca_bits, pk_bits = mk_ca() + mk_server(ca_bits, pk_bits) + mk_x509(ca_bits, pk_bits) + mk_signer(ca_bits, pk_bits) + mk_recipient(ca_bits, pk_bits) + + # FIXME This doesn't work well. + # mk_ec_pair() diff --git a/tests/recipient.pem b/tests/recipient.pem index d766266..0a03e4d 100644 --- a/tests/recipient.pem +++ b/tests/recipient.pem @@ -1,61 +1,102 @@ Certificate: Data: Version: 3 (0x2) - Serial Number: - d1:b6:bf:af:06:17:8c:c1 - Signature Algorithm: sha1WithRSAEncryption + Serial Number: 4 (0x4) + Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity - Not Before: Jul 28 04:39:19 2009 GMT - Not After : Jul 26 04:39:19 2019 GMT + Not Before: Oct 7 15:12:02 2018 GMT + Not After : Oct 4 15:12:02 2028 GMT Subject: C=US, ST=California, O=M2Crypto, CN=Recipient/emailAddress=recipient@example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public Key: (1024 bit) - Modulus (1024 bit): - 00:c2:21:a3:4f:64:59:9c:21:39:21:d2:3c:e7:0a: - 60:72:c8:39:b3:c3:27:4a:6d:56:8f:a0:5d:1b:c6: - e4:3e:26:61:09:a9:ae:04:83:69:3f:9d:2b:12:7e: - d4:f7:8e:d0:6e:a9:8c:9b:d1:bf:17:0c:bd:d0:73: - 99:02:6e:7e:cb:7a:80:2d:cf:b1:29:c0:30:36:3f: - 68:12:3e:4e:bf:f9:8b:3d:1d:56:af:24:94:ae:d5: - 59:b4:00:50:0c:c0:2b:59:c3:99:b3:8a:19:f1:86: - 14:bd:ee:e9:c4:f1:d7:6a:0c:e9:67:8a:94:9a:2d: - 2d:60:25:22:c6:72:68:c2:0d + RSA Public-Key: (2048 bit) + Modulus: + 00:cf:c6:83:2b:8c:ea:4e:10:7c:5a:c6:45:07:45: + f2:a6:17:55:33:f4:e8:24:df:4e:55:de:3d:0c:e6: + a0:a5:e0:b0:eb:bd:0e:55:2f:4e:f3:69:38:f0:31: + 1d:0d:54:0c:39:d6:da:37:89:4c:ab:c1:9c:10:9f: + 8d:e1:e6:c1:eb:ad:97:c0:8a:a2:4f:6f:e6:10:a0: + ad:f2:a0:11:4e:58:16:25:81:3a:5b:7d:6c:b4:e0: + 76:83:f2:67:eb:17:be:44:d9:5a:38:2c:2c:b6:f5: + 1a:d3:f5:48:85:6a:50:81:f1:74:0b:b1:22:92:cd: + e9:1f:fb:a3:1d:ec:03:be:1b:66:05:e9:24:4e:0a: + d7:7f:35:a3:92:d8:00:99:06:e9:ad:32:a0:df:7f: + 72:d0:de:82:f8:a7:7c:d7:41:73:68:97:7e:f3:de: + ea:73:e6:7e:0b:d8:eb:a6:4e:eb:a2:20:e0:2e:5a: + 8a:5e:79:b1:dd:e1:a6:64:3e:a2:7a:70:be:6a:5b: + 65:e8:bb:a0:d0:4c:00:b3:a4:aa:2f:c3:0a:30:4d: + 9e:d1:89:c2:c0:67:51:a0:13:a1:d3:0a:a4:db:82: + 85:96:dd:c9:06:49:68:c7:36:e6:ba:60:2a:de:71: + 36:5c:3b:16:a9:fe:c8:e3:91:48:6a:62:05:c1:b8: + 11:ef Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE - Netscape Comment: - OpenSSL Generated Certificate X509v3 Subject Key Identifier: - 11:CB:60:AC:55:85:52:84:C5:C8:20:5A:50:13:D0:89:C7:7A:B7:81 - X509v3 Authority Key Identifier: - keyid:AD:64:45:74:8F:83:C7:2C:D5:D7:A0:85:91:10:40:9A:9C:96:CF:EE - - Signature Algorithm: sha1WithRSAEncryption - 87:56:17:6d:ba:3b:a6:c4:22:af:20:f1:a0:e5:9d:27:c4:50: - bd:79:eb:d2:84:e5:9a:00:5f:5d:5a:c3:34:58:77:f5:a9:00: - f9:76:e9:2d:89:b4:3f:9d:e3:cf:15:0c:64:1b:0a:03:db:e4: - 6f:2b:ff:1c:82:89:1a:0f:7e:83:58:0f:e6:da:af:26:97:49: - 4a:59:d7:61:3f:4b:ed:1d:5b:51:00:3b:83:96:c7:1e:3d:84: - f4:91:1f:70:69:12:b9:a7:2c:5b:1b:05:cd:74:90:2b:a0:ba: - e7:70:cd:6b:7d:ac:be:d7:92:50:e9:f5:c0:42:29:04:ef:8f: - a1:68 + 24:C1:B1:83:79:31:5E:54:5E:60:65:04:17:FB:76:D3:21:85:3B:68 + Signature Algorithm: sha256WithRSAEncryption + 11:54:e9:1d:b4:5b:36:d8:40:63:45:58:f9:e8:29:53:ff:3e: + c9:3a:2a:89:b7:98:99:50:d4:29:96:03:e2:7e:16:1c:f7:86: + 2d:a3:92:2a:d8:60:16:d1:48:25:5d:9a:65:3e:27:16:c2:ca: + d9:20:62:88:d7:41:7a:9e:cc:bc:d3:a6:0a:af:d4:ea:14:72: + f1:00:13:ff:5a:a1:a1:d4:2e:89:76:98:23:28:60:1e:7f:6b: + 0c:a7:41:f6:56:d3:48:60:7a:63:9d:11:19:b7:57:60:b2:2a: + 23:a4:16:42:2f:9a:41:f3:3d:51:69:fc:30:c1:b2:34:26:89: + c3:b6:13:19:b9:ee:10:2c:52:36:b5:89:37:4b:ae:5a:76:b0: + ec:2c:c7:0f:8b:88:51:61:06:b7:9e:3b:df:d4:8e:2f:43:2d: + 34:79:51:5f:19:4c:21:b4:fc:db:99:c4:08:11:a1:5c:80:31: + 84:74:b5:0d:e2:3d:a4:e9:59:8d:f6:98:53:34:f1:df:18:0f: + c8:ce:42:47:fd:7d:3a:8b:c3:65:4e:e6:a1:40:0b:8b:0b:b4: + 5c:dd:1b:d2:56:c2:52:ab:08:c1:36:e4:e9:f4:b8:63:4f:f6: + 98:20:95:07:e5:d0:b3:f7:99:b4:ed:c7:ce:6a:3b:bb:19:94: + df:a5:ef:ce -----BEGIN CERTIFICATE----- -MIICtzCCAiCgAwIBAgIJANG2v68GF4zBMA0GCSqGSIb3DQEBBQUAME8xCzAJBgNV -BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQKEwhNMkNyeXB0bzEY -MBYGA1UEAxMPSGVpa2tpIFRvaXZvbmVuMB4XDTA5MDcyODA0MzkxOVoXDTE5MDcy -NjA0MzkxOVowbzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAP -BgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlSZWNpcGllbnQxJDAiBgkqhkiG9w0B -CQEWFXJlY2lwaWVudEBleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAwiGjT2RZnCE5IdI85wpgcsg5s8MnSm1Wj6BdG8bkPiZhCamuBINpP50r -En7U947QbqmMm9G/Fwy90HOZAm5+y3qALc+xKcAwNj9oEj5Ov/mLPR1WrySUrtVZ -tABQDMArWcOZs4oZ8YYUve7pxPHXagzpZ4qUmi0tYCUixnJowg0CAwEAAaN7MHkw -CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy -dGlmaWNhdGUwHQYDVR0OBBYEFBHLYKxVhVKExcggWlAT0InHereBMB8GA1UdIwQY -MBaAFK1kRXSPg8cs1deghZEQQJqcls/uMA0GCSqGSIb3DQEBBQUAA4GBAIdWF226 -O6bEIq8g8aDlnSfEUL1569KE5ZoAX11awzRYd/WpAPl26S2JtD+d488VDGQbCgPb -5G8r/xyCiRoPfoNYD+baryaXSUpZ12E/S+0dW1EAO4OWxx49hPSRH3BpErmnLFsb -Bc10kCuguudwzWt9rL7XklDp9cBCKQTvj6Fo +MIIDZTCCAk2gAwIBAgIBBDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM +D0hlaWtraSBUb2l2b25lbjAeFw0xODEwMDcxNTEyMDJaFw0yODEwMDQxNTEyMDJa +MG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN +MkNyeXB0bzESMBAGA1UEAwwJUmVjaXBpZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNp +cGllbnRAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDPxoMrjOpOEHxaxkUHRfKmF1Uz9Ogk305V3j0M5qCl4LDrvQ5VL07zaTjwMR0N +VAw51to3iUyrwZwQn43h5sHrrZfAiqJPb+YQoK3yoBFOWBYlgTpbfWy04HaD8mfr +F75E2Vo4LCy29RrT9UiFalCB8XQLsSKSzekf+6Md7AO+G2YF6SROCtd/NaOS2ACZ +BumtMqDff3LQ3oL4p3zXQXNol37z3upz5n4L2OumTuuiIOAuWopeebHd4aZkPqJ6 +cL5qW2Xou6DQTACzpKovwwowTZ7RicLAZ1GgE6HTCqTbgoWW3ckGSWjHNua6YCre +cTZcOxap/sjjkUhqYgXBuBHvAgMBAAGjLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYE +FCTBsYN5MV5UXmBlBBf7dtMhhTtoMA0GCSqGSIb3DQEBCwUAA4IBAQARVOkdtFs2 +2EBjRVj56ClT/z7JOiqJt5iZUNQplgPifhYc94Yto5Iq2GAW0UglXZplPicWwsrZ +IGKI10F6nsy806YKr9TqFHLxABP/WqGh1C6JdpgjKGAef2sMp0H2VtNIYHpjnREZ +t1dgsiojpBZCL5pB8z1RafwwwbI0JonDthMZue4QLFI2tYk3S65adrDsLMcPi4hR +YQa3njvf1I4vQy00eVFfGUwhtPzbmcQIEaFcgDGEdLUN4j2k6VmN9phTNPHfGA/I +zkJH/X06i8NlTuahQAuLC7Rc3RvSVsJSqwjBNuTp9LhjT/aYIJUH5dCz95m07cfO +aju7GZTfpe/O -----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAz8aDK4zqThB8WsZFB0XyphdVM/ToJN9OVd49DOagpeCw670O +VS9O82k48DEdDVQMOdbaN4lMq8GcEJ+N4ebB662XwIqiT2/mEKCt8qARTlgWJYE6 +W31stOB2g/Jn6xe+RNlaOCwstvUa0/VIhWpQgfF0C7Eiks3pH/ujHewDvhtmBekk +TgrXfzWjktgAmQbprTKg339y0N6C+Kd810FzaJd+897qc+Z+C9jrpk7roiDgLlqK +Xnmx3eGmZD6ienC+altl6Lug0EwAs6SqL8MKME2e0YnCwGdRoBOh0wqk24KFlt3J +BkloxzbmumAq3nE2XDsWqf7I45FIamIFwbgR7wIDAQABAoIBAQC2CdvkrSqfyKvb +MDlMXQlyYaEBy4IUxB0y+GqOwgVgL9NyRwqmsbM/aiI7txwYEFpB1q8L11x4Y0Hk +ApbhpDak0UvSouQAKy7rxIuCtqFS/bQxmd5SSDqU4tCTXC+V9xB56+CytGlcxrSB +njayxWnR34VntQNwkb29is/oKF9DD9MAGv16B6l8sNCO5tCEKVR0YxLdrkVzWlgm +unyZqUmdN+n4YdPNYYxm5IcJHR++X+0evXiQO3sPOz8IlFgPj7NZB8DFUjQh1ToH +srwQihg2T7eusasLL7g9dv2m5yySAjmkfN1L3T8T/WIQRYu8xLaFHGpOa3NukQ6o +CurR314JAoGBAPhQYlzzTnimrmfFcOxMdpIoRtW9b0YB8u/hY/TBrCHzciO31hJS +HRJuqgHLhdu52ke8sJlWsQ3+vv4osyVBPe+vodwFJu+c1OJ5PXPp58oD8TboGgGX +qCEKh96BOZ7MZoiRs9smmKDc/5S17Qsppq3tuAqMSlDEXNbxtVZC5L0bAoGBANY0 +55G10SUDfRN9govEly/zorEIy+gWW+PEKzIkeZpsIzKZTUa5F4CTX/4TSD/FZPAB +TJo4nfQdvVi1OlDQLRnjAsq7f9sWiq2MyZx0eSy5RCpSKNyft6BX6mt+M4EdssQT +/GMVU+qAprXNuC5J1dRR4CNT1g0MLa7oj7Xs6a+9AoGAfpVz31CFI0pNREdJjpxY +IZ/4pENCs1yQ/KpYq1ADsPcKq5yuu34ypc/WSL34yg9PcByHplOkRK8lrCkRUh+V +NFfDWoch1yqK97y4kBugdsJVuBjQERm/ssBMjSgxOHuYlWw5VLGzQuYGQEgRxAwC +lU3G8VGdHNlNPqHPQF8vfhsCgYEAvquY9TrCUBAq5Y5zBbaYXTahOrR5zL0aTkPv +r1KIa8yWCBQtlSZspSaJ679+MEWk8340kZKUBxfx02R95DFp9AD+GzeLN5l5F8Ka +M4n50rWW15UKilghO7kGEWjkr6mf1qlznz7802BxBKN5rrpKfBPlT4zwm+ybPXYF +dgrMeIECgYEAgbmkN4rxUEb9FFteSG0avH5CxY4iBqQSyxmi7XASgHjlkD8n9yRR +IrLlSK01XNKTtZ3ZGxWSUvLIJsfTaBDXpZGMpi53blLbXf9jUaU/DaXXS2pLNHdJ +h0qLNRt9bkQ/1tHUwhptkkI5P6U7ErkWbcB9YCg8LXm8SlgebZUJvHQ= +-----END RSA PRIVATE KEY----- diff --git a/tests/recipient_key.pem b/tests/recipient_key.pem index 5bf0f70..70ef775 100644 --- a/tests/recipient_key.pem +++ b/tests/recipient_key.pem @@ -1,15 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDCIaNPZFmcITkh0jznCmByyDmzwydKbVaPoF0bxuQ+JmEJqa4E -g2k/nSsSftT3jtBuqYyb0b8XDL3Qc5kCbn7LeoAtz7EpwDA2P2gSPk6/+Ys9HVav -JJSu1Vm0AFAMwCtZw5mzihnxhhS97unE8ddqDOlnipSaLS1gJSLGcmjCDQIDAQAB -AoGAZlrJ+kAUpyc1Mkng5ogoFhzPn6ITg0Bm1U9eCBkzmjkuDKQ0JhkLUwkQ/q10 -qBnad55ZjoZmVEbZhaCNWiTcIIy0nKAMWNKRcg3vTgrnbmbjco1HECDStfJKogZl -7egoIImHnU1f/IeKQDUYUfs/INonmnnZ1d2jrU7QsdTz84ECQQDzhT0UwP8S1oma -0IBgeUOt5ptZs7nFdZnbIKCd+ADra6NiQznokCHe5K0WZHqPKvN9asKx1u0h+97H -Wmk6Fw7RAkEAzBR1+mTRSrlJT8/NTCsIDPtCK/+OhmGbNy1pfsOWq1lN58Za5HV7 -fmtaH2No+MP+DlfNigsg557GzAYl2ZumfQJAHQj33W+dehuGUKUniVksDqH+R9W8 -AqUg8RWU0QDu6yLsWhz13JrCzxao5JCaZFOUsJF4IUglAfZL+6z1+u0g4QJAH5aL -LFaujoJfdpsTi9adSGUbuPO1e9dfzwqYaaaci6knBdkN+I62rrqvGGyqstajXFT6 -24MddLx+yNWqxiPxgQJBAKF8YiR4eLqLSnq4ftqCqVCC1XbA2H9b7G5RBWi00WFq -3Nx+B/wjLzbqsMamTCIDUCEW+MzFx6otCxduDZRMKH8= +MIIEpQIBAAKCAQEAz8aDK4zqThB8WsZFB0XyphdVM/ToJN9OVd49DOagpeCw670O +VS9O82k48DEdDVQMOdbaN4lMq8GcEJ+N4ebB662XwIqiT2/mEKCt8qARTlgWJYE6 +W31stOB2g/Jn6xe+RNlaOCwstvUa0/VIhWpQgfF0C7Eiks3pH/ujHewDvhtmBekk +TgrXfzWjktgAmQbprTKg339y0N6C+Kd810FzaJd+897qc+Z+C9jrpk7roiDgLlqK +Xnmx3eGmZD6ienC+altl6Lug0EwAs6SqL8MKME2e0YnCwGdRoBOh0wqk24KFlt3J +BkloxzbmumAq3nE2XDsWqf7I45FIamIFwbgR7wIDAQABAoIBAQC2CdvkrSqfyKvb +MDlMXQlyYaEBy4IUxB0y+GqOwgVgL9NyRwqmsbM/aiI7txwYEFpB1q8L11x4Y0Hk +ApbhpDak0UvSouQAKy7rxIuCtqFS/bQxmd5SSDqU4tCTXC+V9xB56+CytGlcxrSB +njayxWnR34VntQNwkb29is/oKF9DD9MAGv16B6l8sNCO5tCEKVR0YxLdrkVzWlgm +unyZqUmdN+n4YdPNYYxm5IcJHR++X+0evXiQO3sPOz8IlFgPj7NZB8DFUjQh1ToH +srwQihg2T7eusasLL7g9dv2m5yySAjmkfN1L3T8T/WIQRYu8xLaFHGpOa3NukQ6o +CurR314JAoGBAPhQYlzzTnimrmfFcOxMdpIoRtW9b0YB8u/hY/TBrCHzciO31hJS +HRJuqgHLhdu52ke8sJlWsQ3+vv4osyVBPe+vodwFJu+c1OJ5PXPp58oD8TboGgGX +qCEKh96BOZ7MZoiRs9smmKDc/5S17Qsppq3tuAqMSlDEXNbxtVZC5L0bAoGBANY0 +55G10SUDfRN9govEly/zorEIy+gWW+PEKzIkeZpsIzKZTUa5F4CTX/4TSD/FZPAB +TJo4nfQdvVi1OlDQLRnjAsq7f9sWiq2MyZx0eSy5RCpSKNyft6BX6mt+M4EdssQT +/GMVU+qAprXNuC5J1dRR4CNT1g0MLa7oj7Xs6a+9AoGAfpVz31CFI0pNREdJjpxY +IZ/4pENCs1yQ/KpYq1ADsPcKq5yuu34ypc/WSL34yg9PcByHplOkRK8lrCkRUh+V +NFfDWoch1yqK97y4kBugdsJVuBjQERm/ssBMjSgxOHuYlWw5VLGzQuYGQEgRxAwC +lU3G8VGdHNlNPqHPQF8vfhsCgYEAvquY9TrCUBAq5Y5zBbaYXTahOrR5zL0aTkPv +r1KIa8yWCBQtlSZspSaJ679+MEWk8340kZKUBxfx02R95DFp9AD+GzeLN5l5F8Ka +M4n50rWW15UKilghO7kGEWjkr6mf1qlznz7802BxBKN5rrpKfBPlT4zwm+ybPXYF +dgrMeIECgYEAgbmkN4rxUEb9FFteSG0avH5CxY4iBqQSyxmi7XASgHjlkD8n9yRR +IrLlSK01XNKTtZ3ZGxWSUvLIJsfTaBDXpZGMpi53blLbXf9jUaU/DaXXS2pLNHdJ +h0qLNRt9bkQ/1tHUwhptkkI5P6U7ErkWbcB9YCg8LXm8SlgebZUJvHQ= -----END RSA PRIVATE KEY----- diff --git a/tests/sample-p7.pem b/tests/sample-p7.pem new file mode 100644 index 0000000..46034f0 --- /dev/null +++ b/tests/sample-p7.pem @@ -0,0 +1,102 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----38FBD2321B4A76C8BE88AFD029CDED23" + +This is an S/MIME signed message + +------38FBD2321B4A76C8BE88AFD029CDED23 +This directory contains unit tests for M2Crypto. + +To run all tests, make sure you have installed setuptools and then issue the +following command from the M2Crypto root directory: + +python setup.py test + +To run tests in a single file, for example test_ssl.py, do this: + +python setup.py test --test-suite=tests.test_ssl + + +Look also in the demo directory for other samples. + + +To create new test certificates: + +mkdir certs +cd certs + +Making the CA. You may want to use a locally edited openssl.cnf to +make sure that X509v3 Basic Constraints CA:TRUE gets set (by default +it may be false). By default duration may only be just one year; should +set this for at least 3 years. + +CA.sh -newca +cp demoCA/cacert.pem ../ca.pem + +Making the server certificate and private key. make sure commonName +field is localhost. + +CA.sh -newreq +CA.sh -signreq +cp newcert.pem ../server.pem +openssl rsa >../server.pem + +Making the x509 certificate and key. + +CA.sh -newreq +CA.sh -signreq +cp newcert.pem ../x509.pem +openssl rsa >../x509.pem +openssl x509 -in ../x509.pem -out ../x509.der -outform DER + +Making the signer certificate. Make sure the email address is +signer@example.com. + +CA.sh -newreq +CA.sh -signreq +cp newcert.pem ../signer.pem +openssl rsa ../signer_key.pem + +Making the recipient certificate. Make sure the email address is +recipient@example.com. + +CA.sh -newreq +CA.sh -signreq +cp newcert.pem ../recipient.pem +openssl rsa ../recipient_key.pem + + +Finally run the tests and edit for new values. + +------38FBD2321B4A76C8BE88AFD029CDED23 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIEhQYJKoZIhvcNAQcCoIIEdjCCBHICAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggJkMIICYDCCAcmgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBPMQsw +CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEChMITTJDcnlw +dG8xGDAWBgNVBAMTD0hlaWtraSBUb2l2b25lbjAeFw0xNTExMjYyMTMzMTJaFw0y +NTExMjMyMTMzMTJaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh +MREwDwYDVQQKEwhNMkNyeXB0bzESMBAGA1UEAxMJUmVjaXBpZW50MSQwIgYJKoZI +hvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBAJaMhIx8GBrTwmJdDwilmD2LkUw0b80Vr1Ycffk2pgE8nGPPIGT6 +dySl4cv+j1rAqJAbmaMCakPv+TGseQH5zEYRfKrRh9+V1PGkesv8TC6LMyL1M/hT +augiSBiW8kk5/zOZA+U9wiJS8TOWILzRyCG7S3U9Kz1RTqoP1XNdZkS/AgMBAAGj +LDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFFON3U+KXkkZq9wvnavqx8PK9vXUMA0G +CSqGSIb3DQEBBQUAA4GBABCx3TS7lz4+2ODeapnJvoy3gMcdMNs6aNWk2QJ2K3Zi +AIYwWgYDZZK5AKRClF90xpRELowHVfPBbnoKF2ZW71Cvo1/x95dmKdO0FBM0eZaY +rVjbIOb8+nCsHCKQv3vD6uOKCr26SP/lyVCDGNkeYTDAx2zqM/7Q/Kga8Zuj3JEQ +MYIB5TCCAeECAQEwVDBPMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p +YTERMA8GA1UEChMITTJDcnlwdG8xGDAWBgNVBAMTD0hlaWtraSBUb2l2b25lbgIB +BDANBglghkgBZQMEAgEFAKCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwG +CSqGSIb3DQEJBTEPFw0xODA3MjMxODExNTNaMC8GCSqGSIb3DQEJBDEiBCAFNpRM +82d8yvtEyK+nEYuCf5KuyfnooeJYkzIbqUb2yDB5BgkqhkiG9w0BCQ8xbDBqMAsG +CWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMH +MA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG +9w0DAgIBKDANBgkqhkiG9w0BAQEFAASBgEEVB6XZeD44cN+6qmj1LR5Jh6JLGnIQ +eQPGrI8Ygymc1dVDWC72872Xp3UTidhMnCyN36QNBZ7GL63tc2mCZ9rgWE24mvqx +cj5hCyXF240ty20igJe5BDaXHgzO0JGJPUtoOxNWrM40IhGxh9MSGlfioMOsuRD4 +gDf9hUfjCkvG + +------38FBD2321B4A76C8BE88AFD029CDED23-- + diff --git a/tests/server.pem b/tests/server.pem index 825abc6..681528d 100644 --- a/tests/server.pem +++ b/tests/server.pem @@ -1,75 +1,101 @@ Certificate: Data: Version: 3 (0x2) - Serial Number: - d1:b6:bf:af:06:17:8c:be - Signature Algorithm: sha1WithRSAEncryption + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity - Not Before: Jul 28 04:31:41 2009 GMT - Not After : Jul 26 04:31:41 2019 GMT + Not Before: Oct 7 15:12:02 2018 GMT + Not After : Oct 4 15:12:02 2028 GMT Subject: C=US, ST=California, O=M2Crypto, CN=localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public Key: (1024 bit) - Modulus (1024 bit): - 00:d4:99:6f:33:3f:e6:ac:0a:34:d8:0e:45:97:f3: - 2b:6a:50:2a:84:30:0a:52:9c:15:30:9f:05:29:3a: - 21:f4:c1:c3:01:9e:2f:55:56:4e:35:ac:f1:16:1e: - 26:8d:b5:26:b7:99:78:92:ea:1c:74:46:ab:41:12: - ef:cc:53:62:cc:59:5c:9e:c4:86:df:d9:25:35:55: - 05:4b:16:ff:d9:90:e3:f4:51:b4:b4:fa:c5:98:4b: - 60:f0:60:7f:14:4e:1e:dd:61:9b:22:a2:9c:21:17: - 43:a3:cb:07:80:f5:75:59:9c:55:1c:fe:e0:66:d4: - 70:77:5e:13:06:0c:05:c7:1f + RSA Public-Key: (2048 bit) + Modulus: + 00:f4:f3:38:31:09:92:0d:5d:8b:06:f0:43:e0:62: + 62:e1:71:eb:30:ba:d7:b9:57:db:8c:10:9b:9e:1e: + 76:45:ab:14:92:54:d4:47:34:ab:0f:95:f3:83:c5: + f1:45:75:58:72:0a:e1:67:77:d0:d3:7e:6a:6f:5d: + 1a:a4:df:aa:96:c0:0f:8d:0a:95:9e:aa:e5:bc:7a: + 6f:ab:61:41:75:31:0c:da:a6:d5:0d:b3:42:f0:20: + f6:2c:74:69:39:79:90:a0:c9:c2:23:ba:5a:c5:9c: + 8f:fa:4f:06:bb:04:8e:2d:a1:36:82:c4:23:99:18: + 1a:b7:56:0f:8a:ef:ff:57:22:51:96:ca:69:8f:a3: + ae:91:b7:84:02:07:be:4d:55:f2:1c:f9:11:2a:ff: + 20:ab:0f:27:fb:79:75:6c:b2:53:e3:04:ea:4f:e5: + 51:3f:1e:b0:b5:7f:fa:de:0f:f6:e8:e6:85:a3:17: + 8c:b1:a6:dd:fc:e9:b8:92:d5:1c:73:d7:82:6e:60: + 6c:10:b3:22:ca:a5:d8:c5:d2:41:93:b3:57:3f:1b: + cf:cf:78:4c:15:85:b1:ca:b6:84:13:1b:8f:42:ed: + 21:bb:90:a2:b7:39:9d:68:bf:4d:da:31:06:53:98: + e3:de:8f:f8:3e:7d:25:f2:75:7e:d3:09:e4:eb:4d: + 59:c9 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE - Netscape Comment: - OpenSSL Generated Certificate X509v3 Subject Key Identifier: - 04:05:3D:6A:A7:E8:D7:52:BD:2F:C4:52:30:7C:2C:BD:D3:81:46:C6 - X509v3 Authority Key Identifier: - keyid:AD:64:45:74:8F:83:C7:2C:D5:D7:A0:85:91:10:40:9A:9C:96:CF:EE - - Signature Algorithm: sha1WithRSAEncryption - ac:2b:ad:86:36:96:5c:fb:34:2c:02:ca:d9:5f:a7:8e:b6:58: - 24:1d:27:b6:8e:81:aa:69:0e:60:26:64:2e:72:a1:ff:d8:ba: - bb:7e:5d:46:c7:07:2d:a8:c8:4c:df:1e:ba:c8:bc:21:5b:f2: - b3:01:4c:d6:3b:10:fd:49:70:e6:83:01:f3:24:e2:a9:97:d7: - c3:9c:5b:2d:d7:64:2b:e5:e2:0e:3e:d9:8c:e6:93:86:39:32: - 50:43:5f:36:4a:3b:b0:05:e7:65:a3:b3:ef:50:56:7f:7e:dc: - f0:65:83:ac:42:7e:97:a0:c0:7e:63:c6:c8:c6:35:d3:60:d1: - 4f:51 + 56:FF:B6:FD:ED:A3:76:04:AA:CB:1F:25:FB:A5:8D:9D:9A:D5:85:D3 + Signature Algorithm: sha256WithRSAEncryption + 53:99:54:2e:26:26:0c:81:b2:c6:5c:61:6f:1c:60:28:ed:f3: + 1b:74:8e:e8:c1:3c:b5:35:e3:db:51:07:38:43:b0:57:0b:e5: + 7e:fa:0a:9e:bd:bd:82:5a:ed:9b:67:0d:2b:61:4d:44:58:64: + a2:fe:bc:fb:90:80:d2:6b:e4:25:09:ea:ca:a1:17:e6:33:31: + 09:62:b6:db:4c:21:f3:52:02:7d:ca:9a:f9:42:04:50:b4:d8: + a6:49:ea:bd:c0:13:05:c6:c4:d2:59:d6:30:87:80:c6:a3:92: + 45:49:02:43:9c:4a:aa:c1:84:d0:ea:01:29:40:73:87:cd:8e: + aa:93:d3:33:7e:01:cf:b5:c1:4b:35:e7:20:1f:6d:7a:c5:d4: + a9:4a:c1:e2:26:f5:b7:a2:f5:04:31:45:74:30:9a:51:e7:19: + 62:e4:d1:ab:f9:36:29:58:ec:90:f9:8c:3b:28:39:28:d7:8a: + a0:c3:ae:aa:a9:c2:05:6e:a9:f4:b6:62:1b:01:db:f9:3e:b9: + a4:d7:05:ac:76:b8:8a:12:57:b3:66:de:b0:d2:78:0d:07:9c: + 15:1b:85:84:76:31:23:64:ce:1e:7f:be:1e:cc:d9:9f:c0:0c: + 9c:20:b9:f0:2e:09:04:ca:d0:61:fc:ce:ba:df:28:c8:20:c8: + fb:63:1d:52 -----BEGIN CERTIFICATE----- -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 +8C4JBMrQYfzOut8oyCDI+2MdUg== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/tests/server_key.pem b/tests/server_key.pem new file mode 100644 index 0000000..5994dc4 --- /dev/null +++ b/tests/server_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA9PM4MQmSDV2LBvBD4GJi4XHrMLrXuVfbjBCbnh52RasUklTU +RzSrD5Xzg8XxRXVYcgrhZ3fQ035qb10apN+qlsAPjQqVnqrlvHpvq2FBdTEM2qbV +DbNC8CD2LHRpOXmQoMnCI7paxZyP+k8GuwSOLaE2gsQjmRgat1YPiu//VyJRlspp +j6OukbeEAge+TVXyHPkRKv8gqw8n+3l1bLJT4wTqT+VRPx6wtX/63g/26OaFoxeM +sabd/Om4ktUcc9eCbmBsELMiyqXYxdJBk7NXPxvPz3hMFYWxyraEExuPQu0hu5Ci +tzmdaL9N2jEGU5jj3o/4Pn0l8nV+0wnk601ZyQIDAQABAoIBAQCgFpWS9v5NXeWP +E1hJPgQB88IShwqWR6VlVTVfkekaf0Vina5fGzzxYr9UT/nvu1Gitxm51cTVdLl7 +Lw5K0yNagwum0lQW7vpWxG5XQ6jUPsp33LFB0vbcma5KP4rF1X2AmFwZnaHVpQ00 +OpHbiI6jo8lMjYP2epp7V/OwikoHV0873HTmuq2Y+jUvRM3o01moDtuF5mKofNEd +ft9lArRG8yjLgC5G1C9cmiATGoMGyHBRkEv+UrUWLHVxrpXviUd+/iJmhrwXcpvj +rTrZWbUkSA3i4JMml/qYqNQYeVUFVgV/slD331iIwlWP8RipXF5YqN+YGjGeqL0+ +yQ4KWtABAoGBAP7XvGBUWNBSBrqioTzqYMTbwz/YjXJkvlO09wwc/UkraYlSihi0 +2J1dKBePIfOk6gFbuiJNYMJvAt1hBCsN0Z6o/bH7CiOh/55nkTaL0R4zB38uuDDx +4qf6+9HT1eC9yW3UJVPwBBwI4WZmmq4peQoipBtKwpY2Q+yoUU3gp4KhAoGBAPYP ++6uv3gQYoIpkUD2ZdX8kFoaC6rJMP3Z/N75NfsOz1Tx3nNwexYM6EVVQrvTRWpLZ +rJyCgCJi9HY4lPASKSKM1cLCT/M3SdR8OiqlEjziZtSH/di6wq8/Hfqhf75nC7sK +wV7Ic0eQ3Bjg2hggPpjeBJTv8NIlCYbWbxHnsK4pAoGAY0I39vUjWpB4Wn05e/Z2 +FnbaR6XbAfFHSGc1yhwIc1VbV8c0Tocxz6kXEoYHXVSgaEMH7pBg3ZpLbVp6OyK4 +wKlllssGmfZhD5ubLbmri62of9r8luO/ulnBd2qg5VZGfGai21yi3SCAWlggazFw +GYiAjrjBrawZLLYqZMDZvcECgYBoi6/taWKWMPR8+FQTaBFA/M9JRXR8XuMT8Md5 +Zqm2csDl2Rhfef+HWvOkYQyE3jJydGPfd58DfTHKzQ2S1tR9ZoMoJbEccGBBFKsO +FWajUbpJEKKtI+S12sZdB6Mj/dpBFTfFkrtQK98n/tkLKSAPiT0/HpceYjgi/xbf +76XkyQKBgQCkAuuTYi/9vlqYBcUH+23f0XmzQ6NNCqi0JxrnUmPv0Mc/ci7QfBZ6 +BkjPxfllpAsDihfTFpfp6p1PCMpASq1J+w1yR+lnKgw9BlbBLT4SqSVVDiju0cfw +njm6zQu7IR6Ts/vi+YbVqn3yeP8U5W9as7QL5y6KeYfAhwuPqWhvog== +-----END RSA PRIVATE KEY----- diff --git a/tests/signer.pem b/tests/signer.pem index 816f5fa..a7e2fb9 100644 --- a/tests/signer.pem +++ b/tests/signer.pem @@ -1,61 +1,75 @@ Certificate: Data: Version: 3 (0x2) - Serial Number: - d1:b6:bf:af:06:17:8c:c0 - Signature Algorithm: sha1WithRSAEncryption + Serial Number: 3 (0x3) + Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity - Not Before: Jul 28 04:37:25 2009 GMT - Not After : Jul 26 04:37:25 2019 GMT + Not Before: Oct 7 15:12:02 2018 GMT + Not After : Oct 4 15:12:02 2028 GMT Subject: C=US, ST=California, O=M2Crypto, CN=Signer/emailAddress=signer@example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public Key: (1024 bit) - Modulus (1024 bit): - 00:c3:9c:76:f3:21:aa:10:19:9f:77:e3:82:1d:9d: - c3:4a:da:bc:c3:83:71:d1:89:78:8b:82:a4:b9:c5: - 70:bb:e3:00:bf:49:b8:99:96:67:0b:bf:fe:72:cb: - d9:b6:63:85:f4:fb:86:55:32:22:1e:6e:ce:fd:88: - 5c:75:9d:77:3c:92:17:c5:b2:70:04:59:02:33:ef: - be:33:26:f1:e4:72:41:45:72:f1:bf:c4:21:b1:fe: - de:92:b9:f3:25:3e:1a:15:4b:26:47:29:cc:38:7f: - 58:3b:ae:b7:c5:69:e7:48:81:b6:55:61:45:c3:3f: - b6:9d:06:e5:17:41:f6:f2:e9 + RSA Public-Key: (2048 bit) + Modulus: + 00:c8:85:86:3d:72:aa:91:d8:7b:11:02:05:92:b7: + 1b:bf:9f:35:be:88:56:db:96:f2:70:3e:98:3c:c3: + 62:42:ff:54:74:7a:63:e7:a9:4c:ae:52:48:a2:4f: + ab:c5:6b:1d:de:39:b8:f0:89:36:15:f7:70:3d:a8: + a6:c3:49:3e:10:d8:ae:ba:cf:1a:e6:dd:0b:d8:cd: + d9:00:ea:57:f2:7c:2e:6d:89:80:95:68:b1:fd:06: + bc:ea:ba:44:c1:fa:20:87:57:d3:ac:e5:b4:5d:ba: + 4f:10:20:82:5b:1b:27:75:b3:0c:ce:4f:79:3f:49: + 8e:e3:ba:14:30:cf:8a:82:11:65:59:78:7b:41:16: + 43:e8:ea:7f:a4:60:52:46:93:53:4e:de:87:3f:50: + 8a:56:c5:d3:04:5c:3c:a2:d3:b0:64:d8:ce:1e:75: + ad:ce:cd:91:b1:58:cc:2d:a6:dc:da:b5:b2:c2:0e: + 2f:68:74:a7:a5:6e:61:4c:01:f2:d0:7d:83:66:78: + 66:9f:b9:87:33:cc:59:dc:03:82:6f:bb:98:0c:e9: + 10:63:12:ee:e9:05:c1:5b:98:7e:94:65:98:df:31: + bf:59:90:f0:1c:6c:ac:2c:1b:dd:90:71:ab:11:95: + 8b:9c:f7:2a:2f:c0:0f:2d:b1:c8:5a:65:d6:a9:34: + 44:81 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE - Netscape Comment: - OpenSSL Generated Certificate X509v3 Subject Key Identifier: - 22:CA:29:B7:D7:39:B4:BF:35:F9:36:5E:EE:2B:E4:17:4E:F9:6E:EE - X509v3 Authority Key Identifier: - keyid:AD:64:45:74:8F:83:C7:2C:D5:D7:A0:85:91:10:40:9A:9C:96:CF:EE - - Signature Algorithm: sha1WithRSAEncryption - 5f:a0:da:6b:37:b4:bb:25:34:a7:ed:f3:f7:2e:f2:85:aa:91: - 01:8f:c3:80:e5:44:87:df:9e:64:5e:5f:3e:5c:7f:c1:07:12: - 2a:46:cc:bb:9f:a4:a5:c8:3f:84:9a:a4:9e:d5:26:33:af:b4: - 5f:eb:8e:7d:81:65:f6:44:18:78:89:17:74:fb:07:dc:04:65: - fa:15:0c:b2:f3:e7:e7:af:1f:d9:02:c4:c4:44:b7:95:91:47: - fe:c0:2a:e1:7a:ae:dd:5f:f8:a9:fa:bb:dd:89:2d:0b:05:b6: - ce:ba:12:37:7f:97:4c:48:a9:fb:d4:b7:a5:d1:61:f6:85:ea: - 30:8c + 68:03:33:27:D9:87:9A:EA:7D:41:D8:2D:EB:F9:EE:AB:C9:6A:C5:FA + Signature Algorithm: sha256WithRSAEncryption + 47:27:62:6d:43:f3:f6:87:0a:8f:1f:f1:4b:2b:67:05:11:85: + b1:13:69:ca:de:1e:6f:8f:78:ae:b5:b7:75:ca:84:f3:58:26: + 9d:c5:0b:0e:4c:e9:ce:1c:5d:69:03:6e:d7:2e:88:28:75:78: + c5:54:37:e6:70:4f:8f:92:fb:5f:ce:c2:b3:a3:74:77:e6:c3: + 94:ab:c6:d2:69:bb:dd:d8:16:9d:36:2a:d1:c1:e1:0d:81:da: + 96:9f:f1:ae:a4:b9:73:16:b1:98:b5:f9:6a:4c:8b:08:30:c3: + d6:31:3a:79:e2:ef:7f:db:4f:6f:13:f8:98:d6:b2:04:72:c3: + 03:b2:ff:63:ad:ce:4e:8d:95:37:a6:dc:52:5e:5c:26:35:9f: + 14:7e:9d:a0:04:46:00:ff:52:94:f1:2b:75:1c:52:f0:79:eb: + 41:a8:39:a2:5a:63:cc:de:70:cd:82:72:77:1d:77:e1:3d:ff: + 38:86:2d:12:4f:ab:4c:72:35:69:4f:ad:55:1d:da:ae:9d:0a: + 23:4a:cc:2a:40:d8:4e:f5:bd:33:4c:eb:b7:47:41:82:2a:c9: + fc:64:0d:33:76:00:61:ba:b6:40:ca:24:96:5e:84:d5:4f:d2: + 4d:2e:7a:31:a5:50:53:ba:eb:31:7b:78:9f:f4:43:f1:e5:54: + 4f:59:dc:ba -----BEGIN CERTIFICATE----- -MIICsTCCAhqgAwIBAgIJANG2v68GF4zAMA0GCSqGSIb3DQEBBQUAME8xCzAJBgNV -BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQKEwhNMkNyeXB0bzEY -MBYGA1UEAxMPSGVpa2tpIFRvaXZvbmVuMB4XDTA5MDcyODA0MzcyNVoXDTE5MDcy -NjA0MzcyNVowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAP -BgNVBAoTCE0yQ3J5cHRvMQ8wDQYDVQQDEwZTaWduZXIxITAfBgkqhkiG9w0BCQEW -EnNpZ25lckBleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA -w5x28yGqEBmfd+OCHZ3DStq8w4Nx0Yl4i4KkucVwu+MAv0m4mZZnC7/+csvZtmOF -9PuGVTIiHm7O/YhcdZ13PJIXxbJwBFkCM+++Mybx5HJBRXLxv8Qhsf7ekrnzJT4a -FUsmRynMOH9YO663xWnnSIG2VWFFwz+2nQblF0H28ukCAwEAAaN7MHkwCQYDVR0T -BAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNh -dGUwHQYDVR0OBBYEFCLKKbfXObS/Nfk2Xu4r5BdO+W7uMB8GA1UdIwQYMBaAFK1k -RXSPg8cs1deghZEQQJqcls/uMA0GCSqGSIb3DQEBBQUAA4GBAF+g2ms3tLslNKft -8/cu8oWqkQGPw4DlRIffnmReXz5cf8EHEipGzLufpKXIP4SapJ7VJjOvtF/rjn2B -ZfZEGHiJF3T7B9wEZfoVDLLz5+evH9kCxMREt5WRR/7AKuF6rt1f+Kn6u92JLQsF -ts66Ejd/l0xIqfvUt6XRYfaF6jCM +MIIDXzCCAkegAwIBAgIBAzANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM +D0hlaWtraSBUb2l2b25lbjAeFw0xODEwMDcxNTEyMDJaFw0yODEwMDQxNTEyMDJa +MGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN +MkNyeXB0bzEPMA0GA1UEAwwGU2lnbmVyMSEwHwYJKoZIhvcNAQkBFhJzaWduZXJA +ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIhYY9 +cqqR2HsRAgWStxu/nzW+iFbblvJwPpg8w2JC/1R0emPnqUyuUkiiT6vFax3eObjw +iTYV93A9qKbDST4Q2K66zxrm3QvYzdkA6lfyfC5tiYCVaLH9BrzqukTB+iCHV9Os +5bRduk8QIIJbGyd1swzOT3k/SY7juhQwz4qCEWVZeHtBFkPo6n+kYFJGk1NO3oc/ +UIpWxdMEXDyi07Bk2M4eda3OzZGxWMwtptzatbLCDi9odKelbmFMAfLQfYNmeGaf +uYczzFncA4Jvu5gM6RBjEu7pBcFbmH6UZZjfMb9ZkPAcbKwsG92QcasRlYuc9yov +wA8tschaZdapNESBAgMBAAGjLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGgDMyfZ +h5rqfUHYLev57qvJasX6MA0GCSqGSIb3DQEBCwUAA4IBAQBHJ2JtQ/P2hwqPH/FL +K2cFEYWxE2nK3h5vj3iutbd1yoTzWCadxQsOTOnOHF1pA27XLogodXjFVDfmcE+P +kvtfzsKzo3R35sOUq8bSabvd2BadNirRweENgdqWn/GupLlzFrGYtflqTIsIMMPW +MTp54u9/209vE/iY1rIEcsMDsv9jrc5OjZU3ptxSXlwmNZ8Ufp2gBEYA/1KU8St1 +HFLweetBqDmiWmPM3nDNgnJ3HXfhPf84hi0ST6tMcjVpT61VHdqunQojSswqQNhO +9b0zTOu3R0GCKsn8ZA0zdgBhurZAyiSWXoTVT9JNLnoxpVBTuusxe3if9EPx5VRP +Wdy6 -----END CERTIFICATE----- diff --git a/tests/signer_key.pem b/tests/signer_key.pem index 39abda1..dda4f85 100644 --- a/tests/signer_key.pem +++ b/tests/signer_key.pem @@ -1,15 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/tests/te_chunked_response.txt b/tests/te_chunked_response.txt new file mode 100644 index 0000000..f7eaadd --- /dev/null +++ b/tests/te_chunked_response.txt @@ -0,0 +1,11 @@ +HTTP/1.1 200 ok +Content-Type: text/plain +Transfer-Encoding: chunked + +4 +foo + +7 +foobar + +0 diff --git a/tests/test_aes.py b/tests/test_aes.py new file mode 100644 index 0000000..1da122d --- /dev/null +++ b/tests/test_aes.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +from __future__ import absolute_import, print_function +"""Unit tests for _aes.i. + +Copyright (c) 2018 Matej Cepl. All rights reserved. +""" +import logging + +from M2Crypto import m2 +from tests import unittest + +log = logging.getLogger('test_AES') + +KEY_TEXT = (b'blabulka' * 3)[:16] # 128/8 == 16 + + +class AESTestCase(unittest.TestCase): + """ + Functions in AES module are very low level, and you are HIGHLY + encouraged NOT to use them. Use functions from EVP module instead. + + These tests are here only for checking regressions, not as an + illustration for the real world use. + """ + + def test_existing_methods(self): + missing = [] + exp_mtds = ('aes_128_cbc', 'aes_128_cfb', 'aes_128_ctr', + 'aes_128_ecb', 'aes_128_ofb', 'aes_192_cbc', + 'aes_192_cfb', 'aes_192_ctr', 'aes_192_ecb', + 'aes_192_ofb', 'aes_256_cbc', 'aes_256_cfb', + 'aes_256_ctr', 'aes_256_ecb', 'aes_256_ofb') + for name in exp_mtds: + if not hasattr(m2, name): + missing.append(name) + + self.assertEqual(missing, []) + + def test_set_key(self): + key = m2.aes_new() + m2.AES_set_key(key, KEY_TEXT, 128, 1) + m2.AES_free(key) + + key2 = m2.aes_new() + m2.AES_set_key(key2, KEY_TEXT, 128, 0) + m2.AES_free(key2) + # Just to make sure nothing crashed + + def test_type_check(self): + key = m2.aes_new() + m2.AES_set_key(key, KEY_TEXT, 128, 1) + res = m2.AES_type_check(key) + m2.AES_free(key) + self.assertEqual(res, 1) # Just to make sure nothing crashed + + def test_crypt(self): + padded = b'zezulicka ' # len(padded) % 16 == 0 + key = m2.aes_new() + # op == 0: encrypt + # otherwise: decrypt (Python code will supply the value 1.) + m2.AES_set_key(key, KEY_TEXT, 128, 0) + enc = m2.AES_crypt(key, padded, len(padded), 0) + m2.AES_free(key) + + key2 = m2.aes_new() + m2.AES_set_key(key2, KEY_TEXT, 128, 1) + observed = m2.AES_crypt(key2, enc, len(enc), 1) + m2.AES_free(key2) + + self.assertEqual(padded, observed) + + +def suite(): + t_suite = unittest.TestSuite() + t_suite.addTest(unittest.makeSuite(AESTestCase)) + return t_suite + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_asn1.py b/tests/test_asn1.py index 30ef759..0f5274f 100644 --- a/tests/test_asn1.py +++ b/tests/test_asn1.py @@ -4,58 +4,117 @@ Copyright (c) 2005 Open Source Applications Foundation. All rights reserved.""" -import unittest, time, datetime +import datetime +import time + from M2Crypto import ASN1, m2 +from tests import unittest + class ASN1TestCase(unittest.TestCase): def test_Integer(self): - pass # XXX Dunno how to test + pass # XXX Dunno how to test def test_BitSTring(self): - pass # XXX Dunno how to test + pass # XXX Dunno how to test def test_String(self): asn1ptr = m2.asn1_string_new() - text = 'hello there' + # FIXME this is probably wrong ... asn1_string_set should have + # Python string as its parameter. + text = b'hello there' # In RFC2253 format: # #040B68656C6C6F207468657265 - # h e l l o t h e r e + # h e l l o t h e r e m2.asn1_string_set(asn1ptr, text) a = ASN1.ASN1_String(asn1ptr, 1) - assert a.as_text() == 'hello there', a.as_text() - assert a.as_text(flags=m2.ASN1_STRFLGS_RFC2253) == '#040B68656C6C6F207468657265', a.as_text(flags=m2.ASN1_STRFLGS_RFC2253) + self.assertEqual(a.as_text(), 'hello there', a.as_text()) + self.assertEqual(a.as_text(flags=m2.ASN1_STRFLGS_RFC2253), + '#040B68656C6C6F207468657265', + a.as_text(flags=m2.ASN1_STRFLGS_RFC2253)) self.assertEqual(a.as_text(), str(a)) def test_Object(self): - pass # XXX Dunno how to test + pass # XXX Dunno how to test + + def test_TIME(self): + asn1 = ASN1.ASN1_TIME() + self.assertEqual(str(asn1), 'Bad time value') + + format = '%b %d %H:%M:%S %Y GMT' + utcformat = '%y%m%d%H%M%SZ' + + s = '990807053011Z' + asn1.set_string(s) + # assert str(asn1) == 'Aug 7 05:30:11 1999 GMT' + t1 = time.strptime(str(asn1), format) + t2 = time.strptime(s, utcformat) + self.assertEqual(t1, t2) + + asn1.set_time(500) + # assert str(asn1) == 'Jan 1 00:08:20 1970 GMT' + t1 = time.strftime(format, time.strptime(str(asn1), format)) + t2 = time.strftime(format, time.gmtime(500)) + self.assertEqual(t1, t2) + + t = int(time.time()) + time.timezone + asn1.set_time(t) + t1 = time.strftime(format, time.strptime(str(asn1), format)) + t2 = time.strftime(format, time.gmtime(t)) + self.assertEqual(t1, t2) def test_UTCTIME(self): asn1 = ASN1.ASN1_UTCTIME() - assert str(asn1) == 'Bad time value' - + self.assertEqual(str(asn1), 'Bad time value') + format = '%b %d %H:%M:%S %Y GMT' utcformat = '%y%m%d%H%M%SZ' s = '990807053011Z' asn1.set_string(s) - #assert str(asn1) == 'Aug 7 05:30:11 1999 GMT' + # assert str(asn1) == 'Aug 7 05:30:11 1999 GMT' t1 = time.strptime(str(asn1), format) t2 = time.strptime(s, utcformat) self.assertEqual(t1, t2) - + asn1.set_time(500) - #assert str(asn1) == 'Jan 1 00:08:20 1970 GMT' + # assert str(asn1) == 'Jan 1 00:08:20 1970 GMT' t1 = time.strftime(format, time.strptime(str(asn1), format)) t2 = time.strftime(format, time.gmtime(500)) self.assertEqual(t1, t2) - - t = long(time.time()) + time.timezone + + t = int(time.time()) + time.timezone asn1.set_time(t) t1 = time.strftime(format, time.strptime(str(asn1), format)) t2 = time.strftime(format, time.gmtime(t)) self.assertEqual(t1, t2) + def test_TIME_datetime(self): + asn1 = ASN1.ASN1_TIME() + # Test get_datetime and set_datetime + t = time.time() + dt = datetime.datetime.fromtimestamp(int(t)) + udt = dt.replace(tzinfo=ASN1.LocalTimezone()).astimezone(ASN1.UTC) + asn1.set_time(int(t)) + t1 = str(asn1) + asn1.set_datetime(dt) + t2 = str(asn1) + self.assertEqual(t1, t2) + self.assertEqual(str(udt), str(asn1.get_datetime())) + + dt = dt.replace(tzinfo=ASN1.LocalTimezone()) + asn1.set_datetime(dt) + t2 = str(asn1) + self.assertEqual(t1, t2) + self.assertEqual(str(udt), str(asn1.get_datetime())) + + dt = dt.astimezone(ASN1.UTC) + asn1.set_datetime(dt) + t2 = str(asn1) + self.assertEqual(t1, t2) + self.assertEqual(str(udt), str(asn1.get_datetime())) + def test_UTCTIME_datetime(self): asn1 = ASN1.ASN1_UTCTIME() # Test get_datetime and set_datetime @@ -74,13 +133,13 @@ class ASN1TestCase(unittest.TestCase): t2 = str(asn1) self.assertEqual(t1, t2) self.assertEqual(str(udt), str(asn1.get_datetime())) - + dt = dt.astimezone(ASN1.UTC) asn1.set_datetime(dt) t2 = str(asn1) self.assertEqual(t1, t2) self.assertEqual(str(udt), str(asn1.get_datetime())) - + def suite(): return unittest.makeSuite(ASN1TestCase) diff --git a/tests/test_authcookie.py b/tests/test_authcookie.py old mode 100644 new mode 100755 index 9ce0eb8..006571f --- a/tests/test_authcookie.py +++ b/tests/test_authcookie.py @@ -4,15 +4,20 @@ Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" -import Cookie, binascii, time, unittest, sys +import logging +import time + +from M2Crypto import EVP, Rand, six, util from M2Crypto.AuthCookie import AuthCookie, AuthCookieJar, mix, unmix, unmix3 -from M2Crypto import Rand, EVP +from M2Crypto.six.moves.http_cookies import SimpleCookie # pylint: disable=no-name-in-module,import-error +from tests import unittest + +log = logging.getLogger(__name__) + class AuthCookieTestCase(unittest.TestCase): - _format = 'Set-Cookie: _M2AUTH_="exp=%s&data=%s&digest=%s"' - if sys.version_info < (2,5): - _format += ';' + _format = 'Set-Cookie: _M2AUTH_="exp=%f&data=%s&digest=%s"' _token = '_M2AUTH_' def setUp(self): @@ -23,117 +28,137 @@ class AuthCookieTestCase(unittest.TestCase): def tearDown(self): pass + def _corrupt_part_str(self, s, fr, to): + # type: (str, int, int) -> str + out = s[:fr] + ''.join([chr(ord(x) + 13) for x in s[fr:to]]) + s[to:] + self.assertNotEqual(s, out) + return out + + def test_encode_part_str(self): + a_str = 'a1b2c3d4e5f6h7i8j9' + self.assertEqual(self._corrupt_part_str(a_str, 3, 5), + 'a1b?p3d4e5f6h7i8j9') + def test_mix_unmix(self): dough = mix(self.exp, self.data) exp, data = unmix(dough) - self.failUnlessEqual(data, self.data) - self.failUnlessEqual(exp, self.exp) + self.assertEqual(data, self.data) + # we are comparing seconds here, ten-thousandth + # second should be enough. + self.assertAlmostEqual(exp, self.exp, places=4) def test_make_cookie(self): c = self.jar.makeCookie(self.exp, self.data) - self.failUnless(isinstance(c, AuthCookie)) - self.failUnlessEqual(c.expiry(), self.exp) - self.failUnlessEqual(c.data(), self.data) + self.assertTrue(isinstance(c, AuthCookie)) + self.assertEqual(c.expiry(), self.exp) + self.assertEqual(c.data(), self.data) # Peek inside the cookie jar... - key = self.jar._key - mac = binascii.b2a_base64(EVP.hmac(key, mix(self.exp, self.data), 'sha1'))[:-1] - self.failUnlessEqual(c.mac(), mac) + key = self.jar._key # pylint: disable=protected-access + mac = util.bin_to_hex( + EVP.hmac(key, six.ensure_binary(mix(self.exp, self.data)), 'sha1')) + self.assertEqual(c.mac(), mac) # Ok, stop peeking now. - cookie_str = self._format % (repr(self.exp), self.data, mac) - self.failUnlessEqual(c.output(), cookie_str) + cookie_str = self._format % (self.exp, self.data, mac) + self.assertEqual(c.output(), cookie_str) + + def test_make_cookie_invalid(self): + with self.assertRaises(ValueError): + self.jar.makeCookie("complete nonsense", self.data) def test_expired(self): t = self.exp - 7200 c = self.jar.makeCookie(t, self.data) - self.failUnless(c.isExpired()) + self.assertTrue(c.isExpired()) def test_not_expired(self): c = self.jar.makeCookie(self.exp, self.data) - self.failIf(c.isExpired()) + self.assertFalse(c.isExpired()) def test_is_valid(self): c = self.jar.makeCookie(self.exp, self.data) - self.failUnless(self.jar.isGoodCookie(c)) - + self.assertTrue(self.jar.isGoodCookie(c)) + def test_is_invalid_expired(self): t = self.exp - 7200 c = self.jar.makeCookie(t, self.data) - self.failIf(self.jar.isGoodCookie(c)) + self.assertFalse(self.jar.isGoodCookie(c)) def test_is_invalid_changed_exp(self): c = self.jar.makeCookie(self.exp, self.data) - c._expiry = 'this is bad' - self.failIf(self.jar.isGoodCookie(c)) + c._expiry = 0 # pylint: disable=protected-access + self.assertFalse(self.jar.isGoodCookie(c)) def test_is_invalid_changed_data(self): c = self.jar.makeCookie(self.exp, self.data) - c._data = 'this is bad' - self.failIf(self.jar.isGoodCookie(c)) + c._data = 'this is bad' # pylint: disable=protected-access + self.assertFalse(self.jar.isGoodCookie(c)) def test_is_invalid_changed_mac(self): c = self.jar.makeCookie(self.exp, self.data) - c._mac = 'this is bad' - self.failIf(self.jar.isGoodCookie(c)) + c._mac = 'this is bad' # pylint: disable=protected-access + self.assertFalse(self.jar.isGoodCookie(c)) def test_mix_unmix3(self): c = self.jar.makeCookie(self.exp, self.data) - s = Cookie.SmartCookie() - s.load(c.output()) + s = SimpleCookie() + s.load(c.output(header="")) exp, data, digest = unmix3(s[self._token].value) - self.failUnlessEqual(data, self.data) - self.failUnlessEqual(float(exp), self.exp) - key = self.jar._key # Peeking... - mac = binascii.b2a_base64(EVP.hmac(key, mix(self.exp, self.data), 'sha1'))[:-1] - self.failUnlessEqual(digest, mac) + self.assertEqual(data, self.data) + # see comment in test_mix_unmix + self.assertAlmostEqual(exp, self.exp, places=4) + key = self.jar._key # pylint: disable=protected-access + mac = util.bin_to_hex( + EVP.hmac(key, six.ensure_binary(mix(self.exp, self.data)), 'sha1')) + self.assertEqual(digest, mac) def test_cookie_str(self): c = self.jar.makeCookie(self.exp, self.data) - self.failUnless(self.jar.isGoodCookieString(c.output())) + self.assertTrue(self.jar.isGoodCookieString(c.output(header=""))) def test_cookie_str2(self): c = self.jar.makeCookie(self.exp, self.data) - s = Cookie.SmartCookie() - s.load(c.output()) - self.failUnless(self.jar.isGoodCookieString(s.output())) + s = SimpleCookie() + s.load(c.output(header="")) + self.assertTrue(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_expired(self): t = self.exp - 7200 c = self.jar.makeCookie(t, self.data) - s = Cookie.SmartCookie() - s.load(c.output()) - self.failIf(self.jar.isGoodCookieString(s.output())) + s = SimpleCookie() + s.load(c.output(header="")) + self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_arbitrary_change(self): c = self.jar.makeCookie(self.exp, self.data) - cout = c.output() - str = cout[:32] + 'this is bad' + cout[32:] - s = Cookie.SmartCookie() - s.load(str) - self.failIf(self.jar.isGoodCookieString(s.output())) + cout = c.output(header="") + cout_str = cout[:20] + 'this is bad' + cout[20:] + s = SimpleCookie() + s.load(cout_str) + self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_changed_exp(self): c = self.jar.makeCookie(self.exp, self.data) - cout = c.output() - str = cout[:26] + '2' + cout[27:] - s = Cookie.SmartCookie() - s.load(str) - self.failIf(self.jar.isGoodCookieString(s.output())) + cout = c.output(header="") + cout_str = self._corrupt_part_str(cout, 14, 16) + s = SimpleCookie() + s.load(cout_str) + self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_changed_data(self): c = self.jar.makeCookie(self.exp, self.data) - cout = c.output() - str = cout[:36] + 'X' + cout[37:] - s = Cookie.SmartCookie() - s.load(str) - self.failIf(self.jar.isGoodCookieString(s.output())) + cout = c.output(header="") + cout_str = self._corrupt_part_str(cout, 24, 26) + s = SimpleCookie() + s.load(cout_str) + self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_changed_mac(self): c = self.jar.makeCookie(self.exp, self.data) - cout = c.output() - str = cout[:76] + 'X' + cout[77:] - s = Cookie.SmartCookie() - s.load(str) - self.failIf(self.jar.isGoodCookieString(s.output())) + cout = c.output(header="") + cout_str = self._corrupt_part_str(cout, 64, 66) + s = SimpleCookie() + s.load(cout_str) + self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def suite(): @@ -141,7 +166,6 @@ def suite(): if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_bio.py b/tests/test_bio.py index 1d7b0c3..d2b4fa4 100644 --- a/tests/test_bio.py +++ b/tests/test_bio.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import absolute_import """ Unit tests for M2Crypto.BIO. @@ -8,69 +9,86 @@ Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Copyright (c) 2006 Open Source Applications Foundation Author: Heikki Toivonen """ +import logging -import unittest from M2Crypto import BIO, Rand +from tests import unittest +from tests.fips import fips_mode + +log = logging.getLogger('test_bio') -from fips import fips_mode class CipherStreamTestCase(unittest.TestCase): def try_algo(self, algo): - enc = 1 - dec = 0 - data = '123456789012345678901234' + data = b'123456789012345678901234' + my_key = 3 * 15 * b"key" + my_IV = 3 * 16 * b'IV' # Encrypt. mem = BIO.MemoryBuffer() cf = BIO.CipherStream(mem) - cf.set_cipher(algo, 'key', 'iv', 1) + cf.set_cipher(algo, my_key, my_IV, 1) cf.write(data) cf.flush() cf.write_close() cf.close() - xxx = mem.read() - + ciphertext = mem.read() + # Decrypt. - mem = BIO.MemoryBuffer(xxx) + mem = BIO.MemoryBuffer(ciphertext) cf = BIO.CipherStream(mem) - cf.set_cipher(algo, 'key', 'iv', 0) + cf.set_cipher(algo, my_key, my_IV, 0) cf.write_close() data2 = cf.read() cf.close() - assert not cf.readable() - - self.assertRaises(IOError, cf.read) - self.assertRaises(IOError, cf.readline) - self.assertRaises(IOError, cf.readlines) - - assert data == data2, '%s algorithm cipher test failed' % algo - + self.assertFalse(cf.readable()) + + with self.assertRaises(IOError): + cf.read() + with self.assertRaises(IOError): + cf.readline() + with self.assertRaises(IOError): + cf.readlines() + + self.assertEqual(data, data2, + '%s algorithm cipher test failed' % algo) + def test_ciphers(self): - ciphers=[ + ciphers = [ 'des_ede_ecb', 'des_ede_cbc', 'des_ede_cfb', 'des_ede_ofb', 'des_ede3_ecb', 'des_ede3_cbc', 'des_ede3_cfb', 'des_ede3_ofb', 'aes_128_ecb', 'aes_128_cbc', 'aes_128_cfb', 'aes_128_ofb', 'aes_192_ecb', 'aes_192_cbc', 'aes_192_cfb', 'aes_192_ofb', 'aes_256_ecb', 'aes_256_cbc', 'aes_256_cfb', 'aes_256_ofb'] - nonfips_ciphers=['bf_ecb', 'bf_cbc', 'bf_cfb', 'bf_ofb', - #'idea_ecb', 'idea_cbc', 'idea_cfb', 'idea_ofb', - 'cast5_ecb', 'cast5_cbc', 'cast5_cfb', 'cast5_ofb', - #'rc5_ecb', 'rc5_cbc', 'rc5_cfb', 'rc5_ofb', - 'des_ecb', 'des_cbc', 'des_cfb', 'des_ofb', - 'rc4', 'rc2_40_cbc'] - if not fips_mode: # Forbidden ciphers + nonfips_ciphers = ['bf_ecb', 'bf_cbc', 'bf_cfb', 'bf_ofb', + # 'idea_ecb', 'idea_cbc', 'idea_cfb', 'idea_ofb', + 'cast5_ecb', 'cast5_cbc', 'cast5_cfb', 'cast5_ofb', + # 'rc5_ecb', 'rc5_cbc', 'rc5_cfb', 'rc5_ofb', + 'des_ecb', 'des_cbc', 'des_cfb', 'des_ofb', + 'rc4', 'rc2_40_cbc'] + if not fips_mode: # Forbidden ciphers ciphers += nonfips_ciphers + + failed_ciphers = [] + log.debug('ciphers:\n%s', ciphers) for i in ciphers: - self.try_algo(i) + try: + self.try_algo(i) + except AssertionError: + failed_ciphers.append(i) + + self.assertEqual(len(failed_ciphers), 0, + "failed ciphers: %s" % ', '.join(failed_ciphers)) + + with self.assertRaises(ValueError): + self.try_algo('nosuchalgo4567') - self.assertRaises(ValueError, self.try_algo, 'nosuchalgo4567') def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(CipherStreamTestCase)) - return suite + t_suite = unittest.TestSuite() + t_suite.addTest(unittest.makeSuite(CipherStreamTestCase)) + return t_suite if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_bio_file.py b/tests/test_bio_file.py index e118386..fe0a8a7 100644 --- a/tests/test_bio_file.py +++ b/tests/test_bio_file.py @@ -4,75 +4,141 @@ Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" -import unittest -import M2Crypto +import logging +import os +import platform +import tempfile +import ctypes +if platform.system() == 'Windows': + import ctypes.wintypes + from M2Crypto.BIO import File, openfile -import os, sys +from tests import unittest + +log = logging.getLogger(__name__) + + +def getCountProcHandles(): + PROCESS_QUERY_INFORMATION = 0x400 + handle = ctypes.windll.kernel32.OpenProcess( + PROCESS_QUERY_INFORMATION, 0, os.getpid()) + hndcnt = ctypes.wintypes.DWORD() + ctypes.windll.kernel32.GetProcessHandleCount( + handle, ctypes.byref(hndcnt)) + sys_value = hndcnt.value + ctypes.windll.kernel32.CloseHandle(handle) + return sys_value + 1 + class FileTestCase(unittest.TestCase): def setUp(self): - self.data = 'abcdef' * 64 - if sys.platform != 'win32': - self.fname = os.tmpnam() + self.data = b'abcdef' * 64 + self.fd, self.fname = tempfile.mkstemp() + + if platform.system() in ['Linux', 'Darwin', 'FreeBSD']: + self.__dev_fd = "/dev/fd/" + + self.fd_count = self.__mfd() + + def __mfd(self): + if hasattr(self, '__dev_fd'): + return len(os.listdir(self.__dev_fd)) + elif platform.system() == 'Windows': + return getCountProcHandles() else: - import tempfile - self.fname = tempfile.mktemp() + return None def tearDown(self): + + self.assertEqual(self.fd_count, self.__mfd(), + "last test did not close all file descriptors properly") + try: - os.unlink(self.fname) + os.close(self.fd) except OSError: pass def test_openfile_rb(self): # First create the file using Python's open(). - f = open(self.fname, 'wb') - f.write(self.data) - f.close() + with open(self.fname, 'wb') as f: + f.write(self.data) + # Now open the file using M2Crypto.BIO.openfile(). - f = openfile(self.fname, 'rb') - data = f.read(len(self.data)) - assert data == self.data + with openfile(self.fname, 'rb') as f: + data = f.read(len(self.data)) + + self.assertEqual(data, self.data) def test_openfile_wb(self): # First create the file using M2Crypto.BIO.openfile(). - f = openfile(self.fname, 'wb') - f.write(self.data) - f.close() + with openfile(self.fname, 'wb') as f: + f.write(self.data) + # Now open the file using Python's open(). - f = open(self.fname, 'rb') - data = f.read(len(self.data)) - assert data == self.data + with open(self.fname, 'rb') as f: + data = f.read(len(self.data)) + + self.assertEqual(data, self.data) def test_closed(self): f = openfile(self.fname, 'wb') f.write(self.data) f.close() - self.assertRaises(IOError, f.write, self.data) + with self.assertRaises(IOError): + f.write(self.data) def test_use_pyfile(self): # First create the file. - f = open(self.fname, 'wb') - f2 = File(f) - f2.write(self.data) - f2.close() + with open(self.fname, 'wb') as f: + f2 = File(f) + f2.write(self.data) + f2.close() + # Now read the file. - f = open(self.fname, 'rb') - data = f.read(len(self.data)) - assert data == self.data + with open(self.fname, 'rb') as f: + in_data = f.read(len(self.data)) + + self.assertEqual(len(in_data), len(self.data)) + self.assertEqual(in_data, self.data) + + def test_readline_bin(self): + with open(self.fname, 'wb') as f: + f.write(b'hello\nworld\n') + with openfile(self.fname, 'rb') as f: + self.assertTrue(f.readable()) + self.assertEqual(f.readline(), b'hello\n') + self.assertEqual(f.readline(), b'world\n') + with openfile(self.fname, 'rb') as f: + self.assertEqual( + f.readlines(), + [b'hello\n', b'world\n']) + + def test_readline(self): + sep = os.linesep.encode() + with open(self.fname, 'w') as f: + f.write('hello\nworld\n') + with openfile(self.fname, 'rb') as f: + self.assertTrue(f.readable()) + self.assertEqual(f.readline(), b'hello' + sep) + self.assertEqual(f.readline(), b'world' + sep) + with openfile(self.fname, 'rb') as f: + self.assertEqual( + f.readlines(), + [b'hello' + sep, b'world' + sep]) + + def test_tell_seek(self): + with open(self.fname, 'w') as f: + f.write('hello world') + with openfile(self.fname, 'r') as f: + # Seek absolute + f.seek(6) + self.assertEqual(f.tell(), 6) def suite(): - # Python 2.2 warns that os.tmpnam() is unsafe. - try: - import warnings - warnings.filterwarnings('ignore') - except ImportError: - pass return unittest.makeSuite(FileTestCase) - + if __name__ == '__main__': unittest.TextTestRunner().run(suite()) - diff --git a/tests/test_bio_iobuf.py b/tests/test_bio_iobuf.py index 358e5df..372fd04 100644 --- a/tests/test_bio_iobuf.py +++ b/tests/test_bio_iobuf.py @@ -4,16 +4,16 @@ Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" -from cStringIO import StringIO +from io import BytesIO -import unittest -import M2Crypto from M2Crypto.BIO import IOBuffer, MemoryBuffer +from tests import unittest + class IOBufferTestCase(unittest.TestCase): def setUp(self): - self._data = 'abcdef\n' + self._data = b'abcdef\n' self.data = self._data * 1024 def tearDown(self): @@ -23,30 +23,30 @@ class IOBufferTestCase(unittest.TestCase): mb = MemoryBuffer() io = IOBuffer(mb) out = io.read() - assert out == '' + self.assertEqual(out, b'') def test_init_something(self): mb = MemoryBuffer(self.data) io = IOBuffer(mb) out = io.read(len(self.data)) - assert out == self.data + self.assertEqual(out, self.data) def test_read_less_than(self): chunk = len(self.data) - 7 mb = MemoryBuffer(self.data) io = IOBuffer(mb) out = io.read(chunk) - assert out == self.data[:chunk] - + self.assertEqual(out, self.data[:chunk]) + def test_read_more_than(self): chunk = len(self.data) + 8 mb = MemoryBuffer(self.data) io = IOBuffer(mb) out = io.read(chunk) - assert out == self.data + self.assertEqual(out, self.data) def test_readline(self): - buf = StringIO() + buf = BytesIO() mb = MemoryBuffer(self.data) io = IOBuffer(mb) while 1: @@ -54,37 +54,38 @@ class IOBufferTestCase(unittest.TestCase): if not out: break buf.write(out) - assert out == self._data - assert buf.getvalue() == self.data + self.assertEqual(out, self._data) + self.assertEqual(buf.getvalue(), self.data) def test_readlines(self): - buf = StringIO() + buf = BytesIO() mb = MemoryBuffer(self.data) io = IOBuffer(mb) lines = io.readlines() for line in lines: - assert line == self._data + self.assertEqual(line, self._data) buf.write(line) - assert buf.getvalue() == self.data + self.assertEqual(buf.getvalue(), self.data) def test_closed(self): mb = MemoryBuffer(self.data) io = IOBuffer(mb) io.close() - self.assertRaises(IOError, io.write, self.data) + with self.assertRaises(IOError): + io.write(self.data) assert not io.readable() and not io.writeable() def test_read_only(self): mb = MemoryBuffer(self.data) io = IOBuffer(mb, mode='r') - self.assertRaises(IOError, io.write, self.data) + with self.assertRaises(IOError): + io.write(self.data) assert not io.writeable() def suite(): return unittest.makeSuite(IOBufferTestCase) - + if __name__ == '__main__': unittest.TextTestRunner().run(suite()) - diff --git a/tests/test_bio_membuf.py b/tests/test_bio_membuf.py index 7d719fd..49a0e24 100644 --- a/tests/test_bio_membuf.py +++ b/tests/test_bio_membuf.py @@ -4,61 +4,114 @@ Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" -import unittest -import M2Crypto +import os +import multiprocessing + from M2Crypto.BIO import MemoryBuffer +from tests import unittest + + +class TimeLimitExpired(Exception): + pass + + +def time_limit(timeout, func, exc_msg, *args, **kwargs): + p = multiprocessing.Process(target=func) + p.start() + p.join(timeout) + if p.is_alive(): + p.terminate() + raise TimeLimitExpired(exc_msg) + class MemoryBufferTestCase(unittest.TestCase): def setUp(self): - self.data = 'abcdef' * 64 + self.data = b'abcdef' * 64 def tearDown(self): pass def test_init_empty(self): mb = MemoryBuffer() - assert len(mb) == 0 + self.assertEqual(len(mb), 0) out = mb.read() assert out is None + def test_init_empty_cm(self): + with MemoryBuffer() as mb: + self.assertEqual(len(mb), 0) + out = mb.read() + assert out is None + def test_init_something(self): mb = MemoryBuffer(self.data) - assert len(mb) == len(self.data) + self.assertEqual(len(mb), len(self.data)) out = mb.read() - assert out == self.data + self.assertEqual(out, self.data) + + def test_init_something_result_bytes(self): + mb = MemoryBuffer(self.data) + self.assertEqual(len(mb), len(self.data)) + out = mb.read() + self.assertIsInstance(out, bytes) + + def test_init_something_cm(self): + with MemoryBuffer(self.data) as mb: + self.assertEqual(len(mb), len(self.data)) + out = mb.read() + self.assertEqual(out, self.data) def test_read_less_than(self): chunk = len(self.data) - 7 mb = MemoryBuffer(self.data) out = mb.read(chunk) - assert out == self.data[:chunk] and len(mb) == (len(self.data) - chunk) - + self.assertEqual(out, self.data[:chunk]) + self.assertEqual(len(mb), (len(self.data)) - chunk) + def test_read_more_than(self): chunk = len(self.data) + 8 mb = MemoryBuffer(self.data) out = mb.read(chunk) - assert out == self.data and len(mb) == 0 + self.assertEqual(out, self.data) + self.assertEqual(len(mb), 0) def test_write_close(self): mb = MemoryBuffer(self.data) assert mb.writeable() mb.write_close() assert mb.readable() - self.assertRaises(IOError, mb.write, self.data) + with self.assertRaises(IOError): + mb.write(self.data) assert not mb.writeable() def test_closed(self): mb = MemoryBuffer(self.data) mb.close() - self.assertRaises(IOError, mb.write, self.data) + with self.assertRaises(IOError): + mb.write(self.data) assert mb.readable() and not mb.writeable() + def test_readline(self): + # test against possible endless loop + # http://stackoverflow.com/questions/9280550/ + timeout_secs = 10 + time_limit(timeout_secs, run_test, + 'The readline() should not timeout!') + + +def run_test(*args, **kwargs): + sep = os.linesep.encode() + with MemoryBuffer(b'hello\nworld\n') as mb: + assert mb.readable() + assert mb.readline() == b'hello' + sep + assert mb.readline() == b'world' + sep + with MemoryBuffer(b'hello\nworld\n') as mb: + assert mb.readlines() == [b'hello' + sep, b'world' + sep] def suite(): return unittest.makeSuite(MemoryBufferTestCase) - + if __name__ == '__main__': unittest.TextTestRunner().run(suite()) - diff --git a/tests/test_bio_ssl.py b/tests/test_bio_ssl.py index 0dee9da..1f9ae89 100644 --- a/tests/test_bio_ssl.py +++ b/tests/test_bio_ssl.py @@ -1,28 +1,34 @@ #!/usr/bin/env python +from __future__ import absolute_import, print_function + """Unit tests for M2Crypto.BIO.File. Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" -import unittest, threading, sys, socket +import socket +import sys +import threading -from M2Crypto import BIO -from M2Crypto import SSL +from M2Crypto import BIO +from M2Crypto import SSL from M2Crypto import Err from M2Crypto import Rand from M2Crypto import threading as m2threading -from test_ssl import srv_host, srv_port +from tests import unittest +from tests.test_ssl import srv_host, allocate_srv_port + class HandshakeClient(threading.Thread): - + def __init__(self, host, port): threading.Thread.__init__(self) self.host = host self.port = port - + def run(self): ctx = SSL.Context() - ctx.load_cert_chain("tests/server.pem") + ctx.load_cert_chain("tests/server.pem") conn = SSL.Connection(ctx) cipher_list = conn.get_cipher_list() sslbio = BIO.SSLBio() @@ -33,92 +39,96 @@ class HandshakeClient(threading.Thread): conn.set_connect_state() sock = socket.socket() sock.connect((self.host, self.port)) - + handshake_complete = False while not handshake_complete: ret = sslbio.do_handshake() - if ret <= 0: + if ret <= 0: if not sslbio.should_retry() or not sslbio.should_read(): - err_string = Err.get_error() - print err_string + err_string = Err.get_error() + print(err_string) sys.exit("unrecoverable error in handshake - client") else: - output_token = writebio.read() - if output_token is not None: - sock.sendall(output_token) - else: - input_token = sock.recv(1024) - readbio.write(input_token) + output_token = writebio.read() + if output_token is not None: + sock.sendall(output_token) + else: + input_token = sock.recv(1024) + readbio.write(input_token) else: - handshake_complete = True - + handshake_complete = True + + output_token = writebio.read() + if output_token is not None: + sock.sendall(output_token) sock.close() class SSLTestCase(unittest.TestCase): - + def setUp(self): self.sslbio = BIO.SSLBio() - - def test_pass(self): # XXX leaks 64/24 bytes + + def test_pass(self): # XXX leaks 64/24 bytes pass - def test_set_ssl(self): # XXX leaks 64/1312 bytes + def test_set_ssl(self): # XXX leaks 64/1312 bytes ctx = SSL.Context() conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) - def test_do_handshake_fail(self): # XXX leaks 64/42066 bytes + def test_do_handshake_fail(self): # XXX leaks 64/42066 bytes ctx = SSL.Context() conn = SSL.Connection(ctx) conn.set_connect_state() self.sslbio.set_ssl(conn) - ret = self.sslbio.do_handshake() - assert ret == 0 + ret = self.sslbio.do_handshake() + self.assertIn(ret, (-1, 0)) - def test_should_retry_fail(self): # XXX leaks 64/1312 bytes + def test_should_retry_fail(self): # XXX leaks 64/1312 bytes ctx = SSL.Context() - conn = SSL.Connection(ctx) + conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) - ret = self.sslbio.do_handshake() - assert ret == -1 - ret = self.sslbio.should_retry() - assert ret == 0 - - def test_should_write_fail(self): # XXX leaks 64/1312 bytes + ret = self.sslbio.do_handshake() + self.assertIn(ret, (-1, 0)) + ret = self.sslbio.should_retry() + self.assertEqual(ret, 0) + + def test_should_write_fail(self): # XXX leaks 64/1312 bytes ctx = SSL.Context() - conn = SSL.Connection(ctx) + conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) - ret = self.sslbio.do_handshake() - assert ret == -1 - ret = self.sslbio.should_write() - assert ret == 0 - - def test_should_read_fail(self): # XXX leaks 64/1312 bytes + ret = self.sslbio.do_handshake() + self.assertIn(ret, (-1, 0)) + ret = self.sslbio.should_write() + self.assertEqual(ret, 0) + + def test_should_read_fail(self): # XXX leaks 64/1312 bytes ctx = SSL.Context() conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) - ret = self.sslbio.do_handshake() - assert ret == -1 - ret = self.sslbio.should_read() - assert ret == 0 - - def test_do_handshake_succeed(self): # XXX leaks 196/26586 bytes - ctx = SSL.Context() + ret = self.sslbio.do_handshake() + self.assertIn(ret, (-1, 0)) + ret = self.sslbio.should_read() + self.assertEqual(ret, 0) + + def test_do_handshake_succeed(self): # XXX leaks 196/26586 bytes + ctx = SSL.Context() ctx.load_cert_chain("tests/server.pem") - conn = SSL.Connection(ctx) + conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) readbio = BIO.MemoryBuffer() writebio = BIO.MemoryBuffer() conn.set_bio(readbio, writebio) conn.set_accept_state() handshake_complete = False + srv_port = allocate_srv_port() sock = socket.socket() sock.bind((srv_host, srv_port)) sock.listen(5) handshake_client = HandshakeClient(srv_host, srv_port) - handshake_client.start() - new_sock, addr = sock.accept() + handshake_client.start() + new_sock, _ = sock.accept() while not handshake_complete: input_token = new_sock.recv(1024) readbio.write(input_token) @@ -130,17 +140,18 @@ class SSLTestCase(unittest.TestCase): else: handshake_complete = True - output_token = writebio.read() + output_token = writebio.read() if output_token is not None: new_sock.sendall(output_token) - - handshake_client.join() - sock.close() - new_sock.close() -def suite(): + handshake_client.join() + sock.close() + new_sock.close() + + +def suite(): return unittest.makeSuite(SSLTestCase) - + if __name__ == '__main__': Rand.load_file('randpool.dat', -1) diff --git a/tests/test_bn.py b/tests/test_bn.py old mode 100755 new mode 100644 index 62c83fe..410969a --- a/tests/test_bn.py +++ b/tests/test_bn.py @@ -6,18 +6,22 @@ Unit tests for M2Crypto.BN. Copyright (c) 2005 Open Source Applications Foundation. All rights reserved. """ -import unittest, re +import re +import warnings + from M2Crypto import BN, Rand +from tests import unittest loops = 16 + class BNTestCase(unittest.TestCase): def test_rand(self): # defaults for x in range(loops): r8 = BN.rand(8) - + # top for x in range(loops): r8 = BN.rand(8, top=0) @@ -25,7 +29,7 @@ class BNTestCase(unittest.TestCase): for x in range(loops): r8 = BN.rand(8, top=1) assert r8 & 192 - + # bottom for x in range(loops): r8 = BN.rand(8, bottom=1) @@ -41,38 +45,37 @@ class BNTestCase(unittest.TestCase): r256 = BN.rand(256, top=0) r512 = BN.rand(512, top=0) assert r8 < r16 < r32 < r64 < r128 < r256 < r512 < (r512 + 1) - def test_rand_range(self): # small range for x in range(loops): r = BN.rand_range(1) - assert r == 0 - + self.assertEqual(r, 0) + for x in range(loops): r = BN.rand_range(4) assert 0 <= r < 4 - + # large range r512 = BN.rand(512, top=0) for x in range(loops): r = BN.rand_range(r512) assert 0 <= r < r512 - def test_randfname(self): m = re.compile('^[a-zA-Z0-9]{8}$') for x in range(loops): - r = BN.randfname(8) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + r = BN.randfname(8) assert m.match(r) - + def suite(): return unittest.makeSuite(BNTestCase) if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_dh.py b/tests/test_dh.py index 0e66c89..074f154 100644 --- a/tests/test_dh.py +++ b/tests/test_dh.py @@ -4,41 +4,43 @@ Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" -import unittest -from M2Crypto import DH, BIO, Rand, m2 +from M2Crypto import DH, BIO, Rand +from tests import unittest + class DHTestCase(unittest.TestCase): params = 'tests/dhparam.pem' def genparam_callback(self, *args): - pass + pass def genparam_callback2(self): - pass + pass def test_init_junk(self): - self.assertRaises(TypeError, DH.DH, 'junk') + with self.assertRaises(TypeError): + DH.DH('junk') def test_gen_params(self): a = DH.gen_params(1024, 2, self.genparam_callback) - assert a.check_params() == 0 + self.assertEqual(a.check_params(), 0) def test_gen_params_bad_cb(self): a = DH.gen_params(1024, 2, self.genparam_callback2) - assert a.check_params() == 0 + self.assertEqual(a.check_params(), 0) def test_print_params(self): a = DH.gen_params(1024, 2, self.genparam_callback) bio = BIO.MemoryBuffer() a.print_params(bio) params = bio.read() - assert params.find('(1024 bit)') - assert params.find('generator: 2 (0x2)') + self.assertTrue(params.find(b'(1024 bit)')) + self.assertTrue(params.find(b'generator: 2 (0x2)')) def test_load_params(self): a = DH.load_params('tests/dhparams.pem') - assert a.check_params() == 0 + self.assertEqual(a.check_params(), 0) def test_compute_key(self): a = DH.load_params('tests/dhparams.pem') @@ -47,19 +49,20 @@ class DHTestCase(unittest.TestCase): b.gen_key() ak = a.compute_key(b.pub) bk = b.compute_key(a.pub) - assert ak == bk + self.assertEqual(ak, bk) self.assertEqual(len(a), 128) - self.assertRaises(DH.DHError, setattr, a, 'p', 1) - self.assertRaises(DH.DHError, setattr, a, 'priv', 1) + with self.assertRaises(DH.DHError): + setattr(a, 'p', 1) + with self.assertRaises(DH.DHError): + setattr(a, 'priv', 1) def suite(): return unittest.makeSuite(DHTestCase) -if __name__=='__main__': - Rand.load_file('randpool.dat', -1) +if __name__ == '__main__': + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_dsa.py b/tests/test_dsa.py index 7823f50..a9a940a 100644 --- a/tests/test_dsa.py +++ b/tests/test_dsa.py @@ -4,38 +4,44 @@ Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" -import unittest -import sha -from M2Crypto import DSA, BIO, Rand, m2 +import hashlib + +from M2Crypto import DSA, Rand +from tests import unittest + class DSATestCase(unittest.TestCase): - errkey = 'tests/rsa.priv.pem' + errkey = 'tests/rsa.priv.pem' privkey = 'tests/dsa.priv.pem' - pubkey = 'tests/dsa.pub.pem' - param = 'tests/dsa.param.pem' + pubkey = 'tests/dsa.pub.pem' + param = 'tests/dsa.param.pem' - data = sha.sha('Can you spell subliminal channel?').digest() - different_data = sha.sha('I can spell.').digest() + data = hashlib.sha1(b'Can you spell subliminal channel?').digest() + different_data = hashlib.sha1(b'I can spell.').digest() def callback(self, *args): pass def test_loadkey_junk(self): - self.assertRaises(DSA.DSAError, DSA.load_key, self.errkey) + with self.assertRaises(DSA.DSAError): + DSA.load_key(self.errkey) def test_loadkey(self): dsa = DSA.load_key(self.privkey) - assert len(dsa) == 1024 - self.assertRaises(AttributeError, getattr, dsa, 'foobar') + self.assertEqual(len(dsa), 1024) + with self.assertRaises(AttributeError): + getattr(dsa, 'foobar') for k in ('p', 'q', 'g', 'priv', 'pub'): - self.assertRaises(DSA.DSAError, setattr, dsa, k, 1) + with self.assertRaises(DSA.DSAError): + setattr(dsa, k, 1) def test_loadparam(self): - self.assertRaises(DSA.DSAError, DSA.load_key, self.param) + with self.assertRaises(DSA.DSAError): + DSA.load_key(self.param) dsa = DSA.load_params(self.param) assert not dsa.check_key() - assert len(dsa) == 1024 + self.assertEqual(len(dsa), 1024) def test_sign(self): dsa = DSA.load_key(self.privkey) @@ -51,8 +57,10 @@ class DSATestCase(unittest.TestCase): def test_sign_with_params_only(self): dsa = DSA.load_params(self.param) - self.assertRaises(AssertionError, dsa.sign, self.data) - self.assertRaises(AssertionError, dsa.sign_asn1, self.data) + with self.assertRaises(AssertionError): + dsa.sign(self.data) + with self.assertRaises(AssertionError): + dsa.sign_asn1(self.data) def test_pub_verify(self): dsa = DSA.load_key(self.privkey) @@ -60,7 +68,8 @@ class DSATestCase(unittest.TestCase): dsapub = DSA.load_pub_key(self.pubkey) assert dsapub.check_key() assert dsapub.verify(self.data, r, s) - self.assertRaises(DSA.DSAError, dsapub.sign) + with self.assertRaises(DSA.DSAError): + dsapub.sign() def test_verify_fail(self): dsa = DSA.load_key(self.privkey) @@ -69,30 +78,44 @@ class DSATestCase(unittest.TestCase): def test_verify_fail2(self): dsa = DSA.load_key(self.privkey) - r,s = dsa.sign(self.data) + r, s = dsa.sign(self.data) dsa2 = DSA.load_params(self.param) assert not dsa2.check_key() - self.assertRaises(AssertionError, dsa2.verify, self.data, r, s) + with self.assertRaises(AssertionError): + dsa2.verify(self.data, r, s) def test_genparam_setparam_genkey(self): dsa = DSA.gen_params(1024, self.callback) - assert len(dsa) == 1024 + self.assertEqual(len(dsa), 1024) p = dsa.p q = dsa.q g = dsa.g - dsa2 = DSA.set_params(p,q,g) + dsa2 = DSA.set_params(p, q, g) assert not dsa2.check_key() dsa2.gen_key() assert dsa2.check_key() - r,s = dsa2.sign(self.data) + r, s = dsa2.sign(self.data) + assert dsa2.verify(self.data, r, s) + + def test_pub_key_from_params(self): + dsa = DSA.gen_params(1024, self.callback) + dsa.gen_key() + assert len(dsa) == 1024 + p = dsa.p + q = dsa.q + g = dsa.g + pub = dsa.pub + dsa2 = DSA.pub_key_from_params(p, q, g, pub) + assert dsa2.check_key() + r, s = dsa.sign(self.data) assert dsa2.verify(self.data, r, s) + def suite(): return unittest.makeSuite(DSATestCase) - + if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_ec_curves.py b/tests/test_ec_curves.py index d01f863..c15dcec 100644 --- a/tests/test_ec_curves.py +++ b/tests/test_ec_curves.py @@ -1,150 +1,163 @@ #!/usr/bin/env python # XXX memory leaks +from __future__ import absolute_import + """ Unit tests for M2Crypto.EC, the curves - + There are several ways one could unittest elliptical curves - but we are going to only validate that we are using the + but we are going to only validate that we are using the OpenSSL curve and that it works with ECDSA. We will assume - OpenSSL has validated the curves themselves. - - Also, some curves are shorter than a SHA-1 digest of 160 + OpenSSL has validated the curves themselves. + + Also, some curves are shorter than a SHA-1 digest of 160 bits. To keep the testing simple, we will take advantage - of ECDSA's ability to sign any digest length and create a + of ECDSA's ability to sign any digest length and create a digset string of only 48 bits. Remember we are testing our ability to access the curve, not ECDSA itself. - + Copyright (c) 2006 Larry Bugbee. All rights reserved. - + """ +import logging + +from M2Crypto import EC, Rand, m2 # noqa +from tests import unittest + +log = logging.getLogger(__name__) + + +curves = { + 'secp112r1': 112, + 'secp112r2': 112, + 'secp128r1': 128, + 'secp128r2': 128, + 'secp160k1': 160, + 'secp160r1': 160, + 'secp160r2': 160, + 'secp192k1': 192, + 'secp224k1': 224, + 'secp224r1': 224, + 'secp256k1': 256, + 'secp384r1': 384, + 'secp521r1': 521, + + 'sect113r1': 113, + 'sect113r2': 113, + 'sect131r1': 131, + 'sect131r2': 131, + 'sect163k1': 163, + 'sect163r1': 163, + 'sect163r2': 163, + 'sect193r1': 193, + 'sect193r2': 193, + 'sect233k1': 233, + 'sect233r1': 233, + 'sect239k1': 239, + 'sect283k1': 283, + 'sect283r1': 283, + 'sect409k1': 409, + 'sect409r1': 409, + 'sect571k1': 571, + 'sect571r1': 571, + + 'X9_62_prime192v1': 192, + 'X9_62_prime192v2': 192, + 'X9_62_prime192v3': 192, + 'X9_62_prime239v1': 239, + 'X9_62_prime239v2': 239, + 'X9_62_prime239v3': 239, + 'X9_62_prime256v1': 256, -import unittest -#import sha -from M2Crypto import EC, Rand -from test_ecdsa import ECDSATestCase as ECDSATest - - -curves = [ - ('secp112r1', 112), - ('secp112r2', 112), - ('secp128r1', 128), - ('secp128r2', 128), - ('secp160k1', 160), - ('secp160r1', 160), - ('secp160r2', 160), - ('secp192k1', 192), - ('secp224k1', 224), - ('secp224r1', 224), - ('secp256k1', 256), - ('secp384r1', 384), - ('secp521r1', 521), - - ('sect113r1', 113), - ('sect113r2', 113), - ('sect131r1', 131), - ('sect131r2', 131), - ('sect163k1', 163), - ('sect163r1', 163), - ('sect163r2', 163), - ('sect193r1', 193), - ('sect193r2', 193), - ('sect233k1', 233), - ('sect233r1', 233), - ('sect239k1', 239), - ('sect283k1', 283), - ('sect283r1', 283), - ('sect409k1', 409), - ('sect409r1', 409), - ('sect571k1', 571), - ('sect571r1', 571), - - ('X9_62_prime192v1', 192), - ('X9_62_prime192v2', 192), - ('X9_62_prime192v3', 192), - ('X9_62_prime239v1', 239), - ('X9_62_prime239v2', 239), - ('X9_62_prime239v3', 239), - ('X9_62_prime256v1', 256), - - ('X9_62_c2pnb163v1', 163), - ('X9_62_c2pnb163v2', 163), - ('X9_62_c2pnb163v3', 163), - ('X9_62_c2pnb176v1', 176), - ('X9_62_c2tnb191v1', 191), - ('X9_62_c2tnb191v2', 191), - ('X9_62_c2tnb191v3', 191), - ('X9_62_c2pnb208w1', 208), - ('X9_62_c2tnb239v1', 239), - ('X9_62_c2tnb239v2', 239), - ('X9_62_c2tnb239v3', 239), - ('X9_62_c2pnb272w1', 272), - ('X9_62_c2pnb304w1', 304), - ('X9_62_c2tnb359v1', 359), - ('X9_62_c2pnb368w1', 368), - ('X9_62_c2tnb431r1', 431), - - ('wap_wsg_idm_ecid_wtls1', 113), - ('wap_wsg_idm_ecid_wtls3', 163), - ('wap_wsg_idm_ecid_wtls4', 113), - ('wap_wsg_idm_ecid_wtls5', 163), - ('wap_wsg_idm_ecid_wtls6', 112), - ('wap_wsg_idm_ecid_wtls7', 160), - ('wap_wsg_idm_ecid_wtls8', 112), - ('wap_wsg_idm_ecid_wtls9', 160), - ('wap_wsg_idm_ecid_wtls10', 233), - ('wap_wsg_idm_ecid_wtls11', 233), - ('wap_wsg_idm_ecid_wtls12', 224), -] - -# The following two curves, according to OpenSSL, have a -# "Questionable extension field!" and are not supported by + 'X9_62_c2pnb163v1': 163, + 'X9_62_c2pnb163v2': 163, + 'X9_62_c2pnb163v3': 163, + 'X9_62_c2pnb176v1': 176, + 'X9_62_c2tnb191v1': 191, + 'X9_62_c2tnb191v2': 191, + 'X9_62_c2tnb191v3': 191, + 'X9_62_c2pnb208w1': 208, + 'X9_62_c2tnb239v1': 239, + 'X9_62_c2tnb239v2': 239, + 'X9_62_c2tnb239v3': 239, + 'X9_62_c2pnb272w1': 272, + 'X9_62_c2pnb304w1': 304, + 'X9_62_c2tnb359v1': 359, + 'X9_62_c2pnb368w1': 368, + 'X9_62_c2tnb431r1': 431, + + 'wap_wsg_idm_ecid_wtls1': 113, + 'wap_wsg_idm_ecid_wtls3': 163, + 'wap_wsg_idm_ecid_wtls4': 113, + 'wap_wsg_idm_ecid_wtls5': 163, + 'wap_wsg_idm_ecid_wtls6': 112, + 'wap_wsg_idm_ecid_wtls7': 160, + 'wap_wsg_idm_ecid_wtls8': 112, + 'wap_wsg_idm_ecid_wtls9': 160, + 'wap_wsg_idm_ecid_wtls10': 233, + 'wap_wsg_idm_ecid_wtls11': 233, + 'wap_wsg_idm_ecid_wtls12': 224 +} + +# The following two curves, according to OpenSSL, have a +# "Questionable extension field!" and are not supported by # the OpenSSL inverse function. ECError: no inverse. -# As such they cannot be used for signing. They might, -# however, be usable for encryption but that has not +# As such they cannot be used for signing. They might, +# however, be usable for encryption but that has not # been tested. Until thir usefulness can be established, # they are not supported at this time. -#curves2 = [ +# curves2 = [ # ('ipsec3', 155), # ('ipsec4', 185), -#] +# ] + + +def available_curves(): + bc_dict = EC.get_builtin_curves() + bin_curves = set(x['sname'] for x in bc_dict) + out_curves = tuple((m2.obj_sn2nid(x[0]), x[1]) for x in curves + if x[0] in bin_curves) + return out_curves + +# Seems like one of the most widely supported curves. +tested_curve = EC.NID_secp384r1, curves['secp384r1'] + class ECCurveTests(unittest.TestCase): - #data = sha.sha('Kilroy was here!').digest() # 160 bits - data = "digest" # keep short (48 bits) so lesser curves - # will work... ECDSA requires curve be - # equal or longer than digest - - def genkey(self, curveName, curveLen): - curve = getattr(EC, 'NID_'+curveName) - ec = EC.gen_params(curve) - assert len(ec) == curveLen + data = "digest" + + def genkey(self, curve): + try: + curve_name = m2.obj_nid2sn(curve[0]) + except TypeError: + # we have to throw different exception for compatibility + raise AttributeError('Unknown cipher %s', curve[0]) + ec = EC.gen_params(curve[0]) + self.assertEqual(len(ec), curve[1]) ec.gen_key() - assert ec.check_key(), 'check_key() failure for "%s"' % curveName + self.assertTrue(ec.check_key(), + 'check_key() failure for "%s"' % + curve_name) return ec -# def check_ec_curves_genkey(self): -# for curveName, curveLen in curves2: -# self.genkey(curveName, curveLen) -# -# self.assertRaises(AttributeError, self.genkey, -# 'nosuchcurve', 1) - - def sign_verify_ecdsa(self, curveName, curveLen): - ec = self.genkey(curveName, curveLen) + def sign_verify_ecdsa(self, curve): + ec = self.genkey(curve) r, s = ec.sign_dsa(self.data) - assert ec.verify_dsa(self.data, r, s) - assert not ec.verify_dsa(self.data, s, r) + self.assertTrue(ec.verify_dsa(self.data, r, s)) + self.assertFalse(ec.verify_dsa(self.data, s, r)) - def test_ec_curves_ECDSA(self): - for curveName, curveLen in curves: - self.sign_verify_ecdsa(curveName, curveLen) + def test_ec_curves_ECDSA(self): # noqa + for curve in available_curves(): + self.sign_verify_ecdsa(curve) - self.assertRaises(AttributeError, self.sign_verify_ecdsa, - 'nosuchcurve', 1) + with self.assertRaises(AttributeError): + self.sign_verify_ecdsa(('nosuchcurve', 1)) + + def test_ec_get_builtin_curves(self): + curves = EC.get_builtin_curves() + self.assertNotEqual(curves, []) + self.assertIsNotNone(curves) -# for curveName, curveLen in curves2: -# self.assertRaises(EC.ECError, self.sign_verify_ecdsa, -# curveName, curveLen) def suite(): suite = unittest.TestSuite() @@ -153,7 +166,6 @@ def suite(): if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_ecdh.py b/tests/test_ecdh.py index 29581dc..0dc4600 100644 --- a/tests/test_ecdh.py +++ b/tests/test_ecdh.py @@ -3,47 +3,49 @@ """Unit tests for M2Crypto.EC, ECDH part. Copyright (c) 2000 Ng Pheng Siong. All rights reserved. -Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. +Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All +rights reserved. """ +from M2Crypto import EC, Rand + +from tests import unittest +from tests.test_ec_curves import tested_curve -import unittest -from M2Crypto import EC, BIO, Rand, m2 -import sys class ECDHTestCase(unittest.TestCase): privkey = 'tests/ec.priv.pem' def test_init_junk(self): - self.assertRaises(TypeError, EC.EC, 'junk') + with self.assertRaises(TypeError): + EC.EC('junk') def test_compute_key(self): a = EC.load_key(self.privkey) - b = EC.gen_params(EC.NID_sect233k1) + b = EC.gen_params(tested_curve[0]) b.gen_key() ak = a.compute_dh_key(b.pub()) bk = b.compute_dh_key(a.pub()) - assert ak == bk + self.assertEqual(ak, bk) def test_pubkey_from_der(self): - a = EC.gen_params(EC.NID_sect233k1) + a = EC.gen_params(tested_curve[0]) a.gen_key() - b = EC.gen_params(EC.NID_sect233k1) + b = EC.gen_params(tested_curve[0]) b.gen_key() a_pub_der = a.pub().get_der() a_pub = EC.pub_key_from_der(a_pub_der) ak = a.compute_dh_key(b.pub()) bk = b.compute_dh_key(a_pub) - assert ak == bk + self.assertEqual(ak, bk) def suite(): return unittest.makeSuite(ECDHTestCase) -if __name__=='__main__': - Rand.load_file('randpool.dat', -1) +if __name__ == '__main__': + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_ecdsa.py b/tests/test_ecdsa.py index 74d9a82..dea1209 100644 --- a/tests/test_ecdsa.py +++ b/tests/test_ecdsa.py @@ -3,12 +3,19 @@ """Unit tests for M2Crypto.EC, ECDSA part. Copyright (c) 2000 Ng Pheng Siong. All rights reserved. -Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. +Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All +rights reserved. """ +import hashlib +import logging + +from M2Crypto import EC, Rand + +from tests import unittest +from tests.test_ec_curves import tested_curve + +log = logging.getLogger(__name__) -import unittest -import sha -from M2Crypto import EC, BIO, Rand, m2 class ECDSATestCase(unittest.TestCase): @@ -16,7 +23,7 @@ class ECDSATestCase(unittest.TestCase): privkey = 'tests/ec.priv.pem' pubkey = 'tests/ec.pub.pem' - data = sha.sha('Can you spell subliminal channel?').digest() + data = hashlib.sha1(b'Can you spell subliminal channel?').digest() def callback(self, *args): pass @@ -25,22 +32,25 @@ class ECDSATestCase(unittest.TestCase): pass def test_loadkey_junk(self): - self.assertRaises(ValueError, EC.load_key, self.errkey) + with self.assertRaises(ValueError): + EC.load_key(self.errkey) def test_loadkey(self): ec = EC.load_key(self.privkey) - assert len(ec) == 233 + self.assertEqual(len(ec), tested_curve[1]) def test_loadpubkey(self): # XXX more work needed ec = EC.load_pub_key(self.pubkey) - assert len(ec) == 233 - self.assertRaises(EC.ECError, EC.load_pub_key, self.errkey) + self.assertEqual(len(ec), tested_curve[1]) + with self.assertRaises(EC.ECError): + EC.load_pub_key(self.errkey) def _test_sign_dsa(self): - ec = EC.gen_params(EC.NID_sect233k1) + ec = EC.gen_params(tested_curve[0]) # ec.gen_key() - self.assertRaises(EC.ECError, ec.sign_dsa, self.data) + with self.assertRaises(EC.ECError): + ec.sign_dsa(self.data) ec = EC.load_key(self.privkey) r, s = ec.sign_dsa(self.data) assert ec.verify_dsa(self.data, r, s) @@ -50,7 +60,8 @@ class ECDSATestCase(unittest.TestCase): ec = EC.load_key(self.privkey) blob = ec.sign_dsa_asn1(self.data) assert ec.verify_dsa_asn1(self.data, blob) - self.assertRaises(EC.ECError, ec.verify_dsa_asn1, blob, self.data) + with self.assertRaises(EC.ECError): + ec.verify_dsa_asn1(blob, self.data) def test_verify_dsa(self): ec = EC.load_key(self.privkey) @@ -58,18 +69,28 @@ class ECDSATestCase(unittest.TestCase): ec2 = EC.load_pub_key(self.pubkey) assert ec2.verify_dsa(self.data, r, s) assert not ec2.verify_dsa(self.data, s, r) - + def test_genparam(self): - ec = EC.gen_params(EC.NID_sect233k1) - assert len(ec) == 233 + ec = EC.gen_params(tested_curve[0]) + self.assertEqual(len(ec), tested_curve[1]) + + def test_pub_key_from_params(self): + curve = EC.NID_prime256v1 + ec = EC.gen_params(curve) + ec.gen_key() + ec_pub = ec.pub() + k = ec_pub.get_key() + ec2 = EC.pub_key_from_params(curve, k) + assert ec2.check_key() + r, s = ec.sign_dsa(self.data) + assert ec2.verify_dsa(self.data, r, s) def suite(): return unittest.makeSuite(ECDSATestCase) - + if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_engine.py b/tests/test_engine.py index 91c2aa8..5439ee3 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -2,8 +2,9 @@ """Unit tests for M2Crypto.Engine.""" -import unittest -from M2Crypto import Engine, m2 +from M2Crypto import Engine +from tests import unittest + class EngineTestCase(unittest.TestCase): @@ -14,19 +15,26 @@ class EngineTestCase(unittest.TestCase): Engine.cleanup() def test_by_id_junk(self): - self.assertRaises(ValueError, Engine.Engine, self.bad_id) - self.assertRaises(ValueError, Engine.Engine) + with self.assertRaises(ValueError): + Engine.Engine(self.bad_id) + with self.assertRaises(ValueError): + Engine.Engine() def test_by_id_openssl(self): Engine.load_openssl() e = Engine.Engine('openssl') self.assertEqual(e.get_name(), 'Software engine support') self.assertEqual(e.get_id(), 'openssl') - + def test_by_id_dynamic(self): Engine.load_dynamic() Engine.Engine('dynamic') - + + def test_engine_ctrl_cmd_string(self): + Engine.load_dynamic() + e = Engine.Engine('dynamic') + e.ctrl_cmd_string('ID', 'TESTID') + def test_load_private(self): Engine.load_openssl() e = Engine.Engine('openssl') @@ -37,12 +45,16 @@ class EngineTestCase(unittest.TestCase): Engine.load_openssl() e = Engine.Engine('openssl') e.set_default() - self.assertRaises(Engine.EngineError, e.load_certificate, '/dev/null') + try: + with self.assertRaises(Engine.EngineError): + e.load_certificate('/dev/null') + except SystemError: + pass + def suite(): return unittest.makeSuite(EngineTestCase) - + if __name__ == '__main__': unittest.TextTestRunner().run(suite()) - diff --git a/tests/test_err.py b/tests/test_err.py new file mode 100644 index 0000000..05fe425 --- /dev/null +++ b/tests/test_err.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Unit tests for M2Crypto.Err. + +Copyright (C) 2019 Matěj Cepl +Released under the terms of MIT/X11 License, +see the file LICENCE for more. +""" +from M2Crypto import Err +from tests import unittest + + +class ErrTestCase(unittest.TestCase): + + def test_no_error(self): + # Protection against gl#m2crypto/m2crypto#258 + self.assertEqual(Err.get_error_reason(0), '') + + + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(ErrTestCase)) + return suite + + +if __name__ == '__main__': + unittest.TextTestRunner().run(suite()) diff --git a/tests/test_evp.py b/tests/test_evp.py index ba09092..d133ed0 100644 --- a/tests/test_evp.py +++ b/tests/test_evp.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +from __future__ import absolute_import, division """ Unit tests for M2Crypto.EVP. @@ -7,183 +7,296 @@ Copyright (c) 2004-2007 Open Source Applications Foundation Author: Heikki Toivonen """ -import unittest -import cStringIO, sha -from binascii import hexlify, unhexlify -from M2Crypto import EVP, RSA, util, Rand, m2, BIO -from M2Crypto.util import h2b +import base64 +import hashlib +import io +import logging + +from binascii import a2b_hex, hexlify, unhexlify + +from M2Crypto import BIO, EVP, RSA, Rand, m2, util +from tests import unittest +from tests.fips import fips_mode + +log = logging.getLogger('test_EVP') -from fips import fips_mode class EVPTestCase(unittest.TestCase): def _gen_callback(self, *args): pass - + def _pass_callback(self, *args): - return 'foobar' - + return b'foobar' + def _assign_rsa(self): rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() - pkey.assign_rsa(rsa, capture=0) # capture=1 should cause crash + pkey.assign_rsa(rsa, capture=0) # capture=1 should cause crash return rsa - + def test_assign(self): rsa = self._assign_rsa() rsa.check_key() - + def test_pem(self): rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() pkey.assign_rsa(rsa) - assert pkey.as_pem(callback=self._pass_callback) != pkey.as_pem(cipher=None) - self.assertRaises(ValueError, pkey.as_pem, cipher='noXX$$%%suchcipher', - callback=self._pass_callback) - + + result_w_callback = pkey.as_pem(callback=self._pass_callback) + result_wo_callback = pkey.as_pem(cipher=None) + self.assertNotEqual(result_w_callback, result_wo_callback) + + with self.assertRaises(ValueError): + pkey.as_pem(cipher='noXX$$%%suchcipher', + callback=self._pass_callback) + def test_as_der(self): """ - Test DER encoding the PKey instance after assigning + Test DER encoding the PKey instance after assigning a RSA key to it. """ rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() pkey.assign_rsa(rsa) - der_blob = pkey.as_der() - #A quick but not thorough sanity check - assert len(der_blob) == 160 - - - def test_MessageDigest(self): - self.assertRaises(ValueError, EVP.MessageDigest, 'sha513') + der_blob = pkey.as_der() + # A quick but not thorough sanity check + self.assertEqual(len(der_blob), 160) + + def test_get_digestbyname(self): + with self.assertRaises(EVP.EVPError): + m2.get_digestbyname('sha513') + self.assertNotEqual(m2.get_digestbyname('sha1'), None) + + def test_MessageDigest(self): # noqa + with self.assertRaises(ValueError): + EVP.MessageDigest('sha513') + md = EVP.MessageDigest('sha1') + self.assertEqual(md.update(b'Hello'), 1) + self.assertEqual(util.octx_to_num(md.final()), + 1415821221623963719413415453263690387336440359920) + + # temporarily remove sha1 from m2 + old_sha1 = m2.sha1 + del m2.sha1 + + # now run the same test again, relying on EVP.MessageDigest() to call + # get_digestbyname() under the hood md = EVP.MessageDigest('sha1') - assert md.update('Hello') == 1 - assert util.octx_to_num(md.final()) == 1415821221623963719413415453263690387336440359920 + self.assertEqual(md.update(b'Hello'), 1) + self.assertEqual(util.octx_to_num(md.final()), + 1415821221623963719413415453263690387336440359920) + + # put sha1 back in place + m2.sha1 = old_sha1 def test_as_der_capture_key(self): """ - Test DER encoding the PKey instance after assigning + Test DER encoding the PKey instance after assigning a RSA key to it. Have the PKey instance capture the RSA key. """ rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() pkey.assign_rsa(rsa, 1) der_blob = pkey.as_der() - #A quick but not thorough sanity check - assert len(der_blob) == 160 + # A quick but not thorough sanity check + self.assertEqual(len(der_blob), 160) def test_size(self): rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() pkey.assign_rsa(rsa) - size = pkey.size() - assert size == 128 - + size = pkey.size() + self.assertEqual(size, 128) + def test_hmac(self): - assert util.octx_to_num(EVP.hmac('key', 'data')) == 92800611269186718152770431077867383126636491933, util.octx_to_num(EVP.hmac('key', 'data')) - if not fips_mode: # Disabled algorithms - assert util.octx_to_num(EVP.hmac('key', 'data', algo='md5')) == 209168838103121722341657216703105225176, util.octx_to_num(EVP.hmac('key', 'data', algo='md5')) - assert util.octx_to_num(EVP.hmac('key', 'data', algo='ripemd160')) == 1176807136224664126629105846386432860355826868536, util.octx_to_num(EVP.hmac('key', 'data', algo='ripemd160')) - - if m2.OPENSSL_VERSION_NUMBER >= 0x90800F: - assert util.octx_to_num(EVP.hmac('key', 'data', algo='sha224')) == 2660082265842109788381286338540662430962855478412025487066970872635, util.octx_to_num(EVP.hmac('key', 'data', algo='sha224')) - assert util.octx_to_num(EVP.hmac('key', 'data', algo='sha256')) == 36273358097036101702192658888336808701031275731906771612800928188662823394256, util.octx_to_num(EVP.hmac('key', 'data', algo='sha256')) - assert util.octx_to_num(EVP.hmac('key', 'data', algo='sha384')) == 30471069101236165765942696708481556386452105164815350204559050657318908408184002707969468421951222432574647369766282, util.octx_to_num(EVP.hmac('key', 'data', algo='sha384')) - assert util.octx_to_num(EVP.hmac('key', 'data', algo='sha512')) == 3160730054100700080556942280820129108466291087966635156623014063982211353635774277148932854680195471287740489442390820077884317620321797003323909388868696, util.octx_to_num(EVP.hmac('key', 'data', algo='sha512')) - - self.assertRaises(ValueError, EVP.hmac, 'key', 'data', algo='sha513') + self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data')), + 92800611269186718152770431077867383126636491933, + util.octx_to_num(EVP.hmac(b'key', b'data'))) + if not fips_mode: # Disabled algorithms + self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', + algo='md5')), + 209168838103121722341657216703105225176, + util.octx_to_num(EVP.hmac(b'key', b'data', + algo='md5'))) + self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', + algo='ripemd160')), + 1176807136224664126629105846386432860355826868536, + util.octx_to_num(EVP.hmac(b'key', b'data', + algo='ripemd160'))) + if m2.OPENSSL_VERSION_NUMBER >= 0x90800F: + self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', + algo='sha224')), + 2660082265842109788381286338540662430962855478412025487066970872635, + util.octx_to_num(EVP.hmac(b'key', b'data', + algo='sha224'))) + self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', + algo='sha256')), + 36273358097036101702192658888336808701031275731906771612800928188662823394256, + util.octx_to_num(EVP.hmac(b'key', b'data', + algo='sha256'))) + self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', + algo='sha384')), + 30471069101236165765942696708481556386452105164815350204559050657318908408184002707969468421951222432574647369766282, + util.octx_to_num(EVP.hmac(b'key', b'data', + algo='sha384'))) + self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', + algo='sha512')), + 3160730054100700080556942280820129108466291087966635156623014063982211353635774277148932854680195471287740489442390820077884317620321797003323909388868696, + util.octx_to_num(EVP.hmac(b'key', b'data', + algo='sha512'))) + + with self.assertRaises(ValueError): + EVP.hmac(b'key', b'data', algo='sha513') def test_get_rsa(self): """ Testing retrieving the RSA key from the PKey instance. """ - rsa = RSA.gen_key(512, 3, callback=self._gen_callback) - assert isinstance(rsa, RSA.RSA) + rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) + self.assertIsInstance(rsa, RSA.RSA) pkey = EVP.PKey() - pkey.assign_rsa(rsa) + pkey.assign_rsa(rsa) rsa2 = pkey.get_rsa() - assert isinstance(rsa2, RSA.RSA_pub) - assert rsa.e == rsa2.e - assert rsa.n == rsa2.n + self.assertIsInstance(rsa2, RSA.RSA_pub) + self.assertEqual(rsa.e, rsa2.e) + self.assertEqual(rsa.n, rsa2.n) + # FIXME + # hanging call is + # m2.rsa_write_key(self.rsa, bio._ptr(), ciph, callback)s + # from RSA.py/save_key_bio + pem = rsa.as_pem(callback=self._pass_callback) pem2 = rsa2.as_pem() assert pem assert pem2 - assert pem != pem2 - - message = "This is the message string" - digest = sha.sha(message).digest() - assert rsa.sign(digest) == rsa2.sign(digest) - + self.assertNotEqual(pem, pem2) + + message = b'This is the message string' + digest = hashlib.sha1(message).digest() + self.assertEqual(rsa.sign(digest), rsa2.sign(digest)) + rsa3 = RSA.gen_key(1024, 3, callback=self._gen_callback) - assert rsa.sign(digest) != rsa3.sign(digest) - + self.assertNotEqual(rsa.sign(digest), rsa3.sign(digest)) + + def test_load_key_string_pubkey(self): + """ + Testing creating a PKey instance from PEM string. + """ + rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) + self.assertIsInstance(rsa, RSA.RSA) + + rsa_pem = BIO.MemoryBuffer() + rsa.save_pub_key_bio(rsa_pem) + pkey = EVP.load_key_string_pubkey(rsa_pem.read()) + rsa2 = pkey.get_rsa() + self.assertIsInstance(rsa2, RSA.RSA_pub) + self.assertEqual(rsa.e, rsa2.e) + self.assertEqual(rsa.n, rsa2.n) + pem = rsa.as_pem(callback=self._pass_callback) + pem2 = rsa2.as_pem() + assert pem + assert pem2 + self.assertNotEqual(pem, pem2) + def test_get_rsa_fail(self): """ Testing trying to retrieve the RSA key from the PKey instance when it is not holding a RSA Key. Should raise a ValueError. """ pkey = EVP.PKey() - self.assertRaises(ValueError, pkey.get_rsa) + with self.assertRaises(ValueError): + pkey.get_rsa() def test_get_modulus(self): pkey = EVP.PKey() - self.assertRaises(ValueError, pkey.get_modulus) + with self.assertRaises(ValueError): + pkey.get_modulus() - rsa = RSA.gen_key(512, 3, callback=self._gen_callback) + rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey.assign_rsa(rsa) mod = pkey.get_modulus() - assert len(mod) > 0, mod - assert len(mod.strip('0123456789ABCDEF')) == 0 - + self.assertGreater(len(mod), 0, mod) + self.assertEqual(len(mod.strip(b'0123456789ABCDEF')), 0) + def test_verify_final(self): from M2Crypto import X509 pkey = EVP.load_key('tests/signer_key.pem') pkey.sign_init() - pkey.sign_update('test message') + pkey.sign_update(b'test message') sig = pkey.sign_final() - + # OK x509 = X509.load_cert('tests/signer.pem') pubkey = x509.get_pubkey() pubkey.verify_init() - pubkey.verify_update('test message') - assert pubkey.verify_final(sig) == 1 - + pubkey.verify_update(b'test message') + self.assertEqual(pubkey.verify_final(sig), 1) + # wrong cert x509 = X509.load_cert('tests/x509.pem') pubkey = x509.get_pubkey() pubkey.verify_init() - pubkey.verify_update('test message') - assert pubkey.verify_final(sig) == 0 - + pubkey.verify_update(b'test message') + self.assertEqual(pubkey.verify_final(sig), 0) + # wrong message x509 = X509.load_cert('tests/signer.pem') pubkey = x509.get_pubkey() pubkey.verify_init() - pubkey.verify_update('test message not') - assert pubkey.verify_final(sig) == 0 + pubkey.verify_update(b'test message not') + self.assertEqual(pubkey.verify_final(sig), 0) def test_load_bad(self): - self.assertRaises(BIO.BIOError, EVP.load_key, - 'thisdoesnotexist-dfgh56789') - self.assertRaises(EVP.EVPError, EVP.load_key, - 'tests/signer.pem') # not a key - self.assertRaises(EVP.EVPError, EVP.load_key_bio, - BIO.MemoryBuffer('no a key')) + with self.assertRaises(BIO.BIOError): + EVP.load_key('thisdoesnotexist-dfgh56789') + with self.assertRaises(EVP.EVPError): + EVP.load_key('tests/signer.pem') # not a key + with self.assertRaises(EVP.EVPError): + EVP.load_key_bio(BIO.MemoryBuffer(b'no a key')) def test_pad(self): self.assertEqual(util.pkcs5_pad('Hello World'), 'Hello World\x05\x05\x05\x05\x05') self.assertEqual(util.pkcs7_pad('Hello World', 15), 'Hello World\x04\x04\x04\x04') - self.assertRaises(ValueError, util.pkcs7_pad, 'Hello', 256) - + with self.assertRaises(ValueError): + util.pkcs7_pad('Hello', 256) + + def test_pkey_verify_crash(self): + SIGN_PRIVATE = EVP.load_key('tests/rsa.priv.pem') + SIGN_PUBLIC = RSA.load_pub_key('tests/rsa.pub.pem') + + def sign(data): + SIGN_PRIVATE.sign_init() + SIGN_PRIVATE.sign_update(data) + signed_data = SIGN_PRIVATE.sign_final() + return base64.b64encode(signed_data) + + def verify(response): + signature = base64.b64decode(response['sign']) + data = response['data'] + verify_evp = EVP.PKey() + # capture parameter on the following line is required by + # the documentation + verify_evp.assign_rsa(SIGN_PUBLIC, capture=False) + verify_evp.verify_init() + verify_evp.verify_update(data) + # m2.verify_final(self.ctx, sign, self.pkey) + fin_res = verify_evp.verify_final(signature) + return fin_res == 1 + + data = b"test message" + signature = sign(data) + res = {"data": data, "sign": signature} + self.assertTrue(verify(res)) # works fine + self.assertTrue(verify(res)) # segmentation fault in *verify_final* class CipherTestCase(unittest.TestCase): def cipher_filter(self, cipher, inf, outf): while 1: - buf=inf.read() + buf = inf.read() if not buf: break outf.write(cipher.update(buf)) @@ -193,110 +306,120 @@ class CipherTestCase(unittest.TestCase): def try_algo(self, algo): enc = 1 dec = 0 - otxt='against stupidity the gods themselves contend in vain' - - k=EVP.Cipher(algo, 'goethe','12345678', enc, 1, 'sha1', 'saltsalt', 5) - pbuf=cStringIO.StringIO(otxt) - cbuf=cStringIO.StringIO() - ctxt=self.cipher_filter(k, pbuf, cbuf) + otxt = b'against stupidity the gods themselves contend in vain' + + k = EVP.Cipher(algo, b'goethe', b'12345678', enc, + 1, 'sha1', b'saltsalt', 5) + pbuf = io.BytesIO(otxt) + cbuf = io.BytesIO() + ctxt = self.cipher_filter(k, pbuf, cbuf) pbuf.close() cbuf.close() - - j=EVP.Cipher(algo, 'goethe','12345678', dec, 1, 'sha1', 'saltsalt', 5) - pbuf=cStringIO.StringIO() - cbuf=cStringIO.StringIO(ctxt) - ptxt=self.cipher_filter(j, cbuf, pbuf) + + j = EVP.Cipher(algo, b'goethe', b'12345678', dec, + 1, 'sha1', b'saltsalt', 5) + pbuf = io.BytesIO() + cbuf = io.BytesIO(ctxt) + ptxt = self.cipher_filter(j, cbuf, pbuf) pbuf.close() cbuf.close() - - assert otxt == ptxt, '%s algorithm cipher test failed' % algo - + + self.assertEqual(otxt, ptxt, '%s algorithm cipher test failed' % algo) + def test_ciphers(self): - ciphers=[ + ciphers = [ 'des_ede_ecb', 'des_ede_cbc', 'des_ede_cfb', 'des_ede_ofb', 'des_ede3_ecb', 'des_ede3_cbc', 'des_ede3_cfb', 'des_ede3_ofb', 'aes_128_ecb', 'aes_128_cbc', 'aes_128_cfb', 'aes_128_ofb', - 'aes_192_ecb', 'aes_192_cbc', 'aes_192_cfb', 'aes_192_ofb', - 'aes_256_ecb', 'aes_256_cbc', 'aes_256_cfb', 'aes_256_ofb'] - nonfips_ciphers=['bf_ecb', 'bf_cbc', 'bf_cfb', 'bf_ofb', - #'idea_ecb', 'idea_cbc', 'idea_cfb', 'idea_ofb', - 'cast5_ecb', 'cast5_cbc', 'cast5_cfb', 'cast5_ofb', - #'rc5_ecb', 'rc5_cbc', 'rc5_cfb', 'rc5_ofb', - 'des_ecb', 'des_cbc', 'des_cfb', 'des_ofb', - 'rc4', 'rc2_40_cbc'] - if not fips_mode: # Disabled algorithms + 'aes_128_ctr', 'aes_192_ecb', 'aes_192_cbc', 'aes_192_cfb', + 'aes_192_ofb', 'aes_192_ctr', 'aes_256_ecb', 'aes_256_cbc', + 'aes_256_cfb', 'aes_256_ofb', 'aes_256_ctr'] + nonfips_ciphers = ['bf_ecb', 'bf_cbc', 'bf_cfb', 'bf_ofb', + # 'idea_ecb', 'idea_cbc', 'idea_cfb', 'idea_ofb', + 'cast5_ecb', 'cast5_cbc', 'cast5_cfb', 'cast5_ofb', + # 'rc5_ecb', 'rc5_cbc', 'rc5_cfb', 'rc5_ofb', + 'des_ecb', 'des_cbc', 'des_cfb', 'des_ofb', + 'rc4', 'rc2_40_cbc'] + if not fips_mode: # Disabled algorithms ciphers += nonfips_ciphers for i in ciphers: self.try_algo(i) # idea might not be compiled in - ciphers=['idea_ecb', 'idea_cbc', 'idea_cfb', 'idea_ofb'] + ciphers = ['idea_ecb', 'idea_cbc', 'idea_cfb', 'idea_ofb'] try: for i in ciphers: self.try_algo(i) - except ValueError, e: + except ValueError as e: if str(e) != "('unknown cipher', 'idea_ecb')": - raise + raise # rc5 might not be compiled in - ciphers=['rc5_ecb', 'rc5_cbc', 'rc5_cfb', 'rc5_ofb'] + ciphers = ['rc5_ecb', 'rc5_cbc', 'rc5_cfb', 'rc5_ofb'] try: for i in ciphers: self.try_algo(i) - except ValueError, e: + except ValueError as e: if str(e) != "('unknown cipher', 'rc5_ecb')": - raise + raise + + with self.assertRaises(ValueError): + self.try_algo('nosuchalgo4567') - self.assertRaises(ValueError, self.try_algo, 'nosuchalgo4567') - - def test_AES(self): + def test_AES(self): # noqa enc = 1 dec = 0 tests = [ # test vectors from rfc 3602 - #Case #1: Encrypting 16 bytes (1 block) using AES-CBC with 128-bit key + # Case #1: Encrypting 16 bytes (1 block) using AES-CBC with + # 128-bit key { - 'KEY': '06a9214036b8a15b512e03d534120006', - 'IV': '3dafba429d9eb430b422da802c9fac41', - 'PT': 'Single block msg', - 'CT': 'e353779c1079aeb82708942dbe77181a', + 'KEY': '06a9214036b8a15b512e03d534120006', + 'IV': '3dafba429d9eb430b422da802c9fac41', + 'PT': b'Single block msg', + 'CT': b'e353779c1079aeb82708942dbe77181a', }, - - #Case #2: Encrypting 32 bytes (2 blocks) using AES-CBC with 128-bit key + + # Case #2: Encrypting 32 bytes (2 blocks) using AES-CBC with + # 128-bit key { - 'KEY': 'c286696d887c9aa0611bbb3e2025a45a', - 'IV': '562e17996d093d28ddb3ba695a2e6f58', - 'PT': unhexlify('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'), - 'CT': 'd296cd94c2cccf8a3a863028b5e1dc0a7586602d253cfff91b8266bea6d61ab1', + 'KEY': 'c286696d887c9aa0611bbb3e2025a45a', + 'IV': '562e17996d093d28ddb3ba695a2e6f58', + 'PT': unhexlify(b'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'), + 'CT': b'd296cd94c2cccf8a3a863028b5e1dc0a7586602d253cfff91b8266bea6d61ab1', }, - - #Case #3: Encrypting 48 bytes (3 blocks) using AES-CBC with 128-bit key + + # Case #3: Encrypting 48 bytes (3 blocks) using AES-CBC with + # 128-bit key { - 'KEY': '6c3ea0477630ce21a2ce334aa746c2cd', - 'IV': 'c782dc4c098c66cbd9cd27d825682c81', - 'PT': 'This is a 48-byte message (exactly 3 AES blocks)', - 'CT': 'd0a02b3836451753d493665d33f0e8862dea54cdb293abc7506939276772f8d5021c19216bad525c8579695d83ba2684', + 'KEY': '6c3ea0477630ce21a2ce334aa746c2cd', + 'IV': 'c782dc4c098c66cbd9cd27d825682c81', + 'PT': b'This is a 48-byte message (exactly 3 AES blocks)', + 'CT': b'd0a02b3836451753d493665d33f0e8862dea54cdb293abc7506939276772f8d5021c19216bad525c8579695d83ba2684', }, ] - + # Test with padding for test in tests: # encrypt - k=EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), iv=unhexlify(test['IV']), op=enc) - pbuf=cStringIO.StringIO(test['PT']) - cbuf=cStringIO.StringIO() + k = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), + iv=unhexlify(test['IV']), op=enc) + pbuf = io.BytesIO(test['PT']) + cbuf = io.BytesIO() ciphertext = hexlify(self.cipher_filter(k, pbuf, cbuf)) cipherpadding = ciphertext[len(test['PT']) * 2:] - ciphertext = ciphertext[:len(test['PT']) * 2] # Remove the padding from the end + # Remove the padding from the end + ciphertext = ciphertext[:len(test['PT']) * 2] pbuf.close() cbuf.close() self.assertEqual(ciphertext, test['CT']) # decrypt - j=EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), iv=unhexlify(test['IV']), op=dec) - pbuf=cStringIO.StringIO() - cbuf=cStringIO.StringIO(unhexlify(test['CT'] + cipherpadding)) - plaintext=self.cipher_filter(j, cbuf, pbuf) + j = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), + iv=unhexlify(test['IV']), op=dec) + pbuf = io.BytesIO() + cbuf = io.BytesIO(unhexlify(test['CT'] + cipherpadding)) + plaintext = self.cipher_filter(j, cbuf, pbuf) pbuf.close() cbuf.close() self.assertEqual(plaintext, test['PT']) @@ -304,26 +427,67 @@ class CipherTestCase(unittest.TestCase): # Test without padding for test in tests: # encrypt - k=EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), iv=unhexlify(test['IV']), op=enc, padding=False) - pbuf=cStringIO.StringIO(test['PT']) - cbuf=cStringIO.StringIO() + k = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), + iv=unhexlify(test['IV']), op=enc, padding=False) + pbuf = io.BytesIO(test['PT']) + cbuf = io.BytesIO() ciphertext = hexlify(self.cipher_filter(k, pbuf, cbuf)) pbuf.close() cbuf.close() self.assertEqual(ciphertext, test['CT']) # decrypt - j=EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), iv=unhexlify(test['IV']), op=dec, padding=False) - pbuf=cStringIO.StringIO() - cbuf=cStringIO.StringIO(unhexlify(test['CT'])) - plaintext=self.cipher_filter(j, cbuf, pbuf) + j = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), + iv=unhexlify(test['IV']), op=dec, padding=False) + pbuf = io.BytesIO() + cbuf = io.BytesIO(unhexlify(test['CT'])) + plaintext = self.cipher_filter(j, cbuf, pbuf) pbuf.close() cbuf.close() self.assertEqual(plaintext, test['PT']) + def test_AES_ctr(self): # noqa + # In CTR mode, encrypt and decrypt are actually the same + # operation because you encrypt the nonce value, then use the + # output of that to XOR the plaintext. So we set operation=0, + # even though this setting is ignored by OpenSSL. + op = 0 + + nonce = unhexlify('4a45a048a1e9f7c1bd17f2908222b964') # CTR nonce value, 16 bytes + key = unhexlify('8410ad66fe53a09addc0d041ae00bc6d70e8038ec17019f27e52eecd3846757e') + plaintext_value = b'This is three blocks of text with unicode char \x03' + + ciphertext_values = { + '128': unhexlify('6098fb2e49b3f7ed34f841f43f825d84cf4834021511594b931c85f04662544bdb4f38232e9d87fda6280ab1ef450e27'), # noqa + '192': unhexlify('2299b1c5363824cb92b5851dedc73f49f30b23fb23f288492e840c951ce703292a5c6de6fc7f0625c403648f8ca4a582'), # noqa + '256': unhexlify('713e34bcd2c59affc9185a716c3c6aef5c9bf7b9914337dd96e9d7436344bcb9c35175afb54adb78aab322829ce9cb4a'), # noqa + } + + for key_size in [128, 192, 256]: + alg = 'aes_%s_ctr' % str(key_size) + + # Our key for this test is 256 bits in length (32 bytes). + # We will trim it to the appopriate length for testing AES-128 + # and AES-192 as well (so 16 and 24 bytes, respectively). + key_truncated = key[0:(key_size // 8)] + + # Test encrypt operations + cipher = EVP.Cipher(alg=alg, key=key_truncated, iv=nonce, op=op) + ciphertext = cipher.update(plaintext_value) + ciphertext = ciphertext + cipher.final() + self.assertEqual(ciphertext, ciphertext_values[str(key_size)]) + + # Test decrypt operations + cipher = EVP.Cipher(alg=alg, key=key_truncated, iv=nonce, op=op) + plaintext = cipher.update(ciphertext_values[str(key_size)]) + plaintext = plaintext + cipher.final() + # XXX not quite sure this is the actual intention + # but for now let's be happy to find the same content even if with + # a different type - XXX + self.assertEqual(plaintext, plaintext_value) def test_raises(self): - def _cipherFilter(cipher, inf, outf): + def _cipherFilter(cipher, inf, outf): # noqa while 1: buf = inf.read() if not buf: @@ -334,126 +498,127 @@ class CipherTestCase(unittest.TestCase): def decrypt(ciphertext, key, iv, alg='aes_256_cbc'): cipher = EVP.Cipher(alg=alg, key=key, iv=iv, op=0) - pbuf = cStringIO.StringIO() - cbuf = cStringIO.StringIO(ciphertext) + pbuf = io.BytesIO() + cbuf = io.BytesIO(ciphertext) plaintext = _cipherFilter(cipher, cbuf, pbuf) pbuf.close() cbuf.close() return plaintext - - self.assertRaises(EVP.EVPError, decrypt, - unhexlify('941d3647a642fab26d9f99a195098b91252c652d07235b9db35758c401627711724637648e45cad0f1121751a1240a4134998cfdf3c4a95c72de2a2444de3f9e40d881d7f205630b0d8ce142fdaebd8d7fbab2aea3dc47f5f29a0e9b55aae59222671d8e2877e1fb5cd8ef1c427027e0'), - unhexlify('5f2cc54067f779f74d3cf1f78c735aec404c8c3a4aaaa02eb1946f595ea4cddb'), - unhexlify('0001efa4bd154ee415b9413a421cedf04359fff945a30e7c115465b1c780a85b65c0e45c')) - self.assertRaises(EVP.EVPError, decrypt, - unhexlify('a78a510416c1a6f1b48077cc9eeb4287dcf8c5d3179ef80136c18876d774570d'), - unhexlify('5cd148eeaf680d4ff933aed83009cad4110162f53ef89fd44fad09611b0524d4'), - unhexlify('')) + with self.assertRaises(EVP.EVPError): + decrypt( + unhexlify('941d3647a642fab26d9f99a195098b91252c652d07235b9db35758c401627711724637648e45cad0f1121751a1240a4134998cfdf3c4a95c72de2a2444de3f9e40d881d7f205630b0d8ce142fdaebd8d7fbab2aea3dc47f5f29a0e9b55aae59222671d8e2877e1fb5cd8ef1c427027e0'), + unhexlify('5f2cc54067f779f74d3cf1f78c735aec404c8c3a4aaaa02eb1946f595ea4cddb'), + unhexlify('0001efa4bd154ee415b9413a421cedf04359fff945a30e7c115465b1c780a85b65c0e45c')) + + with self.assertRaises(EVP.EVPError): + decrypt( + unhexlify('a78a510416c1a6f1b48077cc9eeb4287dcf8c5d3179ef80136c18876d774570d'), + unhexlify('5cd148eeaf680d4ff933aed83009cad4110162f53ef89fd44fad09611b0524d4'), + unhexlify('')) class PBKDF2TestCase(unittest.TestCase): def test_rfc3211_test_vectors(self): - from binascii import hexlify, unhexlify - - password = 'password' - salt = unhexlify('12 34 56 78 78 56 34 12'.replace(' ', '')) + + password = b'password' + salt = unhexlify('1234567878563412') iter = 5 keylen = 8 ret = EVP.pbkdf2(password, salt, iter, keylen) - self.assertEqual(hexlify(ret), 'D1 DA A7 86 15 F2 87 E6'.replace(' ', '').lower()) - - password = 'All n-entities must communicate with other n-entities via n-1 entiteeheehees' - salt = unhexlify('12 34 56 78 78 56 34 12'.replace(' ', '')) + self.assertEqual(ret, unhexlify(b'd1daa78615f287e6')) + + password = b'All n-entities must communicate with other n-entities' + \ + b' via n-1 entiteeheehees' + salt = unhexlify('1234567878563412') iter = 500 keylen = 16 ret = EVP.pbkdf2(password, salt, iter, keylen) - self.assertEqual(hexlify(ret), '6A 89 70 BF 68 C9 2C AE A8 4A 8D F2 85 10 85 86'.replace(' ', '').lower()) - + self.assertEqual(ret, unhexlify(b'6a8970bf68c92caea84a8df285108586')) + class HMACTestCase(unittest.TestCase): - data1=['', 'More text test vectors to stuff up EBCDIC machines :-)', \ - h2b("e9139d1e6ee064ef8cf514fc7dc83e86")] + data1 = [b'', b'More text test vectors to stuff up EBCDIC machines :-)', + a2b_hex("b760e92d6662d351eb3801057695ac0346295356")] - data2=[h2b('0b'*16), "Hi There", \ - h2b("9294727a3638bb1c13f48ef8158bfc9d")] + data2 = [a2b_hex(b'0b' * 16), b"Hi There", + a2b_hex("675b0b3a1b4ddf4e124872da6c2f632bfed957e9")] - data3=['Jefe', "what do ya want for nothing?", \ - h2b("750c783e6ab0b503eaa86e310a5db738")] + data3 = [b'Jefe', b"what do ya want for nothing?", + a2b_hex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")] - data4=[h2b('aa'*16), h2b('dd'*50), \ - h2b("0x56be34521d144c88dbb8c733f0e8b3f6")] + data4 = [a2b_hex(b'aa' * 16), a2b_hex(b'dd' * 50), + a2b_hex("d730594d167e35d5956fd8003d0db3d3f46dc7bb")] - data=[data1, data2, data3, data4] + data = [data1, data2, data3, data4] def test_simple(self): - algo = 'md5' + algo = 'sha1' for d in self.data: h = EVP.HMAC(d[0], algo) h.update(d[1]) ret = h.final() self.assertEqual(ret, d[2]) - self.assertRaises(ValueError, EVP.HMAC, d[0], algo='nosuchalgo') + with self.assertRaises(ValueError): + EVP.HMAC(d[0], algo='nosuchalgo') - def make_chain_HMAC(self, key, start, input, algo='sha1'): + def make_chain_HMAC(self, key, start, input, algo='sha1'): # noqa chain = [] hmac = EVP.HMAC(key, algo) - hmac.update(`start`) + hmac.update(repr(start)) digest = hmac.final() chain.append((digest, start)) for i in input: hmac.reset(digest) - hmac.update(`i`) + hmac.update(repr(i)) digest = hmac.final() chain.append((digest, i)) return chain - + def make_chain_hmac(self, key, start, input, algo='sha1'): - from M2Crypto.EVP import hmac chain = [] - digest = hmac(key, `start`, algo) + digest = EVP.hmac(key, start, algo) chain.append((digest, start)) for i in input: - digest = hmac(digest, `i`, algo) + digest = EVP.hmac(digest, i, algo) chain.append((digest, i)) return chain - + def verify_chain_hmac(self, key, start, chain, algo='sha1'): - from M2Crypto.EVP import hmac - digest = hmac(key, `start`, algo) + digest = EVP.hmac(key, start, algo) c = chain[0] if c[0] != digest or c[1] != start: return 0 for d, v in chain[1:]: - digest = hmac(digest, `v`, algo) + digest = EVP.hmac(digest, v, algo) if digest != d: return 0 return 1 - - def verify_chain_HMAC(self, key, start, chain, algo='sha1'): + + def verify_chain_HMAC(self, key, start, chain, algo='sha1'): # noqa hmac = EVP.HMAC(key, algo) - hmac.update(`start`) + hmac.update(start) digest = hmac.final() c = chain[0] if c[0] != digest or c[1] != start: return 0 for d, v in chain[1:]: hmac.reset(digest) - hmac.update(`v`) + hmac.update(v) digest = hmac.final() if digest != d: return 0 return 1 - + def test_complicated(self): make_chain = self.make_chain_hmac verify_chain = self.verify_chain_hmac - key = 'numero uno' - start = 'zeroth item' - input = ['first item', 'go go go', 'fly fly fly'] + key = b'numero uno' + start = b'zeroth item' + input = [b'first item', b'go go go', b'fly fly fly'] chain = make_chain(key, start, input) - self.assertEquals(verify_chain('some key', start, chain), 0) - self.assertEquals(verify_chain(key, start, chain), 1) + self.assertEqual(verify_chain(b'some key', start, chain), 0) + self.assertEqual(verify_chain(key, start, chain), 1) def suite(): @@ -462,10 +627,9 @@ def suite(): suite.addTest(unittest.makeSuite(CipherTestCase)) suite.addTest(unittest.makeSuite(PBKDF2TestCase)) suite.addTest(unittest.makeSuite(HMACTestCase)) - return suite + return suite if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_obj.py b/tests/test_obj.py index 9144135..7748492 100644 --- a/tests/test_obj.py +++ b/tests/test_obj.py @@ -2,30 +2,41 @@ """Unit tests for M2Crypto.m2 obj_* functions. """ - -import unittest -from M2Crypto import X509, ASN1, BIO, Rand, m2 +from M2Crypto import ASN1, BIO, Rand, X509, m2, six +from tests import unittest """ These functions must be cleaned up and moved to some python module Taken from CA managment code """ + def x509_name2list(name): for i in range(0, name.entry_count()): - yield X509.X509_Name_Entry(m2.x509_name_get_entry(name._ptr(), i), _pyfree = 0) + yield X509.X509_Name_Entry(m2.x509_name_get_entry(name._ptr(), i), + _pyfree=0) + def x509_name_entry2tuple(entry): bio = BIO.MemoryBuffer() m2.asn1_string_print(bio._ptr(), m2.x509_name_entry_get_data(entry._ptr())) - return (m2.obj_obj2txt(m2.x509_name_entry_get_object(entry._ptr()), 0), bio.getvalue()) + return ( + six.ensure_text(m2.obj_obj2txt( + m2.x509_name_entry_get_object(entry._ptr()), 0)), + six.ensure_text(bio.getvalue())) + def tuple2x509_name_entry(tup): obj, data = tup - _x509_ne = m2.x509_name_entry_create_by_txt(None, obj, ASN1.MBSTRING_ASC, data, len(data)) + # TODO This is evil, isn't it? Shouldn't we use only official API? + # Something like X509.X509_Name.add_entry_by_txt() + _x509_ne = m2.x509_name_entry_create_by_txt(None, six.ensure_str(obj), + ASN1.MBSTRING_ASC, + six.ensure_str(data), len(data)) if not _x509_ne: raise ValueError("Invalid object indentifier: %s" % obj) - return X509.X509_Name_Entry(_x509_ne, _pyfree = 1) # Prevent memory leaks + return X509.X509_Name_Entry(_x509_ne, _pyfree=1) # Prevent memory leaks + class ObjectsTestCase(unittest.TestCase): @@ -33,57 +44,94 @@ class ObjectsTestCase(unittest.TestCase): pass def test_obj2txt(self): - assert m2.obj_obj2txt(m2.obj_txt2obj("commonName", 0), 1) == "2.5.4.3", "2.5.4.3" - assert m2.obj_obj2txt(m2.obj_txt2obj("commonName", 0), 0) == "commonName", "commonName" + self.assertEqual(m2.obj_obj2txt(m2.obj_txt2obj("commonName", 0), 1), + b"2.5.4.3", b"2.5.4.3") + self.assertEqual(m2.obj_obj2txt(m2.obj_txt2obj("commonName", 0), 0), + b"commonName", b"commonName") def test_nid(self): - assert m2.obj_ln2nid("commonName") == m2.obj_txt2nid("2.5.4.3"), "ln2nid and txt2nid mismatch" - assert m2.obj_ln2nid("CN") == 0, "ln2nid on sn" - assert m2.obj_sn2nid("CN") == m2.obj_ln2nid("commonName"), "ln2nid and sn2nid mismatch" - assert m2.obj_sn2nid("CN") == m2.obj_obj2nid(m2.obj_txt2obj("CN", 0)), "obj2nid" - assert m2.obj_txt2nid("__unknown") == 0, "__unknown" - + self.assertEqual(m2.obj_ln2nid("commonName"), + m2.obj_txt2nid("2.5.4.3"), + "ln2nid and txt2nid mismatch") + self.assertEqual(m2.obj_ln2nid("CN"), + 0, "ln2nid on sn") + self.assertEqual(m2.obj_sn2nid("CN"), + m2.obj_ln2nid("commonName"), + "ln2nid and sn2nid mismatch") + self.assertEqual(m2.obj_sn2nid("CN"), + m2.obj_obj2nid(m2.obj_txt2obj("CN", 0)), "obj2nid") + self.assertEqual(m2.obj_txt2nid("__unknown"), + 0, "__unknown") + def test_tuple2tuple(self): tup = ("CN", "someCommonName") tup1 = x509_name_entry2tuple(tuple2x509_name_entry(tup)) - assert tup1[1] == tup[1], tup1 # tup1[0] is 'commonName', not 'CN' - assert x509_name_entry2tuple(tuple2x509_name_entry(tup1)) == tup1, tup1 + # tup1[0] is 'commonName', not 'CN' + self.assertEqual(tup1[1], tup[1], tup1) + self.assertEqual(x509_name_entry2tuple(tuple2x509_name_entry(tup1)), + tup1, tup1) def test_unknown(self): - self.assertRaises(ValueError, tuple2x509_name_entry, ("__unknown", "_")) - + with self.assertRaises(ValueError): + tuple2x509_name_entry(("__unknown", "_")) + def test_x509_name(self): n = X509.X509_Name() - n.C = 'US' # It seems this actually needs to be a real 2 letter country code - n.SP = 'State or Province' - n.L = 'locality name' - n.O = 'orhanization name' - n.OU = 'org unit' - n.CN = 'common name' - n.Email = 'bob@example.com' - n.serialNumber = '1234' - n.SN = 'surname' - n.GN = 'given name' - - n.givenName = 'name given' - assert len(n) == 11, len(n) - - tl = map(x509_name_entry2tuple, x509_name2list(n)) - - assert len(tl) == len(n), len(tl) + # It seems this actually needs to be a real 2 letter country code + n.C = b'US' + n.SP = b'State or Province' + n.L = b'locality name' + n.O = b'orhanization name' + n.OU = b'org unit' + n.CN = b'common name' + n.Email = b'bob@example.com' + n.serialNumber = b'1234' + n.SN = b'surname' + n.GN = b'given name' + + n.givenName = b'name given' + self.assertEqual(len(n), 11, len(n)) + + # Thierry: this call to list seems extraneous... + tl = [x509_name_entry2tuple(x) for x in x509_name2list(n)] + + self.assertEqual(len(tl), len(n), len(tl)) x509_n = m2.x509_name_new() - for o in map(tuple2x509_name_entry, tl): + for o in [tuple2x509_name_entry(x) for x in tl]: m2.x509_name_add_entry(x509_n, o._ptr(), -1, 0) - o._pyfree = 0 # Take care of underlying object + o._pyfree = 0 # Take care of underlying object n1 = X509.X509_Name(x509_n) - assert n.as_text() == n1.as_text(), n1.as_text() + self.assertEqual(n.as_text(), n1.as_text(), n1.as_text()) + + # Detailed OpenSSL error message is visible in Python error message: + def test_detailed_error_message(self): + from M2Crypto import SMIME, X509 + s = SMIME.SMIME() + x509 = X509.load_cert('tests/recipient.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + st = X509.X509_Store() + st.load_info('tests/recipient.pem') + s.set_x509_store(st) + + p7, data = SMIME.smime_load_pkcs7('tests/sample-p7.pem') + self.assertIsInstance(p7, SMIME.PKCS7, p7) + + try: + s.verify(p7, data) + except SMIME.PKCS7_Error as e: + self.assertRegexpMatches(str(e), + "unable to get local issuer certificate", + "Not received expected error message") def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ObjectsTestCase)) - return suite + t_suite = unittest.TestSuite() + t_suite.addTest(unittest.makeSuite(ObjectsTestCase)) + return t_suite if __name__ == '__main__': diff --git a/tests/test_pgp.py b/tests/test_pgp.py deleted file mode 100644 index c86d153..0000000 --- a/tests/test_pgp.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -"""PGP test program. - -Copyright (c) 1999 Ng Pheng Siong. All rights reserved.""" - -import unittest -from M2Crypto import EVP, PGP -from cStringIO import StringIO - - -class PGPTestCase(unittest.TestCase): - - def test_simple(self): - pkr = PGP.load_pubring('tests/pubring.pgp') - daft = pkr['daft'] - daft_pkt = daft._pubkey_pkt.pack() - s1 = EVP.MessageDigest('sha1') - s1.update(daft_pkt) - s1f = `s1.final()` - - buf = StringIO(daft_pkt) - ps = PGP.packet_stream(buf) - dift_pkt = ps.read() - s2 = EVP.MessageDigest('sha1') - s2.update(dift_pkt.pack()) - s2f = `s2.final()` - - self.assertEqual(s1f, s2f) - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(PGPTestCase)) - return suite - - -if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) - unittest.TextTestRunner().run(suite()) - Rand.save_file('randpool.dat') diff --git a/tests/test_rand.py b/tests/test_rand.py index 3e4d65d..cd27a25 100644 --- a/tests/test_rand.py +++ b/tests/test_rand.py @@ -2,45 +2,78 @@ """Unit tests for M2Crypto.Rand. -Copyright (C) 2006 Open Source Applications Foundation (OSAF). All Rights Reserved. +Copyright (C) 2006 Open Source Applications Foundation (OSAF). +All Rights Reserved. """ -import unittest -import os, sys -from M2Crypto import Rand +import os +import ctypes +import warnings + +from M2Crypto import Rand, m2 +from tests import unittest + class RandTestCase(unittest.TestCase): def test_bytes(self): - self.assertRaises(MemoryError, Rand.rand_bytes, -1) - assert Rand.rand_bytes(0) == '' - assert len(Rand.rand_bytes(1)) == 1 - + with self.assertRaises(MemoryError): + Rand.rand_bytes(-1) + self.assertEqual(Rand.rand_bytes(0), b'') + self.assertEqual(len(Rand.rand_bytes(1)), 1) + def test_pseudo_bytes(self): - self.assertRaises(MemoryError, Rand.rand_pseudo_bytes, -1) - assert Rand.rand_pseudo_bytes(0) == ('', 1) - a, b = Rand.rand_pseudo_bytes(1) - assert len(a) == 1 - assert b == 1 - + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + with self.assertRaises(MemoryError): + Rand.rand_pseudo_bytes(-1) + self.assertEqual(Rand.rand_pseudo_bytes(0), (b'', 1)) + a, b = Rand.rand_pseudo_bytes(1) + self.assertEqual(len(a), 1) + self.assertEqual(b, 1) + + def test_file_name(self): + if os.name == 'nt': + is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0 + rand_env = ('RANDFILE', 'HOME', 'USERPROFILE', 'SYSTEMROOT') + else: + rand_env = ('RANDFILE', 'HOME') + is_admin = False + key = next((k for k in rand_env if os.environ.get(k)), None) + if is_admin and m2.OPENSSL_VERSION_NUMBER < 0x1010000F: + path = 'C:\\' + else: + path = os.path.join(os.environ[key]) + self.assertIsNotNone(key, "Could not find required environment") + rand_file = os.path.abspath(os.path.join(path, '.rnd')) + self.assertEqual(os.path.abspath(Rand.rand_file_name()), rand_file) + def test_load_save(self): try: os.remove('tests/randpool.dat') except OSError: pass - assert Rand.load_file('tests/randpool.dat', -1) == 0 - assert Rand.save_file('tests/randpool.dat') == 1024 - assert Rand.load_file('tests/randpool.dat', -1) == 1024 - + self.assertIn(Rand.load_file('tests/randpool.dat', -1), [0, -1]) + self.assertEqual(Rand.save_file('tests/randpool.dat'), 1024) + self.assertEqual(Rand.load_file('tests/randpool.dat', -1), 1024) + def test_seed_add(self): - if sys.version_info >= (2, 4): - assert Rand.rand_seed(os.urandom(1024)) is None - - # XXX Should there be limits on the entropy parameter? - assert Rand.rand_add(os.urandom(2), 0.5) is None - Rand.rand_add(os.urandom(2), -0.5) - Rand.rand_add(os.urandom(2), 5000.0) - - + self.assertIsNone(Rand.rand_seed(os.urandom(1024))) + + # XXX Should there be limits on the entropy parameter? + self.assertIsNone(Rand.rand_add(os.urandom(2), 0.5)) + Rand.rand_add(os.urandom(2), -0.5) + Rand.rand_add(os.urandom(2), 5000.0) + + def test_rand_status(self): + # Although it is hard to believe we would ever get 0 (i.e., PRNG + # hasn't enough entropy), it is a legitimate value. + status = Rand.rand_status() + self.assertIn(status, [0, 1], + 'Illegal value of RAND.rand_status {0}!'.format(status)) + if status == 0: + warnings.warn('RAND_status reports insufficient seeding of PRNG!') + + def suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(RandTestCase)) diff --git a/tests/test_rc4.py b/tests/test_rc4.py index 5a2d239..b06406c 100644 --- a/tests/test_rc4.py +++ b/tests/test_rc4.py @@ -1,41 +1,52 @@ #!/usr/bin/env python +from __future__ import absolute_import """Unit tests for M2Crypto.RC4. Copyright (c) 2009 Heikki Toivonen. All rights reserved.""" -import unittest +from M2Crypto import RC4, Rand from binascii import hexlify -from M2Crypto import RC4 + +from tests import unittest +from tests.fips import fips_mode + class RC4TestCase(unittest.TestCase): + @unittest.skipIf(fips_mode, "Can't be run in FIPS mode") def test_vectors(self): """ Test with test vectors from Wikipedia: http://en.wikipedia.org/wiki/Rc4 """ - vectors = (('Key', 'Plaintext', 'BBF316E8D940AF0AD3'), - ('Wiki', 'pedia', '1021BF0420'), - ('Secret', 'Attack at dawn', '45A01F645FC35B383552544B9BF5')) - + if fips_mode: + return + vectors = ((b'Key', b'Plaintext', b'BBF316E8D940AF0AD3'), + (b'Wiki', b'pedia', b'1021BF0420'), + (b'Secret', b'Attack at dawn', + b'45A01F645FC35B383552544B9BF5')) + rc4 = RC4.RC4() for key, plaintext, ciphertext in vectors: rc4.set_key(key) - self.assertEqual(hexlify(rc4.update(plaintext)).upper(), ciphertext) + self.assertEqual(hexlify(rc4.update(plaintext)).upper(), + ciphertext) self.assertEqual(rc4.final(), '') - + + @unittest.skipIf(fips_mode, "Can't be run in FIPS mode") def test_bad(self): - rc4 = RC4.RC4('foo') - self.assertNotEqual(hexlify(rc4.update('bar')).upper(), '45678') - - + if fips_mode: + return + rc4 = RC4.RC4(b'foo') + self.assertNotEqual(hexlify(rc4.update(b'bar')).upper(), b'45678') + + def suite(): return unittest.makeSuite(RC4TestCase) - + if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_rsa.py b/tests/test_rsa.py index 0bb986b..7028b60 100644 --- a/tests/test_rsa.py +++ b/tests/test_rsa.py @@ -1,12 +1,20 @@ #!/usr/bin/env python +from __future__ import absolute_import """Unit tests for M2Crypto.RSA. Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" -import unittest -import sha, md5, os, sys -from M2Crypto import RSA, BIO, Rand, m2, EVP, X509 +import hashlib +import logging +import os + +from M2Crypto import BIO, RSA, Rand, X509, m2, six +from tests import unittest +from tests.fips import fips_mode + +log = logging.getLogger('test_RSA') + class RSATestCase(unittest.TestCase): @@ -15,7 +23,7 @@ class RSATestCase(unittest.TestCase): privkey2 = 'tests/rsa.priv2.pem' pubkey = 'tests/rsa.pub.pem' - data = sha.sha('The magic words are squeamish ossifrage.').digest() + data = hashlib.sha1(b'The magic words are squeamish ossifrage.').digest() e_padding_ok = ('pkcs1_padding', 'pkcs1_oaep_padding') @@ -30,50 +38,63 @@ class RSATestCase(unittest.TestCase): def pp_callback(self, *args): # The passphrase for rsa.priv2.pem is 'qwerty'. - return 'qwerty' + return b'qwerty' def pp2_callback(self, *args): # Misbehaving passphrase callback. - pass + return b'blabla' + + def test_rsa_exceptions(self): + with self.assertRaises(RSA.RSAError): + RSA.rsa_error() def test_loadkey_junk(self): - self.assertRaises(RSA.RSAError, RSA.load_key, self.errkey) + with self.assertRaises(RSA.RSAError): + RSA.load_key(self.errkey) def test_loadkey_pp(self): rsa = RSA.load_key(self.privkey2, self.pp_callback) - assert len(rsa) == 1024 - assert rsa.e == '\000\000\000\003\001\000\001' # aka 65537 aka 0xf4 - assert rsa.check_key() == 1 + self.assertEqual(len(rsa), 1024) + self.assertEqual(rsa.e, + b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 + self.assertEqual(rsa.check_key(), 1) def test_loadkey_pp_bad_cb(self): - self.assertRaises(RSA.RSAError, RSA.load_key, self.privkey2, self.pp2_callback) + with self.assertRaises(RSA.RSAError): + RSA.load_key(self.privkey2, self.pp2_callback) def test_loadkey(self): rsa = RSA.load_key(self.privkey) - assert len(rsa) == 1024 - assert rsa.e == '\000\000\000\003\001\000\001' # aka 65537 aka 0xf4 - self.assertEqual(rsa.n, "\x00\x00\x00\x81\x00\xcde!\x15\xdah\xb5`\xce[\xd6\x17d\xba8\xc1I\xb1\xf1\xber\x86K\xc7\xda\xb3\x98\xd6\xf6\x80\xae\xaa\x8f!\x9a\xefQ\xdeh\xbb\xc5\x99\x01o\xebGO\x8e\x9b\x9a\x18\xfb6\xba\x12\xfc\xf2\x17\r$\x00\xa1\x1a \xfc/\x13iUm\x04\x13\x0f\x91D~\xbf\x08\x19C\x1a\xe2\xa3\x91&\x8f\xcf\xcc\xf3\xa4HRf\xaf\xf2\x19\xbd\x05\xe36\x9a\xbbQ\xc86|(\xad\x83\xf2Eu\xb2EL\xdf\xa4@\x7f\xeel|\xfcU\x03\xdb\x89'") - self.assertRaises(AttributeError, getattr, rsa, 'nosuchprop') - assert rsa.check_key() == 1 + self.assertEqual(len(rsa), 1024) + self.assertEqual(rsa.e, + b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 + self.assertEqual(rsa.n, b"\x00\x00\x00\x81\x00\xcde!\x15\xdah\xb5`\xce[\xd6\x17d\xba8\xc1I\xb1\xf1\xber\x86K\xc7\xda\xb3\x98\xd6\xf6\x80\xae\xaa\x8f!\x9a\xefQ\xdeh\xbb\xc5\x99\x01o\xebGO\x8e\x9b\x9a\x18\xfb6\xba\x12\xfc\xf2\x17\r$\x00\xa1\x1a \xfc/\x13iUm\x04\x13\x0f\x91D~\xbf\x08\x19C\x1a\xe2\xa3\x91&\x8f\xcf\xcc\xf3\xa4HRf\xaf\xf2\x19\xbd\x05\xe36\x9a\xbbQ\xc86|(\xad\x83\xf2Eu\xb2EL\xdf\xa4@\x7f\xeel|\xfcU\x03\xdb\x89'") + with self.assertRaises(AttributeError): + getattr(rsa, 'nosuchprop') + self.assertEqual(rsa.check_key(), 1) def test_loadkey_bio(self): - keybio = BIO.MemoryBuffer(open(self.privkey).read()) + with open(self.privkey, "rb") as f: + keybio = BIO.MemoryBuffer(f.read()) rsa = RSA.load_key_bio(keybio) - assert len(rsa) == 1024 - assert rsa.e == '\000\000\000\003\001\000\001' # aka 65537 aka 0xf4 - assert rsa.check_key() == 1 + self.assertEqual(len(rsa), 1024) + self.assertEqual(rsa.e, + b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 + self.assertEqual(rsa.check_key(), 1) def test_keygen(self): rsa = RSA.gen_key(1024, 65537, self.gen_callback) - assert len(rsa) == 1024 - assert rsa.e == '\000\000\000\003\001\000\001' # aka 65537 aka 0xf4 - assert rsa.check_key() == 1 + self.assertEqual(len(rsa), 1024) + self.assertEqual(rsa.e, + b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 + self.assertEqual(rsa.check_key(), 1) def test_keygen_bad_cb(self): rsa = RSA.gen_key(1024, 65537, self.gen2_callback) - assert len(rsa) == 1024 - assert rsa.e == '\000\000\000\003\001\000\001' # aka 65537 aka 0xf4 - assert rsa.check_key() == 1 + self.assertEqual(len(rsa), 1024) + self.assertEqual(rsa.e, + b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 + self.assertEqual(rsa.check_key(), 1) def test_private_encrypt(self): priv = RSA.load_key(self.privkey) @@ -82,14 +103,18 @@ class RSATestCase(unittest.TestCase): p = getattr(RSA, padding) ctxt = priv.private_encrypt(self.data, p) ptxt = priv.public_decrypt(ctxt, p) - assert ptxt == self.data + self.assertEqual(ptxt, self.data) # The other paddings. for padding in self.s_padding_nok: p = getattr(RSA, padding) - self.assertRaises(RSA.RSAError, priv.private_encrypt, self.data, p) + with self.assertRaises(RSA.RSAError): + priv.private_encrypt(self.data, p) # Type-check the data to be encrypted. - self.assertRaises(TypeError, priv.private_encrypt, self.gen_callback, RSA.pkcs1_padding) + with self.assertRaises(TypeError): + priv.private_encrypt(self.gen_callback, RSA.pkcs1_padding) + @unittest.skipIf(m2.OPENSSL_VERSION_NUMBER < 0x1010103f, + 'Relies on fix which happened only in OpenSSL 1.1.1c') def test_public_encrypt(self): priv = RSA.load_key(self.privkey) # pkcs1_padding, pkcs1_oaep_padding @@ -97,38 +122,49 @@ class RSATestCase(unittest.TestCase): p = getattr(RSA, padding) ctxt = priv.public_encrypt(self.data, p) ptxt = priv.private_decrypt(ctxt, p) - assert ptxt == self.data + self.assertEqual(ptxt, self.data) + # sslv23_padding ctxt = priv.public_encrypt(self.data, RSA.sslv23_padding) - self.assertRaises(RSA.RSAError, priv.private_decrypt, ctxt, RSA.sslv23_padding) + res = priv.private_decrypt(ctxt, RSA.sslv23_padding) + self.assertEqual(res, self.data) + # no_padding - self.assertRaises(RSA.RSAError, priv.public_encrypt, self.data, RSA.no_padding) + with six.assertRaisesRegex(self, TypeError, 'data too small'): + priv.public_encrypt(self.data, RSA.no_padding) + # Type-check the data to be encrypted. - self.assertRaises(TypeError, priv.public_encrypt, self.gen_callback, RSA.pkcs1_padding) + with self.assertRaises(TypeError): + priv.public_encrypt(self.gen_callback, RSA.pkcs1_padding) def test_x509_public_encrypt(self): x509 = X509.load_cert("tests/recipient.pem") rsa = x509.get_pubkey().get_rsa() - rsa.public_encrypt("data", RSA.pkcs1_padding) - + rsa.public_encrypt(b"data", RSA.pkcs1_padding) + def test_loadpub(self): rsa = RSA.load_pub_key(self.pubkey) - assert len(rsa) == 1024 - assert rsa.e == '\000\000\000\003\001\000\001' # aka 65537 aka 0xf4 - self.assertRaises(RSA.RSAError, setattr, rsa, 'e', '\000\000\000\003\001\000\001') - self.assertRaises(RSA.RSAError, rsa.private_encrypt, 1) - self.assertRaises(RSA.RSAError, rsa.private_decrypt, 1) + self.assertEqual(len(rsa), 1024) + self.assertEqual(rsa.e, + b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 + with self.assertRaises(RSA.RSAError): + setattr(rsa, 'e', '\000\000\000\003\001\000\001') + with self.assertRaises(RSA.RSAError): + rsa.private_encrypt(1) + with self.assertRaises(RSA.RSAError): + rsa.private_decrypt(1) assert rsa.check_key() def test_loadpub_bad(self): - self.assertRaises(RSA.RSAError, RSA.load_pub_key, self.errkey) + with self.assertRaises(RSA.RSAError): + RSA.load_pub_key(self.errkey) def test_savepub(self): rsa = RSA.load_pub_key(self.pubkey) - assert rsa.as_pem() # calls save_key_bio + assert rsa.as_pem() # calls save_key_bio f = 'tests/rsa_test.pub' try: - self.assertEquals(rsa.save_key(f), 1) + self.assertEqual(rsa.save_key(f), 1) finally: try: os.remove(f) @@ -137,100 +173,134 @@ class RSATestCase(unittest.TestCase): def test_set_bn(self): rsa = RSA.load_pub_key(self.pubkey) - assert m2.rsa_set_e(rsa.rsa, '\000\000\000\003\001\000\001') is None - self.assertRaises(RSA.RSAError, m2.rsa_set_e, rsa.rsa, '\000\000\000\003\001') + with self.assertRaises(RSA.RSAError): + m2.rsa_set_en(rsa.rsa, + b'\000\000\000\003\001\000\001', + b'\000\000\000\003\001') + + def test_set_n(self): + rsa = m2.rsa_new() + m2.rsa_set_n(rsa, b'\000\000\000\003\001\000\001') + + n = m2.rsa_get_n(rsa) + e = m2.rsa_get_e(rsa) + + self.assertEqual(n, b'\000\000\000\003\001\000\001') + self.assertEqual(e, b'\x00\x00\x00\x00') + + def test_set_e(self): + rsa = m2.rsa_new() + m2.rsa_set_e(rsa, b'\000\000\000\003\001\000\001') + + n = m2.rsa_get_n(rsa) + e = m2.rsa_get_e(rsa) + + self.assertEqual(e, b'\000\000\000\003\001\000\001') + self.assertEqual(n, b'\x00\x00\x00\x00') + + def test_set_n_then_set_e(self): + rsa = m2.rsa_new() + m2.rsa_set_n(rsa, b'\000\000\000\004\020\011\006\006') + m2.rsa_set_e(rsa, b'\000\000\000\003\001\000\001') + + n = m2.rsa_get_n(rsa) + e = m2.rsa_get_e(rsa) + + self.assertEqual(e, b'\000\000\000\003\001\000\001') + self.assertEqual(n, b'\000\000\000\004\020\011\006\006') def test_newpub(self): old = RSA.load_pub_key(self.pubkey) new = RSA.new_pub_key(old.pub()) - assert new.check_key() - assert len(new) == 1024 - assert new.e == '\000\000\000\003\001\000\001' # aka 65537 aka 0xf4 - + self.assertTrue(new.check_key()) + self.assertEqual(len(new), 1024) + # aka 65537 aka 0xf4 + self.assertEqual(new.e, b'\000\000\000\003\001\000\001') + def test_sign_and_verify(self): """ Testing signing and verifying digests """ - algos = {'sha1':'', - 'ripemd160':'', - 'md5':''} + algos = {'sha1': '', + 'ripemd160': '', + 'md5': ''} if m2.OPENSSL_VERSION_NUMBER >= 0x90800F: algos['sha224'] = '' algos['sha256'] = '' - algos['sha384'] = '' - algos['sha512'] = '' + algos['sha384'] = '' + algos['sha512'] = '' - message = "This is the message string" - digest = sha.sha(message).digest() + message = b"This is the message string" + digest = hashlib.sha1(message).digest() rsa = RSA.load_key(self.privkey) rsa2 = RSA.load_pub_key(self.pubkey) for algo in algos.keys(): signature = rsa.sign(digest, algo) - #assert signature == algos[algo], 'mismatched signature with algorithm %s: signature=%s' % (algo, signature) - verify = rsa2.verify(digest, signature, algo) - assert verify == 1, 'verification failed with algorithm %s' % algo - + # assert signature == algos[algo], + # 'mismatched signature with algorithm %s: + # signature=%s' % (algo, signature) + verify = rsa2.verify(digest, signature, algo) + self.assertEqual(verify, 1, + 'verification failed with algorithm %s' % algo) + if m2.OPENSSL_VERSION_NUMBER >= 0x90708F: def test_sign_and_verify_rsassa_pss(self): """ Testing signing and verifying using rsassa_pss - + The maximum size of the salt has to decrease as the - size of the digest increases because of the size of + size of the digest increases because of the size of our test key limits it. """ - message = "This is the message string" - if sys.version_info < (2, 5): - algos = {'sha1': (43, sha.sha(message).digest()), - 'md5': (47, md5.md5(message).digest())} - - else: - import hashlib - algos = {'sha1': 43, - 'ripemd160': 43, - 'md5': 47} - - if m2.OPENSSL_VERSION_NUMBER >= 0x90800F: - algos['sha224'] = 35 - algos['sha256'] = 31 - algos['sha384'] = 15 - algos['sha512'] = 0 - - for algo, salt_max in algos.iteritems(): - h = hashlib.new(algo) - h.update(message) - digest = h.digest() - algos[algo] = (salt_max, digest) - + message = b"This is the message string" + import hashlib + algos = {'sha1': 43} + if not fips_mode: + algos['md5'] = 47 + algos['ripemd160'] = 43 + + if m2.OPENSSL_VERSION_NUMBER >= 0x90800F: + algos['sha224'] = 35 + algos['sha256'] = 31 + algos['sha384'] = 15 + algos['sha512'] = 0 + + for algo, salt_max in algos.items(): + h = hashlib.new(algo) + h.update(message) + digest = h.digest() + algos[algo] = (salt_max, digest) + rsa = RSA.load_key(self.privkey) rsa2 = RSA.load_pub_key(self.pubkey) - for algo, (salt_max, digest) in algos.iteritems(): + for algo, (salt_max, digest) in algos.items(): for salt_length in range(0, salt_max): signature = rsa.sign_rsassa_pss(digest, algo, salt_length) - verify = rsa2.verify_rsassa_pss(digest, signature, algo, salt_length) - assert verify == 1, 'verification failed with algorithm %s salt length %d' % (algo, salt_length) + verify = rsa2.verify_rsassa_pss(digest, signature, + algo, salt_length) + self.assertEqual(verify, 1, + 'verification failed with algorithm ' + '%s salt length %d' % (algo, salt_length)) def test_sign_bad_method(self): """ Testing calling sign with an unsupported message digest algorithm """ rsa = RSA.load_key(self.privkey) - message = "This is the message string" - digest = md5.md5(message).digest() - self.assertRaises(ValueError, rsa.sign, - digest, 'bad_digest_method') - + digest = 'a' * 16 + with self.assertRaises(ValueError): + rsa.sign(digest, 'bad_digest_method') + def test_verify_bad_method(self): """ Testing calling verify with an unsupported message digest algorithm """ rsa = RSA.load_key(self.privkey) - message = "This is the message string" - digest = md5.md5(message).digest() + digest = b'a' * 16 signature = rsa.sign(digest, 'sha1') - self.assertRaises(ValueError, rsa.verify, - digest, signature, 'bad_digest_method') + with self.assertRaises(ValueError): + rsa.verify(digest, signature, 'bad_digest_method') def test_verify_mismatched_algo(self): """ @@ -238,13 +308,12 @@ class RSATestCase(unittest.TestCase): message digest algorithm """ rsa = RSA.load_key(self.privkey) - message = "This is the message string" - digest = sha.sha(message).digest() + message = b"This is the message string" + digest = hashlib.sha1(message).digest() signature = rsa.sign(digest, 'sha1') - rsa2 = RSA.load_pub_key(self.pubkey) - self.assertRaises(RSA.RSAError, rsa.verify, - digest, signature, 'md5') - + with self.assertRaises(RSA.RSAError): + rsa.verify(digest, signature, 'md5') + def test_sign_fail(self): """ Testing sign to make sure it fails when I give it @@ -253,33 +322,33 @@ class RSATestCase(unittest.TestCase): it has to be longer than a certain length. """ rsa = RSA.load_key(self.privkey) - digest = """This string should be long enough to warrant an error in + digest = b"""This string should be long enough to warrant an error in RSA_sign""" * 2 - - self.assertRaises(RSA.RSAError, rsa.sign, digest) - + + with self.assertRaises(RSA.RSAError): + rsa.sign(digest) + def test_verify_bad_signature(self): """ Testing verify to make sure it fails when we use a bad signature """ rsa = RSA.load_key(self.privkey) - message = "This is the message string" - digest = sha.sha(message).digest() + message = b"This is the message string" + digest = hashlib.sha1(message).digest() + + other_message = b"Abracadabra" + other_digest = hashlib.sha1(other_message).digest() + other_signature = rsa.sign(other_digest) + + with self.assertRaises(RSA.RSAError): + rsa.verify(digest, other_signature) - otherMessage = "Abracadabra" - otherDigest = sha.sha(otherMessage).digest() - otherSignature = rsa.sign(otherDigest) - self.assertRaises(RSA.RSAError, rsa.verify, - digest, otherSignature) - - def suite(): return unittest.makeSuite(RSATestCase) - + if __name__ == '__main__': - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_smime.py b/tests/test_smime.py index f18c9db..a0edca8 100644 --- a/tests/test_smime.py +++ b/tests/test_smime.py @@ -5,97 +5,209 @@ Copyright (C) 2006 Open Source Applications Foundation. All Rights Reserved. """ -import unittest -from M2Crypto import SMIME, BIO, Rand, X509, EVP +import os.path + +from M2Crypto import BIO, EVP, Rand, SMIME, X509 +from tests import unittest + + +# Various callbacks to set by X509_Store.set_verify_cb() for +# testing with SMIME.verify() afterwards. +# NOTE: if the Python callback function contains compile-time or run-time +# errors, then SMIME.verify() can fail with a mysterious error which can be +# hard to trace back. +# Python exceptions in callbacks do *not* propagate to verify() call. +def verify_cb_dummy_function(ok, ctx): + return ok + + +def verify_cb_rejects_cert_from_heikki_toivonen(ok, ctx): + cert = ctx.get_current_cert() + return "Heikki Toivonen" not in cert.get_issuer().as_text() + class SMIMETestCase(unittest.TestCase): - cleartext = 'some text to manipulate' + cleartext = b'some text to manipulate' def setUp(self): # XXX Ugly, but not sure what would be better self.signed = self.test_sign() self.encrypted = self.test_encrypt() - + def test_load_bad(self): s = SMIME.SMIME() - self.assertRaises(EVP.EVPError, s.load_key, - 'tests/signer.pem', - 'tests/signer.pem') - - self.assertRaises(BIO.BIOError, SMIME.load_pkcs7, 'nosuchfile-dfg456') - self.assertRaises(SMIME.PKCS7_Error, SMIME.load_pkcs7, 'tests/signer.pem') - self.assertRaises(SMIME.PKCS7_Error, SMIME.load_pkcs7_bio, BIO.MemoryBuffer('no pkcs7')) - - self.assertRaises(SMIME.SMIME_Error, SMIME.smime_load_pkcs7, 'tests/signer.pem') - self.assertRaises(SMIME.SMIME_Error, SMIME.smime_load_pkcs7_bio, BIO.MemoryBuffer('no pkcs7')) + with self.assertRaises(EVP.EVPError): + s.load_key('tests/signer.pem', + 'tests/signer.pem') + + with self.assertRaises(BIO.BIOError): + SMIME.load_pkcs7('nosuchfile-dfg456') + with self.assertRaises(SMIME.PKCS7_Error): + SMIME.load_pkcs7('tests/signer.pem') + with self.assertRaises(SMIME.PKCS7_Error): + SMIME.load_pkcs7_bio(BIO.MemoryBuffer(b'no pkcs7')) + + with self.assertRaises(BIO.BIOError): + SMIME.load_pkcs7_der('nosuchfile-dfg456') + with self.assertRaises(SMIME.PKCS7_Error): + SMIME.load_pkcs7_der('tests/signer.pem') + with self.assertRaises(SMIME.PKCS7_Error): + SMIME.load_pkcs7_bio_der(BIO.MemoryBuffer(b'no pkcs7')) + + with self.assertRaises(SMIME.SMIME_Error): + SMIME.smime_load_pkcs7('tests/signer.pem') + with self.assertRaises(SMIME.SMIME_Error): + SMIME.smime_load_pkcs7_bio(BIO.MemoryBuffer(b'no pkcs7')) def test_crlf(self): - self.assertEqual(SMIME.text_crlf('foobar'), 'Content-Type: text/plain\r\n\r\nfoobar') - self.assertEqual(SMIME.text_crlf_bio(BIO.MemoryBuffer('foobar')).read(), 'Content-Type: text/plain\r\n\r\nfoobar') - + self.assertEqual(SMIME.text_crlf(b'foobar'), b'Content-Type: text/plain\r\n\r\nfoobar') + self.assertEqual(SMIME.text_crlf_bio( + BIO.MemoryBuffer(b'foobar')).read(), b'Content-Type: text/plain\r\n\r\nfoobar') + def test_sign(self): buf = BIO.MemoryBuffer(self.cleartext) s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') p7 = s.sign(buf, SMIME.PKCS7_DETACHED) - assert len(buf) == 0 - assert p7.type() == SMIME.PKCS7_SIGNED, p7.type() - assert isinstance(p7, SMIME.PKCS7), p7 + self.assertEqual(len(buf), 0) + self.assertEqual(p7.type(), SMIME.PKCS7_SIGNED, p7.type()) + self.assertIsInstance(p7, SMIME.PKCS7, p7) out = BIO.MemoryBuffer() p7.write(out) - + buf = out.read() - - assert buf[:len('-----BEGIN PKCS7-----')] == '-----BEGIN PKCS7-----' + + self.assertTrue(buf.startswith(b'-----BEGIN PKCS7-----'), + b'-----BEGIN PKCS7-----') buf = buf.strip() - assert buf[-len('-----END PKCS7-----'):] == '-----END PKCS7-----', buf[-len('-----END PKCS7-----'):] - assert len(buf) > len('-----END PKCS7-----') + len('-----BEGIN PKCS7-----') - + self.assertTrue(buf.endswith(b'-----END PKCS7-----'), + buf[-len(b'-----END PKCS7-----'):]) + self.assertGreater(len(buf), + len(b'-----END PKCS7-----') + + len(b'-----BEGIN PKCS7-----')) + s.write(out, p7, BIO.MemoryBuffer(self.cleartext)) return out - def test_store_load_info(self): + def test_sign_unknown_digest(self): + buf = BIO.MemoryBuffer(self.cleartext) + s = SMIME.SMIME() + s.load_key('tests/signer_key.pem', 'tests/signer.pem') + self.assertRaises(SMIME.SMIME_Error, s.sign, + buf, SMIME.PKCS7_DETACHED, 'invalid digest name') + + def test_sign_nondefault_digest(self): + buf = BIO.MemoryBuffer(self.cleartext) + s = SMIME.SMIME() + s.load_key('tests/signer_key.pem', 'tests/signer.pem') + p7 = s.sign(buf, flags=SMIME.PKCS7_DETACHED, algo='sha512') + self.assertEqual(p7.type(), SMIME.PKCS7_SIGNED) + + def test_sign_with_stack(self): + buf = BIO.MemoryBuffer(self.cleartext) + s = SMIME.SMIME() + s.load_key('tests/signer_key.pem', 'tests/signer.pem') + cert = X509.load_cert('tests/server.pem') + stack = X509.X509_Stack() + stack.push(cert) + s.set_x509_stack(stack) + p7 = s.sign(buf, flags=SMIME.PKCS7_DETACHED, algo='sha512') + self.assertEqual(p7.type(), SMIME.PKCS7_SIGNED) + + def test_store_load_info(self): st = X509.X509_Store() - self.assertRaises(X509.X509Error, st.load_info, 'tests/ca.pem-typoname') - self.assertEqual(st.load_info('tests/ca.pem'), 1) + with self.assertRaises(X509.X509Error): + st.load_info('tests/ca.pem-typoname') + self.assertEqual(st.load_info('tests/ca.pem'), 1) def test_verify(self): s = SMIME.SMIME() - + x509 = X509.load_cert('tests/signer.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) - + st = X509.X509_Store() st.load_info('tests/ca.pem') s.set_x509_store(st) - + p7, data = SMIME.smime_load_pkcs7_bio(self.signed) - - assert isinstance(p7, SMIME.PKCS7), p7 + self.assertIsInstance(p7, SMIME.PKCS7, p7) + v = s.verify(p7, data) - assert v == self.cleartext - + self.assertEqual(v, self.cleartext) + t = p7.get0_signers(sk) - assert len(t) == 1 - assert t[0].as_pem() == x509.as_pem(), t[0].as_text() + self.assertEqual(len(t), 1) + self.assertEqual(t[0].as_pem(), x509.as_pem(), t[0].as_text()) + + def test_verify_with_static_callback(self): + s = SMIME.SMIME() + + x509 = X509.load_cert('tests/signer.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + st = X509.X509_Store() + st.load_info('tests/ca.pem') + st.set_verify_cb(verify_cb_rejects_cert_from_heikki_toivonen) + s.set_x509_store(st) + + p7, data = SMIME.smime_load_pkcs7_bio(self.signed) + self.assertIsInstance(p7, SMIME.PKCS7, p7) + + # Should reject certificate issued by Heikki Toivonen: + with self.assertRaises(SMIME.PKCS7_Error): + s.verify(p7, data) + + st.set_verify_cb(verify_cb_dummy_function) + v = s.verify(p7, data) + self.assertEqual(v, self.cleartext) + + st.set_verify_cb() + v = s.verify(p7, data) + self.assertEqual(v, self.cleartext) + + def verify_cb_dummy_method(self, ok, store): + return verify_cb_dummy_function(ok, store) + + def test_verify_with_method_callback(self): + s = SMIME.SMIME() + + x509 = X509.load_cert('tests/signer.pem') + sk = X509.X509_Stack() + sk.push(x509) + s.set_x509_stack(sk) + + st = X509.X509_Store() + st.load_info('tests/ca.pem') + st.set_verify_cb(self.verify_cb_dummy_method) + s.set_x509_store(st) + + p7, data = SMIME.smime_load_pkcs7_bio(self.signed) + + self.assertIsInstance(p7, SMIME.PKCS7, p7) + v = s.verify(p7, data) + self.assertEqual(v, self.cleartext) def test_verifyBad(self): s = SMIME.SMIME() - + x509 = X509.load_cert('tests/recipient.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) - + st = X509.X509_Store() st.load_info('tests/recipient.pem') s.set_x509_store(st) - + p7, data = SMIME.smime_load_pkcs7_bio(self.signed) - assert isinstance(p7, SMIME.PKCS7), p7 - self.assertRaises(SMIME.PKCS7_Error, s.verify, p7) # Bad signer + self.assertIsInstance(p7, SMIME.PKCS7, p7) + with self.assertRaises(SMIME.PKCS7_Error): + s.verify(p7) # Bad signer def test_encrypt(self): buf = BIO.MemoryBuffer(self.cleartext) @@ -106,146 +218,159 @@ class SMIMETestCase(unittest.TestCase): sk.push(x509) s.set_x509_stack(sk) - self.assertRaises(ValueError, SMIME.Cipher, 'nosuchcipher') + with self.assertRaises(ValueError): + SMIME.Cipher('nosuchcipher') s.set_cipher(SMIME.Cipher('des_ede3_cbc')) p7 = s.encrypt(buf) - - assert len(buf) == 0 - assert p7.type() == SMIME.PKCS7_ENVELOPED, p7.type() - assert isinstance(p7, SMIME.PKCS7), p7 + + self.assertEqual(len(buf), 0) + self.assertEqual(p7.type(), SMIME.PKCS7_ENVELOPED, + p7.type()) + self.assertIsInstance(p7, SMIME.PKCS7, p7) out = BIO.MemoryBuffer() p7.write(out) - + buf = out.read() - - assert buf[:len('-----BEGIN PKCS7-----')] == '-----BEGIN PKCS7-----' + + self.assertTrue(buf.startswith(b'-----BEGIN PKCS7-----')) buf = buf.strip() - assert buf[-len('-----END PKCS7-----'):] == '-----END PKCS7-----' - assert len(buf) > len('-----END PKCS7-----') + len('-----BEGIN PKCS7-----') - + self.assertTrue(buf.endswith(b'-----END PKCS7-----')) + self.assertGreater(len(buf), + len(b'-----END PKCS7-----') + + len(b'-----BEGIN PKCS7-----')) + s.write(out, p7) return out - + def test_decrypt(self): s = SMIME.SMIME() s.load_key('tests/recipient_key.pem', 'tests/recipient.pem') - + p7, data = SMIME.smime_load_pkcs7_bio(self.encrypted) - assert isinstance(p7, SMIME.PKCS7), p7 - self.assertRaises(SMIME.SMIME_Error, s.verify, p7) # No signer - + self.assertIsInstance(p7, SMIME.PKCS7, p7) + with self.assertRaises(SMIME.SMIME_Error): + s.verify(p7) # No signer + out = s.decrypt(p7) - assert out == self.cleartext + self.assertEqual(out, self.cleartext) def test_decryptBad(self): s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') - + p7, data = SMIME.smime_load_pkcs7_bio(self.encrypted) - assert isinstance(p7, SMIME.PKCS7), p7 - self.assertRaises(SMIME.SMIME_Error, s.verify, p7) # No signer + self.assertIsInstance(p7, SMIME.PKCS7, p7) + with self.assertRaises(SMIME.SMIME_Error): + s.verify(p7) # No signer # Cannot decrypt: no recipient matches certificate - self.assertRaises(SMIME.PKCS7_Error, s.decrypt, p7) + with self.assertRaises(SMIME.PKCS7_Error): + s.decrypt(p7) def test_signEncryptDecryptVerify(self): # sign buf = BIO.MemoryBuffer(self.cleartext) - s = SMIME.SMIME() + s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') p7 = s.sign(buf) - + # encrypt x509 = X509.load_cert('tests/recipient.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) - + s.set_cipher(SMIME.Cipher('des_ede3_cbc')) - + tmp = BIO.MemoryBuffer() s.write(tmp, p7) p7 = s.encrypt(tmp) - + signedEncrypted = BIO.MemoryBuffer() s.write(signedEncrypted, p7) # decrypt s = SMIME.SMIME() - + s.load_key('tests/recipient_key.pem', 'tests/recipient.pem') - + p7, data = SMIME.smime_load_pkcs7_bio(signedEncrypted) - + out = s.decrypt(p7) - + # verify x509 = X509.load_cert('tests/signer.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) - + st = X509.X509_Store() st.load_info('tests/ca.pem') s.set_x509_store(st) - + p7_bio = BIO.MemoryBuffer(out) p7, data = SMIME.smime_load_pkcs7_bio(p7_bio) v = s.verify(p7) - assert v == self.cleartext + self.assertEqual(v, self.cleartext) class WriteLoadTestCase(unittest.TestCase): def setUp(self): s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') - p7 = s.sign(BIO.MemoryBuffer('some text')) + p7 = s.sign(BIO.MemoryBuffer(b'some text')) self.filename = 'tests/sig.p7' - f = BIO.openfile(self.filename, 'wb') - assert p7.write(f) == 1 - f.close() + with BIO.openfile(self.filename, 'wb') as f: + self.assertEqual(p7.write(f), 1) + self.filename_der = 'tests/sig.p7.der' + with BIO.openfile(self.filename_der, 'wb') as f: + self.assertEqual(p7.write_der(f), 1) - p7 = s.sign(BIO.MemoryBuffer('some text'), SMIME.PKCS7_DETACHED) + p7 = s.sign(BIO.MemoryBuffer(b'some text'), SMIME.PKCS7_DETACHED) self.filenameSmime = 'tests/sig.p7s' - f = BIO.openfile(self.filenameSmime, 'wb') - assert s.write(f, p7, BIO.MemoryBuffer('some text')) == 1 - f.close() - - def test_write_pkcs7_der(self): - buf = BIO.MemoryBuffer() - assert SMIME.load_pkcs7(self.filename).write_der(buf) == 1 - s = buf.read() - assert len(s) in (1204, 1243), len(s) - + with BIO.openfile(self.filenameSmime, 'wb') as f: + self.assertEqual(s.write(f, p7, BIO.MemoryBuffer(b'some text')), 1) + + def tearDown(self): + if os.path.exists(self.filename_der): + os.unlink(self.filename_der) + def test_load_pkcs7(self): - assert SMIME.load_pkcs7(self.filename).type() == SMIME.PKCS7_SIGNED - + self.assertEqual(SMIME.load_pkcs7(self.filename).type(), SMIME.PKCS7_SIGNED) + def test_load_pkcs7_bio(self): - f = open(self.filename, 'rb') - buf = BIO.MemoryBuffer(f.read()) - f.close() - - assert SMIME.load_pkcs7_bio(buf).type() == SMIME.PKCS7_SIGNED + with open(self.filename, 'rb') as f: + buf = BIO.MemoryBuffer(f.read()) + + self.assertEqual(SMIME.load_pkcs7_bio(buf).type(), SMIME.PKCS7_SIGNED) + + def test_load_pkcs7_der(self): + self.assertEqual(SMIME.load_pkcs7_der(self.filename_der).type(), SMIME.PKCS7_SIGNED) + + def test_load_pkcs7_bio_der(self): + with open(self.filename_der, 'rb') as f: + buf = BIO.MemoryBuffer(f.read()) + + self.assertEqual(SMIME.load_pkcs7_bio_der(buf).type(), SMIME.PKCS7_SIGNED) def test_load_smime(self): a, b = SMIME.smime_load_pkcs7(self.filenameSmime) - assert isinstance(a, SMIME.PKCS7), a - assert isinstance(b, BIO.BIO), b - assert a.type() == SMIME.PKCS7_SIGNED - + self.assertIsInstance(a, SMIME.PKCS7, a) + self.assertIsInstance(b, BIO.BIO, b) + self.assertEqual(a.type(), SMIME.PKCS7_SIGNED) + def test_load_smime_bio(self): - f = open(self.filenameSmime, 'rb') - buf = BIO.MemoryBuffer(f.read()) - f.close() + with open(self.filenameSmime, 'rb') as f: + buf = BIO.MemoryBuffer(f.read()) a, b = SMIME.smime_load_pkcs7_bio(buf) - assert isinstance(a, SMIME.PKCS7), a - assert isinstance(b, BIO.BIO), b - assert a.type() == SMIME.PKCS7_SIGNED + self.assertIsInstance(a, SMIME.PKCS7, a) + self.assertIsInstance(b, BIO.BIO, b) + self.assertEqual(a.type(), SMIME.PKCS7_SIGNED) def suite(): @@ -259,4 +384,3 @@ if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') - diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 701484d..925d365 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -1,5 +1,5 @@ #!/usr/bin/env python - +from __future__ import absolute_import, print_function """Unit tests for M2Crypto.SSL. Copyright (c) 2000-2004 Ng Pheng Siong. All rights reserved. @@ -19,280 +19,320 @@ Others: - ForkingSSLServer - ThreadingSSLServer """ +import gc +import logging +import os +import os.path +import signal +import socket +import subprocess +import sys +import tempfile +import time +import warnings + +from M2Crypto import (Err, Rand, SSL, X509, ftpslib, httpslib, m2, m2urllib, + m2urllib2, m2xmlrpclib, py27plus, six) +from M2Crypto.SSL.timeout import DEFAULT_TIMEOUT +from tests import unittest +from tests.fips import fips_mode + +log = logging.getLogger('test_SSL') + +OPENSSL111=m2.OPENSSL_VERSION_NUMBER > 0x10101000 + +# FIXME +# It would be probably better if the port was randomly selected. +# https://fedorahosted.org/libuser/browser/tests/alloc_port.c +srv_host = 'localhost' -import os, socket, string, sys, tempfile, thread, time, unittest -from M2Crypto import Rand, SSL, m2, Err -from fips import fips_mode +def allocate_srv_port(): + s = socket.socket() + try: + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind((srv_host, 0)) + (host, port) = s.getsockname() + finally: + s.close() + return port -srv_host = 'localhost' -srv_port = 64000 def verify_cb_new_function(ok, store): - try: - assert not ok - err = store.get_error() - assert err in [m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, - m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, - m2.X509_V_ERR_CERT_UNTRUSTED, - m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE] - assert store.get_error_depth() == 0 - app_data = m2.x509_store_ctx_get_app_data(store.ctx) - assert app_data - x509 = store.get_current_cert() - assert x509 - stack = store.get1_chain() - assert len(stack) == 1 - assert stack[0].as_pem() == x509.as_pem() - except AssertionError, e: - # If we let exceptions propagate from here the - # caller may see strange errors. This is cleaner. - return 0 + assert not ok + err = store.get_error() + assert err in [m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, + m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, + m2.X509_V_ERR_CERT_UNTRUSTED, + m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE] + assert store.get_error_depth() == 0 + app_data = m2.x509_store_ctx_get_ex_data( + store.ctx, m2.ssl_get_ex_data_x509_store_ctx_idx()) + assert app_data + x509 = store.get_current_cert() + assert x509 + stack = store.get1_chain() + assert len(stack) == 1 + assert stack[0].as_pem() == x509.as_pem() return 1 -class VerifyCB: + +class VerifyCB(object): def __call__(self, ok, store): return verify_cb_new_function(ok, store) -sleepTime = float(os.getenv('M2CRYPTO_TEST_SSL_SLEEP', 0.5)) +sleepTime = float(os.getenv('M2CRYPTO_TEST_SSL_SLEEP', '1.5')) -def find_openssl(): - if os.name == 'nt' or sys.platform == 'cygwin': - openssl = 'openssl.exe' - else: - openssl = 'openssl' - - plist = os.environ['PATH'].split(os.pathsep) - for p in plist: - try: - dir = os.listdir(p) - if openssl in dir: - return True - except: - pass - return False class BaseSSLClientTestCase(unittest.TestCase): - openssl_in_path = find_openssl() + # I would like to make it into a staticmethod, but apparently it + # doesn't mesh with @property. Oh well. + @property + def _is_openssl_in_path(self): + if os.name == 'nt' or sys.platform == 'cygwin': + openssl = 'openssl.exe' + else: + openssl = 'openssl' + + plist = os.environ['PATH'].split(os.pathsep) + for p in plist: + try: + dir = os.listdir(p) + if openssl in dir: + return True + except: + pass + return False def start_server(self, args): - if not self.openssl_in_path: + if not self._is_openssl_in_path: raise Exception('openssl command not in PATH') - - pid = os.fork() - if pid == 0: - # openssl must be started in the tests directory for it - # to find the .pem files - os.chdir('tests') - try: - os.execvp('openssl', args) - finally: - os.chdir('..') - - else: - time.sleep(sleepTime) - return pid + + pid = subprocess.Popen(['openssl'] + args, + cwd='tests', + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + time.sleep(sleepTime) + return pid def stop_server(self, pid): - os.kill(pid, 1) - os.waitpid(pid, 0) + pid.terminate() + out, err = pid.communicate() + return six.ensure_text(out), six.ensure_text(err) def http_get(self, s): - s.send('GET / HTTP/1.0\n\n') - resp = '' + s.send(b'GET / HTTP/1.0\n\n') + resp = b'' while 1: try: r = s.recv(4096) if not r: break - except SSL.SSLError: # s_server throws an 'unexpected eof'... + except SSL.SSLError: # s_server throws an 'unexpected eof'... break - resp = resp + r - return resp + resp = resp + r + return six.ensure_text(resp) def setUp(self): self.srv_host = srv_host - self.srv_port = srv_port - self.srv_addr = (srv_host, srv_port) - self.srv_url = 'https://%s:%s/' % (srv_host, srv_port) + self.srv_port = allocate_srv_port() + self.srv_addr = (srv_host, self.srv_port) + self.srv_url = 'https://%s:%s/' % (srv_host, self.srv_port) self.args = ['s_server', '-quiet', '-www', - #'-cert', 'server.pem', Implicitly using this + # '-cert', 'server.pem', Implicitly using this '-accept', str(self.srv_port)] - def tearDown(self): - global srv_port - srv_port = srv_port - 1 - class PassSSLClientTestCase(BaseSSLClientTestCase): - + def test_pass(self): pass + class HttpslibSSLClientTestCase(BaseSSLClientTestCase): + def setUp(self): + super(HttpslibSSLClientTestCase, self).setUp() + self.ctx = SSL.Context() + + def tearDown(self): + self.ctx.close() def test_HTTPSConnection(self): pid = self.start_server(self.args) try: - from M2Crypto import httpslib - c = httpslib.HTTPSConnection(srv_host, srv_port) + c = httpslib.HTTPSConnection(srv_host, self.srv_port) c.request('GET', '/') data = c.getresponse().read() c.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', six.ensure_text(data)) + @unittest.skipIf(OPENSSL111, "Doesn't work with OpenSSL 1.1.1") def test_HTTPSConnection_resume_session(self): pid = self.start_server(self.args) try: - from M2Crypto import httpslib - ctx = SSL.Context() - ctx.load_verify_locations(cafile='tests/ca.pem') - ctx.load_cert('tests/x509.pem') - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 1) - ctx.set_session_cache_mode(m2.SSL_SESS_CACHE_CLIENT) - c = httpslib.HTTPSConnection(srv_host, srv_port, ssl_context=ctx) + self.ctx.load_verify_locations(cafile='tests/ca.pem') + self.ctx.load_cert('tests/x509.pem') + self.ctx.set_verify( + SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 1) + self.ctx.set_session_cache_mode(m2.SSL_SESS_CACHE_CLIENT) + c = httpslib.HTTPSConnection(srv_host, self.srv_port, + ssl_context=self.ctx) c.request('GET', '/') ses = c.get_session() t = ses.as_text() data = c.getresponse().read() # Appearently closing connection here screws session; Ali Polatel? # c.close() - + ctx2 = SSL.Context() ctx2.load_verify_locations(cafile='tests/ca.pem') ctx2.load_cert('tests/x509.pem') - ctx2.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 1) + ctx2.set_verify( + SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 1) ctx2.set_session_cache_mode(m2.SSL_SESS_CACHE_CLIENT) - c2 = httpslib.HTTPSConnection(srv_host, srv_port, ssl_context=ctx2) + c2 = httpslib.HTTPSConnection(srv_host, self.srv_port, + ssl_context=ctx2) c2.set_session(ses) c2.request('GET', '/') ses2 = c2.get_session() t2 = ses2.as_text() - data = c2.getresponse().read() + data = six.ensure_text(c2.getresponse().read()) c.close() c2.close() - assert t == t2, "Sessions did not match" + self.assertEqual(t, t2, + "Sessions did not match: t = %s, t2 = %s" % (t, t2,)) finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_HTTPSConnection_secure_context(self): pid = self.start_server(self.args) try: - from M2Crypto import httpslib - ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) - ctx.load_verify_locations('tests/ca.pem') - c = httpslib.HTTPSConnection(srv_host, srv_port, ssl_context=ctx) + self.ctx.set_verify( + SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + self.ctx.load_verify_locations('tests/ca.pem') + c = httpslib.HTTPSConnection(srv_host, self.srv_port, + ssl_context=self.ctx) c.request('GET', '/') - data = c.getresponse().read() + data = six.ensure_text(c.getresponse().read()) c.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_HTTPSConnection_secure_context_fail(self): pid = self.start_server(self.args) try: - from M2Crypto import httpslib - ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) - ctx.load_verify_locations('tests/server.pem') - c = httpslib.HTTPSConnection(srv_host, srv_port, ssl_context=ctx) - self.assertRaises(SSL.SSLError, c.request, 'GET', '/') + self.ctx.set_verify( + SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + self.ctx.load_verify_locations('tests/server.pem') + c = httpslib.HTTPSConnection(srv_host, self.srv_port, + ssl_context=self.ctx) + with self.assertRaises(SSL.SSLError): + c.request('GET', '/') c.close() finally: self.stop_server(pid) - def test_HTTPS(self): - pid = self.start_server(self.args) - try: - from M2Crypto import httpslib - c = httpslib.HTTPS(srv_host, srv_port) - c.putrequest('GET', '/') - c.putheader('Accept', 'text/html') - c.putheader('Accept', 'text/plain') - c.endheaders() - err, msg, headers = c.getreply() - assert err == 200, err - f = c.getfile() - data = f.read() - c.close() - finally: - self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + def test_HTTPSConnection_illegalkeywordarg(self): + with self.assertRaises(ValueError): + httpslib.HTTPSConnection('example.org', badKeyword=True) + + +class HttpslibSSLSNIClientTestCase(BaseSSLClientTestCase): + def setUp(self): + super(HttpslibSSLSNIClientTestCase, self).setUp() + self.args = ['s_server', '-servername', srv_host, '-debug', '-www', '-msg', + '-cert', 'server.pem', '-key', 'server_key.pem', + '-cert2', 'server.pem', '-key2', 'server_key.pem', + '-accept', str(self.srv_port)] + self.ctx = SSL.Context() - def test_HTTPS_secure_context(self): + def tearDown(self): + self.ctx.close() + + def test_SNI_support(self): pid = self.start_server(self.args) try: - from M2Crypto import httpslib - ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) - ctx.load_verify_locations('tests/ca.pem') - c = httpslib.HTTPS(srv_host, srv_port, ssl_context=ctx) - c.putrequest('GET', '/') - c.putheader('Accept', 'text/html') - c.putheader('Accept', 'text/plain') - c.endheaders() - err, msg, headers = c.getreply() - assert err == 200, err - f = c.getfile() - data = f.read() + c = httpslib.HTTPSConnection(self.srv_host, self.srv_port, + ssl_context=self.ctx) + c.request('GET', '/') c.close() finally: - self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + # (openssl s_server) buffers its log output, and ends the TLS session + # with the client (allowing the client to terminate) before flushing + # the log; so, the client may get here and terminate the server + # before it manages to log the output. + # So, give the server hopefully enough time to flush the logs. + time.sleep(sleepTime) + out, _ = self.stop_server(pid) + self.assertIn('Hostname in TLS extension: "%s"' % srv_host, out) - def test_HTTPS_secure_context_fail(self): + def test_IP_call(self): + no_exception = True + runs_counter = 0 pid = self.start_server(self.args) - try: - from M2Crypto import httpslib - ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) - ctx.load_verify_locations('tests/server.pem') - c = httpslib.HTTPS(srv_host, srv_port, ssl_context=ctx) - c.putrequest('GET', '/') - c.putheader('Accept', 'text/html') - c.putheader('Accept', 'text/plain') - self.assertRaises(SSL.SSLError, c.endheaders) - c.close() - finally: - self.stop_server(pid) - - def test_HTTPSConnection_illegalkeywordarg(self): - from M2Crypto import httpslib - self.assertRaises(ValueError, httpslib.HTTPSConnection, 'example.org', - badKeyword=True) + + for entry in socket.getaddrinfo(self.srv_host, self.srv_port, + socket.AF_INET, + socket.SOCK_STREAM, + socket.IPPROTO_TCP): + ipfamily, socktype, _, _, sockaddr = entry + ip = sockaddr[0] + + sock = socket.socket(ipfamily, socktype) + conn = SSL.Connection(self.ctx, sock=sock) + conn.set_tlsext_host_name(self.srv_host) + conn.set1_host(self.srv_host) + + runs_counter += 1 + try: + conn.connect((ip, self.srv_port)) + except (SSL.SSLError, socket.error): + log.exception("Failed to connect to %s:%s", ip, self.srv_port) + no_exception = False + finally: + conn.close() + + out, _ = self.stop_server(pid) + self.assertEqual( + out.count('Hostname in TLS extension: "%s"' % self.srv_host), + runs_counter) + + self.assertTrue(no_exception) class MiscSSLClientTestCase(BaseSSLClientTestCase): def test_no_connection(self): ctx = SSL.Context() - s = SSL.Connection(ctx) - + SSL.Connection(ctx) + def test_server_simple(self): pid = self.start_server(self.args) try: - self.assertRaises(ValueError, SSL.Context, 'tlsv5') + with self.assertRaises(ValueError): + SSL.Context('tlsv5') ctx = SSL.Context() s = SSL.Connection(ctx) s.connect(self.srv_addr) - self.assertRaises(ValueError, s.read, 0) + with self.assertRaises(ValueError): + s.read(0) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_server_simple_secure_context(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9) ctx.load_verify_locations('tests/ca.pem') s = SSL.Connection(ctx) s.connect(self.srv_addr) @@ -300,62 +340,74 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_server_simple_secure_context_fail(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9) ctx.load_verify_locations('tests/server.pem') s = SSL.Connection(ctx) - self.assertRaises(SSL.SSLError, s.connect, self.srv_addr) + with self.assertRaises(SSL.SSLError): + s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_server_simple_timeouts(self): pid = self.start_server(self.args) + # Arbitrary value: + test_timeout_sec = 909 + # Linux rounds microseconds in the timeouts up to the HZ kernel parameter. + # Windows rounds down to milliseconds. + # To avoid checking for rounded values, pick interval long enough + # so that it is a whole number of ms and HZ for any reasonable HZ value. + test_timeout_microsec = 500000 + try: - self.assertRaises(ValueError, SSL.Context, 'tlsv5') + with self.assertRaises(ValueError): + SSL.Context('tlsv5') ctx = SSL.Context() s = SSL.Connection(ctx) - + r = s.get_socket_read_timeout() w = s.get_socket_write_timeout() - assert r.sec == 0, r.sec - assert r.microsec == 0, r.microsec - assert w.sec == 0, w.sec - assert w.microsec == 0, w.microsec + self.assertEqual(r.sec, 0, r.sec) + self.assertEqual(r.microsec, 0, r.microsec) + self.assertEqual(w.sec, 0, w.sec) + self.assertEqual(w.microsec, 0, w.microsec) s.set_socket_read_timeout(SSL.timeout()) - s.set_socket_write_timeout(SSL.timeout(909,9)) + s.set_socket_write_timeout(SSL.timeout(test_timeout_sec, test_timeout_microsec)) r = s.get_socket_read_timeout() w = s.get_socket_write_timeout() - assert r.sec == 600, r.sec - assert r.microsec == 0, r.microsec - assert w.sec == 909, w.sec - #assert w.microsec == 9, w.microsec XXX 4000 - + self.assertEqual(r.sec, DEFAULT_TIMEOUT, r.sec) + self.assertEqual(r.microsec, 0, r.microsec) + self.assertEqual(w.sec, test_timeout_sec, w.sec) + self.assertEqual(w.microsec, test_timeout_microsec, w.microsec) + s.connect(self.srv_addr) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) + # TLS is required in FIPS mode + @unittest.skipIf(fips_mode, "Can't be run in FIPS mode") def test_tls1_nok(self): - if fips_mode: # TLS is required in FIPS mode - return self.args.append('-no_tls1') pid = self.start_server(self.args) try: - ctx = SSL.Context('tlsv1') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + ctx = SSL.Context('tlsv1') s = SSL.Connection(ctx) - try: + with six.assertRaisesRegex(self, SSL.SSLError, + r'version|unexpected eof'): s.connect(self.srv_addr) - except SSL.SSLError, e: - self.failUnlessEqual(e[0], 'wrong version number') s.close() finally: self.stop_server(pid) @@ -364,58 +416,16 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): self.args.append('-tls1') pid = self.start_server(self.args) try: - ctx = SSL.Context('tlsv1') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + ctx = SSL.Context('tlsv1') s = SSL.Connection(ctx) s.connect(self.srv_addr) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) - - def test_sslv23_no_v2(self): - if fips_mode: # TLS is required in FIPS mode - return - self.args.append('-no_tls1') - pid = self.start_server(self.args) - try: - ctx = SSL.Context('sslv23') - s = SSL.Connection(ctx) - s.connect(self.srv_addr) - self.failUnlessEqual(s.get_version(), 'SSLv3') - s.close() - finally: - self.stop_server(pid) - - def test_sslv23_no_v2_no_service(self): - if fips_mode: # TLS is required in FIPS mode - return - self.args = self.args + ['-no_tls1', '-no_ssl3'] - pid = self.start_server(self.args) - try: - ctx = SSL.Context('sslv23') - s = SSL.Connection(ctx) - self.assertRaises(SSL.SSLError, s.connect, self.srv_addr) - s.close() - finally: - self.stop_server(pid) - - def test_sslv23_weak_crypto(self): - if fips_mode: # TLS is required in FIPS mode - return - self.args = self.args + ['-no_tls1', '-no_ssl3'] - pid = self.start_server(self.args) - try: - ctx = SSL.Context('sslv23', weak_crypto=1) - s = SSL.Connection(ctx) - if m2.OPENSSL_VERSION_NUMBER < 0x10000000: # SSLv2 ciphers disabled by default in newer OpenSSL - s.connect(self.srv_addr) - self.failUnlessEqual(s.get_version(), 'SSLv2') - else: - self.assertRaises(SSL.SSLError, s.connect, self.srv_addr) - s.close() - finally: - self.stop_server(pid) + self.assertIn('s_server -quiet -www', data) def test_cipher_mismatch(self): self.args = self.args + ['-cipher', 'AES256-SHA'] @@ -424,14 +434,14 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): ctx = SSL.Context() s = SSL.Connection(ctx) s.set_cipher_list('AES128-SHA') - try: - s.connect(self.srv_addr) - except SSL.SSLError, e: - self.failUnlessEqual(e[0], 'sslv3 alert handshake failure') + if not OPENSSL111: + with six.assertRaisesRegex(self, SSL.SSLError, + 'sslv3 alert handshake failure'): + s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) - + def test_no_such_cipher(self): self.args = self.args + ['-cipher', 'AES128-SHA'] pid = self.start_server(self.args) @@ -439,79 +449,64 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): ctx = SSL.Context() s = SSL.Connection(ctx) s.set_cipher_list('EXP-RC2-MD5') - try: - s.connect(self.srv_addr) - except SSL.SSLError, e: - self.failUnlessEqual(e[0], 'no ciphers available') - s.close() - finally: - self.stop_server(pid) - - def test_no_weak_cipher(self): - if fips_mode: # Weak ciphers are prohibited - return - self.args = self.args + ['-cipher', 'EXP'] - pid = self.start_server(self.args) - try: - ctx = SSL.Context() - s = SSL.Connection(ctx) - try: - s.connect(self.srv_addr) - except SSL.SSLError, e: - self.failUnlessEqual(e[0], 'sslv3 alert handshake failure') - s.close() - finally: - self.stop_server(pid) - - def test_use_weak_cipher(self): - if fips_mode: # Weak ciphers are prohibited - return - self.args = self.args + ['-cipher', 'EXP'] - pid = self.start_server(self.args) - try: - ctx = SSL.Context(weak_crypto=1) - s = SSL.Connection(ctx) - s.connect(self.srv_addr) - data = self.http_get(s) + if not OPENSSL111: + with six.assertRaisesRegex(self, SSL.SSLError, + 'no ciphers available'): + s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) - + def test_cipher_ok(self): - self.args = self.args + ['-cipher', 'AES128-SHA'] + if OPENSSL111: + TCIPHER = 'TLS_AES_256_GCM_SHA384' + self.args = self.args + ['-ciphersuites', TCIPHER] + else: + TCIPHER = 'AES128-SHA' + self.args = self.args + ['-cipher', TCIPHER] + pid = self.start_server(self.args) try: ctx = SSL.Context() s = SSL.Connection(ctx) - s.set_cipher_list('AES128-SHA') + s.set_cipher_list(TCIPHER) s.connect(self.srv_addr) data = self.http_get(s) - - assert s.get_cipher().name() == 'AES128-SHA', s.get_cipher().name() - + + self.assertEqual(s.get_cipher().name(), TCIPHER, + s.get_cipher().name()) + cipher_stack = s.get_ciphers() - assert cipher_stack[0].name() == 'AES128-SHA', cipher_stack[0].name() - self.assertRaises(IndexError, cipher_stack.__getitem__, 2) + self.assertEqual(cipher_stack[0].name(), TCIPHER, + cipher_stack[0].name()) + + if not OPENSSL111: + with self.assertRaises(IndexError): + cipher_stack.__getitem__(2) + # For some reason there are 2 entries in the stack - #assert len(cipher_stack) == 1, len(cipher_stack) - assert s.get_cipher_list() == 'AES128-SHA', s.get_cipher_list() - + # self.assertEqual(len(cipher_stack), 1, len(cipher_stack)) + self.assertEqual(s.get_cipher_list(), TCIPHER, + s.get_cipher_list()) + # Test Cipher_Stack iterator i = 0 for cipher in cipher_stack: i += 1 - assert cipher.name() == 'AES128-SHA', '"%s"' % cipher.name() - self.assertEqual('AES128-SHA-128', str(cipher)) + if not OPENSSL111: + cipname = cipher.name() + self.assertEqual(cipname, 'AES128-SHA', + '"%s" (%s)' % (cipname, type(cipname))) + self.assertEqual('AES128-SHA-128', str(cipher)) # For some reason there are 2 entries in the stack - #assert i == 1, i + # self.assertEqual(i, 1, i) self.assertEqual(i, len(cipher_stack)) - + s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) - + self.assertIn('s_server -quiet -www', data) + def verify_cb_new(self, ok, store): return verify_cb_new_function(ok, store) @@ -519,115 +514,118 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, - self.verify_cb_new) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, self.verify_cb_new) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_verify_cb_new_class(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, - VerifyCB()) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, VerifyCB()) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + log.exception(e) + self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_verify_cb_new_function(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, - verify_cb_new_function) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, verify_cb_new_function) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_verify_cb_lambda(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, - lambda ok, store: 1) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, lambda ok, store: 1) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def verify_cb_exception(self, ok, store): - raise Exception, 'We should fail verification' + self.fail('We should fail verification') def test_verify_cb_exception(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, - self.verify_cb_exception) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, self.verify_cb_exception) s = SSL.Connection(ctx) - self.assertRaises(SSL.SSLError, s.connect, self.srv_addr) + with self.assertRaises(SSL.SSLError): + s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_verify_cb_not_callable(self): ctx = SSL.Context() - self.assertRaises(TypeError, - ctx.set_verify, - SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, - 9, - 1) + with self.assertRaises(TypeError): + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, 1) def test_verify_cb_wrong_callable(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, - lambda _: '') + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, lambda _: '') s = SSL.Connection(ctx) - self.assertRaises(SSL.SSLError, s.connect, self.srv_addr) + with self.assertRaises(SSL.SSLError): + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def verify_cb_old(self, ctx_ptr, x509_ptr, err, depth, ok): try: - from M2Crypto import X509 - assert not ok - assert err == m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT or \ - err == m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY or \ - err == m2.X509_V_ERR_CERT_UNTRUSTED or \ - err == m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE - assert m2.ssl_ctx_get_cert_store(ctx_ptr) - assert X509.X509(x509_ptr).as_pem() + self.assertFalse(ok) + self.assertIn(err, + [m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, + m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, + m2.X509_V_ERR_CERT_UNTRUSTED, + m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE]) + self.assertTrue(m2.ssl_ctx_get_cert_store(ctx_ptr)) + self.assertTrue(X509.X509(x509_ptr).as_pem()) except AssertionError: # If we let exceptions propagate from here the # caller may see strange errors. This is cleaner. @@ -635,146 +633,160 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): return 1 def test_verify_cb_old(self): - pid = self.start_server(self.args) - try: - ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, - self.verify_cb_old) - s = SSL.Connection(ctx) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + pid = self.start_server(self.args) try: - s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e - data = self.http_get(s) - s.close() - finally: - self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + ctx = SSL.Context() + ctx.set_verify( + SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, self.verify_cb_old) + s = SSL.Connection(ctx) + try: + s.connect(self.srv_addr) + except SSL.SSLError as e: + self.fail(e) + data = self.http_get(s) + s.close() + finally: + self.stop_server(pid) + self.assertIn('s_server -quiet -www', data) def test_verify_allow_unknown_old(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, - SSL.cb.ssl_verify_callback) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, SSL.cb.ssl_verify_callback_allow_unknown_ca) ctx.set_allow_unknown_ca(1) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError: + log.error('Failed to connect to %s', self.srv_addr) + raise data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_verify_allow_unknown_new(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, - SSL.cb.ssl_verify_callback_allow_unknown_ca) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9, SSL.cb.ssl_verify_callback_allow_unknown_ca) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_verify_cert(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9) ctx.load_verify_locations('tests/ca.pem') s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_verify_cert_fail(self): pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9) ctx.load_verify_locations('tests/server.pem') s = SSL.Connection(ctx) - self.assertRaises(SSL.SSLError, s.connect, self.srv_addr) + with self.assertRaises(SSL.SSLError): + s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_verify_cert_mutual_auth(self): - self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) + self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9) ctx.load_verify_locations('tests/ca.pem') ctx.load_cert('tests/x509.pem') s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_verify_cert_mutual_auth_servernbio(self): self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem', '-nbio']) pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9) ctx.load_verify_locations('tests/ca.pem') ctx.load_cert('tests/x509.pem') s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_verify_cert_mutual_auth_fail(self): - self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) + self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9) ctx.load_verify_locations('tests/ca.pem') s = SSL.Connection(ctx) - self.assertRaises(SSL.SSLError, s.connect, self.srv_addr) + if not OPENSSL111: + with self.assertRaises(SSL.SSLError): + s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_verify_nocert_fail(self): - self.args.extend(['-nocert']) + self.args.extend(['-nocert']) pid = self.start_server(self.args) try: ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, + 9) ctx.load_verify_locations('tests/ca.pem') s = SSL.Connection(ctx) - self.assertRaises(SSL.SSLError, s.connect, self.srv_addr) + with self.assertRaises(SSL.SSLError): + s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) @@ -785,7 +797,8 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): ctx = SSL.Context() s = SSL.Connection(ctx) s.setblocking(0) - self.assertRaises(Exception, s.connect, self.srv_addr) + with self.assertRaises(Exception): + s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) @@ -798,13 +811,13 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): s.setblocking(1) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_makefile(self): pid = self.start_server(self.args) @@ -813,18 +826,18 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e - bio = s.makefile('rw') - #s.close() # XXX bug 6628? - bio.write('GET / HTTP/1.0\n\n') + except SSL.SSLError as e: + self.fail(e) + bio = s.makefile('rwb') + # s.close() # XXX bug 6628? + bio.write(b'GET / HTTP/1.0\n\n') bio.flush() data = bio.read() bio.close() s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn(b's_server -quiet -www', data) def test_makefile_err(self): pid = self.start_server(self.args) @@ -833,20 +846,21 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): s = SSL.Connection(ctx) try: s.connect(self.srv_addr) - except SSL.SSLError, e: - assert 0, e + except SSL.SSLError as e: + self.fail(e) f = s.makefile() data = self.http_get(s) s.close() del f del s err_code = Err.peek_error_code() - assert not err_code, 'Unexpected error: %s' % err_code + self.assertEqual(err_code, 0, + 'Unexpected error: %s' % err_code) err = Err.get_error() - assert not err, 'Unexpected error: %s' % err + self.assertIsNone(err, 'Unexpected error: %s' % err) finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) def test_info_callback(self): pid = self.start_server(self.args) @@ -859,118 +873,260 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): s.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) + + def test_ssl_connection_free(self): + pid = self.start_server(self.args) + orig_m2_ssl_free = SSL.Connection.m2_ssl_free + def _m2_ssl_free(ssl): + orig_m2_ssl_free(ssl) + _m2_ssl_free.called = True + + try: + ctx = SSL.Context() + s = SSL.Connection(ctx) + s.m2_ssl_free = _m2_ssl_free + s.connect(self.srv_addr) + data = self.http_get(s) + s.close() + self.assertFalse(hasattr(_m2_ssl_free, 'called')) + # keep fingers crossed that SSL.Connection.__del__ is called + # by the python interpreter + del s + finally: + self.stop_server(pid) + self.assertIn('s_server -quiet -www', data) + self.assertTrue(getattr(_m2_ssl_free, 'called', False)) + + def test_ssl_connection_no_free(self): + pid = self.start_server(self.args) + orig_m2_ssl_free = SSL.Connection.m2_ssl_free + def _m2_ssl_free(ssl): + _m2_ssl_free.called = True + orig_m2_ssl_free(ssl) + + try: + ctx = SSL.Context() + s = SSL.Connection(ctx) + s.m2_ssl_free = _m2_ssl_free + s.set_ssl_close_flag(m2.bio_close) + s.connect(self.srv_addr) + data = self.http_get(s) + s.close() + self.assertFalse(hasattr(_m2_ssl_free, 'called')) + # keep fingers crossed that SSL.Connection.__del__ is called + # by the python interpreter + del s + finally: + self.stop_server(pid) + self.assertIn('s_server -quiet -www', data) + self.assertFalse(hasattr(_m2_ssl_free, 'called')) class UrllibSSLClientTestCase(BaseSSLClientTestCase): + @unittest.skipIf(six.PY3, "urllib.URLOpener is deprecated in py3k") def test_urllib(self): pid = self.start_server(self.args) try: - from M2Crypto import m2urllib url = m2urllib.FancyURLopener() url.addheader('Connection', 'close') - u = url.open('https://%s:%s/' % (srv_host, srv_port)) + u = url.open('https://%s:%s/' % (srv_host, self.srv_port)) data = u.read() u.close() finally: self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) + self.assertIn('s_server -quiet -www', data) # XXX Don't actually know how to use m2urllib safely! - #def test_urllib_secure_context(self): - #def test_urllib_secure_context_fail(self): - - # XXX Don't actually know how to use m2urllib safely! - #def test_urllib_safe_context(self): - #def test_urllib_safe_context_fail(self): + # def test_urllib_safe_context(self): + # def test_urllib_safe_context_fail(self): class Urllib2SSLClientTestCase(BaseSSLClientTestCase): - if sys.version_info >= (2,4): - def test_urllib2(self): - pid = self.start_server(self.args) - try: - from M2Crypto import m2urllib2 - opener = m2urllib2.build_opener() - opener.addheaders = [('Connection', 'close')] - u = opener.open('https://%s:%s/' % (srv_host, srv_port)) - data = u.read() - u.close() - finally: - self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) - - def test_urllib2_secure_context(self): - pid = self.start_server(self.args) - try: - ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) - ctx.load_verify_locations('tests/ca.pem') - - from M2Crypto import m2urllib2 - opener = m2urllib2.build_opener(ctx) - opener.addheaders = [('Connection', 'close')] - u = opener.open('https://%s:%s/' % (srv_host, srv_port)) - data = u.read() - u.close() - finally: - self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) - - def test_urllib2_secure_context_fail(self): - pid = self.start_server(self.args) - try: - ctx = SSL.Context() - ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) - ctx.load_verify_locations('tests/server.pem') - - from M2Crypto import m2urllib2 - opener = m2urllib2.build_opener(ctx) - opener.addheaders = [('Connection', 'close')] - self.assertRaises(SSL.SSLError, opener.open, 'https://%s:%s/' % (srv_host, srv_port)) - finally: - self.stop_server(pid) + def test_urllib2(self): + pid = self.start_server(self.args) + try: + opener = m2urllib2.build_opener() + opener.addheaders = [('Connection', 'close')] + u = opener.open('https://%s:%s/' % (srv_host, self.srv_port)) + data = u.read() + u.close() + finally: + self.stop_server(pid) + self.assertIn(b's_server -quiet -www', data) - def test_z_urllib2_opener(self): - pid = self.start_server(self.args) - try: - ctx = SSL.Context() + def test_urllib2_secure_context(self): + pid = self.start_server(self.args) + try: + ctx = SSL.Context() + ctx.set_verify( + SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.load_verify_locations('tests/ca.pem') + + opener = m2urllib2.build_opener(ctx) + opener.addheaders = [('Connection', 'close')] + u = opener.open('https://%s:%s/' % (srv_host, self.srv_port)) + data = u.read() + u.close() + finally: + self.stop_server(pid) + self.assertIn(b's_server -quiet -www', data) + + def test_urllib2_secure_context_fail(self): + pid = self.start_server(self.args) + try: + ctx = SSL.Context() + ctx.set_verify( + SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) + ctx.load_verify_locations('tests/server.pem') + + opener = m2urllib2.build_opener(ctx) + opener.addheaders = [('Connection', 'close')] + with self.assertRaises(SSL.SSLError): + opener.open('https://%s:%s/' % (srv_host, self.srv_port)) + finally: + self.stop_server(pid) + + def test_z_urllib2_opener(self): + pid = self.start_server(self.args) + try: + ctx = SSL.Context() + + opener = m2urllib2.build_opener( + ctx, m2urllib2.HTTPBasicAuthHandler()) + m2urllib2.install_opener(opener) + req = m2urllib2.Request('https://%s:%s/' % + (srv_host, self.srv_port)) + u = m2urllib2.urlopen(req) + data = u.read() + u.close() + finally: + self.stop_server(pid) + self.assertIn(b's_server -quiet -www', data) + + def test_urllib2_opener_handlers(self): + ctx = SSL.Context() + + m2urllib2.build_opener(ctx, m2urllib2.HTTPBasicAuthHandler()) + + def test_urllib2_leak(self): + pid = self.start_server(self.args) + try: + o = m2urllib2.build_opener() + r = o.open('https://%s:%s/' % (srv_host, self.srv_port)) + s = [r.fp._sock.fp] + r.close() + # TODO This should be assertEqual 1, but we leak sock + # somehwere. Not sure how to fix it. + log.debug('get_referrers = %d', len(gc.get_referrers(s[0]))) + self.assertLessEqual(len(gc.get_referrers(s[0])), 2) + finally: + self.stop_server(pid) + + +class Urllib2TEChunkedSSLClientTestCase(BaseSSLClientTestCase): + """Test a response with "Transfer-Encoding: chunked".""" + + def setUp(self): + super(Urllib2TEChunkedSSLClientTestCase, self).setUp() + self.args = ['s_server', '-quiet', '-HTTP', + '-accept', str(self.srv_port)] + + def test_transfer_encoding_chunked(self): + pid = self.start_server(self.args) + try: + url = 'https://%s:%s/te_chunked_response.txt' % (srv_host, + self.srv_port) + o = m2urllib2.build_opener() + u = o.open(url) + data = u.read() + self.assertEqual(b'foo\nfoobar\n', data) + finally: + self.stop_server(pid) - from M2Crypto import m2urllib2 - opener = m2urllib2.build_opener(ctx, m2urllib2.HTTPBasicAuthHandler()) - m2urllib2.install_opener(opener) - req = m2urllib2.Request('https://%s:%s/' % (srv_host, srv_port)) - u = m2urllib2.urlopen(req) - data = u.read() - u.close() - finally: - self.stop_server(pid) - self.failIf(string.find(data, 's_server -quiet -www') == -1) - def test_urllib2_opener_handlers(self): +@unittest.skipUnless(py27plus, + "Twisted doesn't test well with Python 2.6") +class TwistedSSLClientTestCase(BaseSSLClientTestCase): + + def test_timeout(self): + pid = self.start_server(self.args) + try: ctx = SSL.Context() + s = SSL.Connection(ctx) + # Just a really small number so we can timeout + s.settimeout(0.000000000000000000000000000001) + + # TODO: Figure out which exception should be raised for timeout. + # The following assertion originally expected only a + # SSL.SSLTimeoutError exception, but what is raised is actually a + # socket.timeout exception. As a temporary circumvention to this + # issue, both exceptions are now tolerated. A final fix would need + # to figure out which of these two exceptions is supposed to be + # raised by SSL.Connection.connect() and possibly other methods + # to indicate a timeout. + with self.assertRaises((SSL.SSLTimeoutError, socket.timeout)): + s.connect(self.srv_addr) - from M2Crypto import m2urllib2 - opener = m2urllib2.build_opener(ctx, - m2urllib2.HTTPBasicAuthHandler()) + s.close() + finally: + self.stop_server(pid) - def test_urllib2_leak(self): + def test_makefile_timeout(self): + # httpslib uses makefile to read the response + pid = self.start_server(self.args) + try: + c = httpslib.HTTPSConnection(srv_host, self.srv_port) + c.putrequest('GET', '/') + c.putheader('Accept', 'text/html') + c.putheader('Accept', 'text/plain') + c.endheaders() + c.sock.settimeout(100) + resp = c.getresponse() + self.assertEqual(resp.status, 200, resp.reason) + data = resp.read() + c.close() + finally: + self.stop_server(pid) + self.assertIn(b's_server -quiet -www', data) + + def test_makefile_timeout_fires(self): + # This is convoluted because (openssl s_server -www) starts + # writing the response as soon as it receives the first line of + # the request, so it's possible for it to send the response + # before the request is sent and there would be no timeout. So, + # let the server spend time reading from an empty pipe + FIFO_NAME = 'test_makefile_timeout_fires_fifo' # noqa + os.mkfifo('tests/' + FIFO_NAME) + pipe_pid = os.fork() + try: + if pipe_pid == 0: + try: + with open('tests/' + FIFO_NAME, 'w') as f: + time.sleep(sleepTime + 1) + f.write('Content\n') + finally: + os._exit(0) + self.args[self.args.index('-www')] = '-WWW' pid = self.start_server(self.args) try: - import gc - from M2Crypto import m2urllib2 - o = m2urllib2.build_opener() - r = o.open('https://%s:%s/' % (srv_host, srv_port)) - s = [r.fp._sock.fp] - r.close() - self.assertEqual(len(gc.get_referrers(s[0])), 1) + c = httpslib.HTTPSConnection(srv_host, self.srv_port) + c.putrequest('GET', '/' + FIFO_NAME) + c.putheader('Accept', 'text/html') + c.putheader('Accept', 'text/plain') + c.endheaders() + c.sock.settimeout(0.0000000001) + with self.assertRaises(socket.timeout): + c.getresponse() + c.close() finally: self.stop_server(pid) - - -class TwistedSSLClientTestCase(BaseSSLClientTestCase): + finally: + os.kill(pipe_pid, signal.SIGTERM) + os.waitpid(pipe_pid, 0) + os.unlink('tests/' + FIFO_NAME) def test_twisted_wrapper(self): # Test only when twisted and ZopeInterfaces are present @@ -980,13 +1136,14 @@ class TwistedSSLClientTestCase(BaseSSLClientTestCase): from twisted.internet import reactor import M2Crypto.SSL.TwistedProtocolWrapper as wrapper except ImportError: - import warnings - warnings.warn('Skipping twisted wrapper test because twisted not found') + warnings.warn( + 'Skipping twisted wrapper test because twisted not found') return - + + # TODO Class must implement all abstract methods class EchoClient(LineReceiver): def connectionMade(self): - self.sendLine('GET / HTTP/1.0\n\n') + self.sendLine(b'GET / HTTP/1.0\n\n') def lineReceived(self, line): global twisted_data @@ -994,31 +1151,33 @@ class TwistedSSLClientTestCase(BaseSSLClientTestCase): class EchoClientFactory(ClientFactory): protocol = EchoClient - + def clientConnectionFailed(self, connector, reason): reactor.stop() - assert 0, reason - + self.fail(reason) + def clientConnectionLost(self, connector, reason): reactor.stop() - + pid = self.start_server(self.args) - class ContextFactory: + class ContextFactory(object): def getContext(self): return SSL.Context() try: global twisted_data - twisted_data = '' - - contextFactory = ContextFactory() + twisted_data = b'' + + context_factory = ContextFactory() factory = EchoClientFactory() - wrapper.connectSSL(srv_host, srv_port, factory, contextFactory) - reactor.run() # This will block until reactor.stop() is called + wrapper.connectSSL(srv_host, self.srv_port, factory, + context_factory) + # This will block until reactor.stop() is called + reactor.run() finally: self.stop_server(pid) - self.failIf(string.find(twisted_data, 's_server -quiet -www') == -1) + self.assertIn(b's_server -quiet -www', twisted_data) twisted_data = '' @@ -1026,29 +1185,28 @@ twisted_data = '' class XmlRpcLibTestCase(unittest.TestCase): def test_lib(self): - from M2Crypto import m2xmlrpclib m2xmlrpclib.SSL_Transport() # XXX need server to test against class FtpsLibTestCase(unittest.TestCase): def test_lib(self): - from M2Crypto import ftpslib ftpslib.FTP_TLS() # XXX need server to test against class SessionTestCase(unittest.TestCase): def test_session_load_bad(self): - self.assertRaises(SSL.SSLError, SSL.Session.load_session, - 'tests/signer.pem') + with self.assertRaises(SSL.SSLError): + SSL.Session.load_session('tests/signer.pem') + class FtpslibTestCase(unittest.TestCase): def test_26_compat(self): - from M2Crypto import ftpslib f = ftpslib.FTP_TLS() # 2.6 used to raise AttributeError: - self.assertRaises(socket.gaierror, f.connect, 'no-such-host-dfgHJK56789', 990) + with self.assertRaises((socket.gaierror, socket.error,)): + f.connect('no-such-host-dfgHJK56789', 990) def suite(): @@ -1058,51 +1216,52 @@ def suite(): suite.addTest(unittest.makeSuite(FtpsLibTestCase)) suite.addTest(unittest.makeSuite(PassSSLClientTestCase)) suite.addTest(unittest.makeSuite(HttpslibSSLClientTestCase)) + suite.addTest(unittest.makeSuite(HttpslibSSLSNIClientTestCase)) suite.addTest(unittest.makeSuite(UrllibSSLClientTestCase)) suite.addTest(unittest.makeSuite(Urllib2SSLClientTestCase)) + suite.addTest(unittest.makeSuite(Urllib2TEChunkedSSLClientTestCase)) suite.addTest(unittest.makeSuite(MiscSSLClientTestCase)) suite.addTest(unittest.makeSuite(FtpslibTestCase)) try: - import M2Crypto.SSL.TwistedProtocolWrapper as wrapper - suite.addTest(unittest.makeSuite(TwistedSSLClientTestCase)) + if py27plus: + import M2Crypto.SSL.TwistedProtocolWrapper as wrapper # noqa + suite.addTest(unittest.makeSuite(TwistedSSLClientTestCase)) except ImportError: pass - return suite - + return suite + def zap_servers(): s = 's_server' - fn = tempfile.mktemp() + fn = tempfile.mktemp() cmd = 'ps | egrep %s > %s' % (s, fn) os.system(cmd) - f = open(fn) - while 1: - ps = f.readline() - if not ps: - break - chunk = string.split(ps) - pid, cmd = chunk[0], chunk[4] - if cmd == s: - os.kill(int(pid), 1) - f.close() + with open(fn) as f: + while 1: + ps = f.readline() + if not ps: + break + chunk = ps.split() + pid, cmd = chunk[0], chunk[4] + if cmd == s: + os.kill(int(pid), signal.SIGTERM) os.unlink(fn) if __name__ == '__main__': report_leaks = 0 - + if report_leaks: - import gc gc.enable() gc.set_debug(gc.DEBUG_LEAK & ~gc.DEBUG_SAVEALL) - + try: - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') finally: zap_servers() if report_leaks: - import alltests + from tests import alltests alltests.dump_garbage() diff --git a/tests/test_ssl_offline.py b/tests/test_ssl_offline.py index ba77434..3ffc1f1 100644 --- a/tests/test_ssl_offline.py +++ b/tests/test_ssl_offline.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + """Unit tests for M2Crypto.SSL offline parts Copyright (C) 2006 Open Source Applications Foundation. All Rights Reserved. @@ -5,37 +7,45 @@ Copyright (C) 2006 Open Source Applications Foundation. All Rights Reserved. Copyright (C) 2009-2010 Heikki Toivonen. All Rights Reserved. """ -import unittest, doctest -from M2Crypto.SSL import Checker -from M2Crypto import X509 -from M2Crypto import SSL -from test_ssl import srv_host +import doctest + +from M2Crypto import Rand, SSL, X509 +from tests import unittest +from tests.test_ssl import srv_host class CheckerTestCase(unittest.TestCase): def test_checker(self): - check = Checker.Checker(host=srv_host, - peerCertHash='7B754EFA41A264AAD370D43460BC8229F9354ECE') + check = SSL.Checker.Checker( + host=srv_host, + peerCertHash='0305E329FF3C9F1931B8DD3F0CF9F8E350E29839') x509 = X509.load_cert('tests/server.pem') - assert check(x509, srv_host) - self.assertRaises(Checker.WrongHost, check, x509, 'example.com') - - doctest.testmod(Checker) + self.assertTrue(check(x509, srv_host)) + with self.assertRaises(SSL.Checker.WrongHost): + check(x509, 'example.com') + + doctest.testmod(SSL.Checker) + - class ContextTestCase(unittest.TestCase): def test_ctx_load_verify_locations(self): ctx = SSL.Context() - self.assertRaises(ValueError, ctx.load_verify_locations, None, None) - + with self.assertRaises(ValueError): + ctx.load_verify_locations(None, None) + + def test_ctx_set_default_verify_paths(self): + ctx = SSL.Context() + ctx.set_default_verify_paths() + # test will get here only if the previous won't fail + def test_map(self): - from M2Crypto.SSL.Context import map, _ctxmap - assert isinstance(map(), _ctxmap) + from M2Crypto.SSL.Context import ctxmap, _ctxmap + self.assertIsInstance(ctxmap(), _ctxmap) ctx = SSL.Context() - assert map() + assert ctxmap() ctx.close() - assert map() is _ctxmap.singleton + self.assertIs(ctxmap(), _ctxmap.singleton) def test_certstore(self): ctx = SSL.Context() @@ -44,14 +54,14 @@ class ContextTestCase(unittest.TestCase): ctx.load_cert('tests/x509.pem') store = ctx.get_cert_store() - assert isinstance(store, X509.X509_Store) + self.assertIsInstance(store, X509.X509_Store) def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(CheckerTestCase)) - suite.addTest(unittest.makeSuite(ContextTestCase)) - return suite + t_suite = unittest.TestSuite() + t_suite.addTest(unittest.makeSuite(CheckerTestCase)) + t_suite.addTest(unittest.makeSuite(ContextTestCase)) + return t_suite if __name__ == '__main__': diff --git a/tests/test_ssl_win.py b/tests/test_ssl_win.py index 0d13bd0..027c457 100644 --- a/tests/test_ssl_win.py +++ b/tests/test_ssl_win.py @@ -1,70 +1,73 @@ #!/usr/bin/env python +from __future__ import absolute_import -"""Unit tests for M2Crypto.SSL. +"""Unit tests for M2Crypto.SSL. -Win32 version - requires Mark Hammond's Win32 extensions and openssl.exe +Win32 version - requires Mark Hammond's Win32 extensions and openssl.exe on your PATH. Copyright (c) 2000-2001 Ng Pheng Siong. All rights reserved.""" -import os, os.path, string, time, unittest +import os +import os.path +import time + try: import win32process except ImportError: win32process = None +from tests import test_ssl, unittest + if win32process: - from M2Crypto import Rand, SSL - import test_ssl - + from M2Crypto import Rand + def find_openssl(): plist = os.environ['PATH'].split(';') for p in plist: try: - dir = os.listdir(p) - if 'openssl.exe' in dir: + path_dir = os.listdir(p) + if 'openssl.exe' in path_dir: return os.path.join(p, 'openssl.exe') - except WindowsError: + except win32process.WindowsError: pass return None - - + srv_host = 'localhost' srv_port = 64000 - - class SSLWinClientTestCase(test_ssl.SSLClientTestCase): - + + class SSLWinClientTestCase(test_ssl.BaseSSLClientTestCase): + startupinfo = win32process.STARTUPINFO() openssl = find_openssl() - + def start_server(self, args): # openssl must be started in the tests directory for it # to find the .pem files - os.chdir('tests') + os.chdir('tests') try: - hproc, hthread, pid, tid = win32process.CreateProcess(self.openssl, - string.join(args), None, None, 0, win32process.DETACHED_PROCESS, - None, None, self.startupinfo) + hproc, _, _, _ = win32process.CreateProcess( + self.openssl, ' '.join(args), None, None, 0, + win32process.DETACHED_PROCESS, None, None, + self.startupinfo) finally: - os.chdir('..') + os.chdir('..') time.sleep(0.3) return hproc - + def stop_server(self, hproc): win32process.TerminateProcess(hproc, 0) - - + def suite(): return unittest.makeSuite(SSLWinClientTestCase) - + def zap_servers(): pass - - + if __name__ == '__main__': try: if find_openssl() is not None: - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') finally: diff --git a/tests/test_threading.py b/tests/test_threading.py index 7912a61..ad1d111 100644 --- a/tests/test_threading.py +++ b/tests/test_threading.py @@ -4,9 +4,8 @@ Copyright (C) 2007 Open Source Applications Foundation. All Rights Reserved. """ - -import unittest from M2Crypto import threading as m2threading, Rand +from tests import unittest class ThreadingTestCase(unittest.TestCase): diff --git a/tests/test_timeout.py b/tests/test_timeout.py new file mode 100644 index 0000000..6d05449 --- /dev/null +++ b/tests/test_timeout.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python + +"""Unit tests for M2Crypto.SSL.timeout. +""" + +import sys +from M2Crypto.SSL import timeout, struct_to_timeout, struct_size +from tests import unittest + +# Max value for sec argument on Windows: +# - needs to fit DWORD (signed 32-bit) when converted to millisec +MAX_SEC_WIN32 = int((2**31 - 1) / 1000) + +# Max value for sec argument on other platforms: +# Note: It may actually be 64-bit but we are happy with 32-bit. +# We use the signed maximum, because the packing uses lower case "l". +MAX_SEC_OTHER = 2**31 - 1 + +# Enable this to test the Windows logic on a non-Windows platform: +# sys.platform = 'win32' + + +class TimeoutTestCase(unittest.TestCase): + + def timeout_test(self, sec, microsec, exp_sec=None, exp_microsec=None): + """ + Test that the timeout values (sec, microsec) are the same after + round tripping through a pack / unpack cycle. + """ + if exp_sec is None: + exp_sec = sec + if exp_microsec is None: + exp_microsec = microsec + + to = timeout(sec, microsec) + + binstr = to.pack() + + act_to = struct_to_timeout(binstr) + + self.assertEqual( + (act_to.sec, act_to.microsec), (exp_sec, exp_microsec), + "Unexpected timeout(sec,microsec) after pack + unpack: " + "Got (%r,%r), expected (%r,%r), input was (%r,%r)" % + (act_to.sec, act_to.microsec, exp_sec, exp_microsec, + sec, microsec)) + + def test_timeout_0_0(self): + self.timeout_test(0, 0) + + def test_timeout_123_0(self): + self.timeout_test(123, 0) + + def test_timeout_max_0(self): + if sys.platform == 'win32': + self.timeout_test(MAX_SEC_WIN32, 0) + else: + self.timeout_test(MAX_SEC_OTHER, 0) + + def test_timeout_0_456000(self): + self.timeout_test(0, 456000) + + def test_timeout_123_456000(self): + self.timeout_test(123, 456000) + + def test_timeout_2_3000000(self): + if sys.platform == 'win32': + self.timeout_test(2, 3000000, 5, 0) + else: + self.timeout_test(2, 3000000) + + def test_timeout_2_2499000(self): + if sys.platform == 'win32': + self.timeout_test(2, 2499000, 4, 499000) + else: + self.timeout_test(2, 2499000) + + def test_timeout_2_2999000(self): + if sys.platform == 'win32': + self.timeout_test(2, 2999000, 4, 999000) + else: + self.timeout_test(2, 2999000) + + def test_timeout_max_456000(self): + if sys.platform == 'win32': + self.timeout_test(MAX_SEC_WIN32, 456000) + else: + self.timeout_test(MAX_SEC_OTHER, 456000) + + def test_timeout_0_456(self): + if sys.platform == 'win32': + self.timeout_test(0, 456, None, 0) + else: + self.timeout_test(0, 456) + + def test_timeout_123_456(self): + if sys.platform == 'win32': + self.timeout_test(123, 456, None, 0) + else: + self.timeout_test(123, 456) + + def test_timeout_max_456(self): + if sys.platform == 'win32': + self.timeout_test(MAX_SEC_WIN32, 456, None, 0) + else: + self.timeout_test(MAX_SEC_OTHER, 456) + + def test_timeout_1_499(self): + if sys.platform == 'win32': + self.timeout_test(123, 499, None, 0) # 499 us rounds down to 0 + else: + self.timeout_test(123, 499) + + def test_timeout_1_501(self): + # We use 501 for this test and not 500 because 0.5 is not exactly + # represented in binary floating point numbers, and because 0.5 + # rounds differently between py2 and py3. See Python round() docs. + if sys.platform == 'win32': + self.timeout_test(123, 501, None, 1000) # 501 us rounds up to 1000 + else: + self.timeout_test(123, 501) + + def test_timeout_size(self): + exp_size = len(timeout(0, 0).pack()) + self.assertEqual(struct_size(), exp_size) + + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TimeoutTestCase)) + return suite + + +if __name__ == '__main__': + unittest.TextTestRunner().run(suite()) diff --git a/tests/test_util.py b/tests/test_util.py new file mode 100644 index 0000000..f4c758e --- /dev/null +++ b/tests/test_util.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +"""Unit tests for M2Crypto.Rand. + +Copyright (C) 2006 Open Source Applications Foundation (OSAF). +All Rights Reserved. +""" + +from M2Crypto import six +from tests import unittest + + +class UtilTestCase(unittest.TestCase): + def test_py3bytes(self): + self.assertIsInstance(six.ensure_binary('test'), six.binary_type) + + def test_py3str(self): + self.assertIsInstance(six.ensure_text('test'), six.text_type) + + def test_py3bytes_str(self): + self.assertIsInstance(six.ensure_binary(u'test'), six.binary_type) + + def test_py3str_str(self): + self.assertIsInstance(six.ensure_text(u'test'), six.string_types) + + def test_py3bytes_bytes(self): + self.assertIsInstance(six.ensure_binary(b'test'), six.binary_type) + + def test_py3str_bytes(self): + self.assertIsInstance(six.ensure_text(b'test'), six.text_type) + + def test_py3bytes_None(self): + with self.assertRaises(TypeError): + six.ensure_binary(None) + + def test_py3str_None(self): + with self.assertRaises(TypeError): + six.ensure_text(None) + + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(UtilTestCase)) + return suite + + +if __name__ == '__main__': + unittest.TextTestRunner().run(suite()) diff --git a/tests/test_x509.py b/tests/test_x509.py index 7ea86df..057d7da 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -9,143 +9,203 @@ Copyright (C) 2004-2005 OSAF. All Rights Reserved. Author: Heikki Toivonen """ -import unittest -import os, time, base64, sys -from M2Crypto import X509, EVP, RSA, Rand, ASN1, m2, util, BIO +import base64 +import logging +import os +import time +import warnings + +from M2Crypto import ASN1, BIO, EVP, RSA, Rand, X509, m2 # noqa +from tests import unittest + +log = logging.getLogger(__name__) + class X509TestCase(unittest.TestCase): def callback(self, *args): pass + def setUp(self): + self.expected_hash = 'BA4212E8B55527570828E7F5A0005D17C64BDC4C' + def mkreq(self, bits, ca=0): pk = EVP.PKey() x = X509.Request() rsa = RSA.gen_key(bits, 65537, self.callback) pk.assign_rsa(rsa) - rsa = None # should not be freed here + rsa = None # should not be freed here x.set_pubkey(pk) name = x.get_subject() name.C = "UK" name.CN = "OpenSSL Group" if not ca: - ext1 = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') + ext1 = X509.new_extension('subjectAltName', + 'DNS:foobar.example.com') ext2 = X509.new_extension('nsComment', 'Hello there') extstack = X509.X509_Extension_Stack() extstack.push(ext1) extstack.push(ext2) x.add_extensions(extstack) - self.assertRaises(ValueError, x.sign, pk, 'sha513') - x.sign(pk,'sha1') - assert x.verify(pk) + + with self.assertRaises(ValueError): + x.sign(pk, 'sha513') + + x.sign(pk, 'sha1') + self.assertTrue(x.verify(pk)) pk2 = x.get_pubkey() - assert x.verify(pk2) + self.assertTrue(x.verify(pk2)) return x, pk def test_ext(self): - self.assertRaises(ValueError, X509.new_extension, - 'subjectKeyIdentifier', 'hash') + with self.assertRaises(ValueError): + X509.new_extension('subjectKeyIdentifier', 'hash') + ext = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') - assert ext.get_value() == 'DNS:foobar.example.com' - assert ext.get_value(indent=2) == ' DNS:foobar.example.com' - assert ext.get_value(flag=m2.X509V3_EXT_PARSE_UNKNOWN) == 'DNS:foobar.example.com' + self.assertEqual(ext.get_value(), 'DNS:foobar.example.com') + self.assertEqual(ext.get_value(indent=2), + ' DNS:foobar.example.com') + self.assertEqual(ext.get_value(flag=m2.X509V3_EXT_PARSE_UNKNOWN), + 'DNS:foobar.example.com') + + def test_ext_error(self): + with self.assertRaises(X509.X509Error): + X509.new_extension('nonsensicalName', 'blabla') def test_extstack(self): # new ext1 = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') ext2 = X509.new_extension('nsComment', 'Hello there') extstack = X509.X509_Extension_Stack() - + # push extstack.push(ext1) extstack.push(ext2) - assert(extstack[1].get_name() == 'nsComment') - assert len(extstack) == 2 - + self.assertEqual(extstack[1].get_name(), 'nsComment') + self.assertEqual(len(extstack), 2) + # iterator i = 0 for e in extstack: i += 1 - assert len(e.get_name()) > 0 - assert i == 2 - + self.assertGreater(len(e.get_name()), 0) + self.assertEqual(i, 2) + # pop ext3 = extstack.pop() - assert len(extstack) == 1 - assert(extstack[0].get_name() == 'subjectAltName') + self.assertEqual(len(extstack), 1) + self.assertEqual(extstack[0].get_name(), 'subjectAltName') extstack.push(ext3) - assert len(extstack) == 2 - assert(extstack[1].get_name() == 'nsComment') - - assert extstack.pop() is not None - assert extstack.pop() is not None - assert extstack.pop() is None + self.assertEqual(len(extstack), 2) + self.assertEqual(extstack[1].get_name(), 'nsComment') + + self.assertIsNotNone(extstack.pop()) + self.assertIsNotNone(extstack.pop()) + self.assertIsNone(extstack.pop()) def test_x509_name(self): n = X509.X509_Name() - n.C = 'US' # It seems this actually needs to be a real 2 letter country code - assert n.C == 'US' + # It seems this actually needs to be a real 2 letter country code + n.C = 'US' + self.assertEqual(n.C, 'US') n.SP = 'State or Province' - assert n.SP == 'State or Province' + self.assertEqual(n.SP, 'State or Province') n.L = 'locality name' - assert n.L == 'locality name' + self.assertEqual(n.L, 'locality name') + # Yes, 'orhanization' is a typo, I know it and you're smart. + # However, fixing this typo would break later hashes. + # I don't think it is worthy of troubles. n.O = 'orhanization name' - assert n.O == 'orhanization name' + self.assertEqual(n.O, 'orhanization name') n.OU = 'org unit' - assert n.OU == 'org unit' + self.assertEqual(n.OU, 'org unit') n.CN = 'common name' - assert n.CN == 'common name' + self.assertEqual(n.CN, 'common name') n.Email = 'bob@example.com' - assert n.Email == 'bob@example.com' + self.assertEqual(n.Email, 'bob@example.com') n.serialNumber = '1234' - assert n.serialNumber == '1234' + self.assertEqual(n.serialNumber, '1234') n.SN = 'surname' - assert n.SN == 'surname' + self.assertEqual(n.SN, 'surname') n.GN = 'given name' - assert n.GN == 'given name' - assert n.as_text() == 'C=US, ST=State or Province, L=locality name, O=orhanization name, OU=org unit, CN=common name/emailAddress=bob@example.com/serialNumber=1234, SN=surname, GN=given name', '"%s"' % n.as_text() - assert len(n) == 10, len(n) + self.assertEqual(n.GN, 'given name') + self.assertEqual(n.as_text(), + 'C=US, ST=State or Province, ' + + 'L=locality name, O=orhanization name, ' + + 'OU=org unit, CN=common ' + + 'name/emailAddress=bob@example.com' + + '/serialNumber=1234, ' + + 'SN=surname, GN=given name') + self.assertEqual(len(n), 10, + 'X509_Name has inappropriate length %d ' % len(n)) n.givenName = 'name given' - assert n.GN == 'given name' # Just gets the first - assert n.as_text() == 'C=US, ST=State or Province, L=locality name, O=orhanization name, OU=org unit, CN=common name/emailAddress=bob@example.com/serialNumber=1234, SN=surname, GN=given name, GN=name given', '"%s"' % n.as_text() - assert len(n) == 11, len(n) + self.assertEqual(n.GN, 'given name') # Just gets the first + self.assertEqual(n.as_text(), 'C=US, ST=State or Province, ' + + 'L=locality name, O=orhanization name, ' + + 'OU=org unit, ' + + 'CN=common name/emailAddress=bob@example.com' + + '/serialNumber=1234, ' + + 'SN=surname, GN=given name, GN=name given') + self.assertEqual(len(n), 11, + 'After adding one more attribute X509_Name should ' + + 'have 11 and not %d attributes.' % len(n)) n.add_entry_by_txt(field="CN", type=ASN1.MBSTRING_ASC, entry="Proxy", len=-1, loc=-1, set=0) - assert len(n) == 12, len(n) - assert n.entry_count() == 12, n.entry_count() - assert n.as_text() == 'C=US, ST=State or Province, L=locality name, O=orhanization name, OU=org unit, CN=common name/emailAddress=bob@example.com/serialNumber=1234, SN=surname, GN=given name, GN=name given, CN=Proxy', '"%s"' % n.as_text() - - self.assertRaises(AttributeError, n.__getattr__, 'foobar') + self.assertEqual(len(n), 12, + 'After adding one more attribute X509_Name should ' + + 'have 12 and not %d attributes.' % len(n)) + self.assertEqual(n.entry_count(), 12, n.entry_count()) + self.assertEqual(n.as_text(), 'C=US, ST=State or Province, ' + + 'L=locality name, O=orhanization name, ' + + 'OU=org unit, ' + + 'CN=common name/emailAddress=bob@example.com' + + '/serialNumber=1234, ' + + 'SN=surname, GN=given name, GN=name given, ' + + 'CN=Proxy') + + with self.assertRaises(AttributeError): + n.__getattr__('foobar') n.foobar = 1 - assert n.foobar == 1, n.foobar - + self.assertEqual(n.foobar, 1) + # X509_Name_Entry tests l = 0 for entry in n: - assert isinstance(entry, X509.X509_Name_Entry), entry - assert isinstance(entry.get_object(), ASN1.ASN1_Object), entry - assert isinstance(entry.get_data(), ASN1.ASN1_String), entry + self.assertIsInstance(entry, X509.X509_Name_Entry) + self.assertIsInstance(entry.get_object(), ASN1.ASN1_Object) + self.assertIsInstance(entry.get_data(), ASN1.ASN1_String) l += 1 - assert l == 12, l - + self.assertEqual(l, 12, l) + l = 0 for cn in n.get_entries_by_nid(m2.NID_commonName): - assert isinstance(cn, X509.X509_Name_Entry), cn - assert isinstance(cn.get_object(), ASN1.ASN1_Object), cn + self.assertIsInstance(cn, X509.X509_Name_Entry) + self.assertIsInstance(cn.get_object(), ASN1.ASN1_Object) data = cn.get_data() - assert isinstance(data, ASN1.ASN1_String), data + self.assertIsInstance(data, ASN1.ASN1_String) t = data.as_text() - assert t == "common name" or t == "Proxy", t + self.assertIn(t, ("common name", "Proxy",)) l += 1 - assert l == 2, l + self.assertEqual(l, 2, + 'X509_Name has %d commonName entries instead ' + 'of expected 2' % l) + + # The target list is not deleted when the loop is finished + # https://docs.python.org/2.7/reference\ + # /compound_stmts.html#the-for-statement + # so this checks what are the attributes of the last value of + # ``cn`` variable. + cn.set_data(b"Hello There!") + self.assertEqual(cn.get_data().as_text(), "Hello There!") + + # OpenSSL 1.0.1h switched from encoding strings as PRINTABLESTRING (the + # first hash value) to UTF8STRING (the second one) + self.assertIn(n.as_hash(), (1697185131, 1370641112), + 'Unexpected value of the X509_Name hash %s' % + n.as_hash()) - cn.set_data("Hello There!") - assert cn.get_data().as_text() == "Hello There!", cn.get_data().as_text() - - assert n.as_hash() == 1697185131 - self.assertRaises(IndexError, lambda: n[100]) - self.assert_(n[10]) + self.assertIsNotNone(n[10]) def test_mkreq(self): (req, _) = self.mkreq(1024) @@ -157,78 +217,97 @@ class X509TestCase(unittest.TestCase): os.remove('tests/tmp_request.pem') req.save('tests/tmp_request.der', format=X509.FORMAT_DER) req4 = X509.load_request('tests/tmp_request.der', - format=X509.FORMAT_DER) + format=X509.FORMAT_DER) os.remove('tests/tmp_request.der') - assert req.as_pem() == req2.as_pem() - assert req.as_text() == req2.as_text() - assert req.as_der() == req2.as_der() - assert req.as_pem() == req3.as_pem() - assert req.as_text() == req3.as_text() - assert req.as_der() == req3.as_der() - assert req.as_pem() == req4.as_pem() - assert req.as_text() == req4.as_text() - assert req.as_der() == req4.as_der() + self.assertEqual(req.as_pem(), req2.as_pem()) + self.assertEqual(req.as_text(), req2.as_text()) + self.assertEqual(req.as_der(), req2.as_der()) + self.assertEqual(req.as_pem(), req3.as_pem()) + self.assertEqual(req.as_text(), req3.as_text()) + self.assertEqual(req.as_der(), req3.as_der()) + self.assertEqual(req.as_pem(), req4.as_pem()) + self.assertEqual(req.as_text(), req4.as_text()) + self.assertEqual(req.as_der(), req4.as_der()) self.assertEqual(req.get_version(), 0) req.set_version(1) self.assertEqual(req.get_version(), 1) req.set_version(0) self.assertEqual(req.get_version(), 0) - def test_mkcert(self): - req, pk = self.mkreq(1024) - pkey = req.get_pubkey() - assert(req.verify(pkey)) - sub = req.get_subject() - assert len(sub) == 2, len(sub) - cert = X509.X509() - cert.set_serial_number(1) - cert.set_version(2) - cert.set_subject(sub) - t = long(time.time()) + time.timezone - now = ASN1.ASN1_UTCTIME() - now.set_time(t) - nowPlusYear = ASN1.ASN1_UTCTIME() - nowPlusYear.set_time(t + 60 * 60 * 24 * 365) - cert.set_not_before(now) - cert.set_not_after(nowPlusYear) - assert str(cert.get_not_before()) == str(now) - assert str(cert.get_not_after()) == str(nowPlusYear) - issuer = X509.X509_Name() - issuer.CN = 'The Issuer Monkey' - issuer.O = 'The Organization Otherwise Known as My CA, Inc.' - cert.set_issuer(issuer) - cert.set_pubkey(pkey) - cert.set_pubkey(cert.get_pubkey()) # Make sure get/set work - ext = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') - ext.set_critical(0) - assert ext.get_critical() == 0 - cert.add_ext(ext) - cert.sign(pk, 'sha1') - self.assertRaises(ValueError, cert.sign, pk, 'nosuchalgo') - assert(cert.get_ext('subjectAltName').get_name() == 'subjectAltName') - assert(cert.get_ext_at(0).get_name() == 'subjectAltName') - assert(cert.get_ext_at(0).get_value() == 'DNS:foobar.example.com') - assert cert.get_ext_count() == 1, cert.get_ext_count() - self.assertRaises(IndexError, cert.get_ext_at, 1) - assert cert.verify() - assert cert.verify(pkey) - assert cert.verify(cert.get_pubkey()) - assert cert.get_version() == 2 - assert cert.get_serial_number() == 1 - assert cert.get_issuer().CN == 'The Issuer Monkey' - - if m2.OPENSSL_VERSION_NUMBER >= 0x90800f: - assert not cert.check_ca() - assert not cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 1) - assert not cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 1) - assert cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 0) - assert cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 0) - assert cert.check_purpose(m2.X509_PURPOSE_ANY, 0) - else: - self.assertRaises(AttributeError, cert.check_ca) - - def mkcacert(self): + for utc in (True, False): + req, pk = self.mkreq(1024) + pkey = req.get_pubkey() + self.assertTrue(req.verify(pkey)) + sub = req.get_subject() + self.assertEqual(len(sub), 2, + 'Subject should be long 2 items not %d' % len(sub)) + + cert = X509.X509() + cert.set_serial_number(1) + cert.set_version(2) + cert.set_subject(sub) + t = int(time.time()) + time.timezone + if utc: + now = ASN1.ASN1_UTCTIME() + else: + now = ASN1.ASN1_TIME() + now.set_time(t) + now_plus_year = ASN1.ASN1_TIME() + now_plus_year.set_time(t + 60 * 60 * 24 * 365) + cert.set_not_before(now) + cert.set_not_after(now_plus_year) + self.assertEqual(str(cert.get_not_before()), str(now)) + self.assertEqual(str(cert.get_not_after()), str(now_plus_year)) + + issuer = X509.X509_Name() + issuer.CN = 'The Issuer Monkey' + issuer.O = 'The Organization Otherwise Known as My CA, Inc.' + cert.set_issuer(issuer) + cert.set_pubkey(pkey) + cert.set_pubkey(cert.get_pubkey()) # Make sure get/set work + + ext = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') + ext.set_critical(0) + self.assertEqual(ext.get_critical(), 0) + cert.add_ext(ext) + + cert.sign(pk, 'sha1') + with self.assertRaises(ValueError): + cert.sign(pk, 'nosuchalgo') + + self.assertTrue(cert.get_ext('subjectAltName').get_name(), + 'subjectAltName') + self.assertTrue(cert.get_ext_at(0).get_name(), + 'subjectAltName') + self.assertTrue(cert.get_ext_at(0).get_value(), + 'DNS:foobar.example.com') + self.assertEqual(cert.get_ext_count(), 1, + 'Certificate should have now 1 extension not %d' % + cert.get_ext_count()) + with self.assertRaises(IndexError): + cert.get_ext_at(1) + self.assertTrue(cert.verify()) + self.assertTrue(cert.verify(pkey)) + self.assertTrue(cert.verify(cert.get_pubkey())) + self.assertEqual(cert.get_version(), 2) + self.assertEqual(cert.get_serial_number(), 1) + self.assertEqual(cert.get_issuer().CN, 'The Issuer Monkey') + + if m2.OPENSSL_VERSION_NUMBER >= 0x90800f: + self.assertFalse(cert.check_ca()) + self.assertFalse(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 1)) + self.assertFalse(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, + 1)) + self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 0)) + self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, + 0)) + self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_ANY, 0)) + else: + with self.assertRaises(AttributeError): + cert.check_ca() + + def mkcacert(self, utc): req, pk = self.mkreq(1024, ca=1) pkey = req.get_pubkey() sub = req.get_subject() @@ -236,87 +315,111 @@ class X509TestCase(unittest.TestCase): cert.set_serial_number(1) cert.set_version(2) cert.set_subject(sub) - t = long(time.time()) + time.timezone - now = ASN1.ASN1_UTCTIME() + t = int(time.time()) + time.timezone + if utc: + now = ASN1.ASN1_UTCTIME() + else: + now = ASN1.ASN1_TIME() now.set_time(t) - nowPlusYear = ASN1.ASN1_UTCTIME() - nowPlusYear.set_time(t + 60 * 60 * 24 * 365) + now_plus_year = ASN1.ASN1_TIME() + now_plus_year.set_time(t + 60 * 60 * 24 * 365) cert.set_not_before(now) - cert.set_not_after(nowPlusYear) + cert.set_not_after(now_plus_year) issuer = X509.X509_Name() issuer.C = "UK" issuer.CN = "OpenSSL Group" cert.set_issuer(issuer) - cert.set_pubkey(pkey) + cert.set_pubkey(pkey) ext = X509.new_extension('basicConstraints', 'CA:TRUE') cert.add_ext(ext) cert.sign(pk, 'sha1') - if m2.OPENSSL_VERSION_NUMBER >= 0x0090800fL: - assert cert.check_ca() - assert cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 1) - assert cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 1) - assert cert.check_purpose(m2.X509_PURPOSE_ANY, 1) - assert cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 0) - assert cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 0) - assert cert.check_purpose(m2.X509_PURPOSE_ANY, 0) + if m2.OPENSSL_VERSION_NUMBER >= 0x0090800f: + self.assertTrue(cert.check_ca()) + self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, + 1)) + self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, + 1)) + self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_ANY, 1)) + self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, + 0)) + self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, + 0)) + self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_ANY, 0)) else: - self.assertRaises(AttributeError, cert.check_ca) - + with self.assertRaises(AttributeError): + cert.check_ca() + return cert, pk, pkey - def test_mkcacert(self): - cacert, pk, pkey = self.mkcacert() - assert cacert.verify(pkey) - - - def test_mkproxycert(self): - cacert, pk1, pkey = self.mkcacert() - end_entity_cert_req, pk2 = self.mkreq(1024) - end_entity_cert = self.make_eecert(cacert) - end_entity_cert.set_subject(end_entity_cert_req.get_subject()) - end_entity_cert.set_pubkey(end_entity_cert_req.get_pubkey()) - end_entity_cert.sign(pk1, 'sha1') - proxycert = self.make_proxycert(end_entity_cert) - proxycert.sign(pk2, 'sha1') - assert proxycert.verify(pk2) - assert proxycert.get_ext_at(0).get_name() == 'proxyCertInfo', proxycert.get_ext_at(0).get_name() - assert proxycert.get_ext_at(0).get_value() == 'Path Length Constraint: infinite\nPolicy Language: Inherit all\n', '"%s"' % proxycert.get_ext_at(0).get_value() - assert proxycert.get_ext_count() == 1, proxycert.get_ext_count() - assert proxycert.get_subject().as_text() == 'C=UK, CN=OpenSSL Group, CN=Proxy', proxycert.get_subject().as_text() - assert proxycert.get_subject().as_text(indent=2, flags=m2.XN_FLAG_RFC2253) == ' CN=Proxy,CN=OpenSSL Group,C=UK', '"%s"' % proxycert.get_subject().as_text(indent=2, flags=m2.XN_FLAG_RFC2253) - - def make_eecert(self, cacert): + def test_mkcacert(self): + for utc in (True, False): + cacert, _, pkey = self.mkcacert(utc) + self.assertTrue(cacert.verify(pkey)) + + def test_mkproxycert(self): + for utc in (True, False): + cacert, pk1, _ = self.mkcacert(utc) + end_entity_cert_req, pk2 = self.mkreq(1024) + end_entity_cert = self.make_eecert(cacert, utc) + end_entity_cert.set_subject(end_entity_cert_req.get_subject()) + end_entity_cert.set_pubkey(end_entity_cert_req.get_pubkey()) + end_entity_cert.sign(pk1, 'sha1') + proxycert = self.make_proxycert(end_entity_cert, utc) + proxycert.sign(pk2, 'sha1') + self.assertTrue(proxycert.verify(pk2)) + self.assertEqual(proxycert.get_ext_at(0).get_name(), + 'proxyCertInfo') + self.assertEqual(proxycert.get_ext_at(0).get_value(), + 'Path Length Constraint: infinite\n' + + 'Policy Language: Inherit all\n') + self.assertEqual(proxycert.get_ext_count(), 1, + proxycert.get_ext_count()) + self.assertEqual(proxycert.get_subject().as_text(), + 'C=UK, CN=OpenSSL Group, CN=Proxy') + self.assertEqual( + proxycert.get_subject().as_text(indent=2, + flags=m2.XN_FLAG_RFC2253), + ' CN=Proxy,CN=OpenSSL Group,C=UK') + + @staticmethod + def make_eecert(cacert, utc): eecert = X509.X509() eecert.set_serial_number(2) eecert.set_version(2) - t = long(time.time()) + time.timezone - now = ASN1.ASN1_UTCTIME() + t = int(time.time()) + time.timezone + if utc: + now = ASN1.ASN1_UTCTIME() + else: + now = ASN1.ASN1_TIME() now.set_time(t) - now_plus_year = ASN1.ASN1_UTCTIME() + now_plus_year = ASN1.ASN1_TIME() now_plus_year.set_time(t + 60 * 60 * 24 * 365) eecert.set_not_before(now) eecert.set_not_after(now_plus_year) eecert.set_issuer(cacert.get_subject()) return eecert - - def make_proxycert(self, eecert): + + def make_proxycert(self, eecert, utc): proxycert = X509.X509() pk2 = EVP.PKey() - proxykey = RSA.gen_key(1024, 65537, self.callback) + proxykey = RSA.gen_key(1024, 65537, self.callback) pk2.assign_rsa(proxykey) proxycert.set_pubkey(pk2) proxycert.set_version(2) - not_before = ASN1.ASN1_UTCTIME() - not_after = ASN1.ASN1_UTCTIME() + if utc: + not_before = ASN1.ASN1_UTCTIME() + not_after = ASN1.ASN1_UTCTIME() + else: + not_before = ASN1.ASN1_TIME() + not_after = ASN1.ASN1_TIME() not_before.set_time(int(time.time())) offset = 12 * 3600 - not_after.set_time(int(time.time()) + offset ) + not_after.set_time(int(time.time()) + offset) proxycert.set_not_before(not_before) proxycert.set_not_after(not_after) proxycert.set_issuer_name(eecert.get_subject()) proxycert.set_serial_number(12345678) - proxy_subject_name = X509.X509_Name() issuer_name_string = eecert.get_subject().as_text() seq = issuer_name_string.split(",") @@ -330,153 +433,197 @@ class X509TestCase(unittest.TestCase): subject_name.add_entry_by_txt(field="CN", type=ASN1.MBSTRING_ASC, entry="Proxy", len=-1, loc=-1, set=0) - proxycert.set_subject_name(subject_name) - pci_ext = X509.new_extension("proxyCertInfo", - "critical,language:Inherit all", 1) # XXX leaks 8 bytes + # XXX leaks 8 bytes + pci_ext = X509.new_extension("proxyCertInfo", + "critical,language:Inherit all", 1) proxycert.add_ext(pci_ext) return proxycert - + def test_fingerprint(self): x509 = X509.load_cert('tests/x509.pem') fp = x509.get_fingerprint('sha1') - expected = '8D2EB9E203B5FFDC7F4FA7DC4103E852A55B808D' - assert fp == expected, '%s != %s' % (fp, expected) + self.assertEqual(fp, self.expected_hash) def test_load_der_string(self): - f = open('tests/x509.der', 'rb') - x509 = X509.load_cert_der_string(''.join(f.readlines())) + with open('tests/x509.der', 'rb') as f: + x509 = X509.load_cert_der_string(f.read()) + fp = x509.get_fingerprint('sha1') - expected = '8D2EB9E203B5FFDC7F4FA7DC4103E852A55B808D' - assert fp == expected, '%s != %s' % (fp, expected) + self.assertEqual(fp, self.expected_hash) def test_save_der_string(self): x509 = X509.load_cert('tests/x509.pem') s = x509.as_der() - f = open('tests/x509.der', 'rb') - s2 = f.read() - f.close() - assert s == s2 + with open('tests/x509.der', 'rb') as f: + s2 = f.read() + + self.assertEqual(s, s2) def test_load(self): x509 = X509.load_cert('tests/x509.pem') x5092 = X509.load_cert('tests/x509.der', format=X509.FORMAT_DER) - assert x509.as_text() == x5092.as_text() - assert x509.as_pem() == x5092.as_pem() - assert x509.as_der() == x5092.as_der() + self.assertEqual(x509.as_text(), x5092.as_text()) + self.assertEqual(x509.as_pem(), x5092.as_pem()) + self.assertEqual(x509.as_der(), x5092.as_der()) return - + def test_load_bio(self): - bio = BIO.openfile('tests/x509.pem') - bio2 = BIO.openfile('tests/x509.der') - x509 = X509.load_cert_bio(bio) - x5092 = X509.load_cert_bio(bio2, format=X509.FORMAT_DER) - - self.assertRaises(ValueError, X509.load_cert_bio, bio2, format=45678) - - assert x509.as_text() == x5092.as_text() - assert x509.as_pem() == x5092.as_pem() - assert x509.as_der() == x5092.as_der() - return + with BIO.openfile('tests/x509.pem') as bio: + with BIO.openfile('tests/x509.der') as bio2: + x509 = X509.load_cert_bio(bio) + x5092 = X509.load_cert_bio(bio2, format=X509.FORMAT_DER) + + with self.assertRaises(ValueError): + X509.load_cert_bio(bio2, format=45678) + + self.assertEqual(x509.as_text(), x5092.as_text()) + self.assertEqual(x509.as_pem(), x5092.as_pem()) + self.assertEqual(x509.as_der(), x5092.as_der()) def test_load_string(self): - f = open('tests/x509.pem') - s = f.read() - f.close() - f2 = open('tests/x509.der', 'rb') - s2 = f2.read() - f2.close() + with open('tests/x509.pem') as f: + s = f.read() + + with open('tests/x509.der', 'rb') as f2: + s2 = f2.read() + x509 = X509.load_cert_string(s) x5092 = X509.load_cert_string(s2, X509.FORMAT_DER) - assert x509.as_text() == x5092.as_text() - assert x509.as_pem() == x5092.as_pem() - assert x509.as_der() == x5092.as_der() - return - + self.assertEqual(x509.as_text(), x5092.as_text()) + self.assertEqual(x509.as_pem(), x5092.as_pem()) + self.assertEqual(x509.as_der(), x5092.as_der()) + def test_load_request_bio(self): - (req, _) = self.mkreq(512) + (req, _) = self.mkreq(1024) r1 = X509.load_request_der_string(req.as_der()) r2 = X509.load_request_string(req.as_der(), X509.FORMAT_DER) r3 = X509.load_request_string(req.as_pem(), X509.FORMAT_PEM) - r4 = X509.load_request_bio(BIO.MemoryBuffer(req.as_der()), X509.FORMAT_DER) - r5 = X509.load_request_bio(BIO.MemoryBuffer(req.as_pem()), X509.FORMAT_PEM) + r4 = X509.load_request_bio(BIO.MemoryBuffer(req.as_der()), + X509.FORMAT_DER) + r5 = X509.load_request_bio(BIO.MemoryBuffer(req.as_pem()), + X509.FORMAT_PEM) for r in [r1, r2, r3, r4, r5]: - assert req.as_der() == r.as_der() + self.assertEqual(req.as_der(), r.as_der()) - self.assertRaises(ValueError, X509.load_request_bio, BIO.MemoryBuffer(req.as_pem()), 345678) + with self.assertRaises(ValueError): + X509.load_request_bio(BIO.MemoryBuffer(req.as_pem()), 345678) def test_save(self): x509 = X509.load_cert('tests/x509.pem') - f = open('tests/x509.pem', 'r') - lTmp = f.readlines() - x509_pem = ''.join(lTmp[44:60]) # -----BEGIN CERTIFICATE----- : -----END CERTIFICATE----- - f.close() - f = open('tests/x509.der', 'rb') - x509_der = f.read() - f.close() + with open('tests/x509.pem', 'r') as f: + l_tmp = f.readlines() + # -----BEGIN CERTIFICATE----- : -----END CERTIFICATE----- + beg_idx = l_tmp.index('-----BEGIN CERTIFICATE-----\n') + end_idx = l_tmp.index('-----END CERTIFICATE-----\n') + x509_pem = ''.join(l_tmp[beg_idx:end_idx + 1]) + + with open('tests/x509.der', 'rb') as f: + x509_der = f.read() + x509.save('tests/tmpcert.pem') - f = open('tests/tmpcert.pem') - s = f.read() - f.close() - self.assertEquals(s, x509_pem) + with open('tests/tmpcert.pem') as f: + s = f.read() + + self.assertEqual(s, x509_pem) os.remove('tests/tmpcert.pem') x509.save('tests/tmpcert.der', format=X509.FORMAT_DER) - f = open('tests/tmpcert.der', 'rb') - s = f.read() - f.close() - self.assertEquals(s, x509_der) + with open('tests/tmpcert.der', 'rb') as f: + s = f.read() + + self.assertEqual(s, x509_der) os.remove('tests/tmpcert.der') def test_malformed_data(self): - self.assertRaises(X509.X509Error, X509.load_cert_string, 'Hello') - self.assertRaises(X509.X509Error, X509.load_cert_der_string, 'Hello') - self.assertRaises(X509.X509Error, X509.new_stack_from_der, 'Hello') - self.assertRaises(X509.X509Error, X509.load_cert, 'tests/alltests.py') - self.assertRaises(X509.X509Error, X509.load_request, 'tests/alltests.py') - self.assertRaises(X509.X509Error, X509.load_request_string, 'Hello') - self.assertRaises(X509.X509Error, X509.load_request_der_string, 'Hello') - self.assertRaises(X509.X509Error, X509.load_crl, 'tests/alltests.py') - + try: + with self.assertRaises(X509.X509Error): + X509.load_cert_string('Hello') + with self.assertRaises(X509.X509Error): + X509.load_cert_der_string('Hello') + with self.assertRaises(X509.X509Error): + X509.new_stack_from_der(b'Hello') + with self.assertRaises(X509.X509Error): + X509.load_cert('tests/alltests.py') + with self.assertRaises(X509.X509Error): + X509.load_request('tests/alltests.py') + with self.assertRaises(X509.X509Error): + X509.load_request_string('Hello') + with self.assertRaises(X509.X509Error): + X509.load_request_der_string('Hello') + with self.assertRaises(X509.X509Error): + X509.load_crl('tests/alltests.py') + except SystemError: + pass + def test_long_serial(self): - from M2Crypto import X509 cert = X509.load_cert('tests/long_serial_cert.pem') - self.assertEquals(cert.get_serial_number(), 17616841808974579194) + self.assertEqual(cert.get_serial_number(), 17616841808974579194) cert = X509.load_cert('tests/thawte.pem') - self.assertEquals(cert.get_serial_number(), 127614157056681299805556476275995414779) + self.assertEqual(cert.get_serial_number(), + 127614157056681299805556476275995414779) + + def test_set_long_serial(self): + cert = X509.X509() + cert.set_serial_number(127614157056681299805556476275995414779) + self.assertEqual(cert.get_serial_number(), + 127614157056681299805556476275995414779) + + def test_date_after_2050_working(self): + cert = X509.load_cert('tests/bad_date_cert.crt') + self.assertEqual(str(cert.get_not_after()), 'Feb 9 14:57:46 2116 GMT') + + def test_easy_rsa_generated(self): + """ Test loading a cert generated by easy RSA. + https://github.com/fedora-infra/fedmsg/pull/389 + """ + # Does this raise an exception? + X509.load_cert('tests/easy_rsa.pem') -class X509_StackTestCase(unittest.TestCase): - + +class X509StackTestCase(unittest.TestCase): def test_make_stack_from_der(self): - f = open("tests/der_encoded_seq.b64") - b64 = f.read(1304) - seq = base64.decodestring(b64) + with open("tests/der_encoded_seq.b64", 'rb') as f: + b64 = f.read() + + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + seq = base64.decodestring(b64) + stack = X509.new_stack_from_der(seq) cert = stack.pop() - assert stack.pop() is None - + self.assertIsNone(stack.pop()) + cert.foobar = 1 - assert cert.foobar == 1 - - subject = cert.get_subject() - assert str(subject) == "/DC=org/DC=doegrids/OU=Services/CN=host/bosshog.lbl.gov" + self.assertEqual(cert.foobar, 1) + + subject = cert.get_subject() + self.assertEqual( + str(subject), + "/DC=org/DC=doegrids/OU=Services/CN=host/bosshog.lbl.gov") def test_make_stack_check_num(self): - f = open("tests/der_encoded_seq.b64") - b64 = f.read(1304) - seq = base64.decodestring(b64) + with open("tests/der_encoded_seq.b64", 'rb') as f: + b64 = f.read() + + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + seq = base64.decodestring(b64) + stack = X509.new_stack_from_der(seq) num = len(stack) - assert num == 1 - cert = stack.pop() + self.assertEqual(num, 1) + cert = stack.pop() num = len(stack) - assert num == 0 - subject = cert.get_subject() - assert str(subject) == "/DC=org/DC=doegrids/OU=Services/CN=host/bosshog.lbl.gov" + self.assertEqual(num, 0) + subject = cert.get_subject() + self.assertEqual( + str(subject), + "/DC=org/DC=doegrids/OU=Services/CN=host/bosshog.lbl.gov") def test_make_stack(self): stack = X509.X509_Stack() @@ -486,21 +633,21 @@ class X509_StackTestCase(unittest.TestCase): issuer_subject1 = issuer.get_subject() stack.push(cert) stack.push(issuer) - + # Test stack iterator i = 0 for c in stack: i += 1 - assert len(c.get_subject().CN) > 0 - assert i == 2 - - issuer_pop = stack.pop() - cert_pop = stack.pop() - cert_subject2 = cert_pop.get_subject() + self.assertGreater(len(c.get_subject().CN), 0) + self.assertEqual(i, 2) + + stack.pop() + cert_pop = stack.pop() + cert_subject2 = cert_pop.get_subject() issuer_subject2 = issuer.get_subject() - assert str(cert_subject1) == str(cert_subject2) - assert str(issuer_subject1) == str(issuer_subject2) - + self.assertEqual(str(cert_subject1), str(cert_subject2)) + self.assertEqual(str(issuer_subject1), str(issuer_subject2)) + def test_as_der(self): stack = X509.X509_Stack() cert = X509.load_cert("tests/x509.pem") @@ -509,20 +656,19 @@ class X509_StackTestCase(unittest.TestCase): issuer_subject1 = issuer.get_subject() stack.push(cert) stack.push(issuer) - der_seq = stack.as_der() + der_seq = stack.as_der() stack2 = X509.new_stack_from_der(der_seq) - issuer_pop = stack2.pop() - cert_pop = stack2.pop() - cert_subject2 = cert_pop.get_subject() + stack2.pop() + cert_pop = stack2.pop() + cert_subject2 = cert_pop.get_subject() issuer_subject2 = issuer.get_subject() - assert str(cert_subject1) == str(cert_subject2) - assert str(issuer_subject1) == str(issuer_subject2) - + self.assertEqual(str(cert_subject1), str(cert_subject2)) + self.assertEqual(str(issuer_subject1), str(issuer_subject2)) + -class X509_ExtTestCase(unittest.TestCase): - +class X509ExtTestCase(unittest.TestCase): def test_ext(self): - if 0: # XXX + if 0: # XXX # With this leaks 8 bytes: name = "proxyCertInfo" value = "critical,language:Inherit all" @@ -530,11 +676,10 @@ class X509_ExtTestCase(unittest.TestCase): # With this there are no leaks: name = "nsComment" value = "Hello" - - lhash = m2.x509v3_lhash() - ctx = m2.x509v3_set_conf_lhash(lhash) - x509_ext_ptr = m2.x509v3_ext_conf(lhash, ctx, name, value) - x509_ext = X509.X509_Extension(x509_ext_ptr, 1) + + ctx = m2.x509v3_set_nconf() + x509_ext_ptr = m2.x509v3_ext_conf(None, ctx, name, value) + X509.X509_Extension(x509_ext_ptr, 1) class CRLTestCase(unittest.TestCase): @@ -542,15 +687,15 @@ class CRLTestCase(unittest.TestCase): crl = X509.CRL() self.assertEqual(crl.as_text()[:34], 'Certificate Revocation List (CRL):') - + def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(X509TestCase)) - suite.addTest(unittest.makeSuite(X509_StackTestCase)) - suite.addTest(unittest.makeSuite(X509_ExtTestCase)) - suite.addTest(unittest.makeSuite(CRLTestCase)) - return suite + st = unittest.TestSuite() + st.addTest(unittest.makeSuite(X509TestCase)) + st.addTest(unittest.makeSuite(X509StackTestCase)) + st.addTest(unittest.makeSuite(X509ExtTestCase)) + st.addTest(unittest.makeSuite(CRLTestCase)) + return st if __name__ == '__main__': diff --git a/tests/vendor/unittest2/__init__.py b/tests/vendor/unittest2/__init__.py new file mode 100644 index 0000000..11cbadc --- /dev/null +++ b/tests/vendor/unittest2/__init__.py @@ -0,0 +1,68 @@ +""" +unittest2 + +unittest2 is a backport of the new features added to the unittest testing +framework in Python 2.7. It is tested to run on Python 2.4 - 2.6. + +To use unittest2 instead of unittest simply replace ``import unittest`` with +``import unittest2``. + + +Copyright (c) 1999-2003 Steve Purcell +Copyright (c) 2003-2010 Python Software Foundation +This module is free software, and you may redistribute it and/or modify +it under the same terms as Python itself, so long as this copyright message +and disclaimer are retained in their original form. + +IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF +THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, +AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, +SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +""" + +__all__ = ['TestResult', 'TestCase', 'TestSuite', + 'TextTestRunner', 'TestLoader', 'FunctionTestCase', 'main', + 'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless', + 'expectedFailure', 'TextTestResult', '__version__', 'collector'] + +__version__ = '0.5.1' + +# Expose obsolete functions for backwards compatibility +__all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases']) + + +from unittest2.collector import collector +from unittest2.result import TestResult +from unittest2.case import ( + TestCase, FunctionTestCase, SkipTest, skip, skipIf, + skipUnless, expectedFailure +) +from unittest2.suite import BaseTestSuite, TestSuite +from unittest2.loader import ( + TestLoader, defaultTestLoader, makeSuite, getTestCaseNames, + findTestCases +) +from unittest2.main import TestProgram, main, main_ +from unittest2.runner import TextTestRunner, TextTestResult + +try: + from unittest2.signals import ( + installHandler, registerResult, removeResult, removeHandler + ) +except ImportError: + # Compatibility with platforms that don't have the signal module + pass +else: + __all__.extend(['installHandler', 'registerResult', 'removeResult', + 'removeHandler']) + +# deprecated +_TextTestResult = TextTestResult + +__unittest = True \ No newline at end of file diff --git a/tests/vendor/unittest2/__main__.py b/tests/vendor/unittest2/__main__.py new file mode 100644 index 0000000..04ed982 --- /dev/null +++ b/tests/vendor/unittest2/__main__.py @@ -0,0 +1,10 @@ +"""Main entry point""" + +import sys +if sys.argv[0].endswith("__main__.py"): + sys.argv[0] = "unittest2" + +__unittest = True + +from unittest2.main import main_ +main_() diff --git a/tests/vendor/unittest2/case.py b/tests/vendor/unittest2/case.py new file mode 100644 index 0000000..105914b --- /dev/null +++ b/tests/vendor/unittest2/case.py @@ -0,0 +1,1084 @@ +"""Test case implementation""" + +import sys +import difflib +import pprint +import re +import unittest +import warnings + +from unittest2 import result +from unittest2.util import ( + safe_repr, safe_str, strclass, + unorderable_list_difference +) + +from unittest2.compatibility import wraps + +__unittest = True + + +DIFF_OMITTED = ('\nDiff is %s characters long. ' + 'Set self.maxDiff to None to see it.') + +class SkipTest(Exception): + """ + Raise this exception in a test to skip it. + + Usually you can use TestResult.skip() or one of the skipping decorators + instead of raising this directly. + """ + +class _ExpectedFailure(Exception): + """ + Raise this when a test is expected to fail. + + This is an implementation detail. + """ + + def __init__(self, exc_info): + # can't use super because Python 2.4 exceptions are old style + Exception.__init__(self) + self.exc_info = exc_info + +class _UnexpectedSuccess(Exception): + """ + The test was supposed to fail, but it didn't! + """ + +def _id(obj): + return obj + +def skip(reason): + """ + Unconditionally skip a test. + """ + def decorator(test_item): + if not (isinstance(test_item, type) and issubclass(test_item, TestCase)): + @wraps(test_item) + def skip_wrapper(*args, **kwargs): + raise SkipTest(reason) + test_item = skip_wrapper + + test_item.__unittest_skip__ = True + test_item.__unittest_skip_why__ = reason + return test_item + return decorator + +def skipIf(condition, reason): + """ + Skip a test if the condition is true. + """ + if condition: + return skip(reason) + return _id + +def skipUnless(condition, reason): + """ + Skip a test unless the condition is true. + """ + if not condition: + return skip(reason) + return _id + + +def expectedFailure(func): + @wraps(func) + def wrapper(*args, **kwargs): + try: + func(*args, **kwargs) + except Exception: + raise _ExpectedFailure(sys.exc_info()) + raise _UnexpectedSuccess + return wrapper + + +class _AssertRaisesContext(object): + """A context manager used to implement TestCase.assertRaises* methods.""" + + def __init__(self, expected, test_case, expected_regexp=None): + self.expected = expected + self.failureException = test_case.failureException + self.expected_regexp = expected_regexp + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + if exc_type is None: + try: + exc_name = self.expected.__name__ + except AttributeError: + exc_name = str(self.expected) + raise self.failureException( + "%s not raised" % (exc_name,)) + if not issubclass(exc_type, self.expected): + # let unexpected exceptions pass through + return False + self.exception = exc_value # store for later retrieval + if self.expected_regexp is None: + return True + + expected_regexp = self.expected_regexp + if isinstance(expected_regexp, basestring): + expected_regexp = re.compile(expected_regexp) + if not expected_regexp.search(str(exc_value)): + raise self.failureException('"%s" does not match "%s"' % + (expected_regexp.pattern, str(exc_value))) + return True + + +class _TypeEqualityDict(object): + + def __init__(self, testcase): + self.testcase = testcase + self._store = {} + + def __setitem__(self, key, value): + self._store[key] = value + + def __getitem__(self, key): + value = self._store[key] + if isinstance(value, basestring): + return getattr(self.testcase, value) + return value + + def get(self, key, default=None): + if key in self._store: + return self[key] + return default + + +class TestCase(unittest.TestCase): + """A class whose instances are single test cases. + + By default, the test code itself should be placed in a method named + 'runTest'. + + If the fixture may be used for many test cases, create as + many test methods as are needed. When instantiating such a TestCase + subclass, specify in the constructor arguments the name of the test method + that the instance is to execute. + + Test authors should subclass TestCase for their own tests. Construction + and deconstruction of the test's environment ('fixture') can be + implemented by overriding the 'setUp' and 'tearDown' methods respectively. + + If it is necessary to override the __init__ method, the base class + __init__ method must always be called. It is important that subclasses + should not change the signature of their __init__ method, since instances + of the classes are instantiated automatically by parts of the framework + in order to be run. + """ + + # This attribute determines which exception will be raised when + # the instance's assertion methods fail; test methods raising this + # exception will be deemed to have 'failed' rather than 'errored' + + failureException = AssertionError + + # This attribute sets the maximum length of a diff in failure messages + # by assert methods using difflib. It is looked up as an instance attribute + # so can be configured by individual tests if required. + + maxDiff = 80*8 + + # This attribute determines whether long messages (including repr of + # objects used in assert methods) will be printed on failure in *addition* + # to any explicit message passed. + + longMessage = True + + # Attribute used by TestSuite for classSetUp + + _classSetupFailed = False + + def __init__(self, methodName='runTest'): + """Create an instance of the class that will use the named test + method when executed. Raises a ValueError if the instance does + not have a method with the specified name. + """ + self._testMethodName = methodName + self._resultForDoCleanups = None + try: + testMethod = getattr(self, methodName) + except AttributeError: + raise ValueError("no such test method in %s: %s" % \ + (self.__class__, methodName)) + self._testMethodDoc = testMethod.__doc__ + self._cleanups = [] + + # Map types to custom assertEqual functions that will compare + # instances of said type in more detail to generate a more useful + # error message. + self._type_equality_funcs = _TypeEqualityDict(self) + self.addTypeEqualityFunc(dict, 'assertDictEqual') + self.addTypeEqualityFunc(list, 'assertListEqual') + self.addTypeEqualityFunc(tuple, 'assertTupleEqual') + self.addTypeEqualityFunc(set, 'assertSetEqual') + self.addTypeEqualityFunc(frozenset, 'assertSetEqual') + self.addTypeEqualityFunc(unicode, 'assertMultiLineEqual') + + def addTypeEqualityFunc(self, typeobj, function): + """Add a type specific assertEqual style function to compare a type. + + This method is for use by TestCase subclasses that need to register + their own type equality functions to provide nicer error messages. + + Args: + typeobj: The data type to call this function on when both values + are of the same type in assertEqual(). + function: The callable taking two arguments and an optional + msg= argument that raises self.failureException with a + useful error message when the two arguments are not equal. + """ + self._type_equality_funcs[typeobj] = function + + def addCleanup(self, function, *args, **kwargs): + """Add a function, with arguments, to be called when the test is + completed. Functions added are called on a LIFO basis and are + called after tearDown on test failure or success. + + Cleanup items are called even if setUp fails (unlike tearDown).""" + self._cleanups.append((function, args, kwargs)) + + def setUp(self): + "Hook method for setting up the test fixture before exercising it." + + @classmethod + def setUpClass(cls): + "Hook method for setting up class fixture before running tests in the class." + + @classmethod + def tearDownClass(cls): + "Hook method for deconstructing the class fixture after running all tests in the class." + + def tearDown(self): + "Hook method for deconstructing the test fixture after testing it." + + def countTestCases(self): + return 1 + + def defaultTestResult(self): + return result.TestResult() + + def shortDescription(self): + """Returns a one-line description of the test, or None if no + description has been provided. + + The default implementation of this method returns the first line of + the specified test method's docstring. + """ + doc = self._testMethodDoc + return doc and doc.split("\n")[0].strip() or None + + + def id(self): + return "%s.%s" % (strclass(self.__class__), self._testMethodName) + + def __eq__(self, other): + if type(self) is not type(other): + return NotImplemented + + return self._testMethodName == other._testMethodName + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((type(self), self._testMethodName)) + + def __str__(self): + return "%s (%s)" % (self._testMethodName, strclass(self.__class__)) + + def __repr__(self): + return "<%s testMethod=%s>" % \ + (strclass(self.__class__), self._testMethodName) + + def _addSkip(self, result, reason): + addSkip = getattr(result, 'addSkip', None) + if addSkip is not None: + addSkip(self, reason) + else: + warnings.warn("Use of a TestResult without an addSkip method is deprecated", + DeprecationWarning, 2) + result.addSuccess(self) + + def run(self, result=None): + orig_result = result + if result is None: + result = self.defaultTestResult() + startTestRun = getattr(result, 'startTestRun', None) + if startTestRun is not None: + startTestRun() + + self._resultForDoCleanups = result + result.startTest(self) + + testMethod = getattr(self, self._testMethodName) + + if (getattr(self.__class__, "__unittest_skip__", False) or + getattr(testMethod, "__unittest_skip__", False)): + # If the class or method was skipped. + try: + skip_why = (getattr(self.__class__, '__unittest_skip_why__', '') + or getattr(testMethod, '__unittest_skip_why__', '')) + self._addSkip(result, skip_why) + finally: + result.stopTest(self) + return + try: + success = False + try: + self.setUp() + except SkipTest, e: + self._addSkip(result, str(e)) + except Exception: + result.addError(self, sys.exc_info()) + else: + try: + testMethod() + except self.failureException: + result.addFailure(self, sys.exc_info()) + except _ExpectedFailure, e: + addExpectedFailure = getattr(result, 'addExpectedFailure', None) + if addExpectedFailure is not None: + addExpectedFailure(self, e.exc_info) + else: + warnings.warn("Use of a TestResult without an addExpectedFailure method is deprecated", + DeprecationWarning) + result.addSuccess(self) + except _UnexpectedSuccess: + addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None) + if addUnexpectedSuccess is not None: + addUnexpectedSuccess(self) + else: + warnings.warn("Use of a TestResult without an addUnexpectedSuccess method is deprecated", + DeprecationWarning) + result.addFailure(self, sys.exc_info()) + except SkipTest, e: + self._addSkip(result, str(e)) + except Exception: + result.addError(self, sys.exc_info()) + else: + success = True + + try: + self.tearDown() + except Exception: + result.addError(self, sys.exc_info()) + success = False + + cleanUpSuccess = self.doCleanups() + success = success and cleanUpSuccess + if success: + result.addSuccess(self) + finally: + result.stopTest(self) + if orig_result is None: + stopTestRun = getattr(result, 'stopTestRun', None) + if stopTestRun is not None: + stopTestRun() + + def doCleanups(self): + """Execute all cleanup functions. Normally called for you after + tearDown.""" + result = self._resultForDoCleanups + ok = True + while self._cleanups: + function, args, kwargs = self._cleanups.pop(-1) + try: + function(*args, **kwargs) + except Exception: + ok = False + result.addError(self, sys.exc_info()) + return ok + + def __call__(self, *args, **kwds): + return self.run(*args, **kwds) + + def debug(self): + """Run the test without collecting errors in a TestResult""" + self.setUp() + getattr(self, self._testMethodName)() + self.tearDown() + while self._cleanups: + function, args, kwargs = self._cleanups.pop(-1) + function(*args, **kwargs) + + def skipTest(self, reason): + """Skip this test.""" + raise SkipTest(reason) + + def fail(self, msg=None): + """Fail immediately, with the given message.""" + raise self.failureException(msg) + + def assertFalse(self, expr, msg=None): + "Fail the test if the expression is true." + if expr: + msg = self._formatMessage(msg, "%s is not False" % safe_repr(expr)) + raise self.failureException(msg) + + def assertTrue(self, expr, msg=None): + """Fail the test unless the expression is true.""" + if not expr: + msg = self._formatMessage(msg, "%s is not True" % safe_repr(expr)) + raise self.failureException(msg) + + def _formatMessage(self, msg, standardMsg): + """Honour the longMessage attribute when generating failure messages. + If longMessage is False this means: + * Use only an explicit message if it is provided + * Otherwise use the standard message for the assert + + If longMessage is True: + * Use the standard message + * If an explicit message is provided, plus ' : ' and the explicit message + """ + if not self.longMessage: + return msg or standardMsg + if msg is None: + return standardMsg + try: + return '%s : %s' % (standardMsg, msg) + except UnicodeDecodeError: + return '%s : %s' % (safe_str(standardMsg), safe_str(msg)) + + + def assertRaises(self, excClass, callableObj=None, *args, **kwargs): + """Fail unless an exception of class excClass is thrown + by callableObj when invoked with arguments args and keyword + arguments kwargs. If a different type of exception is + thrown, it will not be caught, and the test case will be + deemed to have suffered an error, exactly as for an + unexpected exception. + + If called with callableObj omitted or None, will return a + context object used like this:: + + with self.assertRaises(SomeException): + do_something() + + The context manager keeps a reference to the exception as + the 'exception' attribute. This allows you to inspect the + exception after the assertion:: + + with self.assertRaises(SomeException) as cm: + do_something() + the_exception = cm.exception + self.assertEqual(the_exception.error_code, 3) + """ + if callableObj is None: + return _AssertRaisesContext(excClass, self) + try: + callableObj(*args, **kwargs) + except excClass: + return + + if hasattr(excClass,'__name__'): + excName = excClass.__name__ + else: + excName = str(excClass) + raise self.failureException, "%s not raised" % excName + + def _getAssertEqualityFunc(self, first, second): + """Get a detailed comparison function for the types of the two args. + + Returns: A callable accepting (first, second, msg=None) that will + raise a failure exception if first != second with a useful human + readable error message for those types. + """ + # + # NOTE(gregory.p.smith): I considered isinstance(first, type(second)) + # and vice versa. I opted for the conservative approach in case + # subclasses are not intended to be compared in detail to their super + # class instances using a type equality func. This means testing + # subtypes won't automagically use the detailed comparison. Callers + # should use their type specific assertSpamEqual method to compare + # subclasses if the detailed comparison is desired and appropriate. + # See the discussion in http://bugs.python.org/issue2578. + # + if type(first) is type(second): + asserter = self._type_equality_funcs.get(type(first)) + if asserter is not None: + return asserter + + return self._baseAssertEqual + + def _baseAssertEqual(self, first, second, msg=None): + """The default assertEqual implementation, not type specific.""" + if not first == second: + standardMsg = '%s != %s' % (safe_repr(first), safe_repr(second)) + msg = self._formatMessage(msg, standardMsg) + raise self.failureException(msg) + + def assertEqual(self, first, second, msg=None): + """Fail if the two objects are unequal as determined by the '==' + operator. + """ + assertion_func = self._getAssertEqualityFunc(first, second) + assertion_func(first, second, msg=msg) + + def assertNotEqual(self, first, second, msg=None): + """Fail if the two objects are equal as determined by the '==' + operator. + """ + if not first != second: + msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first), + safe_repr(second))) + raise self.failureException(msg) + + def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None): + """Fail if the two objects are unequal as determined by their + difference rounded to the given number of decimal places + (default 7) and comparing to zero, or by comparing that the + between the two objects is more than the given delta. + + Note that decimal places (from zero) are usually not the same + as significant digits (measured from the most signficant digit). + + If the two objects compare equal then they will automatically + compare almost equal. + """ + if first == second: + # shortcut + return + if delta is not None and places is not None: + raise TypeError("specify delta or places not both") + + if delta is not None: + if abs(first - second) <= delta: + return + + standardMsg = '%s != %s within %s delta' % (safe_repr(first), + safe_repr(second), + safe_repr(delta)) + else: + if places is None: + places = 7 + + if round(abs(second-first), places) == 0: + return + + standardMsg = '%s != %s within %r places' % (safe_repr(first), + safe_repr(second), + places) + msg = self._formatMessage(msg, standardMsg) + raise self.failureException(msg) + + def assertNotAlmostEqual(self, first, second, places=None, msg=None, delta=None): + """Fail if the two objects are equal as determined by their + difference rounded to the given number of decimal places + (default 7) and comparing to zero, or by comparing that the + between the two objects is less than the given delta. + + Note that decimal places (from zero) are usually not the same + as significant digits (measured from the most signficant digit). + + Objects that are equal automatically fail. + """ + if delta is not None and places is not None: + raise TypeError("specify delta or places not both") + if delta is not None: + if not (first == second) and abs(first - second) > delta: + return + standardMsg = '%s == %s within %s delta' % (safe_repr(first), + safe_repr(second), + safe_repr(delta)) + else: + if places is None: + places = 7 + if not (first == second) and round(abs(second-first), places) != 0: + return + standardMsg = '%s == %s within %r places' % (safe_repr(first), + safe_repr(second), + places) + + msg = self._formatMessage(msg, standardMsg) + raise self.failureException(msg) + + # Synonyms for assertion methods + + # The plurals are undocumented. Keep them that way to discourage use. + # Do not add more. Do not remove. + # Going through a deprecation cycle on these would annoy many people. + assertEquals = assertEqual + assertNotEquals = assertNotEqual + assertAlmostEquals = assertAlmostEqual + assertNotAlmostEquals = assertNotAlmostEqual + assert_ = assertTrue + + # These fail* assertion method names are pending deprecation and will + # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578 + def _deprecate(original_func): + def deprecated_func(*args, **kwargs): + warnings.warn( + ('Please use %s instead.' % original_func.__name__), + PendingDeprecationWarning, 2) + return original_func(*args, **kwargs) + return deprecated_func + + failUnlessEqual = _deprecate(assertEqual) + failIfEqual = _deprecate(assertNotEqual) + failUnlessAlmostEqual = _deprecate(assertAlmostEqual) + failIfAlmostEqual = _deprecate(assertNotAlmostEqual) + failUnless = _deprecate(assertTrue) + failUnlessRaises = _deprecate(assertRaises) + failIf = _deprecate(assertFalse) + + def assertSequenceEqual(self, seq1, seq2, + msg=None, seq_type=None, max_diff=80*8): + """An equality assertion for ordered sequences (like lists and tuples). + + For the purposes of this function, a valid ordered sequence type is one + which can be indexed, has a length, and has an equality operator. + + Args: + seq1: The first sequence to compare. + seq2: The second sequence to compare. + seq_type: The expected datatype of the sequences, or None if no + datatype should be enforced. + msg: Optional message to use on failure instead of a list of + differences. + max_diff: Maximum size off the diff, larger diffs are not shown + """ + if seq_type is not None: + seq_type_name = seq_type.__name__ + if not isinstance(seq1, seq_type): + raise self.failureException('First sequence is not a %s: %s' + % (seq_type_name, safe_repr(seq1))) + if not isinstance(seq2, seq_type): + raise self.failureException('Second sequence is not a %s: %s' + % (seq_type_name, safe_repr(seq2))) + else: + seq_type_name = "sequence" + + differing = None + try: + len1 = len(seq1) + except (TypeError, NotImplementedError): + differing = 'First %s has no length. Non-sequence?' % ( + seq_type_name) + + if differing is None: + try: + len2 = len(seq2) + except (TypeError, NotImplementedError): + differing = 'Second %s has no length. Non-sequence?' % ( + seq_type_name) + + if differing is None: + if seq1 == seq2: + return + + seq1_repr = repr(seq1) + seq2_repr = repr(seq2) + if len(seq1_repr) > 30: + seq1_repr = seq1_repr[:30] + '...' + if len(seq2_repr) > 30: + seq2_repr = seq2_repr[:30] + '...' + elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr) + differing = '%ss differ: %s != %s\n' % elements + + for i in xrange(min(len1, len2)): + try: + item1 = seq1[i] + except (TypeError, IndexError, NotImplementedError): + differing += ('\nUnable to index element %d of first %s\n' % + (i, seq_type_name)) + break + + try: + item2 = seq2[i] + except (TypeError, IndexError, NotImplementedError): + differing += ('\nUnable to index element %d of second %s\n' % + (i, seq_type_name)) + break + + if item1 != item2: + differing += ('\nFirst differing element %d:\n%s\n%s\n' % + (i, item1, item2)) + break + else: + if (len1 == len2 and seq_type is None and + type(seq1) != type(seq2)): + # The sequences are the same, but have differing types. + return + + if len1 > len2: + differing += ('\nFirst %s contains %d additional ' + 'elements.\n' % (seq_type_name, len1 - len2)) + try: + differing += ('First extra element %d:\n%s\n' % + (len2, seq1[len2])) + except (TypeError, IndexError, NotImplementedError): + differing += ('Unable to index element %d ' + 'of first %s\n' % (len2, seq_type_name)) + elif len1 < len2: + differing += ('\nSecond %s contains %d additional ' + 'elements.\n' % (seq_type_name, len2 - len1)) + try: + differing += ('First extra element %d:\n%s\n' % + (len1, seq2[len1])) + except (TypeError, IndexError, NotImplementedError): + differing += ('Unable to index element %d ' + 'of second %s\n' % (len1, seq_type_name)) + standardMsg = differing + diffMsg = '\n' + '\n'.join( + difflib.ndiff(pprint.pformat(seq1).splitlines(), + pprint.pformat(seq2).splitlines())) + + standardMsg = self._truncateMessage(standardMsg, diffMsg) + msg = self._formatMessage(msg, standardMsg) + self.fail(msg) + + def _truncateMessage(self, message, diff): + max_diff = self.maxDiff + if max_diff is None or len(diff) <= max_diff: + return message + diff + return message + (DIFF_OMITTED % len(diff)) + + def assertListEqual(self, list1, list2, msg=None): + """A list-specific equality assertion. + + Args: + list1: The first list to compare. + list2: The second list to compare. + msg: Optional message to use on failure instead of a list of + differences. + + """ + self.assertSequenceEqual(list1, list2, msg, seq_type=list) + + def assertTupleEqual(self, tuple1, tuple2, msg=None): + """A tuple-specific equality assertion. + + Args: + tuple1: The first tuple to compare. + tuple2: The second tuple to compare. + msg: Optional message to use on failure instead of a list of + differences. + """ + self.assertSequenceEqual(tuple1, tuple2, msg, seq_type=tuple) + + def assertSetEqual(self, set1, set2, msg=None): + """A set-specific equality assertion. + + Args: + set1: The first set to compare. + set2: The second set to compare. + msg: Optional message to use on failure instead of a list of + differences. + + assertSetEqual uses ducktyping to support + different types of sets, and is optimized for sets specifically + (parameters must support a difference method). + """ + try: + difference1 = set1.difference(set2) + except TypeError, e: + self.fail('invalid type when attempting set difference: %s' % e) + except AttributeError, e: + self.fail('first argument does not support set difference: %s' % e) + + try: + difference2 = set2.difference(set1) + except TypeError, e: + self.fail('invalid type when attempting set difference: %s' % e) + except AttributeError, e: + self.fail('second argument does not support set difference: %s' % e) + + if not (difference1 or difference2): + return + + lines = [] + if difference1: + lines.append('Items in the first set but not the second:') + for item in difference1: + lines.append(repr(item)) + if difference2: + lines.append('Items in the second set but not the first:') + for item in difference2: + lines.append(repr(item)) + + standardMsg = '\n'.join(lines) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertIn(self, member, container, msg=None): + """Just like self.assertTrue(a in b), but with a nicer default message.""" + if member not in container: + standardMsg = '%s not found in %s' % (safe_repr(member), + safe_repr(container)) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertNotIn(self, member, container, msg=None): + """Just like self.assertTrue(a not in b), but with a nicer default message.""" + if member in container: + standardMsg = '%s unexpectedly found in %s' % (safe_repr(member), + safe_repr(container)) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertIs(self, expr1, expr2, msg=None): + """Just like self.assertTrue(a is b), but with a nicer default message.""" + if expr1 is not expr2: + standardMsg = '%s is not %s' % (safe_repr(expr1), safe_repr(expr2)) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertIsNot(self, expr1, expr2, msg=None): + """Just like self.assertTrue(a is not b), but with a nicer default message.""" + if expr1 is expr2: + standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertDictEqual(self, d1, d2, msg=None): + self.assert_(isinstance(d1, dict), 'First argument is not a dictionary') + self.assert_(isinstance(d2, dict), 'Second argument is not a dictionary') + + if d1 != d2: + standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True)) + diff = ('\n' + '\n'.join(difflib.ndiff( + pprint.pformat(d1).splitlines(), + pprint.pformat(d2).splitlines()))) + standardMsg = self._truncateMessage(standardMsg, diff) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertDictContainsSubset(self, expected, actual, msg=None): + """Checks whether actual is a superset of expected.""" + missing = [] + mismatched = [] + for key, value in expected.iteritems(): + if key not in actual: + missing.append(key) + elif value != actual[key]: + mismatched.append('%s, expected: %s, actual: %s' % + (safe_repr(key), safe_repr(value), + safe_repr(actual[key]))) + + if not (missing or mismatched): + return + + standardMsg = '' + if missing: + standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in + missing) + if mismatched: + if standardMsg: + standardMsg += '; ' + standardMsg += 'Mismatched values: %s' % ','.join(mismatched) + + self.fail(self._formatMessage(msg, standardMsg)) + + def assertItemsEqual(self, expected_seq, actual_seq, msg=None): + """An unordered sequence specific comparison. It asserts that + expected_seq and actual_seq contain the same elements. It is + the equivalent of:: + + self.assertEqual(sorted(expected_seq), sorted(actual_seq)) + + Raises with an error message listing which elements of expected_seq + are missing from actual_seq and vice versa if any. + + Asserts that each element has the same count in both sequences. + Example: + - [0, 1, 1] and [1, 0, 1] compare equal. + - [0, 0, 1] and [0, 1] compare unequal. + """ + try: + expected = sorted(expected_seq) + actual = sorted(actual_seq) + except TypeError: + # Unsortable items (example: set(), complex(), ...) + expected = list(expected_seq) + actual = list(actual_seq) + missing, unexpected = unorderable_list_difference( + expected, actual, ignore_duplicate=False + ) + else: + return self.assertSequenceEqual(expected, actual, msg=msg) + + errors = [] + if missing: + errors.append('Expected, but missing:\n %s' % + safe_repr(missing)) + if unexpected: + errors.append('Unexpected, but present:\n %s' % + safe_repr(unexpected)) + if errors: + standardMsg = '\n'.join(errors) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertMultiLineEqual(self, first, second, msg=None): + """Assert that two multi-line strings are equal.""" + self.assert_(isinstance(first, basestring), ( + 'First argument is not a string')) + self.assert_(isinstance(second, basestring), ( + 'Second argument is not a string')) + + if first != second: + standardMsg = '%s != %s' % (safe_repr(first, True), safe_repr(second, True)) + diff = '\n' + ''.join(difflib.ndiff(first.splitlines(True), + second.splitlines(True))) + standardMsg = self._truncateMessage(standardMsg, diff) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertLess(self, a, b, msg=None): + """Just like self.assertTrue(a < b), but with a nicer default message.""" + if not a < b: + standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b)) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertLessEqual(self, a, b, msg=None): + """Just like self.assertTrue(a <= b), but with a nicer default message.""" + if not a <= b: + standardMsg = '%s not less than or equal to %s' % (safe_repr(a), safe_repr(b)) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertGreater(self, a, b, msg=None): + """Just like self.assertTrue(a > b), but with a nicer default message.""" + if not a > b: + standardMsg = '%s not greater than %s' % (safe_repr(a), safe_repr(b)) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertGreaterEqual(self, a, b, msg=None): + """Just like self.assertTrue(a >= b), but with a nicer default message.""" + if not a >= b: + standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b)) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertIsNone(self, obj, msg=None): + """Same as self.assertTrue(obj is None), with a nicer default message.""" + if obj is not None: + standardMsg = '%s is not None' % (safe_repr(obj),) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertIsNotNone(self, obj, msg=None): + """Included for symmetry with assertIsNone.""" + if obj is None: + standardMsg = 'unexpectedly None' + self.fail(self._formatMessage(msg, standardMsg)) + + def assertIsInstance(self, obj, cls, msg=None): + """Same as self.assertTrue(isinstance(obj, cls)), with a nicer + default message.""" + if not isinstance(obj, cls): + standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertNotIsInstance(self, obj, cls, msg=None): + """Included for symmetry with assertIsInstance.""" + if isinstance(obj, cls): + standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls) + self.fail(self._formatMessage(msg, standardMsg)) + + def assertRaisesRegexp(self, expected_exception, expected_regexp, + callable_obj=None, *args, **kwargs): + """Asserts that the message in a raised exception matches a regexp. + + Args: + expected_exception: Exception class expected to be raised. + expected_regexp: Regexp (re pattern object or string) expected + to be found in error message. + callable_obj: Function to be called. + args: Extra args. + kwargs: Extra kwargs. + """ + if callable_obj is None: + return _AssertRaisesContext(expected_exception, self, expected_regexp) + try: + callable_obj(*args, **kwargs) + except expected_exception, exc_value: + if isinstance(expected_regexp, basestring): + expected_regexp = re.compile(expected_regexp) + if not expected_regexp.search(str(exc_value)): + raise self.failureException('"%s" does not match "%s"' % + (expected_regexp.pattern, str(exc_value))) + else: + if hasattr(expected_exception, '__name__'): + excName = expected_exception.__name__ + else: + excName = str(expected_exception) + raise self.failureException, "%s not raised" % excName + + + def assertRegexpMatches(self, text, expected_regexp, msg=None): + """Fail the test unless the text matches the regular expression.""" + if isinstance(expected_regexp, basestring): + expected_regexp = re.compile(expected_regexp) + if not expected_regexp.search(text): + msg = msg or "Regexp didn't match" + msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text) + raise self.failureException(msg) + + def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None): + """Fail the test if the text matches the regular expression.""" + if isinstance(unexpected_regexp, basestring): + unexpected_regexp = re.compile(unexpected_regexp) + match = unexpected_regexp.search(text) + if match: + msg = msg or "Regexp matched" + msg = '%s: %r matches %r in %r' % (msg, + text[match.start():match.end()], + unexpected_regexp.pattern, + text) + raise self.failureException(msg) + +class FunctionTestCase(TestCase): + """A test case that wraps a test function. + + This is useful for slipping pre-existing test functions into the + unittest framework. Optionally, set-up and tidy-up functions can be + supplied. As with TestCase, the tidy-up ('tearDown') function will + always be called if the set-up ('setUp') function ran successfully. + """ + + def __init__(self, testFunc, setUp=None, tearDown=None, description=None): + super(FunctionTestCase, self).__init__() + self._setUpFunc = setUp + self._tearDownFunc = tearDown + self._testFunc = testFunc + self._description = description + + def setUp(self): + if self._setUpFunc is not None: + self._setUpFunc() + + def tearDown(self): + if self._tearDownFunc is not None: + self._tearDownFunc() + + def runTest(self): + self._testFunc() + + def id(self): + return self._testFunc.__name__ + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + + return self._setUpFunc == other._setUpFunc and \ + self._tearDownFunc == other._tearDownFunc and \ + self._testFunc == other._testFunc and \ + self._description == other._description + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((type(self), self._setUpFunc, self._tearDownFunc, + self._testFunc, self._description)) + + def __str__(self): + return "%s (%s)" % (strclass(self.__class__), + self._testFunc.__name__) + + def __repr__(self): + return "<%s testFunc=%s>" % (strclass(self.__class__), + self._testFunc) + + def shortDescription(self): + if self._description is not None: + return self._description + doc = self._testFunc.__doc__ + return doc and doc.split("\n")[0].strip() or None diff --git a/tests/vendor/unittest2/collector.py b/tests/vendor/unittest2/collector.py new file mode 100644 index 0000000..28ff3f8 --- /dev/null +++ b/tests/vendor/unittest2/collector.py @@ -0,0 +1,9 @@ +import os +import sys +from unittest2.loader import defaultTestLoader + +def collector(): + # import __main__ triggers code re-execution + __main__ = sys.modules['__main__'] + setupDir = os.path.abspath(os.path.dirname(__main__.__file__)) + return defaultTestLoader.discover(setupDir) diff --git a/tests/vendor/unittest2/compatibility.py b/tests/vendor/unittest2/compatibility.py new file mode 100644 index 0000000..b8f15dd --- /dev/null +++ b/tests/vendor/unittest2/compatibility.py @@ -0,0 +1,64 @@ +import os +import sys + +try: + from functools import wraps +except ImportError: + # only needed for Python 2.4 + def wraps(_): + def _wraps(func): + return func + return _wraps + +__unittest = True + +def _relpath_nt(path, start=os.path.curdir): + """Return a relative version of a path""" + + if not path: + raise ValueError("no path specified") + start_list = os.path.abspath(start).split(os.path.sep) + path_list = os.path.abspath(path).split(os.path.sep) + if start_list[0].lower() != path_list[0].lower(): + unc_path, rest = os.path.splitunc(path) + unc_start, rest = os.path.splitunc(start) + if bool(unc_path) ^ bool(unc_start): + raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)" + % (path, start)) + else: + raise ValueError("path is on drive %s, start on drive %s" + % (path_list[0], start_list[0])) + # Work out how much of the filepath is shared by start and path. + for i in range(min(len(start_list), len(path_list))): + if start_list[i].lower() != path_list[i].lower(): + break + else: + i += 1 + + rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] + if not rel_list: + return os.path.curdir + return os.path.join(*rel_list) + +# default to posixpath definition +def _relpath_posix(path, start=os.path.curdir): + """Return a relative version of a path""" + + if not path: + raise ValueError("no path specified") + + start_list = os.path.abspath(start).split(os.path.sep) + path_list = os.path.abspath(path).split(os.path.sep) + + # Work out how much of the filepath is shared by start and path. + i = len(os.path.commonprefix([start_list, path_list])) + + rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] + if not rel_list: + return os.path.curdir + return os.path.join(*rel_list) + +if os.path is sys.modules.get('ntpath'): + relpath = _relpath_nt +else: + relpath = _relpath_posix diff --git a/tests/vendor/unittest2/loader.py b/tests/vendor/unittest2/loader.py new file mode 100644 index 0000000..8ec2ead --- /dev/null +++ b/tests/vendor/unittest2/loader.py @@ -0,0 +1,322 @@ +"""Loading unittests.""" + +import os +import re +import sys +import traceback +import types +import unittest + +from fnmatch import fnmatch + +from unittest2 import case, suite + +try: + from os.path import relpath +except ImportError: + from unittest2.compatibility import relpath + +__unittest = True + + +def _CmpToKey(mycmp): + 'Convert a cmp= function into a key= function' + class K(object): + def __init__(self, obj): + self.obj = obj + def __lt__(self, other): + return mycmp(self.obj, other.obj) == -1 + return K + + +# what about .pyc or .pyo (etc) +# we would need to avoid loading the same tests multiple times +# from '.py', '.pyc' *and* '.pyo' +VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE) + + +def _make_failed_import_test(name, suiteClass): + message = 'Failed to import test module: %s' % name + if hasattr(traceback, 'format_exc'): + # Python 2.3 compatibility + # format_exc returns two frames of discover.py as well + message += '\n%s' % traceback.format_exc() + return _make_failed_test('ModuleImportFailure', name, ImportError(message), + suiteClass) + +def _make_failed_load_tests(name, exception, suiteClass): + return _make_failed_test('LoadTestsFailure', name, exception, suiteClass) + +def _make_failed_test(classname, methodname, exception, suiteClass): + def testFailure(self): + raise exception + attrs = {methodname: testFailure} + TestClass = type(classname, (case.TestCase,), attrs) + return suiteClass((TestClass(methodname),)) + + +class TestLoader(unittest.TestLoader): + """ + This class is responsible for loading tests according to various criteria + and returning them wrapped in a TestSuite + """ + testMethodPrefix = 'test' + sortTestMethodsUsing = cmp + suiteClass = suite.TestSuite + _top_level_dir = None + + def loadTestsFromTestCase(self, testCaseClass): + """Return a suite of all tests cases contained in testCaseClass""" + if issubclass(testCaseClass, suite.TestSuite): + raise TypeError("Test cases should not be derived from TestSuite." + " Maybe you meant to derive from TestCase?") + testCaseNames = self.getTestCaseNames(testCaseClass) + if not testCaseNames and hasattr(testCaseClass, 'runTest'): + testCaseNames = ['runTest'] + loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames)) + return loaded_suite + + def loadTestsFromModule(self, module, use_load_tests=True): + """Return a suite of all tests cases contained in the given module""" + tests = [] + for name in dir(module): + obj = getattr(module, name) + if isinstance(obj, type) and issubclass(obj, unittest.TestCase): + tests.append(self.loadTestsFromTestCase(obj)) + + load_tests = getattr(module, 'load_tests', None) + tests = self.suiteClass(tests) + if use_load_tests and load_tests is not None: + try: + return load_tests(self, tests, None) + except Exception, e: + return _make_failed_load_tests(module.__name__, e, + self.suiteClass) + return tests + + def loadTestsFromName(self, name, module=None): + """Return a suite of all tests cases given a string specifier. + + The name may resolve either to a module, a test case class, a + test method within a test case class, or a callable object which + returns a TestCase or TestSuite instance. + + The method optionally resolves the names relative to a given module. + """ + parts = name.split('.') + if module is None: + parts_copy = parts[:] + while parts_copy: + try: + module = __import__('.'.join(parts_copy)) + break + except ImportError: + del parts_copy[-1] + if not parts_copy: + raise + parts = parts[1:] + obj = module + for part in parts: + parent, obj = obj, getattr(obj, part) + + if isinstance(obj, types.ModuleType): + return self.loadTestsFromModule(obj) + elif isinstance(obj, type) and issubclass(obj, unittest.TestCase): + return self.loadTestsFromTestCase(obj) + elif (isinstance(obj, types.UnboundMethodType) and + isinstance(parent, type) and + issubclass(parent, case.TestCase)): + return self.suiteClass([parent(obj.__name__)]) + elif isinstance(obj, unittest.TestSuite): + return obj + elif hasattr(obj, '__call__'): + test = obj() + if isinstance(test, unittest.TestSuite): + return test + elif isinstance(test, unittest.TestCase): + return self.suiteClass([test]) + else: + raise TypeError("calling %s returned %s, not a test" % + (obj, test)) + else: + raise TypeError("don't know how to make test from: %s" % obj) + + def loadTestsFromNames(self, names, module=None): + """Return a suite of all tests cases found using the given sequence + of string specifiers. See 'loadTestsFromName()'. + """ + suites = [self.loadTestsFromName(name, module) for name in names] + return self.suiteClass(suites) + + def getTestCaseNames(self, testCaseClass): + """Return a sorted sequence of method names found within testCaseClass + """ + def isTestMethod(attrname, testCaseClass=testCaseClass, + prefix=self.testMethodPrefix): + return attrname.startswith(prefix) and \ + hasattr(getattr(testCaseClass, attrname), '__call__') + testFnNames = filter(isTestMethod, dir(testCaseClass)) + if self.sortTestMethodsUsing: + testFnNames.sort(key=_CmpToKey(self.sortTestMethodsUsing)) + return testFnNames + + def discover(self, start_dir, pattern='test*.py', top_level_dir=None): + """Find and return all test modules from the specified start + directory, recursing into subdirectories to find them. Only test files + that match the pattern will be loaded. (Using shell style pattern + matching.) + + All test modules must be importable from the top level of the project. + If the start directory is not the top level directory then the top + level directory must be specified separately. + + If a test package name (directory with '__init__.py') matches the + pattern then the package will be checked for a 'load_tests' function. If + this exists then it will be called with loader, tests, pattern. + + If load_tests exists then discovery does *not* recurse into the package, + load_tests is responsible for loading all tests in the package. + + The pattern is deliberately not stored as a loader attribute so that + packages can continue discovery themselves. top_level_dir is stored so + load_tests does not need to pass this argument in to loader.discover(). + """ + set_implicit_top = False + if top_level_dir is None and self._top_level_dir is not None: + # make top_level_dir optional if called from load_tests in a package + top_level_dir = self._top_level_dir + elif top_level_dir is None: + set_implicit_top = True + top_level_dir = start_dir + + top_level_dir = os.path.abspath(top_level_dir) + + if not top_level_dir in sys.path: + # all test modules must be importable from the top level directory + # should we *unconditionally* put the start directory in first + # in sys.path to minimise likelihood of conflicts between installed + # modules and development versions? + sys.path.insert(0, top_level_dir) + self._top_level_dir = top_level_dir + + is_not_importable = False + if os.path.isdir(os.path.abspath(start_dir)): + start_dir = os.path.abspath(start_dir) + if start_dir != top_level_dir: + is_not_importable = not os.path.isfile(os.path.join(start_dir, '__init__.py')) + else: + # support for discovery from dotted module names + try: + __import__(start_dir) + except ImportError: + is_not_importable = True + else: + the_module = sys.modules[start_dir] + top_part = start_dir.split('.')[0] + start_dir = os.path.abspath(os.path.dirname((the_module.__file__))) + if set_implicit_top: + self._top_level_dir = os.path.abspath(os.path.dirname(os.path.dirname(sys.modules[top_part].__file__))) + sys.path.remove(top_level_dir) + + if is_not_importable: + raise ImportError('Start directory is not importable: %r' % start_dir) + + tests = list(self._find_tests(start_dir, pattern)) + return self.suiteClass(tests) + + def _get_name_from_path(self, path): + path = os.path.splitext(os.path.normpath(path))[0] + + _relpath = relpath(path, self._top_level_dir) + assert not os.path.isabs(_relpath), "Path must be within the project" + assert not _relpath.startswith('..'), "Path must be within the project" + + name = _relpath.replace(os.path.sep, '.') + return name + + def _get_module_from_name(self, name): + __import__(name) + return sys.modules[name] + + def _match_path(self, path, full_path, pattern): + # override this method to use alternative matching strategy + return fnmatch(path, pattern) + + def _find_tests(self, start_dir, pattern): + """Used by discovery. Yields test suites it loads.""" + paths = os.listdir(start_dir) + + for path in paths: + full_path = os.path.join(start_dir, path) + if os.path.isfile(full_path): + if not VALID_MODULE_NAME.match(path): + # valid Python identifiers only + continue + if not self._match_path(path, full_path, pattern): + continue + # if the test file matches, load it + name = self._get_name_from_path(full_path) + try: + module = self._get_module_from_name(name) + except: + yield _make_failed_import_test(name, self.suiteClass) + else: + mod_file = os.path.abspath(getattr(module, '__file__', full_path)) + realpath = os.path.splitext(mod_file)[0] + fullpath_noext = os.path.splitext(full_path)[0] + if realpath.lower() != fullpath_noext.lower(): + module_dir = os.path.dirname(realpath) + mod_name = os.path.splitext(os.path.basename(full_path))[0] + expected_dir = os.path.dirname(full_path) + msg = ("%r module incorrectly imported from %r. Expected %r. " + "Is this module globally installed?") + raise ImportError(msg % (mod_name, module_dir, expected_dir)) + yield self.loadTestsFromModule(module) + elif os.path.isdir(full_path): + if not os.path.isfile(os.path.join(full_path, '__init__.py')): + continue + + load_tests = None + tests = None + if fnmatch(path, pattern): + # only check load_tests if the package directory itself matches the filter + name = self._get_name_from_path(full_path) + package = self._get_module_from_name(name) + load_tests = getattr(package, 'load_tests', None) + tests = self.loadTestsFromModule(package, use_load_tests=False) + + if load_tests is None: + if tests is not None: + # tests loaded from package file + yield tests + # recurse into the package + for test in self._find_tests(full_path, pattern): + yield test + else: + try: + yield load_tests(self, tests, pattern) + except Exception, e: + yield _make_failed_load_tests(package.__name__, e, + self.suiteClass) + +defaultTestLoader = TestLoader() + + +def _makeLoader(prefix, sortUsing, suiteClass=None): + loader = TestLoader() + loader.sortTestMethodsUsing = sortUsing + loader.testMethodPrefix = prefix + if suiteClass: + loader.suiteClass = suiteClass + return loader + +def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): + return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) + +def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, + suiteClass=suite.TestSuite): + return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass) + +def findTestCases(module, prefix='test', sortUsing=cmp, + suiteClass=suite.TestSuite): + return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module) diff --git a/tests/vendor/unittest2/main.py b/tests/vendor/unittest2/main.py new file mode 100644 index 0000000..9db1d30 --- /dev/null +++ b/tests/vendor/unittest2/main.py @@ -0,0 +1,241 @@ +"""Unittest main program""" + +import sys +import os +import types + +from unittest2 import loader, runner +try: + from unittest2.signals import installHandler +except ImportError: + installHandler = None + +__unittest = True + +FAILFAST = " -f, --failfast Stop on first failure\n" +CATCHBREAK = " -c, --catch Catch control-C and display results\n" +BUFFEROUTPUT = " -b, --buffer Buffer stdout and stderr during test runs\n" + +USAGE_AS_MAIN = """\ +Usage: %(progName)s [options] [tests] + +Options: + -h, --help Show this message + -v, --verbose Verbose output + -q, --quiet Minimal output +%(failfast)s%(catchbreak)s%(buffer)s +Examples: + %(progName)s test_module - run tests from test_module + %(progName)s test_module.TestClass - run tests from + test_module.TestClass + %(progName)s test_module.TestClass.test_method - run specified test method + +[tests] can be a list of any number of test modules, classes and test +methods. + +Alternative Usage: %(progName)s discover [options] + +Options: + -v, --verbose Verbose output +%(failfast)s%(catchbreak)s%(buffer)s -s directory Directory to start discovery ('.' default) + -p pattern Pattern to match test files ('test*.py' default) + -t directory Top level directory of project (default to + start directory) + +For test discovery all test modules must be importable from the top +level directory of the project. +""" + +USAGE_FROM_MODULE = """\ +Usage: %(progName)s [options] [test] [...] + +Options: + -h, --help Show this message + -v, --verbose Verbose output + -q, --quiet Minimal output +%(failfast)s%(catchbreak)s%(buffer)s +Examples: + %(progName)s - run default set of tests + %(progName)s MyTestSuite - run suite 'MyTestSuite' + %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething + %(progName)s MyTestCase - run all 'test*' test methods + in MyTestCase +""" + + +class TestProgram(object): + """A command-line program that runs a set of tests; this is primarily + for making test modules conveniently executable. + """ + USAGE = USAGE_FROM_MODULE + + # defaults for testing + failfast = catchbreak = buffer = progName = None + + def __init__(self, module='__main__', defaultTest=None, + argv=None, testRunner=None, + testLoader=loader.defaultTestLoader, exit=True, + verbosity=1, failfast=None, catchbreak=None, buffer=None): + if isinstance(module, basestring): + self.module = __import__(module) + for part in module.split('.')[1:]: + self.module = getattr(self.module, part) + else: + self.module = module + if argv is None: + argv = sys.argv + + self.exit = exit + self.verbosity = verbosity + self.failfast = failfast + self.catchbreak = catchbreak + self.buffer = buffer + self.defaultTest = defaultTest + self.testRunner = testRunner + self.testLoader = testLoader + self.progName = os.path.basename(argv[0]) + self.parseArgs(argv) + self.runTests() + + def usageExit(self, msg=None): + if msg: + print msg + usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '', + 'buffer': ''} + if self.failfast != False: + usage['failfast'] = FAILFAST + if self.catchbreak != False and installHandler is not None: + usage['catchbreak'] = CATCHBREAK + if self.buffer != False: + usage['buffer'] = BUFFEROUTPUT + print self.USAGE % usage + sys.exit(2) + + def parseArgs(self, argv): + if len(argv) > 1 and argv[1].lower() == 'discover': + self._do_discovery(argv[2:]) + return + + import getopt + long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer'] + try: + options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts) + for opt, value in options: + if opt in ('-h','-H','--help'): + self.usageExit() + if opt in ('-q','--quiet'): + self.verbosity = 0 + if opt in ('-v','--verbose'): + self.verbosity = 2 + if opt in ('-f','--failfast'): + if self.failfast is None: + self.failfast = True + # Should this raise an exception if -f is not valid? + if opt in ('-c','--catch'): + if self.catchbreak is None and installHandler is not None: + self.catchbreak = True + # Should this raise an exception if -c is not valid? + if opt in ('-b','--buffer'): + if self.buffer is None: + self.buffer = True + # Should this raise an exception if -b is not valid? + if len(args) == 0 and self.defaultTest is None: + # createTests will load tests from self.module + self.testNames = None + elif len(args) > 0: + self.testNames = args + if __name__ == '__main__': + # to support python -m unittest ... + self.module = None + else: + self.testNames = (self.defaultTest,) + self.createTests() + except getopt.error, msg: + self.usageExit(msg) + + def createTests(self): + if self.testNames is None: + self.test = self.testLoader.loadTestsFromModule(self.module) + else: + self.test = self.testLoader.loadTestsFromNames(self.testNames, + self.module) + + def _do_discovery(self, argv, Loader=loader.TestLoader): + # handle command line args for test discovery + self.progName = '%s discover' % self.progName + import optparse + parser = optparse.OptionParser() + parser.prog = self.progName + parser.add_option('-v', '--verbose', dest='verbose', default=False, + help='Verbose output', action='store_true') + if self.failfast != False: + parser.add_option('-f', '--failfast', dest='failfast', default=False, + help='Stop on first fail or error', + action='store_true') + if self.catchbreak != False and installHandler is not None: + parser.add_option('-c', '--catch', dest='catchbreak', default=False, + help='Catch ctrl-C and display results so far', + action='store_true') + if self.buffer != False: + parser.add_option('-b', '--buffer', dest='buffer', default=False, + help='Buffer stdout and stderr during tests', + action='store_true') + parser.add_option('-s', '--start-directory', dest='start', default='.', + help="Directory to start discovery ('.' default)") + parser.add_option('-p', '--pattern', dest='pattern', default='test*.py', + help="Pattern to match tests ('test*.py' default)") + parser.add_option('-t', '--top-level-directory', dest='top', default=None, + help='Top level directory of project (defaults to start directory)') + + options, args = parser.parse_args(argv) + if len(args) > 3: + self.usageExit() + + for name, value in zip(('start', 'pattern', 'top'), args): + setattr(options, name, value) + + # only set options from the parsing here + # if they weren't set explicitly in the constructor + if self.failfast is None: + self.failfast = options.failfast + if self.catchbreak is None and installHandler is not None: + self.catchbreak = options.catchbreak + if self.buffer is None: + self.buffer = options.buffer + + if options.verbose: + self.verbosity = 2 + + start_dir = options.start + pattern = options.pattern + top_level_dir = options.top + + loader = Loader() + self.test = loader.discover(start_dir, pattern, top_level_dir) + + def runTests(self): + if self.catchbreak: + installHandler() + if self.testRunner is None: + self.testRunner = runner.TextTestRunner + if isinstance(self.testRunner, (type, types.ClassType)): + try: + testRunner = self.testRunner(verbosity=self.verbosity, + failfast=self.failfast, + buffer=self.buffer) + except TypeError: + # didn't accept the verbosity, buffer or failfast arguments + testRunner = self.testRunner() + else: + # it is assumed to be a TestRunner instance + testRunner = self.testRunner + self.result = testRunner.run(self.test) + if self.exit: + sys.exit(not self.result.wasSuccessful()) + +main = TestProgram + +def main_(): + TestProgram.USAGE = USAGE_AS_MAIN + main(module=None) + diff --git a/tests/vendor/unittest2/result.py b/tests/vendor/unittest2/result.py new file mode 100644 index 0000000..7770e64 --- /dev/null +++ b/tests/vendor/unittest2/result.py @@ -0,0 +1,183 @@ +"""Test result object""" + +import sys +import traceback +import unittest + +from StringIO import StringIO + +from unittest2 import util +from unittest2.compatibility import wraps + +__unittest = True + +def failfast(method): + @wraps(method) + def inner(self, *args, **kw): + if getattr(self, 'failfast', False): + self.stop() + return method(self, *args, **kw) + return inner + + +STDOUT_LINE = '\nStdout:\n%s' +STDERR_LINE = '\nStderr:\n%s' + +class TestResult(unittest.TestResult): + """Holder for test result information. + + Test results are automatically managed by the TestCase and TestSuite + classes, and do not need to be explicitly manipulated by writers of tests. + + Each instance holds the total number of tests run, and collections of + failures and errors that occurred among those test runs. The collections + contain tuples of (testcase, exceptioninfo), where exceptioninfo is the + formatted traceback of the error that occurred. + """ + _previousTestClass = None + _moduleSetUpFailed = False + + def __init__(self): + self.failfast = False + self.failures = [] + self.errors = [] + self.testsRun = 0 + self.skipped = [] + self.expectedFailures = [] + self.unexpectedSuccesses = [] + self.shouldStop = False + self.buffer = False + self._stdout_buffer = None + self._stderr_buffer = None + self._original_stdout = sys.stdout + self._original_stderr = sys.stderr + self._mirrorOutput = False + + def startTest(self, test): + "Called when the given test is about to be run" + self.testsRun += 1 + self._mirrorOutput = False + if self.buffer: + if self._stderr_buffer is None: + self._stderr_buffer = StringIO() + self._stdout_buffer = StringIO() + sys.stdout = self._stdout_buffer + sys.stderr = self._stderr_buffer + + def startTestRun(self): + """Called once before any tests are executed. + + See startTest for a method called before each test. + """ + + def stopTest(self, test): + """Called when the given test has been run""" + if self.buffer: + if self._mirrorOutput: + output = sys.stdout.getvalue() + error = sys.stderr.getvalue() + if output: + if not output.endswith('\n'): + output += '\n' + self._original_stdout.write(STDOUT_LINE % output) + if error: + if not error.endswith('\n'): + error += '\n' + self._original_stderr.write(STDERR_LINE % error) + + sys.stdout = self._original_stdout + sys.stderr = self._original_stderr + self._stdout_buffer.seek(0) + self._stdout_buffer.truncate() + self._stderr_buffer.seek(0) + self._stderr_buffer.truncate() + self._mirrorOutput = False + + + def stopTestRun(self): + """Called once after all tests are executed. + + See stopTest for a method called after each test. + """ + + @failfast + def addError(self, test, err): + """Called when an error has occurred. 'err' is a tuple of values as + returned by sys.exc_info(). + """ + self.errors.append((test, self._exc_info_to_string(err, test))) + self._mirrorOutput = True + + @failfast + def addFailure(self, test, err): + """Called when an error has occurred. 'err' is a tuple of values as + returned by sys.exc_info().""" + self.failures.append((test, self._exc_info_to_string(err, test))) + self._mirrorOutput = True + + def addSuccess(self, test): + "Called when a test has completed successfully" + pass + + def addSkip(self, test, reason): + """Called when a test is skipped.""" + self.skipped.append((test, reason)) + + def addExpectedFailure(self, test, err): + """Called when an expected failure/error occured.""" + self.expectedFailures.append( + (test, self._exc_info_to_string(err, test))) + + @failfast + def addUnexpectedSuccess(self, test): + """Called when a test was expected to fail, but succeed.""" + self.unexpectedSuccesses.append(test) + + def wasSuccessful(self): + "Tells whether or not this result was a success" + return (len(self.failures) + len(self.errors) == 0) + + def stop(self): + "Indicates that the tests should be aborted" + self.shouldStop = True + + def _exc_info_to_string(self, err, test): + """Converts a sys.exc_info()-style tuple of values into a string.""" + exctype, value, tb = err + # Skip test runner traceback levels + while tb and self._is_relevant_tb_level(tb): + tb = tb.tb_next + if exctype is test.failureException: + # Skip assert*() traceback levels + length = self._count_relevant_tb_levels(tb) + msgLines = traceback.format_exception(exctype, value, tb, length) + else: + msgLines = traceback.format_exception(exctype, value, tb) + + if self.buffer: + output = sys.stdout.getvalue() + error = sys.stderr.getvalue() + if output: + if not output.endswith('\n'): + output += '\n' + msgLines.append(STDOUT_LINE % output) + if error: + if not error.endswith('\n'): + error += '\n' + msgLines.append(STDERR_LINE % error) + return ''.join(msgLines) + + def _is_relevant_tb_level(self, tb): + return '__unittest' in tb.tb_frame.f_globals + + def _count_relevant_tb_levels(self, tb): + length = 0 + while tb and not self._is_relevant_tb_level(tb): + length += 1 + tb = tb.tb_next + return length + + def __repr__(self): + return "<%s run=%i errors=%i failures=%i>" % \ + (util.strclass(self.__class__), self.testsRun, len(self.errors), + len(self.failures)) diff --git a/tests/vendor/unittest2/runner.py b/tests/vendor/unittest2/runner.py new file mode 100644 index 0000000..15a6f88 --- /dev/null +++ b/tests/vendor/unittest2/runner.py @@ -0,0 +1,206 @@ +"""Running tests""" + +import sys +import time +import unittest + +from unittest2 import result + +try: + from unittest2.signals import registerResult +except ImportError: + def registerResult(_): + pass + +__unittest = True + + +class _WritelnDecorator(object): + """Used to decorate file-like objects with a handy 'writeln' method""" + def __init__(self,stream): + self.stream = stream + + def __getattr__(self, attr): + if attr in ('stream', '__getstate__'): + raise AttributeError(attr) + return getattr(self.stream,attr) + + def writeln(self, arg=None): + if arg: + self.write(arg) + self.write('\n') # text-mode streams translate to \r\n if needed + + +class TextTestResult(result.TestResult): + """A test result class that can print formatted text results to a stream. + + Used by TextTestRunner. + """ + separator1 = '=' * 70 + separator2 = '-' * 70 + + def __init__(self, stream, descriptions, verbosity): + super(TextTestResult, self).__init__() + self.stream = stream + self.showAll = verbosity > 1 + self.dots = verbosity == 1 + self.descriptions = descriptions + + def getDescription(self, test): + doc_first_line = test.shortDescription() + if self.descriptions and doc_first_line: + return '\n'.join((str(test), doc_first_line)) + else: + return str(test) + + def startTest(self, test): + super(TextTestResult, self).startTest(test) + if self.showAll: + self.stream.write(self.getDescription(test)) + self.stream.write(" ... ") + self.stream.flush() + + def addSuccess(self, test): + super(TextTestResult, self).addSuccess(test) + if self.showAll: + self.stream.writeln("ok") + elif self.dots: + self.stream.write('.') + self.stream.flush() + + def addError(self, test, err): + super(TextTestResult, self).addError(test, err) + if self.showAll: + self.stream.writeln("ERROR") + elif self.dots: + self.stream.write('E') + self.stream.flush() + + def addFailure(self, test, err): + super(TextTestResult, self).addFailure(test, err) + if self.showAll: + self.stream.writeln("FAIL") + elif self.dots: + self.stream.write('F') + self.stream.flush() + + def addSkip(self, test, reason): + super(TextTestResult, self).addSkip(test, reason) + if self.showAll: + self.stream.writeln("skipped %r" % (reason,)) + elif self.dots: + self.stream.write("s") + self.stream.flush() + + def addExpectedFailure(self, test, err): + super(TextTestResult, self).addExpectedFailure(test, err) + if self.showAll: + self.stream.writeln("expected failure") + elif self.dots: + self.stream.write("x") + self.stream.flush() + + def addUnexpectedSuccess(self, test): + super(TextTestResult, self).addUnexpectedSuccess(test) + if self.showAll: + self.stream.writeln("unexpected success") + elif self.dots: + self.stream.write("u") + self.stream.flush() + + def printErrors(self): + if self.dots or self.showAll: + self.stream.writeln() + self.printErrorList('ERROR', self.errors) + self.printErrorList('FAIL', self.failures) + + def printErrorList(self, flavour, errors): + for test, err in errors: + self.stream.writeln(self.separator1) + self.stream.writeln("%s: %s" % (flavour, self.getDescription(test))) + self.stream.writeln(self.separator2) + self.stream.writeln("%s" % err) + + def stopTestRun(self): + super(TextTestResult, self).stopTestRun() + self.printErrors() + + +class TextTestRunner(unittest.TextTestRunner): + """A test runner class that displays results in textual form. + + It prints out the names of tests as they are run, errors as they + occur, and a summary of the results at the end of the test run. + """ + resultclass = TextTestResult + + def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1, + failfast=False, buffer=False, resultclass=None): + self.stream = _WritelnDecorator(stream) + self.descriptions = descriptions + self.verbosity = verbosity + self.failfast = failfast + self.buffer = buffer + if resultclass is not None: + self.resultclass = resultclass + + def _makeResult(self): + return self.resultclass(self.stream, self.descriptions, self.verbosity) + + def run(self, test): + "Run the given test case or test suite." + result = self._makeResult() + result.failfast = self.failfast + result.buffer = self.buffer + registerResult(result) + + startTime = time.time() + startTestRun = getattr(result, 'startTestRun', None) + if startTestRun is not None: + startTestRun() + try: + test(result) + finally: + stopTestRun = getattr(result, 'stopTestRun', None) + if stopTestRun is not None: + stopTestRun() + else: + result.printErrors() + stopTime = time.time() + timeTaken = stopTime - startTime + if hasattr(result, 'separator2'): + self.stream.writeln(result.separator2) + run = result.testsRun + self.stream.writeln("Ran %d test%s in %.3fs" % + (run, run != 1 and "s" or "", timeTaken)) + self.stream.writeln() + + expectedFails = unexpectedSuccesses = skipped = 0 + try: + results = map(len, (result.expectedFailures, + result.unexpectedSuccesses, + result.skipped)) + expectedFails, unexpectedSuccesses, skipped = results + except AttributeError: + pass + infos = [] + if not result.wasSuccessful(): + self.stream.write("FAILED") + failed, errored = map(len, (result.failures, result.errors)) + if failed: + infos.append("failures=%d" % failed) + if errored: + infos.append("errors=%d" % errored) + else: + self.stream.write("OK") + if skipped: + infos.append("skipped=%d" % skipped) + if expectedFails: + infos.append("expected failures=%d" % expectedFails) + if unexpectedSuccesses: + infos.append("unexpected successes=%d" % unexpectedSuccesses) + if infos: + self.stream.writeln(" (%s)" % (", ".join(infos),)) + else: + self.stream.write("\n") + return result diff --git a/tests/vendor/unittest2/signals.py b/tests/vendor/unittest2/signals.py new file mode 100644 index 0000000..e40328d --- /dev/null +++ b/tests/vendor/unittest2/signals.py @@ -0,0 +1,57 @@ +import signal +import weakref + +from unittest2.compatibility import wraps + +__unittest = True + + +class _InterruptHandler(object): + def __init__(self, default_handler): + self.called = False + self.default_handler = default_handler + + def __call__(self, signum, frame): + installed_handler = signal.getsignal(signal.SIGINT) + if installed_handler is not self: + # if we aren't the installed handler, then delegate immediately + # to the default handler + self.default_handler(signum, frame) + + if self.called: + self.default_handler(signum, frame) + self.called = True + for result in _results.keys(): + result.stop() + +_results = weakref.WeakKeyDictionary() +def registerResult(result): + _results[result] = 1 + +def removeResult(result): + return bool(_results.pop(result, None)) + +_interrupt_handler = None +def installHandler(): + global _interrupt_handler + if _interrupt_handler is None: + default_handler = signal.getsignal(signal.SIGINT) + _interrupt_handler = _InterruptHandler(default_handler) + signal.signal(signal.SIGINT, _interrupt_handler) + + +def removeHandler(method=None): + if method is not None: + @wraps(method) + def inner(*args, **kwargs): + initial = signal.getsignal(signal.SIGINT) + removeHandler() + try: + return method(*args, **kwargs) + finally: + signal.signal(signal.SIGINT, initial) + return inner + + global _interrupt_handler + if _interrupt_handler is not None: + signal.signal(signal.SIGINT, _interrupt_handler.default_handler) diff --git a/tests/vendor/unittest2/suite.py b/tests/vendor/unittest2/suite.py new file mode 100644 index 0000000..370ca5f --- /dev/null +++ b/tests/vendor/unittest2/suite.py @@ -0,0 +1,287 @@ +"""TestSuite""" + +import sys +import unittest +from unittest2 import case, util + +__unittest = True + + +class BaseTestSuite(unittest.TestSuite): + """A simple test suite that doesn't provide class or module shared fixtures. + """ + def __init__(self, tests=()): + self._tests = [] + self.addTests(tests) + + def __repr__(self): + return "<%s tests=%s>" % (util.strclass(self.__class__), list(self)) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return list(self) == list(other) + + def __ne__(self, other): + return not self == other + + # Can't guarantee hash invariant, so flag as unhashable + __hash__ = None + + def __iter__(self): + return iter(self._tests) + + def countTestCases(self): + cases = 0 + for test in self: + cases += test.countTestCases() + return cases + + def addTest(self, test): + # sanity checks + if not hasattr(test, '__call__'): + raise TypeError("%r is not callable" % (repr(test),)) + if isinstance(test, type) and issubclass(test, + (case.TestCase, TestSuite)): + raise TypeError("TestCases and TestSuites must be instantiated " + "before passing them to addTest()") + self._tests.append(test) + + def addTests(self, tests): + if isinstance(tests, basestring): + raise TypeError("tests must be an iterable of tests, not a string") + for test in tests: + self.addTest(test) + + def run(self, result): + for test in self: + if result.shouldStop: + break + test(result) + return result + + def __call__(self, *args, **kwds): + return self.run(*args, **kwds) + + def debug(self): + """Run the tests without collecting errors in a TestResult""" + for test in self: + test.debug() + + +class TestSuite(BaseTestSuite): + """A test suite is a composite test consisting of a number of TestCases. + + For use, create an instance of TestSuite, then add test case instances. + When all tests have been added, the suite can be passed to a test + runner, such as TextTestRunner. It will run the individual test cases + in the order in which they were added, aggregating the results. When + subclassing, do not forget to call the base class constructor. + """ + + + def run(self, result): + self._wrapped_run(result) + self._tearDownPreviousClass(None, result) + self._handleModuleTearDown(result) + return result + + def debug(self): + """Run the tests without collecting errors in a TestResult""" + debug = _DebugResult() + self._wrapped_run(debug, True) + self._tearDownPreviousClass(None, debug) + self._handleModuleTearDown(debug) + + ################################ + # private methods + def _wrapped_run(self, result, debug=False): + for test in self: + if result.shouldStop: + break + + if _isnotsuite(test): + self._tearDownPreviousClass(test, result) + self._handleModuleFixture(test, result) + self._handleClassSetUp(test, result) + result._previousTestClass = test.__class__ + + if (getattr(test.__class__, '_classSetupFailed', False) or + getattr(result, '_moduleSetUpFailed', False)): + continue + + if hasattr(test, '_wrapped_run'): + test._wrapped_run(result, debug) + elif not debug: + test(result) + else: + test.debug() + + def _handleClassSetUp(self, test, result): + previousClass = getattr(result, '_previousTestClass', None) + currentClass = test.__class__ + if currentClass == previousClass: + return + if result._moduleSetUpFailed: + return + if getattr(currentClass, "__unittest_skip__", False): + return + + try: + currentClass._classSetupFailed = False + except TypeError: + # test may actually be a function + # so its class will be a builtin-type + pass + + setUpClass = getattr(currentClass, 'setUpClass', None) + if setUpClass is not None: + try: + setUpClass() + except Exception, e: + if isinstance(result, _DebugResult): + raise + currentClass._classSetupFailed = True + className = util.strclass(currentClass) + errorName = 'setUpClass (%s)' % className + self._addClassOrModuleLevelException(result, e, errorName) + + def _get_previous_module(self, result): + previousModule = None + previousClass = getattr(result, '_previousTestClass', None) + if previousClass is not None: + previousModule = previousClass.__module__ + return previousModule + + + def _handleModuleFixture(self, test, result): + previousModule = self._get_previous_module(result) + currentModule = test.__class__.__module__ + if currentModule == previousModule: + return + + self._handleModuleTearDown(result) + + + result._moduleSetUpFailed = False + try: + module = sys.modules[currentModule] + except KeyError: + return + setUpModule = getattr(module, 'setUpModule', None) + if setUpModule is not None: + try: + setUpModule() + except Exception, e: + if isinstance(result, _DebugResult): + raise + result._moduleSetUpFailed = True + errorName = 'setUpModule (%s)' % currentModule + self._addClassOrModuleLevelException(result, e, errorName) + + def _addClassOrModuleLevelException(self, result, exception, errorName): + error = _ErrorHolder(errorName) + addSkip = getattr(result, 'addSkip', None) + if addSkip is not None and isinstance(exception, case.SkipTest): + addSkip(error, str(exception)) + else: + result.addError(error, sys.exc_info()) + + def _handleModuleTearDown(self, result): + previousModule = self._get_previous_module(result) + if previousModule is None: + return + if result._moduleSetUpFailed: + return + + try: + module = sys.modules[previousModule] + except KeyError: + return + + tearDownModule = getattr(module, 'tearDownModule', None) + if tearDownModule is not None: + try: + tearDownModule() + except Exception, e: + if isinstance(result, _DebugResult): + raise + errorName = 'tearDownModule (%s)' % previousModule + self._addClassOrModuleLevelException(result, e, errorName) + + def _tearDownPreviousClass(self, test, result): + previousClass = getattr(result, '_previousTestClass', None) + currentClass = test.__class__ + if currentClass == previousClass: + return + if getattr(previousClass, '_classSetupFailed', False): + return + if getattr(result, '_moduleSetUpFailed', False): + return + if getattr(previousClass, "__unittest_skip__", False): + return + + tearDownClass = getattr(previousClass, 'tearDownClass', None) + if tearDownClass is not None: + try: + tearDownClass() + except Exception, e: + if isinstance(result, _DebugResult): + raise + className = util.strclass(previousClass) + errorName = 'tearDownClass (%s)' % className + self._addClassOrModuleLevelException(result, e, errorName) + + +class _ErrorHolder(object): + """ + Placeholder for a TestCase inside a result. As far as a TestResult + is concerned, this looks exactly like a unit test. Used to insert + arbitrary errors into a test suite run. + """ + # Inspired by the ErrorHolder from Twisted: + # http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py + + # attribute used by TestResult._exc_info_to_string + failureException = None + + def __init__(self, description): + self.description = description + + def id(self): + return self.description + + def shortDescription(self): + return None + + def __repr__(self): + return "" % (self.description,) + + def __str__(self): + return self.id() + + def run(self, result): + # could call result.addError(...) - but this test-like object + # shouldn't be run anyway + pass + + def __call__(self, result): + return self.run(result) + + def countTestCases(self): + return 0 + +def _isnotsuite(test): + "A crude way to tell apart testcases and suites with duck-typing" + try: + iter(test) + except TypeError: + return True + return False + + +class _DebugResult(object): + "Used by the TestSuite to hold previous class when running in debug." + _previousTestClass = None + _moduleSetUpFailed = False + shouldStop = False diff --git a/tests/vendor/unittest2/util.py b/tests/vendor/unittest2/util.py new file mode 100644 index 0000000..c45d008 --- /dev/null +++ b/tests/vendor/unittest2/util.py @@ -0,0 +1,99 @@ +"""Various utility functions.""" + +__unittest = True + + +_MAX_LENGTH = 80 +def safe_repr(obj, short=False): + try: + result = repr(obj) + except Exception: + result = object.__repr__(obj) + if not short or len(result) < _MAX_LENGTH: + return result + return result[:_MAX_LENGTH] + ' [truncated]...' + +def safe_str(obj): + try: + return str(obj) + except Exception: + return object.__str__(obj) + +def strclass(cls): + return "%s.%s" % (cls.__module__, cls.__name__) + +def sorted_list_difference(expected, actual): + """Finds elements in only one or the other of two, sorted input lists. + + Returns a two-element tuple of lists. The first list contains those + elements in the "expected" list but not in the "actual" list, and the + second contains those elements in the "actual" list but not in the + "expected" list. Duplicate elements in either input list are ignored. + """ + i = j = 0 + missing = [] + unexpected = [] + while True: + try: + e = expected[i] + a = actual[j] + if e < a: + missing.append(e) + i += 1 + while expected[i] == e: + i += 1 + elif e > a: + unexpected.append(a) + j += 1 + while actual[j] == a: + j += 1 + else: + i += 1 + try: + while expected[i] == e: + i += 1 + finally: + j += 1 + while actual[j] == a: + j += 1 + except IndexError: + missing.extend(expected[i:]) + unexpected.extend(actual[j:]) + break + return missing, unexpected + +def unorderable_list_difference(expected, actual, ignore_duplicate=False): + """Same behavior as sorted_list_difference but + for lists of unorderable items (like dicts). + + As it does a linear search per item (remove) it + has O(n*n) performance. + """ + missing = [] + unexpected = [] + while expected: + item = expected.pop() + try: + actual.remove(item) + except ValueError: + missing.append(item) + if ignore_duplicate: + for lst in expected, actual: + try: + while True: + lst.remove(item) + except ValueError: + pass + if ignore_duplicate: + while actual: + item = actual.pop() + unexpected.append(item) + try: + while True: + actual.remove(item) + except ValueError: + pass + return missing, unexpected + + # anything left in actual is unexpected + return missing, actual diff --git a/tests/x509.der b/tests/x509.der index fbc9e813e9b3a45d2e2489895e3ea71e430cc52a..e3d1f116d837af9cbda07539c9efda1ec206fe7b 100644 GIT binary patch literal 830 zcmXqLVzx49Vp3Yb%*4n9L*4Eznb4LI4DLs{5_nL>jNg$)Ej z91b2X=fs@MwEUvH%tS*$1AdSo7Y~Q8k#kXHK}o)$gn<}Hh?$4qBQ-NSJ5wPfKeH@9 zFE!6VPMp`!!qC9L+|bm}$iOH{oYx4%HGy&sT*$MK*MJ*hAxng*fu%tcqY|=D7+D#Z zn;7{SfZ|+CO^l2T?$e=`_BYtR1mFR&TM%gsLYA>!aR( zl+=2;UBdZuV_dn9WK%wam*W)8C@yEIB`*(qtVm-y_3jnpwh$&cH>rj9!Y;aJujW*^ zn!I_-@s_McTysQrUv}7Au1DZqA-5CUM;{n(xVz+4oiyioVxv$vke#^o!qd>iKzF zMg6Oe>9QnF4k=N)e@03B`=J+XEZj`Yj0}v6bqut?kt-|A!eqc;APWpZSw0pq7Lm1@ zCVhQTU6adf-pbFunBT$ZN(|s(TD4vgKMFX#2AEedNbq z-#@Cc_%EL1`>H0ZZ;Ef^`B1w{ijoiC$TM~ZH^|u@RCXz}{owq??)Wu6*QAvCjKcPR zYVk{j&#|sclhXPy!z)Qy(naY!zr{Y@Hwk}TKWiR3`&BmAg;j9PrN#Qm_HlJ4How0W z=&!pRAQm1TvCDBm>Sx!L-`43b>~C&~^eR0Pu_@bot7?4Ig1a{*9$jAb&x)Hovm literal 656 zcmXqLV(KwyV*I**nTe5!iId^tw*Bkb#C!G|@Un4gwRyCC=VfGMWo0n%H{>?pWMd9x zVH0Kw4K@@u5Cm~Jgt?p(b28KNi}ErP4FwJOL4sVu9KJ@*MU@35`Gyh(Vjv-AVSbO) z%Krvi!W%JOep#UIR-5b0Z4_6JsEZ66ZApam}Dy0~hiv`z+Cb9eLCPl~&% zUb3fxOMSJBp0bQuxyQDC=J(+;3qsaOz4)rK&~2f*N2u|PKew}*^*Zeze4aS>mjCUN z33HeAdbypRziUUr{dMn@yzLu8zsq*oXlvYele{Xi<|VtILu2WlThUh^9%2z?VrFDu zTwHBX2@Y6UVHPF>1_K>7&V)7(#S{J__!sd8tK-C8;S2&Z$Ku znQ58HK#qYd(66$5EMhDo8;|7A$bVtovrtX2ar!Kw057SW4g-0Rv@#1Y5*kF-rnr{$ zHy_uzdVN9bL;;6cbEchtha5J*NM;5Giaoc>o=dmlS6c4l2!8fg;QzG`ivz#yV^%n` zIp{opjeVF?{@kM3oJ&*eoi$aouT@S7(VzL^+`qr~cAs+A5c_Ym#`b8~?RI6GE1BQ@ zq>t=7c|(1sR?0rB?7G0#+oh%sOLNu*ALe|{U@D#>C0=;+YUI=YKhwN^HX1AY984&j IEWvdI0C0HSng9R* diff --git a/tests/x509.pem b/tests/x509.pem index 4a1f1ee..bd13265 100644 --- a/tests/x509.pem +++ b/tests/x509.pem @@ -1,75 +1,101 @@ Certificate: Data: Version: 3 (0x2) - Serial Number: - d1:b6:bf:af:06:17:8c:bf - Signature Algorithm: sha1WithRSAEncryption + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity - Not Before: Jul 28 04:34:34 2009 GMT - Not After : Jul 26 04:34:34 2019 GMT + Not Before: Oct 7 15:12:02 2018 GMT + Not After : Oct 4 15:12:02 2028 GMT Subject: C=US, ST=California, O=M2Crypto, CN=X509 Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public Key: (1024 bit) - Modulus (1024 bit): - 00:d3:62:55:12:30:b8:dc:84:7c:63:bd:80:1d:19: - 1a:72:f2:28:f8:59:0b:2a:6b:f2:2a:23:9d:bb:0f: - 7f:92:5e:dd:27:74:bc:78:0a:27:ab:1c:2e:23:1c: - 26:77:48:b6:8f:03:ef:57:1c:a0:54:ae:1a:e8:f5: - 24:a1:46:a1:27:48:55:33:98:fc:db:6a:83:2e:89: - 3f:e0:f3:91:9d:da:4f:db:74:90:9d:a6:8d:4a:46: - cb:9f:ba:b8:60:df:ae:ee:22:4b:3f:80:55:f7:1d: - 89:3c:2b:28:df:46:19:d5:18:ac:e9:07:4e:40:81: - 75:bc:da:5b:d5:e1:c2:04:15 + RSA Public-Key: (2048 bit) + Modulus: + 00:ef:90:05:eb:97:7f:e3:10:d7:09:f4:1d:64:2a: + 21:d2:ba:39:e6:2c:81:ea:93:2b:58:af:5d:2e:a3: + 34:90:7a:e4:60:af:5a:ef:f1:19:2a:e9:b7:18:43: + f3:81:5e:77:4c:19:82:6f:00:4a:41:94:29:5a:0a: + 43:1a:a4:e9:c3:48:a8:66:04:ca:ee:ea:01:b6:54: + 02:1e:46:1a:a1:de:56:d1:47:6b:ab:09:20:d5:63: + b3:b4:c7:84:bd:02:1d:79:56:8a:f1:f4:d6:27:72: + b4:15:d2:5f:7a:73:db:d0:8f:0a:51:05:be:e7:79: + 0b:39:2a:d6:65:89:7d:d3:93:b5:25:8d:ce:9e:bb: + 67:7b:39:4a:83:2e:5d:e2:de:fd:e9:30:81:51:f4: + 1b:34:4b:d2:76:a0:9f:38:a8:53:6e:d9:9b:99:16: + 18:d7:41:5b:0e:e4:e4:a7:4c:cd:38:d3:ae:24:a0: + ce:0f:1e:4f:25:24:a3:31:e6:94:97:92:f8:f5:4b: + 48:4b:5b:c1:cc:95:b8:4d:c6:66:c1:5c:3e:24:4f: + b4:f3:98:f5:03:91:43:9b:de:a8:71:15:ef:2d:84: + 69:c7:35:02:fa:0f:41:95:cf:9e:b5:15:4f:7a:c6: + 2d:04:61:93:54:74:26:df:cc:22:2b:f7:c2:e8:06: + 04:0b Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE - Netscape Comment: - OpenSSL Generated Certificate X509v3 Subject Key Identifier: - B1:C4:6F:98:6F:E8:3B:8C:A1:26:11:81:97:9A:12:50:4A:1A:6C:88 - X509v3 Authority Key Identifier: - keyid:AD:64:45:74:8F:83:C7:2C:D5:D7:A0:85:91:10:40:9A:9C:96:CF:EE - - Signature Algorithm: sha1WithRSAEncryption - 3f:0b:44:bc:d2:da:5f:a9:39:be:08:53:e6:fd:10:ff:d6:f0: - a3:51:f6:be:03:20:cc:b3:52:cf:0f:7c:3f:56:42:6f:9d:72: - 9b:09:a5:64:3f:43:29:24:2b:d6:79:94:54:2f:99:e8:ce:fe: - fd:de:bb:ca:43:28:16:ff:32:ac:3d:c5:56:db:87:23:3c:d4: - 69:f7:4e:1b:c4:be:c9:d8:27:99:2a:64:be:3a:6b:7e:51:85: - db:75:35:40:a5:6c:ae:53:c3:09:e7:00:35:17:64:1a:17:71: - c5:d5:59:e5:8f:fc:96:4a:f9:81:33:23:4c:c1:60:71:93:18: - 0a:c4 + AD:29:34:8E:8E:5A:8A:93:76:3C:ED:9F:2C:E6:6A:18:D2:D0:AF:C2 + Signature Algorithm: sha256WithRSAEncryption + 35:d2:e4:c4:eb:01:ea:25:bc:31:91:06:6d:38:c0:86:f4:ad: + ef:59:f1:fa:f7:f1:26:04:4f:a3:92:4d:ea:7c:6a:8e:94:4d: + 59:cf:55:3e:d2:21:19:e1:ec:1f:01:89:53:80:1e:3d:c1:23: + 44:71:3d:f0:43:f4:3e:c7:d6:0e:45:62:64:7f:68:71:87:fe: + 26:5f:a5:13:ce:05:ae:66:1a:2a:f0:98:4a:62:23:19:44:22: + cf:0f:38:be:0d:ec:60:fd:45:f3:29:c2:cd:f5:1d:6d:44:05: + 11:ac:d2:a3:2f:63:3f:5e:7e:34:3c:fb:f6:70:2f:ae:d3:50: + 16:57:57:58:ba:41:a0:65:f3:45:a9:f6:ae:2f:a1:8f:83:84: + 59:4a:75:c4:58:b2:6b:4b:b5:25:5f:5a:a0:dd:d9:18:e2:d7: + a9:5a:da:0a:83:15:ab:08:a7:98:86:e2:fa:ba:4f:47:70:b6: + 90:70:8d:05:ca:08:a9:94:be:27:af:43:a9:6e:ec:12:6a:b2: + 8e:83:26:b8:72:cd:63:9b:19:a1:c9:ff:b2:c5:cf:ec:ce:7a: + 13:b8:dd:06:9f:55:85:0d:23:a1:ae:5e:50:67:57:b4:8d:e3: + 49:0f:c0:ee:42:06:64:6d:72:c4:7b:2b:7d:87:28:17:36:59: + 01:44:dc:38 -----BEGIN CERTIFICATE----- -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 +csR7K32HKBc2WQFE3Dg= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/tests/x509_key.pem b/tests/x509_key.pem new file mode 100644 index 0000000..0615b4d --- /dev/null +++ b/tests/x509_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA75AF65d/4xDXCfQdZCoh0ro55iyB6pMrWK9dLqM0kHrkYK9a +7/EZKum3GEPzgV53TBmCbwBKQZQpWgpDGqTpw0ioZgTK7uoBtlQCHkYaod5W0Udr +qwkg1WOztMeEvQIdeVaK8fTWJ3K0FdJfenPb0I8KUQW+53kLOSrWZYl905O1JY3O +nrtnezlKgy5d4t796TCBUfQbNEvSdqCfOKhTbtmbmRYY10FbDuTkp0zNONOuJKDO +Dx5PJSSjMeaUl5L49UtIS1vBzJW4TcZmwVw+JE+085j1A5FDm96ocRXvLYRpxzUC ++g9Blc+etRVPesYtBGGTVHQm38wiK/fC6AYECwIDAQABAoIBAQCR6lmQzDB7L9Cr +IWOdlQQRBJkrl8RyCr4GQJozQ/lKX3Ana+ep6mJ3/u8k+o6hJ9bmJUuLLNQN6Z7e +Vw3Udspjxie8LAMnTqVIVxcLNYwXOAQNaMEt5lt3XkkhPb2eGmG1fH8ZLRYb5QPH +nuHFBjjHabjQ7P0ApHuvkGYSZpKbgVjEIwWxCPlzMo0XmePK0dJVAxsmtNFSoJkD +6UOwX8HN79thbSLwyCSnUUkHbglHLqgBvgLY4uW7BBMuFFW6v1jp1YR3gqhzrHgW +q43WIOEJBBvoI1it8TA7N28IjiA/G+DKeM3KNYAc5m30iXtq+ky/G9xdrhOEDZTs +mj4JInkhAoGBAPwZAmT1aZuftPp90IRATESrxGo0n1uZsF9CBur8+dZKPTgGrtfJ +e+1yh+LKvowY0a4B82nehq0FcHsSjBHXRbwgHd4KSYV0LCc5ZwxQlPg9FKtziFmm +RYPGanpNEdJ8tz0Wj67gP2aIHRaauFxTwSoXyfvrYLWHnvMotUH6QOejAoGBAPNF +VzyJwzdT8WKx8CaWmIoSglE0wIcRtnOgHxZUuNnxdjjnRYgMQDE3GaDnK0TzyH4c +3ewasxCVnfqTR9zPeyu3AdeaxWgOJGirYPQM3qxv85n/7BKGeBoAA3yf9kEpIw9h +M80i1VfgXaRJ+ldwMgVJu5klG0jm/YCFzF6O7dh5AoGANUG/TL6/qb3KiOSNaXL/ +6b3zx5AIXlyQcv9K4NfCm++hETXwN+v7v0TjyhiUupn/qegFmUcGYoT0pzta1eYJ +eF28kYzQzV2mej7ZMzPO1MZqmHHWy0GiC92d3uprKnFocIJUplf/bNSyeHUFH5Qe +CZtu80ZdbtwQy0O9TwvkLEsCgYEAx6qcBUYVAi5Vqunc7+8e2ASFDV28v5+cHp7H +pS54Yfk7TU0U1qsnbL2KvXO/IeLtJgVPaGAppG0Iswd7LhLlR2X3jxyq9dLVs0sm +UmjVwrZIPJe/DR1tKfnk4r7wAV9gNVlUiQQUEwJGGXfWjzm49HomDXZVRKrCWmB2 +8w1gzhECgYBAKhY8brV3bKSKarmlqWV4bhFuxZ8BpY9e3l0MxX3/eHqdimbQEptA +Q6aownp7nurRf9i1m8u1+zbp6efcweEaA9BR+bX0gaGgbDhUY1dQ0/YLUX1Pv5OE +zxCUdc9xW3qTt9Pp/kglGCqM7Nrm71cV86FDHbjDUwY5MzvD1ZLQWg== +-----END RSA PRIVATE KEY----- -- 2.34.1