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