• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.primitives import serialization
31    >>> from cryptography.hazmat.primitives.asymmetric import rsa
32    >>> # Generate our key
33    >>> key = rsa.generate_private_key(
34    ...     public_exponent=65537,
35    ...     key_size=2048,
36    ... )
37    >>> # Write our key to disk for safe keeping
38    >>> with open("path/to/store/key.pem", "wb") as f:
39    ...     f.write(key.private_bytes(
40    ...         encoding=serialization.Encoding.PEM,
41    ...         format=serialization.PrivateFormat.TraditionalOpenSSL,
42    ...         encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"),
43    ...     ))
44
45If you've already generated a key you can load it with
46:func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key`.
47
48Next we need to generate a certificate signing request. A typical CSR contains
49a few details:
50
51* Information about our public key (including a signature of the entire body).
52* Information about who *we* are.
53* Information about what domains this certificate is for.
54
55.. code-block:: pycon
56
57    >>> from cryptography import x509
58    >>> from cryptography.x509.oid import NameOID
59    >>> from cryptography.hazmat.primitives import hashes
60    >>> # Generate a CSR
61    >>> csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
62    ...     # Provide various details about who we are.
63    ...     x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
64    ...     x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"California"),
65    ...     x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"),
66    ...     x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"),
67    ...     x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"),
68    ... ])).add_extension(
69    ...     x509.SubjectAlternativeName([
70    ...         # Describe what sites we want this certificate for.
71    ...         x509.DNSName(u"mysite.com"),
72    ...         x509.DNSName(u"www.mysite.com"),
73    ...         x509.DNSName(u"subdomain.mysite.com"),
74    ...     ]),
75    ...     critical=False,
76    ... # Sign the CSR with our private key.
77    ... ).sign(key, hashes.SHA256())
78    >>> # Write our CSR out to disk.
79    >>> with open("path/to/csr.pem", "wb") as f:
80    ...     f.write(csr.public_bytes(serialization.Encoding.PEM))
81
82Now we can give our CSR to a CA, who will give a certificate to us in return.
83
84Creating a self-signed certificate
85----------------------------------
86
87While most of the time you want a certificate that has been *signed* by someone
88else (i.e. a certificate authority), so that trust is established, sometimes
89you want to create a self-signed certificate. Self-signed certificates are not
90issued by a certificate authority, but instead they are signed by the private
91key corresponding to the public key they embed.
92
93This means that other people don't trust these certificates, but it also means
94they can be issued very easily. In general the only use case for a self-signed
95certificate is local testing, where you don't need anyone else to trust your
96certificate.
97
98Like generating a CSR, we start with creating a new private key:
99
100.. code-block:: pycon
101
102    >>> # Generate our key
103    >>> key = rsa.generate_private_key(
104    ...     public_exponent=65537,
105    ...     key_size=2048,
106    ... )
107    >>> # Write our key to disk for safe keeping
108    >>> with open("path/to/store/key.pem", "wb") as f:
109    ...     f.write(key.private_bytes(
110    ...         encoding=serialization.Encoding.PEM,
111    ...         format=serialization.PrivateFormat.TraditionalOpenSSL,
112    ...         encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"),
113    ...     ))
114
115Then we generate the certificate itself:
116
117.. code-block:: pycon
118
119    >>> # Various details about who we are. For a self-signed certificate the
120    >>> # subject and issuer are always the same.
121    >>> subject = issuer = x509.Name([
122    ...     x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
123    ...     x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"California"),
124    ...     x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"),
125    ...     x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"),
126    ...     x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"),
127    ... ])
128    >>> cert = x509.CertificateBuilder().subject_name(
129    ...     subject
130    ... ).issuer_name(
131    ...     issuer
132    ... ).public_key(
133    ...     key.public_key()
134    ... ).serial_number(
135    ...     x509.random_serial_number()
136    ... ).not_valid_before(
137    ...     datetime.datetime.utcnow()
138    ... ).not_valid_after(
139    ...     # Our certificate will be valid for 10 days
140    ...     datetime.datetime.utcnow() + datetime.timedelta(days=10)
141    ... ).add_extension(
142    ...     x509.SubjectAlternativeName([x509.DNSName(u"localhost")]),
143    ...     critical=False,
144    ... # Sign our certificate with our private key
145    ... ).sign(key, hashes.SHA256())
146    >>> # Write our certificate out to disk.
147    >>> with open("path/to/certificate.pem", "wb") as f:
148    ...     f.write(cert.public_bytes(serialization.Encoding.PEM))
149
150And now we have a private key and certificate that can be used for local
151testing.
152
153Determining Certificate or Certificate Signing Request Key Type
154---------------------------------------------------------------
155
156Certificates and certificate signing requests can be issued with multiple
157key types. You can determine what the key type is by using ``isinstance``
158checks:
159
160.. code-block:: pycon
161
162    >>> public_key = cert.public_key()
163    >>> if isinstance(public_key, rsa.RSAPublicKey):
164    ...     # Do something RSA specific
165    ... elif isinstance(public_key, ec.EllipticCurvePublicKey):
166    ...     # Do something EC specific
167    ... else:
168    ...     # Remember to handle this case
169