def test_fix_tagging_choice(self): correct = core.Integer(200, tag_type='explicit', tag=2) choice = NumChoice(name='three', value=core.Integer(200, tag_type='explicit', tag=1)) self.assertEqual(correct.dump(), choice.dump()) self.assertEqual(correct.tag_type, choice.chosen.tag_type) self.assertEqual(correct.explicit_tag, choice.chosen.explicit_tag)
def test_fix_tagging_choice(self): correct = core.Integer(200, explicit=2) choice = NumChoice(name='three', value=core.Integer(200, explicit=1)) self.assertEqual(correct.dump(), choice.dump()) self.assertEqual(correct.explicit, choice.chosen.explicit) choice2 = NumChoiceOldApi(name='three', value=core.Integer(200, explicit=1)) self.assertEqual(correct.dump(), choice2.dump()) self.assertEqual(correct.explicit, choice2.chosen.explicit)
def format_tbs_crl(self, crl_number: int, this_update: datetime, revoked_certs, next_update: datetime, distpoint: x509.DistributionPoint = None) \ -> crl.TbsCertList: extensions = [ crl.TBSCertListExtension({ 'extn_id': 'crl_number', 'extn_value': core.Integer(crl_number) }), crl.TBSCertListExtension({ 'extn_id': 'authority_key_identifier', 'extn_value': x509.AuthorityKeyIdentifier({ 'key_identifier': self.authority_key_identifier }) }), ] extensions.extend(self.extra_crl_extensions) if distpoint is not None: extn_value = crl.IssuingDistributionPoint(distpoint) extensions.append( crl.TBSCertListExtension({ 'extn_id': 'issuing_distribution_point', 'critical': True, 'extn_value': core.ParsableOctetString(extn_value.dump()) }) ) revoked = crl.RevokedCertificates(revoked_certs) return crl.TbsCertList({ 'version': 'v2', 'signature': self.signature_algo, 'issuer': self.issuer_name, 'this_update': x509.Time({'general_time': this_update}), 'next_update': x509.Time({'general_time': next_update}), 'revoked_certificates': revoked, 'crl_extensions': crl.TBSCertListExtensions(extensions) })
def test_concat(self): child1 = Seq({'id': '1.2.3', 'value': 1}) child2 = core.Integer(0) parent = ConcatTest([child1, child2]) self.assertEqual(child1, parent[0]) self.assertEqual(child2, parent[1]) self.assertEqual(child1.dump() + child2.dump(), parent.dump())
def test_timestamp(requests_mock, setup): setup.illusionist.register(requests_mock) hashed_bytes = hashlib.sha256(b'test').digest() req = tsp.TimeStampReq({ 'version': 'v2', 'message_imprint': tsp.MessageImprint({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': 'sha256'}), 'hashed_message': hashed_bytes }), 'nonce': core.Integer(0x1337), 'cert_req': True }) response = requests.post("http://test.test/testing-ca/tsa/tsa", data=req.dump()) resp: tsp.TimeStampResp = tsp.TimeStampResp.load(response.content) sd = resp['time_stamp_token']['content'] tst_info: tsp.TSTInfo = sd['encap_content_info']['content'].parsed assert tst_info['nonce'].native == 0x1337 assert tst_info['gen_time'].native \ == datetime.now().replace(tzinfo=pytz.utc)
def _unwrap_private_key_info(key_info): """ Unwraps an asn1crypto.keys.PrivateKeyInfo object into an asn1crypto.keys.RSAPrivateKey, asn1crypto.keys.DSAPrivateKey or asn1crypto.keys.ECPrivateKey. :param key_info: An asn1crypto.keys.PrivateKeyInfo object :return: One of: - asn1crypto.keys.RSAPrivateKey - asn1crypto.keys.DSAPrivateKey - asn1crypto.keys.ECPrivateKey """ if key_info.algorithm == 'rsa': return key_info['private_key'].parsed if key_info.algorithm == 'dsa': params = key_info['private_key_algorithm']['parameters'] parsed = key_info['private_key'].parsed return keys.DSAPrivateKey({ 'version': 0, 'p': params['p'], 'q': params['q'], 'g': params['g'], 'public_key': core.Integer( pow(params['g'].native, parsed.native, params['p'].native)), 'private_key': parsed, }) if key_info.algorithm == 'ec': parsed = key_info['private_key'].parsed parsed['parameters'] = key_info['private_key_algorithm']['parameters'] return parsed raise ValueError('Unsupported key_info.algorithm "%s"' % key_info.algorithm)
def compare_primitive_info(): return ( (core.ObjectIdentifier('1.2.3'), core.ObjectIdentifier('1.2.3'), True), (core.Integer(1), Enum(1), False), (core.Integer(1), core.Integer(1, implicit=5), True), (core.Integer(1), core.Integer(1, explicit=5), True), (core.Integer(1), core.Integer(2), False), (core.OctetString(b''), core.OctetString(b''), True), (core.OctetString(b''), core.OctetString(b'1'), False), (core.OctetString(b''), core.OctetBitString(b''), False), (core.ParsableOctetString(b'12'), core.OctetString(b'12'), True), (core.ParsableOctetBitString(b'12'), core.OctetBitString(b'12'), True), (core.UTF8String('12'), core.UTF8String('12'), True), (core.UTF8String('12'), core.UTF8String('1'), False), (core.UTF8String('12'), core.IA5String('12'), False), )
def test_wrong_asn1value2(self): with self.assertRaises(TypeError): CopySeq({'name': core.UTF8String('Test'), 'pair': core.Integer(1)})
def test_untag(self): a = core.Integer(200, explicit=0) b = a.untag() self.assertNotEqual(id(a), id(b)) self.assertEqual(a.contents, b.contents) self.assertNotEqual(a.dump(), b.dump())
def test_retag(self): a = core.Integer(200) b = a.retag('explicit', 0) self.assertNotEqual(id(a), id(b)) self.assertEqual(a.contents, b.contents) self.assertNotEqual(a.dump(), b.dump())
def test_copy(self): a = core.Integer(200) b = a.copy() self.assertNotEqual(id(a), id(b)) self.assertEqual(a.contents, b.contents) self.assertEqual(a.dump(), b.dump())
def test_sequence_any_asn1value(self): seq = SequenceAny() seq.append(core.Integer(5)) self.assertEqual([5], seq.native)
def test_sequece_choice_choice(self): CCSeq({'cc': ChoiceChoice('num', NumChoice('one', core.Integer(0)))})
def integer(self, native, der_bytes): i = core.Integer(native) self.assertEqual(der_bytes, i.dump()) self.assertEqual(native, core.Integer.load(der_bytes).native)
def _fingerprint(key_object, load_private_key): """ Returns a fingerprint used for correlating public keys and private keys :param key_object: An asn1crypto.keys.PrivateKeyInfo or asn1crypto.keys.PublicKeyInfo :raises: ValueError - when the key_object is not of the proper type ;return: A byte string fingerprint """ if isinstance(key_object, keys.PrivateKeyInfo): key = key_object['private_key'].parsed if key_object.algorithm == 'rsa': to_hash = '%d:%d' % ( key['modulus'].native, key['public_exponent'].native, ) elif key_object.algorithm == 'dsa': params = key_object['private_key_algorithm']['parameters'] public_key = core.Integer( pow(params['g'].native, key_object['private_key'].parsed.native, params['p'].native)) to_hash = '%d:%d:%d:%d' % ( params['p'].native, params['q'].native, params['g'].native, public_key.native, ) elif key_object.algorithm == 'ec': public_key = key['public_key'].native if public_key is None: # This is gross, but since the EC public key is optional, # and we need to load the private key and use the crypto lib # to get the public key, we have to import the platform-specific # asymmetric implementation. This is the reason a bunch of the # imports are module imports, so we don't get an import cycle. public_key_object = load_private_key(key_object).public_key public_key = public_key_object.asn1['public_key'].parsed.native to_hash = '%s:' % key_object.curve[1] to_hash = to_hash.encode('utf-8') to_hash += public_key if isinstance(to_hash, str_cls): to_hash = to_hash.encode('utf-8') return hashlib.sha256(to_hash).digest() if isinstance(key_object, keys.PublicKeyInfo): if key_object.algorithm == 'rsa': key = key_object['public_key'].parsed to_hash = '%d:%d' % ( key['modulus'].native, key['public_exponent'].native, ) elif key_object.algorithm == 'dsa': key = key_object['public_key'].parsed params = key_object['algorithm']['parameters'] to_hash = '%d:%d:%d:%d' % ( params['p'].native, params['q'].native, params['g'].native, key.native, ) elif key_object.algorithm == 'ec': public_key = key_object['public_key'].native to_hash = '%s:' % key_object.curve[1] to_hash = to_hash.encode('utf-8') to_hash += public_key if isinstance(to_hash, str_cls): to_hash = to_hash.encode('utf-8') return hashlib.sha256(to_hash).digest() raise ValueError( pretty_message( ''' key_object must be an instance of the asn1crypto.keys.PrivateKeyInfo or asn1crypto.keys.PublicKeyInfo classes, not %s ''', type_name(key_object)))
def test_wrong_asn1value3(self): with self.assertRaises(TypeError): NestSeqAny({'id': '2.3.4.5', 'value': core.Integer(1)})
def test_wrong_asn1value(self): with self.assertRaises(TypeError): Seq({'id': core.Integer(1), 'value': 1})
def sign_message( data_to_sign, digest_alg, sign_key, sign_alg="rsassa_pkcs1v15", use_signed_attributes=True, ): """Function signs the data and returns the generated ASN.1 :param data_to_sign: A byte string of the data to be signed. :param digest_alg: The digest algorithm to be used for generating the signature. :param sign_key: The key to be used for generating the signature. :param sign_alg: The algorithm to be used for signing the message. :param use_signed_attributes: Optional attribute to indicate weather the CMS signature attributes should be included in the signature or not. :return: A CMS ASN.1 byte string of the signed data. """ if use_signed_attributes: digest_func = hashlib.new(digest_alg) digest_func.update(data_to_sign) message_digest = digest_func.digest() class SmimeCapability(core.Sequence): _fields = [ ("0", core.Any, { "optional": True }), ("1", core.Any, { "optional": True }), ("2", core.Any, { "optional": True }), ("3", core.Any, { "optional": True }), ("4", core.Any, { "optional": True }), ] class SmimeCapabilities(core.Sequence): _fields = [ ("0", SmimeCapability), ("1", SmimeCapability, { "optional": True }), ("2", SmimeCapability, { "optional": True }), ("3", SmimeCapability, { "optional": True }), ("4", SmimeCapability, { "optional": True }), ("5", SmimeCapability, { "optional": True }), ] smime_cap = OrderedDict([ ( "0", OrderedDict([ ("0", core.ObjectIdentifier("2.16.840.1.101.3.4.1.42")) ]), ), ( "1", OrderedDict([ ("0", core.ObjectIdentifier("2.16.840.1.101.3.4.1.2")) ]), ), ( "2", OrderedDict([("0", core.ObjectIdentifier("1.2.840.113549.3.7")) ]), ), ( "3", OrderedDict([ ("0", core.ObjectIdentifier("1.2.840.113549.3.2")), ("1", core.Integer(128)), ]), ), ( "4", OrderedDict([ ("0", core.ObjectIdentifier("1.2.840.113549.3.4")), ("1", core.Integer(128)), ]), ), ]) signed_attributes = cms.CMSAttributes([ cms.CMSAttribute({ "type": cms.CMSAttributeType("content_type"), "values": cms.SetOfContentType([cms.ContentType("data")]), }), cms.CMSAttribute({ "type": cms.CMSAttributeType("signing_time"), "values": cms.SetOfTime([ cms.Time({ "utc_time": core.UTCTime( datetime.utcnow().replace(tzinfo=timezone.utc)) }) ]), }), cms.CMSAttribute({ "type": cms.CMSAttributeType("message_digest"), "values": cms.SetOfOctetString([core.OctetString(message_digest)]), }), cms.CMSAttribute({ "type": cms.CMSAttributeType("1.2.840.113549.1.9.15"), "values": cms.SetOfAny([core.Any(SmimeCapabilities(smime_cap))]), }), ]) else: signed_attributes = None # Generate the signature data_to_sign = signed_attributes.dump( ) if signed_attributes else data_to_sign if sign_alg == "rsassa_pkcs1v15": signature = asymmetric.rsa_pkcs1v15_sign(sign_key[0], data_to_sign, digest_alg) elif sign_alg == "rsassa_pss": signature = asymmetric.rsa_pss_sign(sign_key[0], data_to_sign, digest_alg) else: raise AS2Exception("Unsupported Signature Algorithm") return cms.ContentInfo({ "content_type": cms.ContentType("signed_data"), "content": cms.SignedData({ "version": cms.CMSVersion("v1"), "digest_algorithms": cms.DigestAlgorithms([ algos.DigestAlgorithm( {"algorithm": algos.DigestAlgorithmId(digest_alg)}) ]), "encap_content_info": cms.ContentInfo({"content_type": cms.ContentType("data")}), "certificates": cms.CertificateSet( [cms.CertificateChoices({"certificate": sign_key[1].asn1})]), "signer_infos": cms.SignerInfos([ cms.SignerInfo({ "version": cms.CMSVersion("v1"), "sid": cms.SignerIdentifier({ "issuer_and_serial_number": cms.IssuerAndSerialNumber({ "issuer": sign_key[1].asn1["tbs_certificate"]["issuer"], "serial_number": sign_key[1].asn1["tbs_certificate"] ["serial_number"], }) }), "digest_algorithm": algos.DigestAlgorithm( {"algorithm": algos.DigestAlgorithmId(digest_alg)}), "signed_attrs": signed_attributes, "signature_algorithm": algos.SignedDigestAlgorithm( {"algorithm": algos.SignedDigestAlgorithmId(sign_alg)}), "signature": core.OctetString(signature), }) ]), }), }).dump()
def sign_message(data_to_sign, digest_alg, sign_key, use_signed_attributes=True): """Function signs the data and returns the generated ASN.1 :param data_to_sign: A byte string of the data to be signed. :param digest_alg: The digest algorithm to be used for generating the signature. :param sign_key: The key to be used for generating the signature. :param use_signed_attributes: Optional attribute to indicate weather the CMS signature attributes should be included in the signature or not. :return: A CMS ASN.1 byte string of the signed data. """ if use_signed_attributes: digest_func = hashlib.new(digest_alg) digest_func.update(data_to_sign) message_digest = digest_func.digest() class SmimeCapability(core.Sequence): _fields = [('0', core.Any, { 'optional': True }), ('1', core.Any, { 'optional': True }), ('2', core.Any, { 'optional': True }), ('3', core.Any, { 'optional': True }), ('4', core.Any, { 'optional': True })] class SmimeCapabilities(core.Sequence): _fields = [ ('0', SmimeCapability), ('1', SmimeCapability, { 'optional': True }), ('2', SmimeCapability, { 'optional': True }), ('3', SmimeCapability, { 'optional': True }), ('4', SmimeCapability, { 'optional': True }), ('5', SmimeCapability, { 'optional': True }), ] smime_cap = OrderedDict([ ('0', OrderedDict([('0', core.ObjectIdentifier('1.2.840.113549.3.7')) ])), ('1', OrderedDict([('0', core.ObjectIdentifier('1.2.840.113549.3.2')), ('1', core.Integer(128))])), ('2', OrderedDict([('0', core.ObjectIdentifier('1.2.840.113549.3.4')), ('1', core.Integer(128))])), ]) signed_attributes = cms.CMSAttributes([ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': cms.SetOfContentType([cms.ContentType('data')]) }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': cms.SetOfTime( [cms.Time({'utc_time': core.UTCTime(datetime.now())})]) }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': cms.SetOfOctetString([core.OctetString(message_digest)]) }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('1.2.840.113549.1.9.15'), 'values': cms.SetOfAny([core.Any(SmimeCapabilities(smime_cap))]) }), ]) signature = asymmetric.rsa_pkcs1v15_sign(sign_key[0], signed_attributes.dump(), digest_alg) else: signed_attributes = None signature = asymmetric.rsa_pkcs1v15_sign(sign_key[0], data_to_sign, digest_alg) return cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData({ 'version': cms.CMSVersion('v1'), 'digest_algorithms': cms.DigestAlgorithms([ algos.DigestAlgorithm( {'algorithm': algos.DigestAlgorithmId(digest_alg)}) ]), 'encap_content_info': cms.ContentInfo({'content_type': cms.ContentType('data')}), 'certificates': cms.CertificateSet( [cms.CertificateChoices({'certificate': sign_key[1].asn1})]), 'signer_infos': cms.SignerInfos([ cms.SignerInfo({ 'version': cms.CMSVersion('v1'), 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': sign_key[1].asn1['tbs_certificate']['issuer'], 'serial_number': sign_key[1].asn1['tbs_certificate'] ['serial_number'] }) }), 'digest_algorithm': algos.DigestAlgorithm( {'algorithm': algos.DigestAlgorithmId(digest_alg)}), 'signed_attrs': signed_attributes, 'signature_algorithm': algos.SignedDigestAlgorithm({ 'algorithm': algos.SignedDigestAlgorithmId('rsassa_pkcs1v15') }), 'signature': core.OctetString(signature) }) ]) }) }).dump()
def test_required_field(self): with self.assertRaisesRegexp(ValueError, '"id" is missing from structure'): Seq({'value': core.Integer(5)}).dump()
def test_wrong_asn1value4(self): with self.assertRaises(TypeError): NestSeqExplicit({'id': '3.4.5', 'value': core.Integer(1)})