| Tutorial |
| ======== |
| |
| X.509 certificates are used to authenticate clients and servers. The most common |
| use case is for web servers using HTTPS. |
| |
| Creating a Certificate Signing Request (CSR) |
| -------------------------------------------- |
| |
| When obtaining a certificate from a certificate authority (CA), the usual |
| flow is: |
| |
| 1. You generate a private/public key pair. |
| 2. You create a request for a certificate, which is signed by your key (to |
| prove that you own that key). |
| 3. You give your CSR to a CA (but *not* the private key). |
| 4. The CA validates that you own the resource (e.g. domain) you want a |
| certificate for. |
| 5. The CA gives you a certificate, signed by them, which identifies your public |
| key, and the resource you are authenticated for. |
| 6. You configure your server to use that certificate, combined with your |
| private key, to server traffic. |
| |
| If you want to obtain a certificate from a typical commercial CA, here's how. |
| First, you'll need to generate a private key, we'll generate an RSA key (these |
| are the most common types of keys on the web right now): |
| |
| .. code-block:: pycon |
| |
| >>> from cryptography.hazmat.backends import default_backend |
| >>> from cryptography.hazmat.primitives import serialization |
| >>> from cryptography.hazmat.primitives.asymmetric import rsa |
| >>> # Generate our key |
| >>> key = rsa.generate_private_key( |
| ... public_exponent=65537, |
| ... key_size=2048, |
| ... backend=default_backend() |
| ... ) |
| >>> # Write our key to disk for safe keeping |
| >>> with open("path/to/store/key.pem", "wb") as f: |
| ... f.write(key.private_bytes( |
| ... encoding=serialization.Encoding.PEM, |
| ... format=serialization.PrivateFormat.TraditionalOpenSSL, |
| ... encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"), |
| ... )) |
| |
| If you've already generated a key you can load it with |
| :func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key`. |
| |
| Next we need to generate a certificate signing request. A typical CSR contains |
| a few details: |
| |
| * Information about our public key (including a signature of the entire body). |
| * Information about who *we* are. |
| * Information about what domains this certificate is for. |
| |
| .. code-block:: pycon |
| |
| >>> from cryptography import x509 |
| >>> from cryptography.x509.oid import NameOID |
| >>> from cryptography.hazmat.primitives import hashes |
| >>> # Generate a CSR |
| >>> csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([ |
| ... # Provide various details about who we are. |
| ... x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), |
| ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"), |
| ... x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"), |
| ... x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"), |
| ... x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"), |
| ... ])).add_extension( |
| ... x509.SubjectAlternativeName([ |
| ... # Describe what sites we want this certificate for. |
| ... x509.DNSName(u"mysite.com"), |
| ... x509.DNSName(u"www.mysite.com"), |
| ... x509.DNSName(u"subdomain.mysite.com"), |
| ... ]), |
| ... critical=False, |
| ... # Sign the CSR with our private key. |
| ... ).sign(key, hashes.SHA256(), default_backend()) |
| >>> # Write our CSR out to disk. |
| >>> with open("path/to/csr.pem", "wb") as f: |
| ... f.write(csr.public_bytes(serialization.Encoding.PEM)) |
| |
| Now we can give our CSR to a CA, who will give a certificate to us in return. |