Ejemplo n.º 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;
}
Ejemplo n.º 2
0
/**
 * Initialize crypto library, generate keys
 */
void key_init(void)
{
    unsigned char *prf_buf;
    time_t t;
    uint32_t t2;
    int explen, len;

    if (keytype == KEY_NONE) {
        return;
    }

    set_sys_keys(sys_keys);
    get_key_info(keytype, &keylen, &ivlen);
    hmaclen = get_hash_len(hashtype);

    memset(groupkey, 0, sizeof(groupkey));
    memset(groupsalt, 0, sizeof(groupsalt));
    memset(grouphmackey, 0, sizeof(grouphmackey));

    if (!get_random_bytes(groupmaster, sizeof(groupmaster))) {
        log0(0, 0, 0, "Failed to generate group master");
        exit(ERR_CRYPTO);
    }
    groupmaster[0] = UFTP_VER_NUM;
    if (!get_random_bytes(rand1, sizeof(rand1))) {
        log0(0, 0, 0, "Failed to generate rand1");
        exit(ERR_CRYPTO);
    }
    // Sets the first 4 bytes of rand1 to the current time
    t = time(NULL);
    t2 = (uint32_t)(t & 0xFFFFFFFF);
    *(uint32_t *)rand1 = t2;

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

    if ((keyextype == KEYEX_RSA) || (keyextype == KEYEX_ECDH_RSA)) {
        if ((!strcmp(keyfile, "")) || (newkeylen != 0)) {
            privkey.rsa = gen_RSA_key(newkeylen, RSA_EXP, keyfile);
        } else {
            privkey.rsa = read_RSA_key(keyfile);
        }
        if (!privkey.key) {
            log0(0, 0, 0, "Failed to read/generate private key");
            exit(ERR_CRYPTO);
        }
        privkeylen = RSA_keylen(privkey.rsa);
    } else {
        if ((!strcmp(keyfile, "")) || (ecdsa_curve != 0)) {
            privkey.ec = gen_EC_key(ecdsa_curve, 0, keyfile);
        } else {
            privkey.ec = read_EC_key(keyfile);
        }
        if (!privkey.key) {
            log0(0, 0, 0, "Failed to read/generate private key");
            exit(ERR_CRYPTO);
        }
        privkeylen = ECDSA_siglen(privkey.ec);
    }
    if ((keyextype == KEYEX_ECDH_RSA) || (keyextype == KEYEX_ECDH_ECDSA)) {
        dhkey.ec = gen_EC_key(ecdh_curve, 1, NULL);
        if (!dhkey.key) {
            log0(0, 0, 0, "Failed to generate DH key");
            exit(ERR_CRYPTO);
        }
    }
}
Ejemplo n.º 3
0
/**
 * Read encryption related fields from an ANNOUNCE
 */
int read_announce_encryption(struct group_list_t *group,
                             struct enc_info_he *encinfo,
                             const unsigned char *packet, int packetlen)
{
    int keyextype, sigtype, keytype, i;
    unsigned char *keys;

    keys = (unsigned char *)encinfo + sizeof(struct enc_info_he);
    // Sanity check the selected encryption parameters
    if (!cipher_supported(encinfo->keytype)) {
        glog1(group, "Keytype invalid or not supported here");
        send_abort(group, "Keytype invalid or not supported here");
        return 0;
    }
    if (!hash_supported(encinfo->hashtype)) {
        glog1(group, "Hashtype invalid or not supported here");
        send_abort(group, "Hashtype invalid or not supported here");
        return 0;
    }
    keyextype = (encinfo->keyextype_sigtype & 0xF0) >> 4;
    sigtype = encinfo->keyextype_sigtype & 0x0F;
    if (((sigtype != SIG_HMAC) && (sigtype != SIG_KEYEX) &&
                (sigtype != SIG_AUTHENC)) ||
            ((sigtype == SIG_AUTHENC) && (!is_auth_enc(encinfo->keytype)))) {
        glog1(group, "Invalid sigtype specified");
        send_abort(group, "Invalid sigtype specified");
        return 0;
    } 
    if ((keyextype != KEYEX_RSA) && (keyextype != KEYEX_ECDH_RSA) &&
            (keyextype != KEYEX_ECDH_ECDSA)) {
        glog1(group, "Invalid keyextype specified");
        send_abort(group, "Invalid keyextype specified");
        return 0;
    }
    group->keyextype = keyextype;
    group->keytype = encinfo->keytype;
    group->hashtype = encinfo->hashtype;
    group->sigtype = sigtype;
    group->client_auth = ((encinfo->flags & FLAG_CLIENT_AUTH) != 0);

    if (!verify_server_fingerprint(keys, ntohs(encinfo->keylen), group)) {
        glog1(group, "Failed to verify server key fingerprint");
        send_abort(group, "Failed to verify server key fingerprint");
        return 0;
    }

    if ((group->keyextype == KEYEX_RSA) ||
            (group->keyextype == KEYEX_ECDH_RSA)) {
        keytype = KEYBLOB_RSA;
    } else {
        keytype = KEYBLOB_EC;
    }
    // Load server key and select a matching client key
    if (keytype == KEYBLOB_RSA) {
        if (!import_RSA_key(&group->server_pubkey.rsa, keys,
                            ntohs(encinfo->keylen))) {
            glog0(group, "Failed to load server public key");
            send_abort(group, "Failed to load server public key");
            return 0;
        }
        group->server_pubkeylen = RSA_keylen(group->server_pubkey.rsa);
        for (i = 0; i < key_count; i++) {
            if ((privkey_type[i] == KEYBLOB_RSA) &&
                    (group->server_pubkeylen == RSA_keylen(privkey[i].rsa))) {
                group->client_privkey = privkey[i];
                group->client_privkeylen = RSA_keylen(privkey[i].rsa);
                break;
            }
        }
    } else {
        if (!import_EC_key(&group->server_pubkey.ec, keys,
                           ntohs(encinfo->keylen), 0)) {
            glog0(group, "Failed to load server public key");
            send_abort(group, "Failed to load server public key");
            return 0;
        }
        group->server_pubkeylen = ECDSA_siglen(group->server_pubkey.ec);
        for (i = 0; i < key_count; i++) {
            if ((privkey_type[i] == KEYBLOB_EC) &&
                    (get_EC_curve(group->server_pubkey.ec) ==
                        get_EC_curve(privkey[i].ec))) {
                group->client_privkey = privkey[i];
                group->client_privkeylen = ECDSA_siglen(privkey[i].ec);
                break;
            }
        }
    }
    if (!group->client_privkey.key) {
        glog1(group, "No client key compatible with server key");
        send_abort(group, "No client key compatible with server key");
        return 0;
    }
    if (has_proxy) {
        if (!proxy_pubkey.key) {
            glog1(group, "Response proxy set but haven't gotten key yet");
            send_abort(group,"Response proxy set but haven't gotten key yet");
            return 0;
        }
        if (!(((keytype == KEYBLOB_RSA) && (proxy_pubkeytype == KEYBLOB_RSA)) &&
                    (RSA_keylen(group->server_pubkey.rsa) ==
                        RSA_keylen(proxy_pubkey.rsa))) &&
                !(((keytype == KEYBLOB_EC) && (proxy_pubkeytype==KEYBLOB_EC)) &&
                    (get_EC_curve(group->server_pubkey.ec) ==
                        get_EC_curve(proxy_pubkey.ec)))) {
            glog1(group, "Response proxy key not compatible with server key");
            send_abort(group,
                    "Response proxy key not compatible with server key");
            return 0;
        }
    }
    if ((group->keyextype == KEYEX_ECDH_ECDSA) ||
            (group->keyextype == KEYEX_ECDH_RSA)) {
        unsigned char *sigcopy;
        int siglen;
        unsigned char *dhblob = keys + ntohs(encinfo->keylen);
        unsigned char *sig = dhblob + ntohs(encinfo->dhlen);

        if (!import_EC_key(&group->server_dhkey.ec, dhblob,
                           ntohs(encinfo->dhlen), 1)) {
            glog0(group, "Failed to load server public ECDH key");
            send_abort(group, "Failed to load server public ECDH key");
            return 0;
        }

        group->client_dhkey.ec =
                gen_EC_key(get_EC_curve(group->server_dhkey.ec), 1, NULL);
        if (!group->client_dhkey.key) {
            glog0(group, "Failed to generate client ECDH key");
            send_abort(group, "Failed to generate client ECDH key");
            return 0;
        }
        if (has_proxy) {
            // We already checked if the proxy key exists, so no need to repeat
            if (get_EC_curve(group->server_dhkey.ec) !=
                    get_EC_curve(proxy_dhkey.ec)) {
                glog1(group, "Response proxy ECDH key "
                             "not compatible with server ECDH key");
                send_abort(group, "Response proxy ECDH key "
                        "not compatible with server ECDH key");
                return 0;
            }
        }

        siglen = ntohs(encinfo->siglen);
        sigcopy = safe_calloc(siglen, 1);
        memcpy(sigcopy, sig, siglen);
        memset(sig, 0, siglen);
        if (keytype == KEYBLOB_RSA) {
            if (!verify_RSA_sig(group->server_pubkey.rsa, group->hashtype,
                                packet, packetlen, sigcopy, siglen)) {
                glog1(group, "Signature verification failed");
                send_abort(group, "Signature verification failed");
                free(sigcopy);
                return 0;
            }
        } else {
            if (!verify_ECDSA_sig(group->server_pubkey.ec, group->hashtype,
                                  packet, packetlen, sigcopy, siglen)) {
                glog1(group, "Signature verification failed");
                send_abort(group, "Signature verification failed");
                free(sigcopy);
                return 0;
            }
        }
        free(sigcopy);
    }

    // Calculate keys
    if (!calculate_server_keys(group, encinfo)) {
        return 0;
    }

    return 1;
}
Ejemplo n.º 4
0
/**
 * Handles an incoming CLIENT_KEY message from a client.
 */
void handle_clientkey(struct pr_group_list_t *group, int hostidx,
                      const unsigned char *message, unsigned meslen,
                      uint32_t src)
{
    const struct client_key_h *clientkey;
    const unsigned char *keyblob, *verify;
    struct pr_destinfo_t *dest;
    int dupmsg;

    clientkey = (const struct client_key_h *)message;
    keyblob = (const unsigned char *)clientkey + sizeof(struct client_key_h);
    verify = keyblob + ntohs(clientkey->bloblen);

    if (group->destcount == MAXPROXYDEST) {
        glog1(group, "Rejecting CLIENT_KEY from %08X: "
                     "max destinations exceeded", ntohl(src));
        send_downstream_abort(group, src, "Max destinations exceeded", 0);
        return;
    }
    if ((meslen < (clientkey->hlen * 4U)) ||
            ((clientkey->hlen * 4U) < sizeof(struct client_key_h) +
                ntohs(clientkey->bloblen) + ntohs(clientkey->siglen))) {
        glog1(group, "Rejecting CLIENT_KEY from %08X: invalid message size",
                     ntohl(src));
        send_downstream_abort(group, src, "Invalid message size", 0);
        return;
    }
    if ((((group->keyextype == KEYEX_RSA) ||
                    (group->keyextype == KEYEX_ECDH_RSA)) &&
                (keyblob[0] != KEYBLOB_RSA)) ||
            ((group->keyextype == KEYEX_ECDH_ECDSA) &&
             (keyblob[0] != KEYBLOB_EC))) {
        glog1(group, "Rejecting CLIENT_KEY from %08X: invalid keyblob type",
                     ntohl(src));
        send_downstream_abort(group, src, "Invalid keyblob type", 0);
        return;
    }


    if (hostidx == -1) {
        hostidx = add_client(src, group);
    }
    dest = &group->destinfo[hostidx];
    dupmsg = (dest->pubkey.key != 0);

    if (!dest->verified) {
        if (keyblob[0] == KEYBLOB_RSA) {
            if (!import_RSA_key(&dest->pubkey.rsa, keyblob,
                                ntohs(clientkey->bloblen))) {
                glog1(group, "Failed to load client public key");
                send_downstream_abort(group, src,
                                      "Failed to load client public key", 0);
                return;
            }
            dest->pubkeylen = RSA_keylen(dest->pubkey.rsa);
        } else {
            if (!import_EC_key(&dest->pubkey.ec, keyblob,
                               ntohs(clientkey->bloblen), 0)) {
                glog1(group, "Failed to load client public key");
                send_downstream_abort(group, src,
                                      "Failed to load client public key", 0);
                return;
            }
            dest->pubkeylen = ECDSA_siglen(dest->pubkey.ec);
        }
        if (!verify_fingerprint(client_fp, client_fp_count, keyblob,
                                ntohs(clientkey->bloblen), group, src)) {
            glog1(group, "Failed to verify client key fingerprint");
            send_downstream_abort(group, src, 
                                  "Failed to verify client key fingerprint", 0);
            return;
        }
        dest->verified = 1;
    }

    memcpy(dest->verifydata, verify, ntohs(clientkey->siglen));
    dest->verifylen = ntohs(clientkey->siglen);
    if (dest->registered) {
        if (!verify_client_key(group, hostidx)) {
            return;
        }
        dest->state = PR_CLIENT_REGISTERED;
    }

    glog2(group,"Received CLIENT_KEY%s from %s", dupmsg ? "+" : "", dest->name);

    if (dest->state == PR_CLIENT_REGISTERED) {
        // Pass in a dummy REGISTER message to check_pending, since
        // CLIENT_KEY is basically an extension of REGISTER.
        struct register_h reg;
        reg.func = REGISTER;
        check_pending(group, hostidx, (unsigned char *)&reg);
    }
}