def get_cert(pccert, native = False): from asn1crypto.x509 import Certificate cctx = pccert.contents cert_data = ctypes.string_at(cctx.pbCertEncoded, cctx.cbCertEncoded) if native is False: return Certificate.load(cert_data) return Certificate.load(cert_data).native
def test_self_sign_certificate(self): # Warning: proof of concept code only! pub, priv = self.session.generate_keypair(KeyType.RSA, 1024) tbs = TbsCertificate({ 'version': 'v1', 'serial_number': 1, 'issuer': Name.build({ 'common_name': 'Test Certificate', }), 'subject': Name.build({ 'common_name': 'Test Certificate', }), 'signature': { 'algorithm': 'sha1_rsa', 'parameters': None, }, 'validity': { 'not_before': Time({ 'utc_time': datetime.datetime(2017, 1, 1, 0, 0), }), 'not_after': Time({ 'utc_time': datetime.datetime(2038, 12, 31, 23, 59), }), }, 'subject_public_key_info': { 'algorithm': { 'algorithm': 'rsa', 'parameters': None, }, 'public_key': RSAPublicKey.load(encode_rsa_public_key(pub)), } }) # Sign the TBS Certificate value = priv.sign(tbs.dump(), mechanism=Mechanism.SHA1_RSA_PKCS) cert = Certificate({ 'tbs_certificate': tbs, 'signature_algorithm': { 'algorithm': 'sha1_rsa', 'parameters': None, }, 'signature_value': value, }) # Pipe our certificate to OpenSSL to verify it with subprocess.Popen((OPENSSL, 'verify'), stdin=subprocess.PIPE, stdout=subprocess.DEVNULL) as proc: proc.stdin.write(pem.armor('CERTIFICATE', cert.dump())) proc.stdin.close() self.assertEqual(proc.wait(), 0)
def check_ess_certid(cert: x509.Certificate, certid: Union[tsp.ESSCertID, tsp.ESSCertIDv2]): """ Match an ``ESSCertID`` value against a certificate. :param cert: The certificate to match against. :param certid: The ``ESSCertID`` value. :return: ``True`` if the ``ESSCertID`` matches the certificate, ``False`` otherwise. """ if isinstance(certid, tsp.ESSCertID): hash_algo = 'sha1' else: hash_algo = certid['hash_algorithm']['algorithm'].native hash_spec = get_pyca_cryptography_hash(hash_algo) md = hashes.Hash(hash_spec) md.update(cert.dump()) digest_value = md.finalize() expected_digest_value = certid['cert_hash'].native if digest_value != expected_digest_value: return False expected_issuer_serial: tsp.IssuerSerial = certid['issuer_serial'] return (not expected_issuer_serial or match_issuer_serial(expected_issuer_serial, cert))
def test_verify_certificate_ecdsa(self): # Warning: proof of concept code only! CERT = base64.b64decode(""" MIIDGjCCAsKgAwIBAgIJAL+PbwiJUZB1MAkGByqGSM49BAEwRTELMAkGA1UEBhMC QVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdp dHMgUHR5IEx0ZDAeFw0xNzA3MDMxMTUxMTBaFw0xOTA3MDMxMTUxMTBaMEUxCzAJ BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l dCBXaWRnaXRzIFB0eSBMdGQwggFLMIIBAwYHKoZIzj0CATCB9wIBATAsBgcqhkjO PQEBAiEA/////wAAAAEAAAAAAAAAAAAAAAD///////////////8wWwQg/////wAA AAEAAAAAAAAAAAAAAAD///////////////wEIFrGNdiqOpPns+u9VXaYhrxlHQaw zFOw9jvOPD4n0mBLAxUAxJ02CIbnBJNqZnjhE50mt4GffpAEQQRrF9Hy4SxCR/i8 5uVjpEDydwN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2 QGg3v1H1AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQEDQgAE royPJHkCQMq55egxmQxkFWqiz+yJx0MZP98is99SrkiK5UadFim3r3ZSt5kfh/cc Ccmy94BZCmihhGJ0F4eB2qOBpzCBpDAdBgNVHQ4EFgQURNXKlYGsAMItf4Ad8fkg Rg9ATqEwdQYDVR0jBG4wbIAURNXKlYGsAMItf4Ad8fkgRg9ATqGhSaRHMEUxCzAJ BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l dCBXaWRnaXRzIFB0eSBMdGSCCQC/j28IiVGQdTAMBgNVHRMEBTADAQH/MAkGByqG SM49BAEDRwAwRAIgAdJp/S9vSjS6EvRy/9zl5k2DBKGI52A3Ygsp1a96UicCIDul m/eL2OcGdNbzqzsC11alhemJX7Qt9GOcVqQwROIm """) x509 = Certificate.load(CERT) key = self.session.create_object(decode_x509_public_key(CERT)) self.assertIsInstance(key, pkcs11.PublicKey) value = x509['tbs_certificate'].dump() assert x509.signature_algo == 'ecdsa' assert x509.hash_algo == 'sha1' signature = decode_ecdsa_signature(x509.signature) self.assertTrue( key.verify(value, signature, mechanism=Mechanism.ECDSA_SHA1))
def fetch_certificate(session): """ Return smart card certificate Params: session: smart card session """ log.info("fetching certificate") try: certificates = session.findObjects([(LowLevel.CKA_CLASS, LowLevel.CKO_CERTIFICATE)]) except: raise SmartCardConnectionError("Certificate not found") certificate = None log.info("picking non_repudiation certificate") for cert in certificates: cert_value = SignatureUtils.get_certificate_value(session, cert) x509 = Certificate.load(cert_value) try: key_usage = x509.key_usage_value if 'non_repudiation' in key_usage.native: certificate = cert break except: log.info("key usage not found, skip this certificate") continue if certificate is None: log.info("non_repudiation certificate not found, pick the latest") last_certificate_index = len(certificates) - 1 certificate = certificates[last_certificate_index] return certificate
def exploit_certificate( certificate: x509.Certificate, ) -> Tuple[ecdsa.keys.SigningKey, keys.ECPrivateKey]: curve_name = certificate.public_key["algorithm"][ "parameters"].chosen.native ec_private_key = generate_ec_private_key(curve_name) k = ec_private_key["private_key"].native parameters = ec_private_key["parameters"].chosen nist_curve = curve_from_ec_parameters(parameters) Qx, Qy = certificate.public_key["public_key"].to_coords() Gx, Gy = get_exploit_generator(k, Qx, Qy, nist_curve) parameters["base"] = keys.ECPoint.from_coords(Gx, Gy) ec_private_key["parameters"] = parameters ec_private_key["public_key"] = certificate.public_key["public_key"] certificate.public_key["algorithm"]["parameters"] = parameters exploit_curve = curve_from_ec_parameters(parameters) signing_key = ecdsa.keys.SigningKey.from_secret_exponent( k, curve=exploit_curve) signed_digest_algorithm = x509.SignedDigestAlgorithm( {"algorithm": "sha256_ecdsa"}) certificate["tbs_certificate"]["signature"] = signed_digest_algorithm certificate["signature_algorithm"] = signed_digest_algorithm sign_certificate(signing_key, certificate) return (signing_key, ec_private_key)
def sync(): data = request.data session = json.loads(data) c = dbcon.cursor() c.execute("SELECT * FROM Users WHERE uid = ?", (session['mid'], )) master = c.fetchone() cert = Certificate.load(binascii.unhexlify(master[5])) n = cert.public_key.native['public_key']['modulus'] e = cert.public_key.native['public_key']['public_exponent'] hash_package = ''.join(sorted([attn['cid'] for attn in session['attns']])) digest = SHA256.new() digest.update(hash_package) public_key = RSA.construct((n, e)) verifier = PKCS1_v1_5.new(public_key) verified = verifier.verify(digest, binascii.unhexlify(session['sig'])) if verified: dbcon.execute( "INSERT INTO Sessions (sid, sig, master) VALUES (?, ?, ?)", (session['sid'], session['sig'], session['master'])) for attn in session['attns']: db_tuple = (attn['sig'], attn['mid'], attn['uid'], attn['lat'], attn['lon'], attn['ts'], attn['sig'], attn['aid'], attn['confsig'], attn['cid']) dbcon.execute( "INSERT INTO Attendances (sid, mid, uid, lat, lon, ts, sig, aid, confsig, cid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", db_tuple) dbcon.commit() return "", 201 # Created else: return "", 401 # Unauthorized
def get_cert_info(self, hostname, port=443, cert_file_name='cert.der'): f = open(str(cert_file_name), 'wb') certificate = ssl.get_server_certificate((hostname, port)) f.write(ssl.PEM_cert_to_DER_cert(certificate)) with open(str(cert_file_name), "rb") as f: certificate = Certificate.load(f.read()) modulus = certificate.public_key.native["public_key"]["modulus"] pub_exp = certificate.public_key.native["public_key"][ "public_exponent"] sig_algorithm = certificate.signature_algo try: cert_issuer_country = certificate.issuer.native["country_name"] except: cert_issuer_country = "Empty" try: cert_issuer_name = certificate.issuer.native["organization_name"] except: cert_issuer_name = "Empty" try: cert_issuer_common_name = certificate.issuer.native["common_name"] except: cert_issuer_common_name = "Empty" self_signed = certificate.self_signed hash_algo = certificate.hash_algo domains = certificate.valid_domains return ('{0:02x}'.format(modulus), pub_exp, sig_algorithm, cert_issuer_country, cert_issuer_name, cert_issuer_common_name, self_signed, hash_algo, domains)
def apply_sig(filename: str, detach_path: str): """ Attach the signature for the bundle of the same name at the detach_path """ bundle, filepath = get_bundle_exec(filename) detach_bundle = os.path.join(detach_path, os.path.basename(bundle)) bin_code_signers: Dict[str, CodeSigner] = {} for file_path in glob.iglob(os.path.join(detach_bundle, "**"), recursive=True): if os.path.isdir(file_path): continue bundle_relpath = os.path.relpath(file_path, detach_bundle) bundle_path = os.path.join(bundle, bundle_relpath) if os.path.basename(os.path.dirname(file_path)) == "MacOS": # Signature files are only in the MacOS dir if file_path.endswith("sign"): bin_name, ext = os.path.splitext(file_path) bundle_relpath = os.path.relpath(bin_name, detach_bundle) bundle_path = os.path.join(bundle, bundle_relpath) if bin_name not in bin_code_signers: bin_code_signers[bin_name] = CodeSigner( bundle_path, Certificate(), PrivateKeyInfo()) bcs = bin_code_signers[bin_name] # Figure out which index this sig is for idx = 0 macho = bcs.macho if hasattr(bcs.macho, "Fhdr"): if ext == ".sign": raise Exception( "Cannot attach single architecture signature to universal binary" ) arch_type = CPU_NAME_TO_TYPE[ext[1:-4]] for i, h in enumerate(bcs.macho.fh): if h.cputype == arch_type: idx = i macho = bcs.macho.arch[i] break # Create a CodeSignatureAttacher csa = CodeSignatureAttacher(bundle_path, idx, macho, file_path) # Add it to the CodeSigner bcs.code_signers.append(csa) continue # Non-signature files are just copied over os.makedirs(os.path.dirname(bundle_path), exist_ok=True) shutil.copyfile(file_path, bundle_path) # Apply the signature for all CodeSigners for _, cs in bin_code_signers.items(): cs.apply_signature()
def extract_from_system(cert_callback=None): """ Extracts trusted CA certs from the system CA cert bundle :param cert_callback: A callback that is called once for each certificate in the trust store. It should accept two parameters: an asn1crypto.x509.Certificate object, and a reason. The reason will be None if the certificate is being exported, otherwise it will be a unicode string of the reason it won't. :return: A list of 3-element tuples: - 0: a byte string of a DER-encoded certificate - 1: a set of unicode strings that are OIDs of purposes to trust the certificate for - 2: a set of unicode strings that are OIDs of purposes to reject the certificate for """ all_purposes = '2.5.29.37.0' ca_path = system_path() output = [] with open(ca_path, 'rb') as f: for armor_type, _, cert_bytes in unarmor(f.read(), multiple=True): # Without more info, a certificate is trusted for all purposes if armor_type == 'CERTIFICATE': if cert_callback: cert_callback(Certificate.load(cert_bytes), None) output.append((cert_bytes, set(), set())) # The OpenSSL TRUSTED CERTIFICATE construct adds OIDs for trusted # and rejected purposes, so we extract that info. elif armor_type == 'TRUSTED CERTIFICATE': cert, aux = TrustedCertificate.load(cert_bytes) reject_all = False trust_oids = set() reject_oids = set() for purpose in aux['trust']: if purpose.dotted == all_purposes: trust_oids = set([purpose.dotted]) break trust_oids.add(purpose.dotted) for purpose in aux['reject']: if purpose.dotted == all_purposes: reject_all = True break reject_oids.add(purpose.dotted) if reject_all: if cert_callback: cert_callback(cert, 'explicitly distrusted') continue if cert_callback: cert_callback(cert, None) output.append((cert.dump(), trust_oids, reject_oids)) return output
def decode_x509_certificate(der, extended_set=False): """ Decode a DER-encoded X.509 certificate into a dictionary of attributes able to be passed to :meth:`pkcs11.Session.create_object`. Optionally pass `extended_set` to include additional attributes: start date, end date and key identifiers. For PEM-encoded certificates, use :func:`asn1crypto.pem.unarmor`. .. warning:: Does not verify certificate. :param bytes der: DER-encoded certificate :param extended_set: decodes more metadata about the certificate :rtype: dict(Attribute,*) """ x509 = Certificate.load(der) subject = x509.subject issuer = x509.issuer serial = x509['tbs_certificate']['serial_number'] template = { Attribute.CLASS: ObjectClass.CERTIFICATE, Attribute.CERTIFICATE_TYPE: CertificateType.X_509, Attribute.SUBJECT: subject.dump(), Attribute.ISSUER: issuer.dump(), Attribute.SERIAL_NUMBER: serial.dump(), Attribute.VALUE: x509.dump(), } if extended_set: start_date = \ x509['tbs_certificate']['validity']['not_before'].native.date() end_date = \ x509['tbs_certificate']['validity']['not_after'].native.date() template.update({ Attribute.START_DATE: start_date, Attribute.END_DATE: end_date, }) # FIXME: is this correct? try: template[Attribute.HASH_OF_SUBJECT_PUBLIC_KEY] = \ x509.key_identifier except KeyError: pass try: template[Attribute.HASH_OF_ISSUER_PUBLIC_KEY] = \ x509.authority_key_identifier except KeyError: pass return template
def read_dss(cls, handler: PdfHandler) -> 'DocumentSecurityStore': """ Read a DSS record from a file and add the data to a validation context. :param handler: PDF handler from which to read the DSS. :return: A DocumentSecurityStore object describing the current state of the DSS. """ try: dss_dict = handler.root['/DSS'] except KeyError as e: raise NoDSSFoundError() from e cert_refs = {} cert_ref_list = get_and_apply(dss_dict, '/Certs', list, default=()) for cert_ref in cert_ref_list: cert_stream: generic.StreamObject = cert_ref.get_object() cert: Certificate = Certificate.load(cert_stream.data) cert_refs[cert.issuer_serial] = cert_ref ocsp_refs = get_and_apply(dss_dict, '/OCSPs', list, default=()) ocsps = [] for ocsp_ref in ocsp_refs: ocsp_stream: generic.StreamObject = ocsp_ref.get_object() resp = asn1_ocsp.OCSPResponse.load(ocsp_stream.data) ocsps.append(resp) crl_refs = get_and_apply(dss_dict, '/CRLs', list, default=()) crls = [] for crl_ref in crl_refs: crl_stream: generic.StreamObject = crl_ref.get_object() crl = asn1_crl.CertificateList.load(crl_stream.data) crls.append(crl) # shallow-copy the VRI dictionary try: vri_entries = dict(dss_dict['/VRI']) except KeyError: vri_entries = None # if the handler is a writer, the DSS will support updates if isinstance(handler, BasePdfFileWriter): writer = handler else: writer = None # the DSS returned will be backed by the original DSS object, so CRLs # are automagically preserved if they happened to be included in # the original file dss = cls( writer=writer, certs=cert_refs, ocsps=ocsp_refs, vri_entries=vri_entries, crls=crl_refs, backing_pdf_object=dss_dict ) return dss
def verify_signature(self, challenge, application): challenge_data = sha256(challenge.encode('utf-8')).digest() application_data = sha256(application.encode('utf-8')).digest() message = b'\0' + application_data + challenge_data + \ self.key_handle + self.public_key certificate = Certificate.load(self.attestation_certificate) # the public key is represented in uncompressed x,y notation, # with 0x04 as byte 0 and x and y each 32 bytes, 65 bytes in total public_key = bytes(certificate.public_key['public_key']) u2f_verify_signature(self.signature, message, public_key)
def UnpackX509Certificate(self) -> Certificate: b = self.UnpackBytes() if len(b) == 0: return None cert = Certificate.load(b) if cert is None: self.Add(Exception("Error Parsing X509 Cert")) return None return cert
def load_certs(self): """ Return a generator that parses and yields all certificates in the DSS. :return: A generator yielding :class:`.Certificate` objects. """ for cert_ref in self.certs.values(): cert_stream: generic.StreamObject = cert_ref.get_object() cert = Certificate.load(cert_stream.data) yield cert
def extarct_components(cert): # extract (n, e) components from der cert from asn1crypto.x509 import Certificate with open(cert, "rb") as f: cert = Certificate.load(f.read()) n = cert.public_key.native["public_key"]["modulus"] e = cert.public_key.native["public_key"]["public_exponent"] print("{:#x}".format(n)) # prints the modulus (hexadecimal) print("{:#x}".format(e)) # same, for the public exponent
def sign(self, datau, session, cert, cert_value, algomd, sig_attributes, timestamp): log.info('get certificate in format x509 to build signer attributes') x509 = Certificate.load(cert_value) sign_name = sig_attributes['position']['signature_name'] if sign_name == "": sign_name = MyConfigLoader().get_pdf_config()['position']['signatureName'] dct = { b'sigflags': 3, b'name': b'%b' % x509.subject.native['common_name'].encode(), b'signingdate': b'%b' % timestamp.encode(), b'sign_name': sign_name.encode() } # Variabile segnaposto per i bytes che conterranno il file firmato riferimenti della firma zeros = self.aligned(b'\0') log.info('start building the new pdf') try: pdfdata2 = self.makepdf(datau, dct, zeros, sig_attributes) log.info('pdf generated correctly') except PDFLinearizedError as e: raise PDFLinearizedError(e) except Exception: raise PDFCreationError('Exception on creating pdf') log.info('preparing data to be signed') startxref = len(datau) pdfbr1 = pdfdata2.find(zeros) pdfbr2 = pdfbr1 + len(zeros) br = [0, startxref + pdfbr1 - 1, startxref + pdfbr2 + 1, len(pdfdata2) - pdfbr2 - 1] brfrom = b'[0000000000 0000000000 0000000000 0000000000]' brto = b'[%010d %010d %010d %010d]' % tuple(br) pdfdata2 = pdfdata2.replace(brfrom, brto, 1) b1 = pdfdata2[:br[1] - startxref] b2 = pdfdata2[br[2] - startxref:] md = session.digestSession(Mechanism(LowLevel.CKM_SHA256)) md.update(datau) md.update(b1) md.update(b2) md = bytes(md.final()) log.info('start pdf signing') try: contents = pdf_signer.sign(None, session, cert, cert_value, algomd, True, md) contents = self.aligned(contents) pdfdata2 = pdfdata2.replace(zeros, contents, 1) log.info('pdf signed') except Exception: raise PDFSigningError('error in the sign procedure') return pdfdata2
def read_cert_bundle(self, ca_bundle_file, storage=None): """Reads a certificate file including certificates in PEM format.""" if storage is None: storage = SnowflakeOCSP.ROOT_CERTIFICATES_DICT logger.debug('reading certificate bundle: %s', ca_bundle_file) with open(ca_bundle_file, 'rb') as all_certs: # don't lock storage from asn1crypto import pem pem_certs = pem.unarmor(all_certs.read(), multiple=True) for type_name, _, der_bytes in pem_certs: if type_name == 'CERTIFICATE': crt = Certificate.load(der_bytes) storage[crt.subject.sha256] = crt
def decode_x509_public_key(der): """ Decode a DER-encoded X.509 certificate's public key into a set of attributes able to be passed to :meth:`pkcs11.Session.create_object`. For PEM-encoded certificates, use :func:`asn1crypto.pem.unarmor`. .. warning:: Does not verify certificate. :param bytes der: DER-encoded certificate :rtype: dict(Attribute,*) """ x509 = Certificate.load(der) key_info = x509.public_key key = bytes(key_info['public_key']) key_type = { 'rsa': KeyType.RSA, 'dsa': KeyType.DSA, 'ec': KeyType.EC, }[key_info.algorithm] attrs = { Attribute.CLASS: ObjectClass.PUBLIC_KEY, Attribute.KEY_TYPE: key_type, } if key_type is KeyType.RSA: from .rsa import decode_rsa_public_key attrs.update(decode_rsa_public_key(key)) elif key_type is KeyType.DSA: from .dsa import decode_dsa_domain_parameters, decode_dsa_public_key params = key_info['algorithm']['parameters'].dump() attrs.update(decode_dsa_domain_parameters(params)) attrs.update({ Attribute.VALUE: decode_dsa_public_key(key), }) elif key_type is KeyType.EC: params = key_info['algorithm']['parameters'].dump() attrs.update({ Attribute.EC_PARAMS: params, Attribute.EC_POINT: key, }) else: raise AssertionError("Should not be reached") return attrs
def test_verify_certificate_rsa(self): # Warning: proof of concept code only! x509 = Certificate.load(CERT) key = self.session.create_object(decode_x509_public_key(CERT)) self.assertIsInstance(key, pkcs11.PublicKey) value = x509['tbs_certificate'].dump() signature = x509.signature assert x509.signature_algo == 'rsassa_pkcs1v15' assert x509.hash_algo == 'sha1' self.assertTrue( key.verify(value, signature, mechanism=Mechanism.SHA1_RSA_PKCS))
def from_ldap(entry, location): adi = MSADCA() adi.location = location adi.sn = entry['attributes'].get('sn') adi.cn = entry['attributes'].get('cn') adi.distinguishedName = entry['attributes'].get('distinguishedName') adi.whenChanged = entry['attributes'].get('whenChanged') adi.whenCreated = entry['attributes'].get('whenCreated') adi.cACertificate = entry['attributes'].get('cACertificate') if adi.cACertificate is not None: adi.cACertificate = Certificate.load(adi.cACertificate) adi.name = entry['attributes'].get('name') return adi
def __init__(self, end_entity_cert, intermediate_certs=None, validation_context=None): """ :param end_entity_cert: An asn1crypto.x509.Certificate object or a byte string of the DER or PEM-encoded X.509 end-entity certificate to validate :param intermediate_certs: None or a list of asn1crypto.x509.Certificate objects or a byte string of a DER or PEM-encoded X.509 certificate. Used in constructing certificate paths for validation. :param validation_context: A certvalidator.context.ValidationContext() object that controls validation options """ if not isinstance(end_entity_cert, Certificate): if not isinstance(end_entity_cert, byte_cls): raise TypeError( pretty_message( ''' end_entity_cert must be a byte string or an instance of asn1crypto.x509.Certificate, not %s ''', type_name(end_entity_cert))) if pem.detect(end_entity_cert): _, _, end_entity_cert = pem.unarmor(end_entity_cert) end_entity_cert = Certificate.load(end_entity_cert) if validation_context is None: validation_context = ValidationContext() if not isinstance(validation_context, ValidationContext): raise TypeError( pretty_message( ''' validation_context must be an instance of certvalidator.context.ValidationContext, not %s ''', type_name(validation_context))) if intermediate_certs is not None: certificate_registry = validation_context.certificate_registry for intermediate_cert in intermediate_certs: certificate_registry.add_other_cert(intermediate_cert) self._context = validation_context self._certificate = end_entity_cert
def extract_certificate_chain(self, connection): """Gets certificate chain and extract the key info from OpenSSL connection.""" from OpenSSL.crypto import dump_certificate, FILETYPE_ASN1 cert_map = OrderedDict() logger.debug("# of certificates: %s", len(connection.get_peer_cert_chain())) for cert_openssl in connection.get_peer_cert_chain(): cert_der = dump_certificate(FILETYPE_ASN1, cert_openssl) cert = Certificate.load(cert_der) logger.debug('subject: %s, issuer: %s', cert.subject.native, cert.issuer.native) cert_map[cert.subject.sha256] = cert return self.create_pair_issuer_subject(cert_map)
def _fetch_certs(hostname_file): with open(hostname_file) as f: hostnames = f.read().split("\n") map_serial_to_name = {} for h in hostnames: if not h: continue connection = _openssl_connect(h, 443) for cert_openssl in connection.get_peer_cert_chain(): cert_der = dump_certificate(FILETYPE_ASN1, cert_openssl) cert = Certificate.load(cert_der) map_serial_to_name[cert.serial_number] = cert.subject.native return map_serial_to_name
def __init__(self, end_entity_cert, intermediate_certs=None, validation_context=None): """ :param end_entity_cert: An asn1crypto.x509.Certificate object or a byte string of the DER or PEM-encoded X.509 end-entity certificate to validate :param intermediate_certs: None or a list of asn1crypto.x509.Certificate objects or a byte string of a DER or PEM-encoded X.509 certificate. Used in constructing certificate paths for validation. :param validation_context: A certvalidator.context.ValidationContext() object that controls validation options """ if not isinstance(end_entity_cert, Certificate): if not isinstance(end_entity_cert, byte_cls): raise TypeError(pretty_message( ''' end_entity_cert must be a byte string or an instance of asn1crypto.x509.Certificate, not %s ''', type_name(end_entity_cert) )) if pem.detect(end_entity_cert): _, _, end_entity_cert = pem.unarmor(end_entity_cert) end_entity_cert = Certificate.load(end_entity_cert) if validation_context is None: validation_context = ValidationContext() if not isinstance(validation_context, ValidationContext): raise TypeError(pretty_message( ''' validation_context must be an instance of certvalidator.context.ValidationContext, not %s ''', type_name(validation_context) )) if intermediate_certs is not None: certificate_registry = validation_context.certificate_registry for intermediate_cert in intermediate_certs: certificate_registry.add_other_cert(intermediate_cert) self._context = validation_context self._certificate = end_entity_cert
def _check_certificate(cert_abs_path): """ Check the cerficate. Will raise :class:`systemlink.messagebus.exceptions.SystemLinkException` with details if the certicate check fails. :param cert_abs_path: Absolute path to the cerficate file. :type cert_abs_path: str :raises systemlink.messagebus.exceptions.SystemLinkException: If the certificate check fails. """ if not HAS_ASN1CRYPTO and not HAS_PYCRYPTO: error_info = 'Cannot import asn1crypto nor PyCrypto[dome] for certificate check.' raise SystemLinkException.from_name('Skyline.InternalServiceError', info=error_info) with open(cert_abs_path) as fp_: pem = fp_.read() lines = pem.replace(' ', '').split() # Skip over begin and end lines der = a2b_base64(''.join(lines[1:-1])) # Extract validity field from X.509 certificate (see RFC3280) if HAS_ASN1CRYPTO: cert = Certificate.load(der) tbs_certificate = cert['tbs_certificate'] validity = tbs_certificate['validity'] not_before = validity['not_before'].native not_before = not_before.replace(tzinfo=None) not_after = validity['not_after'].native not_after = not_after.replace(tzinfo=None) else: cert = DerSequence() cert.decode(der) tbs_certificate = DerSequence() tbs_certificate.decode(cert[0]) validity = DerSequence() validity.decode(tbs_certificate[4]) not_before = _der_to_datetime(validity[0]) not_after = _der_to_datetime(validity[1]) now = datetime.datetime.utcnow() if now < not_before or now > not_after: error_info = ( 'Certificate check failed. Certificate is valid from {0} to {1} (UTC). ' 'Current system UTC time is {2}, which is outside the valid range. ' 'Please ensure that the current system time is properly set.' ''.format(not_before, not_after, now)) raise SystemLinkException.from_name( 'Skyline.AMQPErrorCertificateExpired', info=error_info)
def parse_der(data): cert = Certificate.load(data) d = cert.native res = {} if d.has_key('tbs_certificate'): tbs = d['tbs_certificate'] res['tls_version'] = tbs['version'] res['tls_serial_number'] = hex(tbs['serial_number'])[2:].rstrip('L') res['sig_algo'] = tbs['signature']['algorithm'] res['tls_issuer'] = dict2str(tbs['issuer']) res['not_valid_before'] = str(tbs['validity']['not_before']) res['not_valid_after'] = str(tbs['validity']['not_after']) pubkey = tbs['subject_public_key_info'] res['pubkey_algo'] = pubkey['algorithm']['algorithm'] res['pubkey_param'] = dict2str(pubkey['public_key']) return res
def check_ess_certid(cert: x509.Certificate, certid: Union[tsp.ESSCertID, tsp.ESSCertIDv2]): if isinstance(certid, tsp.ESSCertID): hash_algo = 'sha1' else: hash_algo = certid['hash_algorithm']['algorithm'].native hash_spec = get_pyca_cryptography_hash(hash_algo) md = hashes.Hash(hash_spec) md.update(cert.dump()) digest_value = md.finalize() expected_digest_value = certid['cert_hash'].native if digest_value != expected_digest_value: return False expected_issuer_serial: tsp.IssuerSerial = certid['issuer_serial'] return (not expected_issuer_serial or match_issuer_serial(expected_issuer_serial, cert))
def from_ldap(entry): adi = MSADEnrollmentService() adi.sn = entry['attributes'].get('sn') adi.cn = entry['attributes'].get('cn') adi.distinguishedName = entry['attributes'].get('distinguishedName') adi.cACertificate = entry['attributes'].get('cACertificate') if adi.cACertificate is not None: adi.cACertificate = Certificate.load(adi.cACertificate) adi.name = entry['attributes'].get('name') adi.displayName = entry['attributes'].get('displayName') adi.dNSHostName = entry['attributes'].get('dNSHostName') adi.cACertificateDN = entry['attributes'].get('cACertificateDN') adi.certificateTemplates = entry['attributes'].get( 'certificateTemplates') for serverdef in entry['attributes'].get('msPKI-Enrollment-Servers', []): adi.enrollmentServers.append(serverdef.split('\n')[3]) return adi
def extract_chain(server_handshake_bytes): """ Extracts the X.509 certificates from the server handshake bytes for use when debugging :param server_handshake_bytes: A byte string of the handshake data received from the server :return: A list of asn1crypto.x509.Certificate objects """ output = [] found = False message_bytes = None pointer = 0 while pointer < len(server_handshake_bytes): record_header = server_handshake_bytes[pointer:pointer + 5] record_type = record_header[0:1] record_length = int_from_bytes(record_header[3:]) sub_type = server_handshake_bytes[pointer + 5:pointer + 6] if record_type == b'\x16' and sub_type == b'\x0b': found = True message_bytes = server_handshake_bytes[pointer + 5:pointer + 5 + record_length] break pointer += 5 + record_length if found: # The first 7 bytes are the handshake type (1 byte) and total message # length (3 bytes) and cert chain length (3 bytes) pointer = 7 while pointer < len(message_bytes): cert_length = int_from_bytes(message_bytes[pointer:pointer + 3]) cert_start = pointer + 3 cert_end = cert_start + cert_length pointer = cert_end cert_bytes = message_bytes[cert_start:cert_end] output.append(Certificate.load(cert_bytes)) return output
def extract_chain(server_handshake_bytes): """ Extracts the X.509 certificates from the server handshake bytes for use when debugging :param server_handshake_bytes: A byte string of the handshake data received from the server :return: A list of asn1crypto.x509.Certificate objects """ output = [] found = False message_bytes = None pointer = 0 while pointer < len(server_handshake_bytes): record_header = server_handshake_bytes[pointer : pointer + 5] record_type = record_header[0:1] record_length = int_from_bytes(record_header[3:]) sub_type = server_handshake_bytes[pointer + 5 : pointer + 6] if record_type == b"\x16" and sub_type == b"\x0b": found = True message_bytes = server_handshake_bytes[pointer + 5 : pointer + 5 + record_length] break pointer += 5 + record_length if found: # The first 7 bytes are the handshake type (1 byte) and total message # length (3 bytes) and cert chain length (3 bytes) pointer = 7 while pointer < len(message_bytes): cert_length = int_from_bytes(message_bytes[pointer : pointer + 3]) cert_start = pointer + 3 cert_end = cert_start + cert_length pointer = cert_end cert_bytes = message_bytes[cert_start:cert_end] output.append(Certificate.load(cert_bytes)) return output
def _read_cert_bundle(ca_bundle_file): """ Reads a certificate file including certificates in PEM format """ from asn1crypto.x509 import Certificate from asn1crypto import pem certs = [] logger = getLogger(__name__) logger.debug('reading certificate bundle: %s', ca_bundle_file) all_certs = open(ca_bundle_file, 'rb').read() pem_certs = pem.unarmor(all_certs, multiple=True) for type_name, _, der_bytes in pem_certs: if type_name == 'CERTIFICATE': crt = Certificate.load(der_bytes) logger.debug("Found part of the chain..") certs.append(crt) return certs
def extract_chain(server_handshake_bytes): """ Extracts the X.509 certificates from the server handshake bytes for use when debugging :param server_handshake_bytes: A byte string of the handshake data received from the server :return: A list of asn1crypto.x509.Certificate objects """ output = [] chain_bytes = None for record_type, _, record_data in parse_tls_records(server_handshake_bytes): if record_type != b'\x16': continue for message_type, message_data in parse_handshake_messages(record_data): if message_type == b'\x0b': chain_bytes = message_data break if chain_bytes: break if chain_bytes: # The first 3 bytes are the cert chain length pointer = 3 while pointer < len(chain_bytes): cert_length = int_from_bytes(chain_bytes[pointer:pointer + 3]) cert_start = pointer + 3 cert_end = cert_start + cert_length pointer = cert_end cert_bytes = chain_bytes[cert_start:cert_end] output.append(Certificate.load(cert_bytes)) return output
def get_list(cache_length=24): """ Retrieves (and caches in memory) the list of CA certs from the OS :param cache_length: The number of hours to cache the CA certs in memory before they are refreshed :raises: oscrypto.errors.CACertsError - when an error occurs exporting/locating certs :return: A (copied) list of asn1crypto.x509.Certificate objects of the CA certs from the OS """ if not _in_memory_up_to_date(cache_length): with memory_lock: if not _in_memory_up_to_date(cache_length): _module_values['certs'] = [Certificate.load(cert) for cert in extract_from_system()] _module_values['last_update'] = time.time() return list(_module_values['certs'])
def extract_from_system(cert_callback=None, callback_only_on_failure=False): """ Extracts trusted CA certificates from the Windows certificate store :param cert_callback: A callback that is called once for each certificate in the trust store. It should accept two parameters: an asn1crypto.x509.Certificate object, and a reason. The reason will be None if the certificate is being exported, otherwise it will be a unicode string of the reason it won't. :param callback_only_on_failure: A boolean - if the callback should only be called when a certificate is not exported. :raises: OSError - when an error is returned by the OS crypto library :return: A list of 3-element tuples: - 0: a byte string of a DER-encoded certificate - 1: a set of unicode strings that are OIDs of purposes to trust the certificate for - 2: a set of unicode strings that are OIDs of purposes to reject the certificate for """ certificates = {} processed = {} now = datetime.datetime.utcnow() for store in ["ROOT", "CA"]: store_handle = crypt32.CertOpenSystemStoreW(null(), store) handle_error(store_handle) context_pointer = null() while True: context_pointer = crypt32.CertEnumCertificatesInStore(store_handle, context_pointer) if is_null(context_pointer): break context = unwrap(context_pointer) trust_all = False data = None digest = None if context.dwCertEncodingType != Crypt32Const.X509_ASN_ENCODING: continue data = bytes_from_buffer(context.pbCertEncoded, int(context.cbCertEncoded)) digest = hashlib.sha1(data).digest() if digest in processed: continue processed[digest] = True cert_info = unwrap(context.pCertInfo) not_before_seconds = _convert_filetime_to_timestamp(cert_info.NotBefore) try: not_before = datetime.datetime.fromtimestamp(not_before_seconds) if not_before > now: if cert_callback: cert_callback(Certificate.load(data), 'not yet valid') continue except (ValueError, OSError): # If there is an error converting the not before timestamp, # it is almost certainly because it is from too long ago, # which means the cert is definitely valid by now. pass not_after_seconds = _convert_filetime_to_timestamp(cert_info.NotAfter) try: not_after = datetime.datetime.fromtimestamp(not_after_seconds) if not_after < now: if cert_callback: cert_callback(Certificate.load(data), 'no longer valid') continue except (ValueError, OSError) as e: # The only reason we would get an exception here is if the # expiration time is so far in the future that it can't be # used as a timestamp, or it is before 0. If it is very far # in the future, the cert is still valid, so we only raise # an exception if the timestamp is less than zero. if not_after_seconds < 0: message = e.args[0] + ' - ' + str_cls(not_after_seconds) e.args = (message,) + e.args[1:] raise e trust_oids = set() reject_oids = set() # Here we grab the extended key usage properties that Windows # layers on top of the extended key usage extension that is # part of the certificate itself. For highest security, users # should only use certificates for the intersection of the two # lists of purposes. However, many seen to treat the OS trust # list as an override. to_read = new(crypt32, 'DWORD *', 0) res = crypt32.CertGetEnhancedKeyUsage( context_pointer, Crypt32Const.CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, null(), to_read ) # Per the Microsoft documentation, if CRYPT_E_NOT_FOUND is returned # from get_error(), it means the certificate is valid for all purposes error_code, _ = get_error() if not res and error_code != Crypt32Const.CRYPT_E_NOT_FOUND: handle_error(res) if error_code == Crypt32Const.CRYPT_E_NOT_FOUND: trust_all = True else: usage_buffer = buffer_from_bytes(deref(to_read)) res = crypt32.CertGetEnhancedKeyUsage( context_pointer, Crypt32Const.CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, cast(crypt32, 'CERT_ENHKEY_USAGE *', usage_buffer), to_read ) handle_error(res) key_usage_pointer = struct_from_buffer(crypt32, 'CERT_ENHKEY_USAGE', usage_buffer) key_usage = unwrap(key_usage_pointer) # Having no enhanced usage properties means a cert is distrusted if key_usage.cUsageIdentifier == 0: if cert_callback: cert_callback(Certificate.load(data), 'explicitly distrusted') continue oids = array_from_pointer( crypt32, 'LPCSTR', key_usage.rgpszUsageIdentifier, key_usage.cUsageIdentifier ) for oid in oids: trust_oids.add(oid.decode('ascii')) cert = None # If the certificate is not under blanket trust, we have to # determine what purposes it is rejected for by diffing the # set of OIDs from the certificate with the OIDs that are # trusted. if not trust_all: cert = Certificate.load(data) if cert.extended_key_usage_value: for cert_oid in cert.extended_key_usage_value: oid = cert_oid.dotted if oid not in trust_oids: reject_oids.add(oid) if cert_callback and not callback_only_on_failure: if cert is None: cert = Certificate.load(data) cert_callback(cert, None) certificates[digest] = (data, trust_oids, reject_oids) result = crypt32.CertCloseStore(store_handle, 0) handle_error(result) store_handle = None return certificates.values()
def get_path(temp_dir=None, cache_length=24, map_vendor_oids=True, cert_callback=None): """ Get the filesystem path to a file that contains OpenSSL-compatible CA certs. On OS X and Windows, there are extracted from the system certificate store and cached in a file on the filesystem. This path should not be writable by other users, otherwise they could inject CA certs into the trust list. :param temp_dir: The temporary directory to cache the CA certs in on OS X and Windows. Needs to have secure permissions so other users can not modify the contents. :param cache_length: The number of hours to cache the CA certs on OS X and Windows :param map_vendor_oids: A bool indicating if the following mapping of OIDs should happen for trust information from the OS trust list: - 1.2.840.113635.100.1.3 (apple_ssl) -> 1.3.6.1.5.5.7.3.1 (server_auth) - 1.2.840.113635.100.1.3 (apple_ssl) -> 1.3.6.1.5.5.7.3.2 (client_auth) - 1.2.840.113635.100.1.8 (apple_smime) -> 1.3.6.1.5.5.7.3.4 (email_protection) - 1.2.840.113635.100.1.9 (apple_eap) -> 1.3.6.1.5.5.7.3.13 (eap_over_ppp) - 1.2.840.113635.100.1.9 (apple_eap) -> 1.3.6.1.5.5.7.3.14 (eap_over_lan) - 1.2.840.113635.100.1.11 (apple_ipsec) -> 1.3.6.1.5.5.7.3.5 (ipsec_end_system) - 1.2.840.113635.100.1.11 (apple_ipsec) -> 1.3.6.1.5.5.7.3.6 (ipsec_tunnel) - 1.2.840.113635.100.1.11 (apple_ipsec) -> 1.3.6.1.5.5.7.3.7 (ipsec_user) - 1.2.840.113635.100.1.11 (apple_ipsec) -> 1.3.6.1.5.5.7.3.17 (ipsec_ike) - 1.2.840.113635.100.1.16 (apple_code_signing) -> 1.3.6.1.5.5.7.3.3 (code_signing) - 1.2.840.113635.100.1.20 (apple_time_stamping) -> 1.3.6.1.5.5.7.3.8 (time_stamping) - 1.3.6.1.4.1.311.10.3.2 (microsoft_time_stamp_signing) -> 1.3.6.1.5.5.7.3.8 (time_stamping) :param cert_callback: A callback that is called once for each certificate in the trust store. It should accept two parameters: an asn1crypto.x509.Certificate object, and a reason. The reason will be None if the certificate is being exported, otherwise it will be a unicode string of the reason it won't. This is only called on Windows and OS X when passed to this function. :raises: oscrypto.errors.CACertsError - when an error occurs exporting/locating certs :return: The full filesystem path to a CA certs file """ ca_path, temp = _ca_path(temp_dir) # Windows and OS X if temp and _cached_path_needs_update(ca_path, cache_length): empty_set = set() with path_lock: if _cached_path_needs_update(ca_path, cache_length): with open(ca_path, 'wb') as f: for cert, trust_oids, reject_oids in extract_from_system(cert_callback): if trust_oids == empty_set and reject_oids == empty_set: f.write(armor('CERTIFICATE', cert)) else: if map_vendor_oids: trust_oids = _map_oids(trust_oids) reject_oids = _map_oids(reject_oids) f.write(armor( 'TRUSTED CERTIFICATE', TrustedCertificate([ Certificate.load(cert), CertificateAux({ 'trust': trust_oids, 'reject': reject_oids, }) ]).dump() )) if not ca_path: raise CACertsError('No CA certs found') return ca_path
def get_path(temp_dir=None, cache_length=24, cert_callback=None): """ Get the filesystem path to a file that contains OpenSSL-compatible CA certs. On OS X and Windows, there are extracted from the system certificate store and cached in a file on the filesystem. This path should not be writable by other users, otherwise they could inject CA certs into the trust list. :param temp_dir: The temporary directory to cache the CA certs in on OS X and Windows. Needs to have secure permissions so other users can not modify the contents. :param cache_length: The number of hours to cache the CA certs on OS X and Windows :param cert_callback: A callback that is called once for each certificate in the trust store. It should accept two parameters: an asn1crypto.x509.Certificate object, and a reason. The reason will be None if the certificate is being exported, otherwise it will be a unicode string of the reason it won't. This is only called on Windows and OS X when passed to this function. :raises: oscrypto.errors.CACertsError - when an error occurs exporting/locating certs :return: The full filesystem path to a CA certs file """ ca_path, temp = _ca_path(temp_dir) # Windows and OS X if temp and _cached_path_needs_update(ca_path, cache_length): empty_set = set() any_purpose = '2.5.29.37.0' apple_ssl = '1.2.840.113635.100.1.3' win_server_auth = '1.3.6.1.5.5.7.3.1' with path_lock: if _cached_path_needs_update(ca_path, cache_length): with open(ca_path, 'wb') as f: for cert, trust_oids, reject_oids in extract_from_system(cert_callback, True): if sys.platform == 'darwin': if trust_oids != empty_set and any_purpose not in trust_oids \ and apple_ssl not in trust_oids: if cert_callback: cert_callback(Certificate.load(cert), 'implicitly distrusted for TLS') continue if reject_oids != empty_set and (apple_ssl in reject_oids or any_purpose in reject_oids): if cert_callback: cert_callback(Certificate.load(cert), 'explicitly distrusted for TLS') continue elif sys.platform == 'win32': if trust_oids != empty_set and any_purpose not in trust_oids \ and win_server_auth not in trust_oids: if cert_callback: cert_callback(Certificate.load(cert), 'implicitly distrusted for TLS') continue if reject_oids != empty_set and (win_server_auth in reject_oids or any_purpose in reject_oids): if cert_callback: cert_callback(Certificate.load(cert), 'explicitly distrusted for TLS') continue if cert_callback: cert_callback(Certificate.load(cert), None) f.write(armor('CERTIFICATE', cert)) if not ca_path: raise CACertsError('No CA certs found') return ca_path
def get_list(cache_length=24, map_vendor_oids=True, cert_callback=None): """ Retrieves (and caches in memory) the list of CA certs from the OS. Includes trust information from the OS - purposes the certificate should be trusted or rejected for. Trust information is encoded via object identifiers (OIDs) that are sourced from various RFCs and vendors (Apple and Microsoft). This trust information augments what is in the certificate itself. Any OID that is in the set of trusted purposes indicates the certificate has been explicitly trusted for a purpose beyond the extended key purpose extension. Any OID in the reject set is a purpose that the certificate should not be trusted for, even if present in the extended key purpose extension. *A list of common trust OIDs can be found as part of the `KeyPurposeId()` class in the `asn1crypto.x509` module of the `asn1crypto` package.* :param cache_length: The number of hours to cache the CA certs in memory before they are refreshed :param map_vendor_oids: A bool indicating if the following mapping of OIDs should happen for trust information from the OS trust list: - 1.2.840.113635.100.1.3 (apple_ssl) -> 1.3.6.1.5.5.7.3.1 (server_auth) - 1.2.840.113635.100.1.3 (apple_ssl) -> 1.3.6.1.5.5.7.3.2 (client_auth) - 1.2.840.113635.100.1.8 (apple_smime) -> 1.3.6.1.5.5.7.3.4 (email_protection) - 1.2.840.113635.100.1.9 (apple_eap) -> 1.3.6.1.5.5.7.3.13 (eap_over_ppp) - 1.2.840.113635.100.1.9 (apple_eap) -> 1.3.6.1.5.5.7.3.14 (eap_over_lan) - 1.2.840.113635.100.1.11 (apple_ipsec) -> 1.3.6.1.5.5.7.3.5 (ipsec_end_system) - 1.2.840.113635.100.1.11 (apple_ipsec) -> 1.3.6.1.5.5.7.3.6 (ipsec_tunnel) - 1.2.840.113635.100.1.11 (apple_ipsec) -> 1.3.6.1.5.5.7.3.7 (ipsec_user) - 1.2.840.113635.100.1.11 (apple_ipsec) -> 1.3.6.1.5.5.7.3.17 (ipsec_ike) - 1.2.840.113635.100.1.16 (apple_code_signing) -> 1.3.6.1.5.5.7.3.3 (code_signing) - 1.2.840.113635.100.1.20 (apple_time_stamping) -> 1.3.6.1.5.5.7.3.8 (time_stamping) - 1.3.6.1.4.1.311.10.3.2 (microsoft_time_stamp_signing) -> 1.3.6.1.5.5.7.3.8 (time_stamping) :param cert_callback: A callback that is called once for each certificate in the trust store. It should accept two parameters: an asn1crypto.x509.Certificate object, and a reason. The reason will be None if the certificate is being exported, otherwise it will be a unicode string of the reason it won't. :raises: oscrypto.errors.CACertsError - when an error occurs exporting/locating certs :return: A (copied) list of 3-element tuples containing CA certs from the OS trust ilst: - 0: an asn1crypto.x509.Certificate object - 1: a set of unicode strings of OIDs of trusted purposes - 2: a set of unicode strings of OIDs of rejected purposes """ if not _in_memory_up_to_date(cache_length): with memory_lock: if not _in_memory_up_to_date(cache_length): certs = [] for cert_bytes, trust_oids, reject_oids in extract_from_system(cert_callback): if map_vendor_oids: trust_oids = _map_oids(trust_oids) reject_oids = _map_oids(reject_oids) certs.append((Certificate.load(cert_bytes), trust_oids, reject_oids)) _module_values['certs'] = certs _module_values['last_update'] = time.time() return list(_module_values['certs'])