def post(self): if not self.app.config['AUTHORITY_CERTIFICATE']: return 'The server lacks an authority certificate. Unable to sign the certificate request.', 403 if not self.app.config['AUTHORITY_PRIVATE_KEY']: return 'The server lacks a private key. Unable to sign the certificate request.', 403 certificate_request_der = base64.b64decode( request.json.get('certificate_request')) certificate_request = X509.load_request_der_string( certificate_request_der) if not (certificate_request.get_subject().CN == current_user.username): return 'I will not a sign certificate request for a different user ! (Got "%s" while "%s" was expected)' % ( certificate_request.get_subject().CN, current_user.username), 403 # Create a new certificate certificate = X509.X509() # Set the certificate version certificate.set_version(2) # Copy the certificate public key from the certificate request certificate.set_pubkey(certificate_request.get_pubkey()) # Set the certificate issuer certificate.set_issuer( self.app.config['AUTHORITY_CERTIFICATE'].get_subject()) # Set the certificate subject subject_name = X509.X509_Name() subject_name.CN = certificate_request.get_subject().CN or '' subject_name.OU = self.app.config['AUTHORITY_CERTIFICATE'].get_subject( ).OU or '' subject_name.O = self.app.config['AUTHORITY_CERTIFICATE'].get_subject( ).O or '' subject_name.L = self.app.config['AUTHORITY_CERTIFICATE'].get_subject( ).L or '' subject_name.ST = self.app.config['AUTHORITY_CERTIFICATE'].get_subject( ).ST or '' subject_name.C = self.app.config['AUTHORITY_CERTIFICATE'].get_subject( ).C or '' certificate.set_subject(subject_name) # Set the certificate "not before" timestamp not_before = ASN1.ASN1_UTCTIME() not_before.set_datetime(datetime.today() + timedelta(days=-1)) certificate.set_not_before(not_before) # Set the certificate "not after" timestamp not_after = ASN1.ASN1_UTCTIME() not_after.set_datetime( datetime.today() + self.app.config['CERTIFICATE_VALIDITY_DURATION']) certificate.set_not_after(not_after) # The issued certificate shall not be used as a certificate authority certificate.add_ext(X509.new_extension('basicConstraints', 'CA:FALSE')) # Sign the certificate pkey = EVP.PKey() pkey.assign_rsa(self.app.config['AUTHORITY_PRIVATE_KEY'], capture=False) certificate.sign(pkey, 'sha1') current_user.certificate = certificate DATABASE.session.commit() result = { 'certificate': current_user.certificate_string, } return jsonify(result)
def verify(context, certificate, error, depth, result): if not result: certificate = X509.X509(certificate) return result
def test_set_long_serial(self): cert = X509.X509() cert.set_serial_number(127614157056681299805556476275995414779) self.assertEqual(cert.get_serial_number(), 127614157056681299805556476275995414779)
def test_mkcert(self): for utc in (True, False): req, pk = self.mkreq(1024) pkey = req.get_pubkey() self.assertTrue(req.verify(pkey)) sub = req.get_subject() self.assertEqual(len(sub), 2, 'Subject should be long 2 items not %d' % len(sub)) cert = X509.X509() cert.set_serial_number(1) cert.set_version(2) cert.set_subject(sub) t = int(time.time()) + time.timezone if utc: now = ASN1.ASN1_UTCTIME() else: now = ASN1.ASN1_TIME() now.set_time(t) now_plus_year = ASN1.ASN1_TIME() now_plus_year.set_time(t + 60 * 60 * 24 * 365) cert.set_not_before(now) cert.set_not_after(now_plus_year) self.assertEqual(str(cert.get_not_before()), str(now)) self.assertEqual(str(cert.get_not_after()), str(now_plus_year)) issuer = X509.X509_Name() issuer.CN = 'The Issuer Monkey' issuer.O = 'The Organization Otherwise Known as My CA, Inc.' cert.set_issuer(issuer) cert.set_pubkey(pkey) cert.set_pubkey(cert.get_pubkey()) # Make sure get/set work ext = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') ext.set_critical(0) self.assertEqual(ext.get_critical(), 0) cert.add_ext(ext) cert.sign(pk, 'sha1') with self.assertRaises(ValueError): cert.sign(pk, 'nosuchalgo') self.assertTrue(cert.get_ext('subjectAltName').get_name(), 'subjectAltName') self.assertTrue(cert.get_ext_at(0).get_name(), 'subjectAltName') self.assertTrue(cert.get_ext_at(0).get_value(), 'DNS:foobar.example.com') self.assertEqual(cert.get_ext_count(), 1, 'Certificate should have now 1 extension not %d' % cert.get_ext_count()) with self.assertRaises(IndexError): cert.get_ext_at(1) self.assertTrue(cert.verify()) self.assertTrue(cert.verify(pkey)) self.assertTrue(cert.verify(cert.get_pubkey())) self.assertEqual(cert.get_version(), 2) self.assertEqual(cert.get_serial_number(), 1) self.assertEqual(cert.get_issuer().CN, 'The Issuer Monkey') if m2.OPENSSL_VERSION_NUMBER >= 0x90800f: self.assertFalse(cert.check_ca()) self.assertFalse(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 1)) self.assertFalse(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 1)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 0)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 0)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_ANY, 0)) else: with self.assertRaises(AttributeError): cert.check_ca()
def genCertificate(privkey, signature, certificate): #首先读取证书请求文件。 # signature=file("req.pem", "rb").read() #返回一个X509.Request类型代表证书请求文件 req=X509.load_request_string(signature) #首先验证一下,是不是真的是使用它本身的私钥签名的。 #如果是,返回非0值。如果不是,说明这是一个非法的证书请求文件。 is_verify = req.verify(req.get_pubkey()) if not is_verify: return False, False, None #接下来载入CA的电子证书。与CA的密钥不一样,CA的电子证书包含了CA的身份信息。 #CA的电子证书会分发给各个通信节点。 # certificate=file("ca.pem", "rb").read() ca=X509.load_cert_string(certificate) #可以使用check_ca()方法判断这个证书文件是不是CA。 #本质是判断它是不是自签名。如果是的话,就返回非0值。如果不是的话就返回0。 is_ca = ca.check_ca() # if not is_ca: # return True, False, None #接下来载入CA的密钥 # cakey_str=file("cakey.pem", "rb").read() #一般CA的密钥要加密保存。回调函数返回密码 # cakey=EVP.load_key_string(privkey, lambda *args: "1234") cakey=EVP.load_key_string(privkey, util.no_passphrase_callback) #接下来开始生成电子证书 cert=X509.X509() #首先,设定开始生效时间与结束生效时间 t = long(time.time()) + time.timezone #当前时间,单位是秒 #开始生效时间。证书的时间类型不是普通的Python datetime类型。 now = ASN1.ASN1_UTCTIME() now.set_time(t) nowPlusYear = ASN1.ASN1_UTCTIME() #结束生效时间 nowPlusYear.set_time(t + 60 * 60 * 24 * 365) #一年以后。 cert.set_not_before(now) cert.set_not_after(nowPlusYear) # 把证书请求附带的身份信息复制过来 cert.set_subject(req.get_subject()) #设置颁发者的身份信息,把CA电子证书内身份信息复制过来 cert.set_issuer(ca.get_subject()) #序列号是指,CA颁发的第几个电子证书文件 cert.set_serial_number(2) #把证书请求内的公钥复制过来 cert.set_pubkey(req.get_pubkey()) #使用CA的秘钥进行签名。 cert.sign(cakey, "sha1") certificateT = cert.as_pem() return True, True, certificateT #保存文件。 file("cert.pem", "wb").write(cert.as_pem())
def new_cert(keySize, subject, expiry, issuer=None, issuer_evp=None, isCA=None, serial=None, extensions=None, e_value=E_VALUE, timestamp_offset=0): """ Generate a new X509 certificate and RSA key. Returns the new RSA and X509 objects. @param keySize: Number of bits for the new RSA key @param subject: X509 subject for new certificate @param expiry: Number of days after which the new certificate will expire @param issuer: X509 name of the CA to which the new certificate will be a client @param issuer_evp: EVP matching the issuer CA, for signing the new certificate @param isCA: If C{True}, the new certificate will be a CA. If C{False}, it will explicitly be a non-CA. If C{None}, no C{basicConstraints} extension will be attached. @param serial: Serial number of the new certificate. @param extensions: List of X509 extensions to add @param e_value: Value of C{e} to use when generating the new key. @param timestamp_offset: Add this many seconds to the 'not before' and 'not after' attributes. """ # Generate RSA key and a matching EVP (signing helper). rsa = RSA.gen_key(keySize, e_value, lambda *_: None) evp = EVP.PKey() evp.assign_rsa(rsa, capture=False) # Create X509 object and assign parameters. now = long(time.time() + timestamp_offset) not_before = ASN1.ASN1_UTCTIME() not_before.set_time(now) not_after = ASN1.ASN1_UTCTIME() not_after.set_time(now + expiry * 86400) if issuer is None: issuer = subject issuer_evp = evp if serial is None: serial = random.randint(1, (2**15) - 1) x509 = X509.X509() x509.set_pubkey(evp) x509.set_subject(subject) x509.set_issuer(issuer) x509.set_not_before(not_before) x509.set_not_after(not_after) x509.set_version(0x2) x509.set_serial_number(serial) # Add extensions to X509. if isCA is not None: constraints = X509.new_extension('basicConstraints', 'CA:%s' % (isCA and 'TRUE' or 'FALSE'), critical=1) x509.add_ext(constraints) if extensions: for extension in extensions: x509.add_ext(extension) # Sign the certificate with the authority's EVP, or ours if this is # a self-sign certificate. x509.sign(issuer_evp, 'sha1') return rsa, x509
def generate_proxycert(new_pkey, cert, key, **kwargs): """Generate a proxy certificate. * new_pkey: EVP.PKey for the proxy certificate * cert: Issuer certificate * key: Issuer private key Optional arguments: * lifetime: proxy certificate lifetime, in seconds. Default: is 12 hours. * full: proxy type, full or limited. Default is False (limited proxy). * hash_algorithm: hash algorithm to use for certificate signing. Default: sha1. * globus_bug: do not use basicConstraints extension and do not allow Key Agreement. Default: true """ args = kwargs.copy() if 'args' in args: args.update(args.pop('args')) legacy = args.get('legacy', is_legacy_proxy(cert)) full = args.get('full', False) globus_bug = args.get('globus_bug', True) proxy = X509.X509() proxy.set_pubkey(new_pkey) proxy.set_version(2) now = int(time.time()) not_before = ASN1.ASN1_UTCTIME() not_before.set_time(now - CLOCK_SKEW) proxy.set_not_before(not_before) not_after = ASN1.ASN1_UTCTIME() not_after.set_time(now + args.get('lifetime', 12 * 60 * 60) + CLOCK_SKEW) proxy.set_not_after(not_after) proxy.set_issuer_name(cert.get_subject()) digest = EVP.MessageDigest('sha1') digest.update(new_pkey.as_der()) serial = struct.unpack("<L", digest.final()[:4])[0] proxy.set_serial_number(int(serial & 0x7fffffff)) # Не совсем понятно, что и как с памятью в следующих операциях, # поэтому по завершению всего действа будет перезагрузка # сертификата через der proxy_subject = X509.X509_Name() subject = cert.get_subject() for idx in xrange(subject.entry_count()): entry = subject[idx].x509_name_entry m2.x509_name_add_entry(proxy_subject._ptr(), entry, -1, 0) if legacy: if full: proxy_subject.add_entry_by_txt('CN', ASN1.MBSTRING_ASC, "proxy", -1, -1, 0) else: proxy_subject.add_entry_by_txt('CN', ASN1.MBSTRING_ASC, "limited proxy", -1, -1, 0) else: proxy_subject.add_entry_by_txt('CN', ASN1.MBSTRING_ASC, str(serial), -1, -1, 0) proxy.set_subject(proxy_subject) if legacy: if globus_bug: proxy.add_ext( X509.new_extension( "keyUsage", "Digital Signature, Key Encipherment, Data Encipherment", 1)) else: proxy.add_ext( X509.new_extension( "keyUsage", "Digital Signature, Key Encipherment, Data Encipherment, Key Agreement", 1)) proxy.add_ext(X509.new_extension("basicConstraints", "CA:FALSE", 1)) # does not work (?) seems like need to add authorityCertIssuer # and authorityCertSerialNumber somehow, see rfc 3280 for more # details # try: # subjkey = cert.get_ext('subjectKeyIdentifier') # keyid = "keyid:%s" % subjkey.get_value() # ext = X509.new_extension("authorityKeyIdentifier", keyid, 0) # proxy.add_ext(ext) # except LookupError: # pass else: if globus_bug: proxy.add_ext( X509.new_extension( "keyUsage", "Digital Signature, Key Encipherment, Data Encipherment", 1)) else: proxy.add_ext(X509.new_extension("basicConstraints", "CA:FALSE", 1)) proxy.add_ext( X509.new_extension( "keyUsage", "Digital Signature, Key Encipherment, Data Encipherment, Key Agreement", 1)) if not legacy: if full: proxy.add_ext( X509.new_extension("proxyCertInfo", "critical, language:Inherit all", 1)) else: proxy.add_ext( X509.new_extension( "proxyCertInfo", "critical, language:1.3.6.1.4.1.3536.1.1.1.9", 1)) sign_pkey = EVP.PKey() sign_pkey.assign_rsa(key, 0) proxy.sign(sign_pkey, args.get('hash_algorithm', 'sha1')) return X509.load_cert_string(proxy.as_pem())
def _sign_request(self, x509_request, lifetime): not_before = ASN1.ASN1_UTCTIME() not_before.set_datetime(datetime.now(UTC)) not_after = ASN1.ASN1_UTCTIME() not_after.set_datetime(datetime.now(UTC) + lifetime) proxy_subject = X509.X509_Name() for entry in self.context.x509.get_subject(): ret = m2.x509_name_add_entry(proxy_subject._ptr(), entry._ptr(), -1, 0) if ret == 0: raise Exception( "%s: '%s'" % (m2.err_reason_error_string(m2.err_get_error()), entry) ) proxy = X509.X509() proxy.set_serial_number(self.context.x509.get_serial_number()) proxy.set_version(x509_request.get_version()) proxy.set_issuer(self.context.x509.get_subject()) proxy.set_pubkey(x509_request.get_pubkey()) # Extensions are broken in SL5!! if _m2crypto_extensions_broken(): log.warning("X509v3 extensions disabled!") else: # X509v3 Basic Constraints proxy.add_ext(X509.new_extension('basicConstraints', 'CA:FALSE', critical=True)) # X509v3 Key Usage proxy.add_ext(X509.new_extension('keyUsage', 'Digital Signature, Key Encipherment', critical=True)) #X509v3 Authority Key Identifier identifier_ext = _workaround_new_extension( 'authorityKeyIdentifier', 'keyid', critical=False, issuer=self.context.x509 ) proxy.add_ext(identifier_ext) any_rfc_proxies = False # FTS-1217 Ignore the user input and select the min proxy lifetime available on the list min_cert_lifetime = self.context.x509_list[0].get_not_after() for cert in self.context.x509_list: if cert.get_not_after().get_datetime() < min_cert_lifetime.get_datetime(): not_after = cert.get_not_after() min_cert_lifetime = cert.get_not_after() try: cert.get_ext('proxyCertInfo') any_rfc_proxies = True except: pass proxy.set_not_after(not_after) proxy.set_not_before(not_before) if any_rfc_proxies: if _m2crypto_extensions_broken(): raise NotImplementedError("X509v3 extensions are disabled, so RFC proxies can not be generated!") else: _add_rfc3820_extensions(proxy) if any_rfc_proxies: m2.x509_name_set_by_nid(proxy_subject._ptr(), X509.X509_Name.nid['commonName'], str(int(time.time()))) else: m2.x509_name_set_by_nid(proxy_subject._ptr(), X509.X509_Name.nid['commonName'], 'proxy') proxy.set_subject(proxy_subject) proxy.set_version(2) proxy.sign(self.context.evp_key, 'sha1') return proxy
def create_proxy(issuer_cred, public_key, lifetime_hours): old_proxy = False # Standard order is cert, private key, then the chain. _begin_idx = issuer_cred.index(_begin_private_key) _end_idx = issuer_cred.index(_end_private_key) + len(_end_private_key) issuer_key = issuer_cred[_begin_idx:_end_idx] issuer_cert = issuer_cred[:_begin_idx] issuer_chain = issuer_cert + issuer_cred[_end_idx:] proxy = X509.X509() proxy.set_version(2) serial = get_random_serial() proxy.set_serial_number(serial) now = long(time.time()) not_before = ASN1.ASN1_UTCTIME() not_before.set_time(now) proxy.set_not_before(not_before) not_after = ASN1.ASN1_UTCTIME() not_after.set_time(now + lifetime_hours * 3600) proxy.set_not_after(not_after) pkey = EVP.PKey() tmp_bio = BIO.MemoryBuffer(str(public_key)) rsa = RSA.load_pub_key_bio(tmp_bio) pkey.assign_rsa(rsa) del rsa del tmp_bio proxy.set_pubkey(pkey) issuer = X509.load_cert_string(issuer_cert) # Examine the last CN to see if it looks like and old proxy. cn_entries = issuer.get_subject().get_entries_by_nid( X509.X509_Name.nid["CN"]) if cn_entries: last_cn = cn_entries[-1].get_data() old_proxy = (str(last_cn) in ("proxy", "limited proxy")) # If the issuer has keyUsage extension, make sure it contains all # the values we require. try: keyUsageExt = issuer.get_ext("keyUsage") if keyUsageExt: values = keyUsageExt.get_value().split(", ") for required in REQUIRED_KEY_USAGE: if required not in values: raise InterfaceError( "issuer contains keyUsage without required usage '%s'" % required) except LookupError: keyUsageExt = None # hack to get a copy of the X509 name that we can append to. issuer_copy = X509.load_cert_string(issuer_cert) proxy_subject = issuer_copy.get_subject() if old_proxy: proxy_subject.add_entry_by_txt(field="CN", type=ASN1.MBSTRING_ASC, entry="proxy", len=-1, loc=-1, set=0) else: proxy_subject.add_entry_by_txt(field="CN", type=ASN1.MBSTRING_ASC, entry=str(serial), len=-1, loc=-1, set=0) proxy.set_subject(proxy_subject) proxy.set_issuer(issuer.get_subject()) # create a full proxy (legacy/old or rfc, draft is not supported) # For old proxies, there is no spec that defines the interpretation, # so the keyUsage extension is more important. # TODO: copy extended key usage also? if keyUsageExt: # Copy from the issuer if it had a keyUsage extension. ku_ext = X509.new_extension("keyUsage", keyUsageExt.get_value(), 1) else: # Otherwise default to this set of usages. ku_ext = X509.new_extension( "keyUsage", "Digital Signature, Key Encipherment, Data Encipherment", 1) proxy.add_ext(ku_ext) if not old_proxy: # For RFC proxies the effictive usage is defined as the intersection # of the usage of each cert in the chain. See section 4.2 of RFC 3820. # We opt not to add keyUsage. pci_ext = X509.new_extension("proxyCertInfo", "critical,language:Inherit all", 1) proxy.add_ext(pci_ext) issuer_rsa = RSA.load_key_string(issuer_key) sign_pkey = EVP.PKey() sign_pkey.assign_rsa(issuer_rsa) proxy.sign(pkey=sign_pkey, md="sha1") return proxy.as_pem() + issuer_chain