コード例 #1
0
ファイル: test_asymmetric.py プロジェクト: nresare/oscrypto
    def test_rsa_private_pkcs1v15_decrypt(self):
        original_data = b'This is the message to sign'
        private = asymmetric.load_private_key(os.path.join(fixtures_dir, 'keys/test.key'))

        with open(os.path.join(fixtures_dir, 'rsa_public_encrypted'), 'rb') as f:
            plaintext = asymmetric.rsa_pkcs1v15_decrypt(private, f.read())
            self.assertEqual(original_data, plaintext)
コード例 #2
0
def test_demo_plugin():

    with_plugin_cfg = CertomancerConfig.from_file('tests/data/with-plugin.yml',
                                                  'tests/data')

    with_plugin_app = Animator(AnimatorArchStore(with_plugin_cfg.pki_archs),
                               with_web_ui=False)
    client = Client(with_plugin_app, Response)

    # make the endpoint encrypt something
    endpoint = '/testing-ca/plugin/encrypt-echo/test-endpoint'
    payload = b'test test test'
    response = client.post(endpoint, data=payload)

    # decrypt it
    env_data = cms.ContentInfo.load(response.data)['content']
    arch = with_plugin_cfg.get_pki_arch(ArchLabel('testing-ca'))
    key = arch.key_set.get_private_key(KeyLabel('signer1'))
    ktri = env_data['recipient_infos'][0].chosen
    encrypted_key = ktri['encrypted_key'].native

    decrypted_key = asymmetric.rsa_pkcs1v15_decrypt(
        asymmetric.load_private_key(key.dump()), encrypted_key)

    eci = env_data['encrypted_content_info']
    cea = eci['content_encryption_algorithm']
    assert cea['algorithm'].native == 'aes256_cbc'
    iv = cea['parameters'].native
    encrypted_content_bytes = eci['encrypted_content'].native
    decrypted_payload = symmetric.aes_cbc_pkcs7_decrypt(
        decrypted_key, encrypted_content_bytes, iv)
    assert decrypted_payload == payload
コード例 #3
0
def decrypt_message(encrypted_data, decryption_key):
    """Function parses an ASN.1 encrypted message and extracts/decrypts 
        the original message.

    :param encrypted_data: A CMS ASN.1 byte string containing the encrypted 
    data.
    
    :param decryption_key: The key to be used for decrypting the data.

    :return: A byte string containing the decrypted original message.    
    """

    cms_content = cms.ContentInfo.load(encrypted_data)
    cipher, decrypted_content = None, None

    if cms_content['content_type'].native == 'enveloped_data':
        recipient_info = cms_content['content']['recipient_infos'][0].parse()
        key_enc_alg = recipient_info['key_encryption_algorithm'][
            'algorithm'].native
        encrypted_key = recipient_info['encrypted_key'].native

        if key_enc_alg == 'rsa':
            try:
                key = asymmetric.rsa_pkcs1v15_decrypt(decryption_key[0],
                                                      encrypted_key)
            except Exception:
                raise DecryptionError(
                    'Failed to decrypt the payload: Could not extract decryption key.'
                )

            alg = cms_content['content']['encrypted_content_info'][
                'content_encryption_algorithm']
            encapsulated_data = cms_content['content'][
                'encrypted_content_info']['encrypted_content'].native

            try:
                if alg['algorithm'].native == '1.2.840.113549.3.4':  # This is RC4
                    decrypted_content = symmetric.rc4_decrypt(
                        key, encapsulated_data)
                elif alg.encryption_cipher == 'tripledes':
                    cipher = 'tripledes_192_cbc'
                    decrypted_content = symmetric.tripledes_cbc_pkcs5_decrypt(
                        key, encapsulated_data, alg.encryption_iv)
                elif alg.encryption_cipher == 'aes':
                    decrypted_content = symmetric.aes_cbc_pkcs7_decrypt(
                        key, encapsulated_data, alg.encryption_iv)
                elif alg.encryption_cipher == 'rc2':
                    decrypted_content = symmetric.rc2_cbc_pkcs5_decrypt(
                        key, encapsulated_data, alg['parameters']['iv'].native)
                else:
                    raise AS2Exception('Unsupported Encryption Algorithm')
            except Exception as e:
                raise DecryptionError(
                    'Failed to decrypt the payload: {}'.format(e))
        else:
            raise AS2Exception('Unsupported Encryption Algorithm')
    else:
        raise DecryptionError('Encrypted data not found in ASN.1 ')

    return cipher, decrypted_content
コード例 #4
0
ファイル: test_asymmetric.py プロジェクト: shinsec/oscrypto
    def test_rsa_private_pkcs1v15_decrypt(self):
        original_data = b'This is the message to sign'
        private = asymmetric.load_private_key(os.path.join(fixtures_dir, 'keys/test.key'))

        with open(os.path.join(fixtures_dir, 'rsa_public_encrypted'), 'rb') as f:
            plaintext = asymmetric.rsa_pkcs1v15_decrypt(private, f.read())
            self.assertEqual(original_data, plaintext)
コード例 #5
0
def test_demo_plugin(requests_mock):

    with_plugin_cfg = CertomancerConfig.from_file('tests/data/with-plugin.yml',
                                                  'tests/data')

    arch = with_plugin_cfg.get_pki_arch(ArchLabel('testing-ca'))

    illusionist.Illusionist(pki_arch=arch).register(requests_mock)

    importlib.import_module('example_plugin.encrypt_echo')

    # make the endpoint encrypt something
    endpoint = 'http://test.test/testing-ca/plugin/encrypt-echo/test-endpoint'
    payload = b'test test test'
    response = requests.post(endpoint, data=payload)

    # decrypt it
    env_data = cms.ContentInfo.load(response.content)['content']
    key = arch.key_set.get_private_key(KeyLabel('signer1'))
    ktri = env_data['recipient_infos'][0].chosen
    encrypted_key = ktri['encrypted_key'].native

    decrypted_key = asymmetric.rsa_pkcs1v15_decrypt(
        asymmetric.load_private_key(key.dump()), encrypted_key)

    eci = env_data['encrypted_content_info']
    cea = eci['content_encryption_algorithm']
    assert cea['algorithm'].native == 'aes256_cbc'
    iv = cea['parameters'].native
    encrypted_content_bytes = eci['encrypted_content'].native
    decrypted_payload = symmetric.aes_cbc_pkcs7_decrypt(
        decrypted_key, encrypted_content_bytes, iv)
    assert decrypted_payload == payload
コード例 #6
0
def decrypt_message(encrypted_data, decryption_key):
    """Function parses an ASN.1 encrypted message and extracts/decrypts the original message.

    :param encrypted_data: A CMS ASN.1 byte string containing the encrypted data.
    :param decryption_key: The key to be used for decrypting the data.

    :return: A byte string containing the decrypted original message.
    """

    cms_content = cms.ContentInfo.load(encrypted_data)
    cipher, decrypted_content = None, None

    if cms_content["content_type"].native == "enveloped_data":
        recipient_info = cms_content["content"]["recipient_infos"][0].parse()
        key_enc_alg = recipient_info["key_encryption_algorithm"][
            "algorithm"].native
        encrypted_key = recipient_info["encrypted_key"].native

        if cms.KeyEncryptionAlgorithmId(
                key_enc_alg) == cms.KeyEncryptionAlgorithmId("rsa"):
            try:
                key = asymmetric.rsa_pkcs1v15_decrypt(decryption_key[0],
                                                      encrypted_key)
            except Exception:
                raise DecryptionError(
                    "Failed to decrypt the payload: Could not extract decryption key."
                )

            alg = cms_content["content"]["encrypted_content_info"][
                "content_encryption_algorithm"]
            encapsulated_data = cms_content["content"][
                "encrypted_content_info"]["encrypted_content"].native

            try:
                if alg["algorithm"].native == "rc4":
                    decrypted_content = symmetric.rc4_decrypt(
                        key, encapsulated_data)
                elif alg.encryption_cipher == "tripledes":
                    cipher = "tripledes_192_cbc"
                    decrypted_content = symmetric.tripledes_cbc_pkcs5_decrypt(
                        key, encapsulated_data, alg.encryption_iv)
                elif alg.encryption_cipher == "aes":
                    decrypted_content = symmetric.aes_cbc_pkcs7_decrypt(
                        key, encapsulated_data, alg.encryption_iv)
                elif alg.encryption_cipher == "rc2":
                    decrypted_content = symmetric.rc2_cbc_pkcs5_decrypt(
                        key, encapsulated_data, alg["parameters"]["iv"].native)
                else:
                    raise AS2Exception("Unsupported Encryption Algorithm")
            except Exception as e:
                raise DecryptionError(
                    "Failed to decrypt the payload: {}".format(e))
        else:
            raise AS2Exception("Unsupported Encryption Algorithm")
    else:
        raise DecryptionError("Encrypted data not found in ASN.1 ")

    return cipher, decrypted_content
コード例 #7
0
ファイル: test_asymmetric.py プロジェクト: nresare/oscrypto
    def test_rsa_pkcs1v15_encrypt(self):
        original_data = b'This is data to encrypt'
        private = asymmetric.load_private_key(os.path.join(fixtures_dir, 'keys/test.key'))
        public = asymmetric.load_public_key(os.path.join(fixtures_dir, 'keys/test.crt'))

        ciphertext = asymmetric.rsa_pkcs1v15_encrypt(public, original_data)
        self.assertIsInstance(ciphertext, byte_cls)

        plaintext = asymmetric.rsa_pkcs1v15_decrypt(private, ciphertext)
        self.assertEqual(original_data, plaintext)
コード例 #8
0
ファイル: test_asymmetric.py プロジェクト: shinsec/oscrypto
    def test_rsa_pkcs1v15_encrypt(self):
        original_data = b'This is data to encrypt'
        private = asymmetric.load_private_key(os.path.join(fixtures_dir, 'keys/test.key'))
        public = asymmetric.load_public_key(os.path.join(fixtures_dir, 'keys/test.crt'))

        ciphertext = asymmetric.rsa_pkcs1v15_encrypt(public, original_data)
        self.assertIsInstance(ciphertext, byte_cls)

        plaintext = asymmetric.rsa_pkcs1v15_decrypt(private, ciphertext)
        self.assertEqual(original_data, plaintext)
コード例 #9
0
    def on_get(self, req, resp):
        operation = req.get_param("operation", required=True)
        if operation.lower() == "getcacert":
            resp.body = keys.parse_certificate(
                self.authority.certificate_buf).dump()
            resp.append_header("Content-Type", "application/x-x509-ca-cert")
            return

        # If we bump into exceptions later
        encrypted_container = b""
        attr_list = [
            cms.CMSAttribute({
                'type': "message_type",
                'values': ["3"]
            }),
            cms.CMSAttribute({
                'type': "pki_status",
                'values': ["2"]  # rejected
            })
        ]

        try:
            info = cms.ContentInfo.load(
                b64decode(req.get_param("message", required=True)))

            ###############################################
            ### Verify signature of the outer container ###
            ###############################################

            signed_envelope = info['content']
            encap_content_info = signed_envelope['encap_content_info']
            encap_content = encap_content_info['content']

            # TODO: try except
            current_certificate, = signed_envelope["certificates"]
            signer, = signed_envelope["signer_infos"]

            # TODO: compare cert to current one if we are renewing

            assert signer["digest_algorithm"]["algorithm"].native == "md5"
            assert signer["signature_algorithm"][
                "algorithm"].native == "rsassa_pkcs1v15"
            message_digest = None
            transaction_id = None
            sender_nonce = None

            for attr in signer["signed_attrs"]:
                if attr["type"].native == "sender_nonce":
                    sender_nonce, = attr["values"]
                elif attr["type"].native == "trans_id":
                    transaction_id, = attr["values"]
                elif attr["type"].native == "message_digest":
                    message_digest, = attr["values"]
                    if hashlib.md5(encap_content.native).digest(
                    ) != message_digest.native:
                        raise SCEPBadMessageCheck()

            assert message_digest
            msg = signer["signed_attrs"].dump(force=True)
            assert msg[0] == 160

            # Verify signature
            try:
                asymmetric.rsa_pkcs1v15_verify(
                    asymmetric.load_certificate(current_certificate.dump()),
                    signer["signature"].native,
                    b"\x31" + msg[1:],  # wtf?!
                    "md5")
            except SignatureError:
                raise SCEPBadMessageCheck()

            ###############################
            ### Decrypt inner container ###
            ###############################

            info = cms.ContentInfo.load(encap_content.native)
            encrypted_envelope = info['content']
            encrypted_content_info = encrypted_envelope[
                'encrypted_content_info']
            iv = encrypted_content_info['content_encryption_algorithm'][
                'parameters'].native

            if encrypted_content_info['content_encryption_algorithm'][
                    "algorithm"].native != "des":
                raise SCEPBadAlgo()

            encrypted_content = encrypted_content_info[
                'encrypted_content'].native
            recipient, = encrypted_envelope['recipient_infos']

            if recipient.native["rid"][
                    "serial_number"] != self.authority.certificate.serial_number:
                raise SCEPBadCertId()

            # Since CA private key is not directly readable here, we'll redirect it to signer socket
            key = asymmetric.rsa_pkcs1v15_decrypt(
                self.authority.private_key, recipient.native["encrypted_key"])
            if len(key) == 8: key = key * 3  # Convert DES to 3DES
            buf = symmetric.tripledes_cbc_pkcs5_decrypt(
                key, encrypted_content, iv)
            _, _, common_name = self.authority.store_request(buf,
                                                             overwrite=True)
            cert, buf = self.authority.sign(common_name, overwrite=True)
            signed_certificate = asymmetric.load_certificate(buf)
            content = signed_certificate.asn1.dump()

        except SCEPError as e:
            attr_list.append(
                cms.CMSAttribute({
                    'type': "fail_info",
                    'values': ["%d" % e.code]
                }))
        else:

            ##################################
            ### Degenerate inner container ###
            ##################################

            degenerate = cms.ContentInfo({
                'content_type':
                "signed_data",
                'content':
                cms.SignedData({
                    'version':
                    "v1",
                    'certificates': [signed_certificate.asn1],
                    'digest_algorithms':
                    [cms.DigestAlgorithm({'algorithm': "md5"})],
                    'encap_content_info': {
                        'content_type':
                        "data",
                        'content':
                        cms.ContentInfo({
                            'content_type': "signed_data",
                            'content': None
                        }).dump()
                    },
                    'signer_infos': []
                })
            })

            ################################
            ### Encrypt middle container ###
            ################################

            key = os.urandom(8)
            iv, encrypted_content = symmetric.des_cbc_pkcs5_encrypt(
                key, degenerate.dump(), os.urandom(8))
            assert degenerate.dump() == symmetric.tripledes_cbc_pkcs5_decrypt(
                key * 3, encrypted_content, iv)

            ri = cms.RecipientInfo({
                'ktri':
                cms.KeyTransRecipientInfo({
                    'version':
                    "v0",
                    'rid':
                    cms.RecipientIdentifier({
                        'issuer_and_serial_number':
                        cms.IssuerAndSerialNumber({
                            'issuer':
                            current_certificate.chosen["tbs_certificate"]
                            ["issuer"],
                            'serial_number':
                            current_certificate.chosen["tbs_certificate"]
                            ["serial_number"],
                        }),
                    }),
                    'key_encryption_algorithm': {
                        'algorithm': "rsa"
                    },
                    'encrypted_key':
                    asymmetric.rsa_pkcs1v15_encrypt(
                        asymmetric.load_certificate(
                            current_certificate.chosen.dump()), key)
                })
            })

            encrypted_container = cms.ContentInfo({
                'content_type':
                "enveloped_data",
                'content':
                cms.EnvelopedData({
                    'version': "v1",
                    'recipient_infos': [ri],
                    'encrypted_content_info': {
                        'content_type': "data",
                        'content_encryption_algorithm': {
                            'algorithm': "des",
                            'parameters': iv
                        },
                        'encrypted_content': encrypted_content
                    }
                })
            }).dump()

            attr_list = [
                cms.CMSAttribute({
                    'type':
                    "message_digest",
                    'values': [hashlib.sha1(encrypted_container).digest()]
                }),
                cms.CMSAttribute({
                    'type': "message_type",
                    'values': ["3"]
                }),
                cms.CMSAttribute({
                    'type': "pki_status",
                    'values': ["0"]  # ok
                })
            ]
        finally:

            ##############################
            ### Signed outer container ###
            ##############################

            attrs = cms.CMSAttributes(attr_list + [
                cms.CMSAttribute({
                    'type': "recipient_nonce",
                    'values': [sender_nonce]
                }),
                cms.CMSAttribute({
                    'type': "trans_id",
                    'values': [transaction_id]
                })
            ])

            signer = cms.SignerInfo({
                "signed_attrs":
                attrs,
                'version':
                "v1",
                'sid':
                cms.SignerIdentifier({
                    'issuer_and_serial_number':
                    cms.IssuerAndSerialNumber({
                        'issuer':
                        self.authority.certificate.issuer,
                        'serial_number':
                        self.authority.certificate.serial_number,
                    }),
                }),
                'digest_algorithm':
                algos.DigestAlgorithm({'algorithm': "sha1"}),
                'signature_algorithm':
                algos.SignedDigestAlgorithm({'algorithm': "rsassa_pkcs1v15"}),
                'signature':
                asymmetric.rsa_pkcs1v15_sign(self.authority.private_key,
                                             b"\x31" + attrs.dump()[1:],
                                             "sha1")
            })

            resp.append_header("Content-Type", "application/x-pki-message")
            resp.body = cms.ContentInfo({
                'content_type':
                "signed_data",
                'content':
                cms.SignedData({
                    'version':
                    "v1",
                    'certificates': [self.authority.certificate],
                    'digest_algorithms':
                    [cms.DigestAlgorithm({'algorithm': "sha1"})],
                    'encap_content_info': {
                        'content_type': "data",
                        'content': encrypted_container
                    },
                    'signer_infos': [signer]
                })
            }).dump()
コード例 #10
0
 def decrypt(self, message):
     return asymmetric.rsa_pkcs1v15_decrypt(self.pair[1], message)
コード例 #11
0
ファイル: scep.py プロジェクト: werty1st/certidude
    def on_get(self, req, resp):
        operation = req.get_param("operation", required=True)
        if operation == "GetCACert":
            resp.body = keys.parse_certificate(
                self.authority.certificate_buf).dump()
            resp.append_header("Content-Type", "application/x-x509-ca-cert")
            return
        elif operation == "GetCACaps":
            # TODO: return renewal flag based on renewal subnets config option
            resp.body = "Renewal\nMD5\nSHA-1\nSHA-256\nSHA-512\nDES3\n"
            return
        elif operation == "PKIOperation":
            pass
        else:
            raise falcon.HTTPBadRequest("Bad request",
                                        "Unknown operation %s" % operation)

        # If we bump into exceptions later
        encrypted_container = b""
        attr_list = [
            cms.CMSAttribute({
                'type': "message_type",
                'values': ["3"]
            }),
            cms.CMSAttribute({
                'type': "pki_status",
                'values': ["2"]  # rejected
            })
        ]

        try:
            info = cms.ContentInfo.load(
                b64decode(req.get_param("message", required=True)))

            ###############################################
            ### Verify signature of the outer container ###
            ###############################################

            signed_envelope = info['content']
            encap_content_info = signed_envelope['encap_content_info']
            encap_content = encap_content_info['content']

            # TODO: try except
            current_certificate, = signed_envelope["certificates"]
            signer, = signed_envelope["signer_infos"]

            # TODO: compare cert to current one if we are renewing

            digest_algorithm = signer["digest_algorithm"]["algorithm"].native
            signature_algorithm = signer["signature_algorithm"][
                "algorithm"].native

            if digest_algorithm not in ("md5", "sha1", "sha256", "sha512"):
                raise SCEPBadAlgo()
            if signature_algorithm != "rsassa_pkcs1v15":
                raise SCEPBadAlgo()

            message_digest = None
            transaction_id = None
            sender_nonce = None

            for attr in signer["signed_attrs"]:
                if attr["type"].native == "sender_nonce":
                    sender_nonce, = attr["values"]
                elif attr["type"].native == "trans_id":
                    transaction_id, = attr["values"]
                elif attr["type"].native == "message_digest":
                    message_digest, = attr["values"]
                    if getattr(hashlib,
                               digest_algorithm)(encap_content.native).digest(
                               ) != message_digest.native:
                        raise SCEPDigestMismatch()

            if not sender_nonce:
                raise SCEPBadRequest()
            if not transaction_id:
                raise SCEPBadRequest()

            assert message_digest
            msg = signer["signed_attrs"].dump(force=True)
            assert msg[0] == 160

            # Verify signature
            try:
                asymmetric.rsa_pkcs1v15_verify(
                    asymmetric.load_certificate(current_certificate.dump()),
                    signer["signature"].native,
                    b"\x31" + msg[1:],  # wtf?!
                    "md5")
            except SignatureError:
                raise SCEPSignatureMismatch()

            ###############################
            ### Decrypt inner container ###
            ###############################

            info = cms.ContentInfo.load(encap_content.native)
            encrypted_envelope = info['content']
            encrypted_content_info = encrypted_envelope[
                'encrypted_content_info']
            iv = encrypted_content_info['content_encryption_algorithm'][
                'parameters'].native

            if encrypted_content_info['content_encryption_algorithm'][
                    "algorithm"].native != "des":
                raise SCEPBadAlgo()

            encrypted_content = encrypted_content_info[
                'encrypted_content'].native
            recipient, = encrypted_envelope['recipient_infos']

            if recipient.native["rid"][
                    "serial_number"] != self.authority.certificate.serial_number:
                raise SCEPBadCertId()

            key = asymmetric.rsa_pkcs1v15_decrypt(
                self.authority.private_key, recipient.native["encrypted_key"])
            if len(key) == 8: key = key * 3  # Convert DES to 3DES
            buf = symmetric.tripledes_cbc_pkcs5_decrypt(
                key, encrypted_content, iv)
            _, _, common_name = self.authority.store_request(buf,
                                                             overwrite=True)
            logger.info(
                "SCEP client from %s requested with %s digest algorithm, %s signature",
                req.context["remote_addr"], digest_algorithm,
                signature_algorithm)
            cert, buf = self.authority.sign(common_name,
                                            profile=config.PROFILES["gw"],
                                            overwrite=True)
            signed_certificate = asymmetric.load_certificate(buf)
            content = signed_certificate.asn1.dump()

        except SCEPError as e:
            attr_list.append(
                cms.CMSAttribute({
                    'type': "fail_info",
                    'values': ["%d" % e.code]
                }))
            logger.info("Failed to sign SCEP request due to: %s" %
                        e.explaination)
        else:

            ##################################
            ### Degenerate inner container ###
            ##################################

            degenerate = cms.ContentInfo({
                'content_type':
                "signed_data",
                'content':
                cms.SignedData({
                    'version':
                    "v1",
                    'certificates': [signed_certificate.asn1],
                    'digest_algorithms':
                    [cms.DigestAlgorithm({'algorithm': digest_algorithm})],
                    'encap_content_info': {
                        'content_type':
                        "data",
                        'content':
                        cms.ContentInfo({
                            'content_type': "signed_data",
                            'content': None
                        }).dump()
                    },
                    'signer_infos': []
                })
            })

            ################################
            ### Encrypt middle container ###
            ################################

            key = os.urandom(8)
            iv, encrypted_content = symmetric.des_cbc_pkcs5_encrypt(
                key, degenerate.dump(), os.urandom(8))
            assert degenerate.dump() == symmetric.tripledes_cbc_pkcs5_decrypt(
                key * 3, encrypted_content, iv)

            ri = cms.RecipientInfo({
                'ktri':
                cms.KeyTransRecipientInfo({
                    'version':
                    "v0",
                    'rid':
                    cms.RecipientIdentifier({
                        'issuer_and_serial_number':
                        cms.IssuerAndSerialNumber({
                            'issuer':
                            current_certificate.chosen["tbs_certificate"]
                            ["issuer"],
                            'serial_number':
                            current_certificate.chosen["tbs_certificate"]
                            ["serial_number"],
                        }),
                    }),
                    'key_encryption_algorithm': {
                        'algorithm': "rsa"
                    },
                    'encrypted_key':
                    asymmetric.rsa_pkcs1v15_encrypt(
                        asymmetric.load_certificate(
                            current_certificate.chosen.dump()), key)
                })
            })

            encrypted_container = cms.ContentInfo({
                'content_type':
                "enveloped_data",
                'content':
                cms.EnvelopedData({
                    'version': "v1",
                    'recipient_infos': [ri],
                    'encrypted_content_info': {
                        'content_type': "data",
                        'content_encryption_algorithm': {
                            'algorithm': "des",
                            'parameters': iv
                        },
                        'encrypted_content': encrypted_content
                    }
                })
            }).dump()

            attr_list = [
                cms.CMSAttribute({
                    'type':
                    "message_digest",
                    'values': [
                        getattr(
                            hashlib,
                            digest_algorithm)(encrypted_container).digest()
                    ]
                }),
                cms.CMSAttribute({
                    'type': "message_type",
                    'values': ["3"]
                }),
                cms.CMSAttribute({
                    'type': "pki_status",
                    'values': ["0"]  # ok
                })
            ]
        finally:

            ##############################
            ### Signed outer container ###
            ##############################

            attrs = cms.CMSAttributes(attr_list + [
                cms.CMSAttribute({
                    'type': "recipient_nonce",
                    'values': [sender_nonce]
                }),
                cms.CMSAttribute({
                    'type': "trans_id",
                    'values': [transaction_id]
                })
            ])

            signer = cms.SignerInfo({
                "signed_attrs":
                attrs,
                'version':
                "v1",
                'sid':
                cms.SignerIdentifier({
                    'issuer_and_serial_number':
                    cms.IssuerAndSerialNumber({
                        'issuer':
                        self.authority.certificate.issuer,
                        'serial_number':
                        self.authority.certificate.serial_number,
                    }),
                }),
                'digest_algorithm':
                algos.DigestAlgorithm({'algorithm': digest_algorithm}),
                'signature_algorithm':
                algos.SignedDigestAlgorithm({'algorithm': "rsassa_pkcs1v15"}),
                'signature':
                asymmetric.rsa_pkcs1v15_sign(self.authority.private_key,
                                             b"\x31" + attrs.dump()[1:],
                                             digest_algorithm)
            })

            resp.append_header("Content-Type", "application/x-pki-message")
            resp.body = cms.ContentInfo({
                'content_type':
                "signed_data",
                'content':
                cms.SignedData({
                    'version':
                    "v1",
                    'certificates': [self.authority.certificate],
                    'digest_algorithms':
                    [cms.DigestAlgorithm({'algorithm': digest_algorithm})],
                    'encap_content_info': {
                        'content_type': "data",
                        'content': encrypted_container
                    },
                    'signer_infos': [signer]
                })
            }).dump()