Exemple #1
0
def u2f_authenticate(control_byte, req):
    # https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#authentication-messages
    global ks_u2f
    L = req[64]
    if L != KEY_HANDLE_LENGTH:
        return SW_WRONG_DATA
    if len(req) != 64 + 1 + L:
        return SW_CONDITIONS_NOT_SATISFIED
    if control_byte not in (0x03, 0x07, 0x08):
        return SW_CONDITIONS_NOT_SATISFIED
    key_handle = dec_key_handle(req[65:], req[32:64])
    if key_handle == b'':
        return SW_WRONG_DATA
    if control_byte == 0x07:  # check-only
        return SW_CONDITIONS_NOT_SATISFIED
    user_presemce = b'\x00'
    if control_byte == 0x03:  # enforce-user-presence-and-sign
        if (up_check() is False):
            return SW_CONDITIONS_NOT_SATISFIED
        user_presemce = b'\x01'
    private_key = int.from_bytes(key_handle[:32], 'big', False)
    ks_u2f.COUNTER = (ks_u2f.COUNTER + 1) % 0x0100000000
    cb = ks_u2f.COUNTER.to_bytes(4, 'big')
    s = sha256(req[32:64] + user_presemce + cb + req[:32])
    h = int.from_bytes(s.digest(), 'big', False)
    signature = ecdsa_sign(secp256r1, private_key, h)
    return user_presemce + cb + signature + SW_NO_ERROR
Exemple #2
0
def getNextAssertion():
    global ks_ctap2
    global NEXT_CREDENTIAL_TIMER, REM_GETASSERTION_PARAMETERS
    global CREDENTIALCOUNTER, NUMBEROFCREDENTIALS
    global REM_GETASSERTION_PARAMETERS_COMMON, REM_LAST_CMD
    if not REM_GETASSERTION_PARAMETERS:
        return CTAP2_ERR_NOT_ALLOWED
    if REM_LAST_CMD not in(authenticatorGetAssertion, authenticatorGetNextAssertion):
        return CTAP2_ERR_NOT_ALLOWED
    if CREDENTIALCOUNTER >= NUMBEROFCREDENTIALS:
        return CTAP2_ERR_NOT_ALLOWED
    if ticks_diff(ticks_ms(), NEXT_CREDENTIAL_TIMER) > 30000:
        return CTAP2_ERR_NOT_ALLOWED
    d, user_description, credentialID = REM_GETASSERTION_PARAMETERS.pop()
    rp_id_hash, clientDataHash, FLAGS, useRK = REM_GETASSERTION_PARAMETERS_COMMON
    # increase signature counter
    ks_ctap2.COUNTER = (ks_ctap2.COUNTER + 1) % 0x0100000000
    cb = ks_ctap2.COUNTER.to_bytes(4, 'big')
    # authenticator data: https://www.w3.org/TR/webauthn/#table-authData
    auth_data = rp_id_hash + FLAGS + cb
    # compute signature
    s = sha256(auth_data + clientDataHash)  # auth_data + client_data_hash
    h = int.from_bytes(s.digest(), 'big', False)
    signature = ecdsa_sign(secp256r1, d, h)
    CREDENTIALCOUNTER += 1
    NEXT_CREDENTIAL_TIMER = ticks_ms()
    ret = {1: {'id': credentialID, 'type': 'public-key'},
           2: auth_data,
           3: signature}
    if useRK is True:
        ret[4] = user_description
    return CTAP2_OK + encode(ret)
Exemple #3
0
    def test_break(self):
        curve_obj = asymmetric.ECC_NISTP256()
        priv = util.be2int(self.TEST_VECTORS['key1w']['private'])
        pub = tuple(map(util.be2int, self.TEST_VECTORS['key1w']['public']))
        hash_func = lambda m: util.be2int(hashlib.sha256(m).digest())
        hash_bits = 256

        msg1 = self.TEST_VECTORS['msg1']['msg']
        msg2 = self.TEST_VECTORS['msg2']['msg']
        k = util.be2int(self.TEST_VECTORS['msg1']['k'])

        sig1 = ecdsa.ecdsa_sign(curve_obj, hash_func, hash_bits, priv, msg1, k)

        sig2 = ecdsa.ecdsa_sign(curve_obj, hash_func, hash_bits, priv, msg2, k)

        recovered = ecdsa.break_ecdsa(curve_obj, hash_func, hash_bits, sig1,
                                      sig2, msg1, msg2)

        self.assertEquals((k, priv), recovered)
Exemple #4
0
    def _test_ecdsa(self, curve_obj, priv, pub, hash_func, hash_bits, msg, k,
                    reference_sig):
        self.assertEquals(pub, curve_obj.derive_public_key(priv))

        sig = ecdsa.ecdsa_sign(curve_obj, hash_func, hash_bits, priv, msg, k)

        self.assertEquals(reference_sig, sig)

        # verify
        self.assertTrue(
            ecdsa.ecdsa_verify(curve_obj, hash_func, hash_bits, pub, msg,
                               reference_sig))

        self.assertTrue(not ecdsa.ecdsa_verify(curve_obj, hash_func, hash_bits,
                                               pub, 'abcdef', reference_sig))
Exemple #5
0
def u2f_register(req):
    # https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-messages
    if len(req) != 64:
        return SW_WRONG_LENGTH
    # ec key genaration
    d, Q = secp256r1.keyGen()
    user_public_key = b'\x04' + Q.x.to_bytes(32, 'big') \
                              + Q.y.to_bytes(32, 'big')
    key_handle = enc_key_handle(d.to_bytes(32, 'big'), req[32:])

    s = sha256(b'\x00' + req[32:] + req[:32] + key_handle + user_public_key)
    h = int.from_bytes(s.digest(), 'big', False)
    signature = ecdsa_sign(secp256r1, PRIVATE_EC_KEY, h)
    return b'\x05' \
           + user_public_key \
           + KEY_HANDLE_LENGTH.to_bytes(1, 'big') \
           + key_handle \
           + CERTIFICATE_DER \
           + signature \
           + SW_NO_ERROR
Exemple #6
0
def makeCredential(data):
    # https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorMakeCredential
    global ks_ctap2
    try:
        data = decode(data)
    except ValueError:
        return CTAP2_ERR_INVALID_CBOR
    # verify structure of parameter for authenticatorMakeCredential
    ret = ccp.authenticatorMakeCredential.verify(data)
    if ret != CTAP2_OK:
        return ret
    # user description
    user_description = {'id': data[3]['id']}
    for key in ('displayName', 'name', 'icon'):
        if key in data[3]:
            user_description[key] = data[3][key]
    rpId_user_description = encode([data[2]['id'], user_description])
    if not {'alg': -7, 'type': 'public-key'} in data[4]:  # ES256
        return CTAP2_ERR_UNSUPPORTED_ALGORITHM
    if 5 in data:   # excludeList
        for x in data[5]:
            if x['type'] != 'public-key':
                continue
            if dec_key_handle(x['id']) != b'':
                return CTAP2_ERR_CREDENTIAL_EXCLUDED
    rk, uv, up = False, False, True  # default options
    if 7 in data:   # Map of authenticator options
        rk = data[7].get('rk', False)
        uv = data[7].get('uv', False)
        up = data[7].get('up', True)
        if uv is True:
            return CTAP2_ERR_UNSUPPORTED_OPTION
        if up is False:
            return CTAP2_ERR_INVALID_OPTION
    FLAGS = 0x40  # ED | AT | 0 | 0 | 0 | uv | 0 | up
    if isPINset():
        if 8 not in data or 9 not in data:  # pinAuth
            return CTAP2_ERR_PIN_REQUIRED
        if verifyPIN(data[8], data[1]) is False:
            return CTAP2_ERR_PIN_AUTH_INVALID
        else:
            FLAGS |= 0x04
    # make credential
    # user presence check
    if (up_check() is False):
        return CTAP2_ERR_OPERATION_DENIED
    FLAGS = int(FLAGS | 0x01).to_bytes(1, 'big')
    # hash rpid
    s = sha256(bytes(data[2]['id'], 'utf8'))
    rp_id_hash = s.digest()
    # ec key genaration
    d, Q = secp256r1.keyGen()
    if secp256r1.verify_point(Q) is False:
        return CTAP1_ERR_OTHER
    cose_key = encode({1: 2,   # kty: EC2 key type
                       3: -7,  # alg: ES256 signature algorithm
                      -1: 1,   # crv: P-256 curve
                      -2: Q.x.to_bytes(32, 'big'),  # x-coordinate
                      -3: Q.y.to_bytes(32, 'big')   # y-coordinate
                       })
    # generate key handle
    key_handle = enc_key_handle(d.to_bytes(32, 'big') + rpId_user_description)
    Lb = len(key_handle).to_bytes(2, 'big')
    # increase signature counter
    ks_ctap2.COUNTER = (ks_ctap2.COUNTER + 1) % 0x0100000000
    cb = ks_ctap2.COUNTER.to_bytes(4, 'big')
    # authenticator data: https://www.w3.org/TR/webauthn/#fig-attStructs
    auth_data = rp_id_hash + FLAGS + cb + ks_ctap2.AAGUID \
        + Lb + key_handle + cose_key
    # compute signature
    s = sha256(auth_data + data[1])  # auth_data + client_data_hash
    h = int.from_bytes(s.digest(), 'big', False)
    signature = ecdsa_sign(secp256r1, PRIVATE_EC_KEY, h)

    if rk is True:
        if ks_ctap2.save_rk(data[2]['id'], data[3]['id'], key_handle) is False:
            return CTAP2_ERR_KEY_STORE_FULL

    # https://www.w3.org/TR/webauthn/#sctn-attestation
    return CTAP2_OK + encode({1: 'packed',
                              2: auth_data,
                              3: {'alg': -7,
                                  'sig': signature, 'x5c': [CERTIFICATE_DER]}
                              })
Exemple #7
0
def getAssertion(data):
    global ks_ctap2
    global NUMBEROFCREDENTIALS, CREDENTIALCOUNTER
    global REM_GETASSERTION_PARAMETERS, NEXT_CREDENTIAL_TIMER
    global REM_GETASSERTION_PARAMETERS_COMMON
    try:
        data = decode(data)
    except ValueError:
        return CTAP2_ERR_INVALID_CBOR
    # verify structure of parameter for authenticatorGetAssertion
    ret = ccp.authenticatorGetAssertion.verify(data)
    if ret != CTAP2_OK:
        return ret

    allowList = []
    len_allowList = 0
    useRK = False
    if 3 in data:   # allowList
        len_allowList = len(data[3])
        for pkc_descriptor in data[3]:
            if pkc_descriptor['type'] != 'public-key':
                continue
            allowList.append(pkc_descriptor['id'])
    if (3 not in data) or ((3 in data) and (len_allowList == 0)):
        # search for residential keys
        for key_handle in ks_ctap2.load_rk(data[1]):
            useRK = True
            allowList.append(key_handle)
    if not allowList:
        return CTAP2_ERR_NO_CREDENTIALS
    # get options
    uv, up = False, True  # default options
    if 5 in data:   # Map of authenticator options
        if 'rk' in data[5]:
            return CTAP2_ERR_UNSUPPORTED_OPTION
        uv = data[5].get('uv', False)
        up = data[5].get('up', True)
        if uv is True:
            return CTAP2_ERR_UNSUPPORTED_OPTION
    FLAGS = 0  # ED | AT | 0 | 0 | 0 | uv | 0 | up
    if isPINset():
        if 6 not in data or 7 not in data:  # pinAuth
            return CTAP2_ERR_PIN_REQUIRED
        if verifyPIN(data[6], data[2]) is False:
            return CTAP2_ERR_PIN_AUTH_INVALID
        else:
            FLAGS |= 0x04
    # make assertion
    REM_GETASSERTION_PARAMETERS.clear()
    for credId in allowList:
        key_data = dec_key_handle(credId)
        if key_data == b'':
            continue
        try:
            rpId, user_description = decode(key_data[32:])
        except ValueError:
            continue
        if rpId != data[1]:
            continue  # rpId does not match
        d = int.from_bytes(key_data[:32], 'big', False)
        if FLAGS & 0x04 == 0:
            # uv=PIN not done: remove all optional user informations
            user_description = {'id': user_description['id']}
        REM_GETASSERTION_PARAMETERS.append([d, user_description, credId])
    NUMBEROFCREDENTIALS = len(REM_GETASSERTION_PARAMETERS)
    if not REM_GETASSERTION_PARAMETERS:
        return CTAP2_ERR_NO_CREDENTIALS
    d, user_description, credentialID = REM_GETASSERTION_PARAMETERS.pop()
    # user presence check
    if up is True:
        if (up_check() is False):
            return CTAP2_ERR_OPERATION_DENIED
        FLAGS |= 1
    # rpIdHash
    s = sha256(bytes(data[1], 'utf8'))
    rp_id_hash = s.digest()
    # flags
    FLAGS = int(FLAGS).to_bytes(1, 'big')
    # increase signature counter
    ks_ctap2.COUNTER = (ks_ctap2.COUNTER + 1) % 0x0100000000
    cb = ks_ctap2.COUNTER.to_bytes(4, 'big')
    # authenticator data: https://www.w3.org/TR/webauthn/#table-authData
    auth_data = rp_id_hash + FLAGS + cb
    # compute signature
    s = sha256(auth_data + data[2])  # auth_data + client_data_hash
    h = int.from_bytes(s.digest(), 'big', False)
    signature = ecdsa_sign(secp256r1, d, h)
    if not REM_GETASSERTION_PARAMETERS:
        REM_GETASSERTION_PARAMETERS_COMMON = rp_id_hash, data[2], FLAGS, useRK
    CREDENTIALCOUNTER = 1
    NEXT_CREDENTIAL_TIMER = ticks_ms()
    # https://www.w3.org/TR/webauthn/#sctn-attestation
    ret = {1: {'id': credentialID, 'type': 'public-key'},
           2: auth_data,
           3: signature}
    if useRK is True:
        ret[4] = user_description
    if NUMBEROFCREDENTIALS > 1:
        ret[5] = NUMBEROFCREDENTIALS
    return CTAP2_OK + encode(ret)
Exemple #8
0
        r_list.append(get_r(ecdsa.decode_sig(sig)))

    for i in range(len(ordered_sigs)):
        for j in range(i+1,len(ordered_sigs)):
            if(r_list[i] == r_list[j]):                
                #find k from common r
                k = find_k(msgs[i],ecdsa.decode_sig(ordered_sigs[i]),msgs[j],ecdsa.decode_sig(ordered_sigs[j]))
                # find private key from reused nonce k
                pk1 = get_private_key(msgs[i],ecdsa.decode_sig(ordered_sigs[i]),k)

    # sign1 = ecdsa.ecdsa_sign(msgs[4], pk1,ecdsa.secp256k1, hashlib.sha256,k)
    # print msgs[4],ecdsa.encode_sig(sign1)

    # sign2 = ecdsa.ecdsa_sign(msgs[5], pk1,ecdsa.secp256k1, hashlib.sha256,k)
    # print msgs[5],ecdsa.encode_sig(sign2)

    new_msg = "Hello from aaku8856 and mifr0750"

    new_sign = ecdsa.ecdsa_sign(new_msg, pk1)

    print new_msg, ecdsa.encode_sig(new_sign)

    if ecdsa_verify(new_msg, pk, new_sign) == True:
        print 'Signature Verified!'
    else:
        print 'Error: Signature is Invalid!!!'

    if ecdsa_verify(new_msg + 'y', pk, new_sign) == False:
        print 'Correctly rejected invalid signature'
    else:
        print 'Error: verify did not reject incorrect signature'