Example #1
0
static int check_frame_protection(struct candidate *cand, struct ieee80211_mgmt_frame *mgmt, int len, struct info_elems *elems)
{
    unsigned char *clear_ampe_ie;
    struct info_elems ies_parsed;
    unsigned short ampe_ie_len, cat_to_mic_len;
    int r;
    unsigned int* key_expiration_p;

    assert(len && cand && mgmt);

    clear_ampe_ie = malloc(sizeof(struct ampe_ie) + 2);
    if (!clear_ampe_ie) {
		sae_debug(AMPE_DEBUG_KEYS, "Verify frame: out of memory\n");
        return -1;
    }

    if (!elems->mic || elems->mic_len != MIC_IE_BODY_SIZE) {
		sae_debug(AMPE_DEBUG_KEYS, "Verify frame: invalid MIC\n");
        free(clear_ampe_ie);
        return -1;
    }

    /*
     *  ampe_ie_len is the length of the ciphertext (the encrypted
     *  AMPE IE) and it needs to be inferred from the total frame
     *  size
     */
    ampe_ie_len = len -
                (elems->mic + elems->mic_len - (unsigned char *)mgmt);
    /*
     *  cat_to_mic_len is the length of the contents of the frame
     *  from the category (inclusive) to the mic (exclusive)
     */
    cat_to_mic_len = elems->mic - 2 - (unsigned char *) &mgmt->action;
    r = siv_decrypt(&cand->sivctx, elems->mic + elems->mic_len,
            clear_ampe_ie,
            ampe_ie_len,
            elems->mic, 3,
            cand->peer_mac, ETH_ALEN,
            cand->my_mac, ETH_ALEN,
            &mgmt->action, cat_to_mic_len);

    sae_debug(AMPE_DEBUG_KEYS, "Checking protection to " MACSTR " from " MACSTR "\n",
            MAC2STR(cand->my_mac), MAC2STR(cand->peer_mac));

    sae_debug(AMPE_DEBUG_KEYS, "Len checking cat-to-mic len:%d ampe ie full length: %d\n",
            cat_to_mic_len, ampe_ie_len);

    sae_hexdump(AMPE_DEBUG_KEYS, "SIV- Got AAD[3]: ", (unsigned char *) &mgmt->action,
            cat_to_mic_len);

    if (r != 1) {
        sae_debug(AMPE_DEBUG_KEYS, "Protection check failed\n");
        free(clear_ampe_ie);
        return -1;
    }

    sae_hexdump(AMPE_DEBUG_KEYS, "AMPE IE: ", clear_ampe_ie, ampe_ie_len);

    parse_ies(clear_ampe_ie, ampe_ie_len, &ies_parsed);

    if (memcmp(ies_parsed.ampe->peer_nonce, null_nonce, 32) != 0 &&
        memcmp(ies_parsed.ampe->peer_nonce, cand->my_nonce, 32) != 0) {
        sae_hexdump(AMPE_DEBUG_KEYS, "IE peer_nonce ", ies_parsed.ampe->peer_nonce, 32);
        sae_debug(AMPE_DEBUG_KEYS, "Unexpected nonce\n");
        free(clear_ampe_ie);
        return -1;
    }
    memcpy(cand->peer_nonce, ies_parsed.ampe->local_nonce, 32);
    memcpy(cand->mgtk, ies_parsed.ampe->mgtk, sizeof(cand->mgtk));
    sae_hexdump(AMPE_DEBUG_KEYS, "Received mgtk: ", cand->mgtk, sizeof(cand->mgtk));
    key_expiration_p = (unsigned int *)ies_parsed.ampe->key_expiration;
    cand->mgtk_expiration = le32toh(*key_expiration_p);
    free(clear_ampe_ie);
    return -1;
#undef MIC_IE_BODY_SIZE
}
Example #2
0
static int check_frame_protection(struct candidate *cand, struct ieee80211_mgmt_frame *mgmt, int len, struct info_elems *elems)
{
    unsigned char *clear_ampe_ie;
    struct info_elems ies_parsed;
    struct mesh_node *mesh = cand->conf->mesh;
    unsigned short ampe_ie_len, cat_to_mic_len;
    int r;
    unsigned int* key_expiration_p;
    u8 ftype = mgmt->action.action_code;
    u8 *gtkdata, *igtkdata;

    assert(len && cand && mgmt);

    if (!elems->mic || elems->mic_len != MIC_IE_BODY_SIZE) {
		sae_debug(AMPE_DEBUG_KEYS, "Verify frame: invalid MIC\n");
        return -1;
    }

    /*
     *  ampe_ie_len is the length of the ciphertext (the encrypted
     *  AMPE IE) and it needs to be inferred from the total frame
     *  size
     */
    ampe_ie_len = len -
                (elems->mic + elems->mic_len - (unsigned char *)mgmt);

    /* expect at least MGTK + RSC + expiry for open/confirm */
    if (ftype != PLINK_CLOSE &&
        ampe_ie_len < 2 + sizeof(struct ampe_ie) + 16 + 8 + 4) {
		sae_debug(AMPE_DEBUG_KEYS, "Verify frame: AMPE IE too small\n");
        return -1;
    }

    /* if PMF, then we also need IGTKData */
    if (mesh->conf->pmf) {
        if (ampe_ie_len < 2 + sizeof(struct ampe_ie) + 16 + 8 + 4 +
                          2 + 6 + 16 /* IGTKData */) {
            sae_debug(AMPE_DEBUG_KEYS, "Verify frame: AMPE IE missing IGTK\n");
            return -1;
        }
    }

    clear_ampe_ie = malloc(ampe_ie_len);
    if (!clear_ampe_ie) {
		sae_debug(AMPE_DEBUG_KEYS, "Verify frame: out of memory\n");
        return -1;
    }

    /*
     *  cat_to_mic_len is the length of the contents of the frame
     *  from the category (inclusive) to the mic (exclusive)
     */
    cat_to_mic_len = elems->mic - 2 - (unsigned char *) &mgmt->action;
    r = siv_decrypt(&cand->sivctx, elems->mic + elems->mic_len,
            clear_ampe_ie,
            ampe_ie_len,
            elems->mic, 3,
            cand->peer_mac, ETH_ALEN,
            cand->my_mac, ETH_ALEN,
            &mgmt->action, cat_to_mic_len);

    sae_debug(AMPE_DEBUG_KEYS, "Checking protection to " MACSTR " from " MACSTR "\n",
            MAC2STR(cand->my_mac), MAC2STR(cand->peer_mac));

    sae_debug(AMPE_DEBUG_KEYS, "Len checking cat-to-mic len:%d ampe ie full length: %d\n",
            cat_to_mic_len, ampe_ie_len);

    sae_hexdump(AMPE_DEBUG_KEYS, "SIV- Got AAD[3]: ", (unsigned char *) &mgmt->action,
            cat_to_mic_len);

    if (r != 1) {
        sae_debug(AMPE_DEBUG_KEYS, "Protection check failed\n");
        free(clear_ampe_ie);
        return -1;
    }

    if (ampe_ie_len != clear_ampe_ie[1] + 2) {
        sae_debug(AMPE_DEBUG_KEYS, "AMPE -Invalid length (expected %d, got %d)\n",
            ampe_ie_len, clear_ampe_ie[1] + 2);
        free(clear_ampe_ie);
        return -1;
    }

    sae_hexdump(AMPE_DEBUG_KEYS, "AMPE IE: ", clear_ampe_ie, ampe_ie_len);

    parse_ies(clear_ampe_ie, ampe_ie_len, &ies_parsed);

    if (memcmp(ies_parsed.ampe->peer_nonce, null_nonce, 32) != 0 &&
        memcmp(ies_parsed.ampe->peer_nonce, cand->my_nonce, 32) != 0) {
        sae_hexdump(AMPE_DEBUG_KEYS, "IE peer_nonce ", ies_parsed.ampe->peer_nonce, 32);
        sae_debug(AMPE_DEBUG_KEYS, "Unexpected nonce\n");
        free(clear_ampe_ie);
        return -1;
    }
    memcpy(cand->peer_nonce, ies_parsed.ampe->local_nonce, 32);

    gtkdata = ies_parsed.ampe->variable;

    memcpy(cand->mgtk, gtkdata, sizeof(cand->mgtk));
    sae_hexdump(AMPE_DEBUG_KEYS, "Received mgtk: ", cand->mgtk, sizeof(cand->mgtk));
    key_expiration_p = (unsigned int *) (gtkdata + 16 + 8);
    cand->mgtk_expiration = le32toh(*key_expiration_p);

    igtkdata = gtkdata + 16 + 8 + 4;
    if (mesh->conf->pmf) {
        cand->igtk_keyid = le16toh(*(u16 *) igtkdata);
        igtkdata += 2 + 6;
        memcpy(cand->igtk, igtkdata, 16);
    }
    free(clear_ampe_ie);
    return -1;
#undef MIC_IE_BODY_SIZE
}