示例#1
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;
}
int EncryptionModule::handshake_in(char *buf, size_t *datalen, size_t *buflen) {
    (void)buflen;

	/* pick up where we left off in the handshake */
	switch(handshake_status_) {
		case kWaitForClientHello: // server-side
		{
			/* make sure the data is a complete client hello */
			if (strncmp("CLIENT HELLO", buf, 12) != 0) {
				ERROR("ERROR: received message was not CLIENT HELLO\n");
				return ERR_NEED_MORE_DATA;
			} else {
				// FIXME: inefficient!
				// int hello_len = strlen("CLIENT HELLO");
				// char* newbuf = (char*)malloc(*buflen);
				// memcpy(newbuf, buf+hello_len, *datalen-hello_len);
				// *datalen -= hello_len;
				// free(buf);
				// buf = newbuf;  // FIXME: need pointer to pointer

				handshake_status_ = kSendServerHello;
				return 0;
			}
			
		}


		case kWaitForServerHello:  // client-side
		{
			/* 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"
			
			// FIXME: this assumes there's no handshake data after us!
			if (*datalen < 11 || strcmp("SERVER DONE", (buf+*datalen-11)) != 0) {
				ERROR("Did not receive complete SERVER DONE. Waiting for more data\n");
				return ERR_NEED_MORE_DATA;
			}

			/* Parse public keys from SERVER HELLO */
			int 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);
			session_pub_key_ = 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) in the real world, verify the key in the cert
			 *	2) verify the sig so we trust the temp key
			 */
			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 ERR_GENERIC;
			}

			// FIXME: inefficient!
			// char* newbuf = (char*)malloc(*buflen);
			// int used_len = offset + strlen("SERVER DONE");
			// memcpy(newbuf, buf+used_len, *datalen-used_len);
			// *datalen -= used_len;
			// free(buf);
			// buf = newbuf; // FIXME need pointer to pointer

			handshake_status_ = kSendPreMasterSecret;
			return 0;
		}


		case kWaitForPreMasterSecret:  // server-side
		{
			/* Receive and decrypt pre-master secret */
			size_t expecting = RSA_size(session_keypair_); // TODO: have client send key size?
			if (*datalen < expecting) {
				WARN("Did not receive full PMS. Waiting for more data.\n");
				return ERR_NEED_MORE_DATA;
			}


			unsigned char* pms = (unsigned char*)malloc(RSA_size(session_keypair_));
			int plaintext_len;
			if ( (plaintext_len = priv_decrypt(session_keypair_, 
									pms, RSA_size(session_keypair_), 
									(unsigned char*)buf, *datalen)) == -1) {  // FIXME what if there's more data for modules above us?
				ERROR("ERROR decrypting session key");
				return ERR_GENERIC;
			}
			if (plaintext_len != PRE_MASTER_SECRET_LENGTH) {
				ERROR("Decrypted key material is not of size PRE_MASTER_SECRET_LENGTH");
				return ERR_GENERIC;
			}
			if (VERBOSITY >= V_DEBUG) {
				DBG("Pre_Master Secret:");
				//print_bytes(pms, PRE_MASTER_SECRET_LENGTH);
			}


			/* 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], PRE_MASTER_SECRET_LENGTH/2, 
						 pms, PRE_MASTER_SECRET_LENGTH/2, 
						 (unsigned char *)&salt, en_, de_)) {
				ERROR("ERROR initializing AES ciphers");
				return ERR_GENERIC;
			}
			free(pms);
			

			/* remove our handshake data before next module gets buf */
			// FIXME: inefficient!
			// char* newbuf = (char*)malloc(*buflen);
			// memcpy(newbuf, buf+expecting, *datalen-expecting);
			// *datalen -= expecting;
			// free(buf);
			// buf = newbuf; // FIXME need pointer to pointer


			/* done with handshake */
			handshake_status_ = kDone;
			handshake_done_ = true;
			ready_ = true;
			return 0;
		}
		default:
			ERROR("Unknown handshake status\n");
            //printf("handshake status: %d\n", handshake_status_);
			return ERR_GENERIC;
	}

}