/** * Sends a CLIENT_KEY message if the server requested it. * Always sent right after a REGISTER. */ void send_client_key(struct group_list_t *group) { struct uftp_h *header; struct client_key_h *client_key; unsigned char *buf, *keyblob, *verify; uint8_t *verifydata; unsigned int siglen, meslen; int verifylen; uint16_t bloblen; buf = safe_calloc(MAXMTU, 1); header = (struct uftp_h *)buf; client_key = (struct client_key_h *)(buf + sizeof(struct uftp_h)); keyblob = (unsigned char *)client_key + sizeof(struct client_key_h); verifydata = build_verify_data(group, &verifylen); if (!verifydata) { glog0(group, "Error getting verify data"); send_abort(group, "Error getting verify data"); goto end; } set_uftp_header(header, CLIENT_KEY, group); client_key->func = CLIENT_KEY; if ((group->keyextype == KEYEX_RSA) || (group->keyextype == KEYEX_ECDH_RSA)) { if (!export_RSA_key(group->client_privkey.rsa, keyblob, &bloblen)) { glog0(group, "Error exporting public key"); send_abort(group, "Error exporting public key"); goto end; } verify = keyblob + bloblen; if (!create_RSA_sig(group->client_privkey.rsa, group->hashtype, verifydata, verifylen, verify, &siglen)) { glog0(group, "Error signing verify data"); send_abort(group, "Error signing verify data"); goto end; } } else { if (!export_EC_key(group->client_privkey.ec, keyblob, &bloblen)) { glog0(group, "Error exporting public key"); send_abort(group, "Error exporting public key"); goto end; } verify = keyblob + bloblen; if (!create_ECDSA_sig(group->client_privkey.ec, group->hashtype, verifydata, verifylen, verify, &siglen)) { glog0(group, "Error signing verify data"); send_abort(group, "Error signing verify data"); goto end; } } client_key->bloblen = htons(bloblen); client_key->siglen = htons(siglen); client_key->hlen = (sizeof(struct client_key_h) + bloblen + siglen) / 4; meslen = sizeof(struct uftp_h) + (client_key->hlen * 4); if (nb_sendto(listener, buf, meslen, 0, (struct sockaddr *)&(group->replyaddr), family_len(group->replyaddr)) == SOCKET_ERROR) { gsockerror(group, "Error sending CLIENT_KEY"); } else { glog2(group, "CLIENT_KEY sent"); } end: free(verifydata); free(buf); }
/** * Sends a PROXY_KEY message to the first listed public multicast address. */ void send_proxy_key() { unsigned char *packet, *keymod, *sig; struct uftp_h *header; struct proxy_key_h *proxykey; uint8_t modulus[PUBKEY_LEN]; uint32_t exponent, nonce; uint16_t modlen; unsigned int meslen, siglen; struct sockaddr_in pubaddr; packet = calloc(sizeof(struct uftp_h) + sizeof(struct hb_req_h) + (PUBKEY_LEN * 2) , 1); if (packet == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } header = (struct uftp_h *)packet; proxykey = (struct proxy_key_h *)(packet + sizeof(struct uftp_h)); keymod = (unsigned char *)proxykey + sizeof(struct proxy_key_h); header->uftp_id = UFTP_VER_NUM; header->func = PROXY_KEY; proxykey->func = PROXY_KEY; if (!export_RSA_key(privkey[0], &exponent, modulus, &modlen)) { log(0, 0, "Error exporting public key"); free(packet); return; } nonce = htonl(rand()); proxykey->nonce = nonce; proxykey->keyexp = htonl(exponent); memcpy(keymod, modulus, modlen); proxykey->keylen = htons(modlen); sig = keymod + modlen; if (!create_RSA_sig(privkey[0], HASH_SHA1, (unsigned char *)&nonce, sizeof(nonce), sig, &siglen) || siglen > modlen) { log(0, 0, "Error signing nonce"); free(packet); return; } proxykey->siglen = htons(siglen); meslen = sizeof(struct proxy_key_h) + modlen + siglen; header->blsize = htons(meslen); meslen += sizeof(struct uftp_h); memset(&pubaddr, 0, sizeof(pubaddr)); pubaddr.sin_family = AF_INET; pubaddr.sin_addr = pub_multi[0]; pubaddr.sin_port = htons(port); if (nb_sendto(listener, packet, meslen, 0, (struct sockaddr *)&pubaddr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { sockerror(0, 0, "Error sending PROXY_KEY"); } else { log(0, 0, "Sent PROXY_KEY to %s", inet_ntoa(pubaddr.sin_addr)); } free(packet); }
/** * Sends a PROXY_KEY message to the first listed public multicast address. */ void send_proxy_key() { unsigned char *packet, *keyblob, *dhblob, *sig; struct uftp_h *header; struct proxy_key_h *proxykey; uint32_t nonce; unsigned int meslen, siglen; uint16_t bloblen, dhlen; char pubname[INET6_ADDRSTRLEN]; int rval; packet = safe_calloc(sizeof(struct uftp_h) + sizeof(struct hb_req_h) + (PUBKEY_LEN * 3) , 1); header = (struct uftp_h *)packet; proxykey = (struct proxy_key_h *)(packet + sizeof(struct uftp_h)); keyblob = (unsigned char *)proxykey + sizeof(struct proxy_key_h); header->version = UFTP_VER_NUM; header->func = PROXY_KEY; header->src_id = uid; proxykey->func = PROXY_KEY; nonce = htonl(rand32()); proxykey->nonce = nonce; if (privkey_type[0] == KEYBLOB_RSA) { if (!export_RSA_key(privkey[0].rsa, keyblob, &bloblen)) { log0(0, 0, 0, "Error exporting public key"); free(packet); return; } } else { if (!export_EC_key(privkey[0].ec, keyblob, &bloblen)) { log0(0, 0, 0, "Error exporting public key"); free(packet); return; } } dhblob = keyblob + bloblen; if (dhkey.key) { if (!export_EC_key(dhkey.ec, dhblob, &dhlen)) { log0(0, 0, 0, "Error exporting public key"); free(packet); return; } } else { dhlen = 0; } sig = dhblob + dhlen; if (privkey_type[0] == KEYBLOB_RSA) { if (!create_RSA_sig(privkey[0].rsa, HASH_SHA1, (unsigned char *)&nonce, sizeof(nonce), sig, &siglen)) { log0(0, 0, 0, "Error signing nonce"); free(packet); return; } } else { if (!create_ECDSA_sig(privkey[0].ec, HASH_SHA1, (unsigned char *)&nonce, sizeof(nonce), sig, &siglen)) { log0(0, 0, 0, "Error signing nonce"); free(packet); return; } } proxykey->bloblen = htons(bloblen); proxykey->dhlen = htons(dhlen); proxykey->siglen = htons(siglen); proxykey->hlen = (sizeof(struct proxy_key_h) + bloblen + dhlen + siglen)/4; meslen = sizeof(struct uftp_h) + (proxykey->hlen * 4); if (nb_sendto(listener, packet, meslen, 0, (struct sockaddr *)&pub_multi[0], family_len(pub_multi[0])) == SOCKET_ERROR) { sockerror(0, 0, 0, "Error sending PROXY_KEY"); } else { if ((rval = getnameinfo((struct sockaddr *)&pub_multi[0], family_len(pub_multi[0]), pubname, sizeof(pubname), NULL, 0, NI_NUMERICHOST)) != 0) { log1(0, 0, 0, "getnameinfo failed: %s", gai_strerror(rval)); } log2(0, 0, 0, "Sent PROXY_KEY to %s", pubname); } free(packet); }
/** * Forward a message unmodified to the next hop, resigning if necessary. */ void forward_message(int listidx, const struct sockaddr_in *src, const unsigned char *packet) { struct uftp_h *header; struct encrypted_h *encrypted; struct sockaddr_in dest; unsigned int meslen, siglen; int hostidx; uint8_t *sig, *sigcopy; RSA_key_t key; header = (struct uftp_h *)packet; meslen = sizeof(struct uftp_h) + ntohs(header->blsize); memset(&dest, 0, sizeof(dest)); if (!memcmp(src, &group_list[listidx].up_addr, sizeof(*src))) { if (proxy_type == RESPONSE_PROXY) { // Response proxy, no downstream fowarding set_timeout(listidx, 0); return; } else if (proxy_type == SERVER_PROXY) { dest = down_addr; } else { dest.sin_family = AF_INET; dest.sin_addr.s_addr = header->destaddr; dest.sin_port = htons(out_port); key = group_list[listidx].serverkey; } } else { dest = group_list[listidx].up_addr; if (proxy_type != SERVER_PROXY) { hostidx = find_client(listidx, header->srcaddr); if (hostidx == -1) { log(group_list[listidx].group_id, 0, "Couldn't find receiver in list"); return; } key = group_list[listidx].destinfo[hostidx].pubkey; } } // If we're using RSA signatures, verify the signature and resign if ((proxy_type != SERVER_PROXY) && (header->func == ENCRYPTED) && (group_list[listidx].sigtype == SIG_RSA)) { encrypted = (struct encrypted_h *)(packet + sizeof(struct uftp_h)); sig = (uint8_t *)encrypted + sizeof(struct encrypted_h); siglen = ntohs(encrypted->sig_len); sigcopy = calloc(siglen, 1); if (sigcopy == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } memcpy(sigcopy, sig, siglen); memset(sig, 0, siglen); if (!verify_RSA_sig(key, group_list[listidx].hashtype, packet, meslen, sigcopy, siglen)) { log(group_list[listidx].group_id, 0, "Signature verification failed"); free(sigcopy); return; } if (!create_RSA_sig(group_list[listidx].proxykey, group_list[listidx].hashtype, packet, meslen, sigcopy, &siglen)) { log(group_list[listidx].group_id, 0, "Signature creation failed"); free(sigcopy); return; } memcpy(sig, sigcopy, siglen); free(sigcopy); } if (nb_sendto(listener, packet, meslen, 0, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { sockerror(group_list[listidx].group_id, 0, "Error forwarding message"); log(group_list[listidx].group_id, 0, "Dest: %s:%d", inet_ntoa(dest.sin_addr), ntohs(dest.sin_port)); } set_timeout(listidx, 0); }
/** * Forward a message unmodified to the next hop, resigning if necessary. */ void forward_message(struct pr_group_list_t *group, const union sockaddr_u *src, unsigned char *packet, int packetlen) { struct uftp_h *header; struct encrypted_h *encrypted; struct announce_h *announce; struct enc_info_he *encinfo; union sockaddr_u dest; unsigned int meslen, siglen; int hostidx, rval, iplen, resign; char destname[INET6_ADDRSTRLEN], destport[PORTNAME_LEN]; uint8_t *sig, *sigcopy; union key_t key; header = (struct uftp_h *)packet; meslen = (unsigned int)packetlen; memset(&dest, 0, sizeof(dest)); if (!memcmp(src, &group->up_addr, sizeof(*src))) { if (proxy_type == RESPONSE_PROXY) { // Response proxy, no downstream forwarding set_timeout(group, 0, 0); return; } else if (proxy_type == SERVER_PROXY) { dest = down_addr; } else { if (header->func == ANNOUNCE) { dest = group->publicmcast; } else { dest = group->privatemcast; } key = group->server_pubkey; } } else { dest = group->up_addr; if (proxy_type != SERVER_PROXY) { hostidx = find_client(group, header->src_id); if (hostidx == -1) { glog1(group, "Couldn't find receiver in list"); return; } key = group->destinfo[hostidx].pubkey; } } // If we're using KEYEX signatures, or sending an ANNOUNCE with ECDH, // verify the signature and resign resign = 0; if ((proxy_type != SERVER_PROXY) && (header->func == ENCRYPTED) && (group->sigtype == SIG_KEYEX)) { encrypted = (struct encrypted_h *)(packet + sizeof(struct uftp_h)); sig = (uint8_t *)encrypted + sizeof(struct encrypted_h); siglen = ntohs(encrypted->sig_len); resign = 1; } else if ((proxy_type != SERVER_PROXY) && (header->func == ANNOUNCE) && ((group->keyextype == KEYEX_ECDH_RSA) || (group->keyextype == KEYEX_ECDH_ECDSA))) { announce = (struct announce_h *)(packet + sizeof(struct uftp_h)); iplen = ((announce->flags & FLAG_IPV6) != 0) ? 16 : 4; encinfo = (struct enc_info_he *) ((uint8_t *)announce + sizeof(struct announce_h) + iplen + iplen); sig = (uint8_t *)encinfo + sizeof(struct enc_info_he) + ntohs(encinfo->keylen) + ntohs(encinfo->dhlen); siglen = ntohs(encinfo->siglen); resign = 1; } if (resign) { sigcopy = safe_calloc(siglen, 1); memcpy(sigcopy, sig, siglen); memset(sig, 0, siglen); if ((group->keyextype == KEYEX_RSA) || (group->keyextype == KEYEX_ECDH_RSA)) { if (header->func == ENCRYPTED) { if (!verify_RSA_sig(key.rsa, group->hashtype, packet, meslen, sigcopy, siglen)) { glog1(group, "Signature verification failed"); free(sigcopy); return; } } if (!create_RSA_sig(group->proxy_privkey.rsa, group->hashtype, packet, meslen, sigcopy, &siglen)) { glog0(group, "Signature creation failed"); free(sigcopy); return; } } else { if (header->func == ENCRYPTED) { if (!verify_ECDSA_sig(key.ec, group->hashtype, packet, meslen, sigcopy, siglen)) { glog1(group, "Signature verification failed"); free(sigcopy); return; } } if (!create_ECDSA_sig(group->proxy_privkey.ec, group->hashtype, packet, meslen, sigcopy, &siglen)) { glog0(group, "Signature creation failed"); free(sigcopy); return; } } memcpy(sig, sigcopy, siglen); free(sigcopy); } if (nb_sendto(listener, packet, meslen, 0, (struct sockaddr *)&dest, family_len(dest)) == SOCKET_ERROR) { gsockerror(group, "Error forwarding message"); if ((rval = getnameinfo((struct sockaddr *)&dest, family_len(dest), destname, sizeof(destname), destport, sizeof(destport), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { glog1(group, "getnameinfo failed: %s", gai_strerror(rval)); } glog2(group, "Dest: %s:%s", destname, destport); } set_timeout(group, 0, 0); }