title: How do I create and sign certificates with Python's pyOpenSSL?
body: <p>I would like to use python to create a CA certificate, and client certificates that I sign with it. I will be using these with OpenVPN. After several days of research, and trial and error, this is what I've come up with:</p>
  
  <pre><code>#!/usr/bin/env python
  
  import os
  import sys
  import random
  from OpenSSL import crypto
  
  ###########
  # CA Cert #
  ###########
  
  ca_key = crypto.PKey()
  ca_key.generate_key(crypto.TYPE_RSA, 2048)
  
  ca_cert = crypto.X509()
  ca_cert.set_version(2)
  ca_cert.set_serial_number(random.randint(50000000,100000000))
  
  ca_subj = ca_cert.get_subject()
  ca_subj.commonName = "My CA"
  
  ca_cert.add_extensions([
      crypto.X509Extension("subjectKeyIdentifier", False, "hash", subject=ca_cert),
  ])
  
  ca_cert.add_extensions([
      crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=ca_cert),
  ])
  
  ca_cert.add_extensions([
      crypto.X509Extension("basicConstraints", False, "CA:TRUE"),
      crypto.X509Extension("keyUsage", False, "keyCertSign, cRLSign"),
  ])
  
  ca_cert.set_issuer(ca_subj)
  ca_cert.set_pubkey(ca_key)
  ca_cert.sign(ca_key, 'sha256')
  
  ca_cert.gmtime_adj_notBefore(0)
  ca_cert.gmtime_adj_notAfter(10*365*24*60*60)
  
  # Save certificate
  with open("ca.crt", "wt") as f:
      f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, ca_cert))
  
  # Save private key
  with open("ca.key", "wt") as f:
      f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, ca_key))
  
  ###############
  # Client Cert #
  ###############
  
  client_key = crypto.PKey()
  client_key.generate_key(crypto.TYPE_RSA, 2048)
  
  client_cert = crypto.X509()
  client_cert.set_version(2)
  client_cert.set_serial_number(random.randint(50000000,100000000))
  
  client_subj = client_cert.get_subject()
  client_subj.commonName = "Client"
  
  client_cert.add_extensions([
      crypto.X509Extension("basicConstraints", False, "CA:FALSE"),
      crypto.X509Extension("subjectKeyIdentifier", False, "hash", subject=client_cert),
  ])
  
  client_cert.add_extensions([
      crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=ca_cert),
      crypto.X509Extension("extendedKeyUsage", False, "clientAuth"),
      crypto.X509Extension("keyUsage", False, "digitalSignature"),
  ])
  
  client_cert.set_issuer(ca_subj)
  client_cert.set_pubkey(client_key)
  client_cert.sign(ca_key, 'sha256')
  
  client_cert.gmtime_adj_notBefore(0)
  client_cert.gmtime_adj_notAfter(10*365*24*60*60)
  
  # Save certificate
  with open("client.crt", "wt") as f:
      f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, client_cert))
  
  # Save private key
  with open("client.key", "wt") as f:
      f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, client_key))
  </code></pre>
  
  <p>This generates the certificates and private keys, but unfortunately, I must be doing something wrong because they do not verify:</p>
  
  <pre><code>$ openssl verify -verbose -CAfile ca.crt client.crt
  client.crt: CN = Client
  error 7 at 0 depth lookup:certificate signature failure
  139823049836448:error:04091068:rsa routines:INT_RSA_VERIFY:bad signature:rsa_sign.c:293:
  139823049836448:error:0D0C5006:asn1 encoding routines:ASN1_item_verify:EVP lib:a_verify.c:241:
  </code></pre>
  
  <p>What am I doing wrong?</p>