def create_ocsp_request(self, issuer, subject): """Creates CertId and OCSPRequest.""" cert_id = CertId({ "hash_algorithm": DigestAlgorithm({ "algorithm": "sha1", "parameters": None }), "issuer_name_hash": OctetString(subject.issuer.sha1), "issuer_key_hash": OctetString(issuer.public_key.sha1), "serial_number": subject.serial_number, }) ocsp_request = OCSPRequest({ "tbs_request": TBSRequest({ "version": Version(0), "request_list": Requests([Request({ "req_cert": cert_id, })]), }), }) return cert_id, ocsp_request
def deriveDigest(self, chain): chain_params = self.getChainParams(chain) # Chain ID self.chainid = chain_params["chain_id"] # Do not serialize signatures sigs = self.data["signatures"] self.data["signatures"] = [] # Get message to sign # bytes(self) will give the wire formated data according to # GrapheneObject and the data given in __init__() self.message = OctetString(unhexlify(self.chainid)).dump() for name, value in list(self.data.items()): if name == "operations": for operation in value: if isinstance(value, string_types): b = py23_bytes(operation, 'utf-8') else: b = py23_bytes(operation) self.message += OctetString(b).dump() elif name != "signatures": if isinstance(value, string_types): b = py23_bytes(value, 'utf-8') else: b = py23_bytes(value) self.message += OctetString(b).dump() self.digest = hashlib.sha256(self.message).digest() # restore signatures self.data["signatures"] = sigs
def _create_ocsp_request(issuer, subject): """ Create CertId and OCSPRequest """ cert_id = CertId({ 'hash_algorithm': DigestAlgorithm({ 'algorithm': u'sha1', 'parameters': None }), 'issuer_name_hash': OctetString(subject.issuer.sha1), 'issuer_key_hash': OctetString(issuer.public_key.sha1), 'serial_number': subject.serial_number, }) req = OCSPRequest({ 'tbs_request': TBSRequest({ 'version': Version(0), 'request_list': Requests([Request({ 'req_cert': cert_id, })]), }), }) return cert_id, req
def encode_cert_id_key(self, hkey): issuer_name_hash, issuer_key_hash, serial_number = hkey issuer_name_hash = OctetString.load(issuer_name_hash) issuer_key_hash = OctetString.load(issuer_key_hash) serial_number = Integer.load(serial_number) cert_id = CertId({ 'hash_algorithm': DigestAlgorithm({ 'algorithm': 'sha1', 'parameters': None}), 'issuer_name_hash': issuer_name_hash, 'issuer_key_hash': issuer_key_hash, 'serial_number': serial_number, }) return cert_id
def generate_private_key(self): parameters = self.session.create_domain_parameters( KeyType.EC, {Attribute.EC_PARAMS: encode_named_curve_parameters('secp256r1')}, local=True) public_template = { Attribute.KEY_TYPE: KeyType.EC, Attribute.CLASS: ObjectClass.PUBLIC_KEY, Attribute.TOKEN: True, Attribute.VERIFY: True, } private_template = { Attribute.KEY_TYPE: KeyType.EC, Attribute.CLASS: ObjectClass.PRIVATE_KEY, Attribute.TOKEN: True, Attribute.PRIVATE: True, Attribute.SIGN: True, Attribute.EXTRACTABLE: False, Attribute.SENSITIVE: True } public_key, private_key = parameters.generate_keypair( store=True, public_template=public_template, private_template=private_template) ecpt = bytes(OctetString.load(public_key[Attribute.EC_POINT])) hash = hashlib.sha256(ecpt) ski = hash.digest() hexski = hash.hexdigest() public_key[Attribute.ID] = ski public_key[Attribute.LABEL] = hexski private_key[Attribute.ID] = ski private_key[Attribute.LABEL] = hexski return PKCS11KeyPair(public_key, private_key)
def decode_ec_public_key(der, encode_ec_point=True): """ Decode a DER-encoded EC public key as stored by OpenSSL into a dictionary of attributes able to be passed to :meth:`pkcs11.Session.create_object`. .. note:: **encode_ec_point** For use as an attribute `EC_POINT` should be DER-encoded (True). For key derivation implementations can vary. Since v2.30 the specification says implementations MUST accept a raw `EC_POINT` for ECDH (False), however not all implementations follow this yet. :param bytes der: DER-encoded key :param encode_ec_point: See text. :rtype: dict(Attribute,*) """ asn1 = PublicKeyInfo.load(der) assert asn1.algorithm == 'ec', \ "Wrong algorithm, not an EC key!" ecpoint = bytes(asn1['public_key']) if encode_ec_point: ecpoint = OctetString(ecpoint).dump() return { Attribute.KEY_TYPE: KeyType.EC, Attribute.CLASS: ObjectClass.PUBLIC_KEY, Attribute.EC_PARAMS: asn1['algorithm']['parameters'].dump(), Attribute.EC_POINT: ecpoint, }
def make_signed_attrs(digest: bytes, hash_type: int) -> CMSAttributes: content_type = CMSAttribute({ "type": CMSAttributeType.unmap("content_type"), "values": [ContentType.unmap("data")], }) time_now = UTCTime() time_now.set(datetime.now(timezone.utc)) signing_time = CMSAttribute({ "type": CMSAttributeType.unmap("signing_time"), "values": [time_now] }) message_digest = CMSAttribute({ "type": CMSAttributeType.unmap("message_digest"), "values": [OctetString(digest)], }) ha_v1 = make_hash_agility_v1(digest) ha_v2 = make_hash_agility_v2(digest, hash_type) return CMSAttributes( [content_type, signing_time, message_digest, ha_v1, ha_v2])
def finalize(self) -> Tuple[EnvelopedData, Union[TripleDES, AES], bytes]: """Encrypt the data and process the key using all available recipients. Returns: EnvelopedData, TripleDES, iv (bytes): The PKCSPKIEnvelope structure, The symmetric key, and the IV for the symmetric key. """ sym_key, iv, ciphertext = self._encrypt_data(self._data) eci = EncryptedContentInfo({ 'content_type': ContentType('data'), 'content_encryption_algorithm': EncryptionAlgorithm({ 'algorithm': self._encryption_algorithm_id, 'parameters': OctetString(iv), }), 'encrypted_content': ciphertext, }) recipients = [ self._build_recipient_info(sym_key.key, recipient) for recipient in self._recipients ] recipient_infos = RecipientInfos(recipients) ed = EnvelopedData({ 'version': 1, 'recipient_infos': recipient_infos, 'encrypted_content_info': eci, }) return ed, sym_key, iv
def encode_cert_id_key(self, hkey): issuer_name_hash, issuer_key_hash, serial_number = hkey issuer_name_hash = OctetString.load(issuer_name_hash) issuer_key_hash = OctetString.load(issuer_key_hash) serial_number = Integer.load(serial_number) cert_id = CertId({ "hash_algorithm": DigestAlgorithm({ "algorithm": "sha1", "parameters": None }), "issuer_name_hash": issuer_name_hash, "issuer_key_hash": issuer_key_hash, "serial_number": serial_number, }) return cert_id
def __bytes__(self): if self.data is None: return py23_bytes() b = b"" output = b"" for name, value in list(self.data.items()): if name == "operations": for operation in value: if isinstance(value, string_types): b = py23_bytes(operation, 'utf-8') else: b = py23_bytes(operation) output += OctetString(b).dump() elif name != "signatures": if isinstance(value, string_types): b = py23_bytes(value, 'utf-8') else: b = py23_bytes(value) output += OctetString(b).dump() return output
def make_hash_agility_v2(digest: bytes, hash_type: int) -> CMSAttribute: """ CMSAttribute: type: HASH_AGILITY_V2_OID values: Set of HashAgility type: DigestAlgorithmId data: digest """ dg_algo = _get_digest_algo(hash_type) ha = HashAgility({"type": dg_algo, "data": OctetString(digest)}) return CMSAttribute({"type": HASH_AGILITY_V2_OID, "values": [ha]})
def encode(byte_string, is_der = None, alg = 'Curve25519' ): try: raw = OctetString(byte_string) except Exception as e: raise FailedToParseByteString privateKey = PrivateKey(raw.dump()) privateKeyAlgorithmIdentifier = PrivateKeyAlgorithmIdentifier( {'algorithm': alg }); oneAsymmetricKey = OneAsymmetricKey({ 'version': Integer(0), 'privateKeyAlgorithm': privateKeyAlgorithmIdentifier, 'privateKey': privateKey}) der = oneAsymmetricKey.dump() if is_der: return der return pem.armor('PRIVATE KEY',der).decode('ASCII')
def make_cms( cert: Certificate, hash_type: int, signed_attrs: CMSAttributes, sig: bytes, unsigned_attrs: Optional[CMSAttributes], ) -> ContentInfo: sid = SignerIdentifier( "issuer_and_serial_number", IssuerAndSerialNumber({ "issuer": cert["tbs_certificate"]["issuer"], "serial_number": cert["tbs_certificate"]["serial_number"], }), ) dg_algo = DigestAlgorithm({"algorithm": _get_digest_algo(hash_type)}) sig_algo = SignedDigestAlgorithm( {"algorithm": SignedDigestAlgorithmId("rsassa_pkcs1v15")}) sig_info = SignerInfo({ "version": CMSVersion(1), "sid": sid, "digest_algorithm": dg_algo, "signed_attrs": signed_attrs, "signature_algorithm": sig_algo, "signature": OctetString(sig), "unsigned_attrs": unsigned_attrs, }) certs = make_certificate_chain(cert) signed_data = SignedData({ "version": CMSVersion(1), "digest_algorithms": [dg_algo], "encap_content_info": ContentInfo({"content_type": ContentType("data")}), "certificates": certs, "signer_infos": [sig_info], }) return ContentInfo({ "content_type": ContentType.unmap("signed_data"), "content": signed_data })
def make_hash_agility_v1(digest: bytes) -> CMSAttribute: """ CMSAttribue: type: HASH_AGILITY_V1_OID values: Set of 1 XML Plist dict: { "cdhashes": [digset truncated to 20 bytes] } """ plist_dict = {"cdhashes": [digest[:20]]} plist_bytes = plistlib.dumps(plist_dict, fmt=plistlib.FMT_XML) return CMSAttribute({ "type": HASH_AGILITY_V1_OID, "values": [OctetString(plist_bytes)] })
def encode_ec_public_key(key): """ Encode a DER-encoded EC public key as stored by OpenSSL. :param PublicKey key: EC public key :rtype: bytes """ ecparams = ECDomainParameters.load(key[Attribute.EC_PARAMS]) ecpoint = bytes(OctetString.load(key[Attribute.EC_POINT])) return PublicKeyInfo({ 'algorithm': { 'algorithm': 'ec', 'parameters': ecparams, }, 'public_key': ecpoint, }).dump()
def get_timestamp_token(digest: bytes, hash_type: int): # Create a TimestampRequest dg_algo = DigestAlgorithm({"algorithm": _get_digest_algo(hash_type)}) imprint = MessageImprint({ "hash_algorithm": dg_algo, "hashed_message": OctetString(digest) }) tsreq = TimeStampReq({ "version": Version(1), "message_imprint": imprint, "cert_req": True, }) # Send tsreq to the server headers = {"Content-Type": "application/timestamp-query"} resp = requests.post(TIMESTAMP_SERVER, data=tsreq.dump(), headers=headers) resp.raise_for_status() tsresp = TimeStampResp.load(resp.content) return tsresp["time_stamp_token"]
def build(self, signing_private_key_path, debug=False): """ Validates the certificate information, constructs the ASN.1 structure and then signs it :param signing_private_key: path to a .pem file with a private key :return: An m2m.Certificate object of the newly signed certificate """ if self._self_signed is not True and self._issuer is None: raise ValueError(_pretty_message( ''' Certificate must be self-signed, or an issuer must be specified ''' )) if self._self_signed: self._issuer = self._subject if self.serial_number is None: time_part = int_to_bytes(int(time.time())) random_part = random.getrandbits(24).to_bytes(3, byteorder='big') # Must contain at least 20 randomly generated BITS self.serial_number = int_from_bytes(time_part + random_part) # Only re non-optionals are always in this dict properties = { 'version':Integer(value=self._version), 'serialNumber':OctetString(value=self.serial_number.to_bytes(20, byteorder='big')), 'subject':self.subject, } # Optional fields are only added if they're not None if self.ca_algorithm is not None: properties['cAAlgorithm'] = self.ca_algorithm if self.ca_algorithm_parameters is not None: properties['cAAlgParams'] = OctetString(value=self.ca_algorithm_parameters) if self.issuer is not None: properties['issuer'] = self.issuer if self.valid_from is not None: properties['validFrom'] = self.valid_from if self.valid_duration is not None: properties['validDuration'] = self.valid_duration if self.pk_algorithm is not None: properties['pKAlgorithm'] = self.pk_algorithm if self.pk_algorithm_parameters is not None: properties['pKAlgParams'] = OctetString(value=self.pk_algorithm_parameters) if self.public_key is not None: properties['pubKey'] = OctetString(value=self.public_key) if self.authkey_id is not None: properties['authKeyId'] = self.authkey_id if self.subject_key_id is not None: properties['subjKeyId'] = OctetString(value=self.subject_key_id) if self.key_usage is not None: properties['keyUsage'] = OctetString(value=self.key_usage) if self.basic_constraints is not None: properties['basicConstraints'] = Integer(value=self.basic_constraints) if self.certificate_policy is not None: properties['certificatePolicy'] = self.certificate_policy if self.subject_alternative_name is not None: properties['subjectAltName'] = self.subject_alternative_name if self.issuer_alternative_name is not None: properties['issuerAltName'] = self.issuer_alternative_name if self.extended_key_usage is not None: properties['extendedKeyUsage'] = self.extended_key_usage if self.auth_info_access_ocsp is not None: properties['authInfoAccessOCSP'] = self.auth_info_access_ocsp if self.crl_distribution_point_uri is not None: properties['cRLDistribPointURI'] = self.crl_distribution_point_uri if self.x509_extensions is not None: properties['x509extensions'] = self.x509_extensions # import ipdb; ipdb.set_trace() # break /usr/local/lib/python3.5/dist-packages/asn1crypto/core.py:2786 tbs_cert = TBSCertificate(properties) bytes_to_sign = tbs_cert.dump() signature = generate_signature(bytes_to_sign, signing_private_key_path) # assert verify_signature(bytes_to_sign, signature, "public.pem") if debug: print("Build - Signed_bytes ({len}): {content}".format(len=len(bytes_to_sign), content=hexlify(bytes_to_sign))) print("Build - Signature ({len}): {content}".format(len=len(signature), content=hexlify(signature))) return Certificate({ 'tbsCertificate': tbs_cert, 'cACalcValue': signature })
def asn1(self) -> _asn1.ImgGroupValue: return _asn1.ImgGroupValue({"ECPoint": OctetString(bytes(self))})
def parse_general_name(name: ParsableGeneralName) -> x509.GeneralName: """Parse a general name from user input. This function will do its best to detect the intended type of any value passed to it: >>> parse_general_name('example.com') <DNSName(value='example.com')> >>> parse_general_name('*.example.com') <DNSName(value='*.example.com')> >>> parse_general_name('.example.com') # Syntax used e.g. for NameConstraints: All levels of subdomains <DNSName(value='.example.com')> >>> parse_general_name('*****@*****.**') <RFC822Name(value='*****@*****.**')> >>> parse_general_name('https://example.com') <UniformResourceIdentifier(value='https://example.com')> >>> parse_general_name('1.2.3.4') <IPAddress(value=1.2.3.4)> >>> parse_general_name('fd00::1') <IPAddress(value=fd00::1)> >>> parse_general_name('/CN=example.com') <DirectoryName(value=<Name(CN=example.com)>)> The default fallback is to assume a :py:class:`~cg:cryptography.x509.DNSName`. If this doesn't work, an exception will be raised: >>> parse_general_name('foo..bar`*123') # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Could not parse name: foo..bar`*123 If you want to override detection, you can prefix the name to match :py:const:`GENERAL_NAME_RE`: >>> parse_general_name('email:[email protected]') <RFC822Name(value='*****@*****.**')> >>> parse_general_name('URI:https://example.com') <UniformResourceIdentifier(value='https://example.com')> >>> parse_general_name('dirname:/CN=example.com') <DirectoryName(value=<Name(CN=example.com)>)> Some more exotic values can only be generated by using this prefix: >>> parse_general_name('rid:2.5.4.3') <RegisteredID(value=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>)> >>> parse_general_name('otherName:2.5.4.3;UTF8:example.com') <OtherName(type_id=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=b'example.com')> If you give a prefixed value, this function is less forgiving of any typos and does not catch any exceptions: >>> parse_general_name('email:foo@bar com') Traceback (most recent call last): ... ValueError: Invalid domain: bar com """ # pylint: disable=too-many-return-statements,too-many-branches,too-many-statements if isinstance(name, x509.GeneralName): return name if not isinstance(name, str): raise ValueError( "Cannot parse general name %s: Must be of type str (was: %s)." % (name, type(name).__name__) ) typ = None match = GENERAL_NAME_RE.match(name) if match is not None: typ, name = match.groups() typ = typ.lower() if typ is None: if re.match("[a-z0-9]{2,}://", name): # Looks like a URI try: return x509.UniformResourceIdentifier(encode_url(name)) except idna.IDNAError: pass if "@" in name: # Looks like an Email address try: return x509.RFC822Name(validate_email(name)) except ValueError: pass if name.strip().startswith("/"): # maybe it's a dirname? return x509.DirectoryName(x509_name(name)) # Try to parse this as IPAddress/Network try: return x509.IPAddress(ip_address(name)) except ValueError: pass try: return x509.IPAddress(ip_network(name)) except ValueError: pass # Almost anything passes as DNS name, so this is our default fallback try: return x509.DNSName(encode_dns(name)) except idna.IDNAError as e: raise ValueError("Could not parse name: %s" % name) from e if typ == "uri": try: return x509.UniformResourceIdentifier(encode_url(name)) except idna.IDNAError as e: raise ValueError("Could not parse DNS name in URL: %s" % name) from e elif typ == "email": return x509.RFC822Name(validate_email(name)) # validate_email already raises ValueError elif typ == "ip": try: return x509.IPAddress(ip_address(name)) except ValueError: pass try: return x509.IPAddress(ip_network(name)) except ValueError: pass raise ValueError("Could not parse IP address.") elif typ == "rid": return x509.RegisteredID(x509.ObjectIdentifier(name)) elif typ == "othername": match = re.match("(.*);(.*):(.*)", name) if match is not None: oid, asn_typ, val = match.groups() if asn_typ == "UTF8": parsed_value = val.encode("utf-8") elif asn_typ == "OctetString": parsed_value = OctetString(bytes(bytearray.fromhex(val))).dump() else: raise ValueError("Unsupported ASN type in otherName: %s" % asn_typ) return x509.OtherName(x509.ObjectIdentifier(oid), parsed_value) raise ValueError("Incorrect otherName format: %s" % name) elif typ == "dirname": return x509.DirectoryName(x509_name(name)) else: try: return x509.DNSName(encode_dns(name)) except idna.IDNAError as e: raise ValueError("Could not parse DNS name: %s" % name) from e
def sign(self): h = hashes.Hash(hashes.SHA256(), backend=default_backend()) h.update(self._content_mime.as_bytes()) message_digest = h.finalize() cs = CertificateSet() cs.append(load(self._certificate.public_bytes(Encoding.DER))) for ca_cert in self._ca: cs.append(load(ca_cert.public_bytes(Encoding.DER))) ec = ContentInfo({ 'content_type': ContentType('data'), }) sident = SignerIdentifier({ 'issuer_and_serial_number': IssuerAndSerialNumber({ 'issuer': load(self._issuer_name.public_bytes(default_backend())), 'serial_number': self._cert_serial, }) }) certv2 = ESSCertIDv2({ 'hash_algorithm': DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), 'cert_hash': OctetString(self._certificate.fingerprint(hashes.SHA256())), 'issuer_serial': IssuerSerial({ 'issuer': load(self._issuer_name.public_bytes(default_backend())), 'serial_number': self._cert_serial, }), }) now = datetime.now().replace(microsecond=0, tzinfo=pytz.utc) # .isoformat() sattrs = CMSAttributes({ CMSAttribute({ 'type': CMSAttributeType('content_type'), 'values': ["data"] }), CMSAttribute({ 'type': CMSAttributeType('message_digest'), 'values': [message_digest] }), CMSAttribute({ 'type': CMSAttributeType('signing_time'), 'values': (Time({'utc_time': UTCTime(now)}), ) }), CMSAttribute({ 'type': CMSAttributeType('signing_certificate_v2'), 'values': [SigningCertificateV2({'certs': (certv2, )})] }) }) signature = self._private_key.sign(sattrs.dump(), padding.PKCS1v15(), hashes.SHA256()) # si = SignerInfo({ 'version': 'v1', 'sid': sident, 'digest_algorithm': DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), 'signed_attrs': sattrs, 'signature_algorithm': SignedDigestAlgorithm( {'algorithm': SignedDigestAlgorithmId('rsassa_pkcs1v15')}), 'signature': signature, }) da = DigestAlgorithms( (DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), )) signed_data = SignedData({ 'version': 'v1', 'encap_content_info': ec, 'certificates': cs, 'digest_algorithms': da, 'signer_infos': SignerInfos((si, )) }) ci = ContentInfo({ 'content_type': ContentType('signed_data'), 'content': signed_data }) self._signature_mime = MIMEApplication(ci.dump(), _subtype="pkcs7-signature", name="smime.p7s", policy=email.policy.SMTPUTF8) self._signature_mime.add_header('Content-Disposition', 'attachment; filename=smime.p7s') super(CADESMIMESignature, self).attach(self._content_mime) super(CADESMIMESignature, self).attach(self._signature_mime)
def sign(self): h = hashes.Hash(hashes.SHA256(), backend=default_backend()) h.update(self._content_mime.as_bytes()) message_digest = h.finalize() cs = CertificateSet() cs.append(load(self._certificate.public_bytes(Encoding.DER))) for ca_cert in self._ca: cs.append(load(ca_cert.public_bytes(Encoding.DER))) ec = EncapsulatedContentInfo({ 'content_type': ContentType('data'), 'content': ParsableOctetString(self._content_mime.as_bytes()) }) sident = SignerIdentifier({ 'issuer_and_serial_number': IssuerAndSerialNumber({ 'issuer': load(self._issuer_name.public_bytes(default_backend())), 'serial_number': self._cert_serial, }) }) certv2 = ESSCertIDv2({ 'hash_algorithm': DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), 'cert_hash': OctetString(self._certificate.fingerprint(hashes.SHA256())), 'issuer_serial': IssuerSerial({ 'issuer': load( self._issuer_name.public_bytes(default_backend()) ), #[GeneralName({'directory_name': self._issuer_name.public_bytes(default_backend())})], 'serial_number': self._cert_serial, }), }) now = datetime.now().replace(microsecond=0, tzinfo=pytz.utc) sattrs = CMSAttributes({ CMSAttribute({ 'type': CMSAttributeType('content_type'), 'values': ["data"] }), CMSAttribute({ 'type': CMSAttributeType('message_digest'), 'values': [message_digest] }), CMSAttribute({ 'type': CMSAttributeType('signing_time'), 'values': (Time({'utc_time': UTCTime(now)}), ) }), # isti k v CMSAttribute({ 'type': CMSAttributeType('signing_certificate_v2'), 'values': [SigningCertificateV2({'certs': (certv2, )})] }) }) signature = self._private_key.sign(sattrs.dump(), padding.PKCS1v15(), hashes.SHA256()) si = SignerInfo({ 'version': 'v1', 'sid': sident, 'digest_algorithm': DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), 'signed_attrs': sattrs, 'signature_algorithm': SignedDigestAlgorithm( {'algorithm': SignedDigestAlgorithmId('rsassa_pkcs1v15')}), 'signature': signature, }) da = DigestAlgorithms( (DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), )) signed_data = SignedData({ 'version': 'v3', 'encap_content_info': ec, 'certificates': cs, 'digest_algorithms': da, 'signer_infos': SignerInfos((si, )) }) ci = ContentInfo({ 'content_type': ContentType('signed_data'), 'content': signed_data }) self.set_payload(ci.dump()) encode_base64(self)
def parse_general_name(name): """Parse a general name from user input. This function will do its best to detect the intended type of any value passed to it: >>> parse_general_name('example.com') <DNSName(value='example.com')> >>> parse_general_name('*.example.com') <DNSName(value='*.example.com')> >>> parse_general_name('.example.com') # Syntax used e.g. for NameConstraints: All levels of subdomains <DNSName(value='.example.com')> >>> parse_general_name('*****@*****.**') <RFC822Name(value='*****@*****.**')> >>> parse_general_name('https://example.com') <UniformResourceIdentifier(value='https://example.com')> >>> parse_general_name('1.2.3.4') <IPAddress(value=1.2.3.4)> >>> parse_general_name('fd00::1') <IPAddress(value=fd00::1)> >>> parse_general_name('/CN=example.com') <DirectoryName(value=<Name(CN=example.com)>)> The default fallback is to assume a :py:class:`~cg:cryptography.x509.DNSName`. If this doesn't work, an exception will be raised: >>> parse_general_name('foo..bar`*123') # doctest: +ELLIPSIS Traceback (most recent call last): ... idna.core.IDNAError: ... If you want to override detection, you can prefix the name to match :py:const:`GENERAL_NAME_RE`: >>> parse_general_name('email:[email protected]') <RFC822Name(value='*****@*****.**')> >>> parse_general_name('URI:https://example.com') <UniformResourceIdentifier(value='https://example.com')> >>> parse_general_name('dirname:/CN=example.com') <DirectoryName(value=<Name(CN=example.com)>)> Some more exotic values can only be generated by using this prefix: >>> parse_general_name('rid:2.5.4.3') <RegisteredID(value=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>)> >>> parse_general_name('otherName:2.5.4.3;UTF8:example.com') <OtherName(type_id=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=b'example.com')> If you give a prefixed value, this function is less forgiving of any typos and does not catch any exceptions: >>> parse_general_name('email:foo@bar com') Traceback (most recent call last): ... ValueError: Invalid domain: bar com """ name = force_text(name) typ = None match = GENERAL_NAME_RE.match(name) if match is not None: typ, name = match.groups() typ = typ.lower() if typ is None: if re.match('[a-z0-9]{2,}://', name): # Looks like a URI try: return x509.UniformResourceIdentifier(name) except Exception: # pragma: no cover - this really accepts anything pass if '@' in name: # Looks like an Email address try: return x509.RFC822Name(validate_email(name)) except Exception: pass if name.strip().startswith('/'): # maybe it's a dirname? return x509.DirectoryName(x509_name(name)) # Try to parse this as IPAddress/Network try: return x509.IPAddress(ip_address(name)) except ValueError: pass try: return x509.IPAddress(ip_network(name)) except ValueError: pass # Try to encode as domain name. DNSName() does not validate the domain name, but this check will fail. if name.startswith('*.'): idna.encode(name[2:]) elif name.startswith('.'): idna.encode(name[1:]) else: idna.encode(name) # Almost anything passes as DNS name, so this is our default fallback return x509.DNSName(name) if typ == 'uri': return x509.UniformResourceIdentifier(name) elif typ == 'email': return x509.RFC822Name(validate_email(name)) elif typ == 'ip': try: return x509.IPAddress(ip_address(name)) except ValueError: pass try: return x509.IPAddress(ip_network(name)) except ValueError: pass raise ValueError('Could not parse IP address.') elif typ == 'rid': return x509.RegisteredID(x509.ObjectIdentifier(name)) elif typ == 'othername': regex = "(.*);(.*):(.*)" if re.match(regex, name) is not None: oid, asn_typ, val = re.match(regex, name).groups() oid = x509.ObjectIdentifier(oid) if asn_typ == 'UTF8': val = val.encode('utf-8') elif asn_typ == 'OctetString': val = bytes(bytearray.fromhex(val)) val = OctetString(val).dump() else: raise ValueError('Unsupported ASN type in otherName: %s' % asn_typ) val = force_bytes(val) return x509.OtherName(oid, val) else: raise ValueError('Incorrect otherName format: %s' % name) elif typ == 'dirname': return x509.DirectoryName(x509_name(name)) else: # Try to encode the domain name. DNSName() does not validate the domain name, but this # check will fail. if name.startswith('*.'): idna.encode(name[2:]) elif name.startswith('.'): idna.encode(name[1:]) else: idna.encode(name) return x509.DNSName(name)
from asn1crypto.core import Sequence, OctetString data = bytes.fromhex('605e06062b0601050502a0543052a024302206092a864882f71201020206092a864886f712010202060a2b06010401823702020aa32a3028a0261b246e6f745f646566696e65645f696e5f5246433431373840706c656173655f69676e6f7265') #data = bytes.fromhex('6E8201FE308201FAA003020105A10302010EA20703050000000000A38201416182013D30820139A003020105A10F1B0D465245454950412E4C4F43414CA21D301BA003020101A11430121B066B61646D696E1B086368616E67657077A38201003081FDA003020112A103020101A281F00481EDECC2A53967B412D791DFF3EA3D50F765DC7ED7C7E66912C836163F5BD0A07FC679E46D36C9B38A2273C877D233AD55FAB9F3D95637F8F1DC22117723E77537C92D909064DE10B26E86C9EFDCCF37CC16D20E75849D0CBD04A56E7F69D46C6D7DB9DDDC6ACBBE37D6CF49C6CC78C57228C0E903FDC08772B030DD22DC84B5D55C66E07279E9840A3EA68F1C27BA26305D1CD05D1E3A994A4246DB8E834948EFD3788409760994AF1A72F5CF1485C49C7646A3B72C460FD62F5C373C224ECE0859F4DDEF5B77BF75A9AB220524E00A35A357722F703A218C5FD1A717ED0392F19864BF0B52921B501906A8AF48C3A4819F30819CA003020112A28194048191EAD1DF7495E86BFEC932DBA81C9A764826080BB8C359AC3627C4B2CE530217042449E9CAA3DB66031FBE4B1CF942EC9EC773A2FB2485DD4D6E1271F9FF41D26C54CE9370D6E4573156CDC051944A563056BFA1D47CECEFF3CB4AC455FE33CD03E91BA9B4DC2243CE59EF0E1865AEBDBA76E30EB2AD8DEB71409B11F86CFA6C6E488270303C0451BD86A91C139018421A07') #data = b'$\x80\x04\r\x8d\xff\xf0\x98\x076\xaf\x93nB:\xcf\xcc\x04\x15\x92w\xf7\xf0\xe4y\xff\xc7\xdc3\xb2\xd0={\x1a\x18mDr\xaaI\x00\x00' a = OctetString.load(data) print(data) print(a) #parsed = Sequence.load(data) #serialized = parsed.dump()