/** * @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_out(char *buf, size_t *datalen, size_t *buflen) { /* pick up where we left off in the handshake. append the next portion of the handshake to buf, after whatever handshake data may be ther already. */ switch(handshake_status_) { case kSendClientHello: // client-side { /* Send CLIENT HELLO */ int hello_len = sprintf((buf+*datalen), "CLIENT HELLO"); *datalen += hello_len; handshake_status_ = kWaitForServerHello; return 0; } case kSendServerHello: // server-side { /* Send SERVER HELLO */ int hello_len = sprintf((buf+*datalen), "SERVER HELLO"); *datalen += hello_len; /* Send public key + temporary public key signed by long-term private key */ // // Copy the following into buf: // keylen || key || tempkeylen || tempkey || siglen || sig // size_t offset = 0; char* base = buf+*datalen; int base_buflen = *buflen-*datalen; uint32_t keybufsize = serialize_rsa_pub_key(master_keypair_, base+sizeof(uint32_t), base_buflen-offset-sizeof(uint32_t)); uint32_t* keybufsizeptr = (uint32_t*)base; *keybufsizeptr = keybufsize; offset += (sizeof(uint32_t) + keybufsize); uint32_t tempkeybufsize = serialize_rsa_pub_key(session_keypair_, base+sizeof(uint32_t)+offset, base_buflen-offset-sizeof(uint32_t)); uint32_t* tempkeybufsizeptr = (uint32_t*)(base+offset); *tempkeybufsizeptr = tempkeybufsize; offset += (sizeof(uint32_t) + tempkeybufsize); uint32_t siglen = sign(master_keypair_, base, offset, base+offset+sizeof(uint32_t), base_buflen-offset-sizeof(uint32_t)); uint32_t* siglenptr = (uint32_t*)(base+offset); *siglenptr = siglen; offset += sizeof(uint32_t); offset += siglen; *datalen += offset; DBGF("Sent keys (%lu bytes)\n\tkeylen: %d\n\ttempkeylen: %d\n\tsiglen:%d", offset, keybufsize, tempkeybufsize, siglen); /* Send SERVER (hello) DONE */ int done_len = sprintf((buf+*datalen), "SERVER DONE"); *datalen += done_len; handshake_status_ = kWaitForPreMasterSecret; return 0; } case kSendPreMasterSecret: // client-side { // We can start adding data at base char* base = buf+*datalen; int base_buflen = *buflen-*datalen; /* Generate pre-master secret and send to server, encrypted with session_pub_key_ */ 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 ERR_GENERIC; } if (VERBOSITY >= V_DEBUG) { DBG("Pre-Master Secret:"); //print_bytes(pms, PRE_MASTER_SECRET_LENGTH); } int ciphertext_len; if ( (ciphertext_len = pub_encrypt(session_pub_key_, pms, PRE_MASTER_SECRET_LENGTH, base, base_buflen)) == -1 ) { ERROR("ERROR: Unable to encrypt session key"); return ERR_GENERIC; } *datalen += ciphertext_len; /* 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, en_, de_)) { ERROR("ERROR initializing AES ciphers"); return ERR_GENERIC; } free(pms); /* 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; } }