Beispiel #1
0
def setup_key_handler(y: str):
    session = Session.query.get(y)
    policy = PolicyModel.query.get(session.policy)

    if policy is None:
        raise Exception(
            "Couldn't find policy matching session information. Consider adding a policy"
        )
    else:
        key_model = policy.get_key(session.timestamp)
        signer = key_model.signer

        # Retrieve pubkey and generate challenge to send in the response
        pubkey = SigConversion.convert_dict_strlist(signer.get_public_key())
        challenge = SigConversion.convert_dict_strlist(signer.get_challenge())

        # Update and Save
        session.u = signer.u
        session.d = signer.d
        session.s1 = signer.s1
        session.s2 = signer.s2
        session.save_to_db()

        data = {'public_key': pubkey, 'challenge': challenge}
        return data
def setup_key_handler(timestamp: int, number: int, policy: int):
    """
    :param timestamp: (int) Timestamp of when the first knowledge proofs should be available on the ledger
    :param number: (int) Number of requested credentials
    :param policy: (int) The policy that a user is requesting credentials for.
    :return: (dict)
    """
    resp = []
    policy = PolicyModel.query.get(policy)
    sigvars = UserModel.query.get(current_user.id).get_sigvar(
        timestamp, policy)
    if not policy:
        raise Exception("Couldn't find policy")
    if sigvars:
        raise Exception("Key already exists")

    for i in range(0, number):
        # Retrieve key for particular timestamp and policy combination
        time = timestamp + (i * policy.publication_interval * 60
                            )  # publication_interval is in minutes

        # If no KeyModel exists for a given policy at a set time we create one
        key_model = policy.get_key(time)
        if key_model is None:
            signer = SignerBlindSignature(IntegerGroupQ())

            new = KeyModel(time, policy, signer)
            policy.keys.append(new)

            new.save_to_db()
            policy.save_to_db()
        else:
            signer = key_model.signer

        # Retrieve pubkey and generate challenge to send in the response
        pubkey = SigConversion.convert_dict_strlist(signer.get_public_key())
        challenge = SigConversion.convert_dict_strlist(signer.get_challenge())

        # Save
        sigvars = SigVarsModel(timestamp=time,
                               policy=policy.policy,
                               u=signer.u,
                               d=signer.d,
                               s1=signer.s1,
                               s2=signer.s2,
                               user_id=current_user.id)
        sigvars.save_to_db()

        data = {
            'timestamp': time,
            'public_key': pubkey,
            'challenge': challenge
        }

        resp.append(data)

    return resp
Beispiel #3
0
 def verify_blind(self, cp, blind_signature):
     # Convert to modular integer dictionary
     sig = SigConversion.convert_dict_modint(json.loads(blind_signature))
     cp_pubk = get_cp_pubkey(cp, self.timestamp, self.policy)
     verifier = BlindSignatureVerifier(cp_pubk)
     message = Conversion.OS2IP(self.pubk)
     return verifier.verify(sig, message)
Beispiel #4
0
def gen_proof_handler(e: dict):
    key = KeyModel.query.get((current_user.timestamp, current_user.policy))
    signer = key.signer
    signer.d = current_user.d
    signer.u = current_user.u
    signer.s1 = current_user.s1
    signer.s2 = current_user.s2

    # Do the appropriate conversions so that we can serialize
    e = SigConversion.convert_dict_modint(e)
    proofs = SigConversion.convert_dict_strlist(signer.get_proofs(e))
    hash_tmp = SHA256Hash().new(json.dumps(proofs).encode())
    hash_proof = Conversion.OS2IP(hash_tmp.digest())

    resp = {'proof': proofs, 'hash': hash_proof}

    return resp
Beispiel #5
0
 def __init__(self, timestamp, policy, u, d, s1, s2, user_id):
     """
     :param timestamp: POSIX timestamp
     :param policy: integer referencing the policy chosen
     :param u: Element.Integer mod q
     :param d: Element.Integer mod q
     :param s1: Element.Integer mod q
     :param s2: Element.Integer mod q
     :param user_id: integer representing the user in the CP's system database
     """
     self.timestamp = timestamp
     self.policy = policy
     self.user_id = user_id
     self.u_ = SigConversion.modint2strlist(u)
     self.d_ = SigConversion.modint2strlist(d)
     self.s1_ = SigConversion.modint2strlist(s1)
     self.s2_ = SigConversion.modint2strlist(s2)
 def __encode_dict__(self, dict_):
     tmp = {**dict_}
     for key in tmp:
         if tmp.get(key) is not None:
             tmp[key] = SigConversion.modint2strlist(tmp.get(key))
         else:
             tmp[key] = 'null'
     return tmp
def user_response():
    data = json.loads(request.json)

    params = {'policy': data.get('policy'), 'timestamp': data.get('timestamp')}

    # Find y in database
    user = User.query.get(data.get('y'))
    if user is None:
        return jsonify({'message': 'Could not find y'}), 500

    # TODO: Ideally the keys should have been distributed by some other means
    res = requests.get('http://%s:5000/pubkey' % ap_host, params=params)
    if res.status_code == 200:
        key = res.json()
        key = SigConversion.convert_dict_modint(key)
        sig = json.loads(data.get('sig'))
        sig = SigConversion.convert_dict_modint(sig)
        if verify_sig(key, sig, data.get('y')):
            return jsonify({'message': 'Success'}), 200
        else:
            return jsonify({'message': 'Could not verify signature'}), 500
def get_cp_pubkey(cp: int, timestamp: int, policy: int):
    """
    Gets the public key from the ledger for a given timestamp and policy.
    :param cp: The ID of the CP on the ledger.
    :param timestamp: The timestamp at which the proofs are valid.
    :param policy: The CP policy the proofs are associated with.
    :return:
    """
    block = get_block(cp, timestamp, policy)
    key_json = block.get('key')
    key_str = json.loads(key_json.get('key'))
    key = SigConversion.convert_dict_modint(key_str)
    return key
def gen_proofs_handler(policy, es):
    # Get policy from database and setup list
    policy = PolicyModel.query.get(policy)
    resp = list()

    # Iterate through the challenge responses received
    for x in es:
        # Retrieve KeyModel object
        timestamp = x.get('timestamp')
        key = policy.get_key(timestamp)

        # Retrieve SigVarsModel object so we can populate the signer with u and d
        sigvars = current_user.get_sigvar(timestamp, policy.policy)

        # Get policy pool
        pool = policy.get_pool(timestamp)
        if key and sigvars:
            signer = key.signer
            signer.d = sigvars.d
            signer.u = sigvars.u
            signer.s1 = sigvars.s1
            signer.s2 = sigvars.s2

            # Do the appropriate conversions so that we can serialize
            x['e'] = SigConversion.strlist2modint(x.get('e'))
            proofs = SigConversion.convert_dict_strlist(signer.get_proofs(x))
            hash_tmp = SHA256Hash().new(json.dumps(proofs).encode())
            hash_proof = Conversion.OS2IP(hash_tmp.digest())

            # Add proofs to the pool
            pool.append_to_pool(proofs)

            resp.append({'timestamp': timestamp, 'hash_proof': hash_proof})

    resp = {'policy': policy.policy, 'hash_proofs': resp}

    return resp
Beispiel #10
0
def handle_challenge_util(signer_type: str,
                          signer_id: int,
                          resp: dict,
                          policy: int,
                          message: int = None):
    """
    Utility function that takes care of type conversions and ultimately calls the signing function
    :param signer_type: Whether a blind signature is being requested from a CP or an AP.
    :param signer_id: The CP\\AP's participant ID
    :param resp: The CP\\AP response to the challenge request.
    :param policy: The policy for which the signature needs to be generated.
    :param message: The message that the blind signature needs to be generated on.
    :return: e: The challenge response that is used by the CP/AP's to generate the proofs.
    """
    pubk = SigConversion.convert_dict_modint(resp.get('public_key'))
    challenge = SigConversion.convert_dict_modint(resp.get('challenge'))
    timestamp = resp.get('timestamp')

    # Generate signer and keymodel
    signer = UserBlindSignature(pubk)
    key_model = KeyModel(provider_type=signer_type,
                         p_id=signer_id,
                         policy=policy,
                         signer=signer,
                         interval=timestamp)

    if message is None:
        message = Conversion.OS2IP(key_model.public_key)

    e = SigConversion.convert_dict_strlist(
        signer.challenge_response(challenge, message))
    e['timestamp'] = timestamp
    key_model.signer = signer
    key_model.save_to_db()

    return e
    def decode(self, jsn):
        obj = json.loads(jsn)
        db = obj.pop('db') if obj.get('db') is not None else None

        if isinstance(self, SignerBlindSignature):
            new = SignerBlindSignature(IntegerGroupQ())
        elif isinstance(self, UserBlindSignature):
            new = UserBlindSignature()
        else:
            raise Exception("Unexpected argument")

        for key in obj:
            if obj[key] == 'null':
                attr_val = None
            else:
                attr_val = SigConversion.strlist2modint(obj[key])
            setattr(new, key, attr_val)
        if db:
            for key in db:
                db[key] = SigConversion.strlist2modint(db[key])
            setattr(new, 'db', db)
        new.group = IntegerGroupQ()
        new.group.setparam(p=new.p, q=new.q)
        return new
Beispiel #12
0
def get_key():
    """
    Allows services to retrieve the public key associated with a specific timestamp and policy.
    :return:
    """
    timestamp = int(request.args.get('timestamp'))
    policy = int(request.args.get('policy'))

    key = KeyModel.query.get((timestamp, policy))
    if key is None:
        return jsonify({'message': 'No key matching those parameters'}), 400
    else:
        pubkey = key.get_public_key()
        pubkey = SigConversion.convert_dict_strlist(pubkey)
        resp = json.dumps(pubkey)
        return resp, 200
def publish_pool(policy: int, timestamp: int) -> bool:
    """

    :param policy:
    :param timestamp:
    :return:
    """
    pol = PolicyModel.query.get(policy)
    pool = pol.get_pool(timestamp) if pol is not None else None
    key = pol.get_key(timestamp) if pol is not None else None
    res = requests.get("http://cp_rest_api:3000/api/ProofBlock")
    cpid = 2000
    if (res.status_code == 200) and (key is not None) and (pol is not None):
        data = {
            "$class": "digid.ProofBlock",
            "assetId": len(res.json()),
            "owner": "resource:digid.CertificationProvider#" + str(cpid),
            "timestamp": timestamp,
            "lifetime": pol.lifetime,
            "key": {
                "$class": "digid.PublicKey",
                "key": str(json.dumps(SigConversion.convert_dict_strlist(key.get_public_key()))),
                "policy": policy
            },
            "proofHash": str(pool.get_pool_hash()),
            "proofs": str(json.dumps(pool.pool))
        }

        res = requests.post("http://cp_rest_api:3000/api/ProofBlock", json=data)
        if res.status_code == 200:
            return True
            db.session.delete(pool)
            db.session.commit()
        else:
            return False
    else:
        return False
Beispiel #14
0
def publish_pool(policy: int, timestamp: int) -> bool:
    """

    :param policy:
    :param timestamp:
    :return:
    """
    cp_rest = current_app.config['CP_REST_URI']
    cpid = current_app.config['CP_DLT_ID']
    pol = PolicyModel.query.get(policy)
    pool = pol.get_pool(timestamp) if pol is not None else None
    key = pol.get_key(timestamp) if pol is not None else None
    res = requests.get(cp_rest + "/api/ProofBlock")

    if (res.status_code == 200) and (key is not None) and (pol is not None):
        data = {
            "$class": "digid.ProofBlock",
            "assetId": len(res.json()),
            "owner": "resource:digid.CertificationProvider#" + cpid,
            "timestamp": timestamp,
            "lifetime": pol.lifetime,
            "key": {
                "$class": "digid.PublicKey",
                "key": str(json.dumps(SigConversion.convert_dict_strlist(key.get_public_key()))),
                "policy": policy
            },
            "proofHash": str(pool.get_pool_hash()),
            "proofs": str(json.dumps(pool.pool))
        }

        res = requests.post(cp_rest + "/api/ProofBlock", json=data)
        if res.status_code == 200:
            return True
        else:
            return False
    else:
        return False
def access_service_post():
    # Get nonce from service
    res = requests.get('http://{}/request'.format(
        current_app.config['service_host'])).json()
    service_y = res.get('y')

    # Setup parameters that are sent to the AP
    params = {
        'cp':
        int(request.form.get('cp')),
        'timestamp':
        int(dateutil.parser.parse(request.form.get('timestamp')).timestamp()),
        'policy':
        int(request.form.get('policy'))
    }

    # Request-certs CP_i
    res = requests.get('http://{}/request_certs'.format(
        current_app.config['ap_host']),
                       params=params)
    if res.status_code == 500:
        flash("Error when requesting certs: " + res.json().get('message'),
              "access_service_error")
        return render_template('service_authenticate.html')

    # Get data from response and find corresponding keymodel
    data = res.json()
    key_model = KeyModel.query.filter_by(
        provider_type_=1,
        p_id_=params.get('cp'),
        policy_=params.get('policy'),
        interval_timestamp_=params.get('timestamp')).first()

    # Validate that block has not been altered
    try:
        validate_block(data)
    except Exception as e:
        flash("Error when validating block: " + str(e), "access_service_error")
        return render_template('service_authenticate.html')

    pubk = {'pubk': Conversion.OS2IP(key_model.public_key)}

    # Get the challenge from the AP in order to prove that the user owns a specific keypair
    res = requests.get('http://{}/prove_owner'.format(
        current_app.config['ap_host']),
                       params=pubk)
    y = res.json().get('y')

    # Prove the user owns the private key corresponding to a set of proofs in the block
    # Proof consists of the signature of the private key on the nonce y and the blind signature on the public key
    try:
        (proof, proof_owner) = prove_owner(y, data, key_model.proof_hash)
        blind_signature = key_model.generate_blind_signature(
            proof.get('proofs'))

        proof_resp = json.dumps({
            'y':
            y,
            'signature':
            proof_owner[1],
            'blind_signature':
            json.dumps(SigConversion.convert_dict_strlist(blind_signature))
        })

        # Post the proofs
        res = requests.post('http://{}/prove_owner'.format(
            current_app.config['ap_host']),
                            json=proof_resp,
                            params=params)

        # Receive access token for AP
        access_info = res.json()
        err = access_info
        headers = {'Authorization': "Bearer " + access_info.get('access')}

        # Request challenge from AP to issue blind signature
        challenge = requests.get('http://{}/init_sig'.format(
            current_app.config['ap_host']),
                                 headers=headers).json()

        # Handle challenge
        try:
            challenge['timestamp'] = params.get('timestamp')
            e = json.dumps(
                handle_challenge_ap(challenge, params.get('policy'),
                                    service_y))

            # Send Response
            proof_response = requests.post('http://{}/generate_proof'.format(
                current_app.config['ap_host']),
                                           json=e,
                                           headers=headers)
            proofs = proof_response.json()

            # Validate Response
            try:
                validate_proof(proofs)
            except Exception as e:
                flash("Error when validating proofs: " + str(e),
                      "access_service_error")
                return render_template('service_authenticate.html')

            # Get AP Keymodel
            ap_key_model = KeyModel.query.filter_by(p_id_=2000,
                                                    provider_type_=2).first()

            # Build signature
            blind_signature = ap_key_model.generate_blind_signature(
                proofs.get('proof'))

            # Send signature on service_y to service
            resp_service = {
                'y':
                service_y,
                'sig':
                json.dumps(
                    SigConversion.convert_dict_strlist(blind_signature)),
                'policy':
                params.get('policy'),
                'timestamp':
                params.get('timestamp')
            }

            # Get access to service
            res = requests.post('http://{}/response'.format(
                current_app.config['service_host']),
                                json=json.dumps(resp_service))
            if res.status_code == 200:
                return render_template('thanks.html')
            else:
                message = res.json().get('message')
                flash("Response code was not 200: " + message,
                      "access_service_error")
                return render_template('service_authenticate.html')
        except Exception as e:
            flash("There was an error when handling the challenge: " + str(e),
                  "access_service_error")
            return render_template('service_authenticate.html')
    except Exception as e:
        flash(
            "There was an error in the ownership proving stage. The blind signature likely failed to verify: "
            + str(e), "access_service_error")
        return render_template('service_authenticate.html')
Beispiel #16
0
 def s1(self, s1):
     self.s1_ = SigConversion.modint2strlist(s1)
Beispiel #17
0
 def s2(self, s2):
     self.s2_ = SigConversion.modint2strlist(s2)
Beispiel #18
0
 def u(self):
     return SigConversion.strlist2modint(self.u_)
Beispiel #19
0
 def d(self):
     return SigConversion.strlist2modint(self.d_)
Beispiel #20
0
 def s1(self):
     return SigConversion.strlist2modint(self.s1_)
Beispiel #21
0
 def d(self, d):
     self.d_ = SigConversion.modint2strlist(d)
Beispiel #22
0
 def s2(self):
     return SigConversion.strlist2modint(self.s2_)
 def generate_blind_signature(self, proof):
     signer = self.signer
     proof = SigConversion.convert_dict_modint(proof)
     return signer.gen_signature(proof)
Beispiel #24
0
 def u(self, u):
     self.u_ = SigConversion.modint2strlist(u)