Alex Gaynor | 11b00cd | 2015-07-13 21:12:39 -0400 | [diff] [blame] | 1 | Tutorial |
| 2 | ======== |
| 3 | |
| 4 | X.509 certificates are used to authenticate clients on servers. The most common |
Alex Gaynor | 0c91ddc | 2015-07-13 21:15:03 -0400 | [diff] [blame] | 5 | use case is for web servers using HTTPS. |
Alex Gaynor | 11b00cd | 2015-07-13 21:12:39 -0400 | [diff] [blame] | 6 | |
| 7 | Creating a Certificate Signing Request (CSR) |
| 8 | -------------------------------------------- |
| 9 | |
| 10 | When obtaining a certificate from a certificate authority (CA), the usual |
Alex Gaynor | 0c91ddc | 2015-07-13 21:15:03 -0400 | [diff] [blame] | 11 | flow is: |
Alex Gaynor | 11b00cd | 2015-07-13 21:12:39 -0400 | [diff] [blame] | 12 | |
| 13 | 1. You generate a private/public key pair. |
Alex Gaynor | 5bcd8e8 | 2015-07-13 21:17:31 -0400 | [diff] [blame] | 14 | 2. You create a request for a certificate, which is signed by your key (to |
| 15 | prove that you own that key). |
Alex Gaynor | 11b00cd | 2015-07-13 21:12:39 -0400 | [diff] [blame] | 16 | 3. You give your CSR to a CA (but *not* the private key). |
| 17 | 4. The CA validates that you own the resource (e.g. domain) you want a |
| 18 | certificate for. |
Alex Gaynor | 5bcd8e8 | 2015-07-13 21:17:31 -0400 | [diff] [blame] | 19 | 5. The CA gives you a certificate, signed by them, which identifies your public |
Alex Gaynor | 11b00cd | 2015-07-13 21:12:39 -0400 | [diff] [blame] | 20 | key, and the resource you are authenticated for. |
Alex Gaynor | 5bcd8e8 | 2015-07-13 21:17:31 -0400 | [diff] [blame] | 21 | 6. You configure your server to use that certificate, combined with your |
| 22 | private key, to server traffic. |
Alex Gaynor | 11b00cd | 2015-07-13 21:12:39 -0400 | [diff] [blame] | 23 | |
| 24 | If you want to obtain a certificate from a typical commercial CA, here's how. |
| 25 | First, you'll need to generate a private key, we'll generate an RSA key (these |
| 26 | are the most common types of keys on the web right now): |
| 27 | |
| 28 | .. code-block:: pycon |
| 29 | |
| 30 | >>> from cryptography.hazmat.backends import default_backend |
| 31 | >>> from cryptography.hazmat.primitives import serialization |
| 32 | >>> from cryptography.hazmat.primitives.asymmetric import rsa |
| 33 | >>> # Generate our key |
| 34 | >>> key = rsa.generate_private_key( |
| 35 | ... public_exponent=65537, |
| 36 | ... key_size=2048, |
| 37 | ... backend=default_backend() |
| 38 | ... ) |
| 39 | >>> # Write our key to disk for safe keeping |
| 40 | >>> with open("path/to/store/key.pem") as f: |
| 41 | ... f.write(key.private_bytes( |
| 42 | ... encoding=serialization.Encoding.PEM, |
| 43 | ... format=serialization.PrivateFormat.TraditionalOpenSSL, |
| 44 | ... encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"), |
Alex Gaynor | d02bc12 | 2015-07-13 21:18:56 -0400 | [diff] [blame^] | 45 | ... )) |
Alex Gaynor | 11b00cd | 2015-07-13 21:12:39 -0400 | [diff] [blame] | 46 | |
| 47 | If you've already generated a key you can load it with |
| 48 | :func:`~cryptography.hazmat.primitives.serialization.load_pem_public_key`. |
| 49 | |
Alex Gaynor | 5bcd8e8 | 2015-07-13 21:17:31 -0400 | [diff] [blame] | 50 | Next we need to generate a certificate signing request. A typical CSR contains |
| 51 | a few details: |
Alex Gaynor | 11b00cd | 2015-07-13 21:12:39 -0400 | [diff] [blame] | 52 | |
| 53 | * Information about our public key (including a signature of the entire body). |
| 54 | * Information about who *we* are. |
| 55 | * Information about what domains this certificate is for. |
| 56 | |
| 57 | .. code-block:: pycon |
| 58 | |
| 59 | >>> from cryptography import x509 |
| 60 | >>> # Generate a CSR |
| 61 | >>> csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([ |
| 62 | ... # Provide various details about who we are. |
| 63 | ... x509.NameAttribute(x509.OID_COUNTRY_NAME, u"US"), |
| 64 | ... x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, u"CA"), |
| 65 | ... x509.NameAttribute(x509.OID_LOCALITY_NAME, u"San Francisco"), |
| 66 | ... x509.NameAttribute(x509.OID_ORGANIZATION_NAME, u"My Company"), |
| 67 | ... x509.NameAttribute(x509.COMMON_NAME, u"mysite.com"), |
| 68 | ... ])).add_extension(x509.SubjectAlternativeName([ |
| 69 | ... # Describe what sites we want this certificate for. |
| 70 | ... x509.DNSName(u"mysite.com"), |
| 71 | ... x509.DNSName(u"www.mysite.com"), |
| 72 | ... x509.DNSName(u"subdomain.mysite.com"), |
| 73 | ... # Sign the CSR with our private key. |
| 74 | ... ])).sign(key, hashes.SHA256(), default_backend()) |
| 75 | >>> # Write our CSR out to disk. |
| 76 | >>> with open("path/to/csr.pem") as f: |
| 77 | ... f.write(csr.public_bytes(serialization.Encoding.PEM)) |
| 78 | |
| 79 | Now we can give our CSR to a CA, who will give a certificate to us in return. |