def certificate_signing_request(self, parent_cert, scope_definition_id, scope_params, userargs=None, password=None): # if server cert does not exist locally, retrieve it from server if not Certificate.objects.filter(id=parent_cert.id).exists(): cert_chain_response = self._get_certificate_chain(parent_cert) # upon receiving cert chain from server, we attempt to save the chain into our records Certificate.save_certificate_chain(cert_chain_response.json(), expected_last_id=parent_cert.id) csr_key = Key() # build up data for csr data = { "parent": parent_cert.id, "profile": parent_cert.profile, "scope_definition": scope_definition_id, "scope_version": parent_cert.scope_version, "scope_params": json.dumps(scope_params), "public_key": csr_key.get_public_key_string() } csr_resp = self._request(api_urls.CERTIFICATE, method="POST", data=data, userargs=userargs, password=password) csr_data = csr_resp.json() # verify cert returned from server, and proceed to save into our records csr_cert = Certificate.deserialize(csr_data["serialized"], csr_data["signature"]) csr_cert.private_key = csr_key csr_cert.check_certificate() csr_cert.save() return csr_cert
def _get_certificate_chain(self, server_cert): # get ancestors certificate chain for this server cert cert_chain_resp = self._request(api_urls.CERTIFICATE, params={'ancestors_of': server_cert.id}) # upon receiving cert chain from server, we attempt to save the chain into our records Certificate.save_certificate_chain(cert_chain_resp.json(), expected_last_id=server_cert.id)
def create_sync_session(self, client_cert, server_cert): # if server cert does not exist locally, retrieve it from server if not Certificate.objects.filter(id=server_cert.id).exists(): cert_chain_response = self._get_certificate_chain(server_cert) # upon receiving cert chain from server, we attempt to save the chain into our records Certificate.save_certificate_chain(cert_chain_response.json(), expected_last_id=server_cert.id) # request the server for a one-time-use nonce nonce_resp = self._get_nonce() nonce = json.loads(nonce_resp.content.decode())["id"] # if no hostname then url is actually an ip url = urlparse(self.base_url) hostname = url.hostname or self.base_url port = url.port or (80 if url.scheme == 'http' else 443) # prepare the data to send in the syncsession creation request data = { "id": uuid.uuid4().hex, "server_certificate_id": server_cert.id, "client_certificate_id": client_cert.id, "profile": client_cert.profile, "certificate_chain": json.dumps( CertificateSerializer( client_cert.get_ancestors(include_self=True), many=True).data), "connection_path": self.base_url, "instance": json.dumps( InstanceIDSerializer( InstanceIDModel.get_or_create_current_instance()[0]).data), "nonce": nonce, "client_ip": _get_client_ip_for_server(hostname, port), "server_ip": _get_server_ip(hostname), } # sign the nonce/ID combo to attach to the request message = "{nonce}:{id}".format(**data) data["signature"] = client_cert.sign(message) # Sync Session creation request session_resp = self._create_sync_session(data) # check that the nonce/id were properly signed by the server cert if not server_cert.verify(message, session_resp.json().get("signature")): raise CertificateSignatureInvalid() # build the data to be used for creating our own syncsession data = { "id": data['id'], "start_timestamp": timezone.now(), "last_activity_timestamp": timezone.now(), "active": True, "is_server": False, "client_certificate": client_cert, "server_certificate": server_cert, "profile": client_cert.profile, "connection_kind": "network", "connection_path": self.base_url, "client_ip": data['client_ip'], "server_ip": data['server_ip'], "client_instance": json.dumps( InstanceIDSerializer( InstanceIDModel.get_or_create_current_instance()[0]).data), "server_instance": session_resp.json().get("server_instance") or "{}", } sync_session = SyncSession.objects.create(**data) return SyncClient(self, sync_session)