Beispiel #1
0
    def test_reference_uris_and_custom_key_info(self):
        with open(os.path.join(os.path.dirname(__file__), "example.pem"), "rb") as fh:
            crt = fh.read()
        with open(os.path.join(os.path.dirname(__file__), "example.key"), "rb") as fh:
            key = fh.read()

        # Both ID and Id formats. XPath 1 doesn't have case insensitive attribute search
        for d in ['''<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                                     xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="responseId">
                      <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="assertionId">
                       <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder" />
                      </saml:Assertion>
                     </samlp:Response>''',
                  '''<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                                     xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Id="responseId">
                      <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xmlns:xs="http://www.w3.org/2001/XMLSchema" Id="assertionId">
                       <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder" />
                      </saml:Assertion>
                      <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xmlns:xs="http://www.w3.org/2001/XMLSchema" Id="assertion2">
                      </saml:Assertion>
                     </samlp:Response>''']:
            data = etree.fromstring(d)
            reference_uri = ["assertionId", "assertion2"] if "assertion2" in d else "assertionId"
            signed_root = XMLSigner().sign(data, reference_uri=reference_uri, key=key, cert=crt)
            signed_data_root = XMLVerifier().verify(etree.tostring(signed_root), x509_cert=crt, expect_references=True)[1]
            ref = signed_root.xpath('/samlp:Response/saml:Assertion/ds:Signature/ds:SignedInfo/ds:Reference',
                                    namespaces={"ds": "http://www.w3.org/2000/09/xmldsig#",
                                                "saml": "urn:oasis:names:tc:SAML:2.0:assertion",
                                                "samlp": "urn:oasis:names:tc:SAML:2.0:protocol"})
            self.assertEqual("assertionId", ref[0].attrib['URI'][1:])

            self.assertEqual("{urn:oasis:names:tc:SAML:2.0:assertion}Assertion", signed_data_root.tag)

            # Also test with detached signing
            for c14_transform_option in include_c14_transformation:
                XMLSigner(method=methods.detached,
                          include_c14n_transform=c14_transform_option
                          ).sign(data, reference_uri=reference_uri, key=key, cert=crt)

            # Test setting custom key info
            custom_key_info = etree.fromstring('''
            <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                <wsse:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1"/>
            </wsse:SecurityTokenReference>''')
            XMLSigner().sign(data, reference_uri=reference_uri, key=key, cert=crt, key_info=custom_key_info)
Beispiel #2
0
    def test_reference_uris_and_custom_key_info(self):
        with open(os.path.join(os.path.dirname(__file__), "example.pem"),
                  "rb") as fh:
            crt = fh.read()
        with open(os.path.join(os.path.dirname(__file__), "example.key"),
                  "rb") as fh:
            key = fh.read()

        # Both ID and Id formats. XPath 1 doesn't have case insensitive attribute search
        for d in [
                '''<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                                     xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="responseId">
                      <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="assertionId">
                       <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder" />
                      </saml:Assertion>
                     </samlp:Response>''',
                '''<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                                     xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Id="responseId">
                      <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xmlns:xs="http://www.w3.org/2001/XMLSchema" Id="assertionId">
                       <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder" />
                      </saml:Assertion>
                      <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xmlns:xs="http://www.w3.org/2001/XMLSchema" Id="assertion2">
                      </saml:Assertion>
                     </samlp:Response>'''
        ]:
            data = etree.fromstring(d)
            reference_uri = ["assertionId", "assertion2"
                             ] if "assertion2" in d else "assertionId"
            signed_root = XMLSigner().sign(data,
                                           reference_uri=reference_uri,
                                           key=key,
                                           cert=crt)
            signed_data_root = XMLVerifier().verify(
                etree.tostring(signed_root),
                x509_cert=crt,
                expect_references=True)[1]
            ref = signed_root.xpath(
                '/samlp:Response/saml:Assertion/ds:Signature/ds:SignedInfo/ds:Reference',
                namespaces={
                    "ds": "http://www.w3.org/2000/09/xmldsig#",
                    "saml": "urn:oasis:names:tc:SAML:2.0:assertion",
                    "samlp": "urn:oasis:names:tc:SAML:2.0:protocol"
                })
            self.assertEqual("assertionId", ref[0].attrib['URI'][1:])

            self.assertEqual(
                "{urn:oasis:names:tc:SAML:2.0:assertion}Assertion",
                signed_data_root.tag)

            # Also test with detached signing
            ref_xpath = "/ds:Signature/ds:SignedInfo/ds:Reference"
            signer = XMLSigner(method=methods.detached)
            s = signer.sign(data,
                            reference_uri=reference_uri,
                            key=key,
                            cert=crt)
            self.assertTrue(
                s.xpath(ref_xpath + "/ds:Transforms", namespaces=namespaces))
            self.assertTrue(
                s.xpath(ref_xpath + "/ds:DigestMethod", namespaces=namespaces))
            self.assertTrue(
                s.xpath(ref_xpath + "/ds:DigestValue", namespaces=namespaces))

            self.assertTrue(
                s.xpath("/ds:Signature/ds:KeyInfo/ds:X509Data",
                        namespaces=namespaces))
            self.assertFalse(
                s.xpath("/ds:Signature/ds:KeyInfo/ds:KeyValue",
                        namespaces=namespaces))
            s2 = signer.sign(data,
                             reference_uri=reference_uri,
                             key=key,
                             cert=crt,
                             always_add_key_value=True)
            self.assertTrue(
                s2.xpath("/ds:Signature/ds:KeyInfo/ds:X509Data",
                         namespaces=namespaces))
            self.assertTrue(
                s2.xpath("/ds:Signature/ds:KeyInfo/ds:KeyValue",
                         namespaces=namespaces))

            # Test setting custom key info
            wsse_ns = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
            with open(
                    os.path.join(os.path.dirname(__file__),
                                 "wsse_keyinfo.xml")) as fh:
                custom_key_info = etree.fromstring(fh.read())
            s3 = signer.sign(data,
                             reference_uri=reference_uri,
                             key=key,
                             cert=crt,
                             key_info=custom_key_info)
            self.assertTrue(
                s3.xpath(
                    "/ds:Signature/ds:KeyInfo/wsse:SecurityTokenReference",
                    namespaces=dict(namespaces, wsse=wsse_ns)))

            # Test setting both X509Data and KeyInfo
            s4 = XMLSigner().sign(data,
                                  reference_uri=reference_uri,
                                  key=key,
                                  cert=crt,
                                  always_add_key_value=True)
            with self.assertRaisesRegexp(InvalidInput,
                                         "Both X509Data and KeyValue found"):
                XMLVerifier().verify(s4, x509_cert=crt)
            expect_refs = etree.tostring(s4).decode().count("<ds:Reference")
            XMLVerifier().verify(s4,
                                 x509_cert=crt,
                                 ignore_ambiguous_key_info=True,
                                 expect_references=expect_refs)
def create_cpix_user_request(
    key_ids,
    media_id,
    user_private_key_path,
    user_public_cert_path,
    use_playready=False,
    use_widevine=False,
    use_fairplay=False,
    nsmap=None,
):
    document_public_cert_path = (
        os.path.dirname(__file__) + '/keys/buydrm_qencode_public_cert.pem'
    )
    """Creates CPIX request XML signed end user

    Arguments:
        key_ids {list} -- List of Key IDs and corresponding track quality types. The list is of
        the following format - { 'kid': [string in GUID/UUID format], 'track_type': [string track type]}.

        media_id {string} -- Some random name for your asset which is shown in KeyOS console and reports.

        nsmap {list} -- List of namespaces.

    Returns:
        string -- CPIX request XML signed end user
    """
    nsmap = nsmap if nsmap is not None else NSMAP

    # Own private key and end user's private key used to sign the document
    end_user_private_key = open(user_private_key_path, 'rb').read()

    # Own public certificate and end user's public certificate to include into the CPIX request
    end_user_public_cert = open(user_public_cert_path, 'rb').read()
    document_public_cert = open(document_public_cert_path, 'rb').read()

    root = etree.Element('{%s}CPIX' % nsmap['cpix'], name=media_id, nsmap=nsmap)
    root.set('{%s}schemaLocation' % nsmap['xsi'], 'urn:dashif:org:cpix cpix.xsd')

    # Delivery data list
    delivery_data_list = etree.SubElement(root, '{%s}DeliveryDataList' % nsmap['cpix'])
    delivery_data = etree.SubElement(
        delivery_data_list, '{%s}DeliveryData' % nsmap['cpix']
    )
    delivery_key = etree.SubElement(delivery_data, '{%s}DeliveryKey' % nsmap['cpix'])

    # The public certificate of a partner. This certificate's public key will be used
    # to encrypt Document Key which will later be used to encrypt Contnet Keys.
    x509_data = etree.SubElement(delivery_key, '{%s}X509Data' % nsmap['ds'])
    x509_cert = etree.SubElement(x509_data, '{%s}X509Certificate' % nsmap['ds'])
    x509_cert.text = (
        document_public_cert.replace('-----BEGIN CERTIFICATE-----', '')
        .replace('-----END CERTIFICATE-----', '')
        .replace('\n', '')
    )

    # Content key list
    content_key_list = etree.SubElement(root, '{%s}ContentKeyList' % nsmap['cpix'])

    # Content key usage rules
    content_key_usage_list = etree.SubElement(
        root, '{%s}ContentKeyUsageRuleList' % nsmap['cpix']
    )

    # DRM systems list
    drm_system_list = etree.SubElement(root, '{%s}DRMSystemList' % nsmap['cpix'])

    for data in key_ids:
        etree.SubElement(
            content_key_list, '{%s}ContentKey' % nsmap['cpix'], kid=data['kid']
        )
        if use_playready:
            etree.SubElement(
                drm_system_list,
                '{%s}DRMSystem' % nsmap['cpix'],
                kid=data['kid'],
                systemId=SYSTEM_ID_PLAYREADY,
            )
        if use_widevine:
            etree.SubElement(
                drm_system_list,
                '{%s}DRMSystem' % nsmap['cpix'],
                kid=data['kid'],
                systemId=SYSTEM_ID_WIDEVINE,
            )
        if use_fairplay:
            etree.SubElement(
                drm_system_list,
                '{%s}DRMSystem' % nsmap['cpix'],
                kid=data['kid'],
                systemId=SYSTEM_ID_FAIRPLAY,
            )

        etree.SubElement(
            content_key_usage_list,
            '{%s}ContentKeyUsageRule' % nsmap['cpix'],
            kid=data['kid'],
            intendedTrackType=data['track_type'],
        )

    # Signing document with end user's data
    end_user_signed_root = XMLSigner(
        c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315',
        signature_algorithm='rsa-sha256',
        digest_algorithm='sha512',
    ).sign(root, key=end_user_private_key, cert=end_user_public_cert)
    x509_sign_cert = end_user_signed_root.xpath(
        '//ds:X509Certificate', namespaces=nsmap
    )[1]
    x509_sign_cert.text = x509_sign_cert.text.replace('\n', '')
    #
    return etree.tostring(end_user_signed_root).decode('utf-8')