X.509 憑證基本觀念
X.509 是由 ITU-T 所製定的 PKI 標準,它主要包含以下 4 個規範:- public key certificates
- certificate revocation lists
- attribute certificates
- certification path validation algorithm
產生 Root CA Certificate
- 產生一把 RSA key pair (public / private keys)
- 準備一個 Root CA 憑證, 以及所需要的資訊,並且設定有效期限(一般來說是10~20年)。
- 設定此 Root CA 憑證的 X.509 V3 的 Extension
- 用此 Root CA 的 RSA private key 來簽署這個憑證( Self-Signed Root CA Certificate)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | import M2Crypto import time import os import struct from M2Crypto import X509, EVP, ASN1 def generate_rsa_keypair(key_len, exponent): def empty_callback(): pass rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback) return rsa def create_self_signed_RootCA_certificate(root_ca_info, sign_method="sha256", days=3650): # Setp 1: Create RSA-key pair (public/private key) rsa = generate_rsa_keypair(2048, 65537) private_key = EVP.PKey() private_key.assign_rsa(rsa) # Step 2-1: Prepare X.509 Certificate Signed Request req = X509.Request() req.set_pubkey(private_key) x509_name = req.get_subject() x509_name.C = root_ca_info["C"] x509_name.CN = root_ca_info["CN"] x509_name.ST = root_ca_info["ST"] x509_name.L = root_ca_info["L"] x509_name.O = root_ca_info["O"] x509_name.OU = root_ca_info["OU"] req.sign(private_key,sign_method) # Step 2-2: Prepare X.509 certificate root_ca_cert = X509.X509() serial = struct.unpack("<Q", os.urandom(8))[0] root_ca_cert.set_serial_number(serial) root_ca_cert.set_version(3) # Setp 2-3: Set required information of RootCA certificate root_ca_cert.set_issuer(x509_name) root_ca_cert.set_subject(root_ca_cert.get_issuer()) root_ca_cert.set_pubkey(req.get_pubkey()) # Get the CSR's public key # Step 2-4: Set Valid Date for RootCA certificate t = long(time.time()) now = ASN1.ASN1_UTCTIME() now.set_time(t) expire = ASN1.ASN1_UTCTIME() expire.set_time(t + days * 24 * 60 * 60) root_ca_cert.set_not_before(now) root_ca_cert.set_not_after(expire) # Step 3: Add Extensions for this Root CA certificate root_ca_cert.add_ext(X509.new_extension('basicConstraints', 'CA:TRUE')) root_ca_cert.add_ext(X509.new_extension('subjectKeyIdentifier', root_ca_cert.get_fingerprint())) # Step 4: Use Root CA's RSA private key to sign this certificate root_ca_cert.sign(private_key, sign_method) return root_ca_cert, private_key if __name__ == '__main__': # Generate a Self-Signed Root CA Certificate root_ca_info = {} root_ca_info['C'] = "TW" root_ca_info['CN'] = "Root CA Certificate" root_ca_info['ST'] = "Taiwan" root_ca_info['O'] = "ijeCorp Ltd." root_ca_info['OU'] = "Security" root_ca_info['L'] = "Taipei" root_ca_cert, private_key = create_self_signed_RootCA_certificate(root_ca_info) with open('root_ca_cert.crt', 'w') as f: f.write(root_ca_cert.as_pem()) with open('root_ca_private_key.pem', 'w') as f: f.write(private_key.as_pem(cipher=None)) with open('root_ca_public_key.pem', 'w') as f: f.write(root_ca_cert.get_pubkey().as_pem(cipher=None)) |
產生 Certificate Signed Certificate
- 產生一把 RSA key pair (public/private key)
- 準備一個 X.509 Request
- 設定 X.509 Request 的資訊
- 用 RSA private key 去簽署這個 X.509 Request
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | import M2Crypto from M2Crypto import X509, EVP def generate_rsa_keypair(key_len, exponent): def empty_callback(): pass rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback) return rsa def create_Signed_Certificate_Request(csr_info, key_len=2048, sign_method="sha256"): # Step 1: Create a RSA key pair (public/private key) rsa_keypair = generate_rsa_keypair(key_len, 65537) evp_private_key = EVP.PKey() evp_private_key.assign_rsa(rsa_keypair) # Step 2: Create a X.509 request csr = X509.Request() csr.set_pubkey(evp_private_key) # Step 3: Set CSR information x509_name = csr.get_subject() x509_name.C = csr_info['C'] x509_name.CN = csr_info['CN'] x509_name.ST = csr_info['ST'] x509_name.O = csr_info['O'] x509_name.OU = csr_info['OU'] x509_name.L = csr_info['L'] # Step 4: Use RSA private key to sign it csr.sign(evp_private_key, sign_method) return csr, evp_private_key if __name__ == '__main__': # Generate CSR for signed Certificate csr_info = {} csr_info['C'] = "TW" csr_info['CN'] = "CA-Certificate" csr_info['ST'] = "Taiwan" csr_info['O'] = "AbcCorp Ltd." csr_info['OU'] = "ABC-CA" csr_info['L'] = "Taipei" csr, private_key = create_Signed_Certificate_Request(csr_info); with open('CSR.pem', 'w') as f: f.write(csr.as_pem()) with open('CSR_private_key.pem', 'w') as f: f.write(private_key.as_pem(cipher = None)) |
Root CA 或是 CA 根據 CSR 簽署一個 Certificate
- 準備一個 X.509 的憑證
- 設定 X.509 憑證的有效期限, 有效時間的長短根據需求而有不同
- 設定 X.509 的 Extension 資訊
- 根據 CSR 所提供的 subject 以及 public key 來設定 X.509 憑證
- 使用 Root CA 或是 CA 的 RSA private key 來簽署這個 X.509 憑證
此範例程式,只需要研讀 Line 130~133 與 Line 14~47 即可,它是直接以 Root CA 的 private key並且依據 CSR 來簽署憑證
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | import M2Crypto import time import os import struct from M2Crypto import X509, EVP, ASN1 def generate_rsa_keypair(key_len, exponent): def empty_callback(): pass rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback) return rsa def create_certificate_from_CSR(rootCA_cert, rootCA_private_key, csr, days = 365): # Step 1: Prepare X.509 Certificate cert = X509.X509() serial = struct.unpack("<Q", os.urandom(8))[0] cert.set_serial_number(serial) cert.set_version(3) # Step 2: Set Expired Date t = long(time.time()) now = ASN1.ASN1_UTCTIME() now.set_time(t) expire = ASN1.ASN1_UTCTIME() expire.set_time(t + days * 24 * 60 * 60) cert.set_not_before(now) cert.set_not_after(expire) # Step 3: Set X.509 Extensions cert.add_ext(X509.new_extension('nsComment', 'SSL sever')) cert.add_ext(X509.new_extension('keyUsage', 'Digital Signature')) cert.add_ext(X509.new_extension('keyUsage', 'Key Encipherment', 1)) # 1 means critical cert.add_ext(X509.new_extension('keyUsage', 'Data Encipherment',1)) cert.add_ext(X509.new_extension('keyUsage', 'Key Agreement', 1)) cert.add_ext(X509.new_extension('extendedKeyUsage', 'clientAuth')) cert.add_ext(X509.new_extension('basicConstraints', 'CA:TRUE')) cert.add_ext(X509.new_extension('subjectAltName', 'DNS:www.ijecorp.com')) PCI_FULL = "critical, language:Inherit all" PCI_LIMITED = "critical, language:1.3.6.1.4.1.3536.1.1.1.9" cert.add_ext(X509.new_extension('proxyCertInfo',PCI_FULL, 1)) # Step 4: Set Subject and Public Key from CSR cert.set_issuer(rootCA_cert.get_issuer()) cert.set_subject(csr.get_subject()) cert.set_pubkey(csr.get_pubkey()) # Step 5: Use Private Key of Root CA or CA to sign this X.509 certificate cert.sign(rootCA_private_key, 'sha256') return cert def create_Signed_Certificate_Request(csr_info, key_len=2048, sign_method="sha256"): # Step 1: Create a RSA key pair (public/private key) rsa_keypair = generate_rsa_keypair(key_len, 65537) evp_private_key = EVP.PKey() evp_private_key.assign_rsa(rsa_keypair) # Step 2: Create a X.509 request csr = X509.Request() csr.set_pubkey(evp_private_key) # Step 3: Set CSR information x509_name = csr.get_subject() x509_name.C = csr_info['C'] x509_name.CN = csr_info['CN'] x509_name.ST = csr_info['ST'] x509_name.O = csr_info['O'] x509_name.OU = csr_info['OU'] # Step 4: Use RSA private key to sign it csr.sign(evp_private_key, sign_method) return csr, evp_private_key def create_self_signed_RootCA_certificate(root_ca_info, sign_method="sha256", days=3650): # Setp 1: Create RSA-key pair (public/private key) rsa = generate_rsa_keypair(2048, 65537) private_key = EVP.PKey() private_key.assign_rsa(rsa) # Step 2-1: Prepare X.509 Certificate Signed Request req = X509.Request() req.set_pubkey(private_key) x509_name = req.get_subject() x509_name.C = root_ca_info["C"] x509_name.CN = root_ca_info["CN"] x509_name.ST = root_ca_info["ST"] x509_name.L = root_ca_info["L"] x509_name.O = root_ca_info["O"] x509_name.OU = root_ca_info["OU"] req.sign(private_key,sign_method) # Step 2-2: Prepare X.509 certificate root_ca_cert = X509.X509() serial = struct.unpack("<Q", os.urandom(8))[0] root_ca_cert.set_serial_number(serial) root_ca_cert.set_version(3) # Setp 2-3: Set required information of RootCA certificate root_ca_cert.set_issuer(x509_name) root_ca_cert.set_subject(root_ca_cert.get_issuer()) root_ca_cert.set_pubkey(req.get_pubkey()) # Get the CSR's public key # Step 2-4: Set Valid Date for RootCA certificate t = long(time.time()) now = ASN1.ASN1_UTCTIME() now.set_time(t) expire = ASN1.ASN1_UTCTIME() expire.set_time(t + days * 24 * 60 * 60) root_ca_cert.set_not_before(now) root_ca_cert.set_not_after(expire) # Step 3: Add Extensions for this Root CA certificate root_ca_cert.add_ext(X509.new_extension('basicConstraints', 'CA:TRUE')) root_ca_cert.add_ext(X509.new_extension('subjectKeyIdentifier', root_ca_cert.get_fingerprint())) # Step 4: Use Root CA's RSA private key to sign this certificate root_ca_cert.sign(private_key, sign_method) return root_ca_cert, private_key if __name__ == '__main__': # Generate a Self-Signed Root CA Certificate root_ca_info = {} root_ca_info['C'] = "TW" root_ca_info['CN'] = "Root CA Certificate" root_ca_info['ST'] = "Taiwan" root_ca_info['O'] = "ijeCorp Ltd." root_ca_info['OU'] = "Security" root_ca_info['L'] = "Taipei" root_ca_cert, root_ca_private_key = create_self_signed_RootCA_certificate(root_ca_info) # Generate CSR for signed Certificate csr_info = {} csr_info['C'] = "TW" csr_info['CN'] = "MyCompany-Certificate" csr_info['ST'] = "." csr_info['O'] = "ijeCorp Ltd." csr_info['OU'] = "Security" csr, ca_private_key = create_Signed_Certificate_Request(csr_info); # Use Root CA's private key to sign a certificate from CSR cert = create_certificate_from_CSR(root_ca_cert, root_ca_private_key, csr) with open('my_cert.crt', 'w') as f: f.write(cert.as_pem()) |
Reference:
[1] http://svn.osafoundation.org/m2crypto/trunk/contrib/SimpleX509create.py
[2] http://www.tbs-certificates.co.uk/FAQ/en/475.html