Example #1
0
/**
 * Sets the fields in a EXT_ENC_INFO extension for transmission.
 * Returns the number of bytes set, or 0 on error.
 */
int set_enc_info(const struct finfo_t *finfo, struct enc_info_he *encinfo)
{
    unsigned char *keyblob;
    uint16_t bloblen;
    int extlen;

    keyblob = ((uint8_t *)encinfo + sizeof(struct enc_info_he));

    encinfo->exttype = EXT_ENC_INFO;
    encinfo->keyextype_sigtype = (keyextype & 0x0F) << 4;
    encinfo->keyextype_sigtype |= (sigtype & 0x0F);
    encinfo->keytype = keytype;
    encinfo->hashtype = hashtype;
    if (client_auth) {
        encinfo->flags |= FLAG_CLIENT_AUTH;
    }
    memcpy(encinfo->rand1, rand1, sizeof(rand1));
    if ((keyextype == KEYEX_RSA) || (keyextype == KEYEX_ECDH_RSA)) {
        if (!export_RSA_key(privkey.rsa, keyblob, &bloblen)) {
            glog0(finfo, "Error exporting server public key");
            return 0;
        }
    } else {
        if (!export_EC_key(privkey.ec, keyblob, &bloblen)) {
            glog0(finfo, "Error exporting server public key");
            return 0;
        }
    }
    encinfo->keylen = htons(bloblen);
    if ((keyextype == KEYEX_ECDH_RSA) || (keyextype == KEYEX_ECDH_ECDSA)) {
        uint16_t dhlen;
        uint8_t *dhblob = ((uint8_t *)encinfo + sizeof(struct enc_info_he) +
                          ntohs(encinfo->keylen));

        if (!export_EC_key(dhkey.ec, dhblob, &dhlen)) {
            glog0(finfo, "Error exporting server ECDH public key");
            return 0;
        }
        encinfo->dhlen = htons(dhlen);
        if (keyextype == KEYEX_ECDH_RSA) {
            encinfo->siglen = htons(RSA_keylen(privkey.rsa)); 
        } else {
            encinfo->siglen = htons(ECDSA_siglen(privkey.ec)); 
        }
    } else {
        encinfo->dhlen = 0;
        encinfo->siglen = 0;
    }
    
    extlen = sizeof(struct enc_info_he) + ntohs(encinfo->keylen) +
            ntohs(encinfo->dhlen) + ntohs(encinfo->siglen);
    encinfo->extlen = extlen / 4;
    return extlen;
}
Example #2
0
/**
 * Returns the verify_data string used in certain messages.  This value
 * is then run through the PRF with the result going into the message.
 */
uint8_t *build_verify_data(struct group_list_t *group, int *verifylen)
{
    uint8_t *verifydata;
    uint32_t group_id;
    int iplen;

    iplen = (group->multi.ss.ss_family == AF_INET6) ?
            sizeof(struct in6_addr) : sizeof(struct in_addr);
    *verifylen = 0;
    if (group->phase == PHASE_REGISTERED) {
        verifydata = safe_calloc(sizeof(group->group_id) +
                iplen + sizeof(group->rand1) +
                sizeof(group->rand2) + sizeof(group->premaster), 1);
    } else {
        verifydata = safe_calloc(sizeof(group->group_id) +
                iplen + sizeof(group->rand1) +
                sizeof(group->rand2) + sizeof(group->premaster) +
                PUBKEY_LEN + sizeof(group->groupmaster), 1);
    }

    group_id = htonl(group->group_id);
    memcpy(verifydata, &group_id, sizeof(group_id));
    *verifylen += sizeof(group_id);
    if (group->multi.ss.ss_family == AF_INET6) {
        memcpy(verifydata + *verifylen, &group->multi.sin6.sin6_addr.s6_addr,
                iplen);
    } else {
        memcpy(verifydata + *verifylen, &group->multi.sin.sin_addr.s_addr,
                iplen);
    }
    *verifylen += iplen;
    memcpy(verifydata + *verifylen, group->rand1, sizeof(group->rand1));
    *verifylen += sizeof(group->rand1);
    memcpy(verifydata + *verifylen, group->rand2, sizeof(group->rand2));
    *verifylen += sizeof(group->rand2);
    memcpy(verifydata + *verifylen, group->premaster, group->premaster_len);
    *verifylen += group->premaster_len;

    if (group->phase != PHASE_REGISTERED) {
        if (group->client_auth) {
            uint16_t bloblen;
            uint8_t *keyblob = verifydata + *verifylen;

            if ((group->keyextype == KEYEX_RSA) ||
                    (group->keyextype == KEYEX_ECDH_RSA)) {
                if (!export_RSA_key(group->client_privkey.rsa,
                                    keyblob, &bloblen)) {
                    free(verifydata);
                    return NULL;
                }
            } else {
                if (!export_EC_key(group->client_privkey.ec,
                                   keyblob, &bloblen)) {
                    free(verifydata);
                    return NULL;
                }
            }
            *verifylen += bloblen;
        }
        memcpy(verifydata + *verifylen, group->groupmaster,
                sizeof(group->groupmaster));
        *verifylen += sizeof(group->groupmaster);
    }

    return verifydata;
}
Example #3
0
/**
 * Sends a REGISTER message in response to an ANNOUNCE or on timeout when
 * waiting for a KEYINFO or REG_CONF.  If the register timeout expired, abort.
 */
void send_register(struct group_list_t *group)
{
    struct uftp_h *header;
    struct register_h *reg;
    unsigned char *buf, *keydata;
    struct timeval now, send_time;
    unsigned int len, meslen;
    union key_t key;

    gettimeofday(&now, NULL);
    if (cmptimestamp(now, group->expire_time) >= 0) {
        glog1(group, "Registration unconfirmed by server");
        send_abort(group, "Registration unconfirmed");
        return;
    }

    buf = safe_calloc(MAXMTU, 1);

    header = (struct uftp_h *)buf;
    reg = (struct register_h *)(buf + sizeof(struct uftp_h));
    keydata = (unsigned char *)reg + sizeof(struct register_h);
    set_uftp_header(header, REGISTER, group);
    reg->func = REGISTER;
    if (group->keytype != KEY_NONE) {
        memcpy(reg->rand2, group->rand2, RAND_LEN);
        if (group->keyextype == KEYEX_RSA) {
            if (has_proxy) {
                key = proxy_pubkey;
            } else {
                key = group->server_pubkey;
            }
            if (!RSA_encrypt(key.rsa, group->premaster, group->premaster_len,
                             keydata, &len)) {
                glog0(group, "Error encrypting premaster secret");
                send_abort(group, "Error encrypting premaster secret");
                free(buf);
                return;
            }
        } else {
            uint16_t keylen;
            if (!export_EC_key(group->client_dhkey.ec, keydata, &keylen)) {
                glog0(group, "Error exporting ECDH public key");
                send_abort(group, "Error exporting ECDH public key");
                free(buf);
                return;
            }
            len = keylen;
        }
        reg->keyinfo_len = htons(len); 
    } else {
        len = 0;
    }
    gettimeofday(&now, NULL);
    if (cmptimestamp(now, group->last_server_rx_ts) <= 0) {
        send_time = group->last_server_ts;
    } else {
        send_time = add_timeval(group->last_server_ts,
                diff_timeval(now, group->last_server_rx_ts));
    }
    reg->tstamp_sec = htonl((uint32_t)send_time.tv_sec);
    reg->tstamp_usec = htonl((uint32_t)send_time.tv_usec);
    reg->hlen = (sizeof(struct register_h) + len) / 4;
    meslen = sizeof(struct uftp_h) + (reg->hlen * 4);

    if (nb_sendto(listener, buf, meslen, 0,
               (struct sockaddr *)&(group->replyaddr),
               family_len(group->replyaddr)) == SOCKET_ERROR) {
        gsockerror(group, "Error sending REGISTER");
    } else {
        glog2(group, "REGISTER sent");
    }
    glog3(group, "send time: %d.%06d", send_time.tv_sec, send_time.tv_usec);

    set_timeout(group, 0);
    if (group->client_auth) {
        send_client_key(group);
    }
    free(buf);
}
Example #4
0
/**
 * 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);
}
Example #5
0
/**
 * 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);
}
Example #6
0
/**
 * Returns the verify_data string used in certain messages.  This value
 * is then run through the PRF with the result going into the message.
 */
uint8_t *build_verify_data(struct pr_group_list_t *group, int hostidx,
                           int *verifylen, int full)
{
    uint8_t *verifydata, *keyblob;
    uint32_t group_id;
    struct pr_destinfo_t *dest;
    union key_t key;
    int iplen;
    uint16_t bloblen;

    iplen = (group->privatemcast.ss.ss_family == AF_INET6) ?
            sizeof(struct in6_addr) : sizeof(struct in_addr);
    if (hostidx != -1) {
        dest = &group->destinfo[hostidx];
    }
    *verifylen = 0;
    if (!full) {
        verifydata = safe_calloc(sizeof(group->group_id) +
                iplen + sizeof(group->rand1) +
                sizeof(group->rand2) + sizeof(group->premaster), 1);
    } else {
        verifydata = safe_calloc(sizeof(group->group_id) +
                iplen + sizeof(group->rand1) +
                sizeof(group->rand2) + sizeof(group->premaster) +
                PUBKEY_LEN + sizeof(group->groupmaster), 1);
    }

    group_id = htonl(group->group_id);
    memcpy(verifydata, &group_id, sizeof(group_id));
    *verifylen += sizeof(group_id);
    if (group->privatemcast.ss.ss_family == AF_INET6) {
        memcpy(verifydata + *verifylen,
                &group->privatemcast.sin6.sin6_addr.s6_addr, iplen);
    } else {
        memcpy(verifydata + *verifylen,
                &group->privatemcast.sin.sin_addr.s_addr, iplen);
    }
    *verifylen += iplen;
    memcpy(verifydata + *verifylen, group->rand1, sizeof(group->rand1));
    *verifylen += sizeof(group->rand1);
    if (hostidx == -1) {
        memcpy(verifydata + *verifylen, group->rand2, sizeof(group->rand2));
        *verifylen += sizeof(group->rand2);
        memcpy(verifydata + *verifylen, group->premaster, group->premaster_len);
        *verifylen += group->premaster_len;
    } else {
        memcpy(verifydata + *verifylen, dest->rand2, sizeof(dest->rand2));
        *verifylen += sizeof(dest->rand2);
        memcpy(verifydata + *verifylen, dest->premaster, dest->premaster_len);
        *verifylen += dest->premaster_len;
    }

    if (full) {
        if (group->client_auth) {
            if (hostidx == -1) {
                key = group->proxy_privkey;
            } else {
                key = dest->pubkey;
            }
            keyblob = verifydata + *verifylen;
            if ((group->keyextype == KEYEX_RSA) ||
                    (group->keyextype == KEYEX_ECDH_RSA)) {
                if (!export_RSA_key(key.rsa, keyblob, &bloblen)) {
                    free(verifydata);
                    return NULL;
                }
            } else {
                if (!export_EC_key(key.ec, keyblob, &bloblen)) {
                    free(verifydata);
                    return NULL;
                }
            }
            *verifylen += bloblen;
        }
        memcpy(verifydata + *verifylen, group->groupmaster,
                sizeof(group->groupmaster));
        *verifylen += sizeof(group->groupmaster);
    }

    return verifydata;
}