Ejemplo n.º 1
0
 def recipient_info(self, session_key):
     cipher = self._get_public_key_cipher()
     if cipher == None:
         return None
     encrypted_key = cipher.encrypt(session_key)
     tbs_cert = self._cert['tbs_certificate']
     # TODO: use subject_key_identifier when available
     return cms.RecipientInfo(name='ktri',
                              value={
                                  'version':
                                  u'v0',
                                  'rid':
                                  cms.RecipientIdentifier(
                                      name='issuer_and_serial_number',
                                      value={
                                          'issuer':
                                          tbs_cert['issuer'],
                                          'serial_number':
                                          tbs_cert['serial_number']
                                      }),
                                  'key_encryption_algorithm': {
                                      'algorithm': cipher.algo,
                                      'parameters': cipher.parameters
                                  },
                                  'encrypted_key':
                                  encrypted_key
                              })
Ejemplo n.º 2
0
 def recipient_info(self, session_key):
     cipher = self._get_public_key_cipher()
     if cipher is None:
         return None
     encrypted_key = cipher.encrypt(session_key)
     tbs_cert = self._cert["tbs_certificate"]
     # TODO: use subject_key_identifier when available
     return cms.RecipientInfo(
         name="ktri",
         value={
             "version":
             "v0",
             "rid":
             cms.RecipientIdentifier(
                 name="issuer_and_serial_number",
                 value={
                     "issuer": tbs_cert["issuer"],
                     "serial_number": tbs_cert["serial_number"],
                 },
             ),
             "key_encryption_algorithm": {
                 "algorithm": cipher.algo,
                 "parameters": cipher.parameters,
             },
             "encrypted_key":
             encrypted_key,
         },
     )
Ejemplo n.º 3
0
    def recipient_info(self, cert, session_key):
        public_key = cert.get_pubkey().to_cryptography_key()
        encrypted_key = public_key.encrypt(session_key, padding.PKCS1v15())
        cert = signer.cert2asn(cert.to_cryptography())

        tbs_cert = cert['tbs_certificate']
        # TODO: use subject_key_identifier when available
        return cms.RecipientInfo(name=u'ktri',
                                 value={
                                     'version':
                                     u'v0',
                                     'rid':
                                     cms.RecipientIdentifier(
                                         name=u'issuer_and_serial_number',
                                         value={
                                             'issuer':
                                             tbs_cert['issuer'],
                                             'serial_number':
                                             tbs_cert['serial_number']
                                         }),
                                     'key_encryption_algorithm': {
                                         'algorithm': u'rsa',
                                     },
                                     'encrypted_key':
                                     core.OctetString(encrypted_key)
                                 })
Ejemplo n.º 4
0
    def recipient_info(self, cert, session_key, oaep):
        public_key = cert.public_key()
        cert = signer.cert2asn(cert)

        tbs_cert = cert['tbs_certificate']
        # TODO: use subject_key_identifier when available
        if oaep:
            encrypted_key = public_key.encrypt(
                session_key,
                padding.OAEP(mgf=padding.MGF1(hashes.SHA512()),
                             algorithm=hashes.SHA512(),
                             label=None))
            kea = cms.KeyEncryptionAlgorithm({
                'algorithm':
                cms.KeyEncryptionAlgorithmId('rsaes_oaep'),
                'parameters':
                algos.RSAESOAEPParams({
                    'hash_algorithm':
                    algos.DigestAlgorithm({'algorithm': 'sha512'}),
                    'mask_gen_algorithm':
                    algos.MaskGenAlgorithm({
                        'algorithm':
                        algos.MaskGenAlgorithmId('mgf1'),
                        'parameters': {
                            'algorithm': algos.DigestAlgorithmId('sha512'),
                        }
                    }),
                    'p_source_algorithm':
                    algos.PSourceAlgorithm({
                        'algorithm':
                        algos.PSourceAlgorithmId('p_specified'),
                        'parameters':
                        b'',
                    })
                })
            })
        else:
            kea = {'algorithm': 'rsa'}
            encrypted_key = public_key.encrypt(session_key, padding.PKCS1v15())
        result = cms.RecipientInfo(name='ktri',
                                   value={
                                       'version':
                                       'v0',
                                       'rid':
                                       cms.RecipientIdentifier(
                                           name='issuer_and_serial_number',
                                           value={
                                               'issuer':
                                               tbs_cert['issuer'],
                                               'serial_number':
                                               tbs_cert['serial_number']
                                           }),
                                       'key_encryption_algorithm':
                                       kea,
                                       'encrypted_key':
                                       core.OctetString(encrypted_key)
                                   })
        return result
Ejemplo n.º 5
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.º 6
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()
Ejemplo n.º 7
0
def encrypt(certificate, data):
    # encrypt data with block cipher AES-256-CBC
    session_key = os.urandom(32)
    iv = os.urandom(16)
    algorithm = algorithms.AES(session_key)
    encryptor = Cipher(algorithm, modes.CBC(iv),
                       backend=default_backend()).encryptor()

    padder = padding.PKCS7(128).padder()
    padded_data = padder.update(data) + padder.finalize()
    encrypted_data = encryptor.update(padded_data) + encryptor.finalize()

    # load certificate
    with open(certificate, 'rb') as fp:
        cert = x509.Certificate.load(pem.unarmor(fp.read())[2])
        tbs_cert = cert['tbs_certificate']

        # encrypt session key with public key
        pub = serialization.load_der_public_key(cert.public_key.dump())
        encrypted_key = pub.encrypt(
            session_key,
            apadding.OAEP(mgf=apadding.MGF1(algorithm=hashes.SHA256()),
                          algorithm=hashes.SHA256(),
                          label=None))

    # encode encrypted key and RSA parameters for recipient
    recipient_info = cms.RecipientInfo(name='ktri',
                                       value={
                                           'version':
                                           'v0',
                                           'rid':
                                           cms.RecipientIdentifier(
                                               name='issuer_and_serial_number',
                                               value={
                                                   'issuer':
                                                   tbs_cert['issuer'],
                                                   'serial_number':
                                                   tbs_cert['serial_number']
                                               }),
                                           'key_encryption_algorithm': {
                                               'algorithm':
                                               'rsaes_oaep',
                                               'parameters':
                                               algos.RSAESOAEPParams({
                                                   'hash_algorithm': {
                                                       'algorithm': 'sha256'
                                                   },
                                                   'mask_gen_algorithm': {
                                                       'algorithm': 'mgf1',
                                                       'parameters': {
                                                           'algorithm':
                                                           'sha256'
                                                       }
                                                   }
                                               }),
                                           },
                                           'encrypted_key':
                                           encrypted_key,
                                       })

    # wrap up encrypted data along with symmetric encryption parameters
    # and recipient info
    enveloped_data = cms.ContentInfo({
        'content_type': 'enveloped_data',
        'content': {
            'version': 'v0',
            'recipient_infos': [recipient_info],
            'encrypted_content_info': {
                'content_type': 'data',
                'content_encryption_algorithm': {
                    'algorithm': 'aes256_cbc',
                    'parameters': iv,
                },
                'encrypted_content': encrypted_data
            }
        }
    })

    return enveloped_data