Ejemplo n.º 1
0
def test_set_curve_in_key():
    with pytest.raises(CoseException) as excinfo:
        key = EC2Key(crv='P257', d=os.urandom(32))

    assert "Unknown COSE header or key attribute" in str(excinfo)

    with pytest.raises(CoseException) as excinfo:
        key = EC2Key(crv='Ed25519', d=os.urandom(32))

    assert "Unknown COSE header or key attribute" in str(excinfo)

    key = EC2Key(crv='P_256', d=os.urandom(32))
    assert key.crv == P256
Ejemplo n.º 2
0
def test_set_curve_in_key():
    with pytest.raises(CoseException) as excinfo:
        _ = EC2Key(crv='P257', d=p256_d)

    assert "Unknown COSE attribute with value: [CoseCurve - P257]" in str(
        excinfo)

    with pytest.raises(CoseUnsupportedCurve) as excinfo:
        _ = EC2Key(crv='Ed25519', d=p256_d)

    assert "Invalid COSE curve <class 'cose.keys.curves.Ed25519'> for key type EC2Key" in str(
        excinfo)

    key = EC2Key(crv='P_256', d=p256_d)
    assert key.crv == P256
Ejemplo n.º 3
0
def test_unknown_key_attribute():
    key = EC2Key(crv='P_256',
                 d=p256_d,
                 optional_params={"subject_name": "signing key"})

    assert "subject_name" in key
    assert key['subject_name'] == "signing key"
Ejemplo n.º 4
0
def test_fail_on_illegal_kty(crv, kty):
    params = {KpKty: kty}

    with pytest.raises(CoseIllegalKeyType) as excinfo:
        _ = EC2Key(crv=crv, x=os.urandom(32), y=os.urandom(32), d=os.urandom(32), optional_params=params)

    assert "Illegal key type in EC2 COSE Key" in str(excinfo.value)
Ejemplo n.º 5
0
def setup_dh_key(selected_cipher: int, private_bytes: bytes):
    if CipherSuite.from_id(selected_cipher).dh_curve in [X448, X25519]:
        return OKPKey(d=private_bytes, crv=CipherSuite.from_id(selected_cipher).dh_curve)
    elif CipherSuite.from_id(selected_cipher).dh_curve in [P256]:
        return EC2Key(d=private_bytes, crv=CipherSuite.from_id(selected_cipher).sign_curve)
    else:
        raise ValueError("Illegal DH keys.")
Ejemplo n.º 6
0
    def remote_pubkey(self) -> RPK:
        """ Returns the remote ephemeral public key. """

        if self.cipher_suite.dh_curve in [X448, X25519]:
            return OKPKey(x=self.g_y, crv=self.cipher_suite.dh_curve)
        else:
            return EC2Key(x=self.g_y, crv=self.cipher_suite.dh_curve)
Ejemplo n.º 7
0
    def local_pubkey(self) -> RPK:
        """ Returns the local ephemeral public key. """

        # Is this a good criterion? (Possibly there doesn't need to be a
        # distinction; self.cipher_suite.dh_curve.keyclass(...) could do)
        if self.cipher_suite.dh_curve in [X448, X25519]:
            return OKPKey(x=self.g_y, crv=self.cipher_suite.dh_curve)
        else:
            return EC2Key(x=self.g_y, crv=self.cipher_suite.dh_curve)
Ejemplo n.º 8
0
def setup_sign_key(selected_cipher: int, private_bytes: bytes):
    if CipherSuite.from_id(selected_cipher).sign_curve in [Ed448, Ed25519]:
        return OKPKey(d=private_bytes,
                      crv=CipherSuite.from_id(selected_cipher).sign_curve,
                      optional_params={KpAlg: CipherSuite.from_id(selected_cipher).sign_alg})
    elif CipherSuite.from_id(selected_cipher).sign_alg == Es256:
        return EC2Key(d=private_bytes, alg=Es256, crv=CipherSuite.from_id(selected_cipher).sign_curve)
    else:
        raise ValueError("Illegal COSE curve.")
Ejemplo n.º 9
0
def test_fail_on_illegal_kty(crv, kty):
    params = {KpKty: kty}

    # NOTE: the stuff in params will override the parameters of the function if they are specified twice
    # Here the KpKty value which is set by the constructor gets overwritten by the params dict
    with pytest.raises(CoseIllegalKeyType) as excinfo:
        _ = EC2Key(crv=crv,
                   x=p256_x,
                   y=p256_y,
                   d=p256_d,
                   optional_params=params)

    assert "Illegal key type in EC2 COSE Key" in str(excinfo.value)
Ejemplo n.º 10
0
def create_cose_1_sign_msg(payload, private_key):
    crv = P384
    d_value = private_key.private_numbers().private_value
    x_coor = private_key.public_key().public_numbers().x
    y_coor = private_key.public_key().public_numbers().y

    key = EC2Key(
        crv=crv,
        d=d_value.to_bytes(crv.size, "big"),
        x=x_coor.to_bytes(crv.size, "big"),
        y=y_coor.to_bytes(crv.size, "big"),
    )

    phdr = {1: Es384}
    msg = Sign1Message(phdr=phdr, payload=payload, key=key)

    sig = msg.compute_signature()
    msg._signature = sig

    return msg.encode(tag=False)
Ejemplo n.º 11
0
def verify_attestation_signature(payload, cert):
    logger.debug("* Verifying attestation certificate signature...")
    cert = load_der_x509_certificate(cert)
    cert_public_numbers = cert.public_key().public_numbers()
    x = cert_public_numbers.x
    y = cert_public_numbers.y

    x = _long_to_bytes(x)
    y = _long_to_bytes(y)

    # Create the EC2 key from public key parameters
    key = EC2Key(x=x, y=y, crv=P384)

    cose_obj = cbor2.loads(payload)
    msg = Sign1Message.from_cose_obj(cose_obj, allow_unknown_attributes=True)
    msg.key = key

    # Verify the signature using the EC2 key
    verified = msg.verify_signature()
    if not verified:
        errmsg = "Malformed attestation doc: incorrect certificate signature."
        logger.error(errmsg)
        raise RuntimeError(errmsg)
    logger.debug("* Attestation certificate signature verified.")
Ejemplo n.º 12
0
def test_on_missing_public_y_values(crv, x):
    key = EC2Key(crv=crv, x=x)

    assert key.y
Ejemplo n.º 13
0
def test_fail_with_d_and_missing_public_y_values(crv):
    with pytest.raises(CoseInvalidKey) as excinfo:
        _ = EC2Key(crv=crv, x=os.urandom(32), d=os.urandom(32))

    assert "Missing public coordinate X/Y" in str(excinfo.value)
Ejemplo n.º 14
0
    def test(self):
        print('\nTest: ' + __name__ + '.' + type(self).__name__)
        private_key = EC2Key(
            crv=curves.P256,
            x=binascii.unhexlify('44c1fa63b84f172b50541339c50beb0e630241ecb4eebbddb8b5e4fe0a1787a8'),
            y=binascii.unhexlify('059451c7630d95d0b550acbd02e979b3f4f74e645b74715fafbc1639960a0c7a'),
            d=binascii.unhexlify('dd6e7d8c4c0e0c0bd3ae1b4a2fa86b9a09b7efee4a233772cf5189786ea63842'),
            optional_params={
                keyparam.KpKid: b'ExampleEC2',
                keyparam.KpKeyOps: [keyops.SignOp, keyops.VerifyOp],
            }
        )
        print('Private Key: {}'.format(encode_diagnostic(cbor2.loads(private_key.encode()))))

        # Primary block
        prim_dec = self._get_primary_item()
        prim_enc = cbor2.dumps(prim_dec)
        print('Primary Block: {}'.format(encode_diagnostic(prim_dec)))
        print('Encoded: {}'.format(encode_diagnostic(prim_enc)))

        # Security target block
        target_dec = self._get_target_item()
        target_enc = cbor2.dumps(target_dec)
        content_plaintext = target_dec[4]
        print('Target Block: {}'.format(encode_diagnostic(target_dec)))
        print('Plaintext: {}'.format(encode_diagnostic(content_plaintext)))

        # Combined AAD
        ext_aad_dec = self._get_aad_item()
        ext_aad_enc = cbor2.dumps(ext_aad_dec)
        print('External AAD: {}'.format(encode_diagnostic(ext_aad_dec)))
        print('Encoded: {}'.format(encode_diagnostic(ext_aad_enc)))

        msg_obj = Sign1Message(
            phdr={
                headers.Algorithm: algorithms.Es256,
            },
            uhdr={
                headers.KID: private_key.kid,
            },
            payload=content_plaintext,
            # Non-encoded parameters
            external_aad=ext_aad_enc,
        )
        msg_obj.key = private_key

        # COSE internal structure
        cose_struct_enc = msg_obj._sig_structure
        cose_struct_dec = cbor2.loads(cose_struct_enc)
        print('COSE Structure: {}'.format(encode_diagnostic(cose_struct_dec)))
        print('Encoded: {}'.format(encode_diagnostic(cose_struct_enc)))

        # Encoded message
        message_enc = msg_obj.encode(tag=False)
        message_dec = cbor2.loads(message_enc)
        # Detach the payload
        content_signature = message_dec[2]
        message_dec[2] = None
        self._print_message(message_dec, recipient_idx=4)
        message_enc = cbor2.dumps(message_dec)

        # ASB structure
        asb_dec = self._get_asb_item([
            msg_obj.cbor_tag,
            message_enc
        ])
        asb_enc = self._get_asb_enc(asb_dec)
        print('ASB: {}'.format(encode_diagnostic(asb_dec)))
        print('Encoded: {}'.format(encode_diagnostic(asb_enc)))

        bpsec_dec = self._get_bpsec_item(
            block_type=BlockType.BIB,
            asb_dec=asb_dec,
        )
        bpsec_enc = cbor2.dumps(bpsec_dec)
        print('BPSec block: {}'.format(encode_diagnostic(bpsec_dec)))
        print('Encoded: {}'.format(encode_diagnostic(bpsec_enc)))

        # Change from detached payload
        message_dec[2] = content_signature
        decode_obj = Sign1Message.from_cose_obj(message_dec)
        decode_obj.external_aad = ext_aad_enc
        decode_obj.key = private_key

        verify_valid = decode_obj.verify_signature()
        self.assertTrue(verify_valid)
        print('Loopback verify:', verify_valid)

        bundle = self._assemble_bundle([prim_enc, bpsec_enc, target_enc])
        print('Total bundle: {}'.format(encode_diagnostic(bundle)))
Ejemplo n.º 15
0
    def extract_cose_key(keyobj):
        ''' Get a COSE version of the local private key.
        :param keyobj: The cryptography key object.
        :return: The associated COSE key.
        :rtype: :py:cls:`CoseKey`
        '''
        if isinstance(keyobj, (rsa.RSAPrivateKey, rsa.RSAPublicKey)):
            if hasattr(keyobj, 'private_numbers'):
                priv_nums = keyobj.private_numbers()
                pub_nums = keyobj.public_key().public_numbers()
            else:
                priv_nums = None
                pub_nums = keyobj.public_numbers()

            kwargs = dict()
            if pub_nums:

                def convert(name, attr=None):
                    val = getattr(pub_nums, attr or name)
                    kwargs[name] = val.to_bytes((val.bit_length() + 7) // 8,
                                                byteorder="big")

                convert('n')
                convert('e')
            if priv_nums:

                def convert(name, attr=None):
                    val = getattr(priv_nums, attr or name)
                    kwargs[name] = val.to_bytes((val.bit_length() + 7) // 8,
                                                byteorder="big")

                convert('d')
                convert('p')
                convert('q')
                convert('dp', 'dmp1')
                convert('dq', 'dmq1')
                convert('qinv', 'iqmp')

            cose_key = RSAKey(**kwargs)
            cose_key.alg = algorithms.Ps256

        elif isinstance(
                keyobj,
            (ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey)):
            CURVE_CLS_MAP = {
                ec.SECP256R1: curves.P256,
                ec.SECP384R1: curves.P384,
                ec.SECP521R1: curves.P521,
            }
            CURVE_ALG_MAP = {
                ec.SECP256R1: algorithms.Es256,
                ec.SECP384R1: algorithms.Es384,
                ec.SECP521R1: algorithms.Es512,
            }

            try:
                curve_cls = CURVE_CLS_MAP[type(keyobj.curve)]
            except KeyError:
                raise CoseUnsupportedCurve('Cannot match curve for {}'.format(
                    repr(keyobj)))
            LOGGER.debug('Found COSE curve %s', curve_cls)

            try:
                alg_cls = CURVE_ALG_MAP[type(keyobj.curve)]
            except KeyError:
                raise CoseUnsupportedCurve(
                    'Cannot match algorithm for {}'.format(repr(keyobj)))
            LOGGER.debug('Found COSE algorithm %s', alg_cls)

            if hasattr(keyobj, 'private_numbers'):
                priv_nums = keyobj.private_numbers()
                pub_nums = keyobj.public_key().public_numbers()
            else:
                priv_nums = None
                pub_nums = keyobj.public_numbers()

            kwargs = dict(
                crv=curve_cls,
                optional_params={
                    keyparam.KpAlg: alg_cls,
                },
            )

            if pub_nums:
                x_coor = pub_nums.x
                y_coor = pub_nums.y
                kwargs.update(
                    dict(x=x_coor.to_bytes((x_coor.bit_length() + 7) // 8,
                                           byteorder="big"),
                         y=y_coor.to_bytes((y_coor.bit_length() + 7) // 8,
                                           byteorder="big")))
            if priv_nums:
                d_value = priv_nums.private_value
                kwargs.update(
                    dict(d=d_value.to_bytes((d_value.bit_length() + 7) // 8,
                                            byteorder="big"), ))

            cose_key = EC2Key(**kwargs)

        else:
            raise TypeError('Cannot handle key {}'.format(repr(keyobj)))

        return cose_key
    def test(self):
        print('\nTest: ' + __name__ + '.' + type(self).__name__)
        private_key = EC2Key(
            crv=curves.P256,
            x=binascii.unhexlify(
                '44c1fa63b84f172b50541339c50beb0e630241ecb4eebbddb8b5e4fe0a1787a8'
            ),
            y=binascii.unhexlify(
                '059451c7630d95d0b550acbd02e979b3f4f74e645b74715fafbc1639960a0c7a'
            ),
            d=binascii.unhexlify(
                'dd6e7d8c4c0e0c0bd3ae1b4a2fa86b9a09b7efee4a233772cf5189786ea63842'
            ),
            optional_params={
                keyparam.KpKid: b'ExampleEC2',
                keyparam.KpKeyOps: [keyops.DeriveKeyOp],
            })
        print('Private Key: {}'.format(
            encode_diagnostic(cbor2.loads(private_key.encode()))))
        # 256-bit content encryption key
        cek = SymmetricKey(k=binascii.unhexlify(
            '13BF9CEAD057C0ACA2C9E52471CA4B19DDFAF4C0784E3F3E8E3999DBAE4CE45C'
        ),
                           optional_params={
                               keyparam.KpKid:
                               b'ExampleCEK',
                               keyparam.KpKeyOps:
                               [keyops.EncryptOp, keyops.DecryptOp],
                           })
        print('CEK: {}'.format(encode_diagnostic(cbor2.loads(cek.encode()))))
        # session IV
        iv = binascii.unhexlify('6F3093EBA5D85143C3DC484A')
        print('IV: {}'.format(binascii.hexlify(iv)))

        # Would be random ephemeral key, but test constant
        sender_key = EC2Key(
            crv=curves.P256,
            x=binascii.unhexlify(
                'fedaba748882050d1bef8ba992911898f554450952070aeb4788ca57d1df6bcc'
            ),
            y=binascii.unhexlify(
                'ceaa8e7ff4751a4f81c70e98f1713378b0bd82a1414a2f493c1c9c0670f28d62'
            ),
            d=binascii.unhexlify(
                'a2e4ed4f2e21842999b0e9ebdaad7465efd5c29bd5761f5c20880f9d9c3b122a'
            ),
        )
        print('Sender Private Key: {}'.format(
            encode_diagnostic(cbor2.loads(sender_key.encode()))))
        sender_public = EC2Key(crv=sender_key.crv,
                               x=sender_key.x,
                               y=sender_key.y)

        # Primary block
        prim_dec = self._get_primary_item()
        prim_enc = cbor2.dumps(prim_dec)
        print('Primary Block: {}'.format(encode_diagnostic(prim_dec)))
        print('Encoded: {}'.format(encode_diagnostic(prim_enc)))

        # Security target block
        target_dec = self._get_target_item()
        content_plaintext = target_dec[4]
        print('Target Block: {}'.format(encode_diagnostic(target_dec)))
        print('Plaintext: {}'.format(encode_diagnostic(content_plaintext)))

        # Combined AAD
        ext_aad_dec = self._get_aad_item()
        ext_aad_enc = cbor2.dumps(ext_aad_dec)
        print('External AAD: {}'.format(encode_diagnostic(ext_aad_dec)))
        print('Encoded: {}'.format(encode_diagnostic(ext_aad_enc)))

        msg_obj = EncMessage(
            phdr={
                headers.Algorithm: algorithms.A256GCM,
            },
            uhdr={
                headers.IV: iv,
            },
            payload=content_plaintext,
            recipients=[
                KeyAgreementWithKeyWrap(
                    uhdr={
                        headers.Algorithm: algorithms.EcdhEsA256KW,
                        headers.KID: private_key.kid,
                        headers.EphemeralKey: sender_public,
                    },
                    payload=cek.k,
                ),
            ],
            # Non-encoded parameters
            external_aad=ext_aad_enc,
        )
        recip = msg_obj.recipients[0]
        recip.key = sender_key
        recip.local_attrs = {
            headers.StaticKey: private_key,
        }

        # COSE internal structure
        cose_struct_enc = msg_obj._enc_structure
        cose_struct_dec = cbor2.loads(cose_struct_enc)
        print('COSE Structure: {}'.format(encode_diagnostic(cose_struct_dec)))
        print('Encoded: {}'.format(encode_diagnostic(cose_struct_enc)))

        # Encoded message
        message_enc = msg_obj.encode(tag=False)
        message_dec = cbor2.loads(message_enc)
        # Detach the payload
        content_ciphertext = message_dec[2]
        message_dec[2] = None
        self._print_message(message_dec, recipient_idx=3)
        print('Ciphertext: {}'.format(encode_diagnostic(content_ciphertext)))
        message_enc = cbor2.dumps(message_dec)

        # ASB structure
        asb_dec = self._get_asb_item([msg_obj.cbor_tag, message_enc])
        asb_enc = self._get_asb_enc(asb_dec)
        print('ASB: {}'.format(encode_diagnostic(asb_dec)))
        print('Encoded: {}'.format(encode_diagnostic(asb_enc)))

        bpsec_dec = self._get_bpsec_item(
            block_type=BlockType.BCB,
            asb_dec=asb_dec,
        )
        bpsec_enc = cbor2.dumps(bpsec_dec)
        print('BPSec block: {}'.format(encode_diagnostic(bpsec_dec)))
        print('Encoded: {}'.format(encode_diagnostic(bpsec_enc)))

        # Change from detached payload
        message_dec[2] = content_ciphertext
        decode_obj = EncMessage.from_cose_obj(message_dec)
        decode_obj.external_aad = ext_aad_enc

        recip = decode_obj.recipients[0]
        recip.key = private_key
        decode_plaintext = decode_obj.decrypt(recipient=recip)
        print('Loopback plaintext:', encode_diagnostic(decode_plaintext))
        self.assertEqual(content_plaintext, decode_plaintext)

        print('Loopback CEK:',
              encode_diagnostic(cbor2.loads(decode_obj.key.encode())))
        self.assertEqual(cek.k, decode_obj.key.k)

        target_dec[4] = content_ciphertext
        target_enc = cbor2.dumps(target_dec)
        bundle = self._assemble_bundle([prim_enc, bpsec_enc, target_enc])
        print('Total bundle: {}'.format(encode_diagnostic(bundle)))
Ejemplo n.º 17
0
def test_ec2_key_construction(crv):
    key = EC2Key(crv=crv, x=os.urandom(32), y=os.urandom(32), d=os.urandom(32))

    assert _is_valid_ec2_key(key)
Ejemplo n.º 18
0
def test_ec2_key_construction(crv, x, y, d):
    key = EC2Key(crv=crv, x=x, y=y, d=d)

    assert _is_valid_ec2_key(key)
Ejemplo n.º 19
0
def test_fail_with_d_and_missing_public_y_values(crv, x, d):
    key = EC2Key(crv=crv, x=x, d=d)

    assert key.y
Ejemplo n.º 20
0
def test_with_d_and_missing_public_x_values(crv, y, d):
    key = EC2Key(crv=crv, y=y, d=d)

    assert key.x
Ejemplo n.º 21
0
def test_fail_on_missing_key_values(crv):
    with pytest.raises(CoseInvalidKey) as excinfo:
        _ = EC2Key(crv=crv)

    assert "Either the public values or the private value must be specified" in str(
        excinfo.value)
Ejemplo n.º 22
0
def test_fail_on_missing_public_x_values(crv, y):
    with pytest.raises(CoseInvalidKey) as excinfo:
        _ = EC2Key(crv=crv, y=y)

    assert "Missing public coordinate X" in str(excinfo.value)