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
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 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
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
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
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 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 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')