コード例 #1
0
ファイル: client_announce.c プロジェクト: PumpkinSpace/uftp
/**
 * Process an incoming KEYINFO message.
 * Expected in response to a REGISTER when encryption is enabled.
 */
void handle_keyinfo(struct group_list_t *group, unsigned char *message,
                    unsigned meslen, uint32_t src_id)
{
    struct keyinfo_h *keyinfo_hdr;
    struct destkey *keylist;
    int i, keyidx, len, destkeycnt, unauth_keytype, unauth_keylen, unauth_ivlen;
    unsigned explen, declen;
    uint8_t decgroupmaster[MASTER_LEN], *prf_buf, *iv;
    uint64_t ivctr;

    keyinfo_hdr = (struct keyinfo_h *)message;
    keylist = (struct destkey *)(message + (keyinfo_hdr->hlen * 4));

    if ((meslen < (keyinfo_hdr->hlen * 4U)) ||
            ((keyinfo_hdr->hlen * 4U) < sizeof(struct keyinfo_h))) {
        glog1(group, "Rejecting KEYINFO from server: invalid message size");
        return;
    }

    destkeycnt = (meslen - (keyinfo_hdr->hlen * 4)) / sizeof(struct destkey);
    // This duplicates uid_in_list, but here it's addressed in a struct array
    for (i = 0, keyidx = -1; (i < destkeycnt) && (keyidx == -1); i++) {
        if (uid == keylist[i].dest_id) {
            keyidx = i;
        }
    }

    // Don't use a cipher in an authentication mode to decrypt the group master
    unauth_keytype = unauth_key(group->keytype);
    get_key_info(unauth_keytype, &unauth_keylen, &unauth_ivlen);
    if (keyidx != -1) {
        glog2(group, "Received KEYINFO");
        if (group->phase == PHASE_MIDGROUP) {
            // We already got the KEYINFO, so no need to reprocess.
            // Just resend the KEYINFO_ACK and reset the timeout
            send_keyinfo_ack(group);
            set_timeout(group, 0);
            return;
        }

        iv = safe_calloc(unauth_ivlen, 1);
        ivctr = ntohl(keyinfo_hdr->iv_ctr_lo);
        ivctr |= (uint64_t)ntohl(keyinfo_hdr->iv_ctr_hi) << 32;
        build_iv(iv, group->salt, unauth_ivlen, uftp_htonll(ivctr), src_id);
        if (!decrypt_block(unauth_keytype, iv, group->key, NULL, 0,
                    keylist[keyidx].groupmaster, MASTER_LEN,
                    decgroupmaster, &declen) ||
                (declen != MASTER_LEN - 1)) {
            glog1(group, "Decrypt failed for group master");
            send_abort(group, "Decrypt failed for group master");
            free(iv);
            return;
        }
        free(iv);
        group->groupmaster[0] = group->version;
        memcpy(&group->groupmaster[1], decgroupmaster, declen);

        explen = group->keylen + SALT_LEN + group->hmaclen;
        prf_buf = safe_calloc(explen + group->hmaclen, 1);
        PRF(group->hashtype, explen, group->groupmaster,
                sizeof(group->groupmaster), "key expansion",
                group->rand1, sizeof(group->rand1), prf_buf, &len);
        memcpy(group->grouphmackey, prf_buf, group->hmaclen);
        memcpy(group->groupkey, prf_buf + group->hmaclen, group->keylen);
        memcpy(group->groupsalt, prf_buf + group->hmaclen + group->keylen,
                SALT_LEN);

        free(prf_buf);
        group->phase = PHASE_MIDGROUP;
        send_keyinfo_ack(group);
        set_timeout(group, 0);

        if (group->restart) {
            read_restart_file(group);
        }
    }
}
コード例 #2
0
ファイル: server_announce.c プロジェクト: No9/uftp
/**
 * Send a KEYINFO message.  Sent during the Announce phase for a group
 * with encryption enabled.
 * Returns 1 on success, 0 on fail.
 */
int send_keyinfo(const struct finfo_t *finfo, int attempt)
{
    unsigned char *buf, *iv;
    struct uftp_h *header;
    struct keyinfo_h *keyinfo;
    struct destkey *keylist;
    unsigned int hsize, payloadlen, len;
    int maxdest, packetcnt, dests, iv_init, i;
    int unauth_keytype, unauth_keylen, unauth_ivlen;

    // Don't use a cipher in an authentication mode to encrypt the group master
    unauth_keytype = unauth_key(keytype);
    get_key_info(unauth_keytype, &unauth_keylen, &unauth_ivlen);

    buf = safe_calloc(MAXMTU, 1);
    iv = safe_calloc(unauth_ivlen, 1);
    header = (struct uftp_h *)buf;
    keyinfo = (struct keyinfo_h *)(buf + sizeof(struct uftp_h));
    keylist = (struct destkey *)((char *)keyinfo + sizeof(struct keyinfo_h));

    set_uftp_header(header, KEYINFO, finfo->group_id, finfo->group_inst,
                    grtt, destcount);
    keyinfo->func = KEYINFO;
    keyinfo->hlen = sizeof(struct keyinfo_h) / 4;
    keylist = (struct destkey *)((uint8_t *)keyinfo + (keyinfo->hlen * 4));

    iv_init = 0;
    hsize = sizeof(struct keyinfo_h);
    maxdest = blocksize / sizeof(struct destkey);
    packetcnt = 1;
    for (i = 0, dests = 0; i < destcount; i++) {
        if (destlist[i].status == DEST_REGISTERED) {
            if (!iv_init) {
                ivctr++;
                keyinfo->iv_ctr_hi =htonl((ivctr & 0xFFFFFFFF00000000LL) >> 32);
                keyinfo->iv_ctr_lo = htonl(ivctr & 0x00000000FFFFFFFFLL);
                iv_init = 1;
            }
            keylist[dests].dest_id = destlist[i].id;
            build_iv(iv, destlist[i].encinfo->salt, unauth_ivlen,
                     uftp_htonll(ivctr), header->src_id);
            if (!encrypt_block(unauth_keytype, iv,destlist[i].encinfo->key,
                               NULL,0, &groupmaster[1], sizeof(groupmaster) - 1,
                               keylist[dests].groupmaster, &len)) {
                glog0(finfo, "Error encrypting KEYINFO for %s",
                             destlist[i].name);
                free(buf);
                free(iv);
                return 0;
            }
            dests++;
        }
        if ((dests >= maxdest) || ((i == destcount - 1) && (dests > 0))) {
            header->seq = htons(send_seq++);
            payloadlen = hsize + (dests * sizeof(struct destkey));
            glog2(finfo, "Sending KEYINFO %d.%d", attempt, packetcnt);
            if (nb_sendto(sock, buf, payloadlen + sizeof(struct uftp_h), 0,
                          (struct sockaddr *)&receive_dest,
                          family_len(receive_dest)) == SOCKET_ERROR) {
                gsockerror(finfo, "Error sending KEYINFO");
                sleep(1);
                free(buf);
                free(iv);
                return 0;
            }
            if (packet_wait) usleep(packet_wait);
            memset(keylist, 0, maxdest * sizeof(struct destkey));
            iv_init = 0;
            dests = 0;
            packetcnt++;
        }
    }
コード例 #3
0
ファイル: proxy_downstream.c プロジェクト: PumpkinSpace/uftp
/**
 * Sends a KEYINFO to each client that the server sent a REG_CONF for.
 */
void send_keyinfo(struct pr_group_list_t *group, const uint32_t *addrlist,
                  int addrlen)
{
    unsigned char *buf, *iv;
    struct uftp_h *header;
    struct keyinfo_h *keyinfo_hdr;
    struct destkey *keylist;
    unsigned int payloadlen, len;
    int maxdest, packetcnt, dests, iv_init, foundaddr, i, j;
    int unauth_keytype, unauth_keylen, unauth_ivlen;
    struct pr_destinfo_t *dest;

    // Don't use a cipher in an authentication mode to encrypt the group master
    unauth_keytype = unauth_key(group->keytype);
    get_key_info(unauth_keytype, &unauth_keylen, &unauth_ivlen);

    buf = safe_calloc(MAXMTU, 1);
    iv = safe_calloc(unauth_ivlen, 1);
    header = (struct uftp_h *)buf;
    keyinfo_hdr = (struct keyinfo_h *)(buf + sizeof(struct uftp_h));
    keylist= (struct destkey *)((char *)keyinfo_hdr + sizeof(struct keyinfo_h));

    set_uftp_header(header, KEYINFO, group);
    keyinfo_hdr->func = KEYINFO;
    keyinfo_hdr->hlen = sizeof(struct keyinfo_h) / 4;

    iv_init = 0;
    maxdest = max_msg_dest(group, KEYINFO, keyinfo_hdr->hlen * 4);
    packetcnt = 1;
    for (i = 0, dests = 0; i < group->destcount; i++) {
        dest = &group->destinfo[i];
        if (dest->state == PR_CLIENT_CONF) {
            if (addrlist) {
                // We just got a REG_CONF, so only send to listed hosts
                for (j = 0, foundaddr = 0; (j < addrlen) && (!foundaddr); j++) {
                    if (dest->id == addrlist[j]) {
                        foundaddr = 1;
                    }
                }
            } else {
                foundaddr = 1;
            }
            if (foundaddr) {
                if (!iv_init) {
                    group->ivctr++;
                    keyinfo_hdr->iv_ctr_hi =
                            htonl((group->ivctr & 0xFFFFFFFF00000000LL) >> 32);
                    keyinfo_hdr->iv_ctr_lo =
                            htonl(group->ivctr & 0x00000000FFFFFFFFLL);
                    iv_init = 1;
                }
                keylist[dests].dest_id = dest->id;
                build_iv(iv, dest->salt, unauth_ivlen,
                         uftp_htonll(group->ivctr), group->src_id);
                if (!encrypt_block(unauth_keytype, iv, dest->key,
                                   NULL, 0, &group->groupmaster[1],
                                   sizeof(group->groupmaster) - 1,
                                   keylist[dests].groupmaster, &len)) {
                    glog0(group, "Error encrypting KEYINFO for %s", dest->name);
                    free(buf);
                    free(iv);
                    return;
                }
                dests++;
            }
        }
        if ((dests >= maxdest) ||
                ((i == group->destcount - 1) && (dests > 0))) {
            payloadlen = sizeof(struct keyinfo_h) +
                         (dests * sizeof(struct destkey));
            glog2(group,"Sending KEYINFO %d.%d", group->keyinfo_cnt, packetcnt);
            if (nb_sendto(listener, buf, payloadlen + sizeof(struct uftp_h), 0,
                       (struct sockaddr *)&group->privatemcast,
                        family_len(group->privatemcast)) == SOCKET_ERROR) {
                gsockerror(group, "Error sending KEYINFO");
                free(buf);
                free(iv);
                return;
            }
            // TODO: This value is good for around 100Mbps.  This is under the
            // assumption that the client proxy is local to the clients
            // it serves.  This should probably be a parameter.
            usleep(120);
            memset(keylist, 0, maxdest * sizeof(struct destkey));
            iv_init = 0;
            dests = 0;
            packetcnt++;
        }
    }