Ejemplo n.º 1
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()
Ejemplo n.º 2
0
def encrypt_message(data_to_encrypt, enc_alg, encryption_cert):
    """Function encrypts data and returns the generated ASN.1

    :param data_to_encrypt: A byte string of the data to be encrypted
    :param enc_alg: The algorithm to be used for encrypting the data
    :param encryption_cert: The certificate to be used for encrypting the data

    :return: A CMS ASN.1 byte string of the encrypted data.
    """

    enc_alg_list = enc_alg.split("_")
    cipher, key_length, _ = enc_alg_list[0], enc_alg_list[1], enc_alg_list[2]

    # Generate the symmetric encryption key and encrypt the message
    key = util.rand_bytes(int(key_length) // 8)
    if cipher == "tripledes":
        algorithm_id = "1.2.840.113549.3.7"
        iv, encrypted_content = symmetric.tripledes_cbc_pkcs5_encrypt(
            key, data_to_encrypt, None)
        enc_alg_asn1 = algos.EncryptionAlgorithm({
            "algorithm":
            algorithm_id,
            "parameters":
            cms.OctetString(iv)
        })

    elif cipher == "rc2":
        algorithm_id = "1.2.840.113549.3.2"
        iv, encrypted_content = symmetric.rc2_cbc_pkcs5_encrypt(
            key, data_to_encrypt, None)
        enc_alg_asn1 = algos.EncryptionAlgorithm({
            "algorithm":
            algorithm_id,
            "parameters":
            algos.Rc2Params({"iv": cms.OctetString(iv)}),
        })

    elif cipher == "rc4":
        algorithm_id = "1.2.840.113549.3.4"
        encrypted_content = symmetric.rc4_encrypt(key, data_to_encrypt)
        enc_alg_asn1 = algos.EncryptionAlgorithm({
            "algorithm": algorithm_id,
        })

    elif cipher == "aes":
        if key_length == "128":
            algorithm_id = "2.16.840.1.101.3.4.1.2"
        elif key_length == "192":
            algorithm_id = "2.16.840.1.101.3.4.1.22"
        else:
            algorithm_id = "2.16.840.1.101.3.4.1.42"

        iv, encrypted_content = symmetric.aes_cbc_pkcs7_encrypt(
            key, data_to_encrypt, None)
        enc_alg_asn1 = algos.EncryptionAlgorithm({
            "algorithm":
            algorithm_id,
            "parameters":
            cms.OctetString(iv)
        })
    elif cipher == "des":
        algorithm_id = "1.3.14.3.2.7"
        iv, encrypted_content = symmetric.des_cbc_pkcs5_encrypt(
            key, data_to_encrypt, None)
        enc_alg_asn1 = algos.EncryptionAlgorithm({
            "algorithm":
            algorithm_id,
            "parameters":
            cms.OctetString(iv)
        })
    else:
        raise AS2Exception("Unsupported Encryption Algorithm")

    # Encrypt the key and build the ASN.1 message
    encrypted_key = asymmetric.rsa_pkcs1v15_encrypt(encryption_cert, key)

    return cms.ContentInfo({
        "content_type":
        cms.ContentType("enveloped_data"),
        "content":
        cms.EnvelopedData({
            "version":
            cms.CMSVersion("v0"),
            "recipient_infos": [
                cms.KeyTransRecipientInfo({
                    "version":
                    cms.CMSVersion("v0"),
                    "rid":
                    cms.RecipientIdentifier({
                        "issuer_and_serial_number":
                        cms.IssuerAndSerialNumber({
                            "issuer":
                            encryption_cert.asn1["tbs_certificate"]["issuer"],
                            "serial_number":
                            encryption_cert.asn1["tbs_certificate"]
                            ["serial_number"],
                        })
                    }),
                    "key_encryption_algorithm":
                    cms.KeyEncryptionAlgorithm(
                        {"algorithm": cms.KeyEncryptionAlgorithmId("rsa")}),
                    "encrypted_key":
                    cms.OctetString(encrypted_key),
                })
            ],
            "encrypted_content_info":
            cms.EncryptedContentInfo({
                "content_type": cms.ContentType("data"),
                "content_encryption_algorithm": enc_alg_asn1,
                "encrypted_content": encrypted_content,
            }),
        }),
    }).dump()
Ejemplo n.º 3
0
def encrypt_message(data_to_encrypt, enc_alg, encryption_cert):
    """Function encrypts data and returns the generated ASN.1

    :param data_to_encrypt: A byte string of the data to be encrypted
    
    :param enc_alg: The algorithm to be used for encrypting the data
    
    :param encryption_cert: The certificate to be used for encrypting the data

    :return: A CMS ASN.1 byte string of the encrypted data.    
    """

    enc_alg_list = enc_alg.split('_')
    cipher, key_length, mode = enc_alg_list[0], enc_alg_list[1], enc_alg_list[
        2]
    enc_alg_asn1, encrypted_content = None, None

    # Generate the symmetric encryption key and encrypt the message
    key = util.rand_bytes(int(key_length) // 8)
    if cipher == 'tripledes':
        algorithm_id = '1.2.840.113549.3.7'
        iv, encrypted_content = symmetric.tripledes_cbc_pkcs5_encrypt(
            key, data_to_encrypt, None)
        enc_alg_asn1 = algos.EncryptionAlgorithm({
            'algorithm':
            algorithm_id,
            'parameters':
            cms.OctetString(iv)
        })

    elif cipher == 'rc2':
        algorithm_id = '1.2.840.113549.3.2'
        iv, encrypted_content = symmetric.rc2_cbc_pkcs5_encrypt(
            key, data_to_encrypt, None)
        enc_alg_asn1 = algos.EncryptionAlgorithm({
            'algorithm':
            algorithm_id,
            'parameters':
            algos.Rc2Params({'iv': cms.OctetString(iv)})
        })

    elif cipher == 'rc4':
        algorithm_id = '1.2.840.113549.3.4'
        encrypted_content = symmetric.rc4_encrypt(key, data_to_encrypt)
        enc_alg_asn1 = algos.EncryptionAlgorithm({
            'algorithm': algorithm_id,
        })

    elif cipher == 'aes':
        if key_length == '128':
            algorithm_id = '2.16.840.1.101.3.4.1.2'
        elif key_length == '192':
            algorithm_id = '2.16.840.1.101.3.4.1.22'
        else:
            algorithm_id = '2.16.840.1.101.3.4.1.42'

        iv, encrypted_content = symmetric.aes_cbc_pkcs7_encrypt(
            key, data_to_encrypt, None)
        enc_alg_asn1 = algos.EncryptionAlgorithm({
            'algorithm':
            algorithm_id,
            'parameters':
            cms.OctetString(iv)
        })

    # Encrypt the key and build the ASN.1 message
    encrypted_key = asymmetric.rsa_pkcs1v15_encrypt(encryption_cert, key)

    return cms.ContentInfo({
        'content_type':
        cms.ContentType('enveloped_data'),
        'content':
        cms.EnvelopedData({
            'version':
            cms.CMSVersion('v0'),
            'recipient_infos': [
                cms.KeyTransRecipientInfo({
                    'version':
                    cms.CMSVersion('v0'),
                    'rid':
                    cms.RecipientIdentifier({
                        'issuer_and_serial_number':
                        cms.IssuerAndSerialNumber({
                            'issuer':
                            encryption_cert.asn1['tbs_certificate']['issuer'],
                            'serial_number':
                            encryption_cert.asn1['tbs_certificate']
                            ['serial_number']
                        })
                    }),
                    'key_encryption_algorithm':
                    cms.KeyEncryptionAlgorithm(
                        {'algorithm': cms.KeyEncryptionAlgorithmId('rsa')}),
                    'encrypted_key':
                    cms.OctetString(encrypted_key)
                })
            ],
            'encrypted_content_info':
            cms.EncryptedContentInfo({
                'content_type': cms.ContentType('data'),
                'content_encryption_algorithm': enc_alg_asn1,
                'encrypted_content': encrypted_content
            })
        })
    }).dump()
Ejemplo n.º 4
0
    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()