blob: f5ca416ceb9f1bd6e0957481319e9af632c26a10 [file] [log] [blame]
Alex Gaynor11b00cd2015-07-13 21:12:39 -04001Tutorial
2========
3
Alex Gaynor077d89d2016-02-10 23:35:20 -05004X.509 certificates are used to authenticate clients and servers. The most
5common use case is for web servers using HTTPS.
Alex Gaynor11b00cd2015-07-13 21:12:39 -04006
7Creating a Certificate Signing Request (CSR)
8--------------------------------------------
9
10When obtaining a certificate from a certificate authority (CA), the usual
Alex Gaynor0c91ddc2015-07-13 21:15:03 -040011flow is:
Alex Gaynor11b00cd2015-07-13 21:12:39 -040012
131. You generate a private/public key pair.
Alex Gaynor5bcd8e82015-07-13 21:17:31 -0400142. You create a request for a certificate, which is signed by your key (to
15 prove that you own that key).
Alex Gaynor11b00cd2015-07-13 21:12:39 -0400163. 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.
Alex Gaynor5bcd8e82015-07-13 21:17:31 -0400195. The CA gives you a certificate, signed by them, which identifies your public
Alex Gaynor11b00cd2015-07-13 21:12:39 -040020 key, and the resource you are authenticated for.
Alex Gaynor5bcd8e82015-07-13 21:17:31 -0400216. You configure your server to use that certificate, combined with your
22 private key, to server traffic.
Alex Gaynor11b00cd2015-07-13 21:12:39 -040023
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
Alex Gaynor11b00cd2015-07-13 21:12:39 -040030 >>> 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,
Alex Gaynor11b00cd2015-07-13 21:12:39 -040036 ... )
37 >>> # Write our key to disk for safe keeping
Tim Buchwaldte7820612015-08-26 19:15:03 +020038 >>> with open("path/to/store/key.pem", "wb") as f:
Alex Gaynor11b00cd2015-07-13 21:12:39 -040039 ... f.write(key.private_bytes(
40 ... encoding=serialization.Encoding.PEM,
41 ... format=serialization.PrivateFormat.TraditionalOpenSSL,
42 ... encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"),
Alex Gaynord02bc122015-07-13 21:18:56 -040043 ... ))
Alex Gaynor11b00cd2015-07-13 21:12:39 -040044
45If you've already generated a key you can load it with
Alex Gaynor9ca48512015-07-16 07:03:40 -040046:func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key`.
Alex Gaynor11b00cd2015-07-13 21:12:39 -040047
Alex Gaynor5bcd8e82015-07-13 21:17:31 -040048Next we need to generate a certificate signing request. A typical CSR contains
49a few details:
Alex Gaynor11b00cd2015-07-13 21:12:39 -040050
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
Paul Kehrer246daf72015-08-10 21:12:24 -050058 >>> from cryptography.x509.oid import NameOID
Abhijeet Rastogia5e999a2015-08-15 08:44:14 +053059 >>> from cryptography.hazmat.primitives import hashes
Alex Gaynor11b00cd2015-07-13 21:12:39 -040060 >>> # Generate a CSR
61 >>> csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
62 ... # Provide various details about who we are.
Paul Kehrer246daf72015-08-10 21:12:24 -050063 ... x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
Lucia Lic6ba99d2021-11-08 22:06:11 +080064 ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"California"),
Paul Kehrer246daf72015-08-10 21:12:24 -050065 ... 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"),
Alex Gaynorf6487342015-09-03 10:10:49 -040068 ... ])).add_extension(
69 ... x509.SubjectAlternativeName([
70 ... # Describe what sites we want this certificate for.
Alex Gaynora17bcba2017-10-19 08:43:46 -040071 ... x509.DNSName(u"mysite.com"),
72 ... x509.DNSName(u"www.mysite.com"),
73 ... x509.DNSName(u"subdomain.mysite.com"),
Alex Gaynorf6487342015-09-03 10:10:49 -040074 ... ]),
75 ... critical=False,
Alex Gaynor11b00cd2015-07-13 21:12:39 -040076 ... # Sign the CSR with our private key.
Lucia Lic6ba99d2021-11-08 22:06:11 +080077 ... ).sign(key, hashes.SHA256())
Alex Gaynor11b00cd2015-07-13 21:12:39 -040078 >>> # Write our CSR out to disk.
Tim Buchwaldte7820612015-08-26 19:15:03 +020079 >>> with open("path/to/csr.pem", "wb") as f:
Alex Gaynor11b00cd2015-07-13 21:12:39 -040080 ... 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.
Alex Gaynord57a72e2016-03-14 12:04:30 -040083
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
Alex Gaynor84c58c42016-03-14 12:17:19 -040089you want to create a self-signed certificate. Self-signed certificates are not
Alex Gaynor1cc38902016-03-14 12:34:52 -040090issued by a certificate authority, but instead they are signed by the private
91key corresponding to the public key they embed.
Alex Gaynord57a72e2016-03-14 12:04:30 -040092
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,
Alex Gaynord57a72e2016-03-14 12:04:30 -0400106 ... )
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"),
Lucia Lic6ba99d2021-11-08 22:06:11 +0800123 ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"California"),
Alex Gaynord57a72e2016-03-14 12:04:30 -0400124 ... 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(
AlexanderWeyman97945882017-02-13 03:00:19 +0100133 ... key.public_key()
Alex Gaynor0fa6b392016-09-09 21:32:14 -0400134 ... ).serial_number(
135 ... x509.random_serial_number()
Alex Gaynord57a72e2016-03-14 12:04:30 -0400136 ... ).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(
Alex Gaynora17bcba2017-10-19 08:43:46 -0400142 ... x509.SubjectAlternativeName([x509.DNSName(u"localhost")]),
Alex Gaynord57a72e2016-03-14 12:04:30 -0400143 ... critical=False,
144 ... # Sign our certificate with our private key
Lucia Lic6ba99d2021-11-08 22:06:11 +0800145 ... ).sign(key, hashes.SHA256())
Alex Gaynord57a72e2016-03-14 12:04:30 -0400146 >>> # 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.
Paul Kehrer136b3242017-05-24 19:24:54 -0700152
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