-
-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CHANGE EVERYTHING #4
Merged
Merged
Changes from 13 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
cdd8dbd
Factor out generic SSL connection logic from stdlib ssl test
njsmith 6691e52
Break convenience API, and add PyOpenSSL support
njsmith 389c29f
Test error handling on unrecognized context types
njsmith 3a767bd
Make tests more robust
njsmith 8586e88
Break *all* the API!
njsmith 098cf9a
Add docs
njsmith 9227e64
CI gunk for docs
njsmith 37b2ce3
Add tests for trustme.Blob
njsmith 7f6885a
[travis] Fix set -u pickiness
njsmith 70a742c
[travis] Fix pip syntax
njsmith 88499b4
[docs] Fix example path
njsmith 4a27d0a
[docs] Add .gitkeep to docs/source/_static/
njsmith 4233322
Tweak wording in example.
njsmith 58b530a
Delete commented-out code
njsmith 6ef9a54
Slightly more careful logic in .tempfile method
njsmith File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,17 @@ | ||
trustme: #1 quality TLS certs while you wait | ||
============================================ | ||
.. note that this README gets 'include'ed into the main documentation | ||
|
||
============================================== | ||
trustme: #1 quality TLS certs while you wait | ||
============================================== | ||
|
||
.. image:: https://vignette2.wikia.nocookie.net/jadensadventures/images/1/1e/Kaa%27s_hypnotic_eyes.jpg/revision/latest?cb=20140310173415 | ||
:width: 200px | ||
:align: right | ||
|
||
You wrote a cool network client or server. You encrypt your | ||
connections using `TLS | ||
You wrote a cool network client or server. It encrypts connections | ||
using `TLS | ||
<https://en.wikipedia.org/wiki/Transport_Layer_Security>`__. Your test | ||
suite needs to make TLS connections. | ||
suite needs to make TLS connections to itself. | ||
|
||
Uh oh. Your test suite *probably* doesn't have a valid TLS | ||
certificate. Now what? | ||
|
@@ -21,95 +24,65 @@ just signed by your CA, which nobody trusts. But you can trust | |
it. Trust me. | ||
|
||
|
||
Example | ||
======= | ||
Vital statistics | ||
================ | ||
|
||
**Install:** ``pip install -U trustme`` | ||
|
||
**Documentation:** https://trustme.readthedocs.io | ||
|
||
**Bug tracker and source code:** https://github.com/python-trio/trustme | ||
|
||
**Tested on:** Python 2.7 and Python 3.5+, CPython and PyPy | ||
|
||
**License:** MIT or Apache 2, your choice. | ||
|
||
**Code of conduct:** Contributors are requested to follow our `code of | ||
conduct | ||
<https://github.com/python-trio/trustme/blob/master/CODE_OF_CONDUCT.md>`__ | ||
in all project spaces. | ||
|
||
|
||
Cheat sheet | ||
=========== | ||
|
||
.. code-block:: python | ||
|
||
from trustme import CA | ||
import trustme | ||
|
||
# Look, you just became a certificate authority | ||
ca = CA() | ||
# ----- Creating certs ----- | ||
|
||
# Issue a server cert, signed by your fake CA | ||
# Look, you just created your own certificate authority! | ||
ca = trustme.CA() | ||
|
||
# And now you issued a cert signed by this fake CA | ||
# https://en.wikipedia.org/wiki/Example.org | ||
server_cert = ca.issue_server_cert(u"my-test-host.example.org") | ||
|
||
# That's it! You have your certs. Now let's see how to use them. | ||
|
||
########### | ||
|
||
# The simplest thing to do is to take the raw PEM certificates, and | ||
# write them out to some files. Maybe this is useful if you want to | ||
# use them for a test suite written in some other language. | ||
|
||
with open("fake-ca.pem", "wb") as f: | ||
f.write(ca.cert_pem) | ||
with open("fake-server-private-key-and-cert-chain.pem", "wb") as f: | ||
f.write(server_cert.private_key_and_cert_chain_pem) | ||
|
||
########### | ||
|
||
# Or, you can use them directly, for example to make a within-process | ||
# connection between two threads. | ||
|
||
import ssl, socket, threading | ||
|
||
# Client side | ||
def fake_ssl_client(raw_client_sock): | ||
# Get an ssl.SSLContext object configured to trust your CA | ||
ssl_ctx = ca.stdlib_client_context() | ||
wrapped_client_sock = ssl_ctx.wrap_socket( | ||
raw_client_sock, server_hostname="my-test-host.example.org") | ||
# Look, here's the cert presented by the server | ||
print("Client got server cert:", wrapped_client_sock.getpeercert()) | ||
# Send some data to prove the connection is good | ||
wrapped_client_sock.send(b"x") | ||
|
||
# Server side | ||
def fake_ssl_server(raw_server_sock): | ||
# Get an ssl.SSLContext object configured to use your server cert | ||
ssl_ctx = server_cert.stdlib_server_context() | ||
wrapped_server_sock = ssl_ctx.wrap_socket(raw_server_sock, server_side=True) | ||
# Prove that we're connected | ||
print("server encrypted with:", wrapped_server_sock.cipher()) | ||
assert wrapped_server_sock.recv(1) == b"x" | ||
|
||
# Blah blah blah actually run the things | ||
raw_client_sock, raw_server_sock = socket.socketpair() | ||
client_thread = threading.Thread(target=fake_ssl_client, args=(raw_client_sock,)) | ||
server_thread = threading.Thread(target=fake_ssl_server, args=(raw_server_sock,)) | ||
client_thread.start() | ||
server_thread.start() | ||
client_thread.join() | ||
server_thread.join() | ||
|
||
|
||
Docs | ||
==== | ||
|
||
``CA()`` gives you a certificate authority. It has attributes | ||
``.cert_pem`` which is a bytestring containing what it sounds like, | ||
``.issue_server_cert(hostname1, [hostname2, ...])`` which does what it | ||
says on the tin, and ``.stdlib_client_context()``, which is a | ||
convenience method that returns an ``ssl.SSLContext`` object | ||
preconfigured to trust this CA. | ||
|
||
``CA.issue_server_cert`` returns a ``ServerCert`` object, which has | ||
attributes ``.private_key_pem``, ``.cert_chain_pem``, and | ||
``.private_key_and_cert_chain_pem``, which are bytestrings containing | ||
what they sound like. It also has a convenience method | ||
``.stdlib_server_context()`` which returns an ``ssl.SSLContext`` | ||
object preconfigured to present this cert to any client that | ||
connects. | ||
|
||
The ``.stdlib_*_context`` methods accept ``**kwargs``, which are | ||
passed on to `ssl.create_default_context | ||
<https://docs.python.org/3/library/ssl.html#ssl.create_default_context>`__. | ||
|
||
Probably this should get moved into Sphinx or something but whatever, | ||
hopefully you get the idea. Or feel free to send a PR converting this | ||
into proper docs. | ||
server_cert = ca.issue_server_cert(u"test-host.example.org") | ||
|
||
# That's it! | ||
|
||
# ----- Using your shiny new certs ----- | ||
|
||
# You can configure SSL context objects to trust this CA: | ||
ca.configure_trust(ssl_context) | ||
# Or configure them to present the server certificate | ||
server_cert.configure_cert(ssl_context) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
# You can use standard library or PyOpenSSL context objects here, | ||
# trustme is happy either way. | ||
|
||
# ----- or ----- | ||
|
||
# Save the PEM-encoded data to a file to use in non-Python test | ||
# suites: | ||
ca.cert_pem.write_to_path("ca.pem") | ||
server_cert.private_key_and_cert_chain_pem.write_to_path("server.pem") | ||
|
||
# ----- or ----- | ||
|
||
# Put the PEM-encoded data in a temporary file, for libraries that | ||
# insist on that: | ||
with ca.cert_pem.tempfile() as ca_temp_path: | ||
requests.get(..., verify=ca_temp_path) | ||
|
||
|
||
FAQ | ||
|
@@ -124,40 +97,13 @@ run in production, and you would *never* disable your certificate | |
validation code in production, right? Plus they're just as easy to | ||
work with. Maybe easier. | ||
|
||
**Why do you only have convenience methods for the stdlib ssl module, | ||
and not PyOpenSSL / Twisted / ...?** Because you didn't send me a PR | ||
yet. | ||
|
||
**I want to test some weirdo TLS configuration.** I'm happy to accept | ||
PRs to do simple things like override the default validity period or | ||
set key sizes or whatever, within reason. But if you have complicated | ||
needs then you're probably better offer stealing the code from this | ||
library and adapting it to do what you want. The underlying API is | ||
pretty straightforward. This is just a convenience library for those | ||
of us who need a cheat sheet to tie our shoelaces, X.509-wise. | ||
|
||
|
||
Vital statistics | ||
================ | ||
|
||
**Bug tracker and source code:** https://github.com/python-trio/trustme | ||
|
||
**License:** MIT or Apache 2, your choice. | ||
|
||
**Install:** ``pip install -U trustme`` | ||
|
||
**Code of conduct:** Contributors are requested to follow our `code of | ||
conduct | ||
<https://github.com/python-trio/trustme/blob/master/CODE_OF_CONDUCT.md>`__ | ||
in all project spaces. | ||
|
||
|
||
Acknowledgements | ||
================ | ||
|
||
This is basically just a trivial wrapper around the awesome Python | ||
`cryptography <https://cryptography.io/>`__ library. Also, `Glyph | ||
<https://glyph.twistedmatrix.com/>`__ wrote most of the tricky bits. I | ||
got tired of never being able to remember how this works or find the | ||
magic snippets to copy/paste, so I stole the code out of `Twisted | ||
<http://twistedmatrix.com/>`__ and wrapped it in a bow. | ||
**What if I want to test some weirdo TLS configuration?** I'm happy to | ||
accept PRs to do simple things like override the default validity | ||
period or set key sizes or whatever, within reason. If you have | ||
complicated needs though then at some point you're probably better | ||
offer stealing the code from this library and adapting it to do what | ||
you want. The underlying `cryptography <https://cryptography.io>`__ | ||
API is pretty straightforward, if what you want to do is create | ||
arbitrary certificate setups. This is largely a convenience library | ||
for those of us who need a cheat sheet to tie our shoelaces, | ||
X.509-wise. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
sphinxcontrib_trio |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Minimal makefile for Sphinx documentation | ||
# | ||
|
||
# You can set these variables from the command line. | ||
SPHINXOPTS = | ||
SPHINXBUILD = python -msphinx | ||
SPHINXPROJ = trustme | ||
SOURCEDIR = source | ||
BUILDDIR = build | ||
|
||
# Put it first so that "make" without argument is like "make help". | ||
help: | ||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||
|
||
.PHONY: help Makefile | ||
|
||
# Catch-all target: route all unknown targets to Sphinx using the new | ||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). | ||
%: Makefile | ||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
@ECHO OFF | ||
|
||
pushd %~dp0 | ||
|
||
REM Command file for Sphinx documentation | ||
|
||
if "%SPHINXBUILD%" == "" ( | ||
set SPHINXBUILD=python -msphinx | ||
) | ||
set SOURCEDIR=source | ||
set BUILDDIR=build | ||
set SPHINXPROJ=trustme | ||
|
||
if "%1" == "" goto help | ||
|
||
%SPHINXBUILD% >NUL 2>NUL | ||
if errorlevel 9009 ( | ||
echo. | ||
echo.The Sphinx module was not found. Make sure you have Sphinx installed, | ||
echo.then set the SPHINXBUILD environment variable to point to the full | ||
echo.path of the 'sphinx-build' executable. Alternatively you may add the | ||
echo.Sphinx directory to PATH. | ||
echo. | ||
echo.If you don't have Sphinx installed, grab it from | ||
echo.http://sphinx-doc.org/ | ||
exit /b 1 | ||
) | ||
|
||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% | ||
goto end | ||
|
||
:help | ||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% | ||
|
||
:end | ||
popd |
Empty file.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
This is clear if less pithy than the alternatives we discussed.