1Tutorial
2========
3
4X.509 certificates are used to authenticate clients and servers. The most
5common use case is for web servers using HTTPS.
6
7Creating a Certificate Signing Request (CSR)
8--------------------------------------------
9
10When obtaining a certificate from a certificate authority (CA), the usual
11flow is:
12
131. You generate a private/public key pair.
142. You create a request for a certificate, which is signed by your key (to
15   prove that you own that key).
163. You give your CSR to a CA (but *not* the private key).
174. The CA validates that you own the resource (e.g. domain) you want a
18   certificate for.
195. The CA gives you a certificate, signed by them, which identifies your public
20   key, and the resource you are authenticated for.
216. You configure your server to use that certificate, combined with your
22   private key, to server traffic.
23
24If you want to obtain a certificate from a typical commercial CA, here's how.
25First, you'll need to generate a private key, we'll generate an RSA key (these
26are 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", "wb") 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"),
45    ...     ))
46
47If you've already generated a key you can load it with
48:func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key`.
49
50Next we need to generate a certificate signing request. A typical CSR contains
51a few details:
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    >>> from cryptography.x509.oid import NameOID
61    >>> from cryptography.hazmat.primitives import hashes
62    >>> # Generate a CSR
63    >>> csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
64    ...     # Provide various details about who we are.
65    ...     x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
66    ...     x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"),
67    ...     x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"),
68    ...     x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"),
69    ...     x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"),
70    ... ])).add_extension(
71    ...     x509.SubjectAlternativeName([
72    ...         # Describe what sites we want this certificate for.
73    ...         x509.DNSName(u"mysite.com"),
74    ...         x509.DNSName(u"www.mysite.com"),
75    ...         x509.DNSName(u"subdomain.mysite.com"),
76    ...     ]),
77    ...     critical=False,
78    ... # Sign the CSR with our private key.
79    ... ).sign(key, hashes.SHA256(), default_backend())
80    >>> # Write our CSR out to disk.
81    >>> with open("path/to/csr.pem", "wb") as f:
82    ...     f.write(csr.public_bytes(serialization.Encoding.PEM))
83
84Now we can give our CSR to a CA, who will give a certificate to us in return.
85
86Creating a self-signed certificate
87----------------------------------
88
89While most of the time you want a certificate that has been *signed* by someone
90else (i.e. a certificate authority), so that trust is established, sometimes
91you want to create a self-signed certificate. Self-signed certificates are not
92issued by a certificate authority, but instead they are signed by the private
93key corresponding to the public key they embed.
94
95This means that other people don't trust these certificates, but it also means
96they can be issued very easily. In general the only use case for a self-signed
97certificate is local testing, where you don't need anyone else to trust your
98certificate.
99
100Like generating a CSR, we start with creating a new private key:
101
102.. code-block:: pycon
103
104    >>> # Generate our key
105    >>> key = rsa.generate_private_key(
106    ...     public_exponent=65537,
107    ...     key_size=2048,
108    ...     backend=default_backend()
109    ... )
110    >>> # Write our key to disk for safe keeping
111    >>> with open("path/to/store/key.pem", "wb") as f:
112    ...     f.write(key.private_bytes(
113    ...         encoding=serialization.Encoding.PEM,
114    ...         format=serialization.PrivateFormat.TraditionalOpenSSL,
115    ...         encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"),
116    ...     ))
117
118Then we generate the certificate itself:
119
120.. code-block:: pycon
121
122    >>> # Various details about who we are. For a self-signed certificate the
123    >>> # subject and issuer are always the same.
124    >>> subject = issuer = x509.Name([
125    ...     x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
126    ...     x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"),
127    ...     x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"),
128    ...     x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"),
129    ...     x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"),
130    ... ])
131    >>> cert = x509.CertificateBuilder().subject_name(
132    ...     subject
133    ... ).issuer_name(
134    ...     issuer
135    ... ).public_key(
136    ...     key.public_key()
137    ... ).serial_number(
138    ...     x509.random_serial_number()
139    ... ).not_valid_before(
140    ...     datetime.datetime.utcnow()
141    ... ).not_valid_after(
142    ...     # Our certificate will be valid for 10 days
143    ...     datetime.datetime.utcnow() + datetime.timedelta(days=10)
144    ... ).add_extension(
145    ...     x509.SubjectAlternativeName([x509.DNSName(u"localhost")]),
146    ...     critical=False,
147    ... # Sign our certificate with our private key
148    ... ).sign(key, hashes.SHA256(), default_backend())
149    >>> # Write our certificate out to disk.
150    >>> with open("path/to/certificate.pem", "wb") as f:
151    ...     f.write(cert.public_bytes(serialization.Encoding.PEM))
152
153And now we have a private key and certificate that can be used for local
154testing.
155
156Determining Certificate or Certificate Signing Request Key Type
157---------------------------------------------------------------
158
159Certificates and certificate signing requests can be issued with multiple
160key types. You can determine what the key type is by using ``isinstance``
161checks:
162
163.. code-block:: pycon
164
165    >>> public_key = cert.public_key()
166    >>> if isinstance(public_key, rsa.RSAPublicKey):
167    ...     # Do something RSA specific
168    ... elif isinstance(public_key, ec.EllipticCurvePublicKey):
169    ...     # Do something EC specific
170    ... else:
171    ...     # Remember to handle this case
172