Example #1
0
void echo_stream()
{
	int acceptor, sock;

	if (signal(SIGCHLD, reaper) == SIG_ERR) {
		die(-1, "unable to catch SIGCHLD");
	}
	say("Stream service started\n");

	/* Prepare XSSL context and get SID (based on RSA key) */
	XSSL_CTX *ctx = XSSL_CTX_new();
	if (ctx == NULL) {
		die(-5, "Unable to create new XSSL_CTX\n");
	}
	char *SID = SID_from_keypair(ctx->keypair);

	/* Prepare listen socket, binding to generated SID */
	if ((acceptor = Xsocket(AF_XIA, SOCK_STREAM, 0)) < 0)
		die(-2, "unable to create the stream socket\n");

	struct addrinfo *ai;
	if (Xgetaddrinfo(NULL, SID, NULL, &ai) != 0)
		die(-1, "getaddrinfo failure!\n");

	Graph g((sockaddr_x*)ai->ai_addr);

	sockaddr_x *sa = (sockaddr_x*)ai->ai_addr;

	printf("\nStream DAG\n%s\n", g.dag_string().c_str());

    if (XregisterName(STREAM_NAME, sa) < 0 )
    	die(-1, "error registering name: %s\n", STREAM_NAME);
	say("registered name: \n%s\n", STREAM_NAME);

	if (Xbind(acceptor, (struct sockaddr *)sa, sizeof(sockaddr_x)) < 0) {
		die(-3, "unable to bind to the dag\n");
	}

	Xlisten(acceptor, 5);

	while (1) {

		say("Xsock %4d waiting for a new connection.\n", acceptor);
		if ((sock = Xaccept(acceptor, NULL, 0)) < 0) {
			warn("Xsock %d accept failure! error = %d\n", acceptor, errno);
			// FIXME: should we die here instead or try and recover?
			continue;
		}

		say ("Xsock %4d new session\n", sock);

		pid_t pid = fork();

		if (pid == -1) {
			die(-1, "FORK FAILED\n");

		} else if (pid == 0) {
			process(sock, ctx);
			exit(0);

		} else {
			// FIXME: we need to close the socket in the main process or the file
			// descriptor limit will be hit. But if Xclose is called, the connection
			// is torn down in click as well keeping the child process from using it.
			// for now use a regular close to shut it here without affecting the child.
			close(sock);
		}
	}

	Xclose(acceptor);
	XSSL_CTX_free(ctx);
	free(SID);
}
Example #2
0
/**
* @brief Initiate an XSSL connection with server.
*
* @param xssl
*
* @return 1 on success, <1 on failure
*/
int XSSL_connect(XSSL *xssl) {

	char buf[XIA_MAXBUF];
	int n;

	/* Send CLIENT HELLO */
	sprintf(buf, "CLIENT HELLO");
	if ((n = Xsend(xssl->sockfd, buf, strlen(buf), 0)) != strlen(buf)) {
		ERROR("ERROR sending CLIENT HELLO");
		return 0;
	}

	/* Wait for SERVER HELLO */
	// Receive public key + temporary public key signed by server's long-term private key
	// Continue receiving until we see "SERVER DONE"
	int offset = 0;
	while ( offset < 11 || strcmp("SERVER DONE", &buf[offset-11]) != 0 ) {
		n = Xrecv(xssl->sockfd, &buf[offset], sizeof(buf)-offset, 0);
		if (n < 0) {
			ERROR("ERROR receiving SERVER HELLO");
			return n;
		}
		if (n == 0) {
			ERROR("ERROR: server closed connection during SERVER HELLO");
			return n;
		}

		offset += n;
	}

	/* Parse public keys from SERVER HELLO */
	offset = strlen("SERVER HELLO");
	char *keys = &buf[offset];  // start of signed portion of message

	uint32_t *keybufsizeptr = (uint32_t*)&buf[offset];
	uint32_t keybufsize = *keybufsizeptr; // TODO: error checking here
	offset += sizeof(uint32_t);
	RSA *pubkey = deserialize_rsa_pub_key(&buf[offset], keybufsize);
	offset += keybufsize;

	uint32_t *tempkeybufsizeptr = (uint32_t*)&buf[offset];
	uint32_t tempkeybufsize = *tempkeybufsizeptr;
	offset += sizeof(uint32_t);
	RSA *sessionPubkey = deserialize_rsa_pub_key(&buf[offset], tempkeybufsize);
	offset += tempkeybufsize;

	uint32_t *siglenptr = (uint32_t*)&buf[offset];
	uint32_t siglen = *siglenptr;
	offset += sizeof(uint32_t);
	char* sig = &buf[offset];
	offset += siglen;
	DBGF("Received keys:\n\tkeylen: %d\n\ttempkeylen: %d\n\tsiglen: %d", keybufsize, tempkeybufsize, siglen);

	/* Verify two things:
	 *	1) hash(key) == SID so we trust the signature
	 *	2) verify the sig so we trust the temp key
	 */
	sockaddr_x *sa = (sockaddr_x*)malloc(sizeof(sockaddr_x));
	socklen_t len = sizeof(sockaddr_x);
	if (Xgetpeername(xssl->sockfd, (struct sockaddr*)sa, &len) < 0) {
		ERRORF("Error in Xgetpeername on socket %d: %s", xssl->sockfd, strerror(errno));
		return 0;
	}	
	Graph g(sa);
	Node sid_node = g.get_final_intent();
	DBGF("SID:          %s", sid_node.to_string().c_str());
	char *sid_from_key_hash = SID_from_keypair(pubkey);
	DBGF("Pub key hash: %s", sid_from_key_hash);
	if (strcmp(sid_node.to_string().c_str(), sid_from_key_hash) != 0) {
		WARN("Hash of received public key does not match SID! Closing connection.");
		return 0;
	}
	if (verify(pubkey, keys, keybufsize+tempkeybufsize+2*sizeof(uint32_t), sig, siglen) != 1) {
		WARN("Unable to verify signature on temporary RSA keypair! Closing connection.");
		return 0;
	}


	/* Generate pre-master secret and send to server, encrypted with sessionPubKey */
	unsigned char* pms = (unsigned char*)malloc(PRE_MASTER_SECRET_LENGTH);
    if (RAND_bytes(pms, PRE_MASTER_SECRET_LENGTH) != 1) {
        ERROR("ERROR: Couldn't generate pre-master secret");
		return 0;
    }
	if (VERBOSITY >= V_DEBUG) {
		DBG("Pre-Master Secret:");
		print_bytes(pms, PRE_MASTER_SECRET_LENGTH);
	}

	int ciphertext_len;
	if ( (ciphertext_len = pub_encrypt(sessionPubkey, 
							pms, PRE_MASTER_SECRET_LENGTH, 
							buf, XIA_MAXBUF)) == -1 ) {
		ERROR("ERROR: Unable to encrypt session key");
		return 0;
	}
    
	n = 0;
	offset = 0;
	while (offset < ciphertext_len) {
		if ((n = Xsend(xssl->sockfd, &buf[offset], ciphertext_len-offset, 0)) < 0) {
			ERROR("ERROR sending pre-master secret");
			return 0;
		}
		offset += n;
	}
	

	/* Init symmetric session ciphers with pre-master secret.
	   Client encrypt context initialized with same key data as
	   server decrypt context and vice versa. */
	uint32_t salt[] = SALT;
	if (aes_init(pms, PRE_MASTER_SECRET_LENGTH/2, 
				 &pms[PRE_MASTER_SECRET_LENGTH/2], PRE_MASTER_SECRET_LENGTH/2, 
				 (unsigned char *)&salt, xssl->en, xssl->de)) {
		ERROR("ERROR initializing AES ciphers");
		return 0;
	}
	free(pms);

	
	/* For now, omitting CLIENT DONE */


	return 1;
}